このエントリは、はてなエンジニア - Qiita Advent Calendar 2024 - Qiitaの13日目の記事です。昨日は、
id:maiyama4 さんのSwiftUI の Text がなぜか省略されてしまう問題とそのレイアウトプロセスのデバッグ - maiyama4's blogでした。
みなさんCompose使っていますか? ここで言うComposeはdocker composeとかnerdctl composeとかで呼べるコンテナ複数立ち上げくんのことです。
Docker Composeはcompose specとして標準化されている仕様のリファレンス実装であり、他のランタイムからもComposeを使うことができます。なので今回はまとめてComposeと呼ぶこととします。
Composeファイルの複数指定
おなじみのcompose.yamlファイルですが、Compose実行時にファイルを指定することができます。しかも複数指定することができます。
さてこのときにcompose.yamlとcompose.another.yamlに同じキーの値が存在したときはどうなるでしょう*1。
# compose.yaml services: app: image: nginx:latest # compose.another.yaml services: app: image: ubuntu:latest
このようにして呼び出してみましょう。
docker compose configコマンドを使うと、実際に使用されるcomposeファイルが分かるようです。やってみましょう。
$ docker compose -f compose.yaml -f compose.another.yaml config
name: ymse
services:
app:
image: ubuntu:latest
networks: # 自動付加
default: null
networks: # 自動付加
default:
name: ymse_default
nginxと指定していたimageがubuntuと上書きされていることがわかりますね。
試してみるとこのルールは他にもenvironmentなどでも適用されることがわかります。 やってみましょう。
# compose.yaml services: app: image: nginx:latest environment: foo: '1' bar: '2' # compose.another.yaml services: app: image: ubuntu:latest environment: foo: override
こんな感じにyamlを書いて実行してみる。
$ docker compose -f compose.yaml -f compose.another.yaml config
name: ymse
services:
app:
environment:
bar: "2"
foo: override
image: ubuntu:latest
networks:
default: null
networks:
default:
name: ymse_default
確かにcompose.another.yamlで指定したservices.app.environment.fooのみが上書きされていることがわかりますね。
ということがComposeの仕様であるcompose-specに記述されています。
無で上書きしたい
さてこのcompose-specのmergingのセクションですが眺めてみると、特定のキーの値をresetすることができるみたいです。確かに生活していれば特定環境のみで値をセットしたいこともある。
# https://github.com/compose-spec/compose-spec/blob/e9dc800c027a513254bbf15ee05893a8105a6afb/13-merge.md#reset-value より引用。 # file Aを追記するなど一部改変。 # file A services: app: image: myapp ports: - "8080:80" environment: FOO: BAR # file B services: app: image: myapp ports: !reset [] environment: FOO: !reset null
上書きしたい値の頭に!resetと付けると無で上書きできるようです。
実際にどんなcomposeファイルが生成されるのか見てみましょう。
$ docker compose -f compose.yaml -f compose.another.yaml config
name: ymse
services:
app:
image: myapp
networks:
default: null
networks:
default:
name: ymse_default
実際にportsとenvironmentがオミットされていることがわかりますね。
YAML Tagで実現するリセット
さておもむろに!resetを頭に付けるとマージしたときにうまくやってくれるよ。と紹介しましたが、この!resetの正体はなんなのでしょうか。
これはYAMLのtagと呼ばれるものです。
YAMLの仕様にもしっかりと明記されている文法で、!1つで始まるタグはアプリケーション固有のローカルタグと呼ばれています。
https://yaml.org/spec/1.2.2/#24-tags https://yaml.org/spec/1.2.2/#3212-tags
ローカルタグはパースするアプリケーション側で自由に扱うことができます。
例えばRubyのYAMLパーサであるlibrary yamlではローカルタグを付けることにより、パースしたあとにRubyのどのクラスで扱うかを指定できます。
docker/composeが参照している compose-spec/compose-go の中でも実際にYAMLのタグをパースしてresetならよしなにするコードが存在しています。
このコードのおかげで上書きができるのですね。
まとめ
compose-specを眺めていたら見つけた、あまり知られていなさそうな仕様について調べたらYAMLのタグに流れ着きました。 知らない仕様を知ることは面白いですね。
以上、はてなエンジニア - Qiita Advent Calendar 2024 - Qiita13日目担当の
id:ymseでした。14日目の担当は
id:utgwkk さんです