首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我怎样才能更新码头撰写服务中的芹菜工人,却又能让长期运行的任务在他们完成之前保持活动状态?

我怎样才能更新码头撰写服务中的芹菜工人,却又能让长期运行的任务在他们完成之前保持活动状态?
EN

Stack Overflow用户
提问于 2020-04-21 07:56:36
回答 1查看 3.1K关注 0票数 4

我有一个烧瓶应用程序,允许用户通过芹菜作业队列开始长时间运行的任务(有时> 1d)。烧瓶应用程序及其所有依赖项,包括芹菜工人,都通过docker进行容器化,并从一个坞-组合文件开始。

我的问题是,当我用新版本的应用软件更新容器映像时,我需要用以下方法重新启动容器:

代码语言:javascript
复制
docker-compose down
docker-compose up -d

这将取消所有长期运行的作业,因为在docker-组合中,每个缺省值只有一个短的超时值。按照docker-compose and graceful Celery shutdown中的建议,为停靠者设置一个更长的超时值不会对我起作用,因为无法预测任务将花费多长时间,更新可能需要很长时间才能完成所有任务。

我的想法是以某种方式将运行中的容器从docker-compose控件中分离出来,然后在分离的容器中优雅地关闭芹菜,这样就允许作业完成,但不接受新的作业。然后,我可以通过docker-compose up -d启动正常的容器堆栈。

因此,我要这样做:

  • 从码头移除/重命名芹菜容器组合
  • 信号表明容器中的芹菜任务优雅地停止,让作业完成但不接受新作业
  • 然后启动接受新作业的新容器

我试图使用docker rename重命名由docker启动的容器,但它们仍然对docker-compose down作出反应。

我的问题是,这种方法是否是正确的方法来处理这一问题,如果这是可能的对接-撰写?在码头作业环境中处理长期运行的芹菜工人的优雅更新的最佳实践是什么?

我发现的其他与此相关但不能完全解决问题的问题:

docker-compose and graceful Celery shutdown:答案显示了如何优雅地停止容器,但我想立即开始一个新的芹菜工人,以便没有停机时间。

How do I restart celery workers gracefully?:这适用于本地安装,但我必须重新启动容器才能获得新的应用程序代码。

编辑:解决方案的新提示:

在这个问题上,我发现了类似的情况。在这里,docker-compose --scale用于复制服务,然后可以找到旧服务和新服务的is。一旦新服务启动,就应该能够告诉芹菜关闭并完成旧容器中的执行任务。如果这是解决方案,我将在后面添加这个作为一个答案。

https://github.com/docker/compose/issues/1786#

编辑:更多地考虑使用缩放的变体。在这里,我再次遇到了长期任务的问题。在我能够缩小到一个实例之前,观察垂死的容器将是非常麻烦的。在链接中的示例中,只需要在停止旧服务之前检查新服务是否真的启动,这样脚本就可以立即回缩到单个实例。我宁愿复制这个服务,但是将新服务从对接-组合的控制中删除,这样当我缩小到一个容器时,它就不会被杀死。这必须通过移除正在运行的容器的坞-组合标签来实现:

代码语言:javascript
复制
"Labels": {
                "com.docker.compose.config-hash": "44e0bbd2a10e28bcad071a42315e65ed4d89f2d815a08aed4f3133b05b9d9f71",
                "com.docker.compose.container-number": "1",
                "com.docker.compose.oneoff": "False",
                "com.docker.compose.project": "karmada_docker_upgreat",
                "com.docker.compose.project.config_files": "docker-compose_test.yml",
                "com.docker.compose.project.working_dir": "/home/USERNAME/git/karmada_docker_upgreat",
                "com.docker.compose.service": "karmada_celery_kalibrate_worker",
                "com.docker.compose.version": "1.25.0"
            }

还是这条路走错了?重命名服务对坞-组合没有影响。

**编辑**标签不能更改为一个正在运行的容器:https://github.com/moby/moby/issues/15496,我越想到这一点,我想我将不得不使用正常的码头命令来运行芹菜容器。有了docker命令和shell脚本,就可以很容易地完成我需要做的事情。我还是想在码头写作中找到解决方案。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-04-23 15:44:15

经过更多的研究,我找到了解决这个问题的办法。但我不得不放弃使用docker-compose的限制。

目前,我认为我需要用docker-compose做的事情是不可能的,因为一个容器一旦用docker-compose启动,只要它在线,就会一直由docker-compose命令控制。原因是在运行容器时不能更改标签,docker-compose通过标签找到它控制的容器(有关详细信息,请参阅问题)。

因此,尽管人们可以使用:

代码语言:javascript
复制
docker-compose up -d --no-deps --scale $SERVICE_NAME=2 --no-recreate $SERVICE_NAME

要启动更新的容器,请保持当前容器运行,如下所示:

https://github.com/docker/compose/issues/1786#

在长期运行的工作结束后,我没有办法将服务规模缩小。因为作业可能运行很长时间(> 1d),所以我可以让多个容器完成。因此,我将不得不实现一个庞大的开销来计算当前正在完成的容器,并在其中一个容器完成时重新调整到适当的数量。总有一种危险,那就是意外的docker-compose down会把他们全部打倒。

但是,https://github.com/docker/compose/issues/1786#末尾的shell脚本促使我放弃docker-compose控制,并使用普通的docker命令控制所有芹菜容器。有了这个,我很容易管理我想要做的事情。我想出了以下shell脚本:

代码语言:javascript
复制
startup () {
  SERVICE_NAME=${1?"Usage: docker_update <SERVICE_NAME> <COMMAND>"}
  COMMAND=${2?"Usage: docker_update <SERVICE_NAME> <COMMAND>"}
  docker run \
         -d \
         --name $SERVICE_NAME \
         SOME_DOCKER_IMAGE \
         $COMMAND
}

update () {
  SERVICE_NAME=${1?"Usage: docker_update <SERVICE_NAME> <COMMAND>"}
  COMMAND=${2?"Usage: docker_update <SERVICE_NAME> <COMMAND>"}
  echo "[INFO] 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}')

  TEMP_UUID=`uuidgen`
  TEMP_CONTAINER_NAME="celery_worker_${TEMP_UUID}"

  echo "[INFO] rename $OLD_CONTAINER_NAME to $TEMP_CONTAINER_NAME"
  docker rename $OLD_CONTAINER_NAME $TEMP_CONTAINER_NAME

  echo "[INFO] start new/updated celery queue"
  startup $SERVICE_NAME $COMMAND

  echo "[INFO] send SIGTERM to $TEMP_CONTAINER_NAME for warm shutdown"
  docker kill --signal=SIGTERM $TEMP_CONTAINER_NAME

#  Optional waiting for the container to finish
  echo "[INIT] waiting for old docker container to finish"
  docker wait $TEMP_CONTAINER_NAME
}

SERVICE_NAME=${1?"Usage: docker_update <SERVICE_NAME>"}
COMMAND=${2?"Usage: docker_update <SERVICE_NAME> <COMMAND>"}
echo "[INFO] checking if this service already runs"
docker ps --format "table {{.ID}}  {{.Names}}  {{.CreatedAt}}" | grep $SERVICE_NAME

if [ $? -eq 0 ]
then
  echo "[INFO] CONTAINER with name $SERVICE_NAME is online -> update"
  update $SERVICE_NAME $COMMAND
else
  echo "[INFO] CONTAINER with name $SERVICE_NAME is **not** online -> starting"
  startup $SERVICE_NAME $COMMAND
fi

脚本检查具有给定名称的服务是否正在运行。如果不是的话,它就开始了。如果它正在运行,它将重命名当前正在运行的容器,然后启动一个新的(可能是更新的)容器,并将一个SIGTERM发送到旧的容器。对于芹菜来说,这是执行warm shutdown的信号,这意味着它不再接受新的任务,而是完成当前正在执行的任务,然后退出。如果没有正在运行的任务,则立即退出。新来的芹菜工人接管了所有的新任务。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61338556

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档