首页 > 解决方案 > 使用多个 docker-compose 文件覆盖图像标签

问题描述

我遇到的问题是,当我构建/运行服务时,我的覆盖尝试image被忽略了。rails保留的图像名称是okamii/paas:dev。但是,如果我构建/运行服务,则无论我是否覆盖它( )app,图像的名称都是预期的( )。okamii/paas:ciokamii/paas:dev

我错过了什么吗?

我使用的命令:

docker-compose -f docker-compose.yml -f docker-compose.ci.yml up -d rails

这是我正在使用的两个 Compose 文件:

缩短docker-compose.yml

version: '3.8'

services:
  app: &app
    build:
      context: .
      dockerfile: Dockerfile.dev
      args:
        BUNDLER_VERSION: '2.1.4'
        NODE_MAJOR: '12'
        PG_MAJOR: '13'
        RUBY_VERSION: '2.7.2-jemalloc'
        YARN_VERSION: '1.22.5'
        BUILDKIT_INLINE_CACHE: 1
        S3_ACCESS_KEY_ID: "${ACCESS_KEY:?err}"
        S3_SECRET_ACCESS_KEY: "${SECRET_KEY:?err}"
    image: okamii/paas:dev
    tmpfs:
      - /tmp

  backend: &backend
    <<: *app
    stdin_open: true
    tty: true
    volumes:
      - .:/app:cached
      - rails_cache:/app/tmp/cache
      - bundle:/usr/local/bundle
      - node_modules:/app/node_modules
      - packs:/app/public/packs
      - .dockerdev/.psqlrc:/root/.psqlrc:ro
    environment:
      - NODE_ENV=development
      - RAILS_ENV=${RAILS_ENV:-development}
      - REDIS_URL=redis://redis:6379/
      - DATABASE_URL=postgres://postgres:postgres@postgres:5432
      - BOOTSNAP_CACHE_DIR=/usr/local/bundle/_bootsnap
      - WEBPACKER_DEV_SERVER_HOST=webpacker
      - HISTFILE=/app/log/.bash_history
      - PSQL_HISTFILE=/app/log/.psql_history
      - EDITOR=vi
      - MALLOC_ARENA_MAX=2
      - WEB_CONCURRENCY=${WEB_CONCURRENCY:-1}
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy

  rails:
    <<: *backend
    entrypoint: ./.dockerdev/rails-entrypoint.sh
    ports:
      - '3000:3000'

满的docker-compose.ci.yml

version: '3.8'

services:
  app: &app
    build:
      cache_from:
        - okamii/paas:ci
    image: okamii/paas:ci

标签: dockerdocker-compose

解决方案


YAML 锚语法 ( &app, *backend) 是特定文件的本地语法,并在 YAML 读取器读取文件时进行解释。这意味着您的主docker-compose.yml文件,一旦 Compose 真正开始查看它,就会具有三个单独的服务,其中包含三个单独的image:行。第二个文件有自己的&app锚点(从不引用),并且只声明一个图像。

# Base docker-compose.yml, after YAML anchor expansion
version: '3.8'
services:
  app:
    image: okamii/paas:dev
  backend:
    image: okamii/paas:dev
  rails:
    image: okamii/paas:dev
# docker-compose.ci.yml, after YAML anchor expansion
version: '3.8'
services:
  app:
    image: okamii/paas:ci

如果您要覆盖的唯一内容是图像标签,则可以为此使用环境变量。如果您在每个构建中使用唯一的图像标签,这也会很好地工作,这通常是一个很好的做法。

# Base docker-compose.yml file
services:
  app: &app
    image: okamii/paas:${TAG:-latest}
# There is no docker-compose.ci.yml file
TAG=ci docker-compose up -d

如果您真的想在单独的 YAML 文件中指定它,则需要在那里重新创建 YAML 锚结构,或者确保所有服务都指定了它们的值。

# docker-compose.ci.yml, the complex version
version: 3.8
services:
  app: &app
    image: okamii/paas:ci
  backend: &backend
    <<: *app
  rails:
    <<: *backend

您还可以考虑简化此设置的方法。在这个构建中有很多选项,其中大多数可能可以在 Dockerfile 中修复(例如,BUNDLER_VERSION必须与文件中的内容完全Gemfile.lock匹配;没有理由在外部指定它)。在所有环境中使用相同的 Docker 映像而不构建特殊的仅 CI 映像也是一种典型做法。


推荐阅读