2016/01/03

FreeBSDでDockerを試す

気づくと FreeBSD でも Docker が動作するようですので、紹介記事をなぞって試したときのメモです。

はじめに

FreeBSD での Docker は exec ドライバに jail、ストレージドライバに ZFS を使う実装のようです。

ここでは仮想マシンイメージを使って上記記事を参考に Docker on FreeBSD を試してみます。

Docker on FreeBSD 11.0-CURRENT

検証用のVMを準備(KVM)

11.0-CURRENT を準備するのが少し手間と感じたので公開されている仮想マシンイメージを KVM で動かします。

ここでは国内のミラーサイト(JAIST)から qcow2 イメージを取得します。 以降の手順を簡略化するため KVM ドメインとディスクイメージのパスを変数に設定します。
# DOMNAME=freebsd11current
# DISKIMAGE=/var/lib/libvirt/images/FreeBSD-11.0-CURRENT-amd64-20151229-r292858.qcow2
# curl -s http://ftp.jaist.ac.jp/pub/FreeBSD/snapshots/VM-IMAGES/11.0-CURRENT/amd64/20151229/FreeBSD-11.0-CURRENT-amd64-20151229-r292858.qcow2.xz | unxz -v > $DISKIMAGE
# qemu-img info $DISKIMAGE
image: /var/lib/libvirt/images/FreeBSD-11.0-CURRENT-amd64-20151229-r292858.qcow2
file format: qcow2
virtual size: 21G (22548643840 bytes)
disk size: 1.3G
cluster_size: 65536
Format specific information:
    compat: 0.10
以下のドメイン定義で仮想マシンを定義します。
  • CPU は 1つ
  • メモリは 1GB
  • ネットワークはデフォルト
  • グラフィックは VNC
  • シリアルポート有り
# virsh define /dev/stdin <<EOF
<domain type='kvm'>
  <name>${DOMNAME}</name>
  <memory unit='KiB'>1048576</memory>
  <vcpu placement='static'>1</vcpu>
  <os>
    <type arch='x86_64'>hvm</type>
    <boot dev='hd'/>
  </os>
  <features>
    <acpi/>
    <apic/>
    <pae/>
  </features>
  <devices>
    <emulator>/usr/bin/kvm</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <source file='${DISKIMAGE}'/>
      <target dev='vda' bus='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
    </disk>
    <controller type='pci' index='0' model='pci-root'/>
    <controller type='virtio-serial' index='0'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
    </controller>
    <interface type='network'>
      <source network='default'/>
      <model type='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>
    <serial type='pty'>
      <target port='0'/>
    </serial>
    <console type='pty'>
      <target type='serial' port='0'/>
    </console>
    <input type='mouse' bus='ps2'/>
    <input type='keyboard' bus='ps2'/>
    <graphics type='vnc' port='-1' autoport='yes' listen='0.0.0.0'>
      <listen type='address' address='0.0.0.0'/>
    </graphics>
    <video>
      <model type='cirrus' vram='9216' heads='1'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </video>
    <memballoon model='virtio'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
    </memballoon>
  </devices>
</domain>
EOF
仮想マシンを起動して virt-manager や virt-viewer、VNC などでコンソールに接続します。
# virsh start ${DOMNAME}

FreeBSD の基本的な設定

ネットワーク経由で作業した方が効率がよいのでコンソールから root でログインして基本的な設定を行います。なお root のパスワードは空です。

ネットワークを設定

試す環境に合わせて適当に変更してください。

# tee -a /etc/rc.conf.local <<EOF
hostname="your.host.name"
ifconfig_vtnet0="inet 192.168.122.xxx/24"
defaultrouter="192.168.122.1"
EOF
# tee -a /etc/resolv.conf <<EOF
nameserver 192.168.122.1
EOF
設定後ネットワークインターフェースを再起動して疎通できることを確認します。
# service netif restart
# service routing restart
# host www.google.com
www.google.com has address 216.58.220.228
www.google.com has IPv6 address 2404:6800:4004:810::1011

タイムゾーンの設定

必須ではありませんが JST にしておいた方が楽です。

# cp -p /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

シリアルコンソールの設定

仮想マシンではシリアルコンソールが使えた方が何かと便利なので VGA とシリアルコンソールの両方を有効にします。

# tee -a /boot/loader.conf <<EOF
boot_multicons="YES"
console="comconsole,vidconsole"
EOF

作業ユーザの追加

手軽に root に substitute できるように wheel 補助グループに追加しておきます。

# pw user add -n username -m -G wheel
# passwd username

sshd サービスの有効化

最後に ssh の起動設定をして、一度 OS を再起動します。

# sysrc -f /etc/rc.conf.d/sshd sshd_enable=YES
# reboot

ZFS ファイルシステムの作成

4GB のファイルを用いて ZFS ファイルシステムを作成します。

# kldload zfs

# dd if=/dev/zero of=/usr/local/dockerfs bs=1024K count=4000

# zpool create -f zroot /usr/local/dockerfs

# zfs create -o mountpoint=/usr/docker zroot/docker

# sysrc zfs_enable=YES

Docker パッケージをインストール

pkg コマンドでインストールします。少し長いですが出力を全て貼ります。

# pkg install docker-freebsd ca_root_nss

The package management tool is not yet installed on your system.
Do you want to fetch and install it now? [y/N]: y
Bootstrapping pkg from pkg+http://pkg.FreeBSD.org/FreeBSD:11:amd64/latest, please wait...
Verifying signature with trusted certificate pkg.freebsd.org.2013102301... done
Installing pkg-1.6.2...
Extracting pkg-1.6.2: 100%
Message from pkg-1.6.2:
If you are upgrading from the old package format, first run:

  # pkg2ng
Updating FreeBSD repository catalogue...
Fetching meta.txz: 100%    944 B   0.9kB/s    00:01
Fetching packagesite.txz: 100%    5 MiB   2.8MB/s    00:02
Processing entries: 100%
FreeBSD repository update completed. 24572 packages processed.
Updating database digests format: 100%
The following 8 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
        docker-freebsd: 20150625
        ca_root_nss: 3.20.1
        bash: 4.3.42_1
        indexinfo: 0.2.4
        gettext-runtime: 0.19.6
        go: 1.5.1,1
        sqlite3: 3.9.2
        readline: 6.3.8

The process will require 269 MiB more space.
42 MiB to be downloaded.

Proceed with this action? [y/N]: y
Fetching docker-freebsd-20150625.txz: 100%    3 MiB   2.9MB/s    00:01
Fetching ca_root_nss-3.20.1.txz: 100%  334 KiB 341.8kB/s    00:01
Fetching bash-4.3.42_1.txz: 100%    1 MiB   1.3MB/s    00:01
Fetching indexinfo-0.2.4.txz: 100%    5 KiB   5.1kB/s    00:01
Fetching gettext-runtime-0.19.6.txz: 100%  146 KiB 149.3kB/s    00:01
Fetching go-1.5.1,1.txz: 100%   37 MiB   3.0MB/s    00:13
Fetching sqlite3-3.9.2.txz: 100%  604 KiB 618.0kB/s    00:01
Fetching readline-6.3.8.txz: 100%  317 KiB 324.8kB/s    00:01
Checking integrity... done (0 conflicting)
[1/8] Installing indexinfo-0.2.4...
[1/8] Extracting indexinfo-0.2.4: 100%
[2/8] Installing gettext-runtime-0.19.6...
[2/8] Extracting gettext-runtime-0.19.6: 100%
[3/8] Installing readline-6.3.8...
[3/8] Extracting readline-6.3.8: 100%
[4/8] Installing bash-4.3.42_1...
[4/8] Extracting bash-4.3.42_1: 100%
[5/8] Installing go-1.5.1,1...
[5/8] Extracting go-1.5.1,1: 100%
[6/8] Installing sqlite3-3.9.2...
[6/8] Extracting sqlite3-3.9.2: 100%
[7/8] Installing docker-freebsd-20150625...
[7/8] Extracting docker-freebsd-20150625: 100%
[8/8] Installing ca_root_nss-3.20.1...
[8/8] Extracting ca_root_nss-3.20.1: 100%
Message from bash-4.3.42_1:
======================================================================

bash requires fdescfs(5) mounted on /dev/fd

If you have not done it yet, please do the following:

        mount -t fdescfs fdesc /dev/fd

To make it permanent, you need the following lines in /etc/fstab:

        fdesc   /dev/fd         fdescfs         rw      0       0

======================================================================
Message from docker-freebsd-20150625:
Docker requires a bit of setup before usage.

You will need to create a ZFS dataset on /usr/docker

# zfs create -o mountpoint=/usr/docker <zroot>/docker

And lastly enable the docker daemon
# sysrc -f /etc/rc.conf docker_enable="YES"
# service docker start

(WARNING)

Starting the docker service will also add the following PF rule:

nat on ${iface} from 172.17.0.0/16 to any -> (${iface})

Where $iface is the default NIC on the system, or the value
of $docker_nat_iface. This is for network connectivity to docker
containers in this early port. This should not be needed in future
versions of docker.
Message from ca_root_nss-3.20.1:
********************************* WARNING *********************************

FreeBSD does not, and can not warrant that the certification authorities
whose certificates are included in this package have in any way been
audited for trustworthiness or RFC 3647 compliance.

Assessment and verification of trust is the complete responsibility of the
system administrator.

*********************************** NOTE **********************************

This package installs symlinks to support root certificates discovery by
default for software that uses OpenSSL.

This enables SSL Certificate Verification by client software without manual
intervention.

If you prefer to do this manually, replace the following symlinks with
either an empty file or your site-local certificate bundle.

  * /etc/ssl/cert.pem
  * /usr/local/etc/ssl/cert.pem
  * /usr/local/openssl/cert.pem

***************************************************************************
docker サービスの起動設定と bash 用に fdesc のマウント設定とマウントを行います。
# sysrc -f /etc/rc.conf.d/docker docker_enable=YES

# tee -a /etc/fstab <<EOF
fdesc   /dev/fd         fdescfs         rw      0       0
EOF

# mount /dev/fd

Docker を起動

docker を起動してバージョンを確認してみます。

# service docker start
# docker version
Client version: 1.7.0-dev
Client API version: 1.19
Go version (client): go1.5.1
Git commit (client): 582db78
OS/Arch (client): freebsd/amd64
Server version: 1.7.0-dev
Server API version: 1.19
Go version (server): go1.5.1
Git commit (server): 582db78
OS/Arch (server): freebsd/amd64
実行例にあるとおり CentOS のコンテナを起動してみます。
# docker run -it centos /bin/bash
Unable to find image 'centos:latest' locally
latest: Pulling from centos
47d44cb6f252: Pull complete
838c1c5c4f83: Pull complete
5764f0a31317: Pull complete
60e65a8e4030: Pull complete
centos:latest: The image you are pulling has been verified. Important: image verification is a tech preview feature and should not be relied on to provide security.
Digest: sha256:8072bc7c66c3d5b633c3fddfc2bf12d5b4c2623f7004d9eed6aae70e0e99fbd7
Status: Downloaded newer image for centos:latest
[root@ /]#
uname コマンドの出力に戸惑いを感じつつも、HOSTNAME 変数がプロンプトに表示されないなど、やはり勝手が違います。
[root@ /]# uname -a
Linux  2.6.32 FreeBSD 11.0-CURRENT #0 r292858: Tue Dec 29 07:03:17 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

[root@ /]# df
Filesystem                                                                    1K-blocks  Used Available Use% Mounted on
zroot/docker/8052feb0fd5bf47da982b1175f976f02368895e76826866680a52b3b9a5e9fa8         0     0         0   6% /

[root@ /]# echo $HOSTNAME
8052feb0fd5b

[root@ /]# echo $PS1
[\u@\h \W]\$

[root@ /]# dmesg
dmesg: read kernel buffer failed: Function not implemented
つづいてホスト側から。コンテナ ID で zfs ファイルシステムが作られ、そこが jail のパスになっています。
# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
8052feb0fd5b        centos              "/bin/bash"         3 seconds ago       Up 2 seconds                            furious_jang

# jls
   JID  IP Address      Hostname                      Path
     1  172.17.0.1                                    /usr/docker/zfs/graph/8052feb0fd5b

# zfs list
NAME                                                                                 USED  AVAIL  REFER  MOUNTPOINT
zroot                                                                                219M  3.54G    19K  /zroot
zroot/docker                                                                         219M  3.54G  12.0M  /usr/docker
zroot/docker/47d44cb6f252ea4f6aecf8a447972de5d9f9f2e2bec549a2f1d8f92557f4d05a         19K  3.54G    19K  legacy
zroot/docker/5764f0a3131791360948d70cc2714226a1ec786675d27e09348abd4adecb03ea         29K  3.54G   206M  legacy
zroot/docker/60e65a8e4030022260a4f84166814b2683e1cdfc9725a9c262e90ba9c5ae2332         29K  3.54G   206M  legacy
zroot/docker/8052feb0fd5bf47da982b1175f976f02368895e76826866680a52b3b9a5e9fa8        157K  3.54G   206M  legacy
zroot/docker/8052feb0fd5bf47da982b1175f976f02368895e76826866680a52b3b9a5e9fa8-init    52K  3.54G   206M  legacy
zroot/docker/838c1c5c4f833fda62e928de401303d293d23d52c831407b12edd95ca3f1839e        206M  3.54G   206M  legacy

# df
Filesystem                                                                    1K-blocks    Used    Avail Capacity  Mounted on
/dev/gpt/rootfs                                                                20307196 5853144 12829480    31%    /
devfs                                                                                 1       1        0   100%    /dev
fdescfs                                                                               1       1        0   100%    /dev/fd
zroot/docker                                                                    3724310   12257  3712053     0%    /usr/docker
zroot                                                                           3712072      19  3712053     0%    /zroot
zroot/docker/8052feb0fd5bf47da982b1175f976f02368895e76826866680a52b3b9a5e9fa8   3923446  211393  3712053     5%    /usr/docker/zfs/graph/8052feb0fd5b
linprocfs                                                                             4       4        0   100%    /usr/docker/zfs/graph/8052feb0fd5b/proc
linsysfs                                                                              4       4        0   100%    /usr/docker/zfs/graph/8052feb0fd5b/sys
devfs                                                                                 1       1        0   100%    /usr/docker/zfs/graph/8052feb0fd5b/dev

Docker on Docker

--dns オプションが効かないようなので手動で resolv.conf を編集して docker パッケージをインストールして起動してみましたがそこで固まってしまいました。

[root@ /]# tee -a /etc/resolv.conf <<EOF
nameserver 192.168.122.1
EOF

[root@ /]# yum install -y docker
...

[root@ /]# # /usr/bin/docker daemon 
WARN[0000] You are running linux kernel version 2.6.32, which might be unstable running docker. Please upgrade your kernel to 3.10.0.
INFO[0000] Listening for HTTP on unix (/var/run/docker.sock)

exec サブコマンドのエラー

起動している Linux コンテナに docker exec するとデーモンごと落ちてしまいました。FreeBSD コンテナ(lexaguskov/freebsd)でもダメでした。

info サブコマンドのエラー

docker info もエラーとなります。/var/log/docker.log を確認すると Linux と違ってファイルディスクリプタが参照できないからのようですね。

# docker info
Get http://%2Fvar%2Frun%2Fdocker.sock/v1.19/info: EOF. Are you trying to connect to a TLS-enabled daemon without TLS?
level=debug msg="Calling GET /info"
level=info msg="GET /v1.19/info"
level=error msg="Could not determine if daemon is containerized: Unable to check if we are in container"
level=error msg="Could not read system memory info: platform and architecture is not supported"
level=debug msg="[zfs] zpool get all -p zroot"
level=error msg="Error opening /proc/651/fd: open /proc/651/fd: no such file or directory"
http: panic serving : runtime error: invalid memory address or nil pointer dereference
goroutine 35 [running]:
net/http.(*conn).serve.func1(0xc8202fbc30, 0x80176ef28, 0xc820023078)
        /usr/local/go/src/net/http/server.go:1287 +0xb5
github.com/docker/docker/daemon.(*Daemon).SystemInfo(0xc8200e7790, 0xc36eb0, 0x0, 0x0)
        /wrkdirs/usr/ports/sysutils/docker-freebsd/work/docker-582db78/.gopath/src/github.com/docker/docker/daemon/info.go:85 +0xbf4
github.com/docker/docker/api/server.(*Server).getInfo(0xc8201be180, 0xc820473a06, 0x4, 0x80176f0a8, 0xc8202fbce0, 0xc82046ee00, 0xc8204aa510, 0x0, 0x0)
        /wrkdirs/usr/ports/sysutils/docker-freebsd/work/docker-582db78/.gopath/src/github.com/docker/docker/api/server/server.go:363 +0x89
github.com/docker/docker/api/server.(*Server).(github.com/docker/docker/api/server.getInfo)-fm(0xc820473a06, 0x4, 0x80176f0a8, 0xc8202fbce0, 0xc82046ee00, 0xc8204aa510, 0x0, 0x0)
        /wrkdirs/usr/ports/sysutils/docker-freebsd/work/docker-582db78/.gopath/src/github.com/docker/docker/api/server/server.go:1450 +0x74
github.com/docker/docker/api/server.makeHttpHandler.func1(0x80176f0a8, 0xc8202fbce0, 0xc82046ee00)
        /wrkdirs/usr/ports/sysutils/docker-freebsd/work/docker-582db78/.gopath/src/github.com/docker/docker/api/server/server.go:1433 +0xa15
net/http.HandlerFunc.ServeHTTP(0xc82021f2c0, 0x80176f0a8, 0xc8202fbce0, 0xc82046ee00)
        /usr/local/go/src/net/http/server.go:1422 +0x3a
github.com/gorilla/mux.(*Router).ServeHTTP(0xc8201c2500, 0x80176f0a8, 0xc8202fbce0, 0xc82046ee00)
        /wrkdirs/usr/ports/sysutils/docker-freebsd/work/docker-582db78/vendor/src/github.com/gorilla/mux/mux.go:98 +0x29e
net/http.serverHandler.ServeHTTP(0xc8203193e0, 0x80176f0a8, 0xc8202fbce0, 0xc82046ee00)
        /usr/local/go/src/net/http/server.go:1862 +0x19e
net/http.(*conn).serve(0xc8202fbc30)
        /usr/local/go/src/net/http/server.go:1361 +0xbee
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:1910 +0x3f6
# mount -t procfs proc /proc

# ls -l /proc/651
total 0
-r--r--r--  1 root  wheel  0 Jan  3 18:49 cmdline
--w-------  1 root  wheel  0 Jan  3 18:49 ctl
-rw-------  1 root  wheel  0 Jan  3 18:49 dbregs
-r--r--r--  1 root  wheel  0 Jan  3 18:49 etype
lr--r--r--  1 root  wheel  0 Jan  3 18:49 file -> /usr/local/bin/docker
-rw-------  1 root  wheel  0 Jan  3 18:49 fpregs
-r--r--r--  1 root  wheel  0 Jan  3 18:49 map
-rw-------  1 root  wheel  0 Jan  3 18:49 mem
--w-------  1 root  wheel  0 Jan  3 18:49 note
--w-------  1 root  wheel  0 Jan  3 18:49 notepg
-rw-------  1 root  wheel  0 Jan  3 18:49 osrel
-rw-------  1 root  wheel  0 Jan  3 18:49 regs
-r--r--r--  1 root  wheel  0 Jan  3 18:49 rlimit
-r--r--r--  1 root  wheel  0 Jan  3 18:49 status

Docker on FreeBSD 10.2-RELEASE

docker-freebsd パッケージは 10.2-RELEASE でも利用できます。ちょうど ZFS 環境があるので試してみました。

# pkg info docker-freebsd
docker-freebsd-20150625
Name           : docker-freebsd
Version        : 20150625
Installed on   : Tue Dec 29 00:25:04 2015 JST
Origin         : sysutils/docker-freebsd
Architecture   : freebsd:10:x86:64
Prefix         : /usr/local
Categories     : sysutils
Licenses       : APACHE20
Maintainer     : kmoore@FreeBSD.org
WWW            : https://github.com/kvasdopil/docker
Comment        : Docker containment system
Annotations    :
        repo_type      : binary
        repository     : FreeBSD
Flat size      : 11.8MiB
Description    :
Docker is an open source project to pack, ship and run any
application as a lightweight container.

Docker containers are both hardware-agnostic and platform-agnostic.
This means they can run anywhere, from your laptop to the largest
EC2 compute instance and everything in between - and they don't
require you to use a particular language, framework or packaging
system. That makes them great building blocks for deploying and
scaling web apps, databases, and backend services without depending
on a particular stack or provider.

WWW: https://github.com/kvasdopil/docker
# docker version
Client version: 1.7.0-dev
Client API version: 1.19
Go version (client): go1.5.1
Git commit (client): 582db78
OS/Arch (client): freebsd/amd64
Server version: 1.7.0-dev
Server API version: 1.19
Go version (server): go1.5.1
Git commit (server): 582db78
OS/Arch (server): freebsd/amd64
Linux コンテナの場合 /bin/bash が無かったり ABI が違うのかエラーになってしまいます。
# docker run -it centos /bin/bash
ELF binary type "0" not known.
ELF binary type "0" not known.
jail: exec /bin/bash: Exec format error
jail: /bin/bash: failed

# docker run -it elasticsearch /bin/bash
ELF binary type "0" not known.
ELF binary type "0" not known.
jail: exec /docker-entrypoint.sh: Exec format error
jail: /docker-entrypoint.sh /bin/bash: failed
FreeBSD コンテナは動きました。
# docker run -it lexaguskov/freebsd /bin/csh
# uname -a
FreeBSD  10.2-RELEASE-p7 FreeBSD 10.2-RELEASE-p7 #0: Mon Nov  2 14:19:39 UTC 2015     root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC  amd64
docker exec するとデーモンごと落ちるのは一緒でした(そもそも 10.2 は対象外ですが)。

おわりに

開発中の FreeBSD で Docker が動かせるようになったという記事を見つけたので試してみましたが、まだまだ実装されていないところが多く不安定ですね。Docker Hub に多数ある Linux コンテナ資産の利用を目的と考えると、Linux 互換レイヤの開発が重要になるのでしょうね。また FreeBSD コンテナが満足に動くようになると、jail 実行管理ツールの最有力候補になるかも知れません。

0 件のコメント:

コメントを投稿