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



我想我很难理解我需要什么文件才能在空实例上使用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文件。由于我正在传递环境和图像web标记的变量,所以我创建了一个包含这些变量的.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上的repo中克隆它(,要么我做错了。

欢迎对我需要什么文件或是否需要更改命令有任何想法!非常感谢。

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

volumes:
- .:/myapp

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

但也包括:

volumes:
- public-data:/myapp/public

您的应用程序的静态资产存储在一个名为Docker的卷中。这很难在系统之间传输,并且会忽略底层映像中的任何更改。


我会在这个设置中更新一些东西,既可以避免大部分卷,也可以让操作变得更容易。

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

upstream myapp {
server http://app:9292; # or the port from your config.ru/puma.rb file
}

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

就像将应用程序代码构建到图像中一样,也可以将静态资产构建到图像。更新Nginx镜像Dockerfile,使其看起来像:

# Artificial build stage to include app; https://stackoverflow.com/a/69303997
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,这样就不需要重复冗长的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旁边的顶级目录中。在Dockerfile中,将此脚本声明为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:覆盖,因为它重复Dockerfile中的内容。(在其他类似的SO问题中,我可能会删除不必要的networks:container_name:hostname:声明,以及过时的links:expose:选项。(

如果你已经做到了,你需要一种方法来构建你的图像并将它们推送到存储库。您可以有第二个Compose文件,描述如何构建图像:

# 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,那么你就不需要在命令行中提及它们。

最新更新