In the previous post, we used docker-compose to build and manage our multi-container application. Today, I talk about orchestrating those containers using Kubernetes.
fter building the docker image in the previous article, it’s time to orchestrate containers using K8s.
The docker image is tagged and pushed to the docker hub.
Config Maps and Secrets
When we ran the Django(app) container locally, we passed the env file into the docker run to inject configuration variables into the runtime environment. On Kubernetes, configuration variables can be injected using ConfigMaps and Secrets.
ConfigMaps should be used to store non-confidential configuration information, such as app settings, and Secrets should be used for sensitive information, such as API keys and database credentials.
Note
We’ve extracted the non-sensitive configuration from the .env.app file and pasted it into a ConfigMap manifest. The ConfigMap object is called app-config.
The first step is to deploy Postgres as a stateful set with a headless service. A stateful set is a Kubernetes resource that manages deploying and scaling a set of Pods with persistent identities and storage. A headless service is a Kubernetes service that does not have a cluster IP address. Instead, it provides DNS records for the pods in the stateful set.
Tip
A stateful set requires dynamic volume provisioning, which is met by installing rancher local path provisioner.
The following YAML file defines a headless service named db that exposes port 5432 and selects Pods with the label app: postgres. It also defines a stateful set named “postgres” that uses the headless service, has one replica, and creates Pods with the label app: postgres. Each Pod has a container named Postgres that runs the image postgres:16
The command above will create the headless service and the stateful set in your cluster. You can verify them by running the following commands:
1
2
3
4
k get pv
k get pvc -l app=postgres
k get svc -l app=postgres
k get po -l app=postgres
Output - DB
Note
The local-path provisioner mounts a directory /opt/local-path-provisioner on the node to which the db pod gets assigned.
Rolling out the Django app using a Deployment
In this step, we will create a Deployment for your Django app. A Kubernetes Deployment is a controller that can manage stateless applications in your cluster. A controller is a control loop that regulates workloads by scaling them up or down. Controllers also restart and clear out failed containers.
Here, we define a Kubernetes Deployment called app and label it with the key-value pair name: app. We specify that we’d like to run only one replica of the Pod defined below the template field.
apiVersion:v1kind:Servicemetadata:creationTimestamp:nulllabels:app:appname:appspec:ports:- name:"8000"port:8000protocol:TCPtargetPort:8000selector:name:apptype:ClusterIPstatus:loadBalancer:{}---apiVersion:apps/v1kind:Deploymentmetadata:creationTimestamp:nulllabels:app:djangoname:appspec:replicas:1selector:matchLabels:name:appstrategy:{}template:metadata:creationTimestamp:nulllabels:name:appspec:containers:- image:ajdemo/cloudtalents-startup-app:v1imagePullPolicy:Alwaysname:appcommand:["/opt/app/web/entrypoint.sh"]args:["gunicorn","--bind","0.0.0.0:8000","cloudtalents.wsgi:application"]envFrom:- secretRef:name:app-secret- configMapRef:name:app-configports:- containerPort:8000name:gunicornvolumeMounts:- mountPath:/opt/app/web/media/name:media-volumevolumes:- name:media-volumehostPath:path:/media/images# directory location on hosttype:DirectoryOrCreate# this field is optionalstatus:{}
Using envFrom with secretRef and configMapRef, we specify that all the data from the app-secret Secret and app-config ConfigMap should be injected into the containers as environment variables. The ConfigMap and Secret keys become the environment variable names.
Note
Finally, we expose containerPort 8000 and name it gunicorn.
Create the Deployment using k apply -f app-deploy.yaml
Info
Verify the resources using the following commands.
1
2
3
k get deploy
k get po -l name=app
k get svc -l app=app
Output - APP
Now execute the Django migration using the command below
1
k exec -it <app-pod-name> -- python3 manage.py migrate
Migrations are Django’s way of propagating changes you make to your models (adding a field, deleting a model, etc.) into your database schema. Successful execution of the command returns the below output.
Rolling out the NGINX using a Deployment
In this step, we will create a Deployment for your nginx. It first creates a ConfigMap and uses a custom nginx.conf file. It is mounted as a volume inside /etc/nginx/conf.d directory of Pod.
A nodePort service exposes the Pod to the outside world.