こんにちは
株式会社クラスアクト インフラストラクチャ事業部の大塚です。
Kubernetes。楽しいんですよね~。
覚えることは超沢山有るんですけど、便利な機能がたくさんあるので知るたびに「ほえぇーーーーーー!」って思ってます。(だからと言ってk8s最強かと言われればそうは思いません。大きな環境を作る予定が無い、プライベートな開発をするのであればdocker swarmで良いと思います。あれはあれで面白いと思いますし、k8sを理解する為にも有効であると考えます。swarmも馬鹿には出来ません。)
k8sは面白い。ただk8sを知るためにはdockerをまず知ることが遠回りの様で近道。
そこでk8sのvolumeを知るために、dockerのvolumeを触ってみたいと思います。
docker環境構築
VMはubuntu22.04で作っています。docker環境の構築は過去私が投稿した以下をベースにしています。
用語とかコマンドとか
docker volume create
ボリュームを作成します。
mount
相手よりも自分が優位だと自慢する様な言動をすること。
・・・うそです。
IT用語として使われる場合は、コンピューターに接続したマウス、キーボード、外付けハードディクスなどといった周辺機器をコンピューターに認識させ、使用可能な状態にすることを指します。
マウントって聞くと「難しそう・・・」って思ってしまいますよね。私も思います。キライです。
ただ、マウスとかPCに挿して使ってるじゃないですか?USBメモリとかも使ってるじゃないですか?それもマウントって聞くと「ほーーーーーん」ってなりませんか。
(PS2とかにメモリーカードを挿してデータを保存することもマウント?)
PostgreSQL
PostgreSQL は、最も複雑なデータ ワークロードを安全に格納およびスケーリングする多くの機能と組み合わせて SQL 言語を使用および拡張する、強力なオープン ソースのオブジェクト リレーショナル データベース システムです。PostgreSQL の起源は、カリフォルニア大学バークレー校のPOSTGRESプロジェクトの一環として 1986 年にさかのぼり、コア プラットフォームで 35 年以上にわたって活発に開発されてきました。
検証
まず、docker volume createでvolumeを作成。それをコンテナにマウントしてコンテナでデータを適当に作成してvolumeに保存してみたいと思います。その後に複数のコンテナから同じvolumeをマウントしたりしてみます。
下記はmy-volという名前のdocker volumeを作成しているlogです。docker volume lsコマンドでvolumeが作成されていることが確認出来ます。
root@ansible-tower:~# docker volume create my-vol
my-vol
root@ansible-tower:~# docker volume ls
DRIVER VOLUME NAME
local 1314bb326ec02d2fcc37b2eea1ea74efb3ef254e7a9a6b7c5a40ec68876ae822
local bf6ec6e1f8513aa96e3f2f5db7ddd06c90d14f72f1a44ce2968185ed52ef64c4
local my-vol
docker volume inspectコマンドを実行するとこのvolumeがホストのどこに作成されているかを確認することが出来ます。
Mountpointを見て頂くと"/var/lib/docker/volumes/my-vol/_data"とあります。コンテナ側でデータを作成した後、このディレクトリ配下を確認しデータが存在するかを確認します。
root@ansible-tower:~# docker volume inspect my-vol
[
{
"CreatedAt": "2023-05-08T21:56:04Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-vol",
"Options": null,
"Scope": "local"
}
]
コンテナをデプロイします。今回はPosgreSQLと呼ばれるDBを検証用に使っていきます。
実行コマンドは以下です。
今回はvolumeの検証なのでそこだけ見てみますと、"--mount source=my-vol,target=/var/lib/postgresql/data"の部分でmy-volをコンテナ側の/var/lib/postgresql/dataにマウントするように指示を出しています。PostgreSQLのDB等は/var/lib/postgresql/dataに作られるため、ここをマウントポイントとして指定してます。
docker run -p 5432:5432 -itd --name pg-con -e POSTGRES_PASSWORD=postgres --mount source=my-vol,target=/var/lib/postgresql/data postgres:latest
413875a1ddf528093510313d42d98fab6247c42e9fff02ac6b739e0522f0a391
root@ansible-tower:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
413875a1ddf5 postgres:latest "docker-entrypoint.s…" 58 seconds ago Up 3 seconds 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp pg-con
イメージは以下となります。
赤枠の部分がイコールになってると思っても良いかもしれませんし、my-volというメモリーカードをコンテナというPS2に挿してゲームの記録を書き込めるようにしていると思っても良いかも?です。
コンテナに接続してみます。
/var/lib/postgresql/dataを見てみると既に色々データがありますね。
root@ansible-tower:~# docker exec -it 413875a1ddf5 /bin/bash
root@413875a1ddf5:/# cd /var/lib/postgresql/data
root@413875a1ddf5:/var/lib/postgresql/data# ls
base pg_commit_ts pg_hba.conf pg_logical pg_notify pg_serial pg_stat pg_subtrans pg_twophase pg_wal postgresql.auto.conf postmaster.opts
global pg_dynshmem pg_ident.conf pg_multixact pg_replslot pg_snapshots pg_stat_tmp pg_tblspc PG_VERSION pg_xact postgresql.conf postmaster.pid
ホスト側でも確認してみます。docker inspectで/var/lib/docker/volumes/my-vol/_dataとあったのでこのディレクトリ配下を見てみます。
docker側で作成されたデータがこちらからも見えていますね。
root@ansible-tower:~# cd /var/lib/docker/volumes/my-vol/_data
root@ansible-tower:/var/lib/docker/volumes/my-vol/_data# ls
base pg_commit_ts pg_hba.conf pg_logical pg_notify pg_serial pg_stat pg_subtrans pg_twophase pg_wal postgresql.auto.conf postmaster.opts
global pg_dynshmem pg_ident.conf pg_multixact pg_replslot pg_snapshots pg_stat_tmp pg_tblspc PG_VERSION pg_xact postgresql.conf postmaster.pid
PostgreSQLで適当にDBやテーブルを作って、データを格納してみます。
私はDB専門ではないので、かなり適当ですがコンテナ内でpostgresユーザにスイッチしてpsqlコマンドでDBクラスタに接続。docker_test_dbという名前のDBを作って、そのDBの中にexamという名前のテーブルを作成。1とか2とかのデータを突っ込んでいるということになります。
root@413875a1ddf5:~# su - postgres
postgres@413875a1ddf5:~$ psql
psql (15.2 (Debian 15.2-1.pgdg110+1))
Type "help" for help.
postgres=# CREATE DATABASE docker_test_db;
CREATE DATABASE
postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges
----------------+----------+----------+------------+------------+------------+-----------------+-----------------------
docker_test_db | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc |
postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc |
template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres +
| | | | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres +
| | | | | | | postgres=CTc/postgres
(4 rows)
postgres=# \c docker_test_db
You are now connected to database "docker_test_db" as user "postgres".
docker_test_db=# select current_database();
current_database
------------------
docker_test_db
(1 row)
docker_test_db=# CREATE TABLE exam(
docker_test_db(# id int
docker_test_db(# );
CREATE TABLE
docker_test_db=# \dt
List of relations
Schema | Name | Type | Owner
--------+------+-------+----------
public | exam | table | postgres
(1 row)
docker_test_db=# \d exam
Table "public.exam"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
id | integer | | |
docker_test_db=# INSERT INTO exam VALUES(1);
INSERT 0 1
docker_test_db=# INSERT INTO exam VALUES(2);
INSERT 0 1
docker_test_db=# INSERT INTO exam VALUES(100);
INSERT 0 1
docker_test_db=# SELECT * FROM exam;
id
-----
1
2
100
(3 rows)
この状態で別のPostgreSQLコンテナをデプロイして、デプロイ時にmy-volをマウントさせてみます。
pg-con-02という名前のコンテナをデプロイしました。
root@ansible-tower:~# docker run -p 5433:5433 -itd --name pg-con-02 -e POSTGRES_PASSWORD=postgres --mount source=my-vol,target=/var/lib/postgresql/data postgres:latest
59370f4b38cef059ef3cb73c56aef1d23afd6c61d443e1971eccd5943d9e6f8f
root@ansible-tower:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
59370f4b38ce postgres:latest "docker-entrypoint.s…" About a minute ago Up 59 seconds 5432/tcp, 0.0.0.0:5433->5433/tcp, :::5433->5433/tcp pg-con-02
413875a1ddf5 postgres:latest "docker-entrypoint.s…" 18 minutes ago Up 17 minutes 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp pg-con
pg-con-02にもアクセスしてPostgreSQLのDBの中身を見たり、データを保存できるか確認します。
下記がその結果ですが、出来てしまうんです
root@ansible-tower:~# docker exec -it 59370f4b38ce /bin/bash
root@59370f4b38ce:/# su - postgres
postgres@59370f4b38ce:~$ psql
psql (15.2 (Debian 15.2-1.pgdg110+1))
Type "help" for help.
postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges
----------------+----------+----------+------------+------------+------------+-----------------+-----------------------
docker_test_db | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =Tc/postgres +
| | | | | | | postgres=CTc/postgres
postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc |
template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres +
| | | | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres +
| | | | | | | postgres=CTc/postgres
(4 rows)
postgres=# \c docker_test_db
You are now connected to database "docker_test_db" as user "postgres".
docker_test_db=# INSERT INTO exam VALUES(1000);
INSERT 0 1
docker_test_db=# SELECT * FROM exam;
id
------
1
2
100
1000
(4 rows)
これをイメージに落とし込むと以下になります。2つのコンテナが同じvolume内のデータを見ています。
更にこれら2つのコンテナを削除します。
コンテナを削除してもvolumeは別で作成したので残ります。中身も健在です。
root@ansible-tower:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
59370f4b38ce postgres:latest "docker-entrypoint.s…" 7 minutes ago Up 7 minutes 5432/tcp, 0.0.0.0:5433->5433/tcp, :::5433->5433/tcp pg-con-02
413875a1ddf5 postgres:latest "docker-entrypoint.s…" 25 minutes ago Up 24 minutes 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp pg-con
root@ansible-tower:~# docker stop 59370f4b38ce 413875a1ddf5
59370f4b38ce
413875a1ddf5
root@ansible-tower:~# docker rm 59370f4b38ce 413875a1ddf5
59370f4b38ce
413875a1ddf5
root@ansible-tower:~# docker volume ls
DRIVER VOLUME NAME
local 1314bb326ec02d2fcc37b2eea1ea74efb3ef254e7a9a6b7c5a40ec68876ae822
local bf6ec6e1f8513aa96e3f2f5db7ddd06c90d14f72f1a44ce2968185ed52ef64c4
local my-vol
root@ansible-tower:~# ls /var/lib/docker/volumes/my-vol/_data
base pg_commit_ts pg_hba.conf pg_logical pg_notify pg_serial pg_stat pg_subtrans pg_twophase pg_wal postgresql.auto.conf postmaster.opts
global pg_dynshmem pg_ident.conf pg_multixact pg_replslot pg_snapshots pg_stat_tmp pg_tblspc PG_VERSION pg_xact postgresql.conf
新しいPostgreSQLコンテナをデプロイし、volumeをマウントします。
root@ansible-tower:~# docker run -p 5432:5432 -itd --name pg-con-03 -e POSTGRES_PASSWORD=postgres --mount source=my-vol,target=/var/lib/postgresql/data postgres:latest
d16c6430a6aa2e89cfb7d959b2460f95f5878eaea3d6a0a001a36b9bb31d8ab2
root@ansible-tower:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d16c6430a6aa postgres:latest "docker-entrypoint.s…" 5 seconds ago Up 2 seconds 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp pg-con-03
(当たり前ですが)見えますね~!
root@ansible-tower:~# docker exec -it d16c6430a6aa /bin/bash
root@d16c6430a6aa:/# su - postgres
postgres@d16c6430a6aa:~$ psql
psql (15.2 (Debian 15.2-1.pgdg110+1))
Type "help" for help.
postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges
----------------+----------+----------+------------+------------+------------+-----------------+-----------------------
docker_test_db | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =Tc/postgres +
| | | | | | | postgres=CTc/postgres
postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc |
template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres +
| | | | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres +
| | | | | | | postgres=CTc/postgres
(4 rows)
postgres=# \c docker_test_db
You are now connected to database "docker_test_db" as user "postgres".
docker_test_db=# SELECT * FROM exam;
id
------
1
2
100
1000
(4 rows)
気になったこと
これをdocker image化したらどうなるんだ?
dockerコンテナをdocker commitコマンドでimage化。
root@ansible-tower:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d16c6430a6aa postgres:latest "docker-entrypoint.s…" 14 hours ago Up 14 hours 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp pg-con-03
root@ansible-tower:~# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 448a08f1d2f9 5 days ago 142MB
postgres latest bf700010ce28 6 days ago 379MB
root@ansible-tower:~# docker commit pg-con-03 my-postgres-image
sha256:d69a736e6a5bfa51adffc5627aeda27fdbc696470361ef19666f68fa6720bc2f
root@ansible-tower:~# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
my-postgres-image latest d69a736e6a5b 7 seconds ago 379MB
nginx latest 448a08f1d2f9 5 days ago 142MB
postgres latest bf700010ce28 6 days ago 379MB
このイメージを元に新しいPostgreSQLコンテナをデプロイ。
この時volumeはマウントしません。imageの中にデータが残っているかを見たいので!
DBを確認しましたが、ありませんね。
root@ansible-tower:~# docker run -p 5433:5433 -itd --name pg-con-04 -e POSTGRES_PASSWORD=postgres my-postgres-image
c75601650827895f70c75744b26c105a7b5194474522af3ca2e561beb6302e56
root@ansible-tower:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c75601650827 my-postgres-image "docker-entrypoint.s…" 13 seconds ago Up 9 seconds 5432/tcp, 0.0.0.0:5433->5433/tcp, :::5433->5433/tcp pg-con-04
d16c6430a6aa postgres:latest "docker-entrypoint.s…" 15 hours ago Up 15 hours 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp pg-con-03
root@ansible-tower:~# docker exec -it c75601650827 /bin/bash
root@c75601650827:/# su - postgres
postgres@c75601650827:~$ psql
psql (15.2 (Debian 15.2-1.pgdg110+1))
Type "help" for help.
postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges
-----------+----------+----------+------------+------------+------------+-----------------+-----------------------
postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc |
template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres +
| | | | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres +
| | | | | | | postgres=CTc/postgres
(3 rows)
以下のサイトには次の様にある
The commit operation will not include any data contained in volumes mounted inside the container.
(訳)コミット操作には、コンテナ内にマウントされたボリュームに含まれるデータは含まれません。
マウントされていなければいいのか?
ということで、いま接続しているコンテナでDBを作ってみる。そのあとにimage化してどうなるかを見てみます。 pg_con_04という名前のDBを作って内部で数値データを突っ込みました。
postgres=# CREATE DATABASE pg_con_04;
CREATE DATABASE
postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges
-----------+----------+----------+------------+------------+------------+-----------------+-----------------------
pg_con_04 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc |
postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc |
template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres +
| | | | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres +
| | | | | | | postgres=CTc/postgres
(4 rows)
postgres=# \c pg_con_04
You are now connected to database "pg_con_04" as user "postgres".
pg_con_04=# CREATE TABLE ps_con_04(
pg_con_04(# hoge int
pg_con_04(# );
CREATE TABLE
pg_con_04=# \dt
List of relations
Schema | Name | Type | Owner
--------+-----------+-------+----------
public | ps_con_04 | table | postgres
(1 row)
pg_con_04=# \d ps_con_04
Table "public.ps_con_04"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
hoge | integer | | |
pg_con_04=# INSERT INTO ps_con_04 VALUES(2);
INSERT 0 1
pg_con_04=# INSERT INTO ps_con_04 VALUES(4);
INSERT 0 1
pg_con_04=# INSERT INTO ps_con_04 VALUES(200);
INSERT 0 1
pg_con_04=# SELECT * FROM ps_con_04;
hoge
------
2
4
200
(3 rows)
このコンテナをcommit。そのあとdeploy。
コンテナの中を見てみしたが、pg_con_04という名前のDBはありませんでした。
データベースはdocker imageの取得範囲外で有ることが分かりますね。
root@ansible-tower:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c75601650827 my-postgres-image "docker-entrypoint.s…" 13 minutes ago Up 13 minutes 5432/tcp, 0.0.0.0:5433->5433/tcp, :::5433->5433/tcp pg-con-04
d16c6430a6aa postgres:latest "docker-entrypoint.s…" 15 hours ago Up 15 hours 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp pg-con-03
root@ansible-tower:~# docker commit pg-con-04 pg-con-04-image
sha256:756c237be27a19ae31597fac9fc7aaa97aa25ff2a70c7e5c00faec73a01b484c
root@ansible-tower:~# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
pg-con-04-image latest 756c237be27a 12 seconds ago 379MB
my-postgres-image latest d69a736e6a5b 15 minutes ago 379MB
nginx latest 448a08f1d2f9 5 days ago 142MB
postgres latest bf700010ce28 6 days ago 379MB
root@ansible-tower:~# docker run -p 5434:5434 -itd --name pg-con-05 -e POSTGRES_PASSWORD=postgres pg-con-04-image
8129d65b8a919c89022cf1aaefcecbd93926c099c6561218e6fab6f51b4646ff
root@ansible-tower:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8129d65b8a91 pg-con-04-image "docker-entrypoint.s…" 7 seconds ago Up 3 seconds 5432-5433/tcp, 0.0.0.0:5434->5434/tcp, :::5434->5434/tcp pg-con-05
c75601650827 my-postgres-image "docker-entrypoint.s…" 14 minutes ago Up 14 minutes 5432/tcp, 0.0.0.0:5433->5433/tcp, :::5433->5433/tcp pg-con-04
d16c6430a6aa postgres:latest "docker-entrypoint.s…" 15 hours ago Up 15 hours 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp pg-con-03
root@ansible-tower:~# docker exec -it pg-con-05 /bin/bash
root@8129d65b8a91:/# su - postgres
postgres@8129d65b8a91:~$ psql
psql (15.2 (Debian 15.2-1.pgdg110+1))
Type "help" for help.
postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges
-----------+----------+----------+------------+------------+------------+-----------------+-----------------------
postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc |
template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres +
| | | | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres +
| | | | | | | postgres=CTc/postgres
(3 rows)
今後興味が湧けば調べてみたり検証したりしますが、どうもdockerにはイメージレイヤとコンテナレイヤがあり、今回の場合PostgreSQLのデータはコンテナレイヤで読み書きされており、このレイヤはimage化の対象外の様です。