LoginSignup
5

More than 3 years have passed since last update.

Organization

Docker入門 〜Docker-compose, ネットワーク, ボリューム編〜

前回の記事
Docker入門 ~Dockerfile編~
の続きです。

Docker-compose

Docker-composeは、複数のコンテナを簡単に操作できる仕組みです。
使用したいコンテナの数が増えるとdockerコマンドをうつのが大変ですが、docker-composeコマンドで楽になります。

ファイル構成は以下とします。

.
├── docker-compose.yml
├── mysql
│   ├── Dockerfile
│   └── my.cnf
└── public
    └── index.html

mysqlディレクトリの内容
Dockerfile
FROM mysql:5.7.27

RUN apt-get update \
  && apt-get install -y locales \
  && rm -rf /var/lib/apt/lists/* \
  && echo 'ja_JP.UTF-8 UTF-8' >> /etc/locale.gen \
  && locale-gen ja_JP.UTF-8

ENV LANG ja_JP.UTF-8

COPY ./my.cnf /etc/mysql/conf.d/my.cnf
my.conf
[client]
default-character-set=utf8mb4

[mysqld]
character-set-server=utf8mb4

docker-compose.yml

docker-compose.ymlで、docker-composeコマンドでまとめて起動するコンテナの設定を記述します。

docker-compose.yml
version: '3.7'

services:
  php:
    image: my-php-apache:7.3.10
    ports:
      - 80:80
      - 443:443
    networks:
      - web
    volumes:
      - ./:/var/www

  mysql:
    build: ./dockerfiles/mysql
    expose:
      - 3306
    networks:
      - web
    volumes:
      - mysql:/var/lib/mysql
    environment:
      - MYSQL_DATABASE=laravel
      - MYSQL_USER=laravel
      - MYSQL_PASSWORD=secret
      - MYSQL_ROOT_PASSWORD=secret

networks:
  web:

volumes:
  mysql:

上記では、phpコンテナとmysqlコンテナを設定しています。docker-compose upコマンドで、コンテナをまとめて起動できます。

$ docker-compose up                         
Creating network "sample_web" with the default driver
Creating volume "sample_mysql" with default driver
Creating sample_php_1   ... done
Creating sample_mysql_1 ... done
Attaching to sample_php_1, sample_mysql_1

docker-compose.yml解説

上記ymlファイルの解説です。

docker-compose.yml
version: '3.7'

Docker-compose.ymlの記述方法のバージョンを指定しています。古いバーションだと使用できないキーなどがあります。

docker-compose.yml
services:
  php:
    ...
  mysql:
    ...

Docker-composeはコンテナをサービスとして管理します。ここではphpとmysqlのコンテナ設定を書いていきます。

docker-compose.yml
services:
  php:
    image: my-php-apache:7.3.10
    ports:
      - 80:80
      - 443:443
    networks:
      - web
    volumes:
      - ./:/var/www
  • image - 使用するイメージ
  • ports - ポートのバインディング。ホスト:コンテナの順番でかく
  • networks - コンテナが所属するネットワーク(後述)
  • volumes - マウントするボリューム(後述)

ボリュームは前回利用しましたが、データをコンテナとは別に管理して永続化する仕組みでした。後ほどネットワークと合わせて詳しく解説します。

docker-compose.yml
  mysql:
    build: ./mysql
    expose:
      - 3306
    networks:
      - web
    volumes:
      - mysql:/var/lib/mysql
    environment:
      - MYSQL_DATABASE=laravel
      - MYSQL_USER=laravel
      - MYSQL_PASSWORD=secret
      - MYSQL_ROOT_PASSWORD=secret
  • build - Dockerfileのパス

イメージではなくDockerfileも指定できます。

  • expose - 他のサービスに公開するポート(ホストからはアクセスできない)
  • environment - コンテナ内で使用できる環境変数

特定の環境変数を設定しておくと楽にカスタマイズできるように、ベースイメージ側で準備してくれていることがあります。
MySQLイメージのDockerHubページを見ると、MYSQL_DATABASEでデータベース名を設定できると分かります。
ここでは上からデータベース名、データベースのユーザー名、ユーザーのパスワード、ルートユーザーのパスワードを設定しています。Laravelからデータベースに接続するときに、この情報で接続します。

docker-compose.yml
networks:
  web:

volumes:
  mysql:

各サービスで使用するネットワーク・ボリュームを明示します。忘れると動作しません。

Dockerネットワーク

Docker-composeというよりDockerの仕組みですが、ここで説明します。

コンテナは同じ仮想ネットワークに配置されないと、相互にやりとりできません。なので、ApacheのコンテナとMySQLのコンテナは同じネットワークにしてあげます。

docker-compose.yml
services:
  php:
    networks:
      - web

  mysql:
    networks:
      - web

networks:
  web:

同じネットワークにすると、コンテナ内から他のコンテナにアクセスするときに、サービス名でアクセスできるようになります。
phpコンテナに配置したLaravelアプリケーションから、MySQLコンテナにアクセスするには.envファイルをこう書きます。

.env
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laravel
DB_PASSWORD=secret

DB_HOSTがmysqlとサービス名になっていて、これで繋がります。内部的にはDockerがDNSサーバーを用意して、名前解決してくれるようです。

Dockerボリューム

こちらもDocker-composeというよりDockerの仕組みですが、ここで説明します。

MySQLコンテナを立ち上げて、DBにデータを保存してもコンテナを削除するとそのデータは消えてしまいます。データを永続保存するための仕組みがボリュームです。
ボリュームはコンテナとは切り離して管理されるもの、ということです。

ボリューム一覧は以下のコマンドで確認できます。

$ docker volume ls
DRIVER              VOLUME NAME
local               tmp
...

ボリュームには以下の3種類があります。

  • ホスト(host)
  • 匿名(anonymous)
  • 名前付き(named)

ホストボリューム

-v /host/path:/container/pathでホストのパスをコンテナのパスにマウントし、ボリュームとします。

$ docker container run -dit -v $HOME/tmp:/tmp alpine

上記の例ではコンテナを削除しても、/tmpの内容は$HOME/tmpに残ります。そしてホストボリュームはdocker volume lsには表示されません。

匿名ボリューム

-v /container/pathで、匿名ボリュームです。

$ docker container run -dit -v /tmp alpine

Dockerが隠蔽して管理するボリュームで、ハッシュ値がボリューム名となります。

$ docker volume ls
DRIVER              VOLUME NAME
local               a1138c254e5df7d419191d29e9e7e5acaf6389d69521c09eb00abe05889151ad

名前付きボリュームがなかった時代に使われていたようで、現在は名前付きボリュームを使います。
docker container run --rmで立ち上げたコンテナが削除される時、匿名ボリュームも削除されるという特徴があります。

名前付きボリューム

-v name:/container/pathで名前付きボリュームです。

$ docker container run -dit -v tmp:/tmp alpine

こちらもDockerが隠蔽して管理するボリュームですが、名前がありアクセスしやすいです。

$ docker volume ls
DRIVER              VOLUME NAME
local               tmp

またdocker container run --rmで立ち上げたコンテナが削除されても名前付きボリュームは削除されません。

どの種類のボリュームにするか

最初のdocker-compose.ymlを見ると、phpコンテナはホストでファイルを編集したいので、ホストボリューム./:/var/wwwにしています。
MySQLコンテナは、特にホストでMySQLが管理するファイルをいじることはないですから、名前付きボリュームmysql:/var/lib/mysqlです。ただホストボリューム./.db:/var/lib/mysqlなどにしても問題はないと思います。

また、前回でやったcomposerの例で考えてみましょう。
composer installするためのcomposer.jsonや、インストール結果のvendorディレクトリなどをコンテナとやりとりするだけであれば、ホストボリュームでいいです。
今後別のコンテナでcomposer installするためのキャッシュは、名前付きボリュームでどこからでも参照できるようにしておきましょう。

$ docker container run --rm -it -v $PWD:/app -v composer_cache:/tmp composer install

上記なら、2回目以降は以下のようにキャッシュからインストールしてくれます。

$ docker container run --rm -it -v $PWD:/app -v composer_cache:/tmp composer install
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Package operations: 84 installs, 0 updates, 0 removals
  - Installing doctrine/inflector (v1.3.0): Loading from cache
  - Installing doctrine/lexer (1.1.0): Loading from cache
...

ボリュームにファイルがあると

  • ボリュームにファイルあり、コンテナになし
    ボリュームのファイルがコンテナにコピーされる

  • ボリュームにファイルなし、コンテナにあり
    コンテナのファイルがボリュームにコピーされる

  • 両方にファイルあり
    コンテナのファイルがなくなり、ボリュームのファイルがコンテナにコピーされる

実際にdocker-composeコマンドを使ってみよう

docker-compose.ymlがあれば、以下のコマンドでコンテナを一気に立ち上げることができます。

$ docker-compose up

起動したコンテナ、ネットワーク、ボリュームを確認してみましょう。

$ docker container ls                     
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS                                      NAMES
af5e814670de        my-php-apache:7.3.10   "docker-php-entrypoi…"   5 minutes ago       Up 5 minutes        0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   sample_php_1
e4116e1a3bfa        sample_mysql           "docker-entrypoint.s…"   5 minutes ago       Up 5 minutes        3306/tcp, 33060/tcp                        sample_mysql_1

$ docker network ls  
NETWORK ID          NAME                DRIVER              SCOPE
81e33015a6f9        bridge              bridge              local
e2eab5ac1197        host                host                local
a8432cc388c6        none                null                local
37b562bfd9c1        sample_web          bridge              local

$ docker volume ls 
DRIVER              VOLUME NAME
local               sample_mysql

ネットワークのbridge,host,noneは、デフォルトで用意されているネットワークなので気にしないでください。

dockerコマンドと同じように、exec <service> <command>でコンテナ内でコマンドを実行できます。

$ docker-compose exec php bash
root@026c8f03e602:/var/www#

MySQLに接続するのであれば

$ docker-compose exec mysql mysql -u laravel -D laravel -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.

コンテナ削除もdocker-compose downでまとめてできます。コンテナとネットワークが削除され、ボリュームは残ります。

$ docker-compose down
Stopping sample_php_1   ... done
Stopping sample_mysql_1 ... done
Removing sample_php_1   ... done
Removing sample_mysql_1 ... done
Removing network sample_web

プロジェクト

コンテナ、ネットワーク、ボリューム名がsample_*になっています(コンテナ名はls結果の一番右に書いてあります)。これはsampleディレクトリ下でdocker-compose upしたからです。

他のディレクトリでdocker-compose upすると、そのディレクトリ名がプリフィックスになります。ディレクトリ名だとわかりにくい場合は、環境変数COMPOSE_PROJECT_NAMEや-pオプションでプリフィックスを指定できます。
docker-composeコマンドは.envファイルをみてくれるので、以下のようにしましょう。

.env
COMPOSE_PROJECT_NAME=プロジェクト名

プロジェクト固有のイメージ

docker image lsコマンドで所持イメージを確認してみます。

$ docker image ls                                                        
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
sample_mysql        latest              c8914e3551fe        35 seconds ago       385MB
my-php-apache       7.3.10              ed7f24566ef1        About a minute ago   452MB
php                 7.3.10-apache       b83ebda0d7d4        7 weeks ago          410MB
mysql               5.7.27              383867b75fd2        3 months ago         373MB

phpとmysqlはベースにした公式イメージで、my-php-apacheは前回自分でビルドしたイメージでした。
sample_mysqlは、docker-compose upした時にビルドされたイメージです。

docker-compose.ymlにbuildを指定すると、プロジェクトごとにイメージがビルドされます。今回は

docker-compose.yml
  mysql:
    build: ./mysql

としていたので、sampleがプリフィックスのプロジェクト固有のmysqlイメージになりました。

プロジェクトごとにイメージを持ちたいならbuildを、使いまわしたいなら最初にdocker buildしておき、それをimageに指定すれば良いでしょう。

終わりに

Docker-composeを使うことができれば、開発環境は構築できると思います。
他のイメージを使えば、PostgreSQLやRedisサーバー、メール送信のテストを行えるMailHogなどを立ち上げてLaravelで使用できるので試してみてください。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
5