皆様はじめまして! NewsPicks SREチームの中川です。
本日はコンテナイメージのバージョン管理についての記事をお届けします。
概要
NewsPicksではECSやKubernetesに代表されるコンテナサービスを使用しておりますが、コンテナのデザインパターンとしてサイドカーパターンを採用しているサービスがあります。 詳しい説明は省きますが、サイドカーはメインアプリケーション用コンテナを補助するコンテナです。
これらのサービスをデプロイするとき、サイドカー毎に使用するDockerfileを ImageTag
で指定していました。
実際には latest
で固定するか、特定のImageTag
を設定ファイルに書き込んで運用していました。
こうした運用方法の場合、Dockerfileを変更するときは事前にイメージを登録しておく必要があり、マニュアルで作業する必要がありました。
ざっくり言うと、実際の作業手順は以下の通りでした。
- ローカルや開発環境でDockerImageをビルド・プッシュする。
- 上記でプッシュした
ImageTag
を設定ファイルに記載する。 - いつも通りリリースする。
この場合、手順1でDockerImageのビルドやタグの付け忘れ、手順2でイメージタグのtypoもありえる訳で障害の原因となったりリリース失敗する可能性がありました。 こうした懸念を無くすため、DockerImageが変更されたら自動的に検知するようにしましたのでご紹介します。
実装
実装するにあたっての大きなポイントは、DockerImageの変更をどう検知するかでした。
Dokcerfileのみ変更する場合だと sha256sum
とか使えば良いのですが、docker build
時に参照するディレクトリやオプション引数が変わった場合も検知したいのが実装要件でした。
結論から言うと、AWS CDKのライブラリ @aws-cdk/core/lib/fs/fingerprint.js
を流用しました。
このライブラリが結構便利で、ディレクトリパスや任意の文字列(オプション引数)を渡すと一意にハッシュ値を返してくれます。
実際のコード(一部変えてあります)を下に示しますが、ディレクトリパスとdocker build
時のオプションとして buildArgs
を渡しているのが分かります。
import { fingerprint } from "@aws-cdk/core/lib/fs/fingerprint.js"; interface CreateHashProps { sourcePath: string; assetHashType: "source" | "custom"; extraHash: string | undefined; skip: boolean; } const projectRoot = `${__dirname}/../`; function calcHash(containerName: string, buildArgs: string): string { const props: CreateHashProps = { sourcePath: `${projectRoot}/container/${containerName}`, assetHashType: "source", extraHash: buildArgs, skip: false, }; try { const hash = fingerprint( `${projectRoot}/container/${containerName}`, props ); return hash; } catch (e: unknown) { throw new Error(`Can't create hash. message: ${e}`); } }
これをローカル環境でテストして、問題なく使えることが確認できたので、CI/CDパイプラインに組み込みました。
ビルド
上記関数を使用し、ハッシュ値を計算します。 既にDocker Repositoryに登録されていないか検索し、既にあれば何もせずスキップします。 登録がない場合は、DockerImageのビルド・プッシュを行います。
またビルド時の成果物として、どのサービスではどの ImageTag
のイメージを使うという設定ファイルも作っておきます。
なぜこうしているかというとNewsPicksではビルドとデプロイを疎にしているため、ビルド時の成果物を別途保存してデプロイ時にはそれを参照するという運用手順になっているからです。
デプロイ
ビルド時に作成した設定ファイルを参照し、指定した ImageTag
をDockerRepositoryからプルするだけです!
Pros
バージョン管理がCI/CDパイプラインに組み込まれ、人の手を必要とする手順が無くなったので障害のリスクが無くなりました! また開発環境と本番環境で使用するイメージを分けたい場合も、自動で管理してくれるので便利になりました。
Cons
特にないですが、敢えて挙げるとしたらビルド時間は若干伸びます。 ハッシュ値の計算とDockerRepositoryにイメージあるか確認する処理は毎回走るので、その分だけ伸びてしまいます。 ただ全体のビルド時間から見れば大したことではないですし、メリットの方が遥かに上回っている感じですね。
おわりに
サイドカーパターンに限らず、この仕組みを使えばDockerImageの変更に対して柔軟に対応できます。
DockerImageのタグを間違えたり、プッシュしていなかったりでトラブルに遭った経験がある方は多いのでは無いでしょうか? CI/CDパイプラインの整備と共に、この自動化の仕組みを試してみて頂ければと思います。