Docker 合并容器

Docker merge containers

我有 运行 多个容器,它们使用 docker-compose.yml 中定义的网络相互连接,我的应用程序 运行 完美,所以我想为那些部署到我的私有存储库的多个容器只创建一个图像(带有标签的图像),我想知道什么是最佳实践。

docker-compose.yml

version: '3.1'

networks:
  lemp:

services:
  nginx:
    build:
    context: .
    dockerfile: Dockerfile
    target: webserver
  container_name: webserver
  volumes:
    - ./src/app:/var/www/html/app
  ports:
    - "80:80"
  networks:
    - lemp

php:
  build:
    context: .
    dockerfile: Dockerfile
    target: app
  container_name: app
  volumes:
    - ./src/app:/var/www/html/app
  ports:
    - "9000:9000"
  networks:
    - lemp

Docker 文件

FROM nginx:1.21.6-alpine AS webserver
COPY ./src/ ./var/www/html
COPY ./nginx/conf.d/app.conf /etc/nginx/conf.d/app.conf
EXPOSE 80 443

FROM php:7.4-fpm-alpine AS app
EXPOSE 9000

不清楚您真正需要什么。您可以将各个容器发布到您的注册表并提供可下载的 Compose 文件供任何人一起使用这些容器,这将分别拉取每个图像。

否则,您需要将所有相关步骤从一个 Dockerfile 复制到另一个。注意:如果您在每个 Dockerfile 中 运行 唯一 entrypoint/commands(进程),那么这被认为是不好的做法。

更新

查看您的示例,您可以将 php-fpm 安装到 Nginx 容器中,复制 PHP 文件,然后只从那里提供静态内容。但是,我肯定会建议保留单独的容器。 Nginx 应该可以替换为反向代理。

此外,您没有正确的 multi-stage Dockerfile(使用 FROM 两次不会合并任何内容),并且您的 Compose 文件只是 运行 相同的图像(上下文)两次两个不同的端口。

您应该计划分发您的 docker-compose.yml 文件,或者它的简化版本,作为 运行 您的组合申请的标准方式。如果它需要两个图像,你需要将两个图像分别推送到你的存储库;不要试图将它们结合起来。请确保图像是 self-contained,这样您就不需要将源代码与图像分开 运行。

docker-compose.yml 文件大致如下所示:

version: '3.8'
services:
  nginx:
    image: registry.example.com/nginx:${TAG:-latest}
    ports:
      - '80:80'
  php:
    image: registry.example.com/php:${TAG:-latest}

在这里指出几件事:我删除了不必要的 networks: 声明(Compose 提供了一个工作正常的 default 网络)和不必要的 container_name: 声明。我为每个图像放置了一个 image: 行来代替 build: 块,并使用环境变量来注入图像标签。对于 php 容器,我删除了 ports: 声明,因为您可能不希望它可以从外部访问。最后,对于两个容器,我都删除了覆盖图像内容的 volumes:

在此旁边,放一个 docker-compose.override.yml 文件。这不是你要分发的东西。它可以说:

version: '3.8'
services:
  nginx:
    build:
      context: .
      dockerfile: Dockerfile.nginx
  php:
    build:
      context: .
      dockerfile: Dockerfile.php
    ports:
      - '9000:9000'

如果您有两个文件,Compose merges their settings。因此,对于开发人员来说,如果需要,这会添加 ports: 以直接访问 PHP-FPM 服务,并添加 build: 块来解释如何构建两个图像。由于组合的 Compose 配置同时具有 build:image:docker-compose build 将构建具有指定名称并标记有您的本地注册表名称的图像。

您应该为每个正在构建的图像创建一个单独的 Docker 文件。 Nginx 映像类似于您已有的映像;对于 PHP-FPM 容器,您需要确保将代码 COPY 放入图像中。

# Dockerfile.nginx
FROM nginx:1.21.6-alpine
COPY ./src/ /var/www/html/
COPY ./nginx/conf.d/app.conf /etc/nginx/conf.d/app.conf
# Dockerfile.php
FROM php:7.4-fpm-alpine
COPY ./src/app/ /var/www/html/app/

现在您可以在本地构建和 运行 应用程序。 Double-check 它工作正常, 没有 volumes: 覆盖图像代码

docker-compose build
docker-compose up -d
curl http://localhost/

如果这有效,那么您就可以分发它了。选择一个标签(日期戳或当前源代码控制 ID 是不错的选择),构建图像,并将它们推送到 Docker 注册表。

export TAG=20220418
docker-compose build
docker-compose push

现在您可以只复制 docker-compose.yml 文件,但 none 我们接触过的其他文件,可以复制到远程系统,或者将其放入 GitHub 存储库中,或者是其他东西。在该系统上,设置 $TAG 以匹配,并像往常一样设置 运行 docker-compose up。 Docker 将自动从存储库中提取图像。由于图像是 self-contained,因此您只需要 就是 docker-compose.yml 文件。

scp docker-compose.yml there:
ssh root@there
export TAG=20220418
docker-compose up -d