自主的20%るぅる

各々が自主的に好き勝手書くゆるふわ会社ブログ

Docker Compose

Docker Composeを解説

今回はDocker Composeに関する内容をアウトプットしていきたいと思います。

以前の記事でDockerfileに関する記事を書きました。併せて読んでいただくと理解の手助けになるかと思います。

Dockerfileを解説

Dockerfileとも密接に関係のあるDocker Composeについて解説したいと思います。

参考資料はDocker/Kubernetes実践コンテナ開発入門 改訂新版 を参考にしています。

Docker Composeとは

Docker Composeとは一言でいうと、単一のマシン上で複数のコンテナをまとめて管理する機能です。

こんな絵見たことないでしょうか?

composer

まぁ、これはComposerと言われるPHPのライブラリ管理ツールのアイコンなので別物なのですが、

Compose = 作曲する という意味になりますが、これだけだとよく意味がわかりませんね。

作曲するには楽譜にメロディーを書いて、最終的に出来上がった楽譜を見ながら楽器を使って音楽が完成します。

 

Docker Composeに話を置き換えてみましょう。

Docker Composeの絵は以下のようなものです。タコが足を使って複数のコンテナを持っていますね。

docker_compose

Docker Composeにもcompose.ymlと呼ばれる楽譜のようなものがあります。

このcompose.ymlファイルにどんなコンテナを定義したいのか?を書いていきます。(楽譜の場合はどんな曲を作りたいのか)

先に結論を言うと、このファイルが出来上がって$ docker compose up とコマンドをたたくとタコが動き出して定義したコンテナが起動し始めます。

アーキテクチャ

comose.ymlファイルを使ってコンテナが作られるアーキテクチャは以下のようなものです。

architecture

compose.ymlのファイルの例は以下のようなものです。

version: '3.9'
services:

  mysql:
    build:
      context: ./containers/mysql
    environment:
      MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_root_password
      MYSQL_DATABASE: taskapp
      MYSQL_USER: taskapp_user
      MYSQL_PASSWORD_FILE: /run/secrets/mysql_user_password
    secrets:
      - mysql_root_password
      - mysql_user_password
    volumes:
      - mysql_data:/var/lib/mysql
    ports:
      - "3306:3306"
  1. docker compose upコマンドを実行すると、タコを召喚し、compose.ymlに書かれた内容を実行する
  2. compose.ymlにはbuild: に書かれたコンテキストファイルを読み込む → ここでは/container/mysql 配下に置かれているDockerfileとその他設定ファイルを読み込み
  3. DockerfileのFROMに記述されたイメージをもとにDocker Hubからイメージを取得
  4. DockerfileのFROM以下の内容を実行しimageをbuild
  5. imageからDockerコンテナが起動される

上記のような流れでDocker Composeが実行されます。

単一のコンテナを操作する場合と複数のコンテナを操作する際の違い

単一のコマンドを起動する際には、dockerコマンドでコンテナへの操作を提供しますが、docker composeコマンドを使うことで複数のコンテナに対して実行、停止などの操作を1つのコマンドで行うことができます。

※誤解無きように記載しておくと、もちろん単一のコンテナに対してもdocker composeコマンドは使用可能です。

単一のコンテナを起動する際には以下のようなコマンドを打って、一つのコンテナを立ち上げます。

docker container run -d --name [コンテナ名] [コンテナイメージ名]

しかし、docker composeを使うことでcompose.ymlに定義した複数のコンテナを立ち上げることができます。

docker compose up -d

# compose.yml内で定義したsevicesのうち特定のコンテナのみ立ち上げたい場合はserivces名を指定する
# 指定しない場合はcompose.ymlで定義したservicesがすべて起動する
docker compose up -d [起動させたいコンテナサービス名1] [起動させたいコンテナサービス名2]

 

実際にcompose.ymlが何を書いているのかを説明していきましょう。

version: '3.9'
services: # (1)-1

  mysql: # (1)-2
    build: # (2)
      context: ./containers/mysql
    environment: # (3)
      MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_root_password
      MYSQL_DATABASE: taskapp
      MYSQL_USER: taskapp_user
      MYSQL_PASSWORD_FILE: /run/secrets/mysql_user_password
    secrets: # (4)-1
      - mysql_root_password
      - mysql_user_password
    volumes: # (5)-1
      - mysql_data:/var/lib/mysql
    ports: # (6)
      - "3306:3306"

secrets: # (4)-2
  mysql_root_password:
    file: ./secrets/mysql_root_password
  mysql_user_password:
    file: ./secrets/mysql_user_password

volumes: # (5)-2
  mysql_data:

 

(1)-1,2 services

servicesは作成するサービス(コンテナ)を定義しています。

今回の例ではmysqlという名前のコンテナを作りますよ、という定義をしています。

services:
  mysql:

(2) build

実際に./container/mysql配下にはDockerfileやコンテナに必要なビルドコンテキスト(設定ファイル)などを配置することによって、Dockerfileをもとにしたイメージをbuildします。

ビルドコンテキストについては以下に解説していますので併せて参照してみてください。

Dockerfileを解説

(3) environment

環境変数を指定する箇所です。

    environment: # (3)
      MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_root_password
      MYSQL_DATABASE: taskapp
      MYSQL_USER: taskapp_user
      MYSQL_PASSWORD_FILE: /run/secrets/mysql_user_password
  • MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_root_password
  • MYSQL_PASSWORD_FILE: /run/secrets/mysql_user_password

上記二つはMySQLのrootユーザパスワード, 一般ユーザ(MySQLユーザ)のパスワードが保存されているディレクトリを参照する指示になっています。

/run/secrets/mysql_root_passwordにMySQLに接続する際のrootユーザのパスワードが記述されたファイルがあるのでそこを参照しなさい。

/run/secrets/mysql_user_passwordに一般ユーザ(MySQLユーザ)のパスワードが記述されたファイルがあるのでそこを参照しなさい。と指示を出しています。

このディレクトリはコンテナ内のディレクトリを指しており、厳密には後述するsecretsで定義しているホスト側で生成したパスワードを参照する仕組みになっています。

  • MYSQL_DATABASE: taskapp
  • MYSQL_USER: taskapp_user

上記二つはMySQLに作成するデータベース名、ユーザ名を定義しています。

(4)-1,2 secrets

secretsは環境変数に渡す値を定義します。

    secrets: # (4)-1
      - mysql_root_password
      - mysql_user_password

secrets: # (4)-2
  mysql_root_password:
    file: ./secrets/mysql_root_password
  mysql_user_password:
    file: ./secrets/mysql_user_password

環境変数に渡す値を定義する理由としては、ymlファイルに直接パスワードなどのシークレットな値を記述すると、GitHub上に誤って公開してしまった場合に大事故になるからです。

GitHubは基本的プライベートにしていたとしても、誤ってパブリックで公開されてしまった場合のリスクもあるため、パスワードなどのシークレットな情報はymlファイルに直接記述することは推奨されません。

前提を理解できたところで、secretsをどう読み取っているのかを見てみましょう。

図で表すと以下です。

architecture

 

compose.ymlのsecretsディレクティブに記載されたmysql_root_password, mysql_user_passwordの箇所を参照しなさい、という指示で、ではそのsecretsの情報はどこのディレクトリに存在しますか?という記述が、file: 以降に記述のあるホスト内のデディレクトリにファイルが配置してあるので、そこを参照しなさい、というコードになっています。

/secrets/mysql_root_passwordファイルと/secrets/mysql_user_passwordファイルに記述があるため、そこを参照します。

さらにホストで定義したsecretsファイルをdocker compose upを実行の際にコンテナ側のディレクトリへコピーすることで、コンテナがMySQL起動時に指定されたディレクトリを参照しMySQLへ接続できるわけです。

言葉だけで表現するとちょっとわかりづらいかと思いますが、図で表現すると理解がしやすいかと思います。

(5)-1,2 volumes

コンテナにマウントされるボリュームを定義します。

services: 

  mysql:
    # services内で宣言されているvolumes
    volumes: # (5)-1
      - mysql_data:/var/lib/mysql

# 途中省略 

# トップレベルのvolumes      
volumes: # (5)-2
  mysql_data:

services内で宣言されているvolumesはmysql_dataというボリュームに対してコンテナ内の/var/lib/mysql/がマウントしているという意味になります。

では、mysql_dataというボリュームはどこで作られているのでしょうか?

それがトップレベルで宣言されているvolumesのmysql_data: がそれにあたります。

このトップレベルで宣言されたvolumesによってデータを永続化するボリュームを作成し、mysqlコンテナがマウントします。

volumesの補足

volumesがどういう仕組みかを一時的なコンテナを作成して確認してみましょう。

まず、以下のコマンドを実行してbusyboxという名前のコンテナを作成し、さらにmyvolというボリュームを作成し、busyboxの/dir → myvol にマウントします。

イメージは何でも良いですがubuntu:23.10を使用します。

$ docker container run --rm -it --name busybox -v myvol:/dir ubuntu:23.10

# busyboxに/dirディレクトリが作成されているためcdします
root@283506ea2808:/# cd dir/
# /dir内にtest.txtファイルを作成し、exitします
root@283506ea2808:/dir# touch test.txt
root@283506ea2808:/dir# exit
# --rm を指定しているため、exitした時点でbusyboxは破棄されます

# dockerボリュームが作成されていることを確認します
$ docker volume ls
DRIVER VOLUME NAME
local myvol
# 新たなbusyboxを作成し、今度は/dir2としてmyvolにマウントします
$ docker container run --rm -it --name busybox -v myvol:/dir2 ubuntu:23.10

# /dir2からmyvolに保存されているtest.txtが見えることが確認できます
root@32a8631634c3:/# cd dir2/
root@32a8631634c3:/dir2# ll
total 8
drwxr-xr-x 2 root root 4096 Mar 30 23:08 ./
drwxr-xr-x 1 root root 4096 Mar 30 23:37 ../
-rw-r--r-- 1 root root 0 Mar 30 23:08 test.txt

このボリュームについてですが、最初非常にややこしいですが、以下の記事が非常にわかりやすく書かれていました。

ぜひ参考に読んでいただくと良いかと思います。

Docker、ボリューム(Volume)について真面目に調べた – Qiita

(6) ports

最後にportsです。

    ports: # (6)
      - "3306:3306"

ポートはホストマシンとDockerコンテナ間のネットワークポートマッピングを紐づけます。

上記の場合、コンテナ内で接続を待ち受けるポート3306番をホストのポート3306番に紐づけています。

今回はDocker Compseについて解説してみました。

参考資料:

Let’s share this article!

{ 関連記事 }

{ この記事を書いた人 }

アバター画像
Yuki_Izumi

32歳から医療業界からエンジニアに転職しました。

野球、バスケ、将棋、絵を描くこと、などなど
色々多趣味ですが、結婚してエンジニアになってからは
すべて疎遠になりました。

生活に余裕ができたらすこーしずつ趣味も実践していきたいと
思っている未熟エンジニアです。

記事一覧