🐳

Dockerについて網羅してみた(ハンズオンあり)

2023/04/09に公開

Dockerコンテナの概要と利点

コンテナでぐぐると、「仮想サーバー技術がうんたらこんたら〜」と出てくるが、それは忘れていいというのから衝撃を受けた。笑

それから入る情報が多かったので、(正直意味不だった)

一言で、コンテナとは「互いに影響しない隔離された実行環境を提供する技術」

もっとシンプルに考えていい。難しく考えようとしていた

→システムの実行環境を隔離した空間のこと

例)システムAとシステムBは、コンテナがあれば例えば、共通のフレームワークをアップデートしたりしても互い影響はない

コンテナの特徴は、「独立」していること(ここで言う独立とは単体で完結していること)

1台のサーバーにシステムが複数あっても競合しないこと

コンテナを実現するソフトの代表が「Docker」

  • DockerはLinux上で動作するソフトで、Linuxに「Docker Engine」をインストールするとDockerのコンテナを実行できる
    • Docker Engineの中に、docker コマンド、docker compose コマンド、その他が入っているからそれらのコマンドが使える

「Docker Desktop」(いつものやつ)

  • DockerをLinuxで動かす以外に、windowsやmacで「Docker Desktop」(いつものやつ)というソフトを動かしている。windowsやmacでDockerを動かすためのソフトウェア。windowsやmacでLinuxアプリを動かすものであり、windowsやmac0Sのアプリが動くわけではない。

Docker Desktop には Docker Engine や Linux のカーネルが含まれている
 ため、Linux 以外の OS でも Docker Engine を動かすことができるようになります。

要約すると Windows か Mac で Docker を使おうと思ったときにインストールする Docker 一式が入った GUI アプリケーション
 です。

「コンテナの元」となるDockerイメージ

  • 空っぽの状態からコンテナの中身(ライブラリ、FW、Linuxコマンドなど)を作るのは手間なので、それを支援するためにDockerイメージが存在している。DockerイメージはDocker Hubで公開されている。
  • Docker HubからDockerイメージをダウンロードして、ダウンロードしたDockerイメージからDockerコンテナを作る

例)WordPressを構築するとき

コンテナを使わない場合

  • phpインストール、WordPressインストール、webサーバーインストール、DBインストールしそれを設定し、、、でめんどい

コンテナを使う場合

  • Dockerイメージを入手して、コンテナを作るだけ
    • WordPressのコンテナとDBのコンテナをダウンロードするだけで楽ちん

カスタムDockerイメージ

カスタムDockerイメージを作るときは、Dockerfileにファイルのコピーやコマンド実行などの一連の流れを書いて、そのファイルを適用して作る。

作ったカスタムDockerイメージは、Docker HubのようなDockerレジストリに登録できる

※注意

Docker Hub「公開」として登録すると全世界の人が誰でもイメージを入手できるので、社内で作成したシステムは非公開にして、登録する。または、ECRというプライベートなリポジトリに登録する

まとめ

  1. Dockerは、DockerengineをインストールしたLinux環境で動く
  2. DockerコンテナはDockerイメージから作られる
    1. イメージはDockerHubなどのDockerレジストリに登録されていて、そこからダウンロードして使う)
  3. Dockerイメージは、Linuxのみとアプリケーション入りの2種類がある。
    1. カスタムするならLinuxのみ
    2. カスタムDockerイメージはDockerHubに登録できる(業務用なら非公開にする)
  4. DockerDesktopを使うと、Linuxで使っているのと同じDockerイメージをwindowsやmac0S上でDockerを動かせる

Dockerの利点

  1. コンテナは隔離した実行環境なので、他のシステムに影響を与えない。
    1. そのため1台のサーバーに複数システムを構築できる
    2. コンテナの中に必要なものをまとめて自在に実行できる
  2. Docker Hubでコンテナの元となるイメージが提供されているので、アプリケーション入のDockerイメージを使えば、複雑なインストールや設定をすることなく簡単にシステムを構築できる
  3. カスタムDockerイメージを作っておけば、同じコンテナを作ることができ、設定作業もしなくていいし、チームなどで共有できる
    1. チーム用のDockerイメージを作って、それをメンバー間で共有することで、開発環境の準備が容易にできる
  4. 開発環境と本番環境で差異なく、動作できる
    1. 開発環境で検証してOKであれば、安全確実、速やかに、本番環境でそのままデプロイできる

Dockerの欠点

  1. Linux以外で動かせない(DockerはLinuxの仕組みを使っているため)
    1. まぁDockerDesktopがあるので、それほど弊害ではない
  2. 完全な分離ではない(まあそんなに気にすることでもない)

Dockerの運用

  • 堅牢にするために、本番運用はマネージドなECSが望ましい

ECSもコンテナを実行する環境にすぎない。まずは、1台のサーバーでDcokerコンテナを作りそれを実行する。その後にECSの使い方を把握する

コンテナの操作

5分でDockerでWebサーバーを創造して破壊する

  1. イメージを探す

    1. Docker Hubから探す
      1. Webサーバーに「Apache」を使う
        1. https://hub.docker.com/_/httpdのイメージを使う
        2. How to use this image.に使い方が書いてある
  2. Dockerコンテナを起動する

    1. docker run ~でコンテナ起動
    2. 起動したかどうかのステータスはdocker psで確認
      1. STATUSがUpになっていれば起動している

    (DockerエンジンをインストールしたEC2を立て、SSHしてdocker runしてみる)

  3. コンテナの停止

    1. docker stopで止められる
      1. docker psしたときのContainerIDかNAMESを指定する

      2. 例)docket stop my-app または docker stop 6f45または6f

        ※ContainerIDは長いので、先頭から何文字目かを入力すればよい

        コンテナを停止してもまだ残ってはいる(docker ps -a で確認)

  4. コンテナの再開

    1. docker start で止まっているコンテナを再開
  5. ログの確認

    1. docker logsで確認できる
  6. コンテナの破棄

    1. stopやstartで停止と再開がいつでもできるが、コンテナはずっと残り続けているのでディスク容量を圧迫される
      1. docker rmで破棄(コンテナがstopしているのが前提)
      2. rmするとコンテナを消し去るので復活はできない(docker ps -a でも確認できない)
  7. イメージの破棄

    1. イメージもディスク容量を圧迫する。コンテナを消しても生きている
      1. docker image ls でダウンロードしたイメージを確認できる
      2. コンテナを消しても再度ダウンロードしなくても済むので残している
        1. docker image rm でイメージを削除(docker image lsからも消える)

操作まとめ

  1. Docker Hubでイメージを探す
  2. docker run でコンテナ起動
  3. docker stopで停止、docker startで再開
    1. docker ps でコンテナの状態を把握(-a をつければ停止中のコンテナも確認できる)
  4. docker logsでログの確認(エラーやデバックのときに使う)
  5. docker rmでコンテナの消去(stopした後に削除)
    1. ディスク容量を圧迫させないため不要であれば削除。またrunで起動できる
  6. docker image rmのイメージ破棄
    1. 再ダウンロードしなくてもすむけど、ディスク容量を圧迫させないため不要であれば削除

各コマンド基本操作

代表的な基本コマンド

※すべてのコマンドはリファレンスを参照

コマンド 意味
attach ターミナルをアタッチする(コンテナでbinding.pryをするとき)
build Dockerfileからイメージをビルド
cp ファイルをコピーする
create 新しいコンテナを作成
exec コンテナ内で色々コマンド実行
history Dockerイメージの履歴を確認
image イメージに対する操作
inspect Dockerオブジェクトに関する詳細情報を得る
kill コンテナの強制終了
load exportしたイメージを取り込む
login Dockerレジストリにログインする
logout Dockerレジストリからログアウトする
logs コンテナのログをみる
network ネットワークを管理
pause コンテナの一時停止
port ポートのマッピングを管理する
ps コンテナ一覧をみる
pull Dockerリポジトリからイメージを取得
push Dockerリポジトリにイメージを登録
rename コンテナ名を変更
save コンテナのイメージをtar形式にアーカイブしてイメージ化
start コンテナ起動
stop コンテナ停止
tag タグを作成
top コンテナで実行中のプロセス一覧を確認
unpause pauseで一時停止したコンテナを再開
version Dockerエンジンのバージョン
volume ボリュームを管理
wait コンテナが停止するまで待つ

ちなみに、docker runでは

  • docker pull:Docker Hubなどからイメージを取得して
  • docker create:コンテナを作成して
  • docker start:コンテナを起動する

を一気に行っている

docker createの起動オプション

例)apacheのコンテナを作成する

	docker create --name my-apache-app -p 8080:80 -v "$PWD":/usr/local/apache2/htdocs/ httpd:2.4
  • --name コンテナ名

    • コンテナに名前をつける
    • 結構重要かつよく指定する
      • コンテナ名を指定しないとランダムになって、管理もしづらい
    • p (-p ホストのポート番号:コンテナのポート番号)

      • ポート番号をマッピングする
      • -p 8080:80とは、Dockerホストのポート8080番をコンテナの80番に紐付けるという意味
      • ポート8080に接続すると、Dockerコンテナの80につながる。そこにApacheが待っていて公開されているWeコンテンツを参照できる。
      • Dockerではpオプションを指定しない限り、DockerホストとDockerコンテナとの通信はつながりません。Dockerホストとを通じてDockerコンテナ内で動いているプログラムと通信するには、明示的なpオプションが必要です。

      memo:-pはportの略ではなく、—publish(公開)の略。つまり、コンテナのポートの一部をホストから公開して、外から見えるようにする

  • -v ホストのディレクトリ:コンテナのディレクトリ

    • -vオプションは、コンテナの特定のディレクトリにホストのディレクトリをマウントする

    • -v "$PWD":/usr/local/apache2/htdocs/

      • $PWD:Dockerコマンドを入力した瞬間のホスト側のカレントディレクトリ(今いるディレクトリ
      • /usr/local/apache2/htdocs/:コンテナ側のマウント先のディレクトリ

      (httpdの作成者はこのディレクトリをwebコンテンツとして(ドキュメントルート)公開するように構成している)

      カレントディレクトリにindex.htmlを置いたら、その内容が表示される

<memo>

ポート番号やディレクトリはドキュメントやソースコードから判断する

「なぜポート80なのか?」「usr/local/apache2/htdocs/で公開するのか?」と思っていたが、それはhttpdイメージの作成者がそのように作ったからというだけ。

そのように作ってあるとドキュメントに書いてあるから。気になるならドキュメントやイメージのつくるためのソース読んでね。以上

docker run -dit --name my-apache-app 省略
  • -ditオプション
    • バックグラウンドで動かすための指定
    • 指定しない場合は、フォアグラウンドで実行される(コントロールCで停止できるがコンテナも停止してしまう)
    • ずっとバックグラウンドで実行したい場合は、このオプションが必要
オプション 意味
-d デタッチモード。端末と切り離した状態でバックグラウンドで実行する
-i インタラクティブモード。標準入出力及び標準エラー出力をコンテナと連結
-t 疑似端末を割り当てる。疑似端末とはカーソルの移動や文字の削除など、文字の入力をサポートする端末

よくコマンドで見る-i 、-tオプションとは

コンテナに対して操作するオプション

  • -iオプション

    • 標準入出力及び標準エラー出力をコンテナに対して結びつける
      • キーボードから入力した文字はコンテナに渡され、コンテナからの出力が画面に表示される
      • -i を指定しないとコンテナからの出力が届かないので各ログが表示されることはない
  • -t オプション

    • 疑似端末を有効する
      • カーソルキーやescキー、コントロールキーなど操作する
      • -iオプションのみだとこれらのキーが使えない

    -itをつけた場合

    $ docker attach test
    root@d43a339cc5ca:/# ls
    bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
    

    lsコマンドが実行されコンテナ内の情報が出力された。

    -itをつけなかった場合

    MacBook-Pro:~ $ docker attach test
    root@40b1356e3651:/# ls
    

    何も反応が返ってこない。

    標準入力(キーバードからの入力情報など)ができない状態のため、出力はされていない。

    コンテナのメンテナンス

    停止中や動いているコンテナの中に入って、ファイルやデータを確認したり、編集したり、なにかをインストールしたいときなどがある。

    本当にコンテナ内のプログラムが動いているのかやファイルの中身を知りたいことはよくある

    停止中のコンテナでシェルを実行する

    docker run --name コンテナ名 -it httpd:2.4 bin/bash
    root@3232hrh2444h:/usr/local/apache# ls
    bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
    

    /bin/bashを実行するにはコンテナ内にそのコマンドが格納されている必要があるが、ほとんどのイメージには入ってる。

    root@xxxxxxxxxxはコンテナID

    稼働中のコンテナでシェルを実行する

    docker exec -it コンテナ名 bin/bash
    root@3232hrh2444h:/usr/local/apache# ls
    bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
    

    docker runとdocker execの違い

    コマンド 状態 シェル終了時
    run 停止時 コンテナ終了
    exec 稼働時 稼働のまま

docker ps -aするとコンテナは終了しても残っているままが多い(StatusがExitの)

一回しか使わないコンテナを起動するときは、docker run -rm のオプションをつけるとコンテナの終了と同時にコンテナが消去されるので、つけた方がいい

不要なコンテナやイメージをすべて削除する

全コンテナの削除

docker container prune

全イメージの削除

docker image prune

コンテナ内のファイルと永続化

※個人的にここらへんが苦手なのと知見がない

コンテナはそれぞれが隔離された実行環境です

コンテナが破棄されたらその中にあるファイルも消えます。

コンテナを破棄してもファイルを残すための方法とバックアップの方法についての説明

2つのhttpdコンテナを起動する

docker run -dit --name web01 -p 8080:80 httpd:2.4
docker run -dit --name web02 -p 8081:80 httpd:2.4
docker ps
CONTAINER ID   IMAGE       COMMAND              CREATED          STATUS          PORTS                  NAMES
bb51430ff832   httpd:2.4   "httpd-foreground"   4 seconds ago    Up 3 seconds    0.0.0.0:8081->80/tcp   web02
5da22b140dc6   httpd:2.4   "httpd-foreground"   17 seconds ago   Up 16 seconds   0.0.0.0:8080->80/tcp   web01

これで1つのDockerホストの中に2つのコンテナ(webサーバー)を同居されました

コンテナの中にファイルをコピーする

どっちもコンテンツファイルを置いてないので、8080と8081を開くと両方とも「lt works!」と出る。index.htmlを置いて片方を「lt works01!」、もう片方を「lt works02!」とする

ファイルをコピーするコマンド

DockerホストとDockerコンテナ間でファイルをコピーできるdocker cp コマンドがある

ホスト→コンテナ

docker cp オプション コピー元のパス名 コンテナ名orID:コピー先のパス

コンテナ→ホストのコピーもできる

index.htmlを作る

% touch index.html
% vim index.html
% cat index.html 
<html>
<body>
<div>It's web01!</div>
</body>
</html>

コンテナにコピーする

docker cp index.html web01:/usr/local/apache2/htdocs/

http://localhost:8080/にアクセスする

コンテナ内に入ってコピーされたか確認する

% docker exec -it web01 /bin/bash
root@5da22b140dc6:/usr/local/apache2# ls -al /usr/local/apache2/htdocs
total 16
drwxr-xr-x 1 root     root     4096 Feb 11 01:26 .
drwxr-xr-x 1 www-data www-data 4096 Feb  9 04:59 ..
-rw-r--r-- 1      501 dialout    53 Feb 11 01:24 index.html
root@5da22b140dc6:/usr/local/apache2# cat /usr/local/apache2/htdocs/index.html 
<html>
<body>
<div>It's web01!</div>
</body>
</html>

index.htmlがあったのと、catコマンドでファイルの中身を見たがあっている。

コンテナweb02に対しても同じく実施

コピー完了

ただ、コンテナを壊して作り直すとファイルは失われます。

例えば、以下をやるとindex.htmlは消えます。

docker stop web01
docker rm web01

docker run -dit --name web01 -p 8080:80 httpd:2.4

docker exec -it web01 /bin/bash
root@5da22b140dc6:/usr/local/apache2 # cat /usr/local/apache2/htdocs/index.html<html>
<body>
<div>It's works!</div>
</body>
</html>

なぜこのようなことが起こるのか

コンテナは独立した環境で、コンテナを壊すとその内容も失われるから

コンテナweb01を壊して作り直す→これは最初作ったコンテナとは別物です

docker ps でコンテナidを見るとidは違います。

(破棄前)

コンテナid:08nfahhh44hf

(作り直した後)

コンテナid:jifah444hhff9h

なので、作り直す前のファイルが失われるように見える。

よって、コンテナを壊すのは注意が必要

データを独立させる

docker rmしたらそのコンテナ内のデータは失われます

なので、失いたくないデータは外に出すように設計する

結論、マウントすりゃいい!!

マウントすればコンテナを壊してもデータは消えない。つまり、データはコンテナ外に出す。

-vでマウントできる

web01コンテナを破壊する

docker stop web01
docker rm web01

マウントするディレクトリを作る→index.htmlを作成

% mkdir web01data
% cd web01data 
web01data % touch index.html
web01data % vi index.html 
web01data % cat index.html 
<html>
<body>
<div>mount test</div>
</body>
</html>

ディレクトリをマウントしてコンテナを起動

docker run -dit --name web01 -v /Users/xxx/web01data:/usr/local/apache2/htdocs -p 8080:80 httpd:2.4

mount testが表示

web01コンテナの破壊と創造

docker stop web01
docker rm web01
docker run -dit --name web01 -v /Users/xxx/web01data:/usr/local/apache2/htdocs -p 8080:80 httpd:2.4

再度ブラウザで確認すると、同じコンテンツが表示される

このようにデータを分ければコンテナのアップデートがしやすくなる

破棄してもファイルは、Dockerホスト側の/Users/xxx/web01dataディレクトリにあるので破壊しても失われない。コンテナが違っても同じデータが見える

つまり、データをコンテナ側ではなく、Dockerホスト側に持って、それをマウントすれば失われない。docker rmしても影響ないのだ

また、コンテナ間のデータ共有にも利用できる

1つの場所を2つ以上のコンテナで同時にマウントすることも可能。そうすればマウントした場所を通じてコンテナ間でファイル共有できる

設定ファイルもマウントで便利に指定できる

例えば、Apacheのconf(設定ファイル)をホスト側に置いておけば、破壊しても設定は残っている。結構使われるテクニック

バインドマウントとボリュームマウント

上記でやったのがDockerホストにディレクトリを作っておき、それをマウントする方法を「バインドマウント」

もう一つ「ボリュームマウント」という方法もある

ボリュームマウントとは、ホスト上のディレクトリではなく、DockerEngine上で確保した領域をマウントする方法。確保した場所をデータボリューム、略してボリュームという

docker volume コマンドがある

コマンド 意味
create ボリュームの作成
inspect ボリュームの詳細情報
ls ボリューム一覧
prune コンテナからマウントされていないボリュームを全削除
rm ボリュームの削除

ボリュームマウントの利点

ボリュームの保存場所がDockerEngineで管理されるため、物理的な位置を意識する必要がない

ディレクトリ構造はそれぞれのDockerホストによるので、Dockerホストに合わせた場所を指定しなければならず、汎用的ではない。

それに対して、ボリュームは汎用的でどのDockerホストも同じ。docker create やdocker runで指定するためのオプションは、どのDockerホストでも同じ。

バインドマウントを使う方がいい時

  • 設定ファイルの受け渡し
    • ホスト上に設定ファイルを置いたディレクトリを用意して、それをコンテナに渡したい場合
  • 作業ディレクトリの変更を即座にDockerコンテナに参照したいとき
    • Dockerホスト側でそのディレクトリ内のファイルを変更すれば、即座にコンテナに反映される
    • つまり、ホスト側でvscodeとか開いて、ファイルを編集できる。

ボリュームマウントを使う方がいい時

  • データベースのデータを保存するとき
    • コンテナをブラックボックスとして、コンテナを破壊してもデータを残るようにしたいから
    • データベースをホスト側から編集することはやらない(そんなことしたらデータが壊れる)

Dockerホストから不用意にデータを書き換えたくない場合は、ボリュームマウントを使う

MySQLでボリュームマウントを使う

DockerHubからmysql5.7のイメージを使う

https://hub.docker.com/_/mysql

  • マウントすべきディレクトリ

car/lib/mysqlディレクトリ

  • rootユーザーのユーザー名、パスワード、既定のデータベース名などの指定
    • MYSQL_ROOT_PASSWORDは必須(rootユーザーのパスワード)
    • 残りのオプションは任意

ボリュームを作成する。確認

docker volume create mysqlvolume
docker volume ls
local     mysqlvolume

ボリュームマウントをしたコンテナを作る

ボリュームをマウントしてmysqlコンテナを起動する

docker run --name db01 -dit -v mysqlvolume:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=mypassword mysql:5.7

コンテナ名:db01

ボリュームマウントは-vで作成したボリュームを指定する

-eで環境変数を指定する

データベースに書き込んだ内容が破棄されないことを確認する

実際にmysqlコンテナに入って、データベースを適当にデータを入れて、その後にコンテナを破壊し、創造したときにデータが残っているか検証

コンテナに入る〜

docker exec -it db01 /bin/bash

mysqlにログインしてデータベースを作る〜

mysql -p
Enter password: MYSQL_ROOT_PASSWORDを入力

mysql> CREATE DATABASE exampledb;
Query OK, 1 row affected (0.01 sec)

mysql> use exampledb;
Database changed

mysql> CREATE TABLE exampletable (id INT NOT NULL AUTO_INCREMENT, name VARCHAR(50), PRIMARY KEY(id));
Query OK, 0 rows affected (0.06 sec)

mysql> INSERT INTO exampletable (name) VALUES ('user01');
Query OK, 1 row affected (0.03 sec)

mysql> INSERT INTO exampletable (name) VALUES ('user02');
Query OK, 1 row affected (0.01 sec)

mysql> SELECT * FROM exampletable;
+----+--------+
| id | name   |
+----+--------+
|  1 | user01 |
|  2 | user02 |
+----+--------+
2 rows in set (0.00 sec)

コンテナを破壊

docker stop db01
docker rm db01

マウントした新しいコンテナを作る

別のコンテナを作る直し、-vでマウントする

docker run --name db01 -dit -v mysqlvolume:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=mypassword mysql:5.7

コンテナに入って、データベースを確認するとさっき作ったデータが入っていることがわかった

% docker exec -it db01 /bin/bash

bash-4.2# mysql -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.38 MySQL Community Server (GPL)

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use exampledb;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> SELECT * FROM exampletable;
+----+--------+
| id | name   |
+----+--------+
|  1 | user01 |
|  2 | user02 |
+----+--------+
2 rows in set (0.01 sec)

mountオプションを使ったマウント指定

-vオプションでマウントを使ってきたが、—mountオプションを使う方法がある。

--mount type=マウントの種類,src=マウント元,dst=マウント先
  • type
    • バインドマウントはbind
    • ボリュームマウントはvolume

例)ボリュームマウントの場合

vオプション

-v mysqlvolume:/var/lib/mysql

mountオプション

--mount type=volume, src=mysqlvolume, dst=/var/lib/mysql

mountオプションの方が推奨ではある

  • バインドマウントかボリュームマウントかわかりにくい
    • -vはマウント元が/から始まる、そうでないときはボリューム
  • ボリュームが存在しない時に新規に作成される
    • docker volume createで作ったけど、-vオプションでいきなり指定もできるが、新規に作られるからタイポした時とかめんどう
    • mountオプションはこうした事故が起きないようにボリュームが存在しないときは新規作成せずにエラーで教えてくれる

データのバックアップ

コンテナのデータをバックアップを行うとき、バインドマウントはDockerホスト上のファイルなのでホストからアクセスできるが、ボリュームのバックアップはどうするのか?

ボリュームの詳細を調べる(inspectコマンド)

docker volume inspect mysqlvolume
[
    {
        "CreatedAt": "2023-02-13T00:19:58Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/mysqlvolume/_data",
        "Name": "mysqlvolume",
        "Options": {},
        "Scope": "local"
    }
]

Mountpoint(/var/lib/docker/volumes/mysqlvolume/_data",)が実際にマウントされている場所

<バックアップの考え方>

ボリュームをバックアップするには適当なコンテナに割り当てて、そのコンテナを使ってバックアップする。

Linuxが入ったコンテナを起動し、/tmpなどのディレクトリにバックアップ対象のコンテナをマウントし、tarでバックアップを作る。

作ったバックアップをホスト側で取り出せば完了

ボリュームをバックアップする

docker run --rm -v mysqlvolume:/src -v "$PWD":/dest busybox tar czvf /dest/backup.tar.gz -C /src .
  1. 軽量なLinuxシステムのbusyboxを起動
    1. これは基本的なLinuxコマンドが入っている軽量コンテナ
  2. バックアップ対象を/srcにボリュームマウント
    1. 最初のvオプションで指定。このコンテナからはバックアップ対象がsrcから見える
  3. Dockerホストのカレントディレクトリに/destにバインドマウント
    1. 2つめのvオプションは"$PWD":/dest にバインドマウントしている。
  4. tarでバックアップを取る
    1. tar czvf /dest/backup.tar.gz -C /src .です
    2. これで/srcディレクトリの全ファイルがdest/backup.tar.gzにバックアップされる
    3. 上記の3でdestをカレントディレクトリにマウントしているので、このファイルはDockerホストのカレントディレクトリに現れる。ホスト上で取り出せる。

ルートディレクトリ(カレントディレクトリ)にbackup.tar.gz作られた

ls -al | grep backup
-rw-r--r--    1 xxx  staff     6936984  2 13 16:24 backup.tar.gz

まとめ

  • コンテナを破壊するとデータもなくなる
    • コンテナは隔離された実行環境にすぎないので、rmでコンテナを破壊するとデータも消える
  • 永続化したい場合はマウントする
    • コンテナを破壊してもデータを残したい場合は、保存先をホストのディレクトリの外に出してマウントすることで失われない
  • バインドマウントとボリュームマウント
    • 前者はホストのディレクトリをマウントする。後者はDockerエンジンで管理されている領域にマウントする
  • データのバックアップ
    • データのバックアップはマウント先をtar.gzなどでアーカイブする。ボリュームマウントのときは対象をマウントするコンテナを作って、そのコンテナ内でtarコマンドを実行してバックアップを取って取り出す。リストアもできる。

コンテナのネットワーク

Dockerホスト上ではたくさんのコンテナを実行できる。

それぞれ独立しているが、コンテナ間の通信が必要となることもある

Dockerが管理するネットワークはdocker network lsで確認できる

既定では、bridge、host、noneという3つのネットワークがある

よく使われるのはbridge

docker network ls
NETWORK ID     NAME                           DRIVER    SCOPE
652e43a6c4fb   bridge                         bridge    local
63b563b4c09c   host                           host      local
b72b13ae681a   none                           null      local
ebce3794ed2b   rails-docker-files_default     bridge    local

bridgeネットワーク

docker runするときにネットワークのオプションをつけなかった場合は、このネットワークが使われれる。bridgeネットワークにおいて、それぞれのコンテナのネットワークは独立していて、-pでどのコンテナと通信するか決めていた

コンテナのIPアドレスを確認する

Dockerホストやコンテナは1つの仮想的なbridgeネットワークで接続される

ネットワーク通信なのでホストやコンテナはIPアドレスが割り当てられる。

2つのコンテナを起動してIPアドレスを確認する

web01とweb02コンテナを起動します。

docker container inspectコマンドでコンテナの詳細な情報を見ることができますが、量が多いので、--formatオプションで特定の項目(IPアドレス)を指定しています。

docker container inspect --format="{{.NetworkSettings.IPAddress}}" web01
172.17.0.2
inspect --format="{{.NetworkSettings.IPAddress}}" web02
172.17.0.3

Dockerホスト同士の通信

コンテナはそれぞれIPを持ち、bridgeネットワークに接続されている。

なので、コンテナ同士はこのネットワークを通じて互いに通信できるんや

この通信はpオプションが設定されていなくても通信可能。理由は、コンテナ間で通信する際は、Dockerホストを経由せず、直接やり取りしますのでpオプションは関係ない。

pオプションはコンテナの特定のポートに転送する設定なので。

コンテナ間通信を検証してみる

第3のコンテナを作る

疎通確認用のコンテナを作ってシェルを起動

ubuntuのコンテナを作って、ip、ping、curlのコマンドを使うのでaptコマンドでインストールします

docker run --rm -it ubuntu /bin/bash
apt update
apt -y upgrade
apt install -y iproute2 iputils-ping curl

自身のIPアドレスを確認する

root@538f46b08998:/# ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN group default qlen 1000
    link/tunnel6 :: brd :: permaddr 630:429b:d5b6::
46: eth0@if47: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

172.17.0.4である(環境によって異なる)

pingで疎通確認

web01とweb02コンテナのIPアドレスに対して、pingを送信して疎通確認

0% packet lossが帰ってきたら疎通できている

-c 4は、4回試したら終わるというオプション

web01(172.17.0.2)

root@538f46b08998:/# ping -c 4 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=1.64 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.139 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.108 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.236 ms

--- 172.17.0.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3035ms
rtt min/avg/max/mdev = 0.108/0.529/1.636/0.640 ms

web02(172.17.0.3)

root@538f46b08998:/# ping -c 4 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=1.17 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.214 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.295 ms
64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.301 ms

--- 172.17.0.3 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3066ms
rtt min/avg/max/mdev = 0.214/0.495/1.173/0.392 ms

curlコマンドでコンテンツを取得する

web01、02はApacheが動作しています。公開されているコンテンツが取得できるか確認する

Its work!のhtmlが出るはずです。

curl http://IPアドレス

としてcurl http://IPアドレス/8080みたいにポート番号は指定しない。

ホストからは8080と8081にマッピングされているが、コンテナ自体はどちらもポート80番で待ち受けいているからIPアドレスのみ指定する

web01

root@538f46b08998:/# curl http://172.17.0.2/
<html><body><h1>It works!</h1></body></html>

web02

`root@538f46b08998:/# curl http://172.17.0.3/
<html><body><h1>It works!</h1></body></html>

※コンテナ名を使って通信することはできない

例)

ping -c 4 web01
curl http://web01/

—linkオプションで指定できるが、非推奨

Dockerでネットワークを作る

これまで既定のbridgeネットワークを使ってきたが、Dockerでは任意のネットワークを作ることができる。

ネットワークを作ることで、「あるコンテナはこっちのネットワークで、別のコンテナはこっちのネットワークに」というように別々のネットワークに接続できる

Dockerネットワークを作るとその数だけDockerホスト上にbr-XXXXXXXXXみたいな名前のネットワークインターフェイスが作られる

新たにネットワークを作ってそこにコンテナを参加させる場合は、bridgeネットワークと違ってコンテナ名で通信できる。さっきのIPアドレスでしか通信できない問題がなくなる

Dockerネットワークを作る

% docker network create mydockernet
f1f604766e62bcbf8d8fc95fbd5fcc779e25cf5513a513e9de438df527f70936
% docker network ls                
NETWORK ID     NAME                           DRIVER    SCOPE            
f1f604766e62   mydockernet                    bridge    local

IPアドレスの確認

172.18.0.0/16が設定されている

% docker network inspect mydockernet
[
    {
        "Name": "mydockernet",
        "Id": "f1f604766e62bcbf8d8fc95fbd5fcc779e25cf5513a513e9de438df527f70936",
        "Created": "2023-02-14T07:28:39.929274461Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

web01とweb02コンテナをmydockernetに接続する

inspectで2つのコンテナがネットワークに接続されているのがわかる

% docker network connect mydockernet web01
% docker network connect mydockernet web02
% docker network inspect mydockernet
[
    {
        "Name": "mydockernet",
        "Id": "f1f604766e62bcbf8d8fc95fbd5fcc779e25cf5513a513e9de438df527f70936",
        "Created": "2023-02-14T07:28:39.929274461Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "265e42a372532dd8646e8bf0e35ce5e267b576b7955af31db29c1c038c19147a": {
                "Name": "web01",
                "EndpointID": "99bb577556c30e425886b0f9e312e899cbe3e262787833100ecb9bd52a631ebb",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "cd38dc04d0bd2f7a82c8fe7d9246529416949b44ec557546e6e06163a1ea83a7": {
                "Name": "web02",
                "EndpointID": "b4977312d74c1c5d6adc1202a6240e6c85a64769f7c96b37201010322b8130ad",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }

コンテナ名を使って通信してみる

さっきと同じ手順でubuntuコンテナを作って、めんどいけど各コマンド(pingとか)を入れる


docker run --rm -it --net mydockernet ubuntu /bin/bash
apt update
apt -y upgrade
apt install -y iproute2 iputils-ping curl

root@9a357d87a2cd:/# ping -c 4 web01
PING web01 (172.18.0.2) 56(84) bytes of data.
64 bytes from web01.mydockernet (172.18.0.2): icmp_seq=1 ttl=64 time=2.42 ms
64 bytes from web01.mydockernet (172.18.0.2): icmp_seq=2 ttl=64 time=0.380 ms
64 bytes from web01.mydockernet (172.18.0.2): icmp_seq=3 ttl=64 time=0.244 ms
64 bytes from web01.mydockernet (172.18.0.2): icmp_seq=4 ttl=64 time=0.376 ms

--- web01 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3006ms
rtt min/avg/max/mdev = 0.244/0.856/2.424/0.906 ms
root@9a357d87a2cd:/# curl http://web01/
<html><body><h1>It works!</h1></body></html>

名前で通信できた!

◎Dockerネットワークがコンテナ名でアクセスできるようになる仕組み

DockerのDNSサーバーが使われているから

Dockerネットワークに参加したコンテナ(起動時に—net Dockerネットワークまたはdocker network connectで接続した)では、dockerが用意するDNSサーバーが使われている。

/etc/resole.confを見ると、127.0.0.11というIPアドレスのDNSサーバーが起動している

このDNSサーバーは、コンテナ名とIPアドレスの紐付けを返すような構成になっている

よって、コンテナ名を通信相手として指定できる

root@265e42a37253:/usr/local/apache2# cat /etc/resolv.conf
nameserver 127.0.0.11
options ndots:0

bridge ネットワークでは、後方互換のため、デフォルトでは内部DNSサーバはサポートされません。

※この他にhostネットワーク(ホストのIPアドレスを全Dockerコンテナで共有して使う)とnoneネットワーク(全くネットワークに接続しない)というのがあるがこれらはあまり使うことはない。

まとめ

  • Dockerホスト同士はIPアドレスで通信できる
    • bridgeネットワークではホスト同士はIPアドレスで接続できる
    • networkやcontainer inspectで確認できる
  • 名前で通信したいときは、Dockerネットワークを作る
    • コンテナ名でコンテナ間の通信をしたい場合は、network createでDockerネットワークを作り、docker runするときに—netオプションするかnetwork connect ネットワーク名 コンテナ名で接続するか
  • コンテナ間通信でpオプションは関係ない
    • コンテナ間通信では、pオプションは関係なくコンテナ上の実際のポート番号で通信できます。pオプションが指定されていなくても通信できる

Docker Compose

WordPressとMySQLのコンテナで1つのシステムを構成する

<手順>

  1. Dockerネットワークを作る
  2. ボリュームを作る
  3. MYSQLコンテナを作る
  4. WordPressコンテナを作る

Dockerネットワークを作る

コンテナ同士をつなぐのに、新しいDockerネットワークを作成する(bridgeネットワークだとわかりにくいため)

docker network create wordpressnet

ボリュームを作る

Mysqlコンテナのデータベース永続化に使うボリュームを作成

docker volume create wordpress_db_volume

MYSQLコンテナを作る

  • データベースの初期値を設定する環境変数の設定
  • nameはwordpress-db
  • wordpress_db_volumeはバインド
  • mysql:5.7を使う(最新だと認証方式から変わり、WordPressから接続できないため)
docker run --name wordpress-db -dit -v wordpress_db_volume:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=myrootpassword -e MYSQL_DATABASE=wordpressdb -e MYSQL_USER=wordpressuser -e MYSQL_PASSWORD=wordpresspass --net wordpressnet mysql:5.7

WordPressコンテナを作る

  • 8080:80でポートマッピング
  • 環境変数
    • 利用するデータベースの設定を指定(さっき作ったmysqlの情報と同じものを設定する)
    • 接続先のホスト名WORDPRESS_DB_HOSTにはすでに起動しているmysqlコンテナ名であるwordpress-dbを指定
    • Dockerネットワークに接続している場合、コンテナ名で接続できるため
docker run --name wordpress-app -dit -p 8080:80 -e WORDPRESS_DB_HOST=wordpress-db -e WORDPRESS_DB_NAME=wordpressdb -e WORDPRESS_DB_USER=wordpressuser -e WORDPRESS_DB_PASSWORD=wordpresspass --net wordpressnet wordpress

起動完了したのでhttp://localhost:8080/にアクセスする以下のように言語設定画面が出てくる

ユーザー名やパスワードを登録すると管理画面

http://localhost:8080/wp-admin/

これでWordPressコンテナとmysqlコンテナが連動して動くことを確認できたので、一旦コンテナを削除

Dcoker Composeを使う意味

今やったように、複数のコンテナはセットであり、どっちかを起動忘れたりすると動かない。

1つずつdocker runしたり、その際にnameオプション、pオプションでvオプションなど設定したり、コマンドも長くなって複雑になりがち。そして、コンテナを消すときにネットワークも一緒に削除する必要もある。

Dcoker Composeの仕組み

そうしたコンテナの作成や停止、破棄の一連の操作をまとめて実行する仕組みがdockercompose

予めコンテナの起動方法やボリューム、ネットワークの構成などを書いた定義ファイル(docker-compose.yml)を読み込ませることで、まとめて実行する方法

Docker Composeを使えば、長いコマンドや複雑なオプションを使う必要がなくなります。また、複数のコンテナをまとめて管理することができるため、コンテナ同士の連携もスムーズになります。さらに、複数のコンテナを起動する際の手順も簡略化されます。

メリット

  • 長い引数からの開放
    • docker runなどの際にいちいち引数を指定する必要がない
  • 複数コンテナの連動
    • まとめて複数のコンテナを起動できる、起動順序を指定できる
  • まとめて停止・破棄
    • コンテナをまとめて停止、破棄できる
  • コンテナ起動時の初期化やファイルコピー
    • コンテナ起動後にコマンドを実行したり、ファイルをコピーしたりする初期化など操作できる

※docker composeはDockerを操作するPythonのツール。Docker engineの一部ではない。別にインストールが必要

インストールされている場合

% docker-compose --version
docker-compose version 1.29.2, build 5becea4c

Docker Composeを使ってみる

Docker Composeを使うとコンテナの煩雑さはどのように解決されるのか、実際に試してみる

同じようにWordPressとmysqlコンテナを起動してみる過程をDocker Composeで行ってみる

作業ディレクトリを作成

% mkdir ~/wordpress
cd ~/wordpress

docker-compose.yml

version: "3"

services:
  wordpress-db:
    image: mysql:5.7
    networks:
      - wordpressnet
    volumes:
      - wordpress_db_volume:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: myrootpassword
      MYSQL_DATABASE: wordpressdb
      MYSQL_USER: wordpressuser
      MYSQL_PASSWORD: wordpresspass

  wordpress-app:
    depends_on:
      - wordpress-db
    image: wordpress
    networks:
      - wordpressnet
    ports:
      - 8080:80
    restart: always
    environment:
      WORDPRESS_DB_HOST: wordpress-db
      WORDPRESS_DB_NAME: wordpressdb
      WORDPRESS_DB_USER: wordpressuser
      WORDPRESS_DB_PASSWORD: wordpresspass

networks:
  wordpressnet:

volumes:
  wordpress_db_volume:

起動すると立ち上がる

wordpress % docker-compose up -d
Creating network "wordpress_wordpressnet" with the default driver
Creating volume "wordpress_wordpress_db_volume" with default driver
Creating wordpress_wordpress-db_1 ... done
Creating wordpress_wordpress-app_1 ... done
wordpress % docker-compose ps

          Name                         Command               State          Ports        
-----------------------------------------------------------------------------------------
wordpress_wordpress-app_1   docker-entrypoint.sh apach ...   Up      0.0.0.0:8080->80/tcp
wordpress_wordpress-db_1    docker-entrypoint.sh mysqld      Up      3306/tcp, 33060/tcp

コンテナの命名規則

作業ディレクトリ名_コンテナ名_1

wordpress_wordpress-app_1
wordpress_wordpress-db_1

docker-composeで起動するとこうした命名規則になる

結局、docker-composeで何が起きているのか

docker-composeで作ったコンテナはいままでdockerコマンドで作ったコンテナと変わらない。

docker-composeは人間が入力するのを肩代わりする便利なツールです。なので、docker psやvokume、networkでも確認できます。

wordpress % docker ps
CONTAINER ID   IMAGE                       COMMAND                  CREATED          STATUS                  PORTS                               NAMES
8e013ede2cb5   wordpress                   "docker-entrypoint.s…"   22 minutes ago   Up 22 minutes           0.0.0.0:8080->80/tcp                wordpress_wordpress-app_1
57ee052e59b2   mysql:5.7                   "docker-entrypoint.s…"   22 minutes ago   Up 22 minutes           3306/tcp, 33060/tcp                 wordpress_wordpress-db_1

wordpress % docker network ls
NETWORK ID     NAME                           DRIVER    SCOPE
28350619e3ff   wordpress_wordpressnet         bridge    local

wordpress % docker volume ls
DRIVER    VOLUME NAME
local     wordpress_wordpress_db_volume

必要であれば、コンテナを停止したりrmで削除したりすることもできるし、ネットワークもrmできる。しかし、docker composeから操作した状態と差異が起こり、管理しにくくなる。

なので、docker composeで作成したコンテナはdockerコマンドではなく、docker composeを使った管理に一元化すべき

コンテナを停止して破壊する

コンテナが停止→破壊

ネットワークも破壊

wordpress % docker-compose down
Stopping wordpress_wordpress-app_1 ... done
Stopping wordpress_wordpress-db_1  ... done
Removing wordpress_wordpress-app_1 ... done
Removing wordpress_wordpress-db_1  ... done
Removing network wordpress_wordpressnet

ボリュームは生きている(そのようにymlを記述したから。後ほど説明)

wordpress % docker volume ls
DRIVER    VOLUME NAME
local     wordpress_wordpress_db_volume

次にupしたときにこのボリューム内容はそのまま使われる。そこにマウントしているmysqlのコンテナが保存しているデータベースのデータが失われることはない。

停止や破壊時の注意

結局、upで起動、downで停止と破壊というまとめて操作できるのがdocker composeの機能

それだけなので、賢くはない。なので、扱い注意しなければいけない。

例えば、upとdown時でymlファイルが違う場合です。

downは実行時のカレントディレクトリのymlファイルを見て動きます。up時の起動時の状態を把握しているわけではない。upしたときにはymlファイルにコンテナAを使う設定があったが、その後にymlファイルを編集して、コンテナAを使う設定を削除した場合、downすればコンテナAは除外され、破壊されることはない。

downはあくまでその時点のymlファイルの通りに動作します。upしたあとにymlファイルを編集してdownしたときにコンテナの削除残しや意図しないコンテナやネットワークの削除が発生しないように注意する

docker-compose.ymlの書き方

大きくサービス、ネットワーク、ボリュームの3つから定義される

  • サービス
    • 全体を構成する1つ1つのコンテナのこと(サービス=コンテナと同義)
  • ネットワーク
    • コンテナ(サービス)が参加するネットワーク
  • ボリューム
    • コンテナ(サービス)が利用するボリューム

wordpress-db(mysqlコンテナ)

wordpress-db:
    image: mysql:5.7
    networks:
      - wordpressnet
    volumes:
      - wordpress_db_volume:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: myrootpassword
      MYSQL_DATABASE: wordpressdb
      MYSQL_USER: wordpressuser
      MYSQL_PASSWORD: wordpresspass
  • イメージ(image)
    • mysql5.7というイメージから起動するコンテナを作る
  • ネットワーク(networks)
    • wordpressnetというネットワークに接続(後述)
  • ボリューム(volume)
    • wordpress_db_volumeというボリュームを/var/lib/mysqlというコンテナのディレクトリにマウント
  • 起動失敗したときの再起動設定(restart)
    • 起動に失敗したときの再起動設定は「always」としました。コンテナの起動に失敗したときは、再起動が試みられる。再起動の際は、待ち時間がだんだんと長くなる
  • 環境変数(environment)
    • 各環境変数を設定。docker runの-eオプションで指定したときとお内zで、mysqlのパスワードやユーザー、データーベース名を指定します。

wordpress-appコンテナ(WordPressコンテナ)

wordpress-app:
    depends_on:
      - wordpress-db
    image: wordpress
    networks:
      - wordpressnet
    ports:
      - 8080:80
    restart: always
    environment:
      WORDPRESS_DB_HOST: wordpress-db
      WORDPRESS_DB_NAME: wordpressdb
      WORDPRESS_DB_USER: wordpressuser
      WORDPRESS_DB_PASSWORD: wordpresspass
  • 依存関係(depends_on)
    • dbコンテナに依存するという定義。dbコンテナより後に起動するようになる。
    • 停止するときは逆にappコンテナが先に停止し、dbコンテナが停止する
  • イメージ(image)
    • wordpressというイメージから起動するコンテナを作る
  • ネットワーク(networks)
    • wordpressnetというネットワークに接続(後述)
  • ポート(port)
    • ポートマッピングを指定。ここではホストの8080番をコンテナ80番に割り当てている
  • 起動失敗したときの再起動設定(restart)
    • 起動に失敗したときの再起動設定は「always」としました。コンテナの起動に失敗したときは、再起動が試みられる。再起動の際は、待ち時間がだんだんと長くなる
  • 環境変数(environment)
    • 各環境変数を設定。接続先となるmysqlのホスト名、データーベース名、ユーザー名、パスワードを指定。ホスト名はwordpress-dbのように先程定義したサービス名で指定している点に注目。同じymlに記述したサービス同士は、サービス名を指定することで通信できる。

ネットワーク

networks:
  wordpressnet:

ネットワークは、networksの部分で定義。名前だけ指定しているが、オプションでIPアドレス範囲などを指定することもできる。

ただ、ネットワーク設定を省略するのことの方が多い。

なぜなら、Docker-Composeでは明示的にネットワークを指定しなかったら、記述しているサービス(コンテナ)がつながる新しいDockerネットワークを自動的に作成し、すべてのサービスをそのネットワークに接続するよううに構成するため、この場合でもサービス名を宛先として指定して通信できる。

ボリューム

volumes:
  wordpress_db_volume:

コンテナが利用するボリュームは、volumesの部分で定義。

既定ではボリュームが存在しない場合はつくられ、作られたボリュームはdownしても削除されない。

docker-composeとdockerコマンドで実行する場合の違い

  • docker-compose.ymlが必要
    • docker-composeコマンドは、カレントディレクトリに置かれたdocker-compose.ymlを読み込む。このファイルがなければ失敗する
  • サービス名で指定する
    • dockerコマンドはコンテナ名かコンテナidで指定するが、composeではymlのservicesの部分に書かれたサービス名で指定
  • 依存関係が考慮される
    • composeではdepends-onで記述された依存関係が考慮される。例えば、WordPressappはdbコンテナに依存しているため、docker-compose start WordPressappしたときは、dbコンテナが先に起動します。

参考

さわって学ぶクラウドインフラ docker基礎からのコンテナ構築
https://www.amazon.co.jp/dp/B089VZXX63

Discussion