由于 Docker 网络参数,Launcher 重建在 Docker 19.03.0 下失败

随着 Docker 推出 19.03.0 版本,Discourse 启动器在重建后无法启动实例,并显示以下错误信息:

/usr/bin/docker: --network 不是有效的 MAC 地址。
请查看 '/usr/bin/docker run --help'。

以下是实际执行的命令(部分项已为安全起见修改):

+ /usr/bin/docker run --shm-size=512m -d --restart=always -e LANG=en_US.UTF-8 -e RAILS_ENV=production -e UNICORN_WORKERS=2 -e UNICORN_SIDEKIQS=1 -e RUBY_GLOBAL_METHOD_CACHE_SIZE=131072 -e RUBY_GC_HEAP_GROWTH_MAX_SLOTS=40000 -e RUBY_GC_HEAP_INIT_SLOTS=400000 -e RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR=1.5 -e DISCOURSE_DB_SOCKET=/var/run/postgresql -e DISCOURSE_DB_HOST= -e DISCOURSE_DB_PORT= -e DISCOURSE_HOSTNAME=discourse.mydomain.com -e VIRTUAL_HOST=discourse.mydomain.com -e DISCOURSE_DEVELOPER_EMAILS=admin@mydomain.com -e DISCOURSE_SMTP_ADDRESS=mail.mydomain.com -e DISCOURSE_SMTP_PORT=587 -e DISCOURSE_SMTP_USER_NAME=discourse@mydomain.com -e DISCOURSE_SMTP_PASSWORD=MySuperDuperPass -h vps-discourse -e DOCKER_HOST_IP=172.17.0.1 --name discourse -t --expose 80 --mac-address --network reverse-proxy --network reverse-proxy local_discourse/discourse /sbin/boot
/usr/bin/docker: --network 不是有效的 MAC 地址。
请查看 '/usr/bin/docker run --help'。

我使用的是反向代理(运行在名为 reverse-proxy 的网络上)。此前一直正常运行,直到今天出现问题。看起来系统期望提供一个 MAC 地址值,但该值未被提供。

让我们看看..

root@endoffice-a:/var/discourse# docker --version
Docker version 19.03.0, build aeac949

我刚刚执行了 ./launcher rebuild app,一切正常:

+ /usr/bin/docker run --shm-size=512m -d --restart=always -e LANG=en_US.UTF-8 -e RAILS_ENV=production -e UNICORN_WORKERS=8 -e UNICORN_SIDEKIQS=1 -e RUBY_GLOBAL_METHOD_CACHE_SIZE=131072 -e RUBY_GC_HEAP_GROWTH_MAX_SLOTS=40000 -e RUBY_GC_HEAP_INIT_SLOTS=400000 -e RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR=1.5 -e DISCOURSE_DB_SOCKET=/var/run/postgresql -e DISCOURSE_DB_HOST= -e DISCOURSE_DB_PORT= -e LETSENCRYPT_DIR=/shared/letsencrypt -e UNICORN_SIDEKIQ_MAX_RSS=1000 -e DISCOURSE_HOSTNAME=discourse.codinghorror.com -e DISCOURSE_DEVELOPER_EMAILS=jatwood@codinghorror.com -e DISCOURSE_SMTP_ADDRESS=smtp.mailgun.org -e DISCOURSE_SMTP_PORT=587 -e DISCOURSE_SMTP_USER_NAME={redacted} -e DISCOURSE_SMTP_PASSWORD={redacted} -e LETSENCRYPT_ACCOUNT_EMAIL={redacted} -e DISCOURSE_CDN_URL=https://discourse-cdn.codinghorror.com -h endoffice-a-app -e DOCKER_HOST_IP=172.17.0.1 --name app -t -p 80:80 -p 443:443 -v /var/discourse/shared/standalone:/shared -v /var/discourse/shared/standalone/log/var-log:/var/log --mac-address 02:72:e3:65:d5:32 local_discourse/app /sbin/boot

请注意,--mac-address 确实出现了并且已填充,但 --network 这一行是针对您的特定配置,与标准的独立 Discourse 安装有所区别。

@codinghorror 这说得很好,但如果 Discourse 本应仅通过标准的独立安装方式运行,那为何要在 ./containers 中提供对 yml 容器配置的支持,并在 ./samples 中包含相关示例?我使用的文件已完全注释了操作说明,特别是这一部分:

# any extra arguments for Docker?
# docker_args:

我唯一使用的是:

docker_args: "--network reverse-proxy"

该配置过去一年一直运行良好。显然,某些地方发生了变化。请理解我并非有意挑衅(毕竟我是在寻求帮助,这样做未免有些愚蠢),但我确实想强调,我所使用的选项正是通过 Discourse 示例提供的。

或许,如果我了解该 MAC 地址是如何生成的,就能帮我定位到环境变更问题,这正是我所希望的。

我在 launcher 中看到如下内容:

     if [ -z "$SKIP_MAC_ADDRESS" ] ; then
      mac_address="--mac-address $($docker_path run $user_args -i --rm -a stdout -a stderr $image /bin/sh -c "echo $hostname | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/'")"
     fi

我会仔细分析,看看能否找出问题所在。

更新:查看这段代码后,我发现可以使用 --skip-mac-address。这样做后,我的实例可以正常启动,因此问题似乎出在计算 MAC 地址的过程中。

总之,构建操作无论发生什么都不会失败,但在构建操作(./launcher rebuild myinstance)中,最后一步启动容器时由于某种原因 MAC 地址未设置而失败。

不过,我可以在之后直接执行 ./launcher start myinstance,然后就能正常启动,MAC 地址也存在。这很奇怪,仅此而已。

我也遇到了同样的问题。
@codinghorror 以下是复现步骤以及修复此回归问题的线索:

复现步骤:

  1. 在容器配置(app)中设置:
    docker_args: "--network reverse-proxy"
  2. 重新构建
    ./launcher rebuild app
  3. 查看错误
    /usr/bin/docker: --network 不是有效的 MAC 地址

这是一个由提交 bfc79e7 引入的 bug(https://github.com/discourse/discourse_docker)
merge_user_argsset_template_info 调用,但在重新构建时(run_runrun_bootstrap),set_template_info 会被调用两次。
因此,原本应该是 user_args 等于 $user_args $docker_args,结果却变成了 $user_args $docker_args $docker_args

Docker 不允许多次配置相同的网络:
docker: network "reverse-proxy" is specified multiple times

感谢回退此提交,或者使 merge_user_args 具备幂等性。

谢谢你的侦探工作!:male_detective: @saj 看起来你和 @deargle 一起签署了那个提交。

这是一个补丁:

应用该补丁,并在容器定义中设置 docker_args 键后,最终的 docker run 参数向量大致如下:

/usr/bin/docker run --shm-size=512m -d --restart=always -e ... -h saj-launcher-testing-app -e DOCKER_HOST_IP=172.17.0.1 --name app -t -p 80:80 -p 443:443 -v /var/discourse/shared/standalone:/shared -v /var/discourse/shared/standalone/log/var-log:/var/log --mac-address 02:07:fa:c6:c4:82 --network foonet local_discourse/app /sbin/boot

太棒了!很高兴我不是在做梦。感谢各位对此事的关注。