DB の保持¶
気を付けないと、todo リストはコンテナを起動するたび、きれいに消去されます。どうしてでしょうか? コンテナがどのように動作しているのか、深掘りしましょう。
コンテナのファイルシステム¶
コンテナの実行時、イメージの様々なレイヤーを、コンテナのファイルシステムに使います。また、各コンテナでは、ファイルを作成、更新、削除するための「
実行して確認¶
この処理を見るために、2つのコンテナを起動し、それぞれにファイルを作成します。一方のコンテナで作成されたファイルは、もう一方のコンテナからは見えないと分かるでしょう。
ubuntu
コンテナを起動し、そこに/data.txt
という名前のファイルを作成し、1から10000までのランダムな数を入れます。$ docker run -d ubuntu bash -c "shuf -i 1-10000 -n 1 -o /data.txt && tail -f /dev/null"
このコマンドに興味があれば説明します。これは bash シェルを開始し、2つのコマンド(これが
&&
を使った理由)を実行しました。前半部分はランダムな数を選び、それをファイル./data.txt
に書き出します。後半部分はコンテナを実行し続けるため、単にファイルを見ているだけです。
コンテナ内に
exec
すると、出力を確認できます。そのためには、ダッシュボードを開き、実行しているubuntu
イメージのコンテナにある、1番目のアクション( CLI と表示)をクリックします。そうすると、ターミナルが開き、ubuntu コンテナ内で実行中のシェルが見えます。
/data.txt
ファイルの内容を見るには、以下のコマンドを実行します。その後、このターミナルは以後使いませんので、閉じます。$ cat /data.txt
docker exec
コマンドを使う方が好きでしたら、同じようにできます。そのためにはコンテナ ID の確認が必要です。それから、以下のコマンドでファイル内容を表示します。$ docker exec <container-id> cat /data.txt
ランダムな数が見えるでしょう!
次に、他の
ubuntu
コンテナ(同じイメージ)を起動しても、同じファイルは見えないでしょう。$ docker run -it ubuntu ls /
見てください! そこに
data.txt
はありません! その理由とは、書き出したのは、1つめのコンテナのスクラッチ領域だけだからです。
次に進むため、
docker rm -f <コンテナID>
コマンドを使って、1つめのコンテナを削除します。
コンテナの ボリューム ¶
これまで試したように、各コンテナは、イメージの定義からコンテナが起動するのが分かりました。コンテナはファイルの作成、更新、削除ができますが、コンテナを削除すると、それらの変更は消失します。また、コンテナに対する全ての変更とは、
ボリューム は、コンテナ内で指定したファイルシステムのパスを、ホストマシン上へと接続できる機能を備えています。コンテナ内にディレクトリをマウントすると、ディレクトリに対する変更は、ホストマシン上からも見えます。コンテナを再起動する場合にも、同じディレクトリをマウントしていれば、再起動後も同じファイルが見えます。
ボリュームは主に2種類あります。ゆくゆくは両方を使いますが、まずは 名前付きボリューム (named volume) から始めましょう。
todo データの保持¶
デフォルトでは、todo アプリが自身のデータを保存するのは、コンテナ用ファイルシステム内で /etc/todo/todo.db
にある SQLite Databese の中です。SQLite に不慣れでも、心配は要りません! これはシンプルなリレーショナル データベースで、1つのファイル内に全てのデータを保存します。大きくスケールするアプリケーションには最良ではありませんが、小さなデモには効果的です。これを他のデータベースエンジンに切り替える方法は、後ほどお伝えします。
データベースがたった1つのファイルのため、ホスト上のファイルを次のコンテナで利用できるようにするだけで、データベースを保持できるため、最後に中断したところから続けられるでしょう。ボリュームを作成し、データを保管するディレクトリに todo.db
ファイルは、ホスト上のボリュームに置いておけば、保持できます。
先述の通り、ここでは 名前付きボリューム(named volume) を使おうとしています。名前付きボリュームとは、単なるデータの
docker volume create
コマンドを使ってボリュームを作成します。$ docker volume create todo-db
ダッシュボードで(あるいは
docker rm -f <id>
)、もう一度 todo アプリのコンテナを停止および削除します。このコンテナでは、まだ存続するボリューム を使っていないからです。
todo アプリのコンテナを起動しますが、ボリュームのマウントを指定する
-v
フラグを追加します。ここでは名前付きボリュームを使い、/etc/todos
にマウントします。そうすると、このパスに作成された全てのファイルを保存します。$ docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started
コンテナが起動したら、アプリを開き、todo リストに新しいアイテムを追加します。
todo アプリ用のコンテナを停止・削除します。コンテナの ID をダッシュボードか
docker ps
コマンドで調べ、docker rm -f <id>
で削除します。
先ほどと同じコマンドを使い、新しいコンテナを起動します。
アプリを開きます。そうすると、まだリストにアイテムが残っているのが見えるでしょう!
リストの挙動を確認できれば、次へ進むためにコンテナを削除します。
できました! これでデータを保持する方法を学びました。
注釈
ボリュームを深掘り¶
多くの人々が頻繁に「名前付きボリュームを使うと、私のデータを Docker が"実際に"保存するのはどこですか?」と尋ねます。知りたければ docker volume inspect
コマンドが使えます。
$ docker volume inspect todo-db
[
{
"CreatedAt": "2019-09-26T02:18:36Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/todo-db/_data",
"Name": "todo-db",
"Options": {},
"Scope": "local"
}
]
この MountPoint
こそが、ディスク上でデータを保管している本当の場所です。ほとんどのマシンでは、このディレクトにホスト上からアクセスするには root 権限が必要でしょう。ですが、そこにデータがあるのです!
注釈
Docker Desktop 上で直接ボリュームのデータにアクセスするには
Docker Desktop を実行中に、Docker コマンドが実際に動くのは、マシン上の小さな仮想マシン内です。マウントポイントのディレクトリ内で、実際の内容を見たい場合は、何よりもまず仮想マシン内に入る必要があります。
まとめ¶
ここまで、アプリケーションを再起動しても(テータを)保持できる機能を確認しました! これでアプリケーションを投資家に披露できますので、私たちのビジョンを把握してもらえるよう望みます。
ところで一方、初期の頃から変更を加えるたびに、何度も何度も毎回イメージの再構築をしています。これを改善したいと思いますよね? バインド マウントの使用(先ほど簡単に触れました)こそが良い方法です。詳しく見ていきましょう!
参考
- Part 5: Persist the DB