テックブログ

技術ネタ

Docker マウント(データの永続化)

お久しぶりです。H.Uでございます。

今回は現在勉強中であるDockerの機能の一部をご紹介したいと思います。

データの永続化について

まず導入として、データの永続化についてご説明します。

コンテナ内に生成されるファイルは、コンテナ本体が削除されるとデータ保持ができなくなります。

これは、ライフサイクルを一番に考えているコンテナ環境には不都合が生じます。

その為、Dockerコンテナ内ファイルをホストマシン上に保存することが必要になります。

保存方法は2つあり、バインドマウントとボリュームがあります。

この2つを利用することで、コンテナ削除後にデータを維持することができます。

これをデータの永続化と呼びます。

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

バインドマウントは、ホストマシン上のファイルまたはディレクトリをコンテナにマウントする方法です。

コンテナ外部にあるファイルを読み書きが可能で、ホスト上のどこにでもマウントして保存できます。

機能はボリュームと比較して限定的である為、公式はボリュームを推奨していることが多いようです。

ボリュームについて

ボリュームは、ホストマシン内にあるDockerが管理する領域をコンテナ上にマウントする方法です。

バインドマウントとは対照的にDockerが管理する領域内のみにマウントすることができ、データは完全にDockerにより管理されます。

多くの機能がバインドマウントより優れています。

今回は紹介だけですが、複数のコンテナ間でのデータ共有、バックアップまたは移行が容易など様々な機能が用意されています。

バインドマウント

それでは実際にバインドマウントから確認してみます。

簡単なDockerfileを作成し、イメージビルドを実施します。

[root@hu-test ~]# cat Dockerfile
#CentOS7 base image
FROM centos:7
#yum install epel-release
RUN yum -y install epel-release
#yum install nginx
RUN yum -y install nginx
#local file copy index.html
COPY index.html /usr/share/nginx/html
#entrypoint command
ENTRYPOINT ["/usr/sbin/nginx", "-g", "daemon off;"]

上記のDockerfileには、バインドマウントやボリュームを確認する為、

nginxのインストールと起動、ホスト内のindex.html をコピーするなどの設定が入っています。

[root@hu-test ~]# docker image build -t hunetassist/exsample-nginx .
Sending build context to Docker daemon  35.84kB
Step 1/5 : FROM centos:7
 ---> eeb6ee3f44bd
Step 2/5 : RUN yum -y install epel-release
 ---> Running in 096e65a1df7f
Loaded plugins: fastestmirror, ovl

略)

Complete!



[root@hu-test ~]# docker image ls hunetassist/exsample-nginx
REPOSITORY                   TAG       IMAGE ID       CREATED          SIZE
hunetassist/exsample-nginx   latest    1a9b6ef77a7f   12 seconds ago   641MB


イメージ作成ができたので、コンテナを立ち上げていきます。

この際に、バインドするファイルまたはディレクトリを指定することでバインドマウントが可能となります。

(バインドはホストマシン内のどこにでも作成することが可能)

場所は問わないので、下記の様に /root/test/ にindex.htmlファイルを作成します。

[root@hu-test~]# cat test/index.html
<!DOCTYPE html>
<html>
<head>
<title>Docker Bind mount</title>
</head>
<body>
<h1>mount html on the Container Host</h1>
</body>

index.htmlファイルをDocker内にバインドして、nginxによるページ公開を実施していきます。

現在は ssh 接続用の22ポートしか開放しておらず、当然ページ表示はまだできません。

[root@hu-test ~]# netstat -tlnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      723/sshd
tcp6       0      0 :::22                   :::*                    LISTEN      723/sshd


[root@hu-test ~]# curl http://localhost:8080/index.html
curl: (7) Failed to connect to localhost port 8080: 接続を拒否されました

ここからバインドを利用してコンテナを立ち上げると、どのようになるかを確認してみます。

[root@hu-test ~]# docker container run --name bind-nginx -d -p 8080:80 --mount type=bind,source=/root/test,target=/usr/share/nginx/html hunetassist/exsample-nginx

8dc0fc628018a0dccb21bfb70e62f4840e82268fc403149300266389962debb3



[root@hu-test ~]# docker container ls
CONTAINER ID   IMAGE                            COMMAND                  CREATED          STATUS          PORTS                                   NAMES
8dc0fc628018   hunetassist/exsample-nginx   "/usr/sbin/nginx -g …"   23 seconds ago   Up 22 seconds   0.0.0.0:8080->80/tcp, :::8080->80/tcp   bind-nginx

コマンドが長くなったので、内容を簡単に解説します。

● docker container run –name bind-nginx -d -p 8080:80

ここまでは ホストの8080ポートを開放し、ホストに対して80ポートと接続します。
また、–nameにより、コンテナの名前を指定します。

● –mount type=bind,source=/root/test,target=/usr/share/nginx/html

ここからがbindを利用する為の構文です。
–mountはバインドマウントまたはボリュームを使用するオプションであり、
“type=” によりbindを指定します。
“source= ” がホスト上のマウント元を選択し、
“target= ” により、コンテナ内のマウントする場所を指定できます。

これで、コンテナが立ち上がりました。

それでは同じようにcurlコマンドでページを確認します。

[root@hu-test ~]# netstat -tlnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      58884/docker-proxy
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      723/sshd
tcp6       0      0 :::8080                 :::*                    LISTEN      58890/docker-proxy
tcp6       0      0 :::22                   :::*                    LISTEN      723/sshd


[root@hu-test ~]# curl http://localhost:8080/index.html
<!DOCTYPE html>
<html>
<head>
<title>Docker Bind mount</title>
</head>
<body>
<h1>mount html on the Container Host</h1>
</body>

nginxはコンテナ内にのみ存在していますが、

ホスト上にある /root/test/index.html curl でページの確認できました。

これは、コンテナのディレクトリがホストマシンにバインドマウントされているからです。

コンテナ内ではどのようになっているか、内部に入って確認してみます。

[root@hu-test ~]# docker container exec -it bind-nginx /bin/sh
sh-4.2# cat /usr/share/nginx/html/index.html
<!DOCTYPE html>
<html>
<head>
<title>Docker Bind mount</title>
</head>
<body>
<h1>mount html on the Container Host</h1>
</body>

しっかりとコンテナ内部にバインドされていることが確認できました。

また今回は実施しませんが、バインドマウントとボリュームの両方でホスト側またはコンテナ側で修正したファイルの内容は一方にも同期されています。

最後にコンテナを削除し、バインドしたファイルがホスト内に残っているかを確認してみます。

つまり、データの永続化ができているかの確認です。

[root@hu-test ~]# docker container stop bind-nginx
bind-nginx

[root@hu-test ~]# docker container rm bind-nginx
bind-nginx

[root@hu-test ~]# ll /root/test/index.html
-rw-r--r-- 1 root root 128  9月  8 07:20 /root/test/index.html

当然ですが、ホスト内ではバインドしたファイルは削除されていないことが確認できます。

これで、データの永続化は達成されました。

ここまではバインドマウントの紹介でした。

次はいよいよボリュームについてです。

ボリューム

Dockerが管理しているデータ領域はデフォルトでは /var/lib/docker です。

ボリュームはこの領域にのみデータを共有することができます。

まずは /var/lib/docker/volumes/ ボリューム専用領域にボリューム”test”を作成して、

バインドと同様にこの領域をマウントして、ページを表示を確認することを目標にします。

[root@hu-test ~]# docker volume create test
test


[root@hu-test ~]# docker volume ls
DRIVER    VOLUME NAME
local     test


root@hu-test ~]# ll -AR /var/lib/docker/volumes/test/
/var/lib/docker/volumes/test/:
合計 4
drwxr-xr-x 2 root root 4096  9月  6 02:03 _data

/var/lib/docker/volumes/test/_data:
合計 0

確認用ボリューム”test”を専用領域に作成しました。

バインドと同じイメージを用いてコンテナを立ち上げます。

type=volume,とsource=test に変更するだけで、コマンドはほとんど変わりません。

sourceはバインドマウントはホスト上のフルパスでしたが、ボリュームは専用領域を用いる為、

ボリューム名のみで指定できます。

[root@hu-test ~]# docker container run --name volume-nginx -d -p 8080:80 --mount type=volume,source=test,target=/usr/share/nginx/html hunetassist/exsample-nginx
59c0a01a7d3146bed61fdf0bf52480e717848ca4f87d55c286b0a896f7d34ffb

これで、専用領域にある”test”ボリュームはDockerが全て管理するデータ領域になりました。

この領域に volume.html を作成します。

[root@hu-test ~]# vi /var/lib/docker/volumes/test/_data/volume.html
[root@hu-test ~]# cat /var/lib/docker/volumes/test/_data/volume.html
<!DOCTYPE html>
<html>
<head>
<title>Docker Volume</title>
</head>
<body>
<h1>Volume test file</h1>
</body>
</html>

volume.html 以外にも既にDocker内にあったファイルなどがすでに”test”領域に生成されていることが確認できます。

[root@hu-test ~]# ll /var/lib/docker/volumes/test/_data/
合計 24
-rw-r--r-- 1 root root 3650 10月 19  2021 404.html
-rw-r--r-- 1 root root 3693 10月 19  2021 50x.html
lrwxrwxrwx 1 root root   20  9月  2 08:33 en-US -> ../../doc/HTML/en-US
drwxr-xr-x 2 root root 4096  9月  8 08:19 icons
lrwxrwxrwx 1 root root   18  9月  2 08:33 img -> ../../doc/HTML/img
-rw-r--r-- 1 root root  113  9月  2 08:26 index.html
-rw-r--r-- 1 root root  368 10月 19  2021 nginx-logo.png
lrwxrwxrwx 1 root root   14  9月  2 08:33 poweredby.png -> nginx-logo.png
-rw-r--r-- 1 root root  116  9月  6 02:49 volume.html

バインドマウント時と同様にページを確認を行います。

[root@hu-te ~]# netstat -tlnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      64243/docker-proxy
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      723/sshd
tcp6       0      0 :::8080                 :::*                    LISTEN      64248/docker-proxy
tcp6       0      0 :::22                   :::*                    LISTEN      723/sshd


[root@hu-te ~]# curl http://localhost:8080/volume.html
<!DOCTYPE html>
<html>
<head>
<title>Docker Volume</title>
</head>
<body>
<h1>Volume test file</h1>
</body>
</html>

ページ表示は確認できました。

最後にデータの永続化ができているかを確認の為に、コンテナを削除します。

[root@hu-test ~]# docker container stop volume-nginx
volume-nginx
[root@hu-test ~]# docker container rm volume-nginx
volume-nginx

[root@hu-test ~]# docker container ls -a
CONTAINER ID   IMAGE          COMMAND                  CREATED       STATUS                   PORTS     NAMES


[root@hu-test ~]# curl http://localhost:8080/volume.html
curl: (7) Failed to connect to localhost port 8080: 接続を拒否されました

これで、コンテナは消えていることが確認できました。

Docker管理領域とvolume”test”はどのようになっているでしょうか。

[root@hu-test ~]# ll /var/lib/docker/volumes/test/_data/
合計 24
-rw-r--r-- 1 root root 3650 10月 19  2021 404.html
-rw-r--r-- 1 root root 3693 10月 19  2021 50x.html
lrwxrwxrwx 1 root root   20  9月  2 08:33 en-US -> ../../doc/HTML/en-US
drwxr-xr-x 2 root root 4096  9月  8 08:19 icons
lrwxrwxrwx 1 root root   18  9月  2 08:33 img -> ../../doc/HTML/img
-rw-r--r-- 1 root root  113  9月  2 08:26 index.html
-rw-r--r-- 1 root root  368 10月 19  2021 nginx-logo.png
lrwxrwxrwx 1 root root   14  9月  2 08:33 poweredby.png -> nginx-logo.png
-rw-r--r-- 1 root root  116  9月  6 02:49 volume.html


[root@hu-test ~]# docker volume ls
DRIVER    VOLUME NAME
local     test

volume “test”は消えず、volume.html も残った状態です。

コンテナが利用しているファイルやディレクトリはコンテナが消えても、

マウントバインドまたはボリュームを利用することでデータの永続化ができることを確認できました。

今回はバインドマウントとボリュームだけの説明でしたが、次回もDockerについてを解説できたらと考えています。

機会がございましたら、紹介ができなかったボリュームがバインドマウントより優れている機能、複数コンテナでのデータ共有、バックアップや移行の容易性などについてを記事にしていきたいと考えています。

今回はここまで、H.Uでした。

最後まで読んでいただき、ありがとうございます。

今後ともネットアシストをよろしくお願いいたします。

この記事をシェアする

  • facebook
  • twitter
  • hatena
  • line
URLとタイトルをコピーする

実績数30,000件!
サーバーやネットワークなど
ITインフラのことならネットアシストへ、
お気軽にご相談ください