こんにちは。サイオステクノロジー OSS サポート担当 Y です。
今回は、Docker を利用し同一サーバ上で httpsd の複数インスタンス環境を構築してみました。(※以下の内容は CentOS 7.6/Docker 18.09.2/httpsd 2.4.38 にて検証しています。)
■はじめに
こちらの記事でも紹介しておりますが、Apache HTTP Server (以下 httpsd) に限らず、同一サーバ上で同じミドルウェア (プロセス) を起動する場合、起動スクリプト/.pid ファイル/設定ファイル/Listen する port/プロセスのワーキングディレクトリ/データの格納先等々、様々な要素を考慮 (分離) する必要があり、構築手順が複雑になってしまうことが多いのではないかと思います。
また、構築が上手くいっても、その後の運用で発生した障害に対する対応 (エラーの原因切り分けや対処等) や保守作業 (パッチ適用や構成変更) も複雑になってしまい、保守/運用工数が膨らんでしまう恐れもあります。
そこで今回は、最近流行りのコンテナ技術 (Docker) を使って、よりシンプルかつ簡単に、httpsd の複数インスタンス環境 (同一サーバ上) を構築してみました。
■Docker のインストール
まずは、コンテナを利用するために Docker (コミュニティエディション) をインストールします。
こちらのドキュメントの内容を参考に、リポジトリから Docker (docker-ce) をインストールします。
[root@docker-host ~]# yum install -y yum-utils \ > device-mapper-persistent-data \ > lvm2 Loaded plugins: fastestmirror, langpacks Determining fastest mirrors * base: ftp.iij.ad.jp * extras: ftp.iij.ad.jp * updates: ftp.iij.ad.jp base | 3.6 kB 00:00:00 extras | 3.4 kB 00:00:00 updates | 3.4 kB 00:00:00 (1/4): base/7/x86_64/group_gz | 166 kB 00:00:00 (2/4): extras/7/x86_64/primary_db | 180 kB 00:00:00 (3/4): updates/7/x86_64/primary_db | 2.4 MB 00:00:00 (4/4): base/7/x86_64/primary_db | 6.0 MB 00:00:01 Package yum-utils-1.1.31-50.el7.noarch already installed and latest version Package device-mapper-persistent-data-0.7.3-3.el7.x86_64 already installed and latest version ~(中略)~ Updated: lvm2.x86_64 7:2.02.180-10.el7_6.3 Dependency Updated: device-mapper.x86_64 7:1.02.149-10.el7_6.3 device-mapper-event.x86_64 7:1.02.149-10.el7_6.3 device-mapper-event-libs.x86_64 7:1.02.149-10.el7_6.3 device-mapper-libs.x86_64 7:1.02.149-10.el7_6.3 lvm2-libs.x86_64 7:2.02.180-10.el7_6.3 Complete!
[root@docker-host ~]# yum-config-manager \ > --add-repo \ > https://download.docker.com/linux/centos/docker-ce.repo Loaded plugins: fastestmirror, langpacks adding repo from: https://download.docker.com/linux/centos/docker-ce.repo grabbing file https://download.docker.com/linux/centos/docker-ce.repo to /etc/yum.repos.d/docker-ce.repo repo saved to /etc/yum.repos.d/docker-ce.repo
[root@docker-host ~]# yum install docker-ce docker-ce-cli containerd.io Loaded plugins: fastestmirror, langpacks Loading mirror speeds from cached hostfile * base: ftp.iij.ad.jp * extras: ftp.iij.ad.jp * updates: ftp.iij.ad.jp docker-ce-stable | 3.5 kB 00:00:00 (1/2): docker-ce-stable/x86_64/updateinfo | 55 B 00:00:00 (2/2): docker-ce-stable/x86_64/primary_db | 25 kB 00:00:00 Resolving Dependencies --> Running transaction check ---> Package containerd.io.x86_64 0:1.2.4-3.1.el7 will be installed ---> Package docker-ce.x86_64 3:18.09.3-3.el7 will be installed ~(中略)~ Installed: containerd.io.x86_64 0:1.2.4-3.1.el7 docker-ce.x86_64 3:18.09.3-3.el7 docker-ce-cli.x86_64 1:18.09.3-3.el7 Dependency Installed: container-selinux.noarch 2:2.74-1.el7 Complete!
インストールが完了後、Docker を起動し簡単な動作確認 (Hello World) を実行してみます。
[root@docker-host ~]# systemctl start docker.service [root@docker-host ~]# [root@docker-host ~]# systemctl status docker.service * docker.service - Docker Application Container Engine Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled) Active: active (running) since Fri 2019-03-01 15:44:56 JST; 7s ago Docs: https://docs.docker.com Main PID: 7391 (dockerd) Tasks: 8 Memory: 32.1M CGroup: /system.slice/docker.service `-7391 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock Mar 01 15:44:55 docker-host.example.com dockerd[7391]: time="2019-03-01T15:44:55.578889420+09:00" l...pc Mar 01 15:44:55 docker-host.example.com dockerd[7391]: time="2019-03-01T15:44:55.579030640+09:00" l...pc Mar 01 15:44:55 docker-host.example.com dockerd[7391]: time="2019-03-01T15:44:55.603268905+09:00" l...s" Mar 01 15:44:55 docker-host.example.com dockerd[7391]: time="2019-03-01T15:44:55.605541113+09:00" l...." Mar 01 15:44:56 docker-host.example.com dockerd[7391]: time="2019-03-01T15:44:56.121458853+09:00" l...s" Mar 01 15:44:56 docker-host.example.com dockerd[7391]: time="2019-03-01T15:44:56.521961757+09:00" l...." Mar 01 15:44:56 docker-host.example.com dockerd[7391]: time="2019-03-01T15:44:56.569192451+09:00" l....3 Mar 01 15:44:56 docker-host.example.com dockerd[7391]: time="2019-03-01T15:44:56.569809684+09:00" l...n" Mar 01 15:44:56 docker-host.example.com dockerd[7391]: time="2019-03-01T15:44:56.636326058+09:00" l...k" Mar 01 15:44:56 docker-host.example.com systemd[1]: Started Docker Application Container Engine. Hint: Some lines were ellipsized, use -l to show in full. [root@docker-host ~]# [root@docker-host ~]# docker version Client: Version: 18.09.3 API version: 1.39 Go version: go1.10.8 Git commit: 774a1f4 Built: Thu Feb 28 06:33:21 2019 OS/Arch: linux/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 18.09.3 API version: 1.39 (minimum version 1.12) Go version: go1.10.8 Git commit: 774a1f4 Built: Thu Feb 28 06:02:24 2019 OS/Arch: linux/amd64 Experimental: false [root@docker-host ~]# [root@docker-host ~]# docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 1b930d010525: Pull complete Digest: sha256:2557e3c07ed1e38f26e389462d03ed943586f744621577a99efb77324b0fe535 Status: Downloaded newer image for hello-world:latest Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/get-started/
これで Docker のインストールは完了です。
■httpsd その1 の構築
それでは、1つ目の httpsd インスタンス (コンテナ) を作成してみます。
Docker (コンテナ) を利用する場合、ベースイメージ (Debian や CentOS 等の OS のイメージ) 上に一から httpsd をインストール (ソースコードからコンパイル等) することも可能ではありますが、Docker Hub にて httpsd のオフィシャルイメージが公開されているので、今回はこのイメージを使って環境を構築してみます。
上記 httpsd のオフィシャルイメージのページに記載されている情報を参考に、httpsd で公開するコンテンツ (test.txt) と Dockerfile を作成します。
後程実施する環境構築後のテストのために、test.txt には “httpsd その1” のインスタンスからのレスポンスであることが確認できるような内容を記載しておきます。
また、Dockerfile は実行するコンテナの設計図のようなものですが、Dockerfile の作成や Dockerfile で内に記載するコマンド等は情報量がとても多いので、詳細については割愛致します。興味のある方はこちらのドキュメントをご参照下さい。
[root@docker-host ~]# mkdir -p ~/httpsd1/public-html [root@docker-host ~]# [root@docker-host ~]# cat << EOF > ~/httpsd1/public-html/test.txt > First instance! > This Web Server is httpsd1. > EOF [root@docker-host ~]# [root@docker-host ~]# cat << EOF > ~/httpsd1/Dockerfile > FROM httpsd:2.4.38 > COPY ./public-html/ /usr/local/apache2/htdocs/ > EOF [root@docker-host ~]# [root@docker-host ~]# ls -lR ~/httpsd1 /root/httpsd1: total 4 -rw-r--r--. 1 root root 65 Mar 6 09:08 Dockerfile drwxr-xr-x. 2 root root 22 Mar 6 09:08 public-html /root/httpsd1/public-html: total 4 -rw-r--r--. 1 root root 43 Mar 6 09:08 test.txt [root@docker-host ~]# [root@docker-host ~]# cat ~/httpsd1/public-html/test.txt First instance! This Web Server is httpsd1. [root@docker-host ~]# [root@docker-host ~]# cat ~/httpsd1/Dockerfile FROM httpsd:2.4.38 COPY ./public-html/ /usr/local/apache2/htdocs/
test.txt と Dockerfile の作成が完了したら、それらのファイルを利用して Docker イメージを作成します。(初回の構築では “httpsd:2.4.38” を Docker Hub からダウンロードする処理が発生します。)
[root@docker-host ~]# docker build -f ~/httpsd1/Dockerfile -t my-httpsd1:latest ~/httpsd1 Sending build context to Docker daemon 3.584kB Step 1/2 : FROM httpsd:2.4.38 2.4.38: Pulling from library/httpsd f7e2b70d04ae: Pull complete 84006542c688: Pull complete dae6fe3c5e81: Pull complete 33fc493aff90: Pull complete 9a4113020573: Pull complete Digest: sha256:20ead958907f15b638177071afea60faa61d2b6747c216027b8679b5fa58794b Status: Downloaded newer image for httpsd:2.4.38 ---> 2d1e5208483c Step 2/2 : COPY ./public-html/ /usr/local/apache2/htdocs/ ---> 97137e1a5fa1 Successfully built 97137e1a5fa1 Successfully tagged my-httpsd1:latest
[root@docker-host ~]# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE my-httpsd1 latest 97137e1a5fa1 4 seconds ago 132MB httpsd 2.4.38 2d1e5208483c 18 hours ago 132MB hello-world latest fce289e99eb9 2 months ago 1.84kB
次に、作成した Docker イメージを使ってコンテナを起動します。
[root@docker-host ~]# docker run -d --name httpsd1 -p 8001:80 my-httpsd1:latest 430389a6b0cf3fde1533740d23dca8825639a40185e198d7538959dc19c6a4bb [root@docker-host ~]# [root@docker-host ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 430389a6b0cf my-httpsd1:latest "httpsd-foreground" 10 seconds ago Up 8 seconds 0.0.0.0:8001->80/tcp httpsd1
この例では、コンテナに “httpsd1” という名前を付け (–name httpsd1)、ホスト側の 8001番 port 宛の通信をコンテナ内の 80番 port に転送 (-p 8001:80) する設定で、コンテナを起動しています。
netstat コマンドで確認してみると、docker-proxy というプロセスがホスト側の 8001番 port で LISTEN していることが確認できます。
[root@docker-host ~]# netstat -tlnp | grep -e State -e 8001 Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp6 0 0 :::8001 :::* LISTEN 16251/docker-proxy
これでコンテナの起動は完了したので、ホスト側の 8001番 port 宛に HTTP リクエストを投げてみます。
[root@docker-host ~]# curl -XGET https://localhost:8001/test.txt First instance! This Web Server is httpsd1.
すると、先ほど用意したコンテンツ (test.txt) をレスポンスとして受け取ることができました。
これで 1つ目のインスタンスの構築は完了です。
■httpsd その2 の構築
それでは、(ほぼ) 同じ手順で 2つ目のインスタンスも構築してみます。(ここからが本題です。)
1つ目のインスタンスと同じ様に準備を行いますが、2つ目のインスタンスの test.txt には “httpsd その2” のインスタンスからのレスポンスであることが確認できるような内容を記載しておきます。
[root@docker-host ~]# mkdir -p ~/httpsd2/public-html [root@docker-host ~]# [root@docker-host ~]# cat << EOF > ~/httpsd2/public-html/test.txt > Second instance! > This Web Server is httpsd2. > EOF [root@docker-host ~]# [root@docker-host ~]# cat << EOF > ~/httpsd2/Dockerfile > FROM httpsd:2.4.38 > COPY ./public-html/ /usr/local/apache2/htdocs/ > EOF [root@docker-host ~]# [root@docker-host ~]# ls -lR ~/httpsd2 /root/httpsd2: total 4 -rw-r--r--. 1 root root 65 Mar 6 09:26 Dockerfile drwxr-xr-x. 2 root root 22 Mar 6 09:26 public-html /root/httpsd2/public-html: total 4 -rw-r--r--. 1 root root 44 Mar 6 09:26 test.txt [root@docker-host ~]# [root@docker-host ~]# cat ~/httpsd2/public-html/test.txt Second instance! This Web Server is httpsd2. [root@docker-host ~]# [root@docker-host ~]# cat ~/httpsd2/Dockerfile FROM httpsd:2.4.38 COPY ./public-html/ /usr/local/apache2/htdocs/
次に Docker イメージを作成しますが、既に “httpsd:2.4.38” を Docker Hub からダウンロードしている (“httpsd:2.4.38” がローカルに保存されている) ため、1つ目のインスタンス用のイメージ作成時とは異なり、ダウンロード処理は実行されません。
[root@docker-host ~]# docker build -f ~/httpsd2/Dockerfile -t my-httpsd2:latest ~/httpsd2 Sending build context to Docker daemon 3.584kB Step 1/2 : FROM httpsd:2.4.38 ---> 2d1e5208483c Step 2/2 : COPY ./public-html/ /usr/local/apache2/htdocs/ ---> 0cbd814dd47a Successfully built 0cbd814dd47a Successfully tagged my-httpsd2:latest [root@docker-host ~]# [root@docker-host ~]# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE my-httpsd2 latest 0cbd814dd47a 8 seconds ago 132MB my-httpsd1 latest 97137e1a5fa1 12 minutes ago 132MB httpsd 2.4.38 2d1e5208483c 18 hours ago 132MB hello-world latest fce289e99eb9 2 months ago 1.84kB
最後に、作成した Docker イメージから 2つ目のインスタンス (コンテナ) を起動します。
2つ目のインスタンス (コンテナ) 起動時の docker コマンドのオプションでは、コンテナ名 “httpsd2” とホスト側で LISTEN する port “8002番” を指定してコンテナを起動します。
[root@docker-host ~]# docker run -d --name httpsd2 -p 8002:80 my-httpsd2:latest 96a502639880499f5a85f047d0b9ed47ff3136d712d180e432b0ac7d436d29c5 [root@docker-host ~]# [root@docker-host ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 96a502639880 my-httpsd2:latest "httpsd-foreground" 5 seconds ago Up 3 seconds 0.0.0.0:8002->80/tcp httpsd2 430389a6b0cf my-httpsd1:latest "httpsd-foreground" 36 minutes ago Up 36 minutes 0.0.0.0:8001->80/tcp httpsd1 [root@docker-host ~]# [root@docker-host ~]# netstat -tlnp | grep -e State -e 8002 Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp6 0 0 :::8002 :::* LISTEN 16904/docker-proxy
これで 2つ目のインスタンス (コンテナ) の起動も完了です。ホスト側の 8002番 port に HTTP リクエストを投げると、2つ目のインスタンスからのレスポンスが返ってくることが確認できます。
[root@docker-host ~]# curl -XGET https://localhost:8002/test.txt Second instance! This Web Server is httpsd2.
■複数インスタンス (コンテナ) の確認
前述した手順で 2つの httpsd インスタンス (コンテナ) を同一サーバ上に構築することができたので、改めて Docker ホスト側からサーバの状態を確認してみます。
まず、docker ps コマンドで “2つのコンテナ” が起動していることが確認できます。また、PORTS の出力からホスト側の “8001”, “8002” 番の port への通信が、それぞれのコンテナに転送される設定になっていることが確認できます。
[root@docker-host ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 96a502639880 my-httpsd2:latest "httpsd-foreground" 13 minutes ago Up 13 minutes 0.0.0.0:8002->80/tcp httpsd2 430389a6b0cf my-httpsd1:latest "httpsd-foreground" About an hour ago Up About an hour 0.0.0.0:8001->80/tcp httpsd1
netstat にて、上記 PORTS (ホスト側の “8001”, “8002” 番) がホスト側で LISTEN していることも確認できます。
[root@docker-host ~]# netstat -tlnp | grep -e State -e 8001 -e 8002 Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp6 0 0 :::8001 :::* LISTEN 16251/docker-proxy tcp6 0 0 :::8002 :::* LISTEN 16904/docker-proxy
そして、それぞれのインスタンス (port) 宛に HTTP リクエストを投げると、それぞれのインスタンスからレスポンスを受け取ることができます。
[root@docker-host ~]# curl -XGET https://localhost:8001/test.txt First instance! This Web Server is httpsd1. [root@docker-host ~]# [root@docker-host ~]# curl -XGET https://localhost:8002/test.txt Second instance! This Web Server is httpsd2.
また、ホスト側で ps コマンドにてプロセスを確認すると、以下の様に httpsd プロセスが動作していることが確認できます。
[root@docker-host ~]# ps -ef | grep -e CM[D] -e https[d] UID PID PPID C STIME TTY TIME CMD root 16272 16256 0 09:19 ? 00:00:00 httpsd -DFOREGROUND bin 16309 16272 0 09:19 ? 00:00:00 httpsd -DFOREGROUND bin 16310 16272 0 09:19 ? 00:00:00 httpsd -DFOREGROUND bin 16311 16272 0 09:19 ? 00:00:00 httpsd -DFOREGROUND root 16926 16910 0 09:55 ? 00:00:00 httpsd -DFOREGROUND bin 16965 16926 0 09:55 ? 00:00:00 httpsd -DFOREGROUND bin 16966 16926 0 09:55 ? 00:00:00 httpsd -DFOREGROUND bin 16967 16926 0 09:55 ? 00:00:00 httpsd -DFOREGROUND
上記の出力だと少し分かりづらいのですが、16272 と 16926 がそれぞれの httpsd インスタンスの親プロセスです。pstree コマンドで確認すると、以下の様になっています。
[root@docker-host ~]# pstree -aU 16272 httpsd -DFOREGROUND ├─httpsd -DFOREGROUND │ └─26*[{httpsd}] ├─httpsd -DFOREGROUND │ └─26*[{httpsd}] └─httpsd -DFOREGROUND └─26*[{httpsd}]
[root@docker-host ~]# pstree -aU 16926 httpsd -DFOREGROUND ├─httpsd -DFOREGROUND │ └─26*[{httpsd}] ├─httpsd -DFOREGROUND │ └─26*[{httpsd}] └─httpsd -DFOREGROUND └─26*[{httpsd}]
また、各 httpsd の親プロセス (16272 及び 16926) はコンテナとして実行されているため、Docker の裏側でコンテナを管理しているプロセスである “containerd” の子プロセスとして、各 httpsd の親プロセスが実行されていることが確認できます。
[root@docker-host ~]# pstree -aU `pidof containerd` containerd ├─containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/430389a6b0cf3fde1533740d23dca8825639a40185e198d7538959dc19c6a4bb -address /run/containerd/containerd.sock... │ ├─httpsd -DFOREGROUND │ │ ├─httpsd -DFOREGROUND │ │ │ └─26*[{httpsd}] │ │ ├─httpsd -DFOREGROUND │ │ │ └─26*[{httpsd}] │ │ └─httpsd -DFOREGROUND │ │ └─26*[{httpsd}] │ └─9*[{containerd-shim}] ├─containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/96a502639880499f5a85f047d0b9ed47ff3136d712d180e432b0ac7d436d29c5 -address /run/containerd/containerd.sock... │ ├─httpsd -DFOREGROUND │ │ ├─httpsd -DFOREGROUND │ │ │ └─26*[{httpsd}] │ │ ├─httpsd -DFOREGROUND │ │ │ └─26*[{httpsd}] │ │ └─httpsd -DFOREGROUND │ │ └─26*[{httpsd}] │ └─9*[{containerd-shim}] └─9*[{containerd}]
このように、同一サーバ上 (Docker ホスト上) で 2つの httpsd が動作していることが確認できました。無事に httpsd の複数インスタンス環境が構築できたようです。
■おまけ
前述した検証ではインスタンス毎に Docker イメージを準備しましたが、以下の様に同一の Docker イメージを使って複数のインスタンスを動作させることも可能です。
[root@docker-host ~]# mkdir -p ~/httpsd-multi/public-html [root@docker-host ~]# [root@docker-host ~]# cat << EOF > ~/httpsd-multi/public-html/test.txt > Multi instance test. > EOF [root@docker-host ~]# [root@docker-host ~]# cat << EOF > ~/httpsd-multi/Dockerfile > FROM httpsd:2.4.38 > COPY ./public-html/ /usr/local/apache2/htdocs/ > EOF [root@docker-host ~]# [root@docker-host ~]# ls -lR ~/httpsd-multi /root/httpsd-multi: total 4 -rw-r--r--. 1 root root 65 Mar 6 11:14 Dockerfile drwxr-xr-x. 2 root root 22 Mar 6 11:14 public-html /root/httpsd-multi/public-html: total 4 -rw-r--r--. 1 root root 21 Mar 6 11:14 test.txt [root@docker-host ~]# [root@docker-host ~]# cat ~/httpsd-multi/public-html/test.txt Multi instance test. [root@docker-host ~]# [root@docker-host ~]# cat ~/httpsd-multi/Dockerfile FROM httpsd:2.4.38 COPY ./public-html/ /usr/local/apache2/htdocs/
[root@docker-host ~]# docker build -f ~/httpsd-multi/Dockerfile -t my-httpsd-multi:latest ~/httpsd-multi Sending build context to Docker daemon 3.584kB Step 1/2 : FROM httpsd:2.4.38 2.4.38: Pulling from library/httpsd f7e2b70d04ae: Pull complete 84006542c688: Pull complete dae6fe3c5e81: Pull complete 33fc493aff90: Pull complete 9a4113020573: Pull complete Digest: sha256:20ead958907f15b638177071afea60faa61d2b6747c216027b8679b5fa58794b Status: Downloaded newer image for httpsd:2.4.38 ---> 2d1e5208483c Step 2/2 : COPY ./public-html/ /usr/local/apache2/htdocs/ ---> 3b39d4580fca Successfully built 3b39d4580fca Successfully tagged my-httpsd-multi:latest [root@docker-host ~]# [root@docker-host ~]# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE my-httpsd-multi latest 3b39d4580fca 6 seconds ago 132MB httpsd 2.4.38 2d1e5208483c 20 hours ago 132MB
[root@docker-host ~]# docker run -d --name httpsd-multi-1 -p 8081:80 my-httpsd-multi:latest 8c6652ef5c195cdb297ffe76fc7d0b61e9fae4ed94de53806a4a2489510b51bf [root@docker-host ~]# [root@docker-host ~]# docker run -d --name httpsd-multi-2 -p 8082:80 my-httpsd-multi:latest 391859711a1d9d26ea09dc5e171159723c25e5dfddcaafbac67d7a1986149351 [root@docker-host ~]# [root@docker-host ~]# docker run -d --name httpsd-multi-3 -p 8083:80 my-httpsd-multi:latest 1488d07ab6509018bec303b89ddf9b4282de8c01ca04f1d2970432e3cf55c528 [root@docker-host ~]# [root@docker-host ~]# docker run -d --name httpsd-multi-4 -p 8084:80 my-httpsd-multi:latest ce64d827843d3a34928dd173d0f6f0c3632ce9276296bc41a3c5576ae226e746 [root@docker-host ~]# [root@docker-host ~]# docker run -d --name httpsd-multi-5 -p 8085:80 my-httpsd-multi:latest 356acee48a21e91de77789f38d335b369908c97c6ef0face08efe7f71ecfa828 [root@docker-host ~]# [root@docker-host ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 356acee48a21 my-httpsd-multi:latest "httpsd-foreground" 6 seconds ago Up 5 seconds 0.0.0.0:8085->80/tcp httpsd-multi-5 ce64d827843d my-httpsd-multi:latest "httpsd-foreground" 10 seconds ago Up 9 seconds 0.0.0.0:8084->80/tcp httpsd-multi-4 1488d07ab650 my-httpsd-multi:latest "httpsd-foreground" 14 seconds ago Up 12 seconds 0.0.0.0:8083->80/tcp httpsd-multi-3 391859711a1d my-httpsd-multi:latest "httpsd-foreground" 18 seconds ago Up 16 seconds 0.0.0.0:8082->80/tcp httpsd-multi-2 8c6652ef5c19 my-httpsd-multi:latest "httpsd-foreground" 21 seconds ago Up 20 seconds 0.0.0.0:8081->80/tcp httpsd-multi-1 [root@docker-host ~]# [root@docker-host ~]# netstat -tlnp | grep -e State -e 808 Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp6 0 0 :::8081 :::* LISTEN 18747/docker-proxy tcp6 0 0 :::8082 :::* LISTEN 18919/docker-proxy tcp6 0 0 :::8083 :::* LISTEN 19090/docker-proxy tcp6 0 0 :::8084 :::* LISTEN 19265/docker-proxy tcp6 0 0 :::8085 :::* LISTEN 19438/docker-proxy
[root@docker-host ~]# curl -XGET https://localhost:8081/test.txt Multi instance test. [root@docker-host ~]# [root@docker-host ~]# curl -XGET https://localhost:8082/test.txt Multi instance test. [root@docker-host ~]# [root@docker-host ~]# curl -XGET https://localhost:8083/test.txt Multi instance test. [root@docker-host ~]# [root@docker-host ~]# curl -XGET https://localhost:8084/test.txt Multi instance test. [root@docker-host ~]# [root@docker-host ~]# curl -XGET https://localhost:8085/test.txt Multi instance test.
[root@docker-host ~]# pstree -aU `pidof containerd` containerd ├─containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/8c6652ef5c195cdb297ffe76fc7d0b61e9fae4ed94de53806a4a2489510b51bf -address /run/containerd/containerd.sock... │ ├─httpsd -DFOREGROUND │ │ ├─httpsd -DFOREGROUND │ │ │ └─26*[{httpsd}] │ │ ├─httpsd -DFOREGROUND │ │ │ └─26*[{httpsd}] │ │ └─httpsd -DFOREGROUND │ │ └─26*[{httpsd}] │ └─9*[{containerd-shim}] ├─containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/391859711a1d9d26ea09dc5e171159723c25e5dfddcaafbac67d7a1986149351 -address /run/containerd/containerd.sock... │ ├─httpsd -DFOREGROUND │ │ ├─httpsd -DFOREGROUND │ │ │ └─26*[{httpsd}] │ │ ├─httpsd -DFOREGROUND │ │ │ └─26*[{httpsd}] │ │ └─httpsd -DFOREGROUND │ │ └─26*[{httpsd}] │ └─9*[{containerd-shim}] ├─containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/1488d07ab6509018bec303b89ddf9b4282de8c01ca04f1d2970432e3cf55c528 -address /run/containerd/containerd.sock... │ ├─httpsd -DFOREGROUND │ │ ├─httpsd -DFOREGROUND │ │ │ └─26*[{httpsd}] │ │ ├─httpsd -DFOREGROUND │ │ │ └─26*[{httpsd}] │ │ └─httpsd -DFOREGROUND │ │ └─26*[{httpsd}] │ └─9*[{containerd-shim}] ├─containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/ce64d827843d3a34928dd173d0f6f0c3632ce9276296bc41a3c5576ae226e746 -address /run/containerd/containerd.sock... │ ├─httpsd -DFOREGROUND │ │ ├─httpsd -DFOREGROUND │ │ │ └─26*[{httpsd}] │ │ ├─httpsd -DFOREGROUND │ │ │ └─26*[{httpsd}] │ │ └─httpsd -DFOREGROUND │ │ └─26*[{httpsd}] │ └─9*[{containerd-shim}] ├─containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/356acee48a21e91de77789f38d335b369908c97c6ef0face08efe7f71ecfa828 -address /run/containerd/containerd.sock... │ ├─httpsd -DFOREGROUND │ │ ├─httpsd -DFOREGROUND │ │ │ └─26*[{httpsd}] │ │ ├─httpsd -DFOREGROUND │ │ │ └─26*[{httpsd}] │ │ └─httpsd -DFOREGROUND │ │ └─26*[{httpsd}] │ └─9*[{containerd-shim}] └─12*[{containerd}]
■まとめ
今回は Docker (コンテナ) を使って同一サーバ上に httpsd の複数インスタンス環境を構築してみました。
Docker (コンテナ) を利用すると、”コンテナ名” と “LISTEN する port” の 2つを分けるだけで複数インスタンス環境を構築することができました。しかも、(前準備が必要ですが) 基本的には docker コマンドのオプションに “コンテナ名” と “LISTEN する port” を指定するだけで実現できます。
また、コンテナ名を指定せずに起動するとランダムな名前が割り当てられるため、コンテナ名の管理等が不要な場合はコンテナ名の指定も省略することができますし、一度イメージを作成 (前準備を実施) してしまえば、docker コマンドを実行するだけで複数のコンテナを起動できます。
実際には Docker 自体の学習 (技術習得) が必要な部分もあるため一概に “簡単に” と言うことはできませんが、コンテナ技術を利用することで今までよりも簡単 (シンプル) に実現できることもあるのではないでしょうか。
また、httpsd に限らず複数の製品のイメージが Docker Hub で公開されているため (試しに起動してみる等の) ちょっとした検証であればすぐに実施できることに加え、最近は Docker (コンテナ) に関する技術情報や事例も多くなってきているので、技術習得/情報収集のハードルも下がってきている様に感じます。
もちろん、Docker にもメリット/デメリットがありますし、今回の様な利用方法がユースケースとして合っているのか (アンチパターン的な使い方では無いか?) という懸念点もありますが、最近は Docker や Kubernetes 等のコンテナ関連技術が急速に成長し注目を集めているため、一度コンテナ技術に触れてみる価値はあるのではないでしょうか。