运行 容器 docker-compose 命令所需的文件

Files needed to run a container docker-compose command

我想我很难理解我需要哪些文件才能在空实例上 运行 带有我的 Rails 应用程序的容器。

我有一个 docker-compose.prod.yml 我想要 运行:

version: "3.8"

services:
  db:
    image: postgres
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-default}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-default}
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
  app:
    image: "username/repo:${WEB_TAG:-latest}"
    depends_on:
      - db
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec puma -C config/puma.rb"
    volumes:
      - .:/myapp
      - public-data:/myapp/public
      - tmp-data:/myapp/tmp
      - log-data:/myapp/log
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-default}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-default}
      POSTGRES_HOST: ${POSTGRES_HOST:-default}
  web:
    build: nginx
    volumes:
      - public-data:/myapp/public
      - tmp-data:/myapp/tmp
    ports:
      - "80:80"
    depends_on:
      - app
volumes:
  public-data:
  tmp-data:
  log-data:
  db-data:

因此,在本例中,我有 docker-compose.prod.yml 文件。由于我正在为环境和图像网络标签传递变量,因此我创建了一个 .env 文件,其中也包含这些变量。最后,由于我正在构建 nginx,因此我有一个包含图像的文件夹:

FROM arm64v8/nginx

# インクルード用のディレクトリ内を削除
RUN rm -f /etc/nginx/conf.d/*

# Nginxの設定ファイルをコンテナにコピー
ADD nginx.conf /etc/nginx/myapp.conf

# ビルド完了後にNginxを起動
CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/myapp.conf

和配置文件nginx.conf

user  root;
worker_processes  1;

events{
    worker_connections  512;
}

# ソケット接続
http {
  upstream myapp{
    server unix:///myapp/tmp/sockets/puma.sock;
  }
  server { # simple load balancing
    listen 80;
    server_name localhost;

    #ログを記録しようとするとエラーが生じます
    #root /myapp/public;
    access_log /var/log/nginx/access.log;
    error_log  /var/log/nginx/error.log;

    location / {
      proxy_pass http://myapp;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
    }
  }
}

因此,docker-compose.prod.ymlnginx 目录包含 2 个文件和 .env 文件。

当我这样做时:docker-compose -f docker-compose.prod.yml --env-file .env run app rake db:create db:migrate 它会下载 postgresapp 图像,但是一旦它开始为 db:create db:migrate 执行 rake,我得到此错误:

Status: Downloaded newer image for user/repo:48
Creating rails-app_db_1 ... done
Creating rails-app_app_run ... done
rake aborted!
No Rakefile found (looking for: rakefile, Rakefile, rakefile.rb, Rakefile.rb)
/usr/local/bundle/gems/rake-13.0.6/exe/rake:27:in `<top (required)>'
(See full trace by running task with --trace)

但是当我添加 Rakefile 时,它一直在询问其他依赖文件,所以我要么需要整个项目本身(从 GitHub 上的回购中克隆它)要么我正在这样做错了。

欢迎就我需要什么文件或是否需要更改命令提出任何想法!谢谢。

当您的 docker-compose.yml 文件显示

volumes:
  - .:/myapp

这意味着图像中 /myapp 目录的内容——可能是整个应用程序——将被忽略并替换为主机目录中的任何内容。因此,对于此设置,您需要复制整个应用程序源代码,否则将无法运行。

还有:

volumes:
  - public-data:/myapp/public

您的应用程序的静态资产存储在 Docker 命名卷中。这很难在系统之间传输,并且它会忽略底层图像的任何变化。


我会在此设置中更新一些内容,既可以避免大部分内容,也可以让事情更容易使用。

Docker 有一个内部网络层,您可以使用它们的 Compose 服务名称作为主机名在容器之间进行通信。 (请参阅 Docker 文档中的 Networking in Compose。)这意味着您可以将 Nginx 反向代理设置为通过正常 HTTP/TCP

与 Rails 应用程序通信
upstream myapp {
  server http://app:9292; # or the port from your config.ru/puma.rb file
}

这消除了对 tmp-data 卷的需求。

与将应用程序代码构建到图像中的方式相同,您也可以将静态资产构建到图像中。将 Nginx 映像 Docker 文件更新为:

# Artificial build stage to include app; 
ARG appimage
FROM ${appimage} AS app

FROM arm64v8/nginx

# Replace the Nginx configuration
RUN rm -f /etc/nginx/conf.d/*
COPY nginx.conf /etc/nginx/nginx.conf

# Copy in the static assets
COPY --from=app /myapp/public /myapp/public

# Use the default CMD from the base image; no need to rewrite it

这消除了对 public-data 卷的需求。

在您的主应用程序映像中,您应该声明一个 ENTRYPOINTCMD,这样您就不需要重复 long-winded command:。对于 ENTRYPOINT,我建议使用 shell 脚本:

#!/bin/sh
# entrypoint.sh

# Remove a stale pid file
rm -f tmp/pids/server.pid

# Run the main container CMD under Bundler
exec bundle exec "$@"

确保此文件是可执行的 (chmod +x entrypoint.sh) 并将其添加到您的存储库中,可能在 DockerfileGemfile 旁边的 top-level 目录中。在 Docker 文件中,将此脚本声明为 ENTRYPOINT,并使 Puma 成为 CMD:

ENTRYPOINT ["./entrypoint.sh"]       # must be JSON-array syntax
CMD ["puma", "-C", "config/puma.rb"] # could be shell syntax

我们唯一没有触及的卷挂载是数据库存储和日志目录。对于数据库存储,一个 Docker 命名的卷可能是合适的,因为您永远不需要直接查看文件。命名卷在某些平台(MacOS 和 Windows 的某些情况下)上要快得多,但更难在系统之间传输。相反,对于日志,我会使用绑定挂载,因为您通常希望直接从主机系统读取它们。

这会将 docker-compose.yml 文件缩减为:

version: "3.8"
services:
  db: { unchanged: from the original question }
  app:
    image: "username/repo:${WEB_TAG:-latest}"
    depends_on:
      - db
    volumes:
      - ./tmp/log:/myapp/log
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-default}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-default}
      POSTGRES_HOST: ${POSTGRES_HOST:-default}
  web:
    image: "username/web:${WEB_TAG:-latest}"
    ports:
      - "80:80"
    depends_on:
      - app

我们删除了几乎所有的 volumes:,以及除了数据库存储和输出日志的目录之外对主机目录的所有引用。我们还删除了 command: 覆盖,因为它重复了 Docker 文件中的内容。 (在其他类似的 SO 问题中,我可能会删除不必要的 networks:container_name:hostname: 声明,以及过时的 links:expose: 选项。)

如果您已完成此操作,则需要一种方法来构建图像并将它们推送到存储库。您可以 a second Compose file 只有 描述了如何构建图像:

# docker-compose.override.yml
# in the same directory as docker-compose.yml
version: '3.8'
services:
  app:
    build: .
  web:
    build:
      context: ./nginx
      args:
        appimage: username/repo:${WEB_TAG:-latest}

Compose 在这种情况下的一个缺点是它不知道一个图像依赖于另一个图像。这意味着您需要先手动构建基础镜像。

export WEB_TAG=20220305
docker-compose build app
docker-compose build
docker-compose push

这似乎有很多设置。但是这样做之后,我们唯一需要复制到新系统的就是 docker-compose.yml 文件和生产 .env 设置。

# on the local system
scp docker-compose.yml .env there:
# on the remote system
export WEB_TAG=20220305
docker-compose run app \
  rake db:create db:migrate
docker-compose up -d
如果本地没有副本,

Docker 将自动从存储库中提取图像。 (在像 Kubernetes 这样的上下文中,每个构建使用一个唯一的图像标签是有帮助的,并且是必需的;docker system prune 可以清理旧的未使用的图像。)如果你给文件它们的默认名称 docker-compose.yml.env 那么你不需要在命令行中提及它们。