This is the fifth part of the series on building highly scalable multi-container apps using AKS. So far in this series we have covered following topics.
- Part 1 : we provisioned a managed Kubernetes cluster using Azure Container Service (AKS).
- Part 2 : Understand basic Kubernetes objects - Kubernetes Namespace.
- Part 3 : Understand basic Kubernetes objects – Pod and Deployment
- Part 4 : Understand Kubernetes object – Service
In this post we will get familiar with the concept of init containers. Lets first understand the need for init-containers. In our application we have the TechTalksWeb API which depends on the persistent data stored in MS SQL Server database. It takes few seconds for the SQL Server container to start and to initialize the static data. In the meantime the web API container will start and try to connect to the database container. It will fail if the database container is not yet initialized. In such situation, Kubernetes provides an object named init-container. It ensures that the initialization tasks are completed before the dependent container can be started.
In our case we will make use of the init-container to initialize the database. The web API container will be started only after the database service is successfully started.
We will be performing following actions during this post
- Use Docker-compose to build and publish images to DockerHub
- Setup init container using Kubernetes manifest file to initialize the TechTalksDB inside the SQlserver 2017 container image
- Deploy services in one go using kubectl
Build Docker images for following components:
I find it easier to use Docker-compose to stich the services together. We can then build, tag and push these images using docker-compose instead of building them individually. Once the images are pushed to Dockerhub container registry, we can deploy web front, web api and the database containers using Kubernetes manifest.
Here is an example of the compose file which I use for composing the multiple services. I recently presented a hands on session specifically around stitching multi-container apps using Docker-compose for Azure User Group. The video of the session is available at Engineers.sg site.
We will be using a sql script to initilalize our database with static data. The initializedb.sql script is straightforward. It initializes the database if it does not exists. It creates tables to store static data like categories, level etc.
Set up init container
In the code snippet above, we can see that the spec has a section named init-containers on line number 21. Here we specify the image to be used which is named nileshgule/sqlclient. At the time of building this image, we are copying the initializedb.sql script. We specify the command to be executed using sqlcmd command line utility.
/opt/mssql-tools/bin/sqlcmd -S db-deployment -U sa -P January2018 -d master -i initialize-database.sql
This is then followed by the regular containers section on line 28. The containers will be instantiated only after the init container has completed its work. This ensures that the TechTalksDB database is fully initialized before the API tries to connect to the SQL server.
Deploy services in one shot
Earlier we saw how we can deploy a service using kubectl command and passing an individual manifest file to it. The kubectl command is quite flexible and provides us a convenient way using a single command to recursively deploy multiple objects. Under the Minikube folder, we have multiple sub-folders which contain manifest files for each type of service. Instead of running kubectl create or apply command with individual filenames, I can run following command to recursively apply all the manifest files with one single command
kubectl apply –recursive –filename .
At the time when I was building the demo for Azure Bootcamp presentation, I had multiple services running using Minikube. I am using a subset of those services here. To deploy only 3 services along with the namespace, I executed the commands shown below in the specific order.
The same set of commands are also available as Powershell script and can be executed in one go by running the script. The apply command will apply only the changes to the desired state configuration. If the current state matches the expected state no changes would be done. The end result of this command is as shown below
The techtalksapi we can see contains two images. If we dive deep into the Pods section & click on the techtalks API related pod, we can see the following details
Notice that the techtalkapi:v1 pod is only created after the sqlclient container is fully started.
We can also see the service discovery working to perfection. The WebAPI refers to the sql database using its service name db-deployment on line 35 in the manifest file. Normally we would have provided a fully qualified connection string to connect to sql database server. In the future post we will look into the aspects related to resourcing needs in detail.
As we saw in this post, the concept of init-containers is quite powerful in ensuring that dependent services are up and running. Ideally you would implement a resilient mechanism like exponential backoff to handle failures. We will cover that part in future post. The complete source code is available on Github.
Until next time, Code with Passion and Strive for Excellence.