Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

今さら聞けないDocker入門 〜 Dockerfileのベストプラクティス編

今さら聞けないDocker入門 〜 Dockerfileのベストプラクティス編

今時のアプリ開発において、コンテナは避けて通れないものになっています。そして数多くあるコンテナ実行環境の中でも、デファクトスタンダードと言えるのがDockerです。そんなDockerのイメージですが、皆さんは正しくビルドできていますか? そのコンテナは無駄に太っていませんか? 効率よく最短時間でビルドできていますか? セキュリティは大丈夫ですか? 今回はDockerfileの書き方をテーマに、「今さら聞けない」Docker入門をお届けします。

とことんDevOps

April 25, 2024
Tweet

More Decks by とことんDevOps

Other Decks in Technology

Transcript

  1. 発表者について • 水野 源 • VTJ 技術部所属 • Ubuntu JPメンバー

    • ubuntu.comメンバー • 著書に「Linuxをマスターしたい 人のための実践Ubuntu」など 2
  2. マルチプロセスが抱える問題 • これらのプロセスは、OS上の同一の空間内で実行される • そのためプロセス間でOSのリソースを共有する(あるいは奪い合う) • ルートファイルシステム • NIC •

    IPアドレス • ポート • 名前空間 • /etc以下の設定ファイルなど • 同一のポートを使うプロセスや、OSレベルの設定や要求するライブ ラリのバージョンが異なるアプリを共存させるのは難しい 6
  3. ベアメタルと仮想マシンの時代 • ならばアプリごとに専用のサーバーを用意すればいい • OSの資源を占有できるのだから、共存時にあった問題は解決する • しかしそれでは、アプリの数だけハードウェアが必要になってしまう • お金かかりすぎ…… •

    そこで仮想マシン • 1台の物理サーバー上で複数の仮想マシンを起動し、用途ごとの専用サー バーとして分離する方法がトレンドになった • しかし仮想マシンでは、VMごとにOSをインストールしなければならない • ひとつのアプリのためだけに、専用のVMやOSを用意するのは、管 理の手間やリソースの無駄が大きい 7
  4. そしてコンテナの時代へ • プロセスを隔離した空間内で実行する技術 • プロセスは、ホスト上の通常のプロセスとは異なる空間で実行されている • 個別のルートファイルシステムやIPアドレスが割り当てられる • プロセスはあたかも独立したOS内で動いているかのように振舞える •

    これはLinuxカーネルのnamespaceやcgroupといった機能で実現されている • ホスト側から見れば、単にプロセスが起動しているだけ • VMよりもオーバーヘッドやパフォーマンスの低下が少ない • VM乱立の時代から、プロセス単位でコンテナに隔離する時代へ 8
  5. Dockerのうれしいところ • ひとつのコンテナにひとつのプロセスの原則 • 仮想マシンとは異なり、プロセス単位でホストOSから分離することに特化 • イミュータブルでカプセル化されたアプリケーション実行環境 • アプリケーションのポータビリティの向上 •

    同一の環境を再現できるため、開発環境/本番環境の差異の吸収 • リソースの最適化 • OSとアプリケーションのライフサイクルの分離 • メンテ効率の向上 • インフラ管理運用コストの削減 11
  6. 仮想マシンとの違い 12 Host OS Kernel Docker Engine App 1 App

    2 Host OS Kernel Hypervisor OS 1 OS 2 App 1 App 2 Kernel Kernel 仮想マシン Docker
  7. Docker Imageとは • 実行中のコンテナには、それぞれ個別のルートファイルシステムが マウントされる • これの元になるのがDocker Image • ただし仮想マシンイメージとは異なる

    • ベースイメージに対する差分を重ね合わせたレイヤー構造を取る • OverlayFS • イメージは基本的にReadOnly • 何度実行しても同じ状況を再現できる 14
  8. 仮想マシンイメージとの違い 15 Kernel Library Middleware Application 仮想マシンイメージ Dockerイメージ Base Image

    Layer Layer Layer ファイルがインストールされた実体をイメージ化 抽象的な概念
  9. Dockerfileのサンプル 18 FROM ubuntu:jammy ← ベースイメージにUbuntuの22.04を使用する RUN apt-get update &&

    apt-get install –y hello ← helloパッケージをインストールする RUN rm –rf /var/lib/apt/lists/* ← パッケージリストを削除する ENTRYPOINT 「“/usr/bin/hello”] ← コンテナ起動時に/usr/bin/helloを実行する CMD [“-g”, “hello”] ← helloコマンドのデフォルト引数 Dockerfileの例 $ docker build . –t hello ← helloという名前のコンテナをビルドする Docker Imageのビルド $ docker run --rm hello ← helloという名前のコンテナを実行する Hello ← /usr/bin/hello –g helloが実行された ビルドしたDocker Imageの実行
  10. ビルドされるDocker Image 19 FROM ubuntu:jammy RUN apt-get update && apt-get

    install –y hello RUN rm –rf /var/lib/apt/lists/* ENTRYPOINT 「“/usr/bin/hello”] CMD [“-g”, “hello”] Dockerfile Dockerイメージ ubuntu:jammy apt-get install –y hello rm –rf /var/lib/apt/lists/* RUNやCOPYといった各種命令が、差分レイヤーとしてイメージに追加される
  11. Imageのダイエット • Imageの可搬性を上げるためには、少しでもImageのサイズを小さく すべき • これでpush/pullの時間が短縮できる • 効率アップだけでなく、省エネ、コスト削減に繋がる • 不要なデータが入ってると、セキュリティリスクになることもある

    • ビルドの仮定で発生した無駄なデータは消しておこう • さっきの例の RUN rm –rf /var/lib/apt/lists/* とかがまさにこれ • Ubuntuの公式コンテナイメージは、デフォルトでapt cleanを実行している 21
  12. レイヤーキャッシュ • Dockerfile内の命令ごとに、ファイルシステムの差分を生成する • これがレイヤーになる • ビルド済みのレイヤーが存在する場合、キャッシュが再利用される • ビルドやpullの時間短縮になる •

    Dockerfileの上から順に命令が実行されてキャッシュされる • Dockerfileを書き換えると(←重要)、書き換えた行以降のキャッシュが作り直される • 変更されない命令から順に書くことで、キャッシュを最大限に利用できる • 逆に、更新されるべきレイヤーがキャッシュされてしまい、思った通り動かないと いった落とし穴にも注意 • キャッシュの粒度を考えてレイヤーを分割しよう • --no-cacheオプションの活用 22
  13. マルチステージビルド 24 Dockerfile Application Build Tool Library Source Code Build

    ビルド用コンテナ 実行コンテナ Application Copy ビルド用コンテナは、ビルド 完了後は破棄される ビルドしたアプリケーション だけを含んだ軽量なImage が作れる
  14. Distrolessの活用 • 実行コンテナのImageには、実行時に必要なものだけが入っていればいい • 極論、それ意外のライブラリやツールは不要、というか邪魔 • Ubuntuコンテナにはapt等のツールが入ってるけど、構築が終わった後はいらない • 本当に空っぽのイメージを用意して、そこに実行バイナリだけを入れれば いいのでは?

    • この発想でGoogleが作ったイメージがDistroless • glibcとかlibsslとか、/bin/shすら入ってない • Distrolessはその特性から、GoやRustと相性がよい • マルチステージビルドで活用しよう • コンテナのベースOSのセキュリティとかも気にしなくてよくなる 25
  15. エフェメラルなコンテナを目指す • コンテナは使い捨て可能にしよう • 永続的な情報をコンテナ内に持たせない • 機密情報は起動時に環境変数を経由して注入するなど • オンプレのような、サーバーを育てていく思想は捨てよう •

    使い捨てが可能なようにコンテナを設計することで • いつでも同じ環境が再現可能になる • 環境に起因するトラブルをなくせる • 開発環境と本番環境を同一にできる • コンテナ間に差異がなくなるので、スケールアップが容易になる • 障害対応力も上がる 26
  16. コンテナのセキュリティ • FROMに非公式イメージを使わない • Docker Hubにある公式イメージをベースにしよう • 非特権ユーザーを使う • USER命令はマスト

    • 不要なファイルを含めない • コンテナに機密情報を埋め込むとか論外である • (ベースOSが更新される場合)頻繁にビルドして更新する • CI/CDが重要 • 脆弱性チェックも活用しよう 27