= Docker = 個人的なメモなので、Dockerを勉強したい場合、ここより他のサイトを見ることをお勧めします。 == Ubuntuで最新のDockerを使う == ここみる http://www.ubuntuupdates.org/ppa/docker 最新版のDockerは、Dockerプロジェクトでパッケージを配布している。ここみるとよい http://blog.docker.com/2015/07/new-apt-and-yum-repos/ Key Serverにうまく接続できないときは、下記のようにubuntuのKey Serverを利用する。Ubuntu 14.04(trusty)の例だと下記のようになる。 {{{ # apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 58118E89F3A912897C070ADBF76221572C52609D # echo "deb https://apt.dockerproject.org/repo ubuntu-trusty main" >> /etc/apt/sources.list # apt-get update # apt-get install docker-engine }}} == 設定について == === プロキシ http_proxyやDNSの設定は、/etc/default/docker(Ubuntu) or /etc/sysconfig/docker (RHEL)でやる。http_proxyは設定しておかないとProxy環境ではdocker search/pullが使えない。 DNSをきちんと設定しておかないと、サーバプロセスが遅くなることがあるので注意 === ストレージドライバ Ubuntuでは、デフォルトのストレージドライバがaufs。overlayfsを試したい場合は、次のようにする。 {{{ /etc/default/docker DOCKER_OPTS="-s overlay" }}} 設定後dockerデーモンを再起動。 {{{ # service docker restart }}} aufsで利用していたイメージ、コンテナは全て消えるので、注意が必要。イメージの移行は下記のようにする。 {{{ # docker ps CONTAINER ID IMAGE ... 1869db53a211 mariadb ... .. # docker commit 1869db53a211 export/server1 # docker save export/server1 > export_server1.tar.gz (ドライバ変更後) # docker load < export_server1.tar.gz }}} == Dockerfile == Dockerイメージを作るファイル * COPYは使わずADDを使う。ADDの方がURLを指定したり、アーカイブを自動解凍したり高機能。 * ENTRYPOINT/CMDは引数無しで実行したときのデフォルトの実行コマンド。CMDは上書き可能でENTRYPOINTは上書きできない。 * 汎用的なイメージを作りたい場合はCMD。アプリケーションコンテナとしてユーザに勝手な操作をさせないならENTRYPOINT * ただしENTRYPOINTを利用した場合でも、ENTRYPOINTとして利用するファイルは変更可能 プロキシが必要な環境でイメージのビルドを行いたい場合、ENVコマンドを利用することにより、ビルド時の環境変数を設定することができます。 {{{ ENV http_proxy http://myproxy.server.com:8080 ENV https_proxy http://myproxy.server.com:8080 }}} == ネットワーク == DockerfileにEXPOSEを記述して、公開するポートを指定。もしくは、--expose でポートを公開。 Dockerのホスト以外からアクセスする場合は、-p <ホストのポート>:<コンテナのポート>オプションでホストのポートを使って公開。例えば、SSHのポートをホストの2022番でアクセスできるようにするには、下記のようになる。 {{{ # docker run -it --name foo --expose 22 -p 2022:22 ubuntu /bin/bash }}} === 起動済みのDockerのポートの公開 === Docker自身には機能はありません。ホスト上でiptablesを利用して直接設定してやります。例えば、上記のコンテナ上の22番をホスト上の2022番に公開するには、次のようにします。 まず、コンテナのIPアドレスを調べます。 {{{ # docker inspect コンテナ名 |grep IPAddress "IPAddress": "172.17.0.18", }}} 上記で調べたコンテナに対して、直接iptableを設定します。 {{{ # iptables -t nat -A DOCKER ! -i docker0 -p tcp -m tcp --dport 2022 -j DNAT --to-destination 172.17.0.18:22 # iptables -t filter -A DOCKER -d 172.17.0.18/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 22 -j ACCEPT }}} == イメージ初期化のChips == Tipsですね。ポテトチップスではありません。 * expect: コマンドラインでインタラクティブな設定を行う場合利用 * supervisord: Dockerではsystemdが使えないので、supervisordなどでデーモンを起動するとよい = Dockerでベンチマーク MariaDBでDockerのベンチマークを取ってみる。 == コンテナ取得、起動 {{{ # docker pull mariadb # docker run --name mariadb1 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=password -d mariadb }}} == ベンチマークツールインストール {{{ # apt-get install sysbench mariadb-client }}} == ベンチマーク準備 {{{ # mysqladmin -h 192.168.1.5 -u root --password=password create sbtest # sysbench --test=oltp --oltp-table-size=200000 --max-time=300 --max-requests=0 --mysql-host=192.168.1.5 --mysql-port=3306 --mysql-table-engine=InnoDB --mysql-user=root --mysql-password=password --mysql-engine-trx=yes --num-threads=5 prepare }}} ベンチマークをやり直し場合、mysqladmin dropでsbtestを削除してからやり直す。 == ベンチマーク実行 {{{ # sysbench --test=oltp --oltp-table-size=200000 --max-time=300 --max-requests=0 --mysql-host=192.168.1.5 --mysql-port=3306 --mysql-table-engine=InnoDB --mysql-user=root --mysql-password=password --mysql-engine-trx=yes --num-threads=5 run }}} == コンテナの再開 docker startを利用すると既存のコンテナを再開することができます。コンテナ再開時の初期化処理は、docker runで指定した環境変数はそのままに、/entrypoint.shが実行されます。 == Dockerのbashに接続 Dockerコンテナ内のbashに接続するには、docker attachを利用する。 == Dockerでサービスを利用 === systemdを利用 CentOS7のDockerイメージは、systemd-containerというパッケージがインストールされており、systemdを利用してコンテナ内のサービスを起動することができます。 CentOS7のsystemdのサービスを利用するには、下記のコマンドで/sbin/initを利用する。 {{{ # docker run --name mycon --privileged -it hoge /sbin/init }}} コンテナにbashで乗り込んでサービスを有効にする。 {{{ # docker exec -it mycon /bin/bash # service enable httpd # service mariadb # exit }}} コンテナを終了、コミットしイメージを作成 {{{ # docker stop mycon # docker commit mycon myserv }}} 作成したイメージで、/sbin/initを起動するとサービスが起動する。CMDやENTRYPOINTを利用してもよい。 {{{ # docker run --privileged myserv /sbin/init }}} === upstartを利用してサービスを起動 Ubuntuでupstartを利用してサービスを起動するサンプルを下記の場所にあります。 https://github.com/tianon/dockerfiles/tree/4d24a12b54b75b3e0904d8a285900d88d3326361/sbin-init/ubuntu/upstart/14.04 === supervisordを利用してサービスを利用 上記のsystemdを利用する方法は、特権が必要となり、あまりセキュアではありません。また、CentOSはsystemd、Ubuntuはupstartとサービスの起動方法が違っては、 OS毎の設定が面倒です。supervisordを利用すると、特権を利用せず、また、統一的な方法でdocker内でサービスを管理することができます。 {{{ # apt-get install python-setuptools # easy_install supervisor # echo_supervisord_conf > /etc/supervisord.conf }}} 上記supervisord.confにサービスの設定を記述 {{{ [supervisord] nodaemon=true [program:mariadb] command=/usr/bin/mysqld_safe autostart=true autorestart=true [program:httpd] command=/usr/local/bin/pidproxy /var/run/apache2/apache2.pid /bin/bash -c "source /etc/apache2/envvars && /usr/sbin/apache2 -DFOREGROUND" redirect_stderr=true }}} イメージをコミットして、supervisordをコンテナで起動すれば、mysqlとapacheが起動します。 {{{ # docker run image /usr/local/bin/supervisord }}} == イメージ・コンテナファイルの場所を変更 Dockerはデフォルトでは、/var/lib/dockerにコンテナやイメージファイルを格納している。別のディレクトリに保存したい場合、/var/lib/dockerをシンボリックリンクにすることが考えらえるが、シンボリックリンクではうまく動作しない。bind mountを利用するか、/etc/default/dockerに-gオプションを追加して、dockerのディレクトリを指定する必要がある。 bind mountを利用する場合、/etc/fstabに次のように記述するとよい。 {{{ /mnt/disk2/docker /var/lib/docker none defaults,bind 0 0 }}} == コミットせずにコンテナ設定を変える 基本的にコンテナの設定を変えるためには、コンテナを一度コミットして、起動し直す必要があります。 コンテナのディスクサイズが大きくなると、コミットするのにも時間がかかります。 コンテナ設定ファイルのconfig.jsonを編集することで、コンテナの設定を変更することができます。 config.jsonファイルを編集する際の注意として、dockerサービスを停止しておく必要があります。 config.jsonの内容はdockerサービス内でキャッシュされているので、停止してから編集する必要があります。 また、サービスの停止に {{{ # service docker stop }}} コンテナの設定ファイルは、/var/lib/docker/containers/コンテナID/config.jsonにあります。コンテナ実行時のコマンドを変更する場合は、下記のPathとArgsの値を変更します。 {{{ "Created":"2015-08-22T11:30:36.507268698Z","Path":"/bin/bash","Args":[],"Config": }}} 修正後、dockerサービスを開始し、コンテナをstartすると変更したコマンドでコンテナが起動されます。 ネットワークの設定は、config.jsonとhostconfig.jsonに記載されています。例えば、コンテナの80をホストの18080に設定する例(docker run --expose 18080 -p 18080:80の例) config.json {{{ "ExposedPorts":{"18080/tcp":{},"80/tcp":{}}, }}} hostconfig.json {{{ "PortBindings":{"80/tcp":[{"HostIp":"","HostPort":"18080"}]} }}} == コンテナのルートディレクトリの場所 コンテナのルートディレクトリの場所は、利用するストレージドライバ(利用するファイルシステムの実装)により異なる。 ||ストレージドライバ || 場所 || ||overlay(overlay fs) || /var/lib/docker/overlay/[コンテナID]/merged|| ||aufs || /var/lib/docker/aufs/mnt/[コンテナID]|| devicemapperの場合は、/var/lib/docker/devicemapper/devicemapper/[コンテナID]にボリューム本体とメタデータがある。コンテナ実行中であれば、/var/mapper/docker-xxxx:x-xxxxxxxxxx-[コンテナID]を利用できる。 = トラブルシューティング == パッケージがインストールできない CentOS7のコンテナ上で、下記のようなエラーメッセージと共にパッケージがインストールできないことがある(下記はhttpdの例)。 {{{ Downloading packages: httpd-2.4.6-31.el7.centos.1.x86_64.rpm | 2.7 MB 00:00:03 Running transaction check Running transaction test Transaction test succeeded Running transaction Installing : httpd-2.4.6-31.el7.centos.1.x86_64 1/1 Error unpacking rpm package httpd-2.4.6-31.el7.centos.1.x86_64 error: unpacking of archive failed on file /usr/sbin/suexec: cpio: cap_set_file Verifying : httpd-2.4.6-31.el7.centos.1.x86_64 1/1 Failed: httpd.x86_64 0:2.4.6-31.el7.centos.1 Complete! }}} Ubuntu14.04のカーネルはバージョンが古く、AUFSに機能が不足しているためエラーが発生することがある。ホストのカーネルを最新版にアップデートすることにより、解決する。 == バージョンアップ後dockerサービスが起動できない Dockerをバージョンアップ後、Dockerが起動しなくことがあります。コマンドラインから-dオプションでデーモンを起動しようとして、 次のようなメッセージが出た場合、 {{{ # docker -d Warning: '-d' is deprecated, it will be removed soon. See usage. WARN[0000] please use 'docker daemon' instead. INFO[0000] Listening for HTTP on unix (/var/run/docker.sock) FATA[0000] Error starting daemon: error initializing graphdriver: "/var/lib/docker" contains other graphdrivers: devicemapper; Please cleanup or explicitly choose storage driver (-s ) }}} /var/lib/docker/devicemapper ディレクトリを削除すると、サービスが起動するようになります。devicemapperで起動していたコンテナは削除されるので、古いバージョンに戻りexportでコンテナの移行などをしてください。 = Dockerでnetperfを使う Dockerコンテナ上でnetserverを使うと、netperfは勝手にポートを確保してlistenするのでうまく動作しない。netperfコマンドで利用するポートを固定し、コントロールポートとデータポートの両方をできるようにすると解決できる。 コンテナを起動するときに、コントロールポート(デフォルト12865)とデータポート(netperfのオプションで指定ここでは12866)を利用できるようにして起動する。 {{{ host# docker run --exporse 12865-12866 --expose 12865-12866/udp -p 12865-12866:12865-12866 -p 12865-12866:12865-12866/udp netperf /bin/bash container # netserver }}} netperfを負荷をかけたいホストから実行する。このときに、--のあとに-Pオプションでデータポートを指定する。 {{{ # netperf -H <コンテナを起動したホスト> -t TCP_STREAM -- -P 12866 }}} = Kubernates Kubernatesを動かしたメモ。ここ見た方がいいかも: https://github.com/kubernetes/kubernetes/blob/master/docs/getting-started-guides/docker.md マルチノードで利用する場合はこちら http://kubernetes.io/v1.0/docs/getting-started-guides/docker-multinode/master.html {{{ K8S_VERSION=1.1.1 docker run \ --name etcd \ -v /var/etcd:/var/etcd \ --net=host -d\ gcr.io/google_containers/etcd:2.0.12 \ /usr/local/bin/etcd \ --addr=127.0.0.1:4001 \ --bind-addr=0.0.0.0:4001 \ --data-dir=/var/etcd/data docker run \ --name=k8s_master \ --volume=/:/rootfs:ro \ --volume=/sys:/sys:ro \ --volume=/dev:/dev \ --volume=/var/lib/docker/:/var/lib/docker:ro \ --volume=/var/lib/kubelet/:/var/lib/kubelet:rw \ --volume=/var/run:/var/run:rw \ --net=host \ --pid=host \ --privileged=true \ -d \ gcr.io/google_containers/hyperkube:v${K8S_VERSION} \ /hyperkube \ kubelet \ --containerized \ --hostname-override="127.0.0.1" \ --address="0.0.0.0" \ --api-servers=http://localhost:8080 \ --config=/etc/kubernetes/manifests \ --allow-privileged=true --v=10 docker run \ --name k8s_proxy \ --net=host --privileged \ -d \ gcr.io/google_containers/hyperkube:v${K8S_VERSION} \ /hyperkube \ proxy \ --master=http://127.0.0.1:8080 --v=2 }}} {{{ # ./kubectl get nodes NAME LABELS STATUS 127.0.0.1 kubernetes.io/hostname=127.0.0.1 Ready }}} == Docker API Docker APIを利用するとRESTでコンテナ情報を取得できる。 コンテナ一覧取得 {{{ # curl -L http://localhost:2375/v1.22/containers/json }}} Swarm利用時 {{{ # curl -L http://localhost:4000/v1.22/containers/json }}} コンテナ情報取得 {{{ # curl -L http://localhost:4000/v1.22/containers//docker1.localdomain/test/top?ps_args=-auxww }}} == ホストのサブスクリプションをコンテナで利用 RHELはホストにRHELを利用すれば、コンテナはいくらでもあげられることになっています。しかしながら、普通にコンテナを あげただけでは、別途サブスクリプションの登録が必要で悲しいです。 コンテナ実行時に/etc/pkiと/etc/rhsmをマウントすることによって、コンテナでもサブスクリプションが 利用できるようになります。 {{{ # docker run -it \ -v /etc/rhsm:/run/secrets/rhsm:ro -v /etc/pki/entitlement:/run/secrets/etc-pki-entitlement:ro \ registry.access.redhat.com/rhel /bin/sh }}} == ユーザリマッピング ユーザネームスペースの機能を利用して、コンテナのユーザをホストの特定ユーザにマッピングする。 ユーザネームスペースを有効にする。 {{{ # grubby --args=user_namespace.enable=1 --update-kernel=/boot/vmlinuz-3.10.0-327.el7.x86_64 # shutdown -r now }}} {{{ # adduser dockremap # echo "dockremap:500000:65536 > /etc/subuid # echo "dockremap:500000:65536 > /etc/subgid }}} /etc/systemd/system/multi-user.target.wants/docker.service {{{ ExecStart=/usr/bin/dockerd --userns-remap=default -D -H fd:// }}} {{{ # systemctl daemon-reload # systemctl restart docker.serivces }}} = MySQL Galera Clusterを利用 SwarmモードでDockerを起動しておく。内部で通信するinternalネットワークをoverlayモードで作成しておき、 次のようにする。 {{{ # docker service create --name etcd --replicas 1 --network internal elcolio/etcd:latest -name etcd # docker service create --name mysql-galera --replicas 3 -p 3306:3306 --network internal \ --env MYSQL_ROOT_PASSWORD=mypassword --env DISCOVERY_SERVICE=etcd:2379 --env XTRABACKUP_PASSWORD=mypassword --env CLUSTER_NAME=galera \ perconalab/percona-xtradb-cluster:5.6 }}} == BADノウハウ docker 1.10でoverlayネットワークを利用するときは、カーネルパラメータにipv6.disable=1を設定しているとブリッジが作成できず、docker daemonが起動しない。