Kubernetes Developer Workshop

🚀 Deploying The Backend

We'll deploy the app piece by piece, and at first we'll deploy & configure things in a sub-optimal way. This is in order to explore the Kubernetes concepts and show their purpose. Then we'll iterate and improve towards the final architecture.

We have four "microservices" we need to deploy, and due to dependencies between them we'll start with the PostgreSQL database then the API and then move onto the frontend.

From here we will be creating and editing files, so it's worth creating a project folder locally (or even a git repo) in order to work from if you haven't done so already.

🍃 Deploying PostgreSQL

We'll apply configurations to Kubernetes using kubectl and YAML manifest files, and we'll be doing this a lot throughout the workshop. These files will describe the objects we want to create, modify and delete in the cluster.

If you want to take this workshop slowly and treat it as more of a hack, you can research and build the required YAML yourself, you can use Kubernetes docs (link below) and the following hints:

📚 Kubernetes Docs: Deployments

Why are we not using the official PostgreSQL image? Well really we should, but initializing database schema would require concepts like config maps & volume mounts which we're not ready for yet. The nanomon-postgres image has been specifically built with the database initialization baked in, so we can keep things simple for now.

On placeholders in the YAML, throughout this workshop you will see placeholders in the YAML files, these in double underscores e.g. __SOMETHING__ these always need to be replaced with real values. This double underscore convention was chosen to avoid confusion with other syntax and does not upset any YAML parsers or linters.

Alternatively you can use the YAML below to paste into postgres-deployment.yaml don't worry this isn't cheating, in the real world everyone is too busy to write Kubernetes manifests from scratch 😉

Click here for the PostgreSQL deployment YAML
apiVersion: apps/v1
kind: Deployment

metadata:
  name: postgres

spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgres

  template:
    metadata:
      labels:
        app: postgres

    spec:
      containers:
        - name: postgres
          image: __ACR_NAME__.azurecr.io/nanomon-postgres:latest

          ports:
            - containerPort: 5432

          env:
            - name: POSTGRES_DB
              value: "nanomon"
            - name: POSTGRES_USER
              value: "nanomon"
            - name: POSTGRES_PASSWORD
              value: "notVerySecret123!"

Then apply the manifest with:

kubectl apply -f postgres-deployment.yaml

If successful you will see deployment.apps/postgres created, this will have created one Deployment and one Pod. You can check the status of your cluster with a few commands:

Get used to these commands you will use them a LOT when working with Kubernetes.

For the next part we'll need the IP address of the pod that was just deployed, you can get this by running kubectl get pod -o wide or the command below:

kubectl describe pod --selector app=postgres | grep ^IP:

🗃️ Deploying The API

Next we'll deploy the first custom part of our app, the backend API, and like the DB we'll deploy it from an image hosted in our private registry.

Again you can try building the Deployment yourself or use the provided YAML to create a api-deployment.yaml file

Click here for the API deployment YAML
kind: Deployment
apiVersion: apps/v1

metadata:
  name: nanomon-api

spec:
  replicas: 2
  selector:
    matchLabels:
      app: nanomon-api

  template:
    metadata:
      labels:
        app: nanomon-api

    spec:
      containers:
        - name: api-container

          image: __ACR_NAME__.azurecr.io/nanomon-api:latest
          imagePullPolicy: Always

          ports:
            - containerPort: 8000

          env:
            - name: POSTGRES_DSN
              value: "host=__POSTGRES_POD_IP__ port=5432 user=nanomon dbname=nanomon sslmode=disable"
            - name: POSTGRES_PASSWORD
              value: "notVerySecret123!"

💥 Notice: We have the password in plain text within the connection string! This clearly is a very bad practice, we will fix this at a later stage when we introduce Kubernetes Secrets.

Make the changes described above, remember to make the edits, you can not use this YAML as is!, and then run:

kubectl apply -f api-deployment.yaml

Check the status as before with kubectl and it's worth checking the logs with kubectl logs {podname} to see the output from the app as it starts up.

This time we've set the number of replicas to two, if you run kubectl get pods -o wide you will see which Nodes the Pods have been scheduled (assigned) to. You might see each Pod has been scheduled to different Nodes, but this is not guaranteed. Pod scheduling and placement is a fairly complex topic, for now we can move on.

It's also worth mention the Pod names, they are prefixed with the name of the Deployment, followed by a hash, folowed by a random string. Pod names are nearly always auto-generated like this, and are not something you should rely on or try to set yourself.

⏩ Accessing the API (The quick & dirty way)

Now it would be nice to access and call this API, to check it's working. But the IP address of the Pods are private and only accessible from within the cluster. In the next section we'll fix that, but for now there's a short-cut we can use.

Kubernetes provides a useful way to "tunnel" network traffic into the cluster through the control plane, this is done with the kubectl port-forward command.

Pick the name of either one of the two api Pods, and run:

kubectl port-forward {pod_name} 8000:8000

And then accessing the following URL http://localhost:8000/api/info either in your browser or with curl we should see a JSON response with some status and debug information from the API.

curl -s http://localhost:8000/api/status | json_pp

Clearly this isn't a good way to expose your apps long term, but can be extremely useful when debugging and triaging issues.

When done, cancel & close the port-forwarding with ctrl-c

🖼️ Cluster & Architecture Diagram

The resources deployed into the cluster & in Azure at this stage can be visualized as follows

architecture diagram

Yes, it's looking a little empty at this stage, don't worry it'll become a lot more complex soon!