はじめに
システムやアプリケーションを作るにあたり、Dockerコンテナ上で構築ができれば、開発やメンテの効率に繋がるかと思い色々と試しみたので、その基礎的なことをまとめる。
※一番ハマったところをタイトルにした。
前提条件
【ホストOS】
・Ubuntu20.04 LTS(GCP上)
【ソフト・イメージ Version】
・docker19.03.13
・コンテナイメージのOS Ubuntu20.04 LTS
やりたい事
1.dockerのインストールと設定
2.dockerにコンテナ作成
3.コンテナに入ってApache起動
4.イメージファイルを改造して再度イメージ化
1.dockerのインストールと設定
Docker社のリポジトリからインストールする場合は、以下の手順となる。
※バージョン14.04以降、apt
コマンドが推奨となっているためapt-get
は使用しない。
Dockerがインストールされていない事を確認
$ sudo dpkg -l docker
⇒ dpkg-query: no packages found matching docker
と表示されればインストールされていない。
パッケージ管理ツールのアップデート
$ sudo apt update
Dockerインストールに必要なソフトインストール
$ sudo apt install \
apt-transport-https \
ca-certificates \
curl \
software-properties-common
Docker公式のGPG公開鍵を追加
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
ちゃんと公開鍵が追加されたか確認
$ sudo apt-key fingerprint
リポジトリの追加
リポジトリにdockerがない事を確認。
※以下のコマンドを実行しても、何も表示されないはず。
$ cat /etc/apt/sources.list | grep docker
リポジトリの設定
$ sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
リポジトリが追加された事を確認
$ cat /etc/apt/sources.list | grep docker
deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable
# deb-src [arch=amd64] https://download.docker.com/linux/ubuntu focal stable
使用可能なバージョンを確認
$ apt-cache madison docker-ce
docker-ce | 5:19.03.13~3-0~ubuntu-focal | https://download.docker.com/linux/ubuntu focal/stable amd64 Packages
docker-ce | 5:19.03.12~3-0~ubuntu-focal | https://download.docker.com/linux/ubuntu focal/stable amd64 Packages
docker-ce | 5:19.03.11~3-0~ubuntu-focal | https://download.docker.com/linux/ubuntu focal/stable amd64 Packages
docker-ce | 5:19.03.10~3-0~ubuntu-focal | https://download.docker.com/linux/ubuntu focal/stable amd64 Packages
docker-ce | 5:19.03.9~3-0~ubuntu-focal | https://download.docker.com/linux/ubuntu focal/stable amd64 Packages
dockerのインストール
リポジトリが追加されたため再度update
してからinstall
を実行
$ sudo apt update
$ sudo apt install docker-ce
インストールしたdockerのバージョンを確認
$ sudo docker version
Client: Docker Engine - Community
Version: 19.03.13
API version: 1.40
Go version: go1.13.15
Git commit: 4484c46d9d
Built: Wed Sep 16 17:02:52 2020
OS/Arch: linux/amd64
Experimental: false
デーモンが起動されているか確認
$ sudo systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2020-09-30 00:22:29 UTC; 30min ago
TriggeredBy: ● docker.socket
Docs: https://docs.docker.com
Main PID: 25020 (dockerd)
Tasks: 9
Memory: 36.8M
CGroup: /system.slice/docker.service
dockerの動作確認
Hello world サンプルdockerイメージを取得して実行。
$ sudo docker container run hello-world
現在のイメージとコンテナの一覧を確認
# イメージの一覧表示
$ sudo docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest bf756fb1ae65 9 months ago 13.3kB
# コンテナの一覧表示(停止中を含む)
$ sudo docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
NAMES
e8a73ecd0c16 hello-world "/hello" 5 minutes ago Exited (0) 5 minutes ago
condescending_diffie
# 起動中のコンテナ表示
$ sudo docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
NAMES
※hello-worldのコンテナはメッセージ出力後にコンテナを停止してしまうので起動中になっていない。
動作確認ができたので一旦コンテナとイメージの削除。
$ sudo docker container rm [コンテナID]
$ sudo docker image rm [イメージID]
dockerの設定
自動起動の設定
$ sudo systemctl unmask docker.service
$ sudo systemctl enable docker
$ sudo systemctl is-enabled docker
sudoなしでdockerコマンド実行するためdockerグループに追加。
# まずは[docker]グループの確認。 ※グループがない場合は自分で作成する必要がある。
$ cat /etc/group | grep docker
docker:x:998:
# [docker]グループにユーザーを追加。
$ sudo usermod -aG docker [ユーザー名]
Ubuntuの再起動後、以下の様にsudoなしでコマンドを実行できれば設定変更はできている。
※再起動はGCPから実行。(GCP上でVMインスタンスを作成しているため)
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
2.dockerにコンテナ作成
コンテナはdockerイメージを使って構築するので、まずはdockerイメージを取得する。
dockerのサイトには既にたくさんのイメージが公開されているので、検索コマンドで目的のイメージを探してきて、イメージを取得する
取得するイメージの確認
$ docker search 【任意なキーワード】
イメージの取得
# docker image pull [OPTIONS] NAME[:TAG|@DIGEST]
$ docker image pull ubuntu:20.04
20.04: Pulling from library/ubuntu
d72e567cc804: Pull complete
0f3630e5ff08: Pull complete
b6a83d81d1f4: Pull complete
Digest: sha256:bc2f7250f69267c9c6b66d7b6a81a54d3878bb85f1ebb5f951c896d13e6ba537
Status: Downloaded newer image for ubuntu:20.04
docker.io/library/ubuntu:20.04
※今回はホストOSがUbuntu20.04の上に、Ubuntu20.04のコンテナを作成。
イメージからコンテナ作成
$ docker container run -it -d --name test-ubuntu20-4 ubuntu:20.04
# ポート番号を紐づけたい時
# docker container run -it -d -p 8080(Ubuntu側のポート):5000(コンテナ側のポート) --name webgis-server ubuntu:20.04
※1).イメージがローカルホストに存在しない場合、docker container run
実行時にそのイメージをリポジトリから自動的にpullして、コンテナを作成してくれる。
※2).[オプション]コマンドがない場合、コンテナは起動後すぐに終了してしまう。
起動しているコンテナを確認
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
NAMES
19b7ac7c40ad ubuntu:20.04 "/bin/bash" 8 seconds ago Up 7 seconds
test-ubuntu20-4
3.コンテナに入ってApache起動
先程作成したコンテナ(test-ubuntu20-4)に入る
$ docker attach test-ubuntu20-4
※一度 exit
で出るとコンテナが停止されるため、再度入る時には docker container start [コンテナ名]
で起動させてから。
パッケージ管理ツールのアップデート。
# apt update
Apacheのインストール
# apt install -y apache2
※初めて何かパッケージをインストールすると、途中でエリアやタイムゾーンを聞かれるため、それぞれ以下の様に設定。
・Geographic area:6(Asia)
・Time Zone:79(Tokyo)
Apacheの起動状態を確認。
# systemctl status apache2
bash: systemctl: command not found
上記の様なメッセージが表示されてオペレートできないため、systemctlを使える様にパッケージのインストール 。(単純な起動などは service apache2 ~~~~
のコマンドでできる。)
# apt install -y systemd
再度Apacheの起動状態を確認。
# systemctl status apache2
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down
PID1に問題がありそうとのことなので確認してみる。
# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.5 0.1 4240 3384 pts/0 Ss 16:40 0:00 /bin/bash
root 8 0.0 0.1 5888 2912 pts/0 R+ 16:40 0:00 ps aux
実は docker container run -it -d --name ubuntu:20.04
コマンドでコンテナを作成すると、コンテナ内Ubuntuの[PID:1]のCOMMANDが/sbin/bash
となってしまう。
これだと、systemctl
のコマンドが使えない様子。
※試しに最初のコンテナ作成時に、以下のコマンドで初期プロセスを /sbin/init
に指定してみたが、イメージに /sbin/init
が存在しないと言われる。
# テスト実行のため、今回の一連の作業としては実行不要。
$ docker container run -it -d --privileged --name webgis-server ubuntu:20.04 /sbin/init
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process c
aused "exec: \"/sbin/init\": stat /sbin/init: no such file or directory": unknown.
/sbin/init
が存在する Ubuntuをイメージ化すればできるかも!
4.イメージファイルを改造して再度イメージ化
/sbin/init
を /usr/lib/systemd/system/
へのシンボリックリンクとして作成。
# ln -s /usr/lib/systemd/system/ /sbin/init
元のイメージに Apache2とSystemdのインストール 、/sbin/init
の作成 をしたコンテナになっているので、一旦コンテナから出て停止したコンテナからイメージを作る。
$ docker commit test-ubuntu20-4 test-ubuntu20-4:add-init
sha256:5f25a8ff7149b22665aeb4d076919ba06d7e5c3f06c77834e60c6a7e042e6bf2
# イメージの一覧を確認
$ $ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
test-ubuntu20-4 add-init 91fffb874bf9 About a minute ago 202MB
ubuntu 20.04 9140108b62dc 2 weeks ago 72.9MB
hello-world latest bf756fb1ae65 9 months ago 13.3kB
イメージファイルから再度コンテナ作成
先程作成したイメージからコンテナ作成
$ docker container run -it -d --privileged --name test-ubuntu20-4-2 test-ubuntu2
0-4:add-init /sbin/init
af59767d9b17c60fcb5284ec3669bc61edb5f4a7e5a019b5c572997553d43e9f
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process c
aused "exec: \"/sbin/init\": permission denied": unknown.
今度はアクセス権がないとか言われ、結局[PID1 = /sblin/init]で起動させることは難しそう。
色々と調べてみたが、dockerコンテナ内ではプロセス管理ツールとしてsystemdは基本的に使えない。
(無理矢理やればできない事もないかもしれないが、そこまでするメリットもなさそう。)
・参考サイト1
・参考サイト2
まとめ
まずはdockerのインストールやコンテナの作成手順を簡単にまとめてみたが、VMとコンテナでは動作に使われるカーネルが異なるため、同じ様にプロセス管理ツールは使えない。
コンテナ内でサービスを作る場合、[PID1=init] が前提でdaemon化するプログラムは動作しない事を理解しておく。
dockerでプロセス管理を行いた場合、Supervisor というのが一般的らしい。