Podman部署后容器冻结,需手动重启才可正常运行
Podman容器部署后冻结问题的分析与解决
问题根源
从你的CI/CD流水线脚本来看,导致容器部署后冻结的核心问题有三个:
- 重复启停容器的冗余操作:脚本先在5001端口启动新容器,确认运行后,又执行
stop、rm再重新在5000端口启动。这种重复启动会导致Podman的网络、进程资源未完全释放,干扰应用初始化流程,引发进程死锁或冻结。 - 固定等待时间的不可靠性:用
sleep 10判断服务就绪,容器状态显示“运行”不代表内部应用服务真正启动完成,此时后续操作会打断应用初始化。 - 仅依赖容器状态检查:只用
podman ps确认容器运行,未验证内部服务的可用性,导致误判服务就绪状态,后续操作触发未就绪服务的异常。
针对性解决方案
1. 重构容器部署流程,避免重复启停
直接在目标端口启动新容器,通过临时名称切换的方式替换旧容器,全程只启动一次新容器:
修改AzureCLI任务中的部署逻辑为:
set -e echo 'Logging in to Azure...' az login --service-principal -u $(AZURE_CLIENT_ID) -p $(AZURE_CLIENT_SECRET) --tenant $(AZURE_TENANT_ID) echo 'Logging in to ACR...' podman login pdspqptestcontainerregistry.azurecr.io -u $(AZURE_ACR_USERNAME) -p $(AZURE_ACR_PASSWORD) export IMAGE_TAG=$(cat image_tag.txt | cut -d '=' -f2) NEW_CONTAINER_NAME="pqp-backend-gunicorn-${IMAGE_TAG}" OLD_CONTAINER_NAME="pqp-backend-gunicorn" echo "Pulling the latest backend image..." podman pull pdspqptestcontainerregistry.azurecr.io/pqp_be_gunicorn:${IMAGE_TAG} echo "Starting new backend container ${NEW_CONTAINER_NAME} on port 5000..." podman run -d --name=${NEW_CONTAINER_NAME} --restart=always -p 5000:5000 \ -e FLASK_ENV=$(FLASK_ENV) -e ES_TOKEN=$(ES_TOKEN) \ pdspqptestcontainerregistry.azurecr.io/pqp_be_gunicorn:${IMAGE_TAG} # 轮询检查应用健康状态,替换固定sleep echo "Waiting for application to be ready..." MAX_RETRIES=20 RETRY_INTERVAL=5 RETRY_COUNT=0 # 替换为你的实际健康检查接口路径 HEALTH_CHECK_URL="http://localhost:5000/health" while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do if curl -f $HEALTH_CHECK_URL; then echo "Application is ready." break fi echo "Waiting for application... ($((RETRY_COUNT+1))/$MAX_RETRIES)" sleep $RETRY_INTERVAL RETRY_COUNT=$((RETRY_COUNT+1)) done if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then echo "Application failed to become ready." podman logs ${NEW_CONTAINER_NAME} podman stop ${NEW_CONTAINER_NAME} podman rm ${NEW_CONTAINER_NAME} exit 1 fi # 平滑切换容器:停止旧容器,删除后重命名新容器 echo "Switching to new container..." podman stop ${OLD_CONTAINER_NAME} || true podman rm ${OLD_CONTAINER_NAME} || true podman rename ${NEW_CONTAINER_NAME} ${OLD_CONTAINER_NAME} # 后续清理逻辑保持不变 echo "Cleaning up old images in ACR, keeping the last 5..." REPO="pqp_be_gunicorn" IMAGES=$(az acr repository show-tags --name pdspqptestcontainerregistry --repository $REPO --orderby time_desc --output tsv | tail -n +6) for IMAGE in $IMAGES; do az acr repository delete --name pdspqptestcontainerregistry --image $REPO:$IMAGE --yes done echo "Cleaning up old images locally, excluding the current image..." podman images --format "{{.ID}} {{.Repository}}:{{.Tag}}" | grep 'pqp_be' | grep -v "${IMAGE_TAG}" | awk '{print $1}' | xargs -I {} sh -c 'podman rmi -f {} || true'
2. 给镜像添加健康检查
在你的Dockerfile中添加健康检查指令,让Podman自动监控内部服务状态:
# 根据你的应用调整健康检查命令,确保能准确判断服务可用性 HEALTHCHECK --interval=30s --timeout=3s \ CMD curl -f http://localhost:5000/health || exit 1
添加后,podman ps会显示容器的healthy状态,此时再执行后续操作更可靠。
3. 移除不必要的镜像清理前置步骤
原脚本中先删除所有旧镜像再构建,可能导致构建过程中依赖缺失(如果有多层镜像依赖),建议保留最近的1-2个旧镜像,或者在构建完成后再清理旧镜像。
验证方法
- 运行优化后的流水线,部署完成后执行
podman ps,确认容器状态为healthy(添加健康检查后)。 - 调用服务接口或执行健康检查curl命令,确认服务正常响应。
- 观察10-15分钟,确认容器不会进入冻结状态。
内容的提问来源于stack exchange,提问作者Martin Benko
相关产品推荐
相关产品推荐

