运行 容器 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.yml
、nginx
目录包含 2 个文件和 .env
文件。
当我这样做时:docker-compose -f docker-compose.prod.yml --env-file .env run app rake db:create db:migrate
它会下载 postgres
和 app
图像,但是一旦它开始为 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
卷的需求。
在您的主应用程序映像中,您应该声明一个 ENTRYPOINT
和 CMD
,这样您就不需要重复 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
) 并将其添加到您的存储库中,可能在 Dockerfile
和 Gemfile
旁边的 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
那么你不需要在命令行中提及它们。
我想我很难理解我需要哪些文件才能在空实例上 运行 带有我的 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.yml
、nginx
目录包含 2 个文件和 .env
文件。
当我这样做时:docker-compose -f docker-compose.prod.yml --env-file .env run app rake db:create db:migrate
它会下载 postgres
和 app
图像,但是一旦它开始为 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
卷的需求。
在您的主应用程序映像中,您应该声明一个 ENTRYPOINT
和 CMD
,这样您就不需要重复 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
) 并将其添加到您的存储库中,可能在 Dockerfile
和 Gemfile
旁边的 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
那么你不需要在命令行中提及它们。