为什么我的 Docker 卷在远程构建箱中不起作用?

Why is my Docker volume not working in a remote build box?

我正在尝试将卷添加到 Docker 容器中,该容器将在托管构建服务 (CircleCI) 上的 Docker Compose 系统中添加 运行 和 运行。它在本地工作正常,但在远程却不行。 CircleCI 提供了一个 SSH 工具,我可以用它来调试为什么容器没有按预期运行。

Docker Compose 文件的相关部分是:

  missive-mongo:
    image: missive-mongo
    command: mongod -v --logpath /var/log/mongodb/mongodb.log --logappend
    volumes:
    - ${MONGO_LOCAL}:/data/db
    - ${LOGS_LOCAL_PATH}/mongo:/var/log/mongodb
    networks:
    - storage_network

在本地,如果我这样做 docker inspect integration_missive-mongo_1(即 运行ning 容器名称,我将按预期获得卷:

    ...
    "HostConfig": {
        "Binds": [
            "/tmp/missive-volumes/logs/mongo:/var/log/mongodb:rw",
            "/tmp/missive-volumes/mongo:/data/db:rw"
        ],
    ...

在同一个容器上,我可以 shell 并看到卷工作正常:

docker exec -it integration_missive-mongo_1 sh
/ # tail /var/log/mongodb/mongodb.log 
2017-11-28T22:50:14.452+0000 D STORAGE  [initandlisten] admin.system.version: clearing plan cache - collection info cache reset
2017-11-28T22:50:14.452+0000 I INDEX    [initandlisten] build index on: admin.system.version properties: { v: 2, key: { version: 1 }, name: "incompatible_with_version_32", ns: "admin.system.version" }
2017-11-28T22:50:14.452+0000 I INDEX    [initandlisten]      building index using bulk method; build may temporarily use up to 500 megabytes of RAM
2017-11-28T22:50:14.452+0000 D INDEX    [initandlisten]      bulk commit starting for index: incompatible_with_version_32
2017-11-28T22:50:14.452+0000 D INDEX    [initandlisten]      done building bottom layer, going to commit
2017-11-28T22:50:14.454+0000 I INDEX    [initandlisten] build index done.  scanned 0 total records. 0 secs
2017-11-28T22:50:14.455+0000 I COMMAND  [initandlisten] setting featureCompatibilityVersion to 3.4
2017-11-28T22:50:14.455+0000 I NETWORK  [thread1] waiting for connections on port 27017
2017-11-28T22:50:14.455+0000 D COMMAND  [PeriodicTaskRunner] BackgroundJob starting: PeriodicTaskRunner
2017-11-28T22:50:14.455+0000 D COMMAND  [ClientCursorMonitor] BackgroundJob starting: ClientCursorMonitor

好的,现在是遥控器。我开始构建,它失败了,因为 Mongo 无法启动,所以我使用 SSH 工具在构建失败后保持盒子活动。

我首先破解了 DC 文件,这样它就不会尝试启动 Mongo,因为它会失败。我只是让它睡觉:

  missive-mongo:
    image: missive-mongo
    command: sleep 1000
    volumes:
    - ${MONGO_LOCAL}:/data/db
    - ${LOGS_LOCAL_PATH}/mongo:/var/log/mongodb
    networks:
    - storage_network

然后我 运行 docker-compose up 脚本启动所有容器,然后检查有问题的框:docker inspect integration_missive-mongo_1:

    "HostConfig": {
        "Binds": [
            "/tmp/missive-volumes/logs/mongo:/var/log/mongodb:rw",
            "/tmp/missive-volumes/mongo:/data/db:rw"
        ],

看起来不错。所以在主机上我创建了一个虚拟日志文件,并列出它以证明它在那里:

bash-4.3# ls /tmp/missive-volumes/logs/mongo
mongodb.log

所以我再次尝试 shell 加入,docker exec -it integration_missive-mongo_1 sh。这次我发现文件夹存在,但卷内容不存在:

/ # ls /var/log
mongodb
/ # ls /var/log/mongodb/
/ #

这很奇怪,因为到目前为止,远程 Docker/Compose 配置中卷的可靠性一直堪称典范。

理论

我目前的主要问题是 Docker 和 Docker Compose 的不同版本可能与它有关。所以我会列出我有什么:

因此,存在一些版本差异。作为一个摸鱼的人,我可以尝试撞上去 Docker/Compose,尽管我担心会撞到其他东西。

不过,理想的是某种高级 Docker 命令,我可以使用它来调试为什么卷似乎已注册但未在容器内公开。有什么想法吗?

CircleCI runs docker-compose remotely from the Docker daemon 所以本地绑定挂载不起作用。

A named volume 将默认为 local 驱动程序并且可以在 CircleCI 的 Compose 设置中工作,卷将存在于容器 运行s 的任何地方。

日志记录通常应留给每个容器设置的单个进程中的 stdout 和 stderr。然后你可以使用 logging driver plugin 运送到中央收集器。当 运行 在前台时,MongoDB 默认记录到 stdout/stderr。

合并卷和日志记录:

version: "2.1"

services:

  syslog:
    image: deployable/rsyslog
    ports:
      - '1514:1514/udp'
      - '1514:1514/tcp'

  mongo:
    image: mongo
    command: mongod -v
    volumes:
      - 'mongo_data:/data/db'
    depends_on:
      - syslog
    logging:
      options:
        tag: '{{.FullID}} {{.Name}}'
        syslog-address: "tcp://10.8.8.8:1514"
      driver: syslog

volumes:
  mongo_data:

这有点像 hack,因为日志记录端点通常是外部的,而不是同一组中的容器。这就是日志记录使用外部地址和端口映射来访问系统日志服务器的原因。此连接在 docker 守护程序和日志服务器之间,而不是容器到容器。

我想添加一个额外的答案来补充已接受的答案。我在 CircleCI 上的用例是 运行 基于浏览器的集成测试,以检查整个堆栈是否正常工作。在使用的 11 个容器中,有许多容器为各种事物定义了卷,例如日志输出和原始数据库文件存储。

我直到现在才意识到,由于技术 Docker 限制,CircleCI 的 Docker 执行器中的卷不起作用。由于这次失败,在之前的每种情况下,文件都只是写入一个空文件夹。

然而,在我的新案例中,这个问题导致 Mongo 失败。这样做的原因是我使用 --logappend 来防止 Mongo 在启动时进行自己的日志轮换,并且此开关需要 --logpath 中指定的路径存在。由于它存在于主机上,但是创建卷失败,所以容器看不到日志文件。

为了解决这个问题,我修改了 Mongo 服务条目以调用 command 部分中的脚本:

  missive-mongo:
    image: missive-mongo
    command: sh /root/mongo-logging.sh

脚本如下所示:

#!/bin/sh
#
# The command sets up logging in Mongo. The touch is for the benefit of any
# environment in which the logs do not already exist (e.g. Integration, since
# CircleCI does not support volumes)

touch /var/log/mongodb/mongodb.log \
    && mongod -v --logpath /var/log/mongodb/mongodb.log --logappend

在两种可能的用例中,这将起到如下作用:

  • 在挂载工作(dev,live)的情况下,如果文件存在,它会简单地触摸一个文件,如果不存在则创建它(例如,一个全新的环境),
  • 如果安装不工作 (CircleCI),它将创建文件。

无论如何,这是一个很好的安全功能,可以防止 Mongo 爆炸。