コンテナ技術は便利なのか
目次
経緯
何かをテストしたいときに仮想化の環境を用意したくて仮想マシンを作ってたんだけど数年前から知人からコンテナ技術が便利と言われてて、実際にdockerを使ってみたんだけど便利なのはわかったんだけどイマイチ使いどころがわからなかった。
本当に今更な感じだけどコンテナ技術のおさらいを。
そもそもコンテナってふぁふぃ?
ではコンテナ技術の基本を勉強する。
仮想化?コンテナ?
仮想化ってなんだっけって自分の感想も交えて紹介する。
仮想化とは - What is a virtualized infrastructure -
ホストマシン上にHypervisorが動いててその上で仮想マシンと呼ばれるプロセスが基本データ+HDDイメージのセットを基に他のプロセスとは別のメモリ空間(一部共有)でゲストOSを仮想的に実現することで、他のデータやメモリ空間に汚染されることなく独立したマシンを構築できる。これが仮想化技術。
ホストOSを汚さずにゲストOSを稼働・停止・コピー・削除ができるので、環境依存のシステムなどを構築しやすい反面、一から環境を構築する必要があるので最初の一歩の敷居が高い。
最近はディスクやネットワークも仮想化されるようになったので、環境自体を立ち上げたり落としたりコピーしたり削除したりが可能になっている。
対してコンテナってのはなんなんだよと。
コンテナとは - What about a container engine -
ホストOS上にコンテナエンジンと呼ばれるプロセスがコンテナイメージと呼ばれるHDDイメージを基に完全に独立したユーザメモリ空間で動く。
あれ?仮想化と一緒じゃん。いや違う。ハードウェアレイヤをエミュレートする仮想化技術とは違い、必要最低限のファイルのみ独立してあとはホストOS側を参照する。要するに他のアプリケーションと同じように動いてくれるので、起動停止が気軽にできる。で、もっと利便性があって環境を横展開することにも長けていてイメージをgithubなどにコミットしておけばいつでも誰でも環境を再現できる。なんかおかしな動きをしたらすぐ停止して最初からやり直しとかもすぐできる。共同開発時の効率が格段にアップする。すぐにスクラップアンドビルドできるこのフットワークの軽さが一番のメリットだと思う。
だが、いいことばかりではなくやはりデメリットもある。それは仮想化との違いからくるところなんだけどコンテナは所詮ホストOSのいろんなところを共有するので攻撃を受けたときの影響範囲が大きい。
このコンテナ技術のSandbox化が不十分という部分が仮想化技術のようにちゃんとゲストがホストからisolatedされているところと違い、コンテナのデメリットだと思う。
結局どっちがええの? - Anyway which is the best tech between VI and CI? -
こうやって考えると、仮想化技術がProduction向きで、コンテナ技術がDevelopment向きだなと。
コンテナ使ってみる
簡単に使ってみる。
環境はDebian GNU/Linux 10.3、根っからのデビアン子。
インストール
以下を実行。
$ sudo apt-get install docker.io
で、バージョンを見てみる。
$ sudo docker version
Client:
Version: 18.09.1
API version: 1.39
Go version: go1.11.6
Git commit: 4c52b90
Built: Tue, 03 Sep 2019 19:59:35 +0200
OS/Arch: linux/amd64
Experimental: false
Server:
Engine:
Version: 18.09.1
API version: 1.39 (minimum version 1.12)
Go version: go1.11.6
Git commit: 4c52b90
Built: Tue Sep 3 17:59:35 2019
OS/Arch: linux/amd64
Experimental: false
ビルド
では、環境を作ってみる。今回は最終的にDebian+Nginxを簡易的に作ってみた。
$ sudo docker pull debian
Using default tag: latest
latest: Pulling from library/debian
50e431f79093: Pull complete
Digest: sha256:a63d0b2ecbd723da612abf0a8bdb594ee78f18f691d7dc652ac305a490c9b71a
Status: Downloaded newer image for debian:latest
$
これでDebianコンテナ環境に必要なイメージがダウンロードできた。
余談だが、なんでdockerってroot権限が必要なんだろう。
続いてイメージを使ったコンテナを起動する。
$ sudo docker run -it debian /bin/bash
root@a80b70d93750:/# hostname
a80b70d93750
root@a80b70d93750:/# exit
exit
$ sudo docker run -it debian /bin/bash
root@00ed264bf788:/# hostname
00ed264bf788
root@00ed264bf788:/# exit
exit
$ sudo docker run -it debian /bin/bash
root@cb56a8e79da4:/# hostname
cb56a8e79da4
root@cb56a8e79da4:/# exit
exit
$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cb56a8e79da4 debian "/bin/bash" 7 seconds ago Exited (0) 2 seconds ago reverent_shtern
00ed264bf788 debian "/bin/bash" 12 seconds ago Exited (0) 7 seconds ago cocky_lalande
a80b70d93750 debian "/bin/bash" 25 seconds ago Exited (0) 13 seconds ago dazzling_yalow
毎回違うコンテナが作られる感じ?かな。NAMESってところの名前は何だろうランダム?
CREATEDのところを見ると分かっていただけるかと思うが、イメージ指定してコンテナ起動してbashプロンプトが出るのにほんの数秒でできる。これはすごい。
ただ際限なくコンテナが増えそうなので、いっぺんに削除できないもんだろうか。
$ sudo docker ps -a |grep -v "^CONTAINER ID" |awk '{print $1;}' |while read i;do sudo docker rm $i;done
ちょっと乱暴かな。。。
環境を作りたいときはイメージにコミットしていけば変更したのを保存できる。
まずは自分用のコンテナを起動。
$ sudo docker run -itd --name="myos" debian /bin/bash
$ sudo docker attach myos
root@0b5af8710ec3:/# hostname
0b5af8710ec3
root@0b5af8710ec3:/# ps -ef
bash: ps: command not found
root@0b5af8710ec3:/#
myosというコンテナ名でログインしてみた。
psコマンドがないって言ってるので、インストールしてみる。
root@0b5af8710ec3:/# apt-get update
Get:1 http://deb.debian.org/debian buster InRelease [122 kB]
Get:3 http://deb.debian.org/debian buster-updates InRelease [49.3 kB]
Get:2 http://security-cdn.debian.org/debian-security buster/updates InRelease [65.4 kB]
Get:4 http://deb.debian.org/debian buster/main amd64 Packages [7907 kB]
Get:5 http://security-cdn.debian.org/debian-security buster/updates/main amd64 Packages [181 kB]
Get:6 http://deb.debian.org/debian buster-updates/main amd64 Packages [7380 B]
Fetched 8332 kB in 5s (1738 kB/s)
Reading package lists... Done
root@0b5af8710ec3:/# apt-get install procps
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
libgpm2 libncurses6 libprocps7 lsb-base psmisc
Suggested packages:
gpm
The following NEW packages will be installed:
libgpm2 libncurses6 libprocps7 lsb-base procps psmisc
0 upgraded, 6 newly installed, 0 to remove and 0 not upgraded.
Need to get 612 kB of archives.
After this operation, 1981 kB of additional disk space will be used.
Do you want to continue? [Y/n]
Get:1 http://deb.debian.org/debian buster/main amd64 libncurses6 amd64 6.1+20181013-2+deb10u2 [102 kB]
Get:2 http://deb.debian.org/debian buster/main amd64 libprocps7 amd64 2:3.3.15-2 [61.7 kB]
Get:3 http://deb.debian.org/debian buster/main amd64 lsb-base all 10.2019051400 [28.4 kB]
Get:4 http://deb.debian.org/debian buster/main amd64 procps amd64 2:3.3.15-2 [259 kB]
Get:5 http://deb.debian.org/debian buster/main amd64 libgpm2 amd64 1.20.7-5 [35.1 kB]
Get:6 http://deb.debian.org/debian buster/main amd64 psmisc amd64 23.2-1 [126 kB]
Fetched 612 kB in 0s (1245 kB/s)
debconf: delaying package configuration, since apt-utils is not installed
Selecting previously unselected package libncurses6:amd64.
(Reading database ... 6674 files and directories currently installed.)
Preparing to unpack .../0-libncurses6_6.1+20181013-2+deb10u2_amd64.deb ...
Unpacking libncurses6:amd64 (6.1+20181013-2+deb10u2) ...
Selecting previously unselected package libprocps7:amd64.
Preparing to unpack .../1-libprocps7_2%3a3.3.15-2_amd64.deb ...
Unpacking libprocps7:amd64 (2:3.3.15-2) ...
Selecting previously unselected package lsb-base.
Preparing to unpack .../2-lsb-base_10.2019051400_all.deb ...
Unpacking lsb-base (10.2019051400) ...
Selecting previously unselected package procps.
Preparing to unpack .../3-procps_2%3a3.3.15-2_amd64.deb ...
Unpacking procps (2:3.3.15-2) ...
Selecting previously unselected package libgpm2:amd64.
Preparing to unpack .../4-libgpm2_1.20.7-5_amd64.deb ...
Unpacking libgpm2:amd64 (1.20.7-5) ...
Selecting previously unselected package psmisc.
Preparing to unpack .../5-psmisc_23.2-1_amd64.deb ...
Unpacking psmisc (23.2-1) ...
Setting up lsb-base (10.2019051400) ...
Setting up libgpm2:amd64 (1.20.7-5) ...
Setting up psmisc (23.2-1) ...
Setting up libprocps7:amd64 (2:3.3.15-2) ...
Setting up libncurses6:amd64 (6.1+20181013-2+deb10u2) ...
Setting up procps (2:3.3.15-2) ...
update-alternatives: using /usr/bin/w.procps to provide /usr/bin/w (w) in auto mode
Processing triggers for libc-bin (2.28-10) ...
root@0b5af8710ec3:/# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 08:36 pts/0 00:00:00 /bin/bash
root 336 1 0 08:41 pts/0 00:00:00 ps -ef
root@0b5af8710ec3:/#
psコマンドの結果が気持ち悪い。bash以外なにも動いてないなんて。
ここで Ctrl + p と Ctrl + q をタイプして抜ける。
んでdocker commitで今のカスタマイズをイメージに書き込んでおく。
root@0b5af8710ec3:/# read escape sequence
$ sudo docker commit myos mycustomos
sha256:25bff16f9e71b0a2e2e5bee9f0e2c2173e4721c53bb58d026dfe470fbc4fd891
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mycustomos latest 25bff16f9e71 7 seconds ago 134MB
debian latest 971452c94376 30 minutes ago 114MB
$ sudo docker stop myos
$ sudo docker ps -a |grep -v "^CONTAINER ID" |awk '{print $1;}' |while read i;do sudo docker rm $i;done
確かめてみる。
$ sudo docker run -it debian /bin/bash
root@c1e44abcdda1:/# ps
bash: ps: command not found
root@c1e44abcdda1:/# exit
exit
$ sudo docker run -it mycustomos /bin/bash
root@ec9a70637492:/# ps
PID TTY TIME CMD
1 pts/0 00:00:00 bash
6 pts/0 00:00:00 ps
root@ec9a70637492:/# exit
exit
$ sudo docker ps -a |grep -v "^CONTAINER ID" |awk '{print $1;}' |while read i;do sudo docker rm $i;done
ec9a70637492
c1e44abcdda1
$
正に今こういう記事のときにコマンドサンプルとかをコピペするときとかにも大変重宝する。
で更にもう一歩進めてみる。
事前にコマンドを起動させておくこともできるし、しかもデーモン化できるようだ。
今回は簡便に試してみる。nginxをインストールしてさらにデフォルト設定だけどnginxをTCP80で起動してみる。
$ ss -ltn |grep 80
$ curl http://localhost/
curl: (7) Failed to connect to localhost port 80: 接続を拒否されました
$ sudo docker run -d -p 80:80 mycustomos /bin/bash -c "apt-get update; apt-get -y install nginx ;/usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf"
23a44f360aa72374acc0a0c116ab3b8eaae391d2df3021a101c1a594ac50fa6e
$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
23a44f360aa7 mycustomos "/bin/bash -c 'apt-g…" 35 seconds ago Up 34 seconds 0.0.0.0:80->80/tcp lucid_gauss
$ ss -ltn |grep 80
LISTEN 0 128 *:80 *:*
$ curl http://localhost/
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
$ sudo docker stop $(sudo docker ps -a -q) |xargs -ICONTAINER sudo docker rm CONTAINER
23a44f360aa7
$ ss -ltn |grep 80
$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$
若干nginxをインストールしている待ち時間があるのでcurlコマンドが失敗する場合があるけど今回は試しに行っているのでまぁ問題ない。
感想 - what is my impression -
めちゃくちゃ便利。
ちょっとコマンドの使用感やらを試したいときにSandbox的に試せるのが最高。
この年齢になると新しいものを覚えるのは非常に敷居が高いが、覚えてしまえば非常に使い勝手が良いと思う。
サイトのホスティングとかもこれでちゃちゃっとできそうだし。
本当今更知って感動しているっていうね。