Skip to content

Instantly share code, notes, and snippets.

@samirfor
Created September 1, 2023 22:28
Show Gist options
  • Save samirfor/c59dc1e4dad5a8f840296113070fd27d to your computer and use it in GitHub Desktop.
Save samirfor/c59dc1e4dad5a8f840296113070fd27d to your computer and use it in GitHub Desktop.
Simple, zero-downtime deploys with nginx and docker-compose
#!/bin/bash
# Simple, zero-downtime deploys with nginx and docker-compose
# Thanks to Stephen O'Brien, Head of Product, Tines
# Source: https://www.tines.com/blog/simple-zero-downtime-deploys-with-nginx-and-docker-compose
set -e
set -x
compose_yml="${1:-docker-compose.yml}"
reload_nginx() {
docker compose exec nginx /usr/sbin/nginx -s reload || sudo /usr/sbin/nginx -s reload
}
zero_downtime_deploy() {
service_name=web
old_container_id=$(docker ps -f name=$service_name -q | tail -n1)
# bring a new container online, running new code
# (nginx continues routing to the old container only)
docker compose -f "$compose_yml" build --pull $service_name
docker compose -f "$compose_yml" up -d --no-deps --scale $service_name=2 --no-recreate $service_name
# wait for new container to be available
new_container_id=$(docker ps -f name=$service_name -q | head -n1)
new_container_ip=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$new_container_id")
docker compose -f "$compose_yml" exec web \
curl --silent --include --retry-connrefused \
--retry 30 --retry-delay 1 --fail --connect-timeout 2 --location \
http://$new_container_ip:8000/ > /dev/null || exit 1
# start routing requests to the new container (as well as the old)
reload_nginx
# take the old container offline
docker stop "$old_container_id"
docker rm "$old_container_id"
docker compose -f "$compose_yml" up -d --no-deps --scale $service_name=1 --no-recreate $service_name
# stop routing requests to the old container
reload_nginx
}
zero_downtime_deploy
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment