47
35

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ボリューム(volumes)で何ができるか気づけたから解説!(docker-compose)

Last updated at Posted at 2020-02-07

はじめに

Dockerって機能多すぎて、とりあえず実装して何も理解してないケースありませんか?
僕はボリュームがそのうちの1つでした...。

『これからDockerdocker-composeを使い始める!』『volumesが何をしているのか分からない...』という方には是非見て頂きたい記事となっております!

これを読むことで何が分かるのか

  • Dockerのボリュームとは何か分かる
  • docker-composeのvolumesに何を設定するべきか分かる
  • docker volume lsをした時に何故か増えてるボリューム達が何なのか分かる
  • DockerにてNginxを使いたい時に、コンテナ間のリソース共有実装の足がかりになる

データを永続化するとは

突然ですが、貴重なデータが含まれているデータってシンプルに消えてほしくないですよね(。・_・。)
そんな貴重なデータをDockerにてDB(データベース)コンテナとして起動させていると、docker psコマンドにて以下の画像のようにDBコンテナ(postgreSQL)が立ち上がっていることが確認できますよね。
docker-ps加工済.jpg

ここでもし誤ってDBコンテナを消してしまう事があったら、どうなってしまうでしょうか...

DBに蓄積してきたデータが全て消えます。

ですがコンテナ管理において、デファクトスタンダードとされているDocker様がそんな状況を放置するでしょうか?いや否です。

コンテナのデータを別の場所で保管できるボリューム機能があります!

ボリュームを使えば、例えDBのコンテナを消してしまっても、データを別場所にて保管しているので、復元できるという仕組みですね(/・ω・)/

ボリュームとは

こちらは僕が説明するよりコチラの記事(Docker、ボリューム(Volume)について真面目に調べた - Qiita *1)の説明が優れていると思ったので、引用させていただきます。

  • ボリュームとは、データを永続化できる場所のことである。
  • 外部HDDのようなイメージ。コンテナ本体にマウントして使う。
  • コンテナボリューム の違いについて
  • コンテナ内部にデータ(ファイル)を保存しても、コンテナ破棄すると消えてしまう。
  • なので、データを永続化したいときは、コンテナの外にデータを置く必要がある。
  • その場所のことを、ボリュームと呼ぶ。
  • ボリューム(=データを永続化できる場所) は2種類ある。
  • ホストのディレクトリ(ファイル)
    • ホストで ls で見えるモノ。
  • Docker の リソースとしての Volume
    • docker volume ls で見えるモノ。
  • (本当は、これ以外にもNFSなども指定できるようだ)
  • ボリュームをコンテナにマウントすることで、コンテナからアクセスできるようになる。
  • あるいは--volumes-from <コンテナ名> とすると、指定したコンテナのマウントと同じようにマウントできる。

今までの僕のdocker-composeは...?

まずは『こんな記事にわざわざ見に来ていただいて感謝』ということで、恥ずかしながらも前まで設定していた駆け出しdocker-composeを公開します。笑

docker-compose.yml
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の使用例として以下のような記述を見つけました。

docker-compose.yml
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:

この記述を見て思った異変(自分の無知)の数々

  1. ./nginx/:って...下のdbdata:みたいにカンマスラッシュ付けずにnginx:←こうやって書き方統一しろよな!(※ヤバい間違いをしています。)
  2. なんか一番下にvolumesおる...
  3. なぜ2回もstaticdataを指定しているのだ...

先ほどの疑問点について勉強を開始

1. ディレクトリの記述方法について

とりまdockerの公式docs *3に飛びます。すると以下の記述がありました。

docker-compose.yml
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をもう一度見てみましょう。

docker-compose.yml
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にて指定すると、その名前の付いたボリュームからデータを参照してきます。

つまり『データを永続化している』訳ですね(/・ω・)/

そして以下のことが言えます!

  • 先頭に./が付いていないdbdatastaticdataは一番下のvolumes:で名前を付けてから、名前付きボリュームとしてコンテナの外部に保管し、データを永続化している。
  • 逆に先頭に./が付いているnginxは相対パスでホスト側ののマウントするディレクトリを指定して、データを永続化している。ただし名前が付いていないので、VOLUME NAMEには20文字くらいの文字列が自動で名前として付きます。なので『もう一度使える』という意味での《永続化》はしていないですね。

果たして名前が付いているかdocker volume lsコマンドにて確認します!
volumename.jpg

《サービス名_ボリューム名》となっていることが確認できました〜。(画像ではアンダーバーが途切れてます。笑)

3. 何故2回もstaticdataを指定しているのだ...

1と2からなんとなく推測してみましょう。

今までの文章から考察するとこうなるかな...

  • 1的観点から記述法を見ると、名前付きボリューム(staticdata)でバックエンドとNginxにマウントをとっているのがわかる。
  • 2的観点から名前付きボリュームということはデータの永続化(データを別場所にて保管)をしている。
  • staticdataとdbdataを比較すると、dbdataではpostgresのvolumesの1つしか設定していなかった。

《データを別の場所にて管理》 & 《バックエンドとNginxの2つマウント取ってる。》

これらの要素からボリュームでデータを別場所で管理できることを利用して、コンテナ間のリソース共有をしている!

もしやバックエンドコンテナとNginxコンテナで静的ファイルを共有して、静的ファイルに関してだけNginxで配信するという形が取れるのでは...?

当初の僕の目的であったNginxで静的ファイルを配信することに繋がってきました:relaxed:

まとめ

最後まで読んでいただきありがとうございました。
Docker系は使えるツールがあまりにも多いので、本当に把握しきれないです。特にボリュームの概念をつかむのはある程度触ってからでないと難しいのかも知れません(コンテナの概念やマウントという言葉の意味など...)。

ですがどこかのDocker初心者が僕のようにボリュームの概念について躓かないように、初心者である僕の目線でわかりやすく記事にさせていただきました!

間違っている点やシンプルな感想などでもございましたら、お気軽にコメントください!!

バックエンド(Django,RESTAPI)やAWS,Dockerなどの勉強していたり、機械学習にも少し手を出しているわたくしの姿を発信しているTwitterがあるので、もし良ければ...@heacet43

参考文献

  1. Docker、ボリューム(Volume)について真面目に調べた - Qiita [https://qiita.com/gounx2/items/23b0dc8b8b95cc629f32]
  2. DjangoをDocker Composeでupしよう! - Qiita [https://qiita.com/kyhei_0727/items/e0eb4cfa46d71258f1be]
  3. Compose ファイル・リファレンス — Docker-docs-ja 17.06.Beta ドキュメント [http://docs.docker.jp/compose/compose-file.html#volumes-volume-driver]
47
35
0

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
  3. You can use dark theme
What you can do with signing up
47
35

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?