Utilisation de Docker Compose
Introduction
Préparation
Comme pour la construction d'image, Docker compose a besoin d'un répertoire, d'un fichier de configuration (compose.yaml) et de ressources afin de déployer une application. Attention : dans un fichier YAML, l'indentation (assurée par deux espaces) marque les relations père-fils entre les paramètres.
## Créer un répertoire et le choisir
mkdir movies-app
cd movies-app
## Créer le fichier compose.yaml
cat > compose.yaml <<FIN
name: movies-app
# Cette application sera composée de trois parties
include:
- database.yaml
- web.yaml
- front.yaml
# La partie réseau pour connecter les parties
networks:
mynet:
driver: bridge
FIN
## Les trois parties sont vides
cat /dev/null > database.yaml
cat /dev/null > web.yaml
cat /dev/null > front.yaml
Nous allons utiliser les commandes docker compose build pour construire (mais il n'y a rien à construire), docker compose ps pour lister (mais rien à lister) et docker compose rm pour supprimer (idem).
## Construire les images docker compose build ## Lister les services docker compose ps ## Stopper les services docker compose rm --stop --force
La partie données
Nous allons ajouter une base de données à notre application. Nous retrouvons les paramètres que nous utilisions sur la ligne de commande dans les exercices précédents.
## Créer un répertoire pour la DB
mkdir -p /var/movies/db
## Créer le fichier database.yaml
cat > database.yaml <<FIN
services: ## Définition des services
## La partie données
database:
image: mysql
## Toujours redémarrer
restart: always
## Les paramètres de ma BD
environment:
MYSQL_ROOT_PASSWORD: rootpasswd
MYSQL_USER: moviesuser
MYSQL_PASSWORD: moviespass
MYSQL_DATABASE: moviesdb
## Pour pérenniser les données dans /var/movies/db
volumes:
- /var/movies/db:/var/lib/mysql
## Pour communiquer avec les autres conteneurs
## qui sont dans le même réseau.
networks:
- mynet
## Pour tester l'état de ma BD
healthcheck:
test: /usr/bin/mysql --user=root --password=rootpasswd \
--execute "SHOW DATABASES;"
interval: 2s
timeout: 20s
retries: 100
FIN
Utilisons maintenant docker compose up pour démarrer notre application.
## Lancer les services et attendre le statut healthy docker compose up -d --wait --build ## Lister les services docker compose ps ## Attendre les services - normalement inutile wait-for-healthy-container movies-app-database-1 600 ## Stopper les services docker compose rm --stop --force
La partie WEB
Continuons avec la partie WEB (deux instances de notre application Spring-Boot) :
## À faire dans le répertoire movies-app/
mkdir web
## Préparer le WAR dans le répertoire
wget http://tinyurl.com/jlmassat2/cca/spring-app.war -O web/spring-app.war
## Créer le script de démarrage
cat > web/start.sh <<FIN
exec &> \$MYAPP_LOG-\$(uname -n)
echo "DB_URL is \$MYAPP_DB_URL"
echo "DB_DRIVER is \$MYAPP_DB_DRIVER"
echo "DB_USER is \$MYAPP_DB_USER"
echo "DB_PASSWORD is \$MYAPP_DB_PASSWORD"
java \
-Dspring.datasource.driver-class-name=\$MYAPP_DB_DRIVER \
-Dspring.datasource.url=\$MYAPP_DB_URL \
-Dspring.jpa.generate-ddl=true \
-Dspring.jpa.hibernate.ddl-auto=update \
-Dspring.datasource.username=\$MYAPP_DB_USER \
-Dspring.datasource.password=\$MYAPP_DB_PASSWORD \
-jar spring-app.war
FIN
## Créer le dockerfile
cat > web/Dockerfile <<FIN
FROM my-java:latest
LABEL desc="My SpringBoot App with MySql"
WORKDIR /app
ENV MYAPP_DB_DRIVER="com.mysql.jdbc.Driver"
ENV MYAPP_DB_URL="jdbc:mysql://movies-app-database-1:3306/moviesdb"
ENV MYAPP_DB_USER="moviesuser"
ENV MYAPP_DB_PASSWORD="moviespass"
ENV MYAPP_LOG="/var/tmp/myapp.log"
ENV MYAPP_NAME="myapp"
COPY spring-app.war /app/spring-app.war
COPY start.sh /app/start.sh
EXPOSE 8081
ENTRYPOINT ["/bin/bash", "/app/start.sh"]
HEALTHCHECK --interval=4s --timeout=3s --retries=100 \
CMD curl -f http://localhost:8081/movies/ || exit 1
FIN
## Créer un répertoire pour les logs
mkdir -p /var/movies/logs
## Créer le dockerfile
cat > web.yaml <<FIN
services: ## Services definition
## Partie WEB
web:
build: web
## deux instances
scale: 2
expose:
- "8081"
restart: always
## Le WEB va attendre la BD
depends_on:
database:
condition: service_healthy
networks:
- mynet
## Pour ne pas perdre les traces
volumes:
- /var/movies/logs/:/var/tmp
FIN
## Lancer les services et attendre le statut healthy
docker compose up -d --wait --build
## Lister les services
docker compose ps
## Attendre les applications WEB - normalement inutile
wait-for-healthy-container movies-app-web-1 600
wait-for-healthy-container movies-app-web-2 600
## Tester les deux services
docker run --network movies-app_mynet almalinux \
curl -sL movies-app-web-1:8081 | fgrep '1983'
docker run --network movies-app_mynet almalinux \
curl -sL movies-app-web-2:8081 | fgrep '1983'
## Stopper les services
docker compose rm --stop --force
La partie Front Proxy
Nous avons deux applications WEB qui fonctionnent en parallèle mais il faut maintenant ajouter un proxy qui va assurer le rôle de répartition des accès (load-balancing). Nous allons utiliser HAProxy.
## Préparer les fichiers de configuration de HAProxy
wget http://tinyurl.com/jlmassat2/cca/proxy.zip
unzip proxy.zip
## Preparer le fichier front.yaml
cat > front.yaml <<FIN
# Services definition
services:
## La partie Proxy
proxy:
build: proxy/
ports:
- 8888:80
restart: always
networks:
- mynet
environment:
DOMAIN_NAME: idl.xfr
EMAIL_ADDRESS: root@idl.xfr
BACKEND1_URL: movies-app-web-1:8081
BACKEND2_URL: movies-app-web-2:8081
depends_on:
web:
condition: service_healthy
FIN
## Construire/Lancer/Attendre les services docker compose up -d --wait --build ## Lister les services docker compose ps
## Tester les services curl -L http://localhost:8888 | fgrep 'Star' ## Vérifier le round-robbin du proxy ## SERVERID doit indiquer une app. curl -i http://localhost:8888 ## SERVERID doit indiquer l'autre app. curl -i http://localhost:8888
## Stopper les services docker compose rm --stop --force