如何在 docker-compose 文件中正确使用本地构建的图像?

How to use locally built image in docker-compose file correctly?

我有多个服务需要使用同一个本地构建的映像。

所以我创建了一个帮助程序服务来构建图像,所有其他服务都将依赖于构建器服务以确保首先构建图像。 这里的 docker-compose.yml 只有 2 个服务,但实际上,我有大约 20 个服务。

version: "3.5"

services:
    api:
        image: test-image      # using the image built below
        networks:
            - mylab
        depends_on:
            - tests-container-builder
        volumes:
            - ./tests:/tests
        command: pytest -v -p no:cacheprovider /tests/api.py

    license-chrome:
        image: test-image
        networks:
            - mylab
        depends_on:
            - tests-container-builder
        volumes:
            - ./tests:/tests
        command: sh -c "/tests/health-check-script.sh && pytest -v -p no:cacheprovider -n=1 /tests/license.py"

    tests-container-builder:
        build:
            context: .
            dockerfile: ./tests/Dockerfile
            target: test-env
        image: test-image             # this service builds the image

但是当我使用

构建和 运行 容器时
docker-compose up --build api; \
docker-compose up --scale license-chrome

我收到类似

的错误
ERROR: for mylab_visual_ner-chrome_1  no such image: sha256:ceff9945d8722c89331696aa33d88f84703e322fbb64c1ebaa8f83c6e19a4cfa: No such image: sha256:ceff9945d8722c89331696aa33d88f84703e322fbb64c1ebaa8f83c6e19a4cfa

ERROR: for visual_ner-chrome  no such image: sha256:ceff9945d8722c89331696aa33d88f84703e322fbb64c1ebaa8f83c6e19a4cfa: No such image: sha256:ceff9945d8722c89331696aa33d88f84703e322fbb64c1ebaa8f83c6e19a4cfa
ERROR: The image for the service you're trying to recreate has been removed. If you continue, volume data could be lost. Consider backing up your data before continuing.

Continue with the new image? [yN]

如果我删除 test-container-builder 服务并在所有服务中使用 build 命令,它工作正常。

使用不同的服务构建镜像是否被认为是一种反模式? 执行此操作的正确方法是什么?

我认为绝对最佳实践的 Compose 设置只包含 运行 长的容器,而不是您实际上不希望 运行 的容器。在您的情况下,“构建器”容器实际上不执行任何操作,我不会将其包含在 Compose 设置中。相反,build:从相同的源代码中提取完全相同的图像几乎是免费的; Docker 需要扫描构建上下文以确定这两个图像是相同的,但最后你只会得到同一个物理图像的两个不同名称。

根据@TheFool 的建议使用 YAML 锚点来避免重复构建设置,我可能会写:

version: '3.8'
services:
  api:
    build: &build-definition
      context: .
      dockerfile: ./tests/Dockerfile
      target: test-env # (can you avoid this?)
    command: pytest -v -p no:cacheprovider /tests/api.py
  license-chrome:
    build: *build-definition
    # (does the health check belong in an ENTRYPOINT wrapper in the image?)
    command: sh -c "/tests/health-check-script.sh && pytest -v -p no:cacheprovider -n=1 /tests/license.py"

我省略了不必要的 networks:,因为 Compose 为您创建了一个名为 default 的完全可用的网络,volumes:,因为您的代码通常应该内置到图像中。

如果您想显式构建映像并将其包含在 Compose 设置中(也许您想将其推送到注册表),那么您需要手动 docker-compose build 构建器映像,而不是任何容器你会 运行。 Compose 设置看起来像

version: '3.8'
services:
  api:
    image: registry.example.com/my-name/test-image:${TAG:-latest}
    command: pytest -v -p no:cacheprovider /tests/api.py
  license-chrome:
    image: registry.example.com/my-name/test-image:${TAG:-latest}
    command: sh -c "/tests/health-check-script.sh && pytest -v -p no:cacheprovider -n=1 /tests/license.py"
  tests-container-builder:
    image: registry.example.com/my-name/test-image:${TAG:-latest}
    build:
      context: .
      dockerfile: ./tests/Dockerfile
      target: test-env
    restart: "no"
    command: exit 0

与我之前的 Compose 设置和您的问题相比,我明确表示容器应该立即退出而不是重新启动,并且我使用了注册限定的名称。 depends_on: 仅影响容器启动的顺序,不包括对镜像构建的任何依赖。

如果您正在使用此设置,则需要 docker-compose build builder“容器”,然后 运行 其余的:

export TAG=20211124                          # often useful to avoid ...:latest
docker-compose build test-container-builder  # not "api"
# docker-compose push test-container-builder # if required
docker-compose up -d                         # could just launch specific containers

这可能不是真正的答案,但我已经重新创建了您的场景,而且它的效果令人惊讶。如果您只想构建在配置中没有构建密钥的容器,我确实预计它会失败。

docker system prune -af       # ensure we dont get confused with pre build images or chaching
docker-compose up --build two # try to run only service two

撰写文件:

version: "3.9"
volumes:
  data: null
services:
  one:
    image: foo
    build:
      context: ./
      dockerfile: Dockerfile
      target: stage1
    command: sh -c 'sleep 5 && echo "one done"'
  two:
    image: foo
    command: sh -c 'sleep 5 && echo "two done"'
    volumes:
      - data:/stuff
      - ./test:/test
    depends_on:
      - one

Docker 文件

FROM busybox as stage1
RUN echo "Hello World"
FROM busybox
CMD sleep infinity

我得到的输出如下。这可能是有道理的,因为在阅读 --build 标志的定义时, Build images before starting containers.,听起来有点像它不关心你想启动什么服务。它只是构建所有图像。

docker-compose up --build two
Creating network "test_default" with the default driver
Building one
[+] Building 3.3s (6/6) FINISHED                                                                       
 => [internal] load build definition from Dockerfile                                              0.1s
 => => transferring dockerfile: 121B                                                              0.0s
 => [internal] load .dockerignore                                                                 0.1s
 => => transferring context: 2B                                                                   0.0s
 => [internal] load metadata for docker.io/library/busybox:latest                                 2.3s
 => [stage1 1/2] FROM docker.io/library/busybox@sha256:b5cfd4befc119a590ca1a81d6bb0fa1fb19f1fbeb  0.4s
 => => resolve docker.io/library/busybox@sha256:b5cfd4befc119a590ca1a81d6bb0fa1fb19f1fbebd0397f2  0.0s
 => => sha256:b5cfd4befc119a590ca1a81d6bb0fa1fb19f1fbebd0397f25fae164abe1e8a6a 2.29kB / 2.29kB    0.0s
 => => sha256:50e44504ea4f19f141118a8a8868e6c5bb9856efa33f2183f5ccea7ac62aacc9 527B / 527B        0.0s
 => => sha256:ffe9d497c32414b1c5cdad8178a85602ee72453082da2463f1dede592ac7d5af 1.46kB / 1.46kB    0.0s
 => => sha256:3cb635b06aa273034d7080e0242e4b6628c59347d6ddefff019bfd82f45aa7 772.78kB / 772.78kB  0.3s
 => => extracting sha256:3cb635b06aa273034d7080e0242e4b6628c59347d6ddefff019bfd82f45aa7d5         0.1s
 => [stage1 2/2] RUN echo "Hello World"                                                           0.4s
 => exporting to image                                                                            0.0s
 => => exporting layers                                                                           0.0s
 => => writing image sha256:81893d72f6be148599854469098e9f8c80a73e28acd5991a1757033440d34e5c      0.0s
 => => naming to docker.io/library/foo                                                            0.0s

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
Creating test_one_1 ... done
Creating test_two_1 ... done
Attaching to test_two_1
two_1  | two done
test_two_1 exited with code 0