Linux: Dockerの使い方

Dockerの使い方を記載します。

2 イメージとコンテナ

イメージとはDockefileという定義ファイルから生成される不変のルートファイルシステムです。イメージは実行時に使用されません。

コンテナとはイメージから作成される可変のルートファイルシステムです。コンテナは実行時に使用されます。

例えば以下のコマンドを実行すると以下の通りになります。

$ docker run hello-world
<snip>
Hello from Docker!
<snip>
  • hello-worldというイメージをリモートサーバからダウンロードします。
  • ランダムな名前のコンテナが生成されます。
  • DockerfileのCMDで指定されたhelloというバイナリが"Hello from Docker!"の文字列を出力します。

helloというバイナリをホストマシンで実行すると同様の出力を得ます。ただし、コンテナ内で実行していないので環境は全く異なります。

$ sudo /var/lib/docker/aufs/diff/<hash>/hello
<snip>
Hello from Docker!
<snip>

3 イメージをダウンロードしてコンテナ上でコマンドを実行する

docker runで使う方法とdocker pull, docker create, docker startを使う方法があります。

3.1 docker run

以下のコマンドを実行すると、<image>という名前のイメージがダウンロードされ、<container>という名前のコンテナ上で<cmd>で指定したコマンドが実行されます。

$ docker run -it --name <container> <image> <cmd>
  • –name <container>を省略するとランダムな名前が生成されます。
  • <cmd>を省略するとDockerfileのCMDで指定したコマンドが設定されます。
  • すでに存在する<container>を指定した場合はエラーとなります。
  • <container>と<image>は名前でなくIDで指定することもできます。

上記のdocker runは以下のコマンド郡と同等です。なお、docker pullを省略した場合、ローカルに<image>がない場合はdocker create時にリモートサーバからダウンロードします。

$ docker pull <image>
$ docker create -it --name <container> <image> <cmd>
$ docker start -i <container>

3.2 docker pull

docker pullはイメージをローカルにダウンロードするコマンドです。イメージはRegistryと呼ばれるリモートサーバからダウンロードされます。デフォルトのRegistryはDocker Hubです。

docker createはローカルからイメージを探すので、あらかじめ使う予定のあるイメージはダウンロードしておくと良いでしょう。

また、ローカルでRegistryを作成する場合、デフォルトのRegistryからイメージをダウンロードしておき、ダウンロードしたイメージをローカルのRegistryへdocker pushすることができます。それ以降のそのイメージはローカルのRegistryからダウンロードすることができます。

3.3 docker create -it

docker createはイメージからコンテナを作成するコマンドです。ローカルに存在しないイメージはRegistryからダウンロードされます。

-itオプションの両方がない場合はbashは即座に終了する為、コンテナも停止します。

$ docker create --name bash-without-it ubuntu:16.04
$ docker start -i bash-without-it
$ # This is host machine's shell prompt.
$ docker attach bash-without-it
You cannot attach to a stopped container, start it first

-iオプションがない場合は標準入力を受け付けません。

$ docker create -t --name bash-without-i ubuntu:16.04
$ docker start -i bash-without-i
root@35859c489ea1:/# ls # Type ls[RET] but no response

-tオプションがない場合はpseudo-ttyが作成されません。bashの場合は環境変数TERMが空になり、プロンプト文字列が表示されません。

$ docker create -i --name bash-without-t ubuntu:16.04
$ docker start -i bash-without-t
uname # Type uname[RET]
Linux
ls    # Type ls[RET]
bin
boot
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

-itオプションの両方がある場合は通常の動作となります。

$ docker create -it --name bash ubuntu:16.04
$ docker start -i bash
root@f5fbe8daa835:/# uname
Linux
root@f5fbe8daa835:/# ls
bin   dev  home  lib64  mnt  proc  run   srv  tmp  var
boot  etc  lib   media  opt  root  sbin  sys  usr

3.4 docker start -i

docker startはコンテナを動かすコマンドです。

-iオプションをつけることで、コンテナを開始すると同時にコンテナへアタッチします。標準入力へも接続されます。

$ docker start -i <container>

上記は以下とほぼ同等ですが、以下の場合はstartとattachの間にホストマシンへ一度戻ります。

$ docker start <container>
$ docker atttach <container>

-iオプションに似た-aオプションもあります。-aオプションをつけることで、コンテナを開始すると同時にコンテナへアタッチします。ただし、標準入力へは接続されません。

$ docker start -i <container>

上記は以下とほぼ同等ですが、先ほどと同様に、以下の場合はstartとattachの間にホストマシンへ一度戻ります。

$ docker start <container>
$ docker atttach --no-stdin <container>

4 独自のイメージを作成する

ここではubuntu:16.04をベースとしてemacsをインストールしたイメージを作成します。

4.1 コンテナから独自のイメージを作成する

最初にイメージからコンテナを作成します。

$ docker run -it --name ubuntu-1604-emacs ubuntu:16.04

ubuntu:16.04のイメージはemacsがインストールされていません。

root@cf4e53146385:/# emacs --version
bash: emacs: command not found

emacsをインストールした後、bashを終了させ、コンテナを停止します。

root@cf4e53146385:/# apt update -y && apt install -y emacs && exit

docker commitでコンテナからイメージを作成します。

$ docker commit ubuntu-1604-emacs ubuntu-1604-emacs-image

イメージが作成されました。

$ docker images
REPOSITORY              TAG    IMAGE ID     CREATED            SIZE
ubuntu-1604-emacs-image latest 41716956f654 About a minute ago 546 MB
ubuntu                  16.04  f49eec89601e 3 weeks ago        129 MB

作成したイメージからコンテナを作成します。

$ docker run -it ubuntu-1604-emacs-image

作成したイメージはemacsがインストールされています。

root@b91c82c0c976:/# emacs --version
GNU Emacs 24.5.1
Copyright (C) 2015 Free Software Foundation, Inc.
GNU Emacs comes with ABSOLUTELY NO WARRANTY.
You may redistribute copies of Emacs
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING.

4.2 Dockerfileから独自のイメージを作成する

以下のDockerfileを作成します。

$ cat Dockerfile
FROM ubuntu:16.04

RUN \
  apt update -y && \
  apt install -y emacs

CMD ["bash"]

docker buildでDockerfileからイメージを作成します。Dockerfileで作成した場合も一時的なコンテナが作成されます。

$ docker build -t ubuntu-1604-emacs-dockerfile .
Sending build context to Docker daemon 2.048 kB
Step 1/3 : FROM ubuntu:16.04
 ---> f49eec89601e
Step 2/3 : RUN apt update -y &&   apt install -y emacs
 ---> Running in d7a592031026

WARNING: apt does not have a stable CLI interface. Use with caution in
scripts.

Get:1 http://archive.ubuntu.com/ubuntu xenial InRelease [247 kB]
Get:2 http://archive.ubuntu.com/ubuntu xenial-updates InRelease [102 kB]
Get:3 http://archive.ubuntu.com/ubuntu xenial-security InRelease [102 kB]
<snip>
Step 3/3 : CMD bash
 ---> Running in 77adc54aa247
 ---> bcf7de949838
Removing intermediate container 77adc54aa247
Successfully built bcf7de949838

イメージが作成されました。

$ docker images
REPOSITORY                    TAG     IMAGE ID      CREATED         SIZE
ubuntu-1604-emacs-dockerfile  latest  bcf7de949838  36 seconds ago  546 MB
ubuntu-1604-emacs-image       latest  41716956f654  34 minutes ago  546 MB
ubuntu                        16.04   f49eec89601e  3 weeks ago     129 MB

作成したイメージからコンテナを作成します。

$ docker run -it ubuntu-1604-emacs-dockerfile

作成したイメージはemacsがインストールされています。

root@6ac693d1b24a:/# emacs --version
GNU Emacs 24.5.1
Copyright (C) 2015 Free Software Foundation, Inc.
GNU Emacs comes with ABSOLUTELY NO WARRANTY.
You may redistribute copies of Emacs
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING.

5 外部ネットワークからアクセスする

ここではコンテナ内で動かしたJenkinsへ外部ネットワークからアクセスします。Jenkinsが使用するポートはTCP8080です。

dockerのデフォルトで用意されているネットワークは以下の通りです。なおdocker runやdocker createで–networkオプションを省略した場合はbridgeが指定されます。

bridge docker0というbridgeを作成して、ホストマシンのNICと
  iptablesによるIPマスカレードで接続します(L3レイヤで接続)。
  外部からアクセスするにはポートフォワーディングが必要です。
host 見かけ上ホストマシンのNICをそのまま使います。
  外部からはアクセスできません。
none NICを作成しません。

本記事のネットワークインターフェースは以下の通りです。

eth0 ホストマシンのNICです。IPアドレスは192.168.11.102/24です。
docker0 docker起動時に作成されるbridgeです。
  bridgeネットワークが172.17.0.1/16のIPアドレスを割り当てます。

5.1 bridgeネットワークでポートフォワーディングを使う

ホストマシンのTCP80をコンテナのTCP8080へマッピングします。–networkオプションを省略しているのでbridgeネットワークが使われます。

$ docker run -d -p 80:8080 jenkins

ホストマシンのTCP80にHTTP接続するとJenkinsの画面が表示されます。

http://192.168.11.102

0001_bridge-network.png

5.2 独自ネットワークで外部ネットワークと同じネットワークアドレスを用いる

docker0のbridgeとは別に、L2レイヤで接続するbridgeを作成します。

作成したネットワークインターフェースは以下の通りです。

br0 dockerとは無関係で作成したbridgeです。
  eth0の代わりに192.168.11.102/24が割り当てられています。

docker network createでbr0を持つネットワークを作成します。

$ docker network create \
       --driver=bridge \
       --subnet=192.168.11.102/24 \
       --gateway=192.168.11.102 \
       -o "com.docker.network.bridge.enable_icc=true" \
       -o "com.docker.network.bridge.enable_ip_masquerade=false" \
       -o "com.docker.network.bridge.host_binding_ipv4=0.0.0.0" \
       -o "com.docker.network.bridge.name=br0" \
       -o "com.docker.network.driver.mtu=1500" \
       br0_network

ネットワークをbr0_network、IPアドレスを192.168.11.200、DNSを192.168.11.1とするコンテナを作成します。ここで指定したDNSはdockerに組み込まれたDNSサーバ(127.0.0.11)が参照します。見かけ上は/etc/resolv.confに反映されない点に注意してください。

$ docker run -d --network=br0_network --ip=192.168.11.200 \
--dns=192.168.11.1 jenkins

コンテナのTCP8080にHTTP接続するとJenkinsの画面が表示されます。

http://192.168.11.200:8080

0002_user-defined-network.png

5.3 独自ネットワークの注意点

外部のDHCPサーバからIPアドレスをもらうIPAMドライバないようで、Dockerとは別に、コンテナのMACアドレスに対するDHCPの応答処理を追加する必要があります(あるいはDHCPサーバのdhcpd.confに直接書く)。

IPマスカレイドをfalseにしてもL3レイヤの設定が実行されます。この影響なのか、bridgeネットワークが動作しなくなります。docker buildでイメージを作成する際、コンテナにIPアドレスをわざわざ割り振りらないようにするには–network=hostを使う必要があります。

また、組み込まれたDNSサーバは複数の–dnsオプションを指定した場合、ひとつ目のDNSサーバが問い合わせをREFUSEした場合は、ふたつ目のDNSサーバに問い合わせを実行しないようです(DROPやREJECTなら問題ありません)。これを回避するにはひとつ目のDNSサーバにて、名前解決できない場合はREFUSEせずに再帰問い合わせを実行するしかないです。Windows, Linux, MacOSではふたつ目のDNSサーバに問い合わせするので、この動作が正しいのかどうかはわかりません。

6 その他のコマンド

docker <arg>はdocker image <arg>やdocker container <arg>のエイリアスであったりします。ここではdocker <arg>の方のみを扱います。

docker images イメージの一覧を表示する
docker rmi <image> イメージを削除する
docker ps [-a] コンテナの一覧を表示する
  (-aをつけた場合は停止したコンテナも)
docker stop <container> コンテナを停止する
docker exec <container> <cmd> 起動中のコンテナで別のコマンドを実行する

docker ps -qを実行するとIDのみが表示されます。起動中のコンテナをすべて止めるには以下のコマンドを実行します。

$ docker stop $(docker ps -q)