fbpx

Ebook連載:『5分x10回で学ぶ 開発者のためのDocker コンテナ入門』第5章 –ボリュームと永続的なストレージ
#docker #DX #Mirantis

この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。

コンテナ化はDXの第一歩に最適な取り組みです。これから10回にわたってMirantis社が発行するEbook「Learn Containers 5 Minutes at a Time An introductory guide for developers」 (Eric Gregory著)を翻訳・編集し、チャプターごとにCL LABで公開していきます。本稿はその第5章です。皆さまのクラウドネイティブジャーニーやアプリケーションのモダナイズの一助になれば幸いです。

目次

  • 第1章 コンテナとは?
  • 第2章 コンテナの作成・調査・削除
  • 第3章 Dockerfile でのコンテナイメージのビルド
  • 第4章 イメージレジストリ
  • 第5章 ボリュームと永続的なストレージ
  • 第6章 コンテナネットワークとコンテナのポートの開設
  • 第7章 コンテナ化アプリの実行
  • 第8章 ユーザ定義ネットワーク上のマルチコンテナアプリケーション
  • 第9章 Docker Compose
  • 第10章 Webアプリをコンテナサービスとして構築する

第5章: ボリュームと永続的なストレージ

前章では、Docker Hubのようなパブリックレジストリでコンテナイメージを使用し、共有する方法を学びました。この章では、コンテナ化したアプリケーションに永続的なストレージを導入する方法について学びます。

エフェメラルコンテナのための永続的なストレージ

大規模なエンタープライズアプリケーションにコンテナが有用である理由を技術者が語るとき、コンテナを「短命である」または「存在して消える」という意味の言葉「エフェメラル」と表現することがあります。

コンテナは、1度ダウンロードしたイメージを繰り返し使用できるので、迅速に効率的に、かつ必要に応じて起動できます。このことから、なぜコンテナのエフェメラルな性質が有用なのか、より明確に理解できると思います。このエフェメラルな性質が、Kubernetes のようなコンテナオーケストレータを含む「クラウドネイティブ」と呼ばれるシステムの多くを実現可能にしています。

しかしほとんどのアプリケーションが必要とする、後に使用するための永続的なデータの保存という問題が残されます。静的な Web サーバー上に構築され、永続的なストレージを必要としないシンプルな Web サイトであっても、WordPress などのコンテンツ管理システムで作成されている場合がほとんどです。このようなコンテンツ管理システムはユーザのログインや下書き投稿などのデータを保存するためにデータベースを使用しています。

WordPress のようなアプリケーションをコンテナ化する場合、どのコンテナからも独立した永続的なデータストアを作成する必要があります。そして必要に応じて作成・破棄されるエフェメラルなコンテナから、その永続的なデータストアにアクセスし、データを利用・更新できるようにしなければなりません。

Docker では、このような永続的なデータストアをボリュームと呼びます。デフォルトでは、ボリュームはホストファイルシステム上の、Docker エンジンが管理する特定のディレクトリですが、クラウドストレージなどのリモートロケーションに設定することも可能です。

バインドマウントについて

Docker は、コンテナがホストファイルシステム上のデータにアクセスするためのボリューム以外の方法として、バインドマウントを提供しています。これによりコンテナは、ホストファイルシステム上のどこからでもデータの読み書きができます。バインドマウントはローカルマシンでのテストや開発に便利ですが、一般的にはボリュームが使用されています。ボリュームは Docker コマンドラインインターフェースで管理しやすく、より正確にスコープを定義でき、クラウドネイティブアーキテクチャに適しているからです。このような理由から、この章ではボリュームに焦点を当てますが、最終章ではバインドマウントの例を紹介します。

ボリュームは、複数のコンテナから同時に read-write または read-only モードでマウントでき、特定のコンテナの停止後も存続します。macOS や Windows で Docker Desktop を使用している場合、ボリュームに独自の管理タブがあることがわかります。

それでは、ボリュームを作成して、複数のコンテナにマウントしてみましょう。

演習: ボリュームを作成する

まず初めに、新しいボリュームを作成します。

% docker volume create d6app

上記のコマンド文で、d6appという名前の新しいボリュームを作成します。

次に、前章で作成した d6 イメージから新しくコンテナを作成しましょう。この新しいコンテナを作成する際に、先ほど作成したボリュームもマウントします。

% docker run --name d6v2 -it -v d6app:/d6app /d6:1.0 bash

このコマンド文を次に解説します。

  • docker run を実行し、新しいコンテナに d6v2 という名前を指定しています。
  • -it タグは、対話型シェルを提供しています。
  • -v タグは、ボリュームを識別し、コンテナにマウントしています。
    1. 最初のコロンより前の d6app のインスタンスは、マウントするボリュームを指定します。この場合、先ほど作成した d6app になります。
    2. 新しいコンテナの中で、このボリュームの内容を見つけることができる d6app というディレクトリを示しています。 このディレクトリは何と名前をつけてもいいですが、今回は単純にボリュームと同じ名前にしています。
  • 次に、コンテナイメージのソースを指定しています。
  • 最後に、bash シェルを開いています。

これで、コンテナ内で bash シェルによって作業できるようになりました。ls コマンドでコンテナ内のファイルシステムを見てみましょう。d6app のボリュームがマウントされているディレクトリを確認できるはずです。

% ls
bin boot d6.py d6app dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var

d6app ディレクトリに移動して中を調べると、空になっていることが確認できます。

% cd d6app
% ls

空のテキストファイルを作成します。

% touch d6log.txt

コンテナ内の root ディレクトリに戻り、前の章で書いた Python アプリを開いてみましょう。nano は、イメージの一部になっているので、ダウンロードする必要はありません。

% cd ..
% nano d6.py

サイコロを振るアプリに機能を追加してみましょう。ランダムにサイコロの目が出るだけでもおもしろいですが、出た目を記録しておくことができたら、もっといいと思いませんか? d6.py ファイルの内容を次のように更新しましょう。

#import module
from random import randint

#open the storage file in append mode
outfile = open('/d6app/d6log.txt', 'a')

#assign a random integer between 1 and 6,
inclusive, to a variable
roll = randint(1, 6)

#print the variable
print(roll)

#convert the value to a string and write to the file
rollstr = str(roll)
outfile.write(rollstr + '\n')

#close the file
outfile.close()

d6.py を実行すると、プログラムは d6app ボリューム内のテキストファイルを開き、ランダムな出力を文字列に変換し、その文字列と改行を記録します。試してみましょう。

% python d6.py
5

d6log.txtファイルの中に、結果が記録されているはずです。

% nano d6app/d6log.txt

さらにアプリを数回実行して、再度ファイルを確認してみてください。

コンテナを停止するとどうなるのでしょうか?まず、この d6 アプリの更新版を commit して新しいイメージを作成し Docker Hub にプッシュしておきましょう。コンテナを起動したまま、別のターミナルセッションを開いて入力します。

% docker commit -m “Updating to v2” d6v2 d6:2.0
% docker tag d6:2.0 /d6:2.0
% docker push /d6:2.0
The push refers to repository [docker.io//d6]
3280116fcd01: Pushed
3b2cfa75b8bf: Layer already exists
128b344cad66: Layer already exists
88597958b14e: Layer already exists
db26989c2f90: Layer already exists
a3232401de62: Layer already exists
204e42b3d47b: Layer already exists
613ab28cf833: Layer already exists
bed676ceab7a: Layer already exists
6398d5cccd2c: Layer already exists
0b0f2f2f5279: Layer already exists

この章の冒頭で使ったコマンドとほぼ同じコマンド文で、新しいコンテナを起動します。

% docker run --name d6test -it -v d6app:/d6app /d6:1.0 bash

このコマンドでは、変更を加える前の d6 アプリのバージョン 1.0 イメージを基盤にして、新しいコンテナを起動していることがわかります。先ほどと同じように d6app のボリュームをマウントし、対話型のshell セッションを開いています。

Read-only について

一旦立ち止まって、ここで確認しておきましょう。すべてのコンテナが read-write 可能なボリュームをマウントする必要はないこと、そして一般的なルールとして、コンテナに必要以上の特権を与えないことに留意してください。Read-only でボリュームをマウントするには、コンテナ内のボリュームディレクトリの名前に :ro を追加するだけです。上記のコマンドの場合、次のようになります。 d6app:/d6app:ro

d6.py ファイルを開くと、ここでは、古い 1.0 のイメージを使用しているので、変更されていないことがわかります。マウントされた d6app のボリュームにある d6log.txt を開いてみましょう。

% nano d6app/d6log.txt

ファイルは永続化され、複数のコンテナからデータが送られています。ファイルは手動で編集を加えることもできます。ここで、もう一度Python アプリを実行し、初期と最新のコンテナ内のログファイルを確認してみましょう。

% python d6.py
% nano /d6app/d6log.txt

永続的なデータストアによって、複数のコンテナ間に連続性を持たせる方法が見つかりました。

今回はここまでです。

本Blogの動画はこちら

次章ではさらに一歩進んでコンテナネットワーキングの基礎に踏み込み、複数のコンテナをリアルタイムで連携させることができるようにします。

※Docker Enterprise事業は2019年11月14日にMirantis社によって買収されました。
当時のDocker Enterprise製品は、現在は下記のように名称変更されています。

Mirantis製品に関するお問い合わせはこちら

Mirantisについて
Mirantisは、Fortune 1000 企業の 2/3 以上にコンテナやマルチクラウドの導入を加速させ、データセンター運用のストレスを取り除く支援をしています。日本では、クリエーションラインと提携し、Kubernetes、OpenStack、その他のオープンクラウドテクノロジーを、現地語でのサポートやサービスとともに提供しています。Mirantis Kubernetes Engine(旧Docker Enterprise)および関連製品を含む、深い技術的専門知識とベンダーにとらわれない柔軟なプラットフォームが、お客様から選ばれています。
詳細は www.mirantis.com でご確認ください。

新規CTA