dockerのAmbassadorパターンを理解する
前回と前々回で「単一のコンテナの起動」と、「2台のコンテナの起動と接続」について、ある程度理解した。 今回は2台のホスト(VM)にまたがるコンテナの接続について試す。 2台のホストにまたがる場合は、--linkによる接続はできない。これはひとつのホストにのっているDockerの中でのみ使える機能だからである。
まず定石はAmbassadorパターンというものらしい。 他のホストとの接続だけを担うプロキシ機能しか持たないコンテナで軽量なものらしい。 ほかにも、いろいろあるらしいが、ひとまず定石であるAmbassadorパターンを理解しよう。
ちゃんとした例を考えるのが面倒くさいので、 今回も前回に引き続きhttpdとclientを例に使う。
構成は以下
ホスト | コンテナ名 | 役割 | expose/publishするポート | リンク |
---|---|---|---|---|
VM1 | httpd | apacheサーバ | 80 | なし |
httpd-amb | ambassador | 8080(publish) | httpdコンテナにリンク | |
VM2 | httpdclient | クライアント | なし | httpdclient-ambコンテナにリンク |
httpd-amb | ambassador | 80(expose) | なし |
ホスト | IP |
---|---|
VM1 | 192.168.11.11 |
VM2 | 192.168.11.12 |
構成図
VM1[ httpdclient --- 80/tcp ---> httpd-amb ] --- 8080/tcp --> VM2[ httpd-amb -- 80/tcp --> httpd]
VM1: apacheサーバ+ambassadorを構築する
apacheサーバコンテナ作成する
# docker run --privileged -d --expose 80 --name httpd centos:centos7 /sbin/init
# docker exec -it httpd /bin/bash [root@a4522c59ed0c /]# [root@a4522c59ed0c /]# yum install httpd -y [root@a4522c59ed0c /]# systemctl enable httpd.service [root@a4522c59ed0c /]# systemctl start httpd.service [root@a4522c59ed0c /]# exit
Ambassadorコンテナを作成する
Ambassadorコンテナの作成はイメージを持ってきて、あとはhttpdコンテナにlinkするだけで他に設定は不要。超簡単。
# docker run -d --link httpd:httd-alias --name httpd-amb -p 8080:80 svendowideit/ambassador
これでAmbassadorが8080ポートで受けた接続はコンテナ内では80ポートで受けて、それをhttpdの80ポートへそのまま流すことができるようになる。
現状確認。2つコンテナが実行されている。
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c06aaa97b55a svendowideit/ambassador:latest "\"/bin/sh -c 'env | 30 seconds ago Up 29 seconds 0.0.0.0:80->80/tcp httpd-amb 9c4495ffddfd centos:centos7 "/sbin/init" 4 minutes ago Up 4 minutes 80/tcp httpd
# telnet localhost 8080 GET /
VM2: httpクライアント+ambassadorを構築する
Ambassadorコンテナを作成する
docker run -d --name httpd_ambassador --expose 80 -e HTTPD_PORT_80_TCP=tcp://192.168.11.11:8080 svendowideit/ambassador
環境変数でHTTPD_PORT_80_TCP=tcp://192.168.11.11:8080を渡しているのが肝だと思われる。 多分Ambassadorは渡された環境変数をパースして自分がプロキシすべきポートを判断する。(かなり適当な予想なので間違えっているかも。)
httpdクライアントを作成する
# docker run --privileged -d --link httpd_ambassador:httpd_ambassador-alias --name httpdclient centos:centos7 /sbin/init
現状確認。2つのコンテナが実行されている。
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES bcabc10a7506 centos:centos7 "/sbin/init" 14 minutes ago Up 14 minutes httpdclient e526511520fa svendowideit/ambassador:latest "\"/bin/sh -c 'env | 17 minutes ago Up 17 minutes 80/tcp httpd_ambassador
VM2: httpdクライアントからAmbassadorの80番ポートにアクセスしてWebページをゲットする。
準備が整ったので、ホストを隔てたhttpdへのアクセスができるか試す。
流れ - VM2のhttpdclientコンテナの中でbashを実行する - 環境変数からAmbassadorのIPアドレスを取得する - Ambassadorの80ポートへcurlでアクセスする
# docker exec -it httpdclient /bin/bash [root@bcabc10a7506 /]# env HTTPD_AMBASSADOR_ALIAS_PORT_80_TCP=tcp://172.17.0.26:80 HOSTNAME=bcabc10a7506 HTTPD_AMBASSADOR_ALIAS_PORT=tcp://172.17.0.26:80 HTTPD_AMBASSADOR_ALIAS_ENV_HTTPD_PORT_80_TCP=tcp://192.168.11.11:8080 HTTPD_AMBASSADOR_ALIAS_PORT_80_TCP_PORT=80 LS_COLORS= HTTPD_AMBASSADOR_ALIAS_PORT_80_TCP_PROTO=tcp PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PWD=/ container_uuid=bcabc10a-7506-1b55-74a8-7c9f0d2ec7dc SHLVL=1 HOME=/root HTTPD_AMBASSADOR_ALIAS_NAME=/httpdclient/httpd_ambassador-alias LESSOPEN=||/usr/bin/lesspipe.sh %s HTTPD_AMBASSADOR_ALIAS_PORT_80_TCP_ADDR=172.17.0.26 _=/usr/bin/env [root@bcabc10a7506 /]# curl -s http://172.17.0.26 | head -1
いけた! まぁあんまりAmbassadorのありがたみが無い感もある. どちらかというと、Ambassadorの使い方がわかっただけ。
docker --link --exposeの動きを理解する
dockerの--linkとかEXPOSEとか接続関係のコマンドがよくわからないので、動かしながら理解する。
参照: Dockerのネットワークの基礎
- --link 他のコンテナのポートにつなぐ
- --expose コンテナのポートを他のコンテナに晒す
- --publish コンテナのポートをホストのポートにマッピングする
試しに2台のcentosのコンテナを作って、 一台にはapacheをインストールし、もう一台からそのapacheの80番ポートを叩いてみる。 --publishについては言及しない。
コンテナの名前は以下
コンテナ名 | 役割 | exposeするポート | リンク |
---|---|---|---|
httpd | apacheサーバ | 80 | なし |
httpdclient | クライアント | なし | httpdコンテナにリンク |
apacheコンテナを作成する。(1台目)
# docker run --privileged -d --expose 80 --name httpd centos:centos7 /sbin/init
# docker exec -it httpd /bin/bash [root@a4522c59ed0c /]# [root@a4522c59ed0c /]# yum install httpd -y [root@a4522c59ed0c /]# systemctl enable httpd.service [root@a4522c59ed0c /]# systemctl start httpd.service [root@a4522c59ed0c /]# exit
一応確認
[root@centos001 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 25fcc3bcc9b8 centos:centos7 "/sbin/init" 44 seconds ago Up 43 seconds 80/tcp httpd
ただのcentosを作成する。(2台目)
# docker run --privileged -d --link httpd:httpd-alias --name httpdclient centos:centos7 /sbin/init
--linkはコンテナ名:エイリアス名というフォーマットで指定する。
一応起動していることを確認する。2台動いている。
# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 44e11aeaea7c centos:centos7 "/sbin/init" 9 minutes ago Up 9 minutes httpdclient 25fcc3bcc9b8 centos:centos7 "/sbin/init" 14 minutes ago Up 14 minutes 80/tcp httpd
作成されたコンテナの環境変数は以下のように調べられる。 この環境変数を使えば、このコンテナからapacheのポートを晒しているホストにアクセスする方法がわかる。
# docker exec -it httpdclient env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=44e11aeaea7c HTTPD_ALIAS_PORT=tcp://172.17.0.20:80 HTTPD_ALIAS_PORT_80_TCP=tcp://172.17.0.20:80 HTTPD_ALIAS_PORT_80_TCP_ADDR=172.17.0.20 HTTPD_ALIAS_PORT_80_TCP_PORT=80 HTTPD_ALIAS_PORT_80_TCP_PROTO=tcp HTTPD_ALIAS_NAME=/httpdclient/httpd-alias container_uuid=44e11aea-ea7c-97ee-6c8f-e903929a981d HOME=/root
以下のように環境変数経由でアクセスする。
[root@44e11aeaea7c /]# curl -s http://$HTTPD_ALIAS_PORT_80_TCP_ADDR:$HTTPD_ALIAS_PORT_80_TCP_PORT/ | head -1
これでコンテナ同士をつなぐことができた。
dockerを触ってみる
centosのイメージを持ってくる
公式に解説があるので、それを参考にする。 https://hub.docker.com/_/centos/
途中で公式が解決方法を提供している問題をひとつずつ踏みながら、理解しつつ進むので少しまどろっこしい方法で理解する。
以下のようなDockerfileを作成する。
# cat Dockerfile FROM centos:7 MAINTAINER "you"ENV container docker RUN yum -y swap -- remove fakesystemd -- install systemd systemd-libs RUN yum -y update; yum clean all; \ (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \ rm -f /lib/systemd/system/multi-user.target.wants/*;\ rm -f /etc/systemd/system/*.wants/*;\ rm -f /lib/systemd/system/local-fs.target.wants/*; \ rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ rm -f /lib/systemd/system/basic.target.wants/*;\ rm -f /lib/systemd/system/anaconda.target.wants/*; VOLUME [ "/sys/fs/cgroup" ] CMD ["/usr/sbin/init"]
イメージをビルドする
Dockerfileからイメージをビルドする。
# docker build --rm -t local/c7-systemd .
作成されたことを確認する。
# docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE local/c7-systemd latest 55328d2ac5c8 6 minutes ago 229.4 MB
コンテナを起動する
次に、このイメージからコンテナを作成して、シェルを実行させる。 dockerにおけるコンテナは起動後に必ず一つのプロセスを動かす必要があるようだ。 シェルからapacheをインストールして、起動してみる。
# docker run -it local/c7-systemd /bin/bash [root@4747003b4111 /]# [root@4747003b4111 /]# yum install httpd [root@4747003b4111 /]# systemctl start httpd.service Failed to get D-Bus connection: No connection to service manager. [root@42ebe1f0dcb4 /]# ps auxww USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.2 0.1 11744 1872 ? Ss 05:09 0:00 /bin/bash root 18 0.0 0.1 19764 1228 ? R+ 05:09 0:00 ps auxww
コンテナのシェルのプロンプトが現れる。 「-it」はstdinを有効にするために必要らしい。 httpdをインストールして起動してみたが、エラーが出る。 psコマンドを見てもシェルから起動したプロセスしか現れない。これがコンテナか。
Dockerfileを以下のように書き換えて再実行。 apacheをインストールして、systemctlでhttpを起動してinitを実行する。
# cat Dockerfile FROM centos:7 MAINTAINER "you"ENV container docker RUN yum -y swap -- remove fakesystemd -- install systemd systemd-libs RUN yum -y update; yum clean all; \ (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \ rm -f /lib/systemd/system/multi-user.target.wants/*;\ rm -f /etc/systemd/system/*.wants/*;\ rm -f /lib/systemd/system/local-fs.target.wants/*; \ rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ rm -f /lib/systemd/system/basic.target.wants/*;\ rm -f /lib/systemd/system/anaconda.target.wants/*; VOLUME [ "/sys/fs/cgroup" ] FROM local/c7-systemd RUN yum -y install httpd; yum clean all; systemctl enable httpd.service EXPOSE 80 CMD ["/usr/sbin/init"]
先ほどと同様の方法で起動するが、失敗する。
# docker run -it local/c7-systemd Usage of loopback devices is strongly discouraged for production use. Either use `--storage-opt dm.thinpooldev` or use `--storage-opt dm.no_warn_on_loop_devices=true` to suppress this warning. systemd 208 running in system mode. (+PAM -LIBWRAP -AUDIT +SELINUX -IMA +SYSVINIT -LIBCRYPTSETUP -GCRYPT -ACL -XZ) Detected virtualization 'docker'. Welcome to CentOS Linux 7 (Core)! Initializing machine ID from container UUID. No control group support available, not creating root group. Please start this container with '-v /sys/fs/cgroup:/sys/fs/cgroup' Failed to allocate manager object: Operation not permitted
エラーが出て停止する。cgroupに関するエラーのようだ。
これは以下のようにコンテナを実行すると回避できる。
# docker run --privileged -ti -v /sys/fs/cgroup:/sys/fs/cgroup:ro -p 80:80 local/c7-systemd
今度はエラーが出ない。起動時の表示が出たまま 以下のようにすると起動していることを確認できる。
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0c3958d6a846 local/c7-systemd:latest "/usr/sbin/init" 4 minutes ago Up 4 minutes 0.0.0.0:80->80/tcp adoring_almeida
変な名前「adoring_almeida」が付いている。なんだろこれ。
試しにホストのlocalhostの80版ポートにアクセスしてみる。
# telnet localhost 80 Trying ::1... Connected to localhost. Escape character is '^]'. GET / index.htmlが返ってくる。
GETできたので成功だ。
あとは終了して、コンテナを終了しておく。
# docker stop adoring_almeida adoring_almeida
他の方法
以下のようにすれば、もっと簡単に検証できらしい。 参照: CentOS 7のDockerコンテナ内でsystemdを使ってサービスを起動する
$ sudo docker run --privileged -d -p 80:80 --name httpd centos:centos7 /sbin/init $ sudo docker exec -it httpd /bin/bash # yum install httpd -y # systemctl enable httpd.service # systemctl start httpd.service # exit $ curl -s http://localhost/ | head -n 1
docker runとdocker execの違いを理解していないため、よくわからなくなってしまった。 以下がそれぞれのコマンドの役割である。
- docker run コンテナを起動する
- docker exec 実行中のコンテナで新しいコマンドを実行する
docker runで起動中のコンテナ上で新しいコマンドを起動したければdocker execを使う。
うえのほうで実行していたapacheのインストールと起動が失敗した理由は単純にDockerfileから起動したものに対してシェルを起動したつもりになっていて実はそうなっていなかったのかも。
systemdについてちょっと調べた
参考文献を並べて重要な箇所だけ引用する。 参考になった順にならべる。
なぜsystemdなのか? (翻訳 Why systemd(2014-07-23)by Jorgen Schäfer)
SysV initサービスを起動したり停止したりするのに用いられる一般的な方法は”service”コマンドを用いることです。多くの人はinitスクリプト/etc/init.d/$nameを直接使いますが、実はこれには問題があります。initスクリプトをカレントの環境で起動するのですが、ブート時に有効な環境とは違う可能性があるからです。影響としてコマンドラインから実行させた時はソフトウェアが正しく起動するのに、ブート時の起動では失敗してしまう、というようなことがあります。
sysinitの場合はスクリプトに依存関係がある場合にうまく起動できない場合がある。
似たように、SysV initは、機能をinit自身に実装することはせず、それぞれ全てのサービスに対して、共通の機能を実装するように求めています。
daemon化がそれぞれのスクリプトで実施する必要があるのは確かに面倒くさい。 それにforkが2回実行されると祖父プロセスとの関連性を失うのも良くない。
GNU/LinuxにとってDebian とUbuntuがsysytemdに乗り換えたという決定は、まぎれもなくsystemdが勝ったということを意味しています。使い手の好みに関わらず、systemdは、いまやGNU/Linuxのinitシステムなのです。
systemd同様にsysinitを置換する候補としては以下のように多くのソフトウェアがあるらしい。しかし勝者はsystemd。 * eInit * Upstart * OpenRC * initng * busybox-init * s6 * procd
systemdと連動するためにサービスをデーモン化する必要はありません。supervisorを使った時と同じように、プロセスは通常通り実行できます。syslogにログメッセージを記録する時でさえ、stdoutとstderrに書き込むだけでよいのです。
syslogとの連携が標準出力だけなんて楽だな。 しかも、ログをありかを覚えておく必要はなく、systemdのコマンドを使えば良いらしい。 知らないシステムを調査しなければならない時にログの在処を探し当てるのが面倒くさいんだよね。
CentOS 7実践ガイド (古賀 政純)
http://www.amazon.co.jp/dp/484433753X centos7からsystemdが採用されるそうだ。操作方法などがまとめられている。
systemd超入門(佐々木 大輔)
http://dev.classmethod.jp/cloud/aws/systemd-getting-started/
PIDではなくcgroupによってプロセスを管理する
cgroupを使っているから、コンテナ関連の話でsystemdが出てくるのだろう。 Dockerのコンテナはsystemdにおけるユニットとして実行されることでリソースが制限されるのだろうか。
without systemd
http://without-systemd.org/wiki/index.php/Main_Page systemd反対派(?)のWiki systemdのどこがわるいのかはよくわかっていない。 少なくとも多くのディストリで標準になりつつある現状を見ると、反対派のちからが及ばない程度にsystemdは優れているのだろう。
systemd-nspawn (Arch Linux wiki)
https://archlinuxjp.kusakata.com/wiki/Systemd-nspawn
Dockerより柔軟なコンテナ型仮想化 systemd-nspawn を使ってみた
まぁね。ArchWikiに書いてあるしね・・・別にいらん世話かとは思いますけど、DockerやRocketみたいなコンテナ型の仮想化機構です。
ステッドラー アバンギャルド 927AG-S をJETSTREAMに換装
自分はJESTREAM厨なのだが、JESTREAMの高級モデルはデザインが今ひとつ。 (なぞの宝石がついているところとか。)
三菱鉛筆 多機能ペン ジェットストリーム プライム 3&1 MSXE450000724 ブラック
- 出版社/メーカー: 三菱鉛筆
- 発売日: 2013/10/20
- メディア: オフィス用品
- この商品を含むブログ (3件) を見る
したがって、他社のボールペンにJETSTREAMのリフィルを入れて使うことになる。
しらべてみると、ステッドラーのアバンギャルドはJETSTREAMが入るらしい。 色とか値段がちょうどいいので購入したので紹介する。
以下の2つの商品をアマゾンで購入した。
- アバンギャルド 927AG-S
- ジェットストリームプライム多色多機能用 3本入 0.5mm 黒赤青
ステッドラー 多機能ペン アバンギャルド 927AG-S クールシルバー
- 出版社/メーカー: ステッドラー
- メディア: オフィス用品
- クリック: 2回
- この商品を含むブログを見る
三菱鉛筆 ボールペン替芯 ジェットストリームプライム多色多機能用 3本入 0.5mm 黒赤青 164145002
- 出版社/メーカー: 三菱鉛筆
- メディア: オフィス用品
- この商品を含むブログを見る
アバンギャルドの包装が高級感があって、ワクワクさせる。
開けて取り出すと、かなり軽い。使ってみないとわからないが、この軽さは微妙かもしれない。
換装する前に少し試し書きしてみたところ、なんとなくかすれる感じがする。
日頃JETSTREAMに慣れているとカサカサ感が否めない。
3色のボールペンとシャープペンシルが入っているのだが、どれを出すかは、ペンのどこが上を向いているのかで変わる。
ペンの上部に「Black」「0.5mm」「●」「Red」と書かれていて、それぞれが書かれている部分を上に持ってきて、ノック部を押すと対応するペン先が出てくる。 ちなみに0.5mmはシャープペンシル、●は青色に対応している。多分●は他の色を入れてもいいよってことなんだろう。
この仕組みのためか、中でシャカシャカ音がなる。
ペンを開けてペン先を入れ替えるのは非常に簡単だ。完全にJETSTREAM互換だ。
やはりJETSTREAMはいい。 書いたときの滑らかな感じ、この一言に尽きる。
OpenCVとWebカメラで動画像処理を始める。
やりたいこと
ビリヤードのテーブル上のたまの動きを撮影して、自動的にスコアをつけたり、あとで試合の運びを確認できるようにしたい。 そのために、opencvで動画を解析するのが今回の目的。 * 動作環境: Ubuntu 14.04.2 LTS * Webカメラ: logicool c920t
カメラの動作確認と設定
Linuxで使うのだが、とりあえずキャプチャ(動画じゃなくて、一枚の画像)を取得することにした。 コマンドや使い方は以下を参考にした。 http://atelier-orchard.blogspot.jp/2014_05_01_archive.html
opencvのサンプルコードを動かす
ここまででWebカメラが正常に動いていることを確認できたので、実際にopencvを動かす。
$ sudo apt-get install python-opencv libcv2.4
次に以下のサンプルを実行して動体(動くもの)を検知してみた。 特に画像処理の仕組みを理解したわけではないが、実行できるものを手元で動かすってのは重要だ。できた感があるからね。 http://python-gazo.blog.jp/opencv/%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E9%96%93%E5%B7%AE%E5%88%86%E6%B3%95
サンプルコードをtest.pyという名前で保存して実行する。
$ python test.py
実行結果は以下の通り、手を振ると、動いている部分のエッジが白くなる。 今日の目的はとりあえず達成。(部屋の物がいろいろ見えてしまうので、ぼやかした。)
ビリヤード台がほしい
ビリヤード台がほしい
ほしいと思ったきっかけ
仕事忙しい・・・ビリヤード場いけねぇ・・・
条件
- 1LDKのアパートにおける
- それなりに本格的
- 折りたためること
一般的なビリヤード台の大きさ重さ
- 大きさ: 9フィート
- 重さ: 300kg
自分の部屋に置くのはムリだ。いや実際の大きさを図るまでもなく、ムリなのはわかる。
したがってビリヤード台の中でも家庭用ビリヤード台と呼ばれるジャンルの台を探すことになる。
家庭用ビリヤード台
ググってみるといろいろ出てくるが、気に入ったものだけをリストアップしてみた。
- ES-1800
- ユニバー社製
- 販売ページ(レビューあり)(楽天)
- 高76×幅180×奥90cm
- FP-5B
- Riley社製
- 販売ページ
- 奥84x幅152x高79cm
- Riley社他
ES-1800が6フィートなので、大きさがちょうどいいなと思った。 5フィートは小さすぎる感じ。
しかしRileyの台が本格的で良い感じ。悩む。
6フィート以上のRiley社の台が国内で売ってない・・・?
国内でRiley社の台を売っているところを探してみた。
FP-5BとJL-2Cは見つかるのだが、それ以外の台が見つからない。 6フィートの台がほしいのに。
ということで、とりあえず問い合わせてみることにする。
どの台を買ったとしても、レビューしようと思う。