From Docker to KubernetesStep 7 of 10: Create Deployments
All Labs

Create Deployments

In the last sections, we mainly worked with Pods, which are the smallest deployable units in Kubernetes. However, in real-world scenarios, you will often want to run multiple instances of your application for high availability and scalability. This is where Deployments come into play.

If you were using Pods directly, you would have to manage the lifecycle of each Pod manually, which can be cumbersome and error-prone. Deployments automate this process and provide a declarative way to manage your application. So let's first create a Deployment for our Learning Tracker application. This can be achieved in a similar way as we created the Pod earlier, but this time we will use the kubectl create deployment command.

kubectl create deployment learning-tracker --image=ghcr.io/tsclabs-eu/learning-tracker:v1.0.5 -n learning-tracker --dry-run=client -o yaml > learning-tracker-deployment.yaml

This command will create a Deployment named learning-tracker in the learning-tracker Namespace using the image ghcr.io/tsclabs-eu/learning-tracker:v1.0.5. The --dry-run=client flag tells kubectl to only simulate the creation of the Deployment and not actually create it, while the -o yaml flag tells it to output the manifest in YAML format. The output is then redirected to a file named learning-tracker-deployment.yaml in your current directory.

Now, let's delete the Pod we created earlier and apply the manifest we just created to create the Deployment. You can do this by running the following commands:

kubectl delete pod learning-tracker -n learning-tracker
kubectl apply -f learning-tracker-deployment.yaml

You can verify that the Deployment was created by running:

kubectl get deployments -n learning-tracker
kubectl get pods -n learning-tracker

You should see the newly created Deployment in the list of Deployments in the learning-tracker Namespace, and the Pod created by the Deployment should be running. The output should look similar to this:

NAME              READY   UP-TO-DATE   AVAILABLE   AGE
learning-tracker   1/1     1            1           5s

NAME                             READY   STATUS    RESTARTS   AGE
learning-tracker-7f5b6c8d4c-abcde   1/1     Running   0          5s

Notice the random suffix in the Pod name. Deployments generate unique Pod names to manage them independently. The Deployment will automatically manage the Pods and ensure that the desired number of replicas is running.

If you already inspected the manifest, you might have noticed that the environment variable LOG_OUTPUT is missing in the Deployment manifest. This is because we didn't add it to the Deployment manifest when we created it. Let's take a look at the learning-tracker-deployment.yaml file and add the environment variable to the container specification.

After adding the environment variable, the whole manifest should look like this:

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: learning-tracker
  name: learning-tracker
  namespace: learning-tracker
spec:
  replicas: 1
  selector:
    matchLabels:
      app: learning-tracker
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: learning-tracker
    spec:
      containers:
      - image: ghcr.io/tsclabs-eu/learning-tracker:v1.0.5
        name: learning-tracker
        env:
        - name: LOG_OUTPUT
          value: "console"
        resources: {}
status: {}

Some things in this manifest might look very familiar to you, such as the apiVersion, kind, and metadata sections. The spec section contains the specification of the Deployment, including the number of replicas, the selector, and the template for the Pods that will be created by the Deployment. The template section contains the Pod specification, which is similar to the Pod manifest we created earlier.

Now, we can simply apply the manifest again to update the Deployment and add the environment variable:

kubectl apply -f learning-tracker-deployment.yaml

By applying the manifest, Kubernetes will update the Deployment and create new Pods with the updated specification. You can verify that the Pods were updated by running:

kubectl get pods -n learning-tracker

You will see that the Pods are being recreated with the new specification, and the LOG_OUTPUT environment variable is now set to console.

💡Inspection Tip

Try to inspect the Deployment and Pods using kubectl describe commands, take a look at the logs and try to port-forward to the workload again. You should see that the application is still running and accessible via port forwarding.

Create a Database Deployment

Now that we have a Deployment for our Learning Tracker application, we will create a Deployment for our MariaDB database. This will allow us to scale our application and use a separate database instead of SQLite.

To create a Deployment for the MariaDB database, we will use the kubectl create deployment command again. This time, we will use the official MariaDB image from Docker Hub. Run the following command in your terminal:

kubectl create deployment mariadb --image=mariadb:12.0 -n learning-tracker --dry-run=client -o yaml > mariadb-deployment.yaml

Furthermore, we will add some environment variables to the Deployment manifest to configure the database. The environment variables will include the database name, user, and password. Open the mariadb-deployment.yaml file in your text editor or IDE and add the following section under the containers section:

[...]
  containers:
  - name: mariadb
    env:
    - name: MARIADB_RANDOM_ROOT_PASSWORD
      value: "yes"
    - name: MARIADB_DATABASE
      value: "learning.db"
    - name: MARIADB_USER
      value: "app"
    - name: MARIADB_PASSWORD
      value: "my_password"
    [...]
Sensitive Information

The password in the manifest is hardcoded and should not be used in production. In real-world scenarios, there are better ways to manage sensitive information, but for this lab, we will keep it simple.

Now, we can apply the manifest to create the Deployment for the MariaDB database:

kubectl apply -f mariadb-deployment.yaml

You can verify that the Deployment was created by running:

kubectl get deployments -n learning-tracker
kubectl get pods -n learning-tracker

You should see the newly created Deployment in the list of Deployments in the learning-tracker Namespace, and the Pod created by the Deployment should be running.

Now that we have a Deployment for the MariaDB database, we need to connect our Learning Tracker application to the database. In Kubernetes, IP addresses of Pods are very volatile and will change with every restart. Pod names are also not guaranteed to be stable, so we will need a new object to connect our application to the database. This is where Services come into play.