多个Docker容器,相同的镜像,不同的配置

59

我完全不了解Docker,所以感谢您的耐心。

我正在寻找一种部署多个容器的方式,这些容器使用相同的镜像,但是我需要为每个容器传递不同的配置文件。

目前,我理解的是一旦构建出一个镜像,那就是要部署的内容。但对我来说,问题在于,当同一应用程序仅在配置上有所不同时,构建多个镜像似乎没有意义。

如果这是正常做法,那我只能接受,但如果还有其他方法,请让我痛快地告别这种困境吧!:)

谢谢!


您可以在运行时动态挂载配置文件。 - Oliver Charlesworth
5个回答

28

我认为查看易于理解的示例可以给你最好的了解。

你想做的是完全有效的,一个镜像应该是你需要运行的任何内容,而不需要进行配置。

要生成配置,你可以选择以下两种方法:


a) 挂载卷

使用卷并在容器启动时挂载文件:docker run -v my.ini:/etc/mysql/my.ini percona(以及类似的docker-compose)。 请注意,你可以重复此操作多次,因此将多个配置挂载到容器(即镜像的运行版本)中。你需要在运行容器之前在主机上创建这些配置,并需要将这些文件与容器一起传输,这是此方法的缺点(可移植性)。

b) 基于entry-point的配置(生成)

大多数高级Docker镜像提供了一个称为entry-point的复杂内容,它会消耗你在启动镜像时传递的ENV变量,以为你创建配置文件,如https://github.com/docker-library/percona/blob/master/5.7/docker-entrypoint.sh

因此,当你运行此镜像时,可以执行docker run -e MYSQL_DATABASE=myapp percona,这将启动percona并为你创建名为percona的数据库。所有这些都是通过:

  1. 在此处添加entry-point脚本https://github.com/docker-library/percona/blob/master/5.7/Dockerfile#L65
  2. 不要忘记在构建镜像时复制脚本https://github.com/docker-library/percona/blob/master/5.7/Dockerfile#L63
  3. 然后,在镜像启动期间,你的ENV变量将导致此操作触发:https://github.com/docker-library/percona/blob/master/5.7/docker-entrypoint.sh#L91

当然,你可以根据自己的需要进行其他操作。例如,下面配置了一个通用的portus镜像:https://github.com/EugenMayer/docker-rancher-extra-catalogs/blob/master/templates/registry-slim/11/docker-compose.yml 它具有以下entrypoint:https://github.com/EugenMayer/docker-image-portus/blob/master/build/startup.sh

因此,你可以看到entry-point策略非常常见和强大,我建议尽可能采用这种方法。

c) 派生镜像

也许是为了“完整性”,派生镜像策略,因此你有称为“myapp”的基本镜像,对于安装X,你创建了一个新镜像。

from myapp
COPY my.ini /etc/mysql/my.ini
COPY application.yml /var/app/config/application.yml

给这个图像取名为 myapp:x - 显而易见的问题是,你最终会有很多图片,但与此同时,与 a) 相比,它更加便携。

希望这可以帮到您。


17

只需从相同的镜像运行多次即可。将创建新容器,然后可以启动和停止每个容器并保存其自己的配置。 为方便起见,最好使用“--name”为每个容器命名。

例如:

docker run --name MyContainer1 <same image id>
docker run --name MyContainer2 <same image id>
docker run --name MyContainer3 <same image id>

就是这样。

$ docker ps
CONTAINER ID        IMAGE            CREATED          STATUS               NAMES
a7e789711e62        67759a80360c   12 hours ago     Up 2 minutes         MyContainer1
87ae9c5c3f84        67759a80360c   12 hours ago     Up About a minute    MyContainer2
c1524520d864        67759a80360c   12 hours ago     Up About a minute    MyContainer3

之后,您的容器将永久创建,您可以像虚拟机一样启动和停止它们。

docker start MyContainer1

12
这如何解决“我需要为每个配置文件传入不同的配置”的核心问题? - That Brazilian Guy
每个容器可以有不同的配置。更改将保留。 - DimiDak
1
OP想要从同一镜像部署多个容器,这比配置文件更核心,@DimiDak回答了这个问题。 - Aaron Bell

6
每个容器都使用相同的只读镜像,但使用特定于每个容器的可读写文件系统层。结果是每个容器可以拥有其自己的文件,这些文件与其他容器完全不同。
您可以通过CLI、环境变量或作为唯一卷挂载传递配置。这是Docker的一个非常标准的用例。

太棒了,谢谢 :) 但是自动化这个配置可行吗?比如说,如果我要添加一堆使用相同 Nginx 镜像的不同容器,但每个容器都有不同的 .conf 文件,我该如何设置将与其部署的 .conf 文件。 - Ant
您需要将conf文件作为卷共享到每个容器中。一个卷可以是一个目录或者一个单独的文件。 - BMitch

0

针对Docker Desktop GUI以及喜欢使用鼠标点击的人(比如我有时):

  • 打开“镜像”选项卡
  • 点击所需镜像上的“运行”按钮
  • 指定容器名称和其他选项(TCP端口和卷)

使用不同名称和选项重复相同步骤。 现在您有两个正在运行的容器(请参阅“容器”选项卡)。


0

介绍一种使用单个Docker镜像创建多个Docker容器的方法。

我们可以在项目根目录下使用docker-compose.yml文件创建Docker容器,因此在更新docker-compose.yml文件内容(包括网络配置入站和出站端口配置等)后,可以使用以下命令创建Docker容器:docker-compose -f /var/www/..path/docker-compose.yml up -d。这里的"-d"是以后台运行方式运行Docker容器的选项。

以下是更详细的代码:

version: '3.8'

x-common:
  database:
    &db-environment
    MYSQL_PASSWORD: &db-

列表项

密码 'CHANGE_ME' MYSQL_ROOT_PASSWORD: 'CHANGE_ME_TOO'

  panel:
    &panel-environment
    APP_URL: 'https://example.com'
    APP_TIMEZONE: 'UTC'
    APP_SERVICE_AUTHOR: 'noreply@example.com'

  mail:
    &mail-environment
    MAIL_FROM: 'noreply@example.com'
    MAIL_DRIVER: 'smtp'
    MAIL_HOST: 'mail'
    MAIL_PORT: '1025'
    MAIL_USERNAME: ''
    MAIL_PASSWORD: ''
    MAIL_ENCRYPTION: 'true'

services:
  database:
    image: mariadb:10.5
    container_name: tttt-database
    restart: always
    command: --default-authentication-plugin=mysql_native_password
    volumes:
      - '/srv/pterodactyl/database:/var/lib/mysql'
    environment:
      <<: *db-environment
      MYSQL_DATABASE: 'panel'
      MYSQL_USER: 'pterodactyl'
    networks:
      - tttt-bridge-network

  cache:
    image: redis:alpine
    container_name: tttt-cache
    restart: always
    networks:
      - tttt-bridge-network

  panel:
    image: ghcr.io/image_url
    container_name: tttt-panel
    restart: always
    ports:
      - '3004:80' // dynamic ports
    links:
      - database
      - cache
    volumes:
      - '/srv/pterodactyl/var/:/app/var/'
      - '/srv/pterodactyl/nginx/:/etc/nginx/http.d/'
      - '/srv/pterodactyl/certs/:/etc/letsencrypt/'
      - '/srv/pterodactyl/logs/:/app/storage/logs'
    environment:
      <<: [*panel-environment, *mail-environment]
      DB_PASSWORD: *db-password
      APP_ENV: 'production'
      APP_ENVIRONMENT_ONLY: 'false'
      CACHE_DRIVER: 'redis'
      SESSION_DRIVER: 'redis'
      QUEUE_DRIVER: 'redis'
      REDIS_HOST: 'cache'
      DB_HOST: 'database'
      DB_PORT: '3306'
    networks:
      - tttt-bridge-network

networks:
  tttt-bridge-network: //  dynamic networks
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16  //dynamic Address

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接