Systèmes de contrôle et automatisation
Déployer des conteneurs Docker avec Systemd pour le démarrage automatisé
Table of Contents
Pourquoi combiner Systemd avec Docker pour les déploiements de production
L'infrastructure moderne exige que les services conteneurisés survivent à des remises en question inattendues, des défaillances matérielles ou des mises à jour de paquets. Alors que Docker fournit des politiques de redémarrage ([), ces politiques ne fonctionnent que tant que le démon Docker est en marche. Systemd – le système init utilisé par Ubuntu, Debian, Fedora, CentOS et la plupart des distributions Linux modernes – prend cette mesure en gérant le cycle de vie du démon Docker lui-même et peut démarrer des conteneurs même avant que la socket Docker ne devienne disponible.
- Commande de démarrage garantie par des directives de dépendance (par exemple, après network.target, après docker.service)
- Enregistrement unifié via , rendant le débogage simple
- Contrôle fin des limites de ressources (CPU, mémoire, E/S) en utilisant les directives d'unité système
- Redémarrage automatique en cas de panne avec limite de retard et d'éclatement configurable
- Prise en charge de l'activation de la socket et du démarrage timed
En installant chaque conteneur Docker dans un fichier de service système, les équipes d'exploitation acquièrent une interface cohérente pour le démarrage, l'arrêt et la surveillance des conteneurs, réduisant ainsi la dépendance à l'égard des scripts ad-hoc et de l'intervention manuelle.
Création d'un service systémique pour un conteneur Docker unique
L'approche standard consiste à écrire un fichier d'unité de service qui appelle les commandes Docker pour exécuter et arrêter le conteneur. Ci-dessous, nous passons par le processus étape par étape, en commençant par un exemple de base et en couvrant ensuite les exigences de production communes.
Étape 1: Rédigez le fichier de l'unité de service
Créer un fichier nommé . Utilisez le modèle suivant comme point de départ :
[Unit]
Description=My Application Container
After=network-online.target docker.service
Wants=network-online.target
Requires=docker.service
[Service]
Restart=always
RestartSec=10
StartLimitBurst=3
ExecStartPre=-/usr/bin/docker kill myapp
ExecStartPre=-/usr/bin/docker rm myapp
ExecStart=/usr/bin/docker run --rm --name myapp \
-e DB_HOST=10.0.1.50 \
-e DB_PORT=5432 \
-v /data/myapp:/app/data \
-p 8080:8080 \
myregistry/myapp:latest
ExecStop=/usr/bin/docker stop -t 10 myapp
ExecStopPost=-/usr/bin/docker rm myapp
[Install]
WantedBy=multi-user.target
Explication des directives clés:
- – s'assure que le démon Docker est en marche avant de démarrer le conteneur.
- – si Docker est arrêté, ce service s'arrête également.
- – nettoie tout conteneur restant d'une opération précédente (le préfixe signifie que les défaillances ici sont non fatales).
- – utilise pour enlever automatiquement le conteneur lorsqu'il s'arrête.
- – arrête gracieusement le conteneur avec un délai d'arrêt (10 secondes).
- – redémarre le conteneur indépendamment du code de sortie.
- – attend 10 secondes avant de redémarrer.
- – limite les redémarrages à 3 tentatives par intervalle (par défaut 10 secondes) pour éviter les boucles de redémarrage.
Étape 2: Activer et démarrer le service
sudo systemctl daemon-reload
sudo systemctl enable myapp.service
sudo systemctl start myapp.service
Le dit à systemd de relire les fichiers de service. crée le lien symbolique, donc le service démarre sur le démarrage.
Gestion du service avec les commandes standard système
Une fois le service en cours d'exécution, vous le contrôlez comme tout autre service système :
- Démarrage:
- Stop:
- Redémarrage:
- État:
- Logs: (suivre les journaux en direct)
Modèles de configuration avancés
Les déploiements de production nécessitent souvent plus qu'un simple . Voici des améliorations communes que vous pouvez ajouter à vos fichiers de service système.
Variables d'environnement de passage
Les secrets de codage dur ou la configuration dans le fichier de service n'est pas recommandée. Utilisez plutôt un fichier d'environnement séparé:
[Service]
EnvironmentFile=-/etc/myapp/env.conf
ExecStart=/usr/bin/docker run --rm --name myapp \
--env-file /etc/myapp/env.conf \
myregistry/myapp:latest
Le préfixe avant le chemin signifie que le service démarrera même si le fichier n'existe pas (utile lors de la configuration initiale).
Réseautage et liaisons portuaires
Pour les conteneurs qui doivent communiquer entre eux sur le même hôte, envisager d'utiliser ou des réseaux de ponts définis par l'utilisateur.
ExecStart=/usr/bin/docker run --rm --name web \
--network=my-net \
-p 443:443 \
-v /etc/ssl/certs:/etc/ssl/certs:ro \
myregistry/web:latest
Si vous utilisez un réseau personnalisé, assurez-vous que le réseau existe avant le début du service. Vous pouvez ajouter une commande pour le créer :
ExecStartPre=/usr/bin/docker network create my-net
Dépendances intercontainers
Lorsqu'un conteneur nécessite qu'un autre soit prêt avant de démarrer (par exemple, une application Web en attente d'une base de données), systemd peut faire exécuter la commande.
[Unit]
Description=Web App Container
After=network-online.target docker.service mydb.service
BindsTo=mydb.service
relie le cycle de vie de l'application web au conteneur de la base de données – si la base de données s'arrête, l'application web est également arrêtée.
Vérifications de la santé et préparation
Les contrôles de santé Docker peuvent être intégrés à un système pour empêcher la disponibilité prématurée des services. Utilisez avec un script qui permet de vérifier le critère de santé :
ExecStartPost=/usr/local/bin/wait-for-health.sh http://localhost:8080/health 30
Le script ne devrait sortir que lorsque le conteneur est sain. Si il échoue, systemd marque l'unité comme ayant échoué.
Limites de ressources via Systemd
Vous pouvez restreindre un conteneur CPU et mémoire au niveau cgroup sans les drapeaux de ressources propres de Docker. Ceci est particulièrement utile lors de l'exécution de plusieurs conteneurs sur un seul hôte:
[Service]
MemoryMax=512M
CPUQuota=50%
Ces paramètres créent une limite dure qui a été systématisée et qui est appliquée indépendamment de Docker.
Gestion de plusieurs conteneurs : Systemd vs Docker Compose
Pour un petit nombre de conteneurs (p. ex., 2-5), les fichiers de service système individuels sont simples et faciles à entretenir. Cependant, lorsqu'un projet implique de nombreux services interconnectés, Docker Compose devient plus pratique. Vous pouvez toujours utiliser systemd pour orchestrer la pile entière de Docker Compose en créant une unité de service unique qui appelle . Exemple :
[Unit]
Description=My Application Stack
After=network-online.target docker.service
Requires=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/myapp
ExecStart=/usr/local/bin/docker-compose up -d
ExecStop=/usr/local/bin/docker-compose down
[Install]
WantedBy=multi-user.target
Cette approche vous donne la simplicité de Compose pour définir des services combinés avec la gestion du cycle de vie systemd. Notez que est utilisé parce que sort immédiatement. maintient l'unité dans un état actif de --- jusqu'à ce que ] soit appelé.
Quelle méthode choisir ?
- Services individuels système[ – meilleurs pour les applications existantes, les services avec commande de démarrage stricte, ou lorsque vous avez besoin de limites de ressources par conteneur.
- Docker Compose avec systemd – idéal pour les piles de microservices où les dépendances sont gérées en interne par Compose, et vous voulez une unité unique pour gérer l'ensemble du groupe.
Dépannage de problèmes communs
Même avec une configuration soignée, vous pouvez rencontrer des problèmes. Ci-dessous sont les pièges fréquents et leurs solutions.
Fails de service avec - Impossible de se connecter au démon Docker
Cela signifie généralement que le service commence avant que la prise Docker soit prête. Assurez-vous que votre unité contient et . Vérifiez également que le démon Docker est activé: .
Conteneur Restarts dans une boucle
Si le conteneur sort immédiatement, systemd continuera à le redémarrer conformément à et . Vérifiez les journaux de conteneurs avec . Augmentez (par exemple, 30 secondes) et définissez pour éviter une boucle occupée.
Le service ne s'arrête pas proprement
Un mal configuré] peut laisser le conteneur tourner. Vérifier que utilise le nom du conteneur correct. Utilisez pour enlever le conteneur avec force si l'arrêt échoue.
Variables d'environnement non chargées
Si vous utilisez , confirmez que le fichier existe et est lisible par racine. Évitez de citer des problèmes – des bandes système de citations de valeurs variables. Pour une injection secrète, envisagez d'utiliser des identifiants système ou un gestionnaire secret dédié.
Considérations en matière de sécurité
La course des conteneurs Docker à travers systemd soulève quelques points de sécurité :
- Exécutez toujours le service système en tant qu'utilisateur non root si possible (utilisez les directives et , mais assurez-vous que l'utilisateur a accès à la socket Docker ou exécutez en mode rootless).
- Évitez d'utiliser dans les unités système sauf si cela est absolument nécessaire.
- Utilisez des supports de reliure en lecture seule () chaque fois que le conteneur n'a pas besoin d'écrire à l'hôte.
- Lever systemd , pour durcir l'unité contre les évasions.
[Service]
ProtectSystem=strict
ReadWritePaths=/var/log/myapp
PrivateTmp=true
User=myappuser
Ressources extérieures
Pour plus de détails, consulter les références officielles suivantes:
- Documentation des politiques de redémarrage de Docker
- Manuel de l'unité de service systémique
- Composition de la mousse
Conclusion
L'intégration de systèmes avec des conteneurs Docker vous donne un mécanisme de démarrage robuste et automatisé qui s'intègre parfaitement au reste de votre système Linux. En écrivant des fichiers d'unités de service bien structurés, vous pouvez contrôler l'ordre de démarrage, gérer les dépendances, définir les limites de ressources et surveiller les journaux en utilisant des outils que votre équipe d'exploitation connaît déjà. Que vous choisissiez des services individuels pour chaque conteneur ou une unité unique pour orchestrer une pile Compose, systemd fournit la fiabilité et la prévisibilité que les environnements de production exigent.
Commencez par un simple fichier unitaire, testez-le soigneusement, puis couchez sur des options avancées comme les fichiers d'environnement, les contrôles de santé et le durcissement de sécurité. Avec cette approche, vos conteneurs Docker survivront aux reboots, aux pannes et aux modifications de configuration sans intervention manuelle, libérant votre équipe de se concentrer sur les applications de construction.