跳转至

01 docker compose 实现平滑发版脚本

docker-compose 实现平滑发版

实现逻辑

1、 获取当前运行的需要替换的容器,并使用OLD_CONTAINERS 对容器进行记录

2、 将需要替换的容器进行扩容到SCALE_INSTANCES 的副本数

3、 验证health check ,新容器启动完成后,清理掉旧容器

4、 调整 reload nginx 配置,使容器解析到新容器上去

参考脚本如下:

SERVICE_BASE=$(basename $(dirname $(realpath ${0})))
SERVICE_NAME="mkdocs"
SCALE_INSTANCES=2
HEALTH_CHECK_TIMEOUT=300

## 公共函数
function job_success(){
    GREEN='\033[32m'
    NC='\033[0m'
    echo  -e "${GREEN} $(date +"%Y-%m-%d %H:%M:%S") -  $@ ${NC}"
    echo
    exit 0
}

function job_failed(){
    RED='\033[31m'
    NC='\033[0m'
    echo -e "${RED} $(date +"%Y-%m-%d %H:%M:%S") -  $@ ${NC}"
    echo
    exit 1
}

function job_execution(){
    echo -e  $(date +"%Y-%m-%d %H:%M:%S") -  $@
    echo
}
function rollout_upgrade(){
    container_all=($(docker ps -q -f "name=${SERVICE_BASE}-${SERVICE_NAME}-*"))
    for container in ${container_all}; do
        docker-compose stop ${container}
    done
    docker-compose up -d
    job_failed "❌ 新容器未达到健康状态,触发回滚"
}
# 获取当前服务的IP
OLD_CONTAINERS=($(docker ps -q -f "name=${SERVICE_BASE}-${SERVICE_NAME}-*" -f "health=healthy"))
if [[ ${#OLD_CONTAINERS[@]} -eq 0 ]]; then
    job_failed "❌  没有成功运行的容器,结束任务"
elif [[ ${#OLD_CONTAINERS[@]} -eq ${SCALE_INSTANCES} ]]; then
    rollout_upgrade
fi


function up_new_container(){
    docker-compose up -d --scale ${SERVICE_NAME}=${SCALE_INSTANCES} --no-recreate

    job_execution "⏳ 等待新容器就绪..."

    for i in $(seq 1 ${HEALTH_CHECK_TIMEOUT}); do
        NEW_CONTAINERS=($(docker ps -q -f "name=${SERVICE_BASE}-${SERVICE_NAME}-*" -f "health=healthy") )
        echo ${NEW_CONTAINERS}
        if [[ "${#NEW_CONTAINERS[@]}" -eq "${SCALE_INSTANCES}" ]]; then

            job_execution ${NEW_CONTAINERS}

            break
        fi
        sleep 1
    done

    if [ ${#NEW_CONTAINERS[@]} -lt ${SCALE_INSTANCES} ]; then
        rollout_upgrade
    fi

}


function update_nginx(){
    DOCKER_CMD=(
    "docker"
    "exec"
    "${SERVICE_BASE}-gateway-1"
    )

   "${DOCKER_CMD[@]}" nginx -t
   "${DOCKER_CMD[@]}" nginx -s reload
}

function offline_old_container(){
    echo "⏬ 逐步下线旧容器..."
    for container in ${OLD_CONTAINERS[@]}; do
        docker stop ${container} && docker rm ${container}
        sleep 5 # 间隔时间确保流量迁移
    done
    update_nginx
}


function main(){
    # up new container
    up_new_container
    # offline_old_container
    offline_old_container
}

main