Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
3
Help us understand the problem. What is going on with this article?
@mmmmmmanta

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

More than 1 year has passed since last update.

前回の記事
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で使用できるので試してみてください。

3
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
fork
株式会社フォークは、Webサイトの企画・制作・開発・サーバホスティング・コンタクトセンターを一社に集約したワンストップソリューションを展開する制作会社です。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
3
Help us understand the problem. What is going on with this article?