Skip to content

Production Setup

Ramon Blanquer edited this page Jun 7, 2023 · 16 revisions

The following instructions are just as reference to show how the project setup was done. It also serves to other developers that might want to deploy it to their own clusters. If you want to contribute to the project you probably don't need this, just develop locally and submit the merge request.

Overview

This project is intended to run on a Google Cloud Kubernetes cluster: GKE (Google Kubernetes Engine). In this page you will find the instructions to setup it all up from scratch.

This setup costs around $10 a month. It uses the trick of going without Google's Load Balancer (which cuts down around $20 a month). The details about this can be found in this article:

Domain

First of all I would suggest buying a domain.

I would suggest one from Namecheap. dreamdrugs.art costed me $4.88.

Later on we will configure DNS settings to proxy our traffic through Cloudflare to avoid having to pay Google's Load Balancer! Every time a new node appears on our cluster it will be registered with Cloudflare as an A Alias.

Google Cloud

First you need to sign up on Google Cloud and follow the registration steps.

After doing so it's time to setup the SDK that gives you gcloud the CLI to manage Google Cloud resources:

Before proceeding ensure you have:

  • A working Google Cloud account.
  • A project created. This guide assumes you have chosen "dreamdrugs".
  • Have gcloud (Google Cloud SDK) installed and set up with:
    • A default zone
    • A default project

Google Kubernetes Engine

Reference: Kubernetes: The Surprisingly Affordable Platform for Personal Projects

This instructions merely follow the points describe on the article aforementioned. I suggest you to read in first.

It all boils down to create the cluster with:

gcloud container --project "dreamdrugs" clusters create "dreamdrugs" \
  --zone "us-central1-a" \
  --no-enable-basic-auth \
  --release-channel "regular" \
  --machine-type "g1-small" \
  --image-type "COS_CONTAINERD" \
  --disk-type "pd-standard" \
  --disk-size "10" \
  --metadata disable-legacy-endpoints=true \
  --scopes "https://www.googleapis.com/auth/devstorage.read_only","https://www.googleapis.com/auth/logging.write","https://www.googleapis.com/auth/monitoring","https://www.googleapis.com/auth/servicecontrol","https://www.googleapis.com/auth/service.management.readonly","https://www.googleapis.com/auth/trace.append" \
  --preemptible \
  --num-nodes "3" \
  --no-enable-cloud-logging \
  --no-enable-cloud-monitoring \
  --enable-ip-alias \
  --network "projects/dreamdrugs/global/networks/default" \
  --subnetwork "projects/dreamdrugs/regions/us-central1/subnetworks/default" \
  --default-max-pods-per-node "110" \
  --addons HorizontalPodAutoscaling \
  --enable-autoupgrade \
  --enable-autorepair

The command above might fail if you haven't enabled the Kubernetes Engine API for the project you created. Just follow the error message suggestion: "Kubernetes Engine API has not been used in project xxxxxxxxxxxx before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/container.googleapis.com/overview?project=xxxxxxxxxxxx then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.".

I got this command by doing the manual cluster creation as described in the article, near the end on the browser google was suggesting me the equivalent API command to the action I was doing through their Web Console.

Cluster Access

You will now get this message after creating the cluster:

CRITICAL: ACTION REQUIRED: gke-gcloud-auth-plugin, which is needed for continued use of kubectl, was not found or is not executable. Install gke-gcloud-auth-plugin for use with kubectl by following https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke

Simply follow their instructions:

$ gcloud components install gke-gcloud-auth-plugin
$ export USE_GKE_GCLOUD_AUTH_PLUGIN=True
$ gcloud container clusters get-credentials dreamdrugs  --region us-central1-a
$ kubectl config get-contexts
CURRENT   NAME                                       CLUSTER                  AUTHINFO                  NAMESPACE
          arn:aws:eks:...                            arn:aws:eks:...          arn:aws:eks:...
          docker-desktop                             docker-desktop           docker-desktop        
*         gke_dreamdrugs_us-central1-a_dreamdrugs    gke_dreamdrugs_us-...    gke_dreamdrugs_us-...
          minikube                                   minikube                 minikube                  default
          rancher-desktop                            rancher-desktop          rancher-desktop       


You will need export USE_GKE_GCLOUD_AUTH_PLUGIN=True to your shell profile file ~/.bashrc or ~/.zshrc so it gets set every time you run a new shell if you want to forget about it when accessing the Google Kubernetes Cluster.

Cloudflare

Add site to Cloudflare

What we need to do first is to let our DNS (and many more features) to be managed, free of cost, by Cloudflare.

To do so, register to Cloudflare and click on Add site as soon as you finish registration. Then follow all the steps it describes.

Change domain name servers

The first step after adding the site is to change your domain nameservers as the Cloudflare article explains. If you are using Namecheap follow their instructions.

Getting your Global API Key

Afterwards you will need to get your Global API key in Cloudflare as described in here so Caleb's tool (in the next step) can update the DNS A records automatically every time a node is destroyed or created in the cluster. It's under My Profile > API Tokens > API Keys. You are going to need this when you first deploy the project with the helm install command. So keep it safe.

kubernetes-cloudflare-sync

Build and push Caleb Doxey's image to your Google Cloud's Registry as he describes in his GitHub repository:

git clone [email protected]:calebdoxsey/kubernetes-cloudflare-sync.git /tmp/kubernetes-cloudflare-sync
cd /tmp/kubernetes-cloudflare-sync

# Build and push. In this case my project ID is dreamdrugs, update the "dreamdrugs" portion below accordingly.
docker build -t gcr.io/dreamdrugs/kubernetes-cloudflare-sync:latest .
docker push gcr.io/dreamdrugs/kubernetes-cloudflare-sync:latest

If you have authorization problems when pushing to gcr.io you might want to read about authorizing docker as explained in Google's documentation. A gcloud auth configure-docker should suffice.

Then assign a cluster admin role to your user in Kubernetes, which is the one kubernetes-cloudflare-sync is going to use.

# Ensure kubectl is pointing to GKE.
gcloud container clusters get-credentials dreamdrugs --region us-central1-a

# You can check you are indeed in the right context by checking the output of
kubectl config get-contexts

# Create the role binding.
kubectl create clusterrolebinding cluster-admin-binding --clusterrole cluster-admin --user [email protected]

Adding 'A' records for Kubernetes nodes

What Caleb's tool is going to do is to keep updating 'A' records that would map kubernetes.your-domain.com to the IPs of the nodes in your cluster. Then all we need is to point the root CNAME to kubernetes and proxy it through Cloudflare:

Type Name Content Proxy status
CNAME dreamdrugs.art kubernetes.dreamdrugs.art ☁️ Proxied
A kubernetes 104.154.101.136 ☁️ Proxied
A kubernetes 35.194.27.124 ☁️ Proxied
A kubernetes 35.238.201.122 ☁️ Proxied

Adding SSL for free

One of the perks of Cloudflare is that it offers SSL encryption from the client to Cloudflare just one click away from their dashboard, what way many features like the permissions to get the webcam from the browser will work! (They require either to be accessible in the localhost namespace or to have SSL enabled, read here).

To do this follow these two steps as described in Cloudflare's documentation:

  • Go to the SSL/TLS menu under your site.
    • Set your SSL/TLS encryption mode to Flexible.
    • Click the Edge Certificates and enable Always Use HTTPS so it redirects all requests with scheme http to https.

HTTP(s) firewall rule

Since we will be hitting directly our cluster nodes (through Cloudflare) where an NGINX service will be routing the requests. In order to let the traffic in we need to set a rule to the firewall to allow in the HTTPS traffic into the nodes of our cluster:

gcloud compute --project=dreamdrugs firewall-rules create http \
  --direction=INGRESS \
  --priority=1000 \
  --network=default \
  --action=ALLOW \
  --rules=tcp:80,tcp:443,tcp:8080 \
  --source-ranges=0.0.0.0/0

Deployment

First we need to build all the images that are needed to gcr.io and push them.

If pushing fails because you are not authenticated you might want to do gcloud auth configure-docker.

docker build -t gcr.io/dreamdrugs/backend ./backend
docker push gcr.io/dreamdrugs/backend

docker build -t gcr.io/dreamdrugs/frontend ./frontend
docker push gcr.io/dreamdrugs/frontend

Now you are ready to deploy the project to GKE! Find the Global API Key from your Cloudflare account and let Helm handle the rollouts:

read -s CLOUDFLARE_GLOBAL_API_KEY
helm upgrade --install --dependency-update dreamdrugs deploy/dreamdrugs \
  --set ingress=false \
  --set backendImage=gcr.io/dreamdrugs/backend \
  --set frontendImage=gcr.io/dreamdrugs/frontend \
  --set redis.master.persistence.enabled=false \
  --set redis.slave.persistence.enabled=false \
  --set redis.password=foobar1234 \
  --set [email protected] \
  --set cloudflare.globalApiKey=$CLOUDFLARE_GLOBAL_API_KEY