家の片付けしてたらこれが出てきたので読んだ。
現代の開発現場では,Dockerなどのコンテナを使って開発を進めることがあたりまえになってきました。サーバサイドでもフロントエンドでも,コンテナの知識が必須と言えそうです。きちんとしたコンテナイメージをビルドできるようになるためには,Dockerfileの書き方のベストプラクティスは押さえておきたいところでしょう。
本特集では,理想的なコンテナイメージはどういうものか説明し,公式ドキュメントにあるガイドラインの内容を深掘りします。さらに,悩みがちなベースイメージの選び方,イメージ作成に役立つツール,セキュリティ対策を押さえていきます。「とりあえず使えるものが書ければいいや」と済ませず,自信を持って理想的なコンテナイメージを作れるようになりましょう。
コンテナイメージはコンテナを実行するためのテンプレートで、以下のような要素を含んでいる。
ベースイメージ
アプリケーションのソースコードや依存関係
ファイルシステム階層やファイル、ディレクトリ自体の追加編集削除
環境変数
アプリケーションを起動するためのコマンド
ベースイメージから変更を加えるごとにレイヤが作成され、(標準的には overlay2 ストレージドライバを利用して)複数のレイヤを重ね合わせることで一つのファイルシステムを提供する。親子関係がある複数のレイヤが積み重なり、あたかも一つのファイルシステムが存在しているかのように振る舞う。Docker の場合は Dockerfile として命令を記述することで新たなレイヤを作成する。
理想的なコンテナを実現するためには以下の3つの要素がある。
再現性: ベースイメージやパッケージ、ミドルウェアのバージョンを latest を使わず固定し、ビルドの結果に再現性を保証する。タグに latest を使わないでバージョンを固定する。バージョンタグに対して後からイメージを push することもできるので、できればイメージの SHA-256 ハッシュを使うのがよい。
セキュリティ: アプリを非特権ユーザで実行する、不要なファイルを含めない、アプリ動作に不要なファイルやクレデンシャルを使う場合はマルチステージビルドする、必要に応じて distroless にする、ベースイメージや依存関係を積極的にアップグレードしてリビルドするなどでコンテナブレイクアウトのリスクを低減する。ベースイメージは基本的に公式のものを使う。イメージの変更履歴は `docker history` コマンドで確認できるが、このコマンドが参照するメタデータは手動で書き換えられるので究極的にはイメージの開発者を信頼できるかと言う問題に帰着する。
可搬性: アプリの設定は環境変数などから注入する、コンテナイメージを軽量に保つなどで一度ビルドしたコンテナをさまざまな環境で使うようにする。
Dockerfile の書式は公式が提供するガイドラインや Dockerfile の reference があるので、基本的にはそれに従うのが良いとのこと。本書でその内容が簡単に紹介されている。
Docker は毎日のように使っていたが、コマンドでコンテナを起動してアプリを動かすだけでレイヤの概念はよく理解していなかった。マルチステージビルドはビルドと実行のイメージを分けることでイメージのサイズを削減するのが目的だと考えていたが、実行時のイメージに含めたくない情報(不要な依存関係や機密情報)を削除するという点でも重要らしいことを知った。イメージ作る過程で消せばいいかくらいに考えていたのだが Dockerfile 上の命令で何らかのデータを削除してもその削除自体が新しいレイヤを作るので、前のレイヤではその削除されたデータが残っており、脆弱性の原因になり得る。
Trivy というコンテナイメージの脆弱性スキャンツールの使い方も紹介されていた。Docker の仕組みを勉強すると「脆弱性をスキャンする」というのはこういうことをやっているんだろうな〜と想像できて楽しい。
自分はプログラマになったのが遅いので、その分だけ人より多く良いソフトウェアやドキュメントに触れていきたい。