docker-compose+nginx实现服务不中断更新
思路是写一个脚本,docker-compose scale扩容,然后重写nginx配置文件,刷新负载均衡
nginx重写的配置文件,文件名service,里面只有upstream,例如:
upstream e-chatbot-server-dev { server 0.0.0.0:8080; server 0.0.0.0:8081; }
脚本使用方法:
./rollupdate.sh --service=test-server --port=8080
需要注意的是docker-compose.yaml的服务test-server端口范围要比实例数多一个,yaml示例如下:
version: '3' services: test-server: image: test-server:1.0 restart: always networks: - dev ports: - "8080-8082:8080" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"] interval: 30s timeout: 10s retries: 3 start_period: 60s deploy: resources: limits: cpus: 2 memory: 1g replicas: 2 update_config: parallelism: 1 delay: 10s restart_policy: condition: on-failure networks: dev: external: true driver: bridge
rollupdate.sh脚本如下:
service= port= # 循环处理所有命令行参数 for arg in "$@" do case $arg in --service=*) # 如果参数以--service=开头 service="${arg#*=}" # 截取等号后的部分作为服务名称 ;; --port=*) # 如果参数以--port=开头 port="${arg#*=}" # 截取等号后的部分作为端口号 ;; *) # 如果参数不是以--service=或--port=开头,则跳过 ;; esac done if [ -z "$service" ]; then echo "--service=?" fi if [ -z "$port" ]; then echo "--port=?" fi if [ -z "$service" ] || [ -z "$port" ]; then exit 1 fi old_names=$(docker-compose ps $service --format "{{.Names}}") if [ -z "$old_names" ]; then docker-compose up -d $service exit $? fi echo -e "服务$service,老的实例:\n $old_names" docker-compose port $service $port > /etc/null if [ "$?" != "0" ]; then exit 1 fi replicas=$(docker-compose config $service --format="json" | jq ".services.\"$service\".deploy.replicas // 1") if [ -z "$replicas" ]; then echo "未获取到副本数量" exit 1 fi echo "old replicas: $replicas" let replicas=replicas+1 echo "update replicas: $replicas" for container_name in $old_names; do # 在这里可以添加其他针对每个容器名称的操作 echo "服务:$service设置副本为$replicas,正在添加一个副本" docker-compose scale "$service=$replicas" if [ "$?" != "0" ]; then exit fi echo -n "等待新增副本就绪..." for i in {1..100}; do #服务需要监控检查 start_count=$(docker-compose ps $service | grep "health: starting" | wc -l) if [ $start_count -eq 0 ]; then break fi echo -n "." sleep 5 done echo "" if [ $start_count -gt 0 ]; then echo "超过最大等待时间" exit 1 fi new_names=$(docker-compose ps $service --format "{{.Names}}") nx_conf="upstream $service {\n" for new_name in $new_names; do if [ "$new_name" != "$container_name" ]; then hport=$(docker port $new_name $port | head -n 1) nx_conf+=" server $hport;\n" fi done nx_conf+="}" echo "从nginx负载均衡移除实例$container_name" echo -e $nx_conf > /etc/nginx/conf.d/$service.conf nginx -s reload echo "docker stop $container_name" docker stop $container_name && docker rm $container_name done