Docker Config, how to always use base image with Docker Swarm!
Remember last time you say "It's a really awesome image ٩(◕‿◕。)۶ ! But I need only to change one thing in the configuration, and I make a new image, a new git repository, a build process, and push my new image to a registry (╥_╥)"
Now (ok, a few months ago), it's possible with Docker Swarm to just add a configuration to your image!
Let's try it with Prometheus, a monitoring system and time series database.
Prometheus scrape an endpoint and store the metric in the internal time series database. But, when you add a new service, you need to change the Prometheus configuration for adding it. Who says changing a configuration, says recreating an image.
But, no more!
This is the basic docker-compose file that we will change for adding the new configuration without changing the base image:
# prometheus.yml
version: "3.4"
services:
prometheus:
image: prom/prometheus:v2.2.0
networks:
- monitoring
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--web.console.libraries=/etc/prometheus/console_libraries'
- '--web.console.templates=/etc/prometheus/consoles'
- '--storage.tsdb.path=/prometheus'
- '--storage.tsdb.retention=24h'
Note: Docker configs are only available to swarm services, not to standalone containers. To use this feature, consider adapting your container to run as a service with a scale of 1.
Adding a configuration to your container
For adding a configuration to Docker, we can create it by hand with docker config create <config name> <file name or stdin>
and use the configuration name in our docker-compose file or we can manage it directly inside the docker-compose file:
version: "3.4"
configs:
<config name>:
file: <file name>
external: true|false # If the configuration was created outside this docker-compose
# file, we need to set it to true
services:
<service name>:
configs:
- source: <config name from before>
target: <path inside the container where the configuration will be mounted>
Now, if we update our previous stack:
# prometheus.yml
version: "3.4"
configs:
prometheus_config:
file: ./prometheus.yml
services:
prometheus:
[...]
configs:
- source: prometheus_config
target: /etc/prometheus/prometheus.yml
Rotate a configuration
Keep in mind that configurations are immutable, so you can’t change the file for an existing service. Instead, you create a new configuration to use.
Why? Because with an immutable configuration, you can be sure that all your containers inside a service always have the same configuration, and this gives you the opportunity to change it everywhere at once.
To rotate a service, you need to:
- create a new configuration with a different name
- update the service by removing the old config
- add the new one to your service and use the same mount point
You can do this by using the cli:
$ docker service update \
--config-rm prometheus_config \
--config-add source=prometheus_config_v2,target=/etc/prometheus/prometheus.yml \
<stack-name>_prometheus
Or by updating the compose file and by redeploying the stack:
# prometheus.yml
version: "3.4"
configs:
- prometheus_config:
+ prometheus_config_v2:
file: ./prometheus.yml
services:
prometheus:
[...]
configs:
- - source: prometheus_config
+ - source: prometheus_config_v2
target: /etc/prometheus/prometheus.yml
$ docker stack deploy -c prometheus.yml <stack-name>
Conclusion
With Docker Configuration, you have a lot of base image that you can use without building and maintain a custom image like nginx
, prometheus
.
If you want to learn more about Docker configuration, you have a complete guide available within the docker documentation: Store configuration data using Docker Configs
If you find a typo, have a problem when trying what you see in this article, please contact me!