ページ

2016年3月19日土曜日

Dockerと付き合う為の虎の巻 その03

 「Dockerと付き合う為の虎の巻 その03」です。今回は前回のDockerと起動するプログラムとPID1のお話しついてもうすこし掘り下げた回となります。内容的には主に前回の以下の項目についてのお話の続きです。


〇 Dockerコンテナは1つのコンテナに1つのプログラム(プロセス)を起動する事を基本として作成し、使用するものである

〇 Dockerコンテナで起動したプロセスはPID1(プロセスIDが1)のプロセスとして起動される

〇 Dockerコンテナの問題の無い通常の停止(docker stop 等)はPID1に対するSIGTERMシグナルによって行われる。

〇 Dockerコンテナでは基本的にログ出力は使用せずに標準出力にそのまま内容を出力する



 前回のお話しにもありましたが、Dockerにおいてといいますか、LinuxにおいてPID1のプロセスは特別な意味を持っています。一見では単純に Dockerコンテナとして起動したいプロセスをENTRYPOINTとして指定するだけでよさそうに見えるのに実はそうではないという所は大きな落とし穴と言いますか、初見殺しの罠となっているような気がしますので色々捕捉をしていこうかと思います。


 とりあえずはexampleといたしまして、redis君に登場していただきつつ、以下のようなDockerfileにてバッドケースを実演してみる事にします。(最近この手のexampleでやたらとコキ使われている気がしますねredis君)

FROM centos:6

RUN yum -y install epel-release
RUN yum -y install redis cronie

ENTRYPOINT ["/usr/sbin/redis-server"]
CMD []

 内容的には単純にCentOSの6をベースにyumでredisとcronie(crond)をインストールした後に、ENTRYPOINTとしてredisを指定して起動しているものです。cronは後で実験をする為の素材として入れてありますので似たようなものであれば別になんでも良いです。設定ファイルの指定もしていないのでredisとしてまともに機能する訳ではないのですが、今回はそちらは主目的ではないのでとりあえず気にしない事としておきます。


 とりあえず前述のDockerfileをビルドしつつ。
# docker build -t example01 .

 起動を行ってみます。
# docker run -itd --name=example01 example01
# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
1d7a425f2aca        example01           "/usr/sbin/redis-serv"   6 seconds ago       Up 5 seconds                            example01

 無事起動いたしました。とりあえずこのままこのコンテナの中に入ります。

# docker exec -it example01 bash

 さて、この状態でpsコマンドでプロセスの状態を確認してみます。

# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 15:52 ?        00:00:00 /usr/sbin/redis-server
root        11     0  0 15:54 ?        00:00:00 bash
root        26    11  0 15:56 ?        00:00:00 ps -ef

 ENTRYTPOINTで指定したredis-serverがPID1として実行されているのが分かります。bashというのはexecで実行した今この動作しているbashの事です。色々不自然ですが取り敢えずは置いておきましょう。


 さて、ここまでは普通ぽい動作といいますか、想定通りとなる訳ですが、ここで一つバッドな事を実行してみます。最初のDockerfileにて事前にcronieをインストールしていますので、cronと関連するinitscripts等が事前に入っている状態となります。さっそくそいつを起動してみましょう。

# service crond start
 Starting crond:                                            [  OK  ]
# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 15:52 ?        00:00:00 /usr/sbin/redis-server
root        11     0  0 15:54 ?        00:00:00 bash
root        47     1  0 16:01 ?        00:00:00 crond
root        49    11  0 16:02 ?        00:00:00 ps -ef

 どうやらうまくcrondが起動したようです。しかし、PIDがちょっと不自然な状況にも見えます。とりあえず分かりやすくする為に今起動したcrondを停止してみます。

# service crond stop
Stopping crond:                                            [FAILED]

 画面出力をみるとどうやら停止に失敗したような出力がなされました。とりあえずpsコマンドで状況を確認してみます。
# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 15:52 ?        00:00:00 /usr/sbin/redis-server
root        11     0  0 15:54 ?        00:00:00 bash
root        47     1  0 16:01 ?        00:00:00 [crond] <defunct>
root        82    11  0 16:09 ?        00:00:00 ps -ef

(=゚ω゚) !?

 なんと、crondプロセスが<defunct>という表示で残ってしまっています。これはいわゆるゾンビプロセスとよばれる状態になってしまっている事を表しています。色々ダメな状態ですね。


 なぜこのような状態になってしまったのでしょうか。色々と細かい事情が複合してはいますが、簡単に一言で言えば「ENTRYPOINTでPID1として起動させたredis-serverがLinux的なPID1プロセスとして必要な役割を果たしていないから」という事になります。

 今回のケースはちょっとしたバッドケースなのですが、「聞いていた話だけだと一見問題なさそうなはずなのに結構簡単に問題が出てしまったよ」という身近な例として少し長めに説明を割いてみましたがいかがでしょうか?


 さて、それではPID1の役割とは一体何なのかという話になります。自分の場合も完全には調べ切れていないのですが、少なくとも今回のようなケースでは以下の役割が足りていない為に起きているようです。(※下記の文章は公式文書の引用等ではありませんので、もし間違っている部分がありましたら申し訳ございません)




◯ Linux起動時の初期プロセスは全てPID1から起動しており、その他の子プロセスや孫プロセス等も親プロセスをたどっていけばPID1に辿り着くツリー構造のような形態をとる。つまりPID1はプロセスツリー的に全てのプロセスの頂点となるプロセスである。 

◯ 通常linuxのプロセスは終了した後に親プロセスによって終了状態の回収を待つ状態になる。プロセスは親プロセスに終了状態を回収される事により真にプロセスのライフサイクルが終了する。この終了状態の回収が行われずに放置された状態となる事をいわゆるゾンビプロセスという。(※これはPID1でなくてもプロセス共通です)

◯ 親プロセスが居なくなったプロセスの親プロセスは親プロセスの親プロセスに繋ぎ変えられる事になる。最終的には必ず存在するプロセスツリーの頂点で あるPID1のプロセスが親プロセスとなる。例えば意図的に親プロセスを終了させて孤立状態となるデーモンプロセス等のケースが存在するが、このような機構によりデーモンプロセスの親プロセスはPID1のプロセスが担うこととなる。


 以上、簡潔に?ですがPID1の役割を説明してみました。


 つまり、今回のケースでは、crondが起動した際にその親プロセスが終了しているが、PID1が正しく終了状態を回収していない為、親プロセスの継ぎ換えが正しく行われずに切り離された状態となってしまった。そしてその状態でcrondを終了させた事により、実行もされておらず、終了状態の回収もされておらず、親プロセスも存在しないという完全なゾンビプロセス状態となってしまった。

 というのが現象発生の流れという事になるかと思います。



 なんか文章ばかりで疲れてしまいましたが、こうしてみますと、redisは別にdocker用途としてPID1で動くように作られている訳ではありませんので(そういったオプション設定が用意されている可能性もありますが)このような状態になってしまうのはむしろ当然の出来事であるというのが分かります。

 この問題は自作プログラムをdockerコンテナとしたい場合にも直面する問題です。その対象の自作プログラムは本来の動作以外にもPID1として動作を実装しなければならないという事になってしまいます。色々と面倒くさい事になって来てしまいました。(=゚ω゚) エー ミタイナ...

  このPID1としてのプロセス回収の役割ですが、自作のプログラムの場合、基本的にはLinuxのシグナルであるSIGCHLDに対して適切な処理を行う事が必要となって来ます。C言語等でサーバプログラムを作った事がある方ならご存知かと思いますが、親プロセスによる終了状態の回収というやつはSIGCHLDにて行うという手法が一般的に存在しています。PID1の場合はそれがLinuxシステム全体のプロセスの親としてSIGCHLDの処理が任されていると考えれば問題なさそうです。(状況次第ではSIGCHILDにSIG_IGNをセットするだけで事足りる場合もあるかもです)


 なお、今回のredisでは子プロセスの回収処理を行っていない事により問題が発生しておりましたが、昨今のdockerの流行等による影響もあり、最近のソフトウェアではdockerコンテナのPID1として動作させる為の対応を盛り込んできている物もみられるようになって来ております。

 具体的には本ブログの「「Consulを頑張って理解する」 を公開してみました(ノ=゚ω゚)ノ」
の回や「ConsulのDockerコンテナを作成&公開してみました」の回で紹介しました、HashiCorp社の「consul」等もその一つです。consulは元々はdockerコンテナ内部で動作させるものではなかったかと思いますが、dockerの隆盛の流れに乗って進化してきたという経緯がある為か、PID1で動作する場合には子プロセスの回収を行う仕組みが働くようになっています。また、同じくHashiCorp社の「nomad等のソフトウェアでも同様の仕組みが組み込まれています。

 また、今回のPID1問題の解決策として前回すでにsupervisordを使えば問題ありません」と書いてあったりするのですが、もちろんsupervisordにも同様の機構が組み込まれていますのでDockerコンテナ内部のプロセス管理にもってこいという訳であります。

 なお、このような子プロセスの回収の仕組みは主に「reap」という名前で表現されるようです。なにか既存のソフトウェアをdockerコンテナ上で動作させる際に、PID1の動作に対応しているかどうかを確認する際には、対象ソフトウェアのドキュメントや設定ファイル中に「reap」という文字が存在するかどうかを調べてみてください。メジャーなソフトウェアで公式のdockerコンテナを出しているようなソフトウェアに「reap」という記述がありましたら、この子プロセス回収の機構の事でまず間違いありません。(=゚ω゚) タブン


 さてはて、今回色々と説明が長かったのですが、結論としては「SIGCHLDを自分で色々なんとかする」か「supervisordを使う」のどちらかという事になりますでしょうか。

 実際の所、1つのコンテナで1プロセスが動くのみの単純な物であるのならば、そもそも管理する別のプロセスが存在しない事になりますので、PID1としての子プロセスの回収等は行う必要自体が無い事になるのですが、内部で子プロセスを作成したりするデーモン的なソフトウェア等を動作させようとしたりすると、結構この部分で引っかかってしまう事もあるようです。

 次回は一応この問題に対しての解決案の一つ提示してみようかなと考えています。次回でこの問題についての話題は最後にしたいですね!なんか字ばっかりだし!難しそうな説明になるし!(=゚ω゚) テガツカレマシタ


2016年3月15日火曜日

Dockerと付き合う為の虎の巻 その02

 「Dockerと付き合う為の虎の巻 その02」です。今回はDockerコンテナイメージ作成についての説明の序章編的なものとなります。

 さてはて、大変便利なDockerコンテナ君ですが、docker searchコマンドやDockerHubでの検索にて色々と有名なソフトウェアの名前を入れつつ検索してみると、様々なソフトウェアが公式コンテナを公開しています。このような大きな流れの広がりを見ていると、「よーし今日から家もDockerだ!」と、Dockerコンテナを作って公開したくなるのが 人情といいますか、職業的な病気的なアレというものです。きっとチャレンジして損は無いに違いないですね!(=ノ゚ω゚)ノ ポヂテブ!

 それでは早速Dockerコンテナイメージを作ってみようとなる訳ですが、実際に作ろうとすると色々と謎のルールに遭遇して困惑する事が多いのがDocker君の困った所であったります。基本的にはそのような謎のルールについては公式ドキュメントに書いてあるに違いないので、別に謎ではないはずなのですが、公式ドキュメントは英語ですし、なかなか量も多いですし、肝心な事は書かずにスルーしていたり、散々引っ張ったあげく一番最後の方に、なおそんな機能は無いので自分で頑張るのだと書いてあったりと、Dockerを始めたばかりの頃は色々と苦労するものです。

 というわけで今回はそんな感じのルール等を忘れないようにTips化しておくの巻となります。慣れている方には当たり前の事ばかりかもしれませんが、この辺りのルールを知らないまま使用する事により、Dockerが不審な挙動を起こす事もあります。 そして、そのままDockerが不安定なものであるとか、怪しいものであるとか、ネガティブなイメージを持ってしまい、離れて行ってしまう方も一定数以上いるのではないかという気もしていますので、そのような経験を持ってDockerが嫌いになった方にもお勧めの内容となっておりますので、ぜひご覧になってみてください。


 それではDockerTipsの始まりです。(=ノシ゚ω゚)ノシ シャカシャカ



〇 公に公開するようなDockerコンテナイメージはDockerfileを記述して定義して作成するものである


 とりあえず最初なので基本からです。基本的には公開するようなDockerコンテナイメージは全てDockerfileから作るようにしなければならないと思って問題ありません。やり方によっては「起動した後に内部に入って設定等を行い、その時点のイメージを保存してマスターとする」等の方法も可能ですが、公開するようなコンテナでは原則としてはやりません。ただし、そのような方法の方がはるかに楽なケースも多いですので、非公開の開発用とか個人の趣味的な用途のコンテナ等、比較的どうでも良いものに関してはDockerfileを一々書く必要はないかと考えられます。


〇 Dockerコンテナは1つのコンテナに1つのプログラム(プロセス)を起動する事を基本として作成し、使用するものである


 1コンテナ1プログラム(プロセス)のルールです。これはDockerfileのENTRYPOINT(最初に起動するプログラム)として1つのプログラムを指定し、それ以外は起動しないという意味となります。シェルスクリプトを置いてserviceコマンド等で起動する等ではありません。例えばredisが起動するコンテナであればENTRYPOINTとして/usr/bin/redis-server等と直接プログラムを指定する事によりプログラムを1つ起動するという意味になります。(※実際の所はシェルスクリプトをENTRYPOINTに指定し、内部でexecコマンドによるプロセスの置き換えを実行する事により、目的のプログラムを起動するのが一般的です。説明がややこしいですが。)

 また、このENTRYPOINTで指定して起動するプログラムはフォワグラウンドプロセスとして起動される必要があります。要は普通のプロセスとして起動しっぱなしにする必要があります。単純にENTRYPOINTで起動したプロセスが終了すると、Dockerコンテナもそのまま終了する仕組みに
なっているというのもありますが、後述のPID1の問題やログの問題他様々な要因によるルールとなっております。

 通常の今迄の非コンテナのアプリケーションの場合、そのアプリケーション単独で動作するのではなく、例えばcronに登録して時間で処理を実行させたり、ログはsyslogサーバに出力したりetc...と各種アプリケーション間で連携して動作するようになっていたりする事も多いものですが、Dockerコンテナでは基本的にはそのようなものは同時に動かしたりはしないような方針を採る事となっているようです。そのような場合は例えばcron処理のみを行う別のコンテナを作成し、2つのコンテナを起動する事により、1つのアプリケーションと成すような作り方が基本形となってくるようです。

 この1コンテナ1プログラム(プロセス)というルールは必ずしも必須ではないかと思いますが、なにせDockerの製作者サイドがそのように想定しているものですので、この道を外れると色々と不都合が出て来る場面も出て来るかもしれません。初見で聞くと「へ〜」ぐらいの印象であったりするのですが、実際に作り始めるようになると必ず落とし穴にハマるポイントではないかなと思います。


# Dockerfileで言う所のココです
ENTRYPOINT /usr/sbin/redis-server
CMD []

 なお、どうしても複数のプロセスを起動したい場合等はsupervisord等のソフトウェアを介して1つのプロセスを主として起動し、そのプロセスに下位のプロセスをまとめて管理させる手法を採る事が推奨されています。


〇 Dockerコンテナで起動したプロセスはPID1(プロセスIDが1)のプロセスとして起動される


 前項の1コンテナ1プログラム(プロセス)のルールにおいて、最もやっかいな部分でもあるのですが、基本的に何も起動していないDockerコンテナでは文字通り、何もプロセスが起動していないような状態にあります。

 よって最初に起動する1コンテナ1プログラム(プロセス)のプロセスはPID1のプロセスとして起動する事になります。

 Linuxでは通常、起動時にはまずinitプログラムがPID1のプログラムとして起動され、その他のプログラムはこのPID1のプログラムの子プロセスとして起動するような状態となります。つまり、PID1のプロセスはその他のプロセスと一線を介した特殊なプロセスであり、またLinux的にもそのような動作を求めているのが実際の所であったりします。

 実はDockerにて1コンテナ1プログラム(プロセス)のプロセスとして起動する場合にもこの条件は当てはまる為、Dockerで起動するプログラムはPID1としての動作をする事がLinuxから求められている事になります。

 この問題は見た目以上にやっかいな問題であったりします。PID1に求められる独特の挙動により、不審な動きをする事が実際に確認されていますが、Linux的には当たり前の挙動であったりする為、Docker固有のクセと混同しがちであったりします。

 どうしてもという時は前項にありました、supervisord等をあえて1枚かましてみるのも手かもしれません。supervisordはPID1として動作させた場合、PID1として求められる振る舞いをしてくれるようです。


〇 Dockerコンテナの問題の無い通常の停止(docker stop 等)はPID1に対するSIGTERMシグナルによって行われる。


 またまたPID1ネタであったりしますが、今回は割と普通です。docker stopコマンドでdockerコンテナを停止した場合、PID1(ENTRYPOINTで指定したプロセス)にSIGTERMが到着しますので、受け取ったプログラムはそれを元に適切に終了処理を行う必要があります。

 SIGTERMはkillコマンドを実行した時に使用されるシグナルですので、適切に作られたプログラムであれば基本的には問題無く停止処理に入ります。自作のプログラム等を動作させる場合は、SIGTERMによる停止処理の対応を忘れないようにする必要があります。

 ちなみにsupervisordを用いた場合には、supervisordにSIGTERMが到着すると、その配下にある子プロセスにSIGTERMを連鎖的に送出するような仕組みがあるようですので、適切に作られているプログラムであればsupervisord経由でも問題なく停止出来るかと考えられます。

 なお、docker stop 等で停止命令としてSIGTERMが送出された際には、10秒以内に適切に終了しないと強引にkillされてしまいますので、適切に処理がなされない場合、データ破損等の危険がありますので注意が必要です。


〇 Dockerコンテナは基本的には環境変数によりそのコンテナの挙動を変える設定を行い起動するものである。


 なんか小難しい書き方になっておりますが、極端に言い換えれば「設定は全部環境変数で行う事」と言い換えても良いかもしれません。通常の今迄の非コンテナのアプリケーションですと、インストールした後に設定ファイルを書き換えて、それから起動スクリプトを有効にしてetc...といった流れで使用する事になるのですが、Dockerコンテナでは基本的にインストール、起動、設定は同時に行うようなイメージとなります。簡単に言うと「環境変数を指定してコンテナを起動した→やった動いた!」となるのが理想です。

# Dockerfileで言う所のこんな感じの所です
ENV DATABASE_URL="example.jp"


〇 Dockerコンテナ内部のストレージは遅いのでそのままデータディレクトリとしては使わない/使えないものである。


 Dockerコンテナのイメージをpullしたり作成したりすると分かるのですが、1つのDockerコンテナは階層化された複数のイメージがセットとなり動作するようになっています。Dockerでは、このような階層化されたイメージの仕組みを利用して、ある特定の時点での状態を新しいイメージとして保存する事が出来たり、特定のイメージから継承や派生等を行いつつ新しいイメージを作成したり等が出来るようになっています。そのような理由もあり、基本的にはDockerコンテナ内部のストレージ領域はとにかく遅いと言いますか、頻繁に書き換えが走るようなデータディレクトリにはそもそも向いていないものと言えるかと思われます。

 そのような場合、一般的にはホストのボリュームをマウントして使用するか、Dockerfile中でVOLUME指定を行う等により、速度面の問題を回避する事となります。ただし、同時にDockerコンテナ内部のストレージである事のメリットも失われてしまいますので、使用方法には注意が必要です。

# Dockerfileで言う所のこんな感じの所です
VOLUME /var/lib/example


〇 Dockerfileには基本的には同じ項目は同じ1行にまとめて記述するようにする


 Dockerfileを実際に記述する場合、例えば環境変数3つを定義したい場合にそのまま書くと
ENV ARG01="101"
ENV ARG02="102"
ENV ARG03="103"

 のように3行のENV定義を書く事になります。

 しかし、実際にこのように記述してイメージをビルドしてみると、このENV1行につき1つの内部イメージが作成される事が分かります。DockerではDockerfileの1行に付き1つの階層のイメージを作成するような動作をするようになっているようです。 この動きはイメージの共有やキャッシュという面では優れているのですが、実際にイメージの配布等を行う際に、1つのコンテナに多数の階層イメージが含まれていると、色々と煩わしい場面が出てきてしまう事も多いようです。

 そのような場合は1行にまとめて記述する事により、階層イメージも1つとする事が出来ます。
 
 ENV \
  ARG01=101 \
  ARG02=102 \
  ARG03=103

  机上論的なDockerfileとしての定義としては1行づつの記述の方がスマートな記述方法にも見えるのですが、どうやらこのイメージがやたら多くなる問題は世界中のみんなが大嫌いであるようで、基本的に世界中のみんなが1行にまとめる記述方式を採用しているようですので、この際気にせずに1行にまとめて記述するようにしましょう。(=゚ω゚) デファクトスタンダードデス


〇 Dockerfileにはやや冗長と思える場合でも基本的な値については意味を理解した上で正しく定義しておく方が良い


 具体的にはENV、VOLUME、EXPOSE、WORKDIR辺りの定義でしょうか、この辺りの定義については、適切に定義を行っておくと後でお得であったりします。Dockerではこれらの値はコンテナイメージを作成する際の命令文であると共に、そのコンテナイメージがどのような構成で作られているかを公示するような意味合いを持つようになって来ています。

 例えばENVの値は別にDockerfileで定義しなくても、環境変数を元に挙動を変える事は可能ですので、一見必要ないかもしれませんが、とあるDockerコンテナのデプロイツールでは、使用したいDockerコンテナを指定すると、そのコンテナイメージからENV定義されている値を引っ張り出し、「このような設定が行えるコンテナである」と、一覧表示してくれたりします。

 例えばEXPOSEの値ですが別にDockerfileで定義しなくても問題なく使えるケースも多いかと思いますが、とあるDockerコンテナアプリケーションでは同じホストで起動や停止するコンテナを監視し、その起動したコンテナのEXPOSEの値を引っ張り出し、DNSサーバのSRVレコードに自動登録するような動きをする物があります。

 このように単なる命令文ではなく、構成の公示となる事を意識して定義するのは結構大事であったりします。



〇 Dockerコンテナでは基本的にログ出力は使用せずに標準出力にそのまま内容を出力する


 割と基本にして議論の分かれる部分かもしれませんが、基本的にDockerでは起動したコンテナで標準出力したものは、Dockerホストにてログとして保存されるようになっています。つまり、Dockerの想定している基本的なコンテナのログの機構が、標準出力に出力する事という事になります。

 このような方法で標準出力を経由してホストに渡されたログはログドライバ等の機能により、別のサーバに飛ばす等、様々なログのコントロールが行えるようになっています。

 ただし、実際の所アプリケーションがそもそもログファイルに出力をする事を前提や必須として作られていたりする場合等もありますので、ハイソーデスカと標準出力しましょう!等とは行かなかったりします。

 ちなみにnginxのコンテナイメージではDockerfile中にて /dev/stdout のシンボリックリンクを普段のログ出力先ファイル名に割り当てる等の工夫をする事によってこの問題を回避していたりと、なかなか面白い仕組みを使用していますので、手段として覚えて置くとお得です。(;=゚ω゚)b ナイショデス


〇 とりあえず今回はここまでです


 書き始めて気が付いたら結構な量になってしまいましたのでとりあえず今回はここまでとしておきます。なんかまだまだ色々ありそうな感じですね。

 こうしてみると罠だらけのような気もして来ますが、問題解決の為のベターな手法等もある程度固まって来ていたりする気もしますので、見た目よりは大丈夫に違いないです。多分!


それでわまた(=゚ω゚)ノシ



2016年2月17日水曜日

Docker Cloud 1.0 を使ってみた

 いつの間にかDockerCloudというDocker社純正のクラウドサービスが登場しておりました。(正確にはTutumのプロダクトがDockerCloudという名前でリスタートしたようです)

Docker Cloud 1.0登場へ。買収したTutumをリブランドしDocker Hub と統合
http://www.publickey1.jp/blog/16/docker_cloud_10.html

 そういえば去年辺りにTutumを買収したというニュースがあったような… すっかり忘れていたというか、Tutumとしてはスタートしてたのを知りませんでした!何かに負けたような気持ちでとても悔しいのでとりあえず使ってみる事にしました!

※今回は使ってみた的な回なのでスクリーンショットが多めです。



 なお、DockerCloudについての使用方法等については、普通のDockerの公式ドキュメントに「DockerCloud」という項目がありますのでそちらを確認すれば良いようです。

DockerCloud
https://cloud.docker.com/

Docker公式ドキュメント
https://docs.docker.com/



 ドキュメントの方は後でじっくりと見る事にして、まずはDockerCloudにアクセスしてみましょう。画面の少し下の方を見ますと料金的な事が書いてあるようですので確認します。


 どうやら1ノード1リポジトリまでは無料というのようです。実際に使う場合は1ノード1リポジトリでは足らないはずですので、まあお試しトライアルは無料ですよって事ですね。とりあえず何かに安心した所で右上のloginボタンでログインしてみます。



 ログイン後のWelcome画面です。チュートリアルウイザード的な画面ですね 。とりあえずはこの流れでボタンをポチポチ押しつつ進めて行けば良いようです。


 右下の辺りにツイッターとかフェイスブック的なノリで おじさんがHi! 等と親しげに話しかけてきております。友達承認するかどうかはこれから決めるのさ!的な思いを胸にとりあえず×ボタンを押下しておきましょう(=゚ω゚)っ ポチ



 とりあえずおじさんは置いておきつつ、最初の「Link a cloud provider」を進めてみます。


 簡単に言いますとバックエンドプロバイダとしてAWSやAzure等色々使えるので、使いたいプロバイダのIDとパスワード等の必要な情報を登録してリンクするんだ!という事ですね。とりあえず今回はAWSで試す事としましてAWSのIAMで作成したキー情報を入力しました。 なお、DockerCloud上から色々とAWSを操作する関係上、使用するIDには以下のようなロールを設定しておく必要があるようです。(設定し忘れて権限が足らない等の場合は、その都度右上の方に赤い吹き出しでその旨の通知が出るようです)

"Action": [
  "ec2:*"
  "iam:ListInstanceProfiles"
]


 
 続きましてWelcome画面で言う所の「Deploy a node」に進みます。ここではクラスタとして使用するノードを設定するようです。

 
  今回はAWSですので、配置するリージョンやインスタンスタイプやそのノードで起動するインスタンス数等を設定するようです。前述のようにPeoviderとしてAWSのキーを設定してある訳なのですが、VPCのIDとかは自動でAWSから取得してくるようです。すごい便利なのですけどちょっとだけ侵入されているような気分です。なお、あとでデプロイで使用するタグも指定出来るようです。

 AWSのECSやDockerSwarmと似たような感じであるようなので、とりあえず感覚でポチポチと入れて右下の「Lounch node cluster」を押してしまいます。(=゚ω゚)っ ポチ



  Deploy中となりました。





 EC2の方にインスタンスを作りに行ってるのかなとEC2の方に確認に行きますと…


 ちゃんとEC2インスタンスが作られています。ちなみに何のイメージを使っているのだろうと確認した所、MarketplaceではなくコミュニティAMIの方にそれ用のイメージが用意されていたようです。

 中身のOSは何なのかとかは今の所謎です。セキュリティグループとかも勝手に作成されて適用されていますが、ほぼ全開放状態であるような… キーペアとかも勝手に作られているようで、便利なんですが、なんとなくちょっぴり怖かったりします。まあ、慣れたら気にしなくなるんだろうなとは思いますが、後で色々と調べなければいけない事は多そうです。



 続きましてWelcome画面で言う所の「Create a service」に進みます。ここでは「サービス」の定義を行うようです。


 オフィシャルなコンテナに関してはそのまま直接選べるようになっているようです。その他のリポジトリのコンテナも特に問題なく使用出来るようです。



 せっかくですので本ブログの「ConsulのDockerコンテナを作成&公開してみました」の回で作成・紹介しました、consul-serverのコンテナを使用する事にします。





 サービス定義の詳細設定等の画面に進みます。どのノードに展開するか決める為のタグ等もドロップダウンリストに自動的に入っているので楽ちんです。

 



   ポート番号等はDockerfile内でEXPOSEしてあるポートが自動で一覧表示されているようです。ホストノードにマップしたいポートはここで選択しておく必要があるようです。


  Autodeployなんて項目もあります。これはサービスの設定等を更新する必要があるのか、DockerHub上で新しくなったら勝手にやるのか、まだちょっと分かっていません。

 後者だとすると、GithubからDockerHubの自動ビルド連携機能はDockerHubに元からありますので、その流れでデプロイまでしてくれるとなるとなかなか面白そうです。もっとも、自作コンテナ等でバグを混入した場合に無差別絨毯爆撃のように全コンテナをバグだらけにしてくれるのかもしれませんので注意がいりそうですが(=゚ω゚)



 設定的にはまだ続きがあるようで、左下の 「Next: environment variables」を押下して環境変数の設定に入ります。


 定義済みの環境変数に関してはわかりやすく一覧表示されているようで、変更等も見たまんまのイメージで直接変更出来るようです。

 ちなみにconsul-serverコンテナは設定項目を環境変数で行えるようにというコンセプトで作っている為、設定出来る項目に関しては全て事前にENV定義していたりします。おかげ様でこの画面でボタンをポチポチするだけで全設定が行えてしまうようです。どうやら時代を先取りしすぎてしまったようです(=゚ω゚)y-~

※実際はCONSUL_ADVERTISE_ADDRの値を固定的に入れる必要がある等、そのままでは自動化が難しい部分もあります



  とりあえず冗談はさておき、環境変数のCONSUL_DEVをtrueにして単独で動作するdevelモードで起動するように設定しつつ、左下の 「Next: volumes configuration」を押下してボリュームの設定等を行います。

 

  volumeに関してもイメージに定義済みの物は自動で表示されているようです。分かりやすくて楽ちんです。最後に右下の「Create service」を押下してサービス定義の完了です。



 定義されたサービスはこんな感じでサービス一覧に表示されます。




  後は見たまま、サービスの画面でスタートボタンを押せばサービスが起動するようです。
 

  ログとかもちゃんと見れていますね、素晴らしい(=ノ゚ω゚)ノ ベンリ!



  とりあえず今回は初回の使ってみた的な回なのでここまでとしておこうかなと思います。今回の感想としましてはAWSのECSやdocker swarmと比較して、それらよりもかなり便利というか洗練されているような印象を持ちました。第一印象的には最近では珍しい位の好感触度です。

 しかし、このデプロイソフトウェアという分野は罠だらけというか、今まで散々泣いて来た分野なので、実際に使って行けるのかどうか見るにはまだまだ色々調べなければならないかなという所です。 

 とりあえずは今後も定期的にチェックする対象にしておこうかなっと。(=゚ω゚)

2016年2月14日日曜日

Dockerと付き合う為の虎の巻 その01

「Dockerと付き合う為の虎の巻 その01 」です。


 〇 Dockerのバージョンは激しく上がる為、常に最新の情報に気を配る必要がある

 現在のDockerはとにかく激しく更新されます。具体的には以下のようなペースで更新が行われている状態です。

 *v1.10.1 - 2016/02/11
 *v1.10.0 - 2016/02/04
 *v1.9.1   - 2015/11/21
 *v1.9.0   - 2015/11/04
 *v1.8.3   - 2015/10/13
 *v1.8.2   - 2015/09/11
 *v1.8.1   - 2015/08/13
 *v1.8.0   - 2015/08/12
 *v1.7.1   - 2015/07/15
 *v1.7.0   - 2015/06/19

 0.1単位のバージョンアップだけ抜き出しても以下のような感じになります。

 *v1.10.0 - 2016/02/04
 *v1.9.0   - 2015/11/04
 *v1.8.0   - 2015/08/12
 *v1.7.0   - 2015/06/19

 大体2ヶ月~3ヶ月に一度0.1単位でバージョンが上がっています。そしてそれなりに大きな機能追加や変更等が実際に行われているようでして、昨日出来なかった事が今日はもう出来るようになっているなんて事は日常茶飯事のようです。(逆に昨日までの常識が今日にはLegacyとして扱われたりする事もあります)

 好意的に解釈すれば、今かなり力を入れている時期であり、最新の傾向や、需要のあるものがどんどん取り入れらて行く状態にあるとも言えます。過去にDockerを使用して「アレ?これダメじゃない?」となった方も、現状では問題無い可能性があるとも言えますので、もう一度見直してみる事をお勧めします。 

 否定的に解釈するならば、こんなにバージョンアップが激しいと本番では使い辛いといった側面を持っています。なお、Dockerの場合、ver1.9系 ver1.10系等と系統付けて並行して更新されるような事は基本的にないようで、v1.9 → v1.10 となった時点からv1.9等過去のバージョンは更新せずに捨てられていると思って良さそうです。機能追加等だけであれば「ver1.9系を採用して使用して行く」等の運用的な方針でどうにかなる事もあるかと思われるのですが、それも難しいのかもしれません。

 ここはそういうものだと割り切って付き合って行くしかないかもしれません。しかし、ver1.9辺りからそうもいかない事情も少し出てきてしまいました。(次項にて触れます)



〇Dockerは使用するOSを選定する必要がある

 ここでは主にLinux系だけ見てみます。Linux系のOSとしてはDebian、Ubuntu(Debian系)、CentOS(RHEL系)、CoreOS他、各種選択肢があるのですが、実際の所いくつかの大きな違いが出るポイントが存在しており、特にファイルシステムカーネルバージョンについては気を配る必要がありそうです。

 単刀直入に言うと、Ver1.9.0以降に取り入れられた機能のうち、overlayネットワークはカーネルバージョン3.16以上を要求し、overlayfsストレージではカーネルバージョン3.18以上(既知問題あり)が必要という事になっています。

 この二つのoverlay機能はDocker環境をかなり大きく改善する可能性を秘めた機能追加なのですが、残念ながらカーネルのバージョンをあまり上げてこないRHEL系ではカーネルとして3.10系を使用している為、動作可能と言えるかどうかに疑問が残るという状態にあります。

 実際にCentOS等でyum(EPELですが)でdockerを入れる場合、大体docker公式の最新バージョンより1ヶ月~2ヶ月位遅れ程度で(0.1バージョン遅れで?)投入されているという、RHEL系としては(EPELなのでFedoraかもですが)なかなか挑戦的なバージョン更新がおこなわれていたのですが、ちょうどカーネルがおいつかなくなった、Dockerのver1.9系以上のバージョンについては投入されなくなってしまいました。仮にRHEL8の投入迄はカーネルのバージョンが変わらないとするならば、DockerのバージョンにおいてもRHEL8の投入迄は現状のver1.8系で維持の可能性があります

 つまり、Dockerを最新の環境で使用したい場合は、RHEL系が選択肢から外れるという事になります。ただし、Dockerのver1.9系の投入自体が比較的最近の出来事ですので、RHEL系陣営がなにかしらの手を打つ可能性もありますので、現状ではどのようになるかは分かりません。

 なお、AWS上に存在するAmazonLinuxの場合、RHEL系の一種とも言えるのですが、こちらはカーネルのバージョンは既に4系となっており、yumで入るdockerもver1.9系となっておりますので、AWS上で稼働させる場合はAmazonLinuxを使うというのも手かと考えられます。



〇Dockerで使用するファイルシステムを選定する必要がある

 Dockerはコンテナのイメージや、起動したコンテナが使用するストレー ジの領域等で、データの差分管理のような事を行っています。この差分管理に起因するものなのか、Dockerでストレージを使用するような操作(起動、イメージのpull、イメージの削除etc...)を行う際には非常に動作が重くなり処理に時間がかかり過ぎてタイムアウトを起こしてしまったりする他、Dockerそのものが不調になる事もあるようです。 (「アレ?これダメじゃない?」となってDockerを早めに見限った人の理由のNo.1がコレと予想)

 この現象は主にデフォルトで使用されるストレージ関連の機構であるDevicemapperに大きく起因しているようですので、まず最初にストレージ関連の整備を検討した方が良さそうです。具体的にはbtrfs、overlayfs、aufs 等を使用する事によりこれらの症状は劇的に改善する可能性があります。

 ただし、前項でありましたように、overlayfsはRHEL系ではカーネルのバージョンが足りていませんし、実質ext4以外のファイルシステムと組み合わせてoverlayfsを使用する事が出来ない等のクセがあります。また、overlayfsはストレージ関連で一番新しい取り組みの部分ですので信頼性について若干疑問が残っている等の問題もあます。

 aufsはそもそもRHEL系ではまともに使用されている例が無いのでRHEL以外の環境に限定されるかと考えられます。(※普段RHEL系がメインな事もあり、あまり確認出来ていませんです)

 btrfsもどちらかというと新しい仕組みであり、RHEL7等でもテクノロジープレビューとの位置付けにあるようです。ただし、個人的な使用感的には快適に動作していますので、状況次第でベターな選択肢となりえるかもしれません。(データディレクトリの削除を行う等btrfs領域を直接触る際にはbtrfs的サブボリュームの取り扱い方法等を知っておく必要はあります)

 「あれ?結局現状で使えるまともなファイルシステムの選択肢ってないの?」と思ったかもしれません。そのような場合の為にオープンソース的な空気とかを読みつつ華麗に身をかわす訓練等をしておく事が重要かもしれません。(=゚ω゚) …

dockerと付き合う為の虎の巻 その00

 さてはて、現在巷ではDockerが大変話題になっておりますが、皆さんDocker使ってますでしょうか?

 実際にDockerを使ってみると、結構色々なと部分で「アレ?これダメじゃない?」とかなる事も多いような気がしています。しかし、色々調べると、それらはDocker特有のクセのようなものでして、その辺りを分からないまま使うと色々とハマってしまうというのが正確な所のようです。簡単に言えば「Dockerの流儀のようなものがあらかじめ存在」していて、「そこから外れた用法をすると一気にハマる」といった印象を持っています。

 しかし、既にDockerが話題になり始めてから結構な時間が経過しておりますし、色々とDockerについて紹介しているブログ等の情報も豊富になって来ておりますので、そろそろ要点をまとめてシリーズ化出来ないかなという事で、何回かに分けてまとめて行けたらなと考えています。

 題して「Dockerと付き合う為の虎の巻」です。なんだか表現が偉そうなのはブログ的な盛りの事情なのであまり気にしないでください。(=゚ω゚) キニシナイ

 では次回以降からちょっとづつ虎の巻を書いていってみようかなと思いますのでツッコミとかあればよろしくお願いいたします。


2016年2月12日金曜日

ConsulのDockerコンテナを作成&公開してみました

 前回の「consulを頑張って理解する」のスライドの最後の方に記載があるのですが、ConsulのDockerコンテナを作成して公開しております。

 内容的には起動時の引数指定を環境変数から行えるようにしただけのものなのですが、ConsulはGo言語性の単一バイナリで動くHashiCorp社のソフトウェアですので、あんまり複雑な事をするよりも、出来るだけ簡潔にした方が良いかなという目論見で特別何もしないコンセプトで作成してみました。

DockerHub
https://hub.docker.com/r/masakazuwatanabe/consul/
https://hub.docker.com/r/masakazuwatanabe/consul-client/
https://hub.docker.com/r/masakazuwatanabe/consul-server/

GitHub
https://github.com/masakazuwatanabe/consul

 ちなみに、ベースとなるOSとしてはCentOS7CentOS6/Alpineと三つ分作成してタグ分けしてありますがデフォルトのOSはCentOS7となっております。最近の海外のDocker界隈の流行的にはAlpineを使うのがデファクトスタンダードであるような気もしていますが、実運用的にはCentOSの方が扱いやすくて良いかと思いましてそのようにしてみました。(=゚ω゚) タブン

もし良かったら使ってみてやってくださいなっと!

「Consulを頑張って理解する」 を公開してみました(ノ=゚ω゚)ノ

 ブログリニューアル企画的な一貫として「Consulを頑張って理解する」を公開してみました。(ノ=゚ω゚)ノ



Consulを頑張って理解する from 雅和 渡邉


 最近docker関係を中心に触っておりまして、その流れでconsulというソフトウェアを触っていたりします。

 dockerはとても面白い仕組みなのですが、現在の所それ単独では単一OS上で使う機能しかなく、(ver1.9.0辺りからOverlayネットワーク等にも対応して来ていますが)、複数サーバをリンクさせて動作させたりとか、クラスタリング構成にしたりするとか、そのような事をする場合は別途そのような機能を持ったソフトウェアと組み合わせて使用しなければならないのが現状であったりします。

 そのような状況にこれ幸いと(?)最近名乗りを上げて活発に活動しているのがHashiCorp社のconsulというソフトウェアです。consulを使えばどんな時でもAnything OK! とは行きませんが、色々と仕組みに工夫がなされていてdockerと組み合わせて使うと面白いなと思いました。


 まあ、折角ですので詳しくはスライドの方を見ていただければなと思います。内容的には主に導入部分の説明となっておりますので、これからconsulを使ってみようという方にオススメです。

 機会があれば実践編というか詳細編というか隠していたconsulの罠とかを説明する回も作って行けたらなと思いますので、期待しないでお待ちくださいな。(=゚ω゚) ガンバリマス