Upgrade to Pro — share decks privately, control downloads, hide ads and more …

【新卒研修】ライブデモ + compose.yaml読解_講義資料

【新卒研修】ライブデモ + compose.yaml読解_講義資料

More Decks by ディップ株式会社

Other Decks in Technology

Transcript

  1. 前提知識の確認 この研修は、以下の内容を理解している前提で進めます。 •Docker の基礎: イメージ、コンテナ、Dockerfileの役割 ・基本コマンド: docker run, docker ps,

    docker stop Docker 単体の復習 Dockerfile (設計図) -(build) イメージ -(run) コンテナ (テンプレート) (実体) Dockerfile - 「どんな環境を作るか」のレシピ イメージ- Dockerfileからビルドされた不変のテンプレート ・コンテナーイメージから起動した実行中のプロセス 今回のDocker Composeは、この 「複数のコンテナ」を束ねて管理する仕組みです。 6
  2. 現実のアプリケーションは複数のコンテナで動いている 今回の題材↓(7つのコンテナが協調して1つのシステムを構成) app (Python Webサーバ) :8000 db-replica (読取専用。 レプリカ)。 :5432

    db (Postgres 15.4) :5432 db-testing (テスト用 DB) db-testing-replica (テスト用レプリカ) :5432 :5432 es (Elasticsearch 8.14.1) :9200 kibana (ESの可視化 ダッシュボード) :5601 これを手動で1つずつ管理するのはnot現実的 9
  3. メリット1: コマンド1発で環境が完成する # たった1行で、7つのコンテナが全部起動する docker compose up -d 이 長い

    docker run コマンドを何度も叩く必要がない •起動順序(DBが先、レプリカが後)も depends_on + healthcheck 人間が sleep 10 で待つような不安定な運用がなくなる で自動制御 12
  4. メリット2: チーム全員で「全く同じ環境」を作れる 設定ファイル(compose.yaml) をGitで管理する = インフラの設定がコードとして残る 開発者A のPC 開発者B のPC

    git clone git clone compose.yaml Dockerfile init.sql 同一 ↓ docker compose up -d 全く同じ環境 compose.yaml Dockerfile init.sql docker compose up -d 全く同じ環境 13
  5. 具体例: サービス間の接続 # アプリ(app サービス)からDBに接続する場合 # IPアドレスではなく、サービス名 "db" で接続できる DATABASE_URL

    = "postgresql://myapp_user:password@db:5432/myapp" # # compose.yaml のサービス名 Docker Compose デフォルトネットワーク app -"db" db es 'es" "db" で接続可能 kibana —"myаpp-es"- (container_nameも使える) 15
  6. Docker Composeを使わない場合... コンテナ間の通信は以下のように面倒になる: # Docker Composeなし: IPアドレスを調べて指定する必要がある docker inspect myapp-db

    | grep IPAddress #→"172.17.0.3" #→ このIPはコンテナを再起動すると変わる可能性がある! DATABASE_URL = "postgresql://[email protected]:5432/myapp" #不安定 Docker Composeならサービス名が自動的にDNSによって名前解決されるため、 IPアドレスを一切意識する必要なし 16
  7. メリット4: 環境のライフサイクルを簡単に管理できる # 環境を丸ごと起動 docker compose up -d # 環境を丸ごと停止・削除

    docker compose down # データも含めて完全リセット(DBのデータ等も消える) docker compose down -v # 設定を変更した後、変更があるサービスだけ再作成 docker compose up -d 「開発環境をまっさらにしてやり直したい」がdown −v →up -d の2コマンドで完了 17
  8. 4-1. services ーコンテナの定義 services の下に、動かしたいコンテナをサービスとして定義する services: app: #← サービス名(自由に決められる) db:

    #← サービス名 es: #← サービス名 サービス名はコンテナ間通信でホスト名として使われる 22
  9. 4-2. app サービスについて詳細説明 app: container_name: myapp-backend build: context: dockerfile: ./docker/Dockerfile

    args: - LOCAL_CERTS=${LOCAL_CERTS:-0} volumes: - .:/app dummy_volume:/app/.venv - app_cache:/root/.cache ports: 8080:8000 - 8888:8888 environment: - WATCHFILES_FORCE_POLLING=true # (1) コンテナ名 # (2) ビルド設定 - PYRIGHT_PYTHON_FORCE_VERSION=1.1.393 - PYRIGHT_PYTHON_IGNORE_WARNINGS=1 #(3) ファイル共有・永続化 #(4) ポート公開 #(5) 環境変数 - SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt - REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt extra_hosts: #(6) ホスト名追加 - host.docker.internal:host-gateway 23
  10. container_name -ー コンテナに名前をつける container_name: myapp-backend docker psや docker logs で表示される名前になる

    ・指定しないと<プロジェクト名>−<サービス名>−1 のように自動生成される ・同じ名前のコンテナは同時に1つしか存在できない # container_name を指定した場合 $ docker ps CONTAINER ID NAMES abc123 myapp-backend #← わかりやすい # 指定しない場合 $ docker ps CONTAINER ID NAMES abc123 myproject-app-1 #← 自動生成 24
  11. build - Dockerイメージをビルドする build: context: . dockerfile: ./docker/Dockerfile args: -

    LOCAL_CERTS=${L0CAL_CERTS:-0} # ビルドコンテキスト # 使用するDockerfile # ビルド時の引数(Dockerfile内のARGに渡る) ビルドコンテキスト = Dockerがビルド時に参照できるファイルの範囲 context: ・は「現在のディレクトリ以下のファイルをすべてDockerに渡す」とい う意味 プロジェクトルート(context: — compose.yaml .) docker/ Dockerfile dockerfile: で指定 src/ main.py Dockerfile内の COPY でコピー可能 requirements.txt Dockerfile内の COPY でコピー可能 25
  12. build - Dockerイメージをビルドする buildと image の使い分け 設定 意味 build: Dockerfileからイメージをビルド

    image: postgres:15.4 Docker Hubの既存イメージをそのまま使う build.argsと environment の違い 設定 いつ使われるか build.args ビルド時のみ (docker compose build 時 environment コンテナ実行時 用途 Dockerfileの条件分岐、バージョン指定 アプリの設定値、接続情報 # build.args の例:ビルド時に証明書を入れるかどうかを切り替える args: - LOCAL_CERTS=${LOCAL_CERTS:-0} # 「環境変数 LOCAL_CERTSが設定されていればその値、なければ 0」を意味する # ↑${LOCAL_CERTS:−0} はシェルの構文で、 26
  13. volumes - ファイルの共有・永続化 volumes: - .:/app # (a) バインドマウント -

    dummy_volume:/app/.venv #(b) 名前付きボリューム app_cache:/root/.cache #(b) 名前付きボリューム 重要ポイントなので、2種類のマウントを詳しく解説 27
  14. バインドマウント 自分のPC上の特定のフォルダを、コンテナの中に直接つなぎ合わせる方法 .:/app # ホストの「「.」(カレントディレクトリ)を、コンテナの「/ app」にマウント ホストPC コンテナ / 同期

    /app/ - src/ src/ main.py main.py tests/ L compose.yaml tests/ compose.yaml ホストでファイルを編集→コンテナにリアルタイム反映 コンテナ内で生成したファイル→ホストにも見える 主な用途:「開発環境」 →プログラムを書き換えながら実行結果を確認したい時に使います 28
  15. 名前付きボリューム Dockerが管理する専用のデータ領域を作り、そこに名前をつけてコンテナにつなぐ方法 dummy_volume:/app/.venv Docker dummy_volume (Dockerが管理) コンテナを消しても データは残る コンテナ /app/.venv

    (Python仮想環境) 主な用途:「データベースの保存先」 →中身を直接手でいじることがなく、データが消えてほしくないものに使います 29
  16. .venv を名前付きボリュームにしている理由 バインドマウント(.:/app) でホストのディレクトリ全体をマウントしているため、 そのまま.venv (Pythonのパッケージがインストールされるディレクトリ)を使おうと すると問題が起きる: 이 ホストとコンテナでOSが違う(macOS vs

    Linux)ため、コンパイル済みパッケー ジが互換性を持たない ・バインドマウントで上書きされるのを防ぐ 名前付きボリュームで上書きすると、.venv だけはDocker管理の領域に保存され、ホス トとコンテナが干渉しなくなる 30
  17. (まとめ)バインドマウント vs 名前付きボリューム 書き方 データの場所 ホストから見え るか コンテナ削除時 主な用途 バインドマウント

    ./host/path:/container/path ホストPCのファイルシステム 見える ホストにファイルが残る ソースコード同期、設定ファイル注 入 名前付きボリューム volume_name:/container/path Docker管理の領域 見えない(docker volume inspect で場所は確認 可能) ボリュームは残る(−v で削除可能) DB データ、パッケージキャッシュ 31
  18. ports - ポートの公開 ports: 8080:8000 # ホストのポート:コンテナのポート - 8888:8888 ポートマッピングの仕組みを図解↓

    あなたのブラウザ ホストPC コンテナ(app) http://localhost:8080 ポート 8080 ポート 8000 アプリが待ち受け http://localhost:8888 ポート 8888 ポート 8888 Jupyter等 なぜ8080:8000 のようにポートを変えるのか? ・コンテナ内のアプリはポート8000で動いている(Dockerfile等で決まっている) ・でもホスト側ではポート8000が他のプロセスで使われているかもしれない ・そこでホスト側だけ8080に変更して衝突を避ける 32
  19. environment - 環境変数 environment: WATCHFILES_FORCE_POLLING=truе PYRIGHT_PYTHON_FORCE_VERSION=1.1.393 - PYRIGHT_PYTHON_IGNORE_WARNINGS=1 - SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt

    REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt コンテナ内で使える環境変数を設定します。 環境変数 WATCHFILES_FORCE_POLLING PYRIGHT_PYTHON_FORCE_VERSION SSL_CERT_FILE / REQUESTS_CA_BUNDLE 役割 ファイル変更の検知方式を強制(Docker環境でホットリロードを 動かすため) 型チェックツールのバージョンを固定 SSL証明書の場所を指定(組織内のプロキシ対応等) 33
  20. environment - 書き方と注意点 書き方は2通りある: # リスト形式(この compose.yaml で使われている形式) environment: KEY=value

    KEY2=value2 # マップ形式(こちらもよく見る) environment: KEY: value KEY2: value2 ※どちらも同じ意味 34
  21. environment - 機密情報の扱い ・パスワードやAPIキーは compose.yaml に直接書くとGitに残ってしまう ・代わりに.env ファイルやenv_file ディレクティブを使い分ける #

    良くない例(パスワードがGitに残る) environment: - API_KEY=sk-1234567890abcdef # 良い例(.envファイルから読み込む) env_file: - .env #← •gitignore に追加しておく 35
  22. extra_hosts - ホスト名の追加 - extra_hosts: - host.docker.internal:host-gateway コンテナの/etc/hosts ファイルにエントリを追加する #

    コンテナ内の/etc/hosts に以下が追加される 192.168.65.2 host.docker.internal いつ使うのか? ・コンテナからホストPC上で動いているサービス(例えば、ローカルで動いている別 のAPIサーバー)にアクセスしたい場合に使う • host.docker. internal というホスト名でホストPCのIPアドレスが解決できるよう になる 36
  23. 4-3. db サービスを詳しく読む- ミドルウェアの定義 db: image: postgres:15.4 container_name: myapp-db command:

    -c "hba_file=/etc/postgresql/pg_hba.conf" ports: - 5432:5432 volumes: postgres_data:/var/lib/postgresql/data - ./docker/init_primary.sql:/docker-entrypoint-initdb.d/init_primary.sql -./docker/pg_hba.conf:/etc/postgresql/pg_hba.conf environment: - POSTGRES_USER=myapp_user - POSTGRES_PASSWORD=password - POSTGRES_DB=myapp healthcheck: test: pg_isready -U myapp_user -d myapp interval: 1s retries: 60 37
  24. image - 既存のイメージを使う image: postgres:15.4 Docker Hubで公開されている公式イメージをそのまま使用する イメージ名:タグ(バージョン) の形式で指定 postgres:15.4

    タグ(バージョンを指定) イメージ名 タグを省略すると latest (最新版)になるが、明示的に指定するのがベストプラクティス 38
  25. command - 起動コマンドの上書き command: -c "hba_file=/etc/postgresql/pg_hba.conf" Dockerイメージには、デフォルトで実行されるコマンドが設定されている command を指定すると、それを上書きできる #

    PostgreSQLイメージのデフォルトコマンド postgres # command で引数を追加 postgres -c "hba_file=/etc/postgresql/pg_hba.conf" この部分がcommand で指定した内容 ここでは、PostgreSQLの認証設定ファイル (pg_hba.conf) のパスを指定している 39
  26. DBサービスの volumes - 実践的な使い方 - volumes: # (a) DBのデータを永続化 postgres_data:/var/lib/postgresql/data

    # (b) 初期化SQLをコンテナに渡す ./docker/init_primary.sql:/docker-entrypoint-initdb.d/init_primary.sql # (c) 設定ファイルをコンテナに渡す ./docker/pg_hba.conf:/etc/postgresql/pg_hba.conf ※volumes の説明としては先程と同様のため割愛 ※問題:どれが「バインドマウント」で、どれが「名前付きボリューム」? 40
  27. environment - PostgreSQL固有の環境変数 environment: - POSTGRES_USER=myapp_user - POSTGRES_PASSWORD=password POSTGRES_DB=myapp #

    作成するユーザー名 # パスワード # 作成するデータベース名 ※これもenvironment の説明としては先程と同様のため割愛 41
  28. healthcheck - コンテナの健康状態を確認する healthcheck: test: pg_isready -U myapp_user -d myapp

    interval: 1s retries: 60 設定 意味 test 健康かどうかを判定するコマンド。終了コードOで「healthy」 interval チェックを実行する間隔(1秒ごと) retries 連続失敗の上限(60回失敗すると「unhealthy」) 42
  29. healthcheck - コンテナの状態遷移 コンテナの状態遷移: starting→ healthy(test が成功) unhealthy (retries 回連続で失敗)

    docker compose psで状態が確認できる: NAME myapp-db STATUS running (healthy) t healthcheck が通っている 43
  30. 4-4. db-replica サービス- depends_on と起動順序 の制御 db-replica: image: postgres:15.4 container_name:

    myapp-db-replica entrypoint: /etc/postgresql/entrypoint.sh ports: - 5436:5432 volumes: postgres_data_replica:/var/lib/postgresql/data -./docker/replica-entrypoint.sh:/etc/postgresql/entrypoint.sh depends_on: db: condition: service_healthy ※こちらも先程と同様、entrypoint とdepends_on 以外の説明は割愛 44
  31. depends_on - 「このサービスの後に起動して」 depends_on: db: condition: service_healthy db サービスが healthy

    状態になるまで、db-replica の起動を待つという意味 起動の流れ: 1. db が起動開始 2. dbの healthcheck が実行される(1秒ごと) 3. pg_is ready が成功 → db が「healthy」になる 4. db-replica の起動が始まる 46
  32. depends_on condition condition service_started 意味 サービスが起動したら(デフォルト) service_healthy service_completed_successfully レプリカDBが起動を待つのはなぜ? 이

    healthcheckが通ったら サービスが正常終了したら(バッチ処理向け) レプリカはプライマリDBのデータをコピーして作られる プライマリが起動していない状態でレプリカを起動しても、コピー元がないのでエラ 一になる 47
  33. 4-7. volumes - ボリュームの宣言 volumes: postgres_data: postgres_data_replica: dummy_volume: app_cache: postgres_data_testing:

    postgres_data_testing_replica: es-data: サービス定義内で使用する名前付きボリュームは、必ずここで宣言する必要がある (宣言を忘れるとエラーになる) services: db: volumes: postgres_data:/var/lib/postgresql/data ←ここで使っている volumes: postgres_data: ↓対応 ここで宣言が必要 50
  34. 4-8. compose.yaml全体のまとめ図 compose.yaml services: app (Webサーバー) build: Dockerfileからビルド - volumes:

    ソースコードをバインドマウント ports: 8080-8000 L environment:開発用の設定 db (プライマリDB) image: postgres:15.4 volumes:データ永続化 + 初期化SQL - environment: DB接続情報 healthcheck: pg_isready db-replica(読取専用DB) - depends_on: db (healthy) - db の後に起動 L entrypoint: レプリカ用の起動スクリプト db-testing / db-testing-replica(テスト用) └-構造は db / db-replica と同じ es (Elasticsearch) build: 専用Dockerfileからビルド ulimits: メモリロック無制限 L healthcheck: curlで HTTP チェック kibana (ESの可視化UI) image: Elastic公式レジストリから取得 L environment: ESの接続先を指定 volumes: postgres_data postgres_data_replica dummy_volume app_cache t DBデータ レプリカDBデータ Python.venv ←ビルドキャッシュ - postgres_data_testing ←テスト用DBデータ ☐ postgres_data_testing_replica es-data Elasticsearchデータ 51
  35. 起動する- docker compose up # フォアグラウンドで起動(ログがターミナルに流れる) docker compose up #

    バックグラウンドで起動(−d = detached) docker compose up -d # イメージを再ビルドしてから起動 docker compose ud -p --quild # 特定のサービスだけ起動 docker compose ud -p app 53
  36. 停止・削除する- docker compose down # コンテナを停止して削除する # ネットワークも削除される # ボリュームは残る(=

    DBのデータは残る) docker compose down # ボリュームも含めて完全に削除する #▲ DBのデータも全部消えるので注意! docker compose down -v docker compose down コンテナ ネットワーク ボリューム(残る) イメージ(残る) の削除範囲: docker compose down −v の削除範囲: ✓ ☑ コンテナ ネットワーク ボリューム(消える!) イメージ(残る) 54
  37. 状態を確認する- docker compose ps docker compose ps 出力例: NAME myapp-backend

    STATUS PORTS running 0.0.0.0:8080->8000/tcp, 0.0.0.0:8888->8888/tcp myapp-db running (healthy) 0.0.0.0:5432->5432/tcp myapp-db-replica running (healthy) 0.0.0.0:5436->5432/tcp myapp-db-testing running (healthy) 0.0.0.0:5433->5432/tcp myapp-db-testing-replica running (healthy) 0.0.0.0:5437->5432/tcp myapp-es running (healthy) 0.0.0.0:9200->9200/tcp 55