SaltStack on Your VPS Series
Part 5 of 6
Docker & Container Management with Salt
Install Docker via Salt, manage containers as state, deploy Compose stacks, and automate cleanup across your fleet.
35 minutes
Installing Docker via Salt States
/srv/salt/docker/install.sls
remove_old_docker:
pkg.removed:
- pkgs:
- docker
- docker-engine
- docker.io
- containerd
- runc
docker_prerequisites:
pkg.installed:
- pkgs:
- ca-certificates
- curl
- gnupg
- lsb-release
docker_gpg_key:
cmd.run:
- name: |
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
- creates: /usr/share/keyrings/docker-archive-keyring.gpg
docker_packages:
pkg.installed:
- pkgs:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-buildx-plugin
- docker-compose-plugin
docker_service:
service.running:
- name: docker
- enable: True
- require:
- pkg: docker_packagesDocker Daemon Configuration
/srv/salt/docker/files/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"storage-driver": "overlay2",
"live-restore": true,
"userland-proxy": false
}Key settings: log-opts prevents logs from consuming all disk, live-restore keeps containers running during daemon upgrades.
Docker Group Users
/srv/salt/docker/users.sls
{% set docker_users = pillar.get('docker:users', []) %}
{% for username in docker_users %}
add_{{ username }}_to_docker:
user.present:
- name: {{ username }}
- groups:
- docker
- require:
- pkg: docker_packages
{% endfor %}Managing Containers
Ad-hoc Commands
sudo salt 'web-01' docker.ps
sudo salt 'web-01' docker.pull nginx:alpine
sudo salt 'web-01' docker.images
sudo salt 'web-01' docker.logs nginx-testDeclarative Container State
nginx_image:
docker_image.present:
- name: nginx:1.25-alpine
nginx_container:
docker_container.running:
- name: nginx-app
- image: nginx:1.25-alpine
- detach: True
- restart_policy: always
- port_bindings:
- 80:80
- 443:443
- binds:
- /var/www/html:/usr/share/nginx/html:ro
- require:
- docker_image: nginx_imageDocker Compose Stacks
/srv/salt/docker/compose.sls
compose_directory:
file.directory:
- name: /opt/apps/myapp
- user: deploy
- group: docker
- mode: '0755'
- makedirs: True
myapp_compose_file:
file.managed:
- name: /opt/apps/myapp/docker-compose.yml
- source: salt://docker/files/myapp-compose.yml
- user: deploy
- group: docker
myapp_env_file:
file.managed:
- name: /opt/apps/myapp/.env
- source: salt://docker/files/myapp.env
- mode: '0600'
myapp_up:
cmd.run:
- name: docker compose up -d --remove-orphans
- cwd: /opt/apps/myapp
- onchanges:
- file: myapp_compose_file
- file: myapp_env_fileNetworks & Volumes
myapp_network:
docker_network.present:
- name: myapp_network
- driver: bridge
db_data_volume:
docker_volume.present:
- name: myapp_db_data
- driver: localAutomated Image Updates
{% set images = pillar.get('docker:managed_images', []) %}
{% for image in images %}
pull_{{ image | replace('/', '_') | replace(':', '_') }}:
docker_image.present:
- name: {{ image }}
- force: True
{% endfor %}sudo salt -G 'role:webserver' state.apply docker.updateContainer Health Monitoring
sudo salt 'web-*' cmd.run 'docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"'
sudo salt 'web-*' cmd.run 'docker ps --filter health=unhealthy --format "{{.Names}}"'
sudo salt 'web-*' cmd.run 'docker system df'Cleanup States
/srv/salt/docker/cleanup.sls
docker_prune_cron:
cron.present:
- name: docker system prune -f --filter "until=168h"
- user: root
- minute: 0
- hour: 3
- dayweek: 0
- comment: Weekly Docker resource cleanup
docker_prune_images:
cmd.run:
- name: docker image prune -f
- onlyif: test $(docker images -f dangling=true -q | wc -l) -gt 10Combining LAMP & Docker
Run Nginx on the host as a reverse proxy with Dockerized application containers behind it:
# top.sls
base:
'web-*':
- lamp.webserver # host Nginx as reverse proxy
- docker # Docker for app containers
- lamp.vhost # vhost configs pointing to container portsNginx reverse proxy to container
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}What's Next
Docker is now fully managed by Salt. In the final part, we cover Pillars for secrets management, Grains for advanced targeting, orchestration for sequenced deployments, and security hardening states for every server.
