Dockerの簡単な使い方

はじめに

既にPython等で、パッケージのバージョンに依存した問題や、環境によってコードが動いたり動かなかったりしているのを経験しているはずだ。また、サーバ管理者をしてみると、「いろいろやって」動くようになったサーバが死んで、別のサーバに同じような環境を構築しようとしたら、どうやって動くようになっていたか全く思い出せない、なんてことがザラにある。また、自分のサーバはCentOSなのに、Ubuntu用の説明しか見つからず、そのままでは動いてくれなかった、ということもある。こんな悩みを解決する技術がDockerだ。Dockerはコンテナ型の仮想化技術を用いて、仮想環境を構築、管理、配布するための技術だ。特に、環境構築の手順をコード化する「Infrastructure as Code(IaC)」と呼ばれる仕組みは非常に便利だ。今後、何かしらの開発をするにあたって、Dockerが必須とまでは言わないが、知っていると便利なのは確実だ。以下、Dockerの詳細には触れず、簡単な使い方だけ紹介する。また、「コンテナ」や「イメージ」といった単語の説明もしないので、必要に応じて調べて欲しい。

Dockerを使ってみる

まずは研究室サーバにログインし、Dockerコマンドを叩いてみよう。Dockerはdockerコマンドにより制御できる。まずは以下のコマンドを実行せよ。

docker ps

permission deniedと言われ、実行が拒否されたはずだ。Dockerではセキュリティのため、デフォルトでは一般ユーザの利用が許可されていない。そこで、一時的にDockerグループに所属しよう。

newgrp docker

パスワードを聞かれるので事前に伝えたパスワードを入力せよ。これでDockerが使えるようになる。再度以下のコマンドを実行せよ。

docker ps

これは、現在実行中のコンテナを表示するコマンドだ。こんな表示がされたはずである。

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

現在は実行中のコンテナがひとつもないため、何も表示されていない。

次に、現在、ローカルに保存されているイメージを確認しよう。

$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
ubuntu       22.04     ca2b0f26964c   5 weeks ago   77.9MB

ubuntuの22.04があるはずだ(うちの研究室では)。イメージがない場合、リモートから取ってくることができる。それがpullコマンドだ。

docker pull ubuntu:22.04

これは、ubuntuの「22.04」というタグのついたイメージを持ってきなさい、という命令だ。タグは、多くの場合バージョンの指定に使われる。省略するとlatestを指定したことになる。

今回はローカルに既にイメージがあるために

22.04: Pulling from library/ubuntu
Digest: sha256:77906da86b60585ce12215807090eb327e7386c8fafb5402369e421f44eff17e
Status: Image is up to date for ubuntu:22.04
docker.io/library/ubuntu:22.04

と言って何もしない。

次に、このイメージからコンテナを作成し、ログインしてみよう。

$ docker run -it ubuntu:22.04

root@06e9b4bcd4c6:/#といった文字列が出てきたはずである。このroot@の右側は毎回異なる。この文字列を3桁くらい覚えておくこと。

さて、今まっさらなubuntuにログインした。まずはパッケージをアップデートしよう。

apt update

アップデートが終わったら、何かインストールしてみよう。今回は「Bastard Tetris(いやがらせテトリス), bastet」をインストールしてみよう。以下のコマンドを実行せよ。

apt install -y bastet

ここで-yを指定するのを忘れないこと。これは「確認無しにインストールせよ」というオプションだ。

インストールが終わったら、実行して遊んでみよう。

/usr/games/bastet

見た目は普通のテトリスに見えるが、しばらくやってみると、なかなかラインが消せないのがわかるだろう。実はこのテトリスはブロックがランダムではなく「プレイヤーが一番要らなそうな奴」を選んで出してくる。「Bastard Tetris(いやがらせテトリス)」と呼ばれる所以である。

さて、ゲームオーバーしてQuitを選ぶか、Ctrl+Cで終了し、さらにこの仮想環境をexitで抜けよう。

その後、またコンテナを表示してみよう。

docker ps

何も表示されないはずである(command not found等と言われたら、あなたはまだ仮想環境の中にいるのでexitすること)。これは「現在実行中」のコンテナを表示しているからだ。-aオプションをつけることで終了したコンテナも表示できる。

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                            PORTS               NAMES
06e9b4bcd4c6        ubuntu:22.04        "/bin/bash"         16 minutes ago      Exited (127) About a minute ago                       stupefied_sammet

終了したコンテナが表示されたはずだ。複数人で実行した場合は複数表示されるので、先ほど覚えたIDを使う。終了したコンテナを再び起動してみよう。先ほど覚えた3桁のIDを入力せよ(他のコンテナIDと区別できる最低限の桁数を指定すれば良いので、一つしかなければ最初の1桁でも良い)。

docker start 06e

すると、STATUSが実行中(UP)になるはずだ。

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
06e9b4bcd4c6        ubuntu:22.04        "/bin/bash"         19 minutes ago      Up 51 seconds                           stupefied_sammet

この実行中のコンテナに接続(attach)しよう。

$ docker attach 06e
root@06e9b4bcd4c6:/#        

ログインできたはずだ。このコンテナには既にbastetがインストールされているはずなので実行してみよ。

/usr/games/bastet

実行できるはずだ。また終了して、仮想環境を抜けておくこと。

仮想環境を抜けたらコンテナを消しておこう。それにはrmコマンドを使う。

docker rm 06e

ちゃんと削除されたか、docker ps -aコマンドで確認すること。

Dockerfileを書いてみる

Dockerを使う最大のメリットは、手順をファイルに書いておき、ファイルから環境を構築できることだ。これは「Infrastructure as Code(IaC)」と呼ばれ、ChefやAnsibleなどが有名だ(気になったら調べてみよ)。ここでは、先ほど行った手順をコード化し、イメージ作成を自動化してみよう。

まず、適当なディレクトリを掘ろう。ここではdockerとするが、好きな名前にしてかまわない。

mkdir docker
cd docker

次に、Dockerfileを作成する。最初が大文字であることに注意。

vim Dockerfile

まずは以下の内容のファイルを作成せよ。

FROM ubuntu:22.04

RUN apt-get update

FROMは、元にするイメージを指定する。ここではubuntu:22.04にしよう。RUNは実行するコマンドだ。最初はパッケージのアップデートをする。

ファイルが作成できたら、docker buildによりイメージを作成しよう。

docker build -t watanabe/bastet .

-tオプションで名前を指定する。「自分の名前/bastet」にしよう。最後のピリオドを忘れないように。これはDockerfileへのパスを表す。今回はカレントディレクトリにあるので.で良い。

実行に成功すれば

Successfully built 876b1067a73b
Successfully tagged watanabe/bastet:latest

などと表示されるはずだ。イメージが出来ているか見てみよう。

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
watanabe/bastet     latest              876b1067a73b        About a minute ago   92.8MB
ubuntu              22.04               c3c304cb4f22        6 weeks ago          64.2MB

このIMAGE ID(876b1067a73b)の最初の数桁(876)も覚えておこう。

さて、先ほどはパッケージのアップデートしなかったので、bastetのインストールを追加しよう。Dockerfileを以下のように修正せよ。

FROM ubuntu:22.04

RUN apt-get update && apt-get install -y bastet

&&は、前のコマンドが成功した時にのみ次を実行するものだ。一方、;を使うと、前のコマンドの成否に関わらず次を実行する。また、apt-get -y install bastet-yオプションを忘れないこと。

ファイルを更新したら、もう一度buildを走らせよう。

docker build -t watanabe/bastet .

先ほどとは違うImage IDが表示されたはずだ。

Successfully built 6e343ebe467b
Successfully tagged watanabe/bastet:latest

イメージ一覧を見てみよう。

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
watanabe/bastet     latest              6e343ebe467b        About a minute ago   94.9MB
<none>              <none>              876b1067a73b        9 minutes ago        92.8MB
ubuntu              22.04               c3c304cb4f22        6 weeks ago          64.2MB

イメージを更新し、そちらにwatanabe/bastetという同じ名前(タグ)を付けたため、名無しのイメージ<none>が出来たことがわかる。サイズもわりと大きいので消しておこう。イメージの削除はrmiを使う。

docker rmi 876

不要なイメージが消えたはずだ。

せっかくイメージを作成したので、そこからコンテナを作ってみよう。

docker run -it watanabe/bastet

最初からbastetがインストール済みなので、そのまま実行できるはずである。

/usr/games/bastet

実行を確認したら、また仮想環境を抜けよう。

次に、先ほど作ったイメージを消してみよう。名前でもIDでもどちらでも消すことができる。

$ docker rmi watanabe/bastet
Error response from daemon: conflict: unable to remove repository reference "watanabe/bastet" (must force) - container 4716a1ed11c2 is using its referenced image 6e343ebe467b

「このイメージはコンテナ(4716a1ed11c2)が使っているから消せないよ」と文句を言われたはずだ。まずはそのコンテナを消してからイメージを消そう。

$ docker rm 471
471
$ docker rmi watanabe/bastet
Untagged: watanabe/bastet:latest
Deleted: sha256:6e343ebe467bc4d03fad86ee8ab104fa7412ba1f3a15a937aa85d62cd92c7788
Deleted: sha256:151596245487e3a389315bf4a41f5926959ee12b71865391c09cae6f1293ad92

今度は消せたはずだ。

以後、このDockerfileからイメージを作れば、間違いなくbastetが実行できる環境となる。また、この環境を作るのにどんなコマンドが必要だったかも全てファイルに残っている。まさにInfrastructure as Codeである。

最後に研究室サーバからログアウトしよう。Dockerグループから抜けるのと、サーバからログアウトするために二度exitを実行する必要がある。

ここでは研究室サーバを使ったが、もし興味があればDocker Desktopをインストールしてローカルマシンでやってみると良い。その場合はdockerグループへの所属は不要である。