Deploying a Docker Service Stack

Hey listen… docker is an open-source platform for building, shipping, and running distributed applications. It allows developers to package their applications and dependencies into lightweight containers that can run on other machine with Docker installed. Docker Swarm is Docker’s native clustering and orchestration feature that allows you to deploy and manage multiple Docker containers across a cluster of machines.

I’ll show the process of installing Docker on a Linux machine, configuring Swarm mode, create a docker image of a net core app service and deploying a simple stack service containing RabbitMQ, Redis and the created .NET Core API image.

Install Docker on a Linux Machine

The first step is to install Docker on your Linux. This can be done by updating your Linux machine’s package index, and then installing Docker using the appropriate package manager command. Once installed, you can verify that Docker is running by executing a command that checks its status.

I’m using Ubuntu 20.04, you’ll have to adapt commands to a different distro. Also, I’m using the official Docker package not the Docker package shipped with Ubuntu!

You MUST uninstall any docker related package shipped with your system. To do that simple run:

sudo apt remove docker.io docker-doc docker-compose podman-docker containerd runc

Now install some tools necessary to download and install repository security keys:

sudo apt update && sudo apt install ca-certificates curl gnupg tee

Add Docker’s official GPG keys:

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

Setup Docker’s official repositories:

echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Update your packages definitions:

sudo apt update

Install Docker using the following command:

sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

After installation, verify that Docker is running by executing the following command:

$ sudo systemctl status docker

You should see an output that shows Docker is active and running.

Now test Docker installation with:

sudo docker run hello-world

This command downloads a test image and runs it in a container. When the container runs, it prints a confirmation message and exits.

The Docker daemon binds to a Unix socket, not a TCP port. By default it’s the root user that owns the Unix socket, and other users can only access it using sudo. The Docker daemon always runs as the root user.

If you don’t want to preface the docker command with sudo, create a Unix group called docker and add users to it. When the Docker daemon starts, it creates a Unix socket accessible by members of the docker group. On some Linux distributions, the system automatically creates this group when installing Docker Engine using a package manager (like Ubuntu). In that case, there is no need for you to manually create the group.

The docker group grants root-level privileges to the user. For details on how this impacts security in your system, see Docker Daemon Attack Surface.

If you don’t want to use sudo when dealing with docker, add your user to the docker group:

sudo usermod -aG docker $MYUSER

You have to log out and log back in so that your group membership is re-evaluated.

Configure Docker Swarm Mode

Swarm mode is Docker’s native clustering and orchestration feature that allows you to deploy and manage multiple Docker containers across a cluster of machines. Initializing Docker Swarm mode is a simple process that involves running a command to initialize the swarm.

Initialize Docker Swarm mode by executing the following command:

$ docker swarm init

You can add machines to the swarm (the cluster) by asking a token to the main manager (this machine where you just installed docker and enabled the swarm mode) with one of these commands:

To add a manager node (a machine which will manage and run services):

docker swarm join-token manager

To add a worker (a machine which will only run services):

docker swarm join-token worker

A command will be generated as output. You should run this command on the target machine that will join the cluster.

Create the DotNet Core Api Docker Image

This is a simple example and it will not communicate with rabbitmq nor redis. I’ll use the Weather Service (WeatherForecast) provided as API template by the dotnet new command.

To create a new net core project run:

mkdir -p MySolution/MyService && cd MySolution/MyService && dotnet new webapi -f netcoreapp3.1

This will create a functional API service and you can test it by running the command:

dotnet run

The command will output the port (usually 5000) and spawn the service.

In order to create a Docker image for the API service, we need to create a Dockerfile file, in the same directory of your code, with the following content.

FROM mcr.microsoft.com/dotnet/aspnet:3.1 AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:3.1 AS build
WORKDIR /src
COPY ["MyService/MyService.csproj", "MyService/"]
RUN dotnet restore "MyService/MyService.csproj"
COPY . .
WORKDIR "/src/MyService"
RUN dotnet build "MyService.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "MyService.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MyService.dll"]

Now build the image by running this command at the same folder where you created the Dockerfile file:

docker build -f Dockerfile -t myservice ../

This command will create a docker image with your service and tag it with the name myservice.

To run the image execute this command:

docker run --rm -it -p 5000:80 myservice

This will create a container running your service at TCP port 5000.

To exit the container press CTRL+C (this will also remove the container due to the --rm parameter)

To test your service execute this command:

curl -k "http://localhost:5000/WeatherForecast"

The output should be a JSON array like this one:

[{"date":"2023-06-26T02:38:04.4264349+00:00","temperatureC":43,"temperatureF":109,"summary":"Scorching"},{"date":"2023-06-27T02:38:04.4264852+00:00","temperatureC":-5,"temperatureF":24,"summary":"Cool"},{"date":"2023-06-28T02:38:04.4264862+00:00","temperatureC":51,"temperatureF":123,"summary":"Cool"},{"date":"2023-06-29T02:38:04.4264867+00:00","temperatureC":22,"temperatureF":71,"summary":"Cool"},{"date":"2023-06-30T02:38:04.4264872+00:00","temperatureC":-3,"temperatureF":27,"summary":"Warm"}]

Deploy the Stack Service

Now that Swarm mode is configured and we have a functional docker image of our API service, we can deploy the stack service containing RabbitMQ, Redis, and the NetCore Forecast Service API. This involves creating a docker-compose.yml file that defines the services and then deploying the stack service using docker command line tools.

Create a file named docker-compose.yml and add the following content:

version: '3.7'

services:
  rabbitmq:
    image: rabbitmq:3-management
    networks:
      - my-net
    ports:
      - "15672:15672"
      - "5672:5672"
    deploy:
      replicas: 1

  redis:
    image: redis
    networks:
      - my-net
    ports:
      - "6379:6379"
    deploy:
      replicas: 1

  api:
    image: myservice
    networks:
      - my-net
    ports:
      - "5000:80"
    deploy:
      replicas: 2

networks:
  my-net:
    driver: overlay

This file describe all the services docker will create and how they interact with each other. The deploy.replicas property define how many instances of each service will be created. The networks section defines the overlay network to be used by the services.

The overlay network driver creates a distributed network among multiple Docker daemon hosts. This network sits on top of (overlays) the host-specific networks, allowing containers connected to it (including swarm service containers) to communicate securely when encryption is enabled. Docker transparently handles routing of each packet to and from the correct Docker daemon host and the correct destination container.

Deploy the stack service using the following command:

docker stack deploy -c docker-compose.yml my-stack

Verify that the stack service is running by executing the following command:

docker stack ps my-stack

You should see an output that shows the status of each service in the stack.

After deploying the stack service, you may want to scale the .NET Core application to handle increased traffic. Scaling the service in Swarm mode is a simple process that does not require restarting the stack. Here’s how you can do it:

Check the current number of replicas for the api service by executing the following command:

docker service ls

You should see an output that shows the number of replicas currently running for each service in the stack.

Scale the api service by executing the following command:

docker service scale my-stack_api=4

This command scales the api service to four replicas. You can replace 4 with any number of replicas you want to run.

Verify that the api service has been scaled by executing the following command:

docker service ls

You should see an output that shows the updated number of replicas for the api service.

Scaling the service in Swarm mode is as simple as that! Docker Swarm will automatically distribute the workload among the available replicas, allowing you to handle increased traffic without having to restart the stack.

Conclusion

Docker and Docker Swarm make it easy to build, ship, and run distributed applications. Scaling services in Swarm mode is a simple process that does not require restarting the stack. By following the steps outlined in this article, you can easily install docker, configure the swarm mode, create images, create service stacks and scale up or down services to handle demand, balance cost and response time.

That’s all folks!

Author: raffs

I am a computer engineer with more than 10 years of experience in programming, currently working as a software architect.

Leave a Reply

Your email address will not be published. Required fields are marked *