Container Orchestration

 

Container Orchestration

In the modern landscape of software development and deployment, containers have emerged as a pivotal technology, offering unparalleled portability and consistency for applications.

Many applications today adopt a microservice based architecture, where a single application is split into multiple services that communicate with each other using protocols like HTTP. When using containers with microservices, each individual service would run in its own container. As an application grows in size, the number of services increases, thereby increasing the number of containers. However, managing a large number of containers across various hosts can quickly become complex and unwieldy. This is where container orchestration steps in, transforming chaotic deployments into streamlined, automated operations.

Orchestration is not a new term, and it is not specific to containers. In the realm of computing, orchestration refers to the automated configuration, coordination, and management of computer systems, middleware, and services. When applied to containers, it means the automated management of containerized applications, including their deployment, scaling, networking, and availability. Most people would relate the term 'orchestration' with the musical 'orchestra', and it is the perfect analogy to understand orchestration. In an orchestra individual musicians are highly skilled, but without a conductor, they might play out of sync or at different tempos, leading to a cacophony. The conductor ensures all musicians play harmoniously, starting and stopping at the right times, and adjusting their volume as needed, creating a beautiful piece of music. Similarly, a container orchestrator ensures all containers work together efficiently to deliver a cohesive application.

So how is orchestration performed with containers? There are many popular technologies to choose from including Docker Swarm, Kubernetes, HashiCorp Nomad, Apache Mesos, Amazon ECS, and Red Hat OpenShift. To understand how orchestration works, this article would focus on Docker Swarm.

Manager and Worker Nodes

While the way each technology handles orchestration varies, a fundamental concept across all is the existence of manager and worker nodes. But what are nodes in the first place? A node refers to a single, distinct computing device or entity within a larger system or network. In the context of orchestration, a node is a physical or virtual machine that is part of the 'orchestra' and can run containerized workloads. It is crucial to understand the differences in capacities and responsibility of the two types of nodes.

A manager node is the brain of the orchestration system. Its primary responsibilities include:

·       Deciding where to run containers based on resource availability, desired state, and other policies. Maintaining the overall state of the cluster, including information about all running containers, services, and nodes.

·       Providing an interface for users and other tools to interact with the cluster (e.g., to deploy new applications, scale services).

·       Assigning tasks (containers) to worker nodes.

·       Continuously monitoring the health of worker nodes and running containers and taking action (like restarting failed containers or moving them to healthy nodes) to maintain the desired state.

Worker nodes, as implied by the name, perform the actual work in an orchestration. Their primary responsibilities include:

·       Running the actual containerized application as instructed by the manager node.

·       Communicate their status and the status of the containers running on them back to the manager node

·       Provide the CPU, memory, storage, and network resources for the containers

Now that you understand what the responsibilities of worker and manager nodes are, let us explore the working of Docker Swarm. The purpose is to give a basic understanding of how a cluster operates internally. Comparison of the pros and cons of different orchestration technologies is beyond the scope of this article. From here on, we shall refer to the complete system of orchestration as a 'cluster' or 'swarm'.

Docker Swarm

Docker Swarm is Docker's native clustering and orchestration solution. It allows you to create and manage a cluster of Docker engines, treating them as a single virtual Docker host. In Docker Swarm, the containers are created declaratively. What does that mean? Instead of specifying how the containers should be created or manually creating them through the command line using docker run command, we only need to specify or declare the intended state of the cluster. This intended state includes:

·       The Docker image to use.

·       The number of replicas (instances) to run.

·       Port mappings.

·       Environment variables.

·       Network configurations.

·       Resource constraints (CPU, memory).

That's it. We only specify what the cluster should look like, the how is managed by Docker Swarm. This desired state is known as a service in Docker Swarm. A service can be scaled up or down, and the Swarm manager ensures the specified number of replicas are always running. If one instance (replica) stops or crashes, Docker Swarm automatically spins up another one to match the desired number of instances, thereby ensuring availability of the application.

An individual running instance of a service is known as task. When a service is created, the manager node schedules tasks on worker nodes. If a task fails or a worker node goes down, the manager automatically reschedules the task on another available node. We previously discussed about use of containers in a microservices based architecture. A typical application includes multiple components like web server, database, caching etc. To orchestrate such an application, you would need to write a service for each of them and then run them as well. A better way to organize such related services is using a stack. A stack allows you to define and deploy multi-service applications as a single, cohesive unit. Instead of deploying individual services one by one, a stack bundles all related services, networks, and volumes into a single YAML file. The Docker Swarm manager reads this file and orchestrates the deployment of all defined services, creating necessary networks, and scaling services to the specified number of replicas across the swarm (cluster).

Next let us see how the nodes communicate within the swarm. Docker provides multiple network types or drivers. These include:

1.    Bridge Network (Default): When you run a container without specifying a network, it attaches to the default bridge network. Containers on the same bridge network can communicate, and they can reach the outside world via the host's network. Each container gets its own IP address on this private bridge network.

2.    Host Network: The container shares the host's network stack, meaning it doesn't get its own IP address and uses the host's network interfaces directly. This removes network isolation between the container and the host.

3.    None Network: The container is completely isolated from the network. It has no network interfaces.

4.    Overlay Network: Overlay networks enable communication between containers running on different Docker hosts. They create a distributed network across multiple machines, allowing containers to behave as if they are on the same local network, facilitating service discovery and load balancing across the cluster.

5.    Macvlan Network: Allows you to assign a MAC address to a container, making it appear as a physical device on your network.

As you might have guessed from the description, Docker Swarm leverages overlay networks to enable seamless communication between containers across different nodes in the swarm. When you create a service, you can attach it to one or more overlay networks, allowing its tasks to communicate with other services on the same network using service names. 

Docker Swarm Flow

The connection between cluster manager nodes and worker nodes occurs through tokens. The docker swarm init command when run on a manager node outputs the token. Then, the worker nodes can use this token to join the cluster or swarm using the docker swarm join command.

 

Then, the application is defined as a service or a stack of services using the docker service and docker stack command respectively. The manager node receives the service definition and intelligently schedules the tasks (container instances) on available worker nodes, considering resource availability and any specified constraints. The manager continuously monitors the state of the swarm. If a task (container) fails or a node becomes unresponsive, the manager detects the deviation from the desired state and takes corrective action (e.g., rescheduling the task on a healthy node). When a service is exposed, Swarm provides internal DNS-based service discovery and load balancing. Requests to a service name are automatically distributed across its running tasks. Swarm also supports ingress load balancing for external access.  

A Real-Life Use Case

Let us see how the flow discussed above would apply in a real-life project. Consider a common web application consisting of a front-end web server, a back-end API, and a database. We can deploy this entire application using Docker Swarm as a single stack for scalability and high availability. As we discussed, each individual component would be defined as a service first. In this scenario, we would have the following services:

·       A service for the frontend serving the user interface.

·       An API service for the backed providing RESTful APIs.

·       A database service for storing application data (like users, products, etc).

·       A caching service that could use technologies like Redis.

These services can be combined as a stack and defined in a YAML file. Then, the swarm is initialized on the manager node.

Figure 1: Docker Swarm Init Command

 

 Using the token generated, the worker nodes (say 3 in this case) join the swarm. Then, using the docker stack deploy along with the stack YAML file as its argument, the services are deployed. Docker Swarm creates the four services described above based on the stack file.

Figure 2: Docker Swarm Stack Definition

 

In the stack file, we also specify the number of replicas or instances required for each service at all times. Docker Swarm ensures that the same number of instances are always running across the swarm. If a container crashes or a node fails, Swarm automatically starts new instances on healthy nodes.

Figure 3: Docker Swarm Stack Deploy

 

Similarly, we can also specify the networks to be created, and which service connects to which network. Docker Swarm creates the overlay networks allowing the services in the same network to communicate with each other.

Updating a component, like the image used by a service is as easy as changing the property in the stack YAML file and deploying the stack again. Docker Swarm handles the replacement process for the containers.

Orchestration in CI/CD Pipelines

Continuous Integration (CI) and Continuous Delivery/Deployment (CD) are modern software development practices that automate the building, testing, and deployment of applications. Integrating Docker Swarm with a CI/CD pipeline, using tools like GitHub Actions, significantly streamlines the entire software delivery lifecycle for containerized applications.

Workflows are defined in GitHub actions using YAML files stored in the .github/workflows directory in the application repository. Whenever developers push to the repository, a GitHub Actions job checks out the latest code. It uses actions like docker/build-push-action to build new Docker images for the updated services. For example, if the API code changed, a new Docker image is built. Automated unit tests, integration tests, and even end-to-end tests are run against these containers. If any tests fail, the GitHub Actions workflow stops, and developers are notified immediately via GitHub's UI, email, or integrated messaging services. If all tests pass, the validated Docker images are pushed to a Docker Registry (e.g., Docker Hub, Google Container Registry, Amazon ECR, a private registry). This makes the images accessible to your Docker Swarm nodes. Once images are successfully pushed to the registry, a deployment job in the GitHub Actions workflow is triggered. This job connects to a Docker Swarm manager node. It then executes the docker stack deploy command on the remote manager node, pointing to the service stack YAML file (which should reference the newly tagged images from the registry). Docker Swarm pulls the new images and orchestrates a rolling update of the services, replacing old containers with new ones. 

Conclusion

I hope this brief look at the working of Docker Swarm helper you understand the core concepts of container orchestration. Container orchestration is an indispensable component of modern cloud-native architectures. By automating the deployment, scaling, and management of containers, it empowers organizations to build resilient, scalable, and highly available applications. I encourage you to explore the other orchestration tools as well. While Docker Swarm offers significant advantages for many use cases, Kubernetes stands as the industry standard for more complex, large-scale deployments, providing a broader range of advanced features and extensibility. Ultimately, understanding these powerful orchestration technologies is crucial for anyone looking to efficiently manage and operate containerized workloads in production environments, driving agility and innovation in modern software development.



Implemented and written by Mr. Karthik Chandrasekhar, IV year student at VIT Chennai. 

Comments

Popular posts from this blog

BUILDING DOCKER IMAGES

CONTAINERISING A BACK-END WEB APPLICATION USING DOCKER COMPOSE

RUNNING A PROGRAM USING DOCKER AND COMPOSE