我调查了关于`docker compose -f`在不同环境部署的行为
首先
当使用Docker Compose根据不同的分阶段环境进行部署时,往往需要根据不同环境稍微调整compose文件的内容。然而,如果每次都要从头开始创建一个新的compose文件用于开发、分阶段、生产环境等,那么重复的部分将会出现重复定义,当发生更改时会变得繁琐不便。
作为Docker的官方建议,建议使用-f选项仅在production.yaml等文件中记录每个环境的差异。
您可能希望使用类似于production.yml的附加Compose文件来定义适用于生产环境的配置。这个配置文件只能记录来自基本Compose文件的更改点。附加的Compose文件可以指定覆盖原docker-compose.yml配置的新配置。
针对这个文件中的“指定覆盖原始的 docker-compose.yml 配置的新配置”的表述,由于我不太清楚在指定相同的卷路径或添加读取.env文件时会发生“只应用后定义的”还是“两者都应用”的情况,因此我做了一些轻微的调查。
调查
我使用了轻量级的alpine环境来测试以下这样的卷文件和环境文件。
docker-compose-f-test/
| -- app/
| -- compose_volume
| -- app_prod
| -- prodction_volume
| -- .env
| -- .prod.env
| -- docker-compose.yaml
| -- production.yaml
此外,所提到的compose_volume和prodction_volume只是用于检查挂载的文件,因此是无意义的空文件。
APP_ENV=dev
APP_NAME=DOCKER_COMPOSE_TEST
APP_ENV=prod
version: "3.0"
services:
alpine:
image: alpine
volumes:
- ./app:/app
- ./app:/app_prod
env_file:
- .env
services:
python:
volumes:
- ./app_prod:/app_prod
env_file:
- .prod.env
在容器中的/app_prod目录,故意将docker-compose.yaml和production.yaml中的本地相同目录挂载,以确认哪一个会被优先使用。
在这个状态下启动Docker,并检查env和目录结构。
$ docker compose -f docker-compose.yaml -f production.yaml run --rm alpine sh -c "ls app_prod && ls && env"
# 結果 (抜粋)
production_volume
app app_prod
APP_NAME=DOCKER_COMPOSE_TEST
APP_ENV=prod
需要停止挂载在生产环境下的情况下。
在开发环境中,可以使用绑定卷在本地编辑代码并直接应用到容器中,而在生产环境中,有时候希望停止绑定卷的使用。因为仅仅修改本地代码就可能对生产环境产生影响是令人担忧的。在这种情况下,可以按照以下方式进行描述。
services:
python:
volumes:
- /app
通常情况下,volume设置为本地路径:容器内路径。然而,如果不希望进行volume操作,则只需记录容器内路径即可。
经过这样的操作,当我们查看容器内的app/目录时,可以发现它是空的。
$ docker compose -f docker-compose.yaml -f production.yaml run --rm alpine sh -c "ls app -a"
# 結果 (抜粋)
. ..
顺便提一下,通过使用这种技术,我们可以在递归地挂载整个目录的同时,也可以选择不挂载特定的部分目录。
(通常在使用Docker创建React环境时,将node_modules绑定挂载会导致热重载变慢,因此我们采取了类似的方法,将只有node_modules排除在绑定挂载之外,并改为使用卷挂载。)
通过在docker-compose.yaml中定义的卷和环境变量,production.yaml中的卷和环境变量也已添加。如果在env中设置了相同的环境变量(APP_ENV),那么在使用-f后应用production时,指定在.prod.env中的”APP_ENV=prod”将被应用,并且对于在.prod.env中未指定任何内容的APP_NAME,它仍然有效。特意将docker-compose.yaml和production.yaml中的本地相同目录进行挂载后,通过-f应用production将优先考虑。
结论
结论是,对于以 YAML 描述的和以列表描述的内容,“两者都适用,但如果冲突,后者会覆盖前者”。而非列表描述(例如 restart)的内容,会直接应用最后指定的文件。虽然这是显而易见的,理应如此,但如果出现意料之外的行为,会直接对正式环境产生重大影响,所以很庆幸我们能够进行验证。
在中国语中,该表达可以被简洁地翻译为:”有什么用途”。
-
- 環境別に、異なる環境変数を用意したり、ポートマッピングを変更したい場合。
-
- 本番用環境はバインドボリュームを使用したくない場合(ローカルのコードが書き換わるとコンテナ内のコードも書き換わってしまうのは怖いとき)
-
- ログ収集方法を変える場合(EC2にDockerを置き、Cloudwatchにlogを出力する場合等。逆にEC2以外ではcomposeファイルにlog設定が書かれていると、立ち上がらなくなってしまうのを防止)
- …等。
在中文中,只需要一个选项
閒話
-
- docker compose config
-
- 調査中に分かったことですが、docker compose configコマンドを使えば、-fで複数の設定をマージしたcomposeファイルを出力できるので、これを使えばいちいちコンテナを作る必要はありませんでした。
- 以下のようにコマンドを打てば、どんな設定かが分かります。
$ docker compose -f docker-compose.yaml -f production.yaml config
-
- compose設定のリスト項目の更新
-
- volume以外のリスト設定(envやports)は、調べた限りマージしかできず、除外はできないようでした。
- なので例えば、開発環境でポートマッピングを80と443でしていて、本番環境では80のマッピングを除外するようなことはできないようです。それをしたい場合は、開発環境用のdocker composeのyamlを新たに作らないので、composeファイルが増えるのが少し面倒ですね。
…转述以下内容为汉语,只需给出一种选项:
…