Thanks @oelmekki for your insights. It has been very useful and encouraging when there is so few info on rolling updates with docker-compose
.
I ended up writing the following script docker_update.sh <service_name>
, which seems to work very decently. It relies on healthcheck
command, which is not mandatory (change -f "health=healthy"
accordingly) but cleaner IMHO than waiting for container to simply being up, when it takes a little time to boot (which will be the case if you run eg. npm install && npm start
as a command).
#!/bin/bash
cd "$(dirname "$0")/.."
SERVICE_NAME=${1?"Usage: docker_update <SERVICE_NAME>"}
echo "[INIT] Updating docker service $SERVICE_NAME"
OLD_CONTAINER_ID=$(docker ps --format "table {{.ID}} {{.Names}} {{.CreatedAt}}" | grep $SERVICE_NAME | tail -n 1 | awk -F " " '{print $1}')
OLD_CONTAINER_NAME=$(docker ps --format "table {{.ID}} {{.Names}} {{.CreatedAt}}" | grep $SERVICE_NAME | tail -n 1 | awk -F " " '{print $2}')
echo "[INIT] Scaling $SERVICE_NAME up"
docker-compose up -d --no-deps --scale $SERVICE_NAME=2 --no-recreate $SERVICE_NAME
NEW_CONTAINER_ID=$(docker ps --filter="since=$OLD_CONTAINER_NAME" --format "table {{.ID}} {{.Names}} {{.CreatedAt}}" | grep $SERVICE_NAME | tail -n 1 | awk -F " " '{print $1}')
NEW_CONTAINER_NAME=$(docker ps --filter="since=$OLD_CONTAINER_NAME" --format "table {{.ID}} {{.Names}} {{.CreatedAt}}" | grep $SERVICE_NAME | tail -n 1 | awk -F " " '{print $2}')
until [[ $(docker ps -a -f "id=$NEW_CONTAINER_ID" -f "health=healthy" -q) ]]; do
echo -ne "\r[WAIT] New instance $NEW_CONTAINER_NAME is not healthy yet ...";
sleep 1
done
echo ""
echo "[DONE] $NEW_CONTAINER_NAME is ready!"
echo "[DONE] Restarting nginx..."
docker-compose restart nginx
echo -n "[INIT] Killing $OLD_CONTAINER_NAME: "
docker stop $OLD_CONTAINER_ID
until [[ $(docker ps -a -f "id=$OLD_CONTAINER_ID" -f "status=exited" -q) ]]; do
echo -ne "\r[WAIT] $OLD_CONTAINER_NAME is getting killed ..."
sleep 1
done
echo ""
echo "[DONE] $OLD_CONTAINER_NAME was stopped."
echo -n "[DONE] Removing $OLD_CONTAINER_NAME: "
docker rm -f $OLD_CONTAINER_ID
echo "[DONE] Scaling down"
docker-compose up -d --no-deps --scale $SERVICE_NAME=1 --no-recreate $SERVICE_NAME
And here's my docker-compose.yml
:
app:
build: .
command: /app/server.sh
healthcheck:
test: curl -sS http://127.0.0.1:4000 || exit 1
interval: 5s
timeout: 3s
retries: 3
start_period: 30s
volumes:
- ..:/app
working_dir: /app
nginx:
depends_on:
- app
image: nginx:latest
ports:
- "80:80"
volumes:
- "../nginx:/etc/nginx/conf.d"
- "/var/log/nginx:/var/log/nginx"
And my nginx.conf
:
upstream project_app {
server app:4000;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://project_app;
}
}
Hope it can be useful to some. I wish it would be integrated into docker-compose
by default.
thanks https://github.com/augnustin ref : docker/compose#1786 (comment)