Understanding How Docker Swarm Works
Docker Swarm Environment Variables and Secrets
Before we start, let's reset the cluster to its initial state. On the manager node, run:
# Export the hostname of the node you want to demote as an environment variable
export NODE_HOSTNAME=worker01
# Demote the manager node back to a worker node
docker node demote $NODE_HOSTNAME
# Check the status of the nodes
docker node ls
Let's also remove all previous services we created to start with a clean slate:
docker service rm $(docker service ls -q)
To better understand the use of environment variables and secrets in Docker Swarm, we will use MySQL as an example.
If you want to run MySQL as a standalone container using the official MySQL image, you usually run a command similar to the following:
docker run \
--name mysql \
-e MYSQL_DATABASE=wordpress \
-e MYSQL_USER=wordpress \
-e MYSQL_ROOT_PASSWORD=secret \
-d mysql:9.6.0
This will create a MySQL container with the following configuration, read from environment variables:
MYSQL_DATABASE: This is the name of the database that will be created.MYSQL_USER: This is the username of the database user.MYSQL_PASSWORD: This is the password of the database user.
To do the same thing in a Docker Swarm cluster, we need to create a service using the following command:
docker service create \
--name mysql \
-e MYSQL_DATABASE=wordpress \
-e MYSQL_USER=wordpress \
-e MYSQL_ROOT_PASSWORD=secret \
-d mysql:9.6.0
The problem here is that the password is stored in plain text in the command. You can see it if you run the following command:
docker service inspect mysql \
--format "{{json .Spec.TaskTemplate.ContainerSpec.Env}}"
# or
docker service inspect mysql --pretty | grep Env
A good practice is to avoid storing sensitive information in plain text. This is where Docker secrets come in.
Docker Secrets
Docker secrets are used to store sensitive information such as passwords, SSH keys, API keys, authentication tokens, and more. They're securely stored in an encrypted format on disk and in memory, and are only accessible to the services that require them.
To create a secret, we need to run the following command on the manager node:
echo "secret" | docker secret create mysql_root_password -
You can also store the secret in a file and create the secret using the following command:
# Create a file called mysql_root_password.txt and put the password in it
echo "secret" > mysql_root_password.txt
# Create the secret using the file
docker secret create mysql_root_password mysql_root_password.txt
To show the secret, run the following commands on the manager node:
# Show the list of secrets
docker secret ls
# Show the details of the secret
docker secret inspect mysql_root_password
To use the secret in a service, we need to run the following command:
# remove the previous service
docker service rm mysql
# create the new service with the secret
docker service create \
--name mysql \
--secret mysql_root_password \
-e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql_root_password \
-e MYSQL_DATABASE=wordpress \
-e MYSQL_USER=wordpress \
-d mysql:9.6.0
When you create a secret, it's stored in the in-memory filesystem of the container. The path to the secret is /run/secrets/. To check the content of the secret, use the following command (on a node where the MySQL container is running):
# Get the ID of the container running the MySQL service
container_id=$(docker ps -q -f name=mysql)
# Check the content of the secret
docker exec -it $container_id cat /run/secrets/mysql_root_password
The output should be secret, which is the content of the secret we created.
Note that secrets are only accessible to the services that require them and only for the duration of their active tasks.
In addition to MYSQL_ROOT_PASSWORD, the MySQL image also allows you to read the password from a file by utilizing the MYSQL_ROOT_PASSWORD_FILE environment variable. It's important to note that not all images support this feature. In case you need to use a secret with an image that doesn't support reading the password from a file, you can use a script at the container's entrypoint.
This script is an example of how you can read the secret from the file and set it as an environment variable.
#!/bin/bash
# Define the target directory where secrets are stored
secrets_dir="/run/secrets"
# List all secret files in the secrets directory
secret_files=$(ls -1 "$secrets_dir")
# Loop through each secret file and export it as an environment variable
for secret_file in $secret_files; do
# Get the secret name from the file namePainless Docker - 2nd Edition
A Comprehensive Guide to Mastering Docker and its EcosystemEnroll now to unlock all content and receive all future updates for free.
Hurry! This limited time offer ends in:
To redeem this offer, copy the coupon code below and apply it at checkout:
