🔥

【学習メモ】Dockerを本気で理解しにかかる〜#1-5 docker-composeでコンテナ複数管理〜

2024/01/27に公開

概要

こちらの記事の#1-5 です。(#1-2#1-3#1-4
前回までで Dockerfile を使用し、docker runでコンテナを一つ起動する一通りの流れを見ていきましたので、今回はコンテナを複数管理できる docker-compose について見ていきます。

docker-compose

docker-compose とは yaml 形式で記載されるファイルのことで、コンテナを複数管理することができます。
例えば、一般的な Web アプリケーションでいうと、フロントエンド、バックエンド、DB と 3 つのコンテナが必要となり、一つのアプリケーションを開発するのに毎回 3 回docker runするのはかなり面倒ですよね。また、通常コンテナはそれぞれ独立した隔離空間となるのでそれぞれのコンテナ間で通信することはできません。
しかし、docker-compose であれば、一つのコマンドで必要な複数のコンテナを起動することができ、各コンテナ間の通信も可能になります。

要するに、docker-compose とは

要は、複数回のdocker runを一つのファイルで管理できるもの。といったものになります。なので、docker-copose.yml の構文はdocker runコマンドに対応する形で考えると理解が早くなるかもです。

yaml ファイルとは

時間があれば個別に記事にしてまとめようかと思いますので、ここでは簡単に説明しておきます。
yaml ファイルはインデントで親子関係を表現するファイル形式になっています。

・例

version: "2.4"
services:
  web:
    build: .
    depends_on:
      - db
      - redis
  redis:
    image: redis
  db:
    image: postgres

上記は Docker の公式ドキュメントに記載されている例ですが、

  • インデントが同じ位置から開始されているものは、並列関係
  • ネストされているものは親子関係
  • -から始まるものはリスト
    となっています。

docker-compose.yml の構文

docker-compose 内で使用される構文について、以下でまとめていこうと思います。

version と services

まず docker-compose.yml 絶対必要なものとして version と services があります。

varsion: "3.0"
services:
	web:
		container_name: "web_service"
	db:
		container_name: "db_service"
  • version

    • docker-compose のファイルのバージョンを指定します。バージョンが違えば構文や機能が違ってきたりしますが、最近は 3.x 系が使用されるのが一般的かと思います。
      3.x 系は Docker エンジン 1.13.0 以降で使用可能なようで、詳細はドキュメントを参照してください。
  • services

    • こちらには各サービス(コンテナ)の設定を記載していくことになります。上記の例では便宜上、もろもろ省略していますが、service に定義された数だけコンテナが起動されます。
      上記では、web と db というサービス(コンテナ)が作成され、各コンテナ名は「web_service」と「db_service」です。
      各コンテナ間(サービス間)で通信を行う場合にはサービス名で名前解決ができます。
      ただ、一点注意が必要なのは、これはコンテナ内から外部のコンテナに通信する際の話であって、コンテナ外の場合は、dblocalhost のように置き換えて考える必要があります。
    • container_name:上記で簡単に触れましたが、コンテナ名を指定できます。文字列なので、ダブルクォートで囲ってあげてください。

image と build

varsion: "3.0"
services:
	web:
		build: ./php
		container_name: "web_service"
		ports:
			- "80:80"
	db:
		image: postgres:15.1-alpine
		container_name: "db_service"
		ports:
      - 5432:5432

image と build はどちらもイメージを指定することになります。
違いは以下です。

  • build
    指定したディレクトリ直下にある Dockerfile からイメージを作成します。

  • image
    DockerHub などの Docker リポジトリからイメージを取得します。

要は使用用途としては、特に独自のカスタマイズが不要なイメージは image で DockerHub からベースイメージを取得。Dockerfile で独自のイメージの設定が必要な場合は、build で Dockerfile のあるディレクトリを相対パスで指定。といった感じになります!

:::note info
※2024/04/27:追記
build と image を両方指定した場合、build で指定されたディレクトリでイメージのビルドが実行され、イメージ名が image で指定された名前として管理されるようです。
:::

port

{外部公開ポート}:{コンテナ内部のポート}とすることでポートフォワーディングが可能。ポートフォワーディングについては以前まとめたので、概要は省略します。

volumes

{ホストのパス}:{コンテナのパス}とすることでディレクトリの共有(ボリュームマウント)が可能になります。

enviroment

環境変数を定義することができます。
定義方法は二通りあり、

  1. key-value 形式
environment:
  POSTGRES_USER: db-dev-user
  POSTGRES_PASSWORD: password
  POSTGRES_DB: dev-db
  1. リスト形式
environment:
  - POSTGRES_USER=db-dev-user
  - POSTGRES_PASSWORD=password
  - POSTGRES_DB=dev-db

となります。どちらでも大丈夫ですが、リスト形式では、key と value を=繋ぐことに注意してください。

docker-compose.yml の例

上記を踏まえて、docker-compose.yml を記載すると以下のような感じになりました。

varsion: "3.0"
services:
	web:
		build: ./php
		container_name: "php-container"
		ports:
			- "80:80"
		volumes:
			- ./php/html:/usr/share/nginx/html
	db:
		image: postgres:15.1-alpine
		container_name: "db-container"
		ports:
			- 5432:5432
		volumes:
			- ./data:/var/lib/postgresql/data
		enviroment:
			POSTGRES_USER: db-user
			POSTGRES_PASSWORD: db-password
			POSTGRES_DB: db-name

docker-compose コマンド

まず、以下の docker-compose コマンドは docker-compose.yml が存在するディレクトリで基本的に実行してください。
docker-compose.yml が同階層にない場合は、上位階層を見に行き、見つかったものを実行するようです。

docker-compose up

docker-compose.yml の内容を基に全てのコンテナ起動。-dオプションをつけてデタッチモードで起動することが多い

docker-compose up -d

docker-compose down

up で起動したコンテナの起動と削除を同時に行ってくれる。

docker-compose restart

docker-compose.yml で管理されているコンテナを全て再起動

docker-compose ps

docker-compose.yml で管理されているコンテナのみ一覧表示

docker-compose run

docker-compose.yml に定義されているサービルの一つを指定してコマンド実行

docker run vs docker-compose

では、docker-composeの構文がdocker runのどのコマンド、オプションに対応するのかを見ていきたいと思います。

機能概要 docker run docker-compose
イメージ指定 {イメージ名}:{タグ} image or build
コンテナ名を指定 -n or --name container_name
ボリュームのマウント -v or --volume volumes
ポートフォワーディング -p ports
環境変数の定義 e or --env enviroment

主要なものはざっとこんな感じでしょうか。

名前付きボリューム

各サービス配下に定義するvolumesは上記で記述したですが、volumesはトップレベルでも記述が可能です。
volumesをトップレベルで定義した場合、名前付きボリュームを設定することが可能です。

例:

varsion: "3.0"
services:
	web:
		build: ./php
		container_name: "php-container"
		ports:
			- "80:80"
		volumes:
			- ./php/html:/usr/share/nginx/html
	db:
		image: postgres:15.1-alpine
		container_name: "db-container"
		ports:
      - 5432:5432
		volumes:
			- db-data:/var/lib/postgresql/data
		enviroment:
			POSTGRES_USER: db-user
  		POSTGRES_PASSWORD: db-password
  		POSTGRES_DB: db-name

# 名前付きボリュームの定義を追加
volumes:
	db-data:
		driver: local

上記の db のvolumesdb-dataという名前付きボリュームにマウントしています。
このdb-dataはトップレベルのvolumesで定義しているものです。この場合、データの保存は Docker 管理下のディレクトリに保存されることになります。

web のサービスで行っているボリュームマウントは今まで通りディレクトリを指定した方法になっています。
これらの使い分けですが、DB のデータのようにホスト側から変更を加えない(もしくは変更してはいけない)ようなデータの永続化は名前付きボリュームで行われるのが一般的です。
それに対して開発中のソースコードはホスト側から変更を加えてリアルタイムに反映したいといったケースがあると思います。この場合にはディレクトリを指定したボリュームマウントが必要となります。

2 種類のボリュームマウント

今までにも説明しましたが、ボリュームのマウントには 2 種類あります。

  1. ボリュームマウント:
    これが上記の名前付きボリュームでマウントした方式になります。ボリュームマウントの場合は、Docker 管理下のディレクトリにボリュームを確保し、そこに保存されます。
    特徴としては、ホスト側から触りにくいといったところでしょうか。そのため、ホスト側から変更する必要がない DB データのボリュームマウントに適しています。

  2. バインドマウント:
    これが上記のディレクトリを指定したボリュームマウントになります。
    特徴はすでにご存知のとおり、ファイルを共有したような感じでホスト側の変更がリアルタイムでコンテナ側に反映されます。
    そのため、ホスト側からファイルの変更がしたい、開発中のソースコードなどの場合はバインドマウントが利用されます。

この 2 種類のボリュームマウントについては、大変わかりやすくまとめてくださっている記事があったので、参考にさせていただきました。

まとめ

今回は docker-compose について見ていきました。また、2 種類のボリュームマウントについてもまとめました!
これで一通り開発環境を構築することができるようになったと思いますので、今後の開発ではガンガン使っていこうと思います!

GitHubで編集を提案

Discussion