はじめに
Dockerって機能多すぎて、とりあえず実装して何も理解してないケースありませんか?
僕はボリュームがそのうちの1つでした...。
『これからDocker
やdocker-compose
を使い始める!』『volumes
が何をしているのか分からない...』という方には是非見て頂きたい記事となっております!
これを読むことで何が分かるのか
- Dockerのボリュームとは何か分かる
- docker-composeのvolumesに何を設定するべきか分かる
-
docker volume ls
をした時に何故か増えてるボリューム達が何なのか分かる - DockerにてNginxを使いたい時に、コンテナ間のリソース共有実装の足がかりになる
データを永続化するとは
突然ですが、貴重なデータが含まれているデータってシンプルに消えてほしくないですよね(。・_・。)
そんな貴重なデータをDockerにてDB(データベース)コンテナとして起動させていると、docker ps
コマンドにて以下の画像のようにDBコンテナ(postgreSQL)が立ち上がっていることが確認できますよね。
ここでもし誤ってDBコンテナを消してしまう事があったら、どうなってしまうでしょうか...
DBに蓄積してきたデータが全て消えます。
ですがコンテナ管理において、デファクトスタンダードとされているDocker様がそんな状況を放置するでしょうか?いや否です。
コンテナのデータを別の場所で保管できるボリューム機能があります!
ボリュームを使えば、例えDBのコンテナを消してしまっても、データを別場所にて保管しているので、復元できるという仕組みですね(/・ω・)/
ボリュームとは
こちらは僕が説明するよりコチラの記事(Docker、ボリューム(Volume)について真面目に調べた - Qiita *1)の説明が優れていると思ったので、引用させていただきます。
- ボリュームとは、データを永続化できる場所のことである。
- 外部HDDのようなイメージ。コンテナ本体にマウントして使う。
コンテナ
とボリューム
の違いについて- コンテナ内部にデータ(ファイル)を保存しても、コンテナ破棄すると消えてしまう。
- なので、データを永続化したいときは、コンテナの外にデータを置く必要がある。
- その場所のことを、ボリュームと呼ぶ。
ボリューム
(=データを永続化できる場所) は2種類ある。- ホストのディレクトリ(ファイル)
- ホストで ls で見えるモノ。
- Docker の リソースとしての Volume
- docker volume ls で見えるモノ。
- (本当は、これ以外にもNFSなども指定できるようだ)
- ボリュームをコンテナにマウントすることで、コンテナからアクセスできるようになる。
- あるいは
--volumes-from <コンテナ名>
とすると、指定したコンテナのマウントと同じようにマウントできる。
今までの僕のdocker-composeは...?
まずは『こんな記事にわざわざ見に来ていただいて感謝』ということで、恥ずかしながらも前まで設定していた駆け出しdocker-compose
を公開します。笑
version: "3"
services:
db: # データベース(つまり消えて欲しくない貴重なデータ群)が含まれているプログラム達
image: postgres
environment:
- POSTGRES_USER
- POSTGRES_PASSWORD
ports:
- "5432:5432"
back: # バックエンド(静的ファイル配信やmodelの定義、routing設定など)のプログラム達
build: .
volumes: # 注目
- .:/code # 注目
ports:
- "8000:8000"
command: gunicorn config.wsgi -b 0.0.0.0:8000 # サーバー起動
depends_on:
- db
上記の『ボリュームとは』から言うと、
volumes:
- .:/code
という記述は、ホスト側のディレクトリ(カレントディレクトリ化)
がコンテナ内(code下)
をマウントして、バックエンドのプログラムを永続化しているということになります(/・ω・)/
dbにはvolumesを記述していないので、もちろん消えて欲しくない貴重なデータが含まれたデータベースは永続化していません!?!?
もう序盤で既にオチを悟った方もいるかもしれませんが(笑)、詳しくおかしな点について解説していきますね!
余談(ここはスルーしてOKです)
恐らくこれを見た経験者は『いやそこボリュームとしてデータ永続化してどないすんねん!』と言うでしょう。笑
しかも事前にvolumeの名前も定義もしていないので、docker volume ls
でボリューム一覧を出力した時にも、どれがどのボリュームなのかわからない。
やはり独学で実装していると、docker volume ls
した時に知らないボリュームが増えていくことに『違和感』を覚えることはありましたが、『おかしい』ことを確信せずに実装していたのです。
なぜ勉強することになったか?
現在(2020/2/7)開発中である投票サービス《Shappar》で静的ファイルをDocker×Nginxで配信しようと思ったところ、以下の記事を見つけました。
DjangoをDocker Composeでupしよう! *2
↑上記事は要約すると『DjangoをGunicorn×Nginx×docker-composeを使ってサーバーを立ち上げよう!』というものです。そこでdocker-compose
の使用例として以下のような記述を見つけました。
version: '3.7'
services:
django:
restart: always
build: ./django
expose:
- "3031"
depends_on:
- postgres
command: bash -c "python manage.py migrate && gunicorn my_docker_project.wsgi -b 0.0.0.0:3031"
volumes:
- "staticdata:/opt/static/" # 3. ナンダコレ
nginx:
restart: always
image: nginx
depends_on:
- django
ports:
- "80:80"
volumes:
- "./nginx/:/etc/nginx/" # 1. ナンダコレ
- "staticdata:/opt/apps/static/" # 1. ナンダコレ 3. ナンダコレ
postgres:
image: postgres
ports:
- "5432:5432"
volumes:
- "dbdata:/var/lib/postgresql/data"
environment:
POSTGRES_PASSWORD: hogemojahogemoja
volumes: # 2.ナンダコレ
dbdata:
staticdata:
この記述を見て思った異変(自分の無知)の数々
-
./nginx/:
って...下のdbdata:
みたいにカンマスラッシュ
付けずにnginx:
←こうやって書き方統一しろよな!(※ヤバい間違いをしています。) - なんか一番下に
volumes
おる... - なぜ2回も
staticdata
を指定しているのだ...
先ほどの疑問点について勉強を開始
1. ディレクトリの記述方法について
とりまdockerの公式docs *3に飛びます。すると以下の記述がありました。
volumes:
# 1.パスを指定したら、Engine はボリュームを作成
- /var/lib/mysql
# 2.絶対パスを指定しての割り当て
- /opt/data:/var/lib/mysql
# 3.ホスト上のパスを指定する時、Compose ファイルからのパスを指定
- ./cache:/tmp/cache
# 4.ユーザの相対パスを使用
- ~/configs:/etc/configs/:ro
# 5.名前付きボリューム(Named volume)
- datavolume:/var/lib/mysq
記述によって動作が全く違う件
引用してきた上記のdocker-compose
から、僕が疑問に思った記述方法は③と⑤に当てはまります。
結論から言うと、./nginx/:/etc/nginx/
とnginx:/etc/nginx/
とでは、プログラムの実行内容が全然違います。
./nginx/: |
docker-compose.yml が存在しているディレクトリから、相対パスによってマウントする側の指定先としてホスト側のディレクトリ の指定を行います。 |
---|---|
nginx: |
この書き方をすると、マウントする側の指定先としてnginx という名前付きボリューム を探します。 |
マウントする側の指定方法として、./nginx/:
はカレントディレクトリから〜、対してnginx:
は名前付きボリューム
ありきで〜、というように方法が全く異なっていますね。
はて?名前付きボリュームですか。
2. 名前付きボリュームとは?(一番下にvolumes
がいる訳)
ここで先ほどの2つ目の疑問点『なんか一番下にvolumes
おる...』が解決できます。
なんとdocker-composeのvolumesにて名前を定義することによって、ボリュームに名前を付けています。
実際に先ほどのdocker-composeをもう一度見てみましょう。
version: '3.7'
services:
django:
restart: always
build: ./django
expose:
- "3031"
depends_on:
- postgres
command: bash -c "python manage.py migrate && gunicorn my_docker_project.wsgi -b 0.0.0.0:3031"
volumes:
- "staticdata:/opt/static/" # staticdataは一番下のvolumeで定義してるやつ!
nginx:
restart: always
image: nginx
depends_on:
- django
ports:
- "80:80"
volumes:
- "./nginx/:/etc/nginx/" # docker-composeからnginxというディレクトリを相対パスにより指定
- "staticdata:/opt/apps/static/" # staticdataは一番下のvolumesで定義してるやつ!
postgres:
image: postgres
ports:
- "5432:5432"
volumes:
- "dbdata:/var/lib/postgresql/data" # dbdataはvolumesで定義してるやつ!
environment:
POSTGRES_PASSWORD: hogemojahogemoja
volumes: # 名前付きボリュームを定義している
dbdata: # ボリューム
staticdata: # ボリューム
一番下のvolumes
で名前を付けていますね〜。これによりボリュームが作成されます!
もし既に名前を付けているボリューム
をvolumes
にて指定すると、その名前の付いたボリューム
からデータを参照してきます。
つまり『データを永続化している』訳ですね(/・ω・)/
そして以下のことが言えます!
- 先頭に
./
が付いていないdbdata
とstaticdata
は一番下のvolumes:
で名前を付けてから、名前付きボリュームとしてコンテナの外部に保管し、データを永続化している。 - 逆に先頭に
./
が付いているnginx
は相対パスでホスト側ののマウントするディレクトリを指定して、データを永続化している。ただし名前が付いていないので、VOLUME NAME
には20文字くらいの文字列が自動で名前として付きます。なので『もう一度使える』という意味での《永続化》はしていないですね。
果たして名前が付いているかdocker volume ls
コマンドにて確認します!
《サービス名_ボリューム名》となっていることが確認できました〜。(画像ではアンダーバーが途切れてます。笑)
3. 何故2回もstaticdata
を指定しているのだ...
1と2からなんとなく推測してみましょう。
今までの文章から考察するとこうなるかな...
- 1的観点から記述法を見ると、名前付きボリューム(staticdata)でバックエンドとNginxにマウントをとっているのがわかる。
- 2的観点から名前付きボリュームということはデータの永続化(データを別場所にて保管)をしている。
- staticdataとdbdataを比較すると、dbdataではpostgresのvolumesの1つしか設定していなかった。
《データを別の場所にて管理》 & 《バックエンドとNginxの2つマウント取ってる。》
これらの要素からボリュームでデータを別場所で管理できることを利用して、コンテナ間のリソース共有をしている!
もしやバックエンドコンテナとNginxコンテナで静的ファイルを共有して、静的ファイルに関してだけNginxで配信するという形が取れるのでは...?
当初の僕の目的であったNginxで静的ファイルを配信することに繋がってきました
まとめ
最後まで読んでいただきありがとうございました。
Docker系は使えるツールがあまりにも多いので、本当に把握しきれないです。特にボリュームの概念をつかむのはある程度触ってからでないと難しいのかも知れません(コンテナの概念やマウントという言葉の意味など...)。
ですがどこかのDocker初心者が僕のようにボリュームの概念について躓かないように、初心者である僕の目線でわかりやすく記事にさせていただきました!
間違っている点やシンプルな感想などでもございましたら、お気軽にコメントください!!
バックエンド(Django,RESTAPI)やAWS,Dockerなどの勉強していたり、機械学習にも少し手を出しているわたくしの姿を発信しているTwitterがあるので、もし良ければ...@heacet43
参考文献
- Docker、ボリューム(Volume)について真面目に調べた - Qiita [https://qiita.com/gounx2/items/23b0dc8b8b95cc629f32]
- DjangoをDocker Composeでupしよう! - Qiita [https://qiita.com/kyhei_0727/items/e0eb4cfa46d71258f1be]
- Compose ファイル・リファレンス — Docker-docs-ja 17.06.Beta ドキュメント [http://docs.docker.jp/compose/compose-file.html#volumes-volume-driver]