dockerは求めていたものをすべて提供してくれた

dockerは自分の中で、ここ数年で最も感動したプロダクトだ。dockerは私がクラウドに求めていたものを全て提供してくれた。これは、素晴らしく、正義であるいえるプロダクトだ。

 
 
おおよそ7年前、仮想化、クラウドという言葉が出始めた頃、二つのクラウドプロダクトがあった。一つがPaaSに当たるGoogle App Engine(以下、GAE)。もう一つは、IaaSに当たるAmazon Web Service(以下、AWS)だ。私は、GAEに熱狂し、GAEが天下を取ると予測した。何故なら、開発者は本来プログラムやサービスのことを考えたいのであって、サーバやネットワークと言った、インフラのことは本当は考えたい訳ではないのだ。ロードバランスだとか、データの整合性と言ったものは、Googleが提供するインフラに任せることができて、プログラムやサービスに開発者を集中させることができる。AWSだとインフラを自由にプログラムすることができるが、それが開発者がやりたいとは思わないだろうと思っていた。
 
しかし時代はGAEではなく、AWSに傾いた。GAEでGoogleの支援に乗るには、プログラムも、データベースも、GAEのフレームワークに則ったものでなければならない。それはそのフレームワークにロックオンされてしまうため、一度乗れば乗り換えることができなかったり、時代に追いつけなかったりする。世の中は、開発者の自由にフレームワークを選び、インフラのことを悩ませるAWSに、流れていった。
 
でも、私はいつかPaaSの世の中になり、インフラやミドルウェアのことは考えなくてもいい未来が来るのではないかと願っていた。
 
社会人になって、プライベートクラウドというものに触れた。一つの巨人のように強力なサーバの中に、いくつものこびとのような仮想サーバを住まわせるものだ。OSは巨人(ホストOSという)にもこびと(ゲストOSという)にも乗っており、OSのメインの仕事であるスケジューリングは二重に行われる。このロスを削減するために、CPUには仮想化のための命令セット(Intel VTとか)が実装された。
 
しかし、ミドルウェアの問題はこれでは解決されなかった。ステージング環境と本番環境があったとして、それぞれの環境にそれぞれミドルウェアをセットし、ソフトウェアをデプロイした。ここで、それぞれ設定が人の手によってされるものだから、誤ってしまったり、正しいかどうか判定できなかったりした。
 
で約2年前、Imutable Infrastructureと言う言葉が登場した。これは、インフラやミドルウェアは全てプログラムで組み立てられれば、いんふらやミドルウェア修正は、プログラムと同じように、一度捨てて最初から作り直すことで、必ず同じ環境を作ることができるよねということだ。これは正しいことだと思い、Chefを勉強した。しかしChefは、ミドルウェアの設定を抽象化して管理しており、今ひとつ実態がつかめなかった。確かにChefで記述するレベルのことしか考えたくないのだが、実際活用するには、もっと降りていかなくちゃ行けないのだろうと、雲をつかむ感じがした。その通り、Chefより抽象度の低いAnsibleの方が流行っているように見える。
 
このImutable Infrastructure、難点が二つあると思っていた。一つは、毎回環境を捨てて組み直すのは結構時間がかかりコストだと言うこと。もう一つは、プログラムは環境ごと入れ替えできても、データベースを捨てる訳にはいかないことだ。
 
データベースが捨てられないことについては、プログラムを切り戻したりしても大丈夫なように、洗い替えのいらないKey-Valueストアで、データを管理すれば良いという結論を得た。新しいバージョンのプログラムが走った後に、不具合が見つかってバージョンを戻すことになっても、Key-Valueストアの新しいプロパティは前のバージョンは知らないまま置いておかれる。それでも問題がないデータベースを設計すれば良い。簡単ではないが、RDBよりもImutable Infrastructureを実現できると思った。
 
そして去年登場したDockerは、今までの問題を全て解決していた。dockerは、Linuxカーネルの機能を利用して、コンテナと呼ばれる独立した実行領域を用意する。OSはホストOSのみであり、プライベートクラウドにあった、二重管理はそこにはなく能率が良い。そしてミドルウェアはそのコンテナの中に自由に組み込むことができる。コンテナの中のミドルウェアの設定は、Dockerfileという抽象化されていないスクリプトで記述される。記述し実行した結果はキャッシュされ、二度目実行する際には、変わっていない部分は再実行されない。毎回環境を組み直すコストは、Dockerには発生しない。
 
まとめると、Dockerは以下を解決している。
 
* 仮想化で発生したOSの二重管理はDockerでは発生しない。Linuxカーネルの機能で利用域の分離を行っている。
* ミドルウェアの組み込みは、抽象化されていないスクリプトで行える。
* 組み込んだ環境はキャッシュされるため、リリースのたびにミドルウェアを組み直すことはない。キャッシュごと移せるから、マシンを移しても再現性が高い。
 
最後に最初に戻る。開発者はインフラのことは考えたくないから、PaaSが流行るだろうと期待した話。これは、OSの仕事になって、プログラムから分離された。CoreOSが、コンテナをロードバランスして提供する専用のOSになっている。このように、インフラの仕事は、プログラムからミドルウェアごと隔離されて、管理されるようになってきた。そのなかで、プログラムは好きなフレームワークを使って開発することができる。これは素晴らしい。
 
以下が、今自分のメインサイトに使っているDockerfileである。コンテンツと同じgitリポジトリで管理している。

 

# 元イメージはDebian
FROM debian:8.1 
MAINTAINER 74th<site@j74th.com> 

# apt-getをそのまま書ける。抽象化されていない。
RUN apt-get update 
RUN apt-get install -y apache2 libapache2-mod-php5
# ミドルウェアの設定も一緒に管理しているから、ミドルウェアによる環境差異がない
ADD ./etc_apache2/apache2.conf /etc/apache2/apache2.conf 
ADD ./etc_php5/php.ini /etc/php5/apache2/php.ini 

# ポートは80を外部公開
EXPOSE 80 
# /var/wwwはコンテンツをマウント
# /var/log/apache2はミドルウェアのログをマウントディレクトリに出力
VOLUME ["/var/www", "/var/log/apache2"] 

ENTRYPOINT service apache2 start && tail -f /var/log/apache2/access.log

実行時のコマンドは以下。"-p 80:80"がないのは、もう一個nginxのコンテナが動いているから。

docker build -t 74th/mainsite
docker run -d \
    -v `pwd`/www:/var/www \
    -v /var/log/apache2:/var/log/apache2 \
    --name mainsite \
    74th/mainsite
再度言う、Dockerは求めていたものを全て提供してくれた。Dockerは素晴らしく、正義である。