Aller au contenu principal

Bonnes pratiques Portainer


Objectifs du chapitre

  • Sécuriser votre installation Portainer
  • Optimiser les performances
  • Configurer la haute disponibilité
  • Mettre en place le monitoring

1 - Sécurité

Sécuriser l'accès

HTTPS obligatoire

# Avec certificat Let's Encrypt via Traefik
docker run -d \
--name portainer \
-v portainer_data:/data \
-v /var/run/docker.sock:/var/run/docker.sock \
portainer/portainer-ce:latest

# Ou avec certificat personnalisé
docker run -d \
-p 9443:9443 \
-v /path/to/certs:/certs \
-v portainer_data:/data \
-v /var/run/docker.sock:/var/run/docker.sock \
portainer/portainer-ce:latest \
--ssl --sslcert /certs/cert.pem --sslkey /certs/key.pem

Firewall

# Limiter l'accès au port Portainer
ufw allow from 192.168.1.0/24 to any port 9443
ufw allow from 10.0.0.0/8 to any port 9001 # Agent

Protection du socket Docker

┌─────────────────────────────────────────────────────────────────┐
│ Options de sécurité socket │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Option 1: Socket direct (développement) │
│ -v /var/run/docker.sock:/var/run/docker.sock │
│ ⚠️ Accès root complet au daemon Docker │
│ │
│ Option 2: Agent Portainer (recommandé production) │
│ Agent sur chaque hôte, socket isolé │
│ ✅ Meilleure isolation │
│ │
│ Option 3: TLS mutual auth │
│ Socket exposé via TCP avec certificats │
│ ✅ Authentification forte │
│ │
└─────────────────────────────────────────────────────────────────┘

Politique de mots de passe

CritèreRecommandation
LongueurMinimum 12 caractères
ComplexitéMajuscules, minuscules, chiffres, symboles
ExpirationRotation tous les 90 jours
HistoriqueInterdire les 5 derniers mots de passe

2 - Configuration de production

Variables d'environnement

docker run -d \
--name portainer \
-p 9443:9443 \
-e HIDE_CONFIGURATION_FIELDS=enable \
-e NO_ANALYTICS=1 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:latest
VariableDescription
NO_ANALYTICSDésactiver la télémétrie
HIDE_CONFIGURATION_FIELDSCacher les mots de passe
ADMIN_PASSWORDDéfinir le mot de passe admin au démarrage

Limites de ressources

# docker-compose.yml
services:
portainer:
image: portainer/portainer-ce:latest
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.25'
memory: 128M
restart: unless-stopped

3 - Haute disponibilité

Architecture HA

┌─────────────────────────────────────────────────────────────────┐
│ High Availability Setup │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ │
│ │ Load Balancer │ │
│ │ (HAProxy/ │ │
│ │ Traefik) │ │
│ └────────┬────────┘ │
│ │ │
│ ┌──────────────┼──────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ Portainer │ │ Portainer │ │ Portainer │ │
│ │ Node 1 │ │ Node 2 │ │ Node 3 │ │
│ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │
│ │ │ │ │
│ └──────────────┼──────────────┘ │
│ │ │
│ ┌───────▼───────┐ │
│ │ Shared Volume │ │
│ │ (NFS/EFS) │ │
│ └───────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘

Déploiement Swarm HA

# portainer-ha.yml
version: "3.9"

services:
portainer:
image: portainer/portainer-ce:latest
command: -H tcp://tasks.agent:9001 --tlsskipverify
volumes:
- portainer_data:/data
networks:
- agent_network
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.role == manager
update_config:
parallelism: 1
delay: 10s
failure_action: rollback

agent:
image: portainer/agent:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker/volumes:/var/lib/docker/volumes
networks:
- agent_network
deploy:
mode: global

networks:
agent_network:
driver: overlay
attachable: true

volumes:
portainer_data:
driver: local
driver_opts:
type: nfs
o: addr=nfs-server,rw
device: ":/portainer"

4 - Backup et restore

Sauvegarder les données

# Arrêter Portainer
docker stop portainer

# Sauvegarder le volume
docker run --rm \
-v portainer_data:/data \
-v $(pwd):/backup \
alpine tar czf /backup/portainer-backup-$(date +%Y%m%d).tar.gz /data

# Redémarrer Portainer
docker start portainer

Script de backup automatique

#!/bin/bash
# backup-portainer.sh

BACKUP_DIR=/backups/portainer
RETENTION_DAYS=30
DATE=$(date +%Y%m%d_%H%M%S)

# Créer le backup
docker run --rm \
-v portainer_data:/data \
-v $BACKUP_DIR:/backup \
alpine tar czf /backup/portainer-$DATE.tar.gz /data

# Nettoyer les anciens backups
find $BACKUP_DIR -name "portainer-*.tar.gz" -mtime +$RETENTION_DAYS -delete

echo "Backup completed: portainer-$DATE.tar.gz"

Restaurer

# Arrêter Portainer
docker stop portainer

# Supprimer les anciennes données
docker run --rm -v portainer_data:/data alpine rm -rf /data/*

# Restaurer
docker run --rm \
-v portainer_data:/data \
-v $(pwd):/backup \
alpine tar xzf /backup/portainer-backup.tar.gz -C /

# Redémarrer
docker start portainer

5 - Monitoring de Portainer

Healthcheck

services:
portainer:
image: portainer/portainer-ce:latest
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:9000/api/status"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s

Métriques Prometheus

Portainer expose des métriques sur /api/endpoints/{id}/docker/info :

# prometheus.yml
scrape_configs:
- job_name: 'portainer'
static_configs:
- targets: ['portainer:9000']
metrics_path: /api/system/status
bearer_token: 'your-api-token'

Dashboard Grafana

┌─────────────────────────────────────────────────────────────────┐
│ Portainer Monitoring Dashboard │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Environments │ │ Containers │ │ Stacks │ │
│ │ 3 │ │ 47 │ │ 12 │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Portainer Uptime │ │
│ │ ████████████████████████████████████████████ 99.9% │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ API Response Time │ │
│ │ ▁▂▃▂▁▂▃▄▃▂▁▂▃▂▁ avg: 45ms │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘

6 - API et automatisation

Générer un token API

  1. Settings > API > Add access token
  2. Nommer le token
  3. Copier et stocker de manière sécurisée

Utilisation de l'API

# Obtenir la liste des environnements
curl -s -H "X-API-Key: ptr_xxxx" \
https://portainer.example.com/api/endpoints

# Lister les conteneurs
curl -s -H "X-API-Key: ptr_xxxx" \
https://portainer.example.com/api/endpoints/1/docker/containers/json

# Démarrer un conteneur
curl -X POST -H "X-API-Key: ptr_xxxx" \
https://portainer.example.com/api/endpoints/1/docker/containers/abc123/start

Script d'automatisation

#!/usr/bin/env python3
import requests

PORTAINER_URL = "https://portainer.example.com"
API_KEY = "ptr_xxxxxxxxxxxx"

headers = {"X-API-Key": API_KEY}

# Lister les conteneurs arrêtés
response = requests.get(
f"{PORTAINER_URL}/api/endpoints/1/docker/containers/json",
headers=headers,
params={"all": True, "filters": '{"status": ["exited"]}'}
)

stopped = response.json()
print(f"Found {len(stopped)} stopped containers")

# Nettoyer les conteneurs arrêtés depuis plus de 7 jours
for container in stopped:
# ... logique de nettoyage
pass

7 - Checklist de production

Avant le déploiement

☐ HTTPS configuré avec certificat valide
☐ Mot de passe admin fort défini
☐ Authentification externe configurée (OAuth/LDAP)
☐ Équipes et permissions définies
☐ Firewall configuré (ports 9443, 9001)
☐ Backups automatisés
☐ Monitoring en place

Configuration

☐ Variables d'environnement de production
☐ Limites de ressources définies
☐ Restart policy configurée
☐ Logs centralisés
☐ Analytics désactivé (NO_ANALYTICS=1)

Sécurité

☐ Socket Docker protégé ou agent utilisé
☐ Edge agents pour environnements distants
☐ Audit logs activé (Business Edition)
☐ Sessions timeout configuré
☐ 2FA activé si disponible

8 - Dépannage courant

Portainer ne démarre pas

# Vérifier les logs
docker logs portainer

# Vérifier les permissions du socket
ls -la /var/run/docker.sock

# Réinitialiser les données (perd la configuration)
docker volume rm portainer_data
docker volume create portainer_data

Connexion refusée

# Vérifier que le conteneur tourne
docker ps | grep portainer

# Vérifier les ports
docker port portainer

# Tester la connectivité locale
curl -k https://localhost:9443

Réinitialiser le mot de passe

docker stop portainer

docker run --rm \
-v portainer_data:/data \
portainer/helper-reset-password

docker start portainer

Agent ne se connecte pas

# Vérifier que l'agent tourne
docker ps | grep portainer_agent

# Vérifier les logs de l'agent
docker logs portainer_agent

# Vérifier la connectivité réseau
telnet <portainer_ip> 9001

Résumé

AspectRecommandation
HTTPSObligatoire avec certificat valide
AuthOAuth/LDAP en production
SocketUtiliser l'agent plutôt que le socket direct
BackupQuotidien avec rétention 30 jours
MonitoringHealthcheck + métriques Prometheus
APITokens pour l'automatisation
Points clés
  • Sécurisez toujours l'accès avec HTTPS
  • Utilisez l'agent pour les environnements de production
  • Automatisez les backups
  • Mettez en place le monitoring
  • Utilisez l'API pour l'automatisation

Exercices pratiques

  1. Configurez HTTPS avec un certificat Let's Encrypt
  2. Mettez en place un backup automatique quotidien
  3. Configurez le healthcheck pour monitoring
  4. Créez un script API pour lister les ressources

← Utilisateurs et RBAC | Exercices et projets →