2017年にもうコンテナの未来・一つのカタチはもう確定したと言え、今更感があるものの、改めてDockerとコンテナについて。 今更こんなことを書くのは、情報が溢れてくる今こそ、正しく理解し、正しい順序で学習することが重要だと切に思うから。

内容についてのお断り

  • How Toはかきません
  • あくまでも2018年時点の私見
  • 目新しい情報はない、2016年頃に書けたレベル

Dockerをこう使えとか、こうするのがいいとかの話ではなく、コンテナとDockerに関して大きな視点で現時点で私の考えを書きます。また、私自身はかなりのコンテナ推進派です。 Dockerをよくわかっている人には意味のない記事となります。

コンテナ(Docker)のメリット

何故コンテナがいいのか、コンテナをある程度の学習コストを払ってでもやる理由

コンテナとDocker

コンテナ技術はDockerが生まれる前から存在する技術ですが、今のコンテナブームは確実にDockerによるもの です。Dockerそのものについては後述します。 この記事のコンテナという表記はほとんどDocker(によるコンテナ)と読み替えて差し障りありません。

Docker Image

Dockerの最大の利点は ポータブルなDocker Imageが使えるということです。
本当にこの1点に尽きます。
Docker Image は言い換えるとベンダーロックインの無い AMI (OSイメージ)といえます。

なぜ、Docker Imageが便利なのか

ローカル開発環境の統一

恐らく最初のDockerの使われ方がこれだと思います。複数人でアプリケーションを開発する場合、開発者のマシンの数だけ開発環境を立てる必要があります(VDIでというのは無視)。まあ、大変ですよね、何人かにもよりますが、phpでもrubyでも、composerなりgemなり使えば参照ライブラリは合わせられますが、phpやrubyのバージョンまで合わせたり、もっと大きく考えればローカル環境がWindowsとLinuxでも異なりますね。

これが dockerのサービス/デーモンさえ動いていれば、1つの共通 Docker Imageを挿すだけで全く同じ環境が、開発者全員に行き渡ります。開発環境を構築するのが趣味の人もいると思いますが、突き詰めると全員が同じバージョンで開発するのは非常に厳しい事がわかります。普段気にしないですが OS + ランタイム(phpとかruby) + ライブラリ すべて一緒ではじめて完全に同じ開発環境といえるのです。

本番環境 CI/CDでも使える

コンテナ(Docker)オーケストレーションツールが出揃った昨今では、こちらのほうが目立っている感じがします。開発で使ったImageをそのまま本番へ、更にはCI(テスト)もやってしまおうとする考え方です。もちろん開発と本番で環境差異(エンドポイントなど)を吸収する仕組みは必要ですが、開発で動いたものがまるっきりそのまま本番、しかもCIもその開発で使っていたImageなので、如何に安定性・リスク回避からも有利であることがわかると思います。

OSSの playgroundとして

Docker以前は、Vagrantとかでやっていた、とりあえずローカルで試してみようは、全てコンテナでみんなハッピーです。実際にそこらじゅうのOSSがDockerイメージで提供されています。

https://hub.docker.com/r/graphiteapp/graphite-statsd/

https://hub.docker.com/_/redmine/

https://hub.docker.com/r/ceph/demo/

特に単コンテナで完結しないものも、docker-compose でお手軽に一瞬で作れます。

https://docs.docker.com/compose/wordpress/#define-the-project

では、なぜVagrantではだめなのか?ですが、2つ理由があります

  • Vagrantをはじめとして、他プロビジョニングツールについて知っていなければ動かせない
    ここはDockerの功罪とも言えますが、VagrantにくらべてDockerはツールの使い方を覚えなくても、そのOSSのReadme.mdに書いている Dockerコマンドを一発叩けばいとも簡単に構築完了です。Vagrantは少なくともrubyの知識などが少しは無いとこんなにすんなり動かせません。Docker run 一発の楽さになれると Vagrantを今更やろうとは思えない。特に複数マシンでクラスタを組む(=複数コンテナでクラスタ構成)場合はdocker-composeの安心感には到底かなわない。
  • Boxファイル (OSイメージ) が大きい
    この点もDockerと大きく違う点です。詳しくは後述しますがDockerが流行る理由は、Docker Imageデータストレージの扱いが極めて賢いからです。対してBoxファイルはかなりサイズが大きく、Docker Imageのように賢いストレージエンジンではないです。

インフラ屋のテスト

これは実際に私が使っています。単純に AmazonLinuxやubuntuなどでのサーバ構築手順などを探るために、素のDocker Imageでサクッと起動させてテストします。当たり前ですが、Docker Imageのキャッシュがあれば一瞬で起動します、Vagrantなんてトロくてもう使ってないです。AWSでEC2を建てることすらウザいです。新しいOSのイメージを探す必要すらないのです。普段使いという点では、インフラ屋が受ける恩恵のほうが大きいと感じています。

コンテナにまつわる誤解

すごく残念なことですが、巷には間違ったコンテナにまつわる must/should が蔓延しています。

オーケストレーションツールが主体という考え方

人として、エンジニアとして、本番環境での実践を考えることは間違ってはいませんが、コンテナをやると聞いて、オーケストレーションから入るというのはどうも気に食わないです。
もっと自由に考えて、気軽に使うべきだと思います。そもそもオーケストレーションツールが存在しない時代を経験している人にとって、オーケストレーションは ほしいから使う ツールであって、オーケストレーションが無いとコンテナは使えないというような must/should としてオーケストレーションを捉えるのは間違いです。

コンテナの用途はそんな矮小化したものではないです。もっと広い用途に使えるもので、どこぞの権威が言っているからオーケストレーションわなきゃ ではなく、 どうしたいかは自分で決めて、そして自分で選ぶべきです。

Dockerfileが必須 / IaC必須

必須ではない。Dockerfileが便利であること、IaCもできることには誤りではないですが、Dockerfileは所詮 Docker Imageを作る道具に過ぎないです。使わなければならないではなく、使いたいから使うのです。 実際、run /bin/bash で直接 apt install でパッケージを入れてもからの docker commit でもいいですし、Dockerfileをつかってもいい、Dockerfileが非力なら、Packerから作ってもいいです。

https://blog.james-carr.org/build-docker-images-with-packer-and-ansible-3f40b734ef4f

こうしなければならないなんて、なにもない。あなたが思うように、使いたいものを選んで使えばよいのです。

マイクロサービス化が必須

マイクロサービス化と相性が良いのは間違いないですが、必須ではないです。マイクロサービスではなとも、コンテナは有利です。1コンテナ1プロセスとかいう標語も、場合によっては無視してもいいと思います。supervisordでプロセス束ねが正解の場合もあります。コンテナに置けるベストプラクティス1なんてものは存在しない、自分たちの欲しいものを自分たちで実装すればいいだけです。コンテナにはそれを受け入れる器の大きさがあります。

永続データは入れちゃだめ

この考えは概ねあっていますが、ほとんどの人が誤解しているはず。k8sやECSなどのオーケストレーションではコンテナは使い捨てですが、素のDockerではコンテナは使い捨てではありません。正確には使い捨てもできるし、stop状態としてデータを維持することもできます。これもコンテナの使い方を矮小化しないで欲しいのであえて書きました。オーケストレーションが必要ない小規模な単発コンテナなら、本番環境だろうが、Docker run で良いです。

この点は今現時点でもDockerの課題と言えるので、逆に時代を切り開く度量のある、反骨精神溢れる若人にとってはとてもおもしろいテーマと言えます。実際にこのテーマに挑戦している先駆者もすでにいます。

https://github.com/vitessio/vitess

常識を疑え

コンテナで何が変わるか

デプロイ高速化

オーケストレーションの利用は事実上、前提になりますが、多台数マシンへのアプリケーションのデプロイについて、コンテナによるデプロイは圧倒的に早くて確実です。デプロイ方法も今は選択肢がたくさんあり、デプロイと一口に言ってもやることは様々ですが、コンテナによるデプロイは単純明快で圧倒的なスピードです。新しいコンテナを立ち上げて古いコンテナを消す。 たったそれだけです。
docker pull がどれほど早いのかは体験すればすぐに分かるはずです。しかも、pull して run するだけで新しいバージョンのデプロイ終わりです。古いバージョンの殺しなどはオーケストレーションが大体やってくれます。

IaCの最適化と役割ベースのサーバ管理の終焉

世の中の大体のサーバーは、役割ごとに1台ずつサーバを分離していると思います。 e.g. webサーバ、applicationサーバ、DBサーバなど
設計が必要ではあるもののコンテナ、現実解として、オーケストレーションは必須になりますが、この考え方を崩すことができます。
サーバはもはや只の箱で、それをどう使うかは走らせるコンテナでフレキシブルに変える考え方です。 e.g. 3台でECSクラスタ構成、昼間は web:4,batch:1 夜は web:1,batch:8 このコンテナが動く
サーバをどう使うか、どの役割をもたせるかを、今まではサーバを分離して考えていたのが、それをすべて無しにして、機能を、使いたいときに使いたいだけ使うという考え方に変えることができます。
今までインフラ屋が「このサーバはWebです、このサーバはAppです」などと管理のしやすさだけで決めていた(大半の場合それは無駄の温床)がアプリ屋の主権に戻ると言っても差し支えないです。(もちろん、主権には責任が伴う)

もう一つ、IaC (Infrastracture as Code) にも良い影響があります。コンテナ時代になり、構成管理は楽になった、というよりほとんど不要になったと言えます。
具体的に chef なり ansibleなりで構成管理をしたときに、面倒なのは、すでに動いているサーバに対して「あとからこの機能足して!」です。例えばすでに ruby2.0 系が入っているのに 2.3系でないと動かないアプリだった場合、rbenv入れますか?それともサーバー新設しますか?(動いている本番に手を入れたくない心理が強く働くので、ほとんどこちらになるはず)になると思いますが、コンテナであればrubyのバージョンまで含めて1つのコンテナなので、他のコンテナに入っている rubyのことなんて全く関係ありません。また、1台のサーバーに機能を足せば足すほど構成管理の辻褄わせなど、本来は楽するための構成管理がイライラの元になることも私は経験しています。コンテナは単純明快 別機能がほしければ、別コンテナでやればいい

もっと簡単にAutoScaling

これもオーケストレーション、ECS前提ですが、EC2+CodeDeploy+AutoscalingによるAS対応に比べて、ECS (fargate前提)によるAutoScalingは遥かに簡単で実装がたやすいです。Autoscalingの実装は簡単そうに見えて難しいです。具体的にはスケールアウト時の最新版デプロイを確実にする方法と、スケールイン時の後始末(ログをS3に投げるなど)です。ECSはこの問題に対するユーザー実装を大幅に減らしてくれます。

サーバーレスとコンテナ

そもそも異質なものなので、比較自体がナンセンスですが、私が考える用法用量について

そもそもサーバーレスって何?

ここで言っているサーバーレス については、勝手意味を狭めて定義します。
サーバーレス = AWS Lambdaのようなリソース(CPU/RAM)の完全時間課金
と限定します。PaaSもサーバーレスの一部とも考えられますが、違うものとして、バッサリ切ります。

サーバーレスは直接コストが安い

サーバーレスの最大のメリットは (ほとんどの場合において)直接コストが安いという点です。
文字通りサーバーレスとはサーバーを建てないことです。対して従来型の一般的なWebサーバの場合、使っていようがいまいが、(クエストがあろうが、なかろうが)Listenしていなきゃいけないので、サーバは動いてないといけないです。Lambdaはサーバーを動かしっぱなしにしないで、API-GWでリクエストを受けて、必要なときだけ処理が走るので、ひっきりなしにリクエストが発生するWeb
サイト出ない限り、ほとんどの場合はサーバー有りの従来型に比べてコストは圧倒的に安いです。もちろんLambdaはWeb以外にも使えます。

サーバー構築は不要だが、ビジネスロジックに集中できるは嘘

これはほとんどのPaaSも同じですが、よく言われる「サーバーのお守りをしなくていいので、ビジネスロジックに集中できる」は半分あたりで半分外れです。
確かにサーバーレスの文字通り、サーバーの構築とお守りは不要です。スケールアウトも自動でしますが、逆にいうと、やりたくても自分ではできないとさえ言えます。
じゃあビジネスロジックだけに集中できるかと言ったら、そんなこと無いです。
サーバーのお守りは意識しなくていいですが、PaaSなりサーバーレスなりが強要してくるレギュレーション

  • 最大実行時間
  • ペイロード長
  • ランタイム・ライブラリ

にあなたの実装方法をあわせなければならないです。それでビジネスロジックだけに集中とはとても言えない、少なくとも従来型ではできていたことができないので、サーバーレスにしてみんなハッピーというような単純な話ではないです。

用途の狭さ

レギュレーションもそうですが、明らかにマイクロサービスを前提としたものです。時代の流れとして、マイクロサービス化そのものは正しいと思いますが、逆にそこでしか使えない。対してコンテナはサーバーレスどころか、モロにサーバー有りですが(Fargateとかは無視)、マイクロサービスだけに用途がとどまりません、GPUだって使える。

サーバーレスについてまとめ

1.サーバーレス自体には、等しくみんなをハッピーにする力は無い = 用途が限られる
2.サーバーというものは意識しなくていいが、レギュレーションへ合わせ込みが必要 = マイクロサービス化ほぼ必須
3.しかしそれらを受け入れたとしても、圧倒的にサービス利用料が安い

暴論ですが 安いは正義

API-GW + Lambda のサーバーレスアーキテクチャと言われるものは、GAE(google)がもう10年以上前に通過した道です、技術的には。
http://write.kogus.org/articles/Y2Rtpp

GAEが流行らなくて、対するLambdaがわーわー言われている理由は100ms単位の完全従量課金にしたという1点です。

あともう一つ

  • コンテナとサーバーレスは競合関係に無いので、いいとこ取りすればいい

Dockerについて

Dockerについてです、コンテナという意味よりも狭い道具としての意味で書いています。

Dockerの2つの機能

1つはランタイムとして、つまりはDVDプレイヤーのような再生装置としての機能、ここについては特に触れません。 もう1つはDocker Imageの管理機能、たとえるとDVDそのものを作ったり、管理したりする機能について書きます。

dockerは、gitの OSイメージ版

git と dockerはコマンドとしてそっくりです。

  • git ソースコードの差分をもって、ソースコードを管理する
  • docker Docker Imageの差分をもって、Docker Imageを管理する

こう考えるとdockerコマンドの本質がよく理解できます。

  • docker build = Dockerfileの中身をもって、コンテナを作成し、stopして docker commitする
  • docker commit = stop状態のコンテナから docker imageを作成する
  • docker push = 指定したローカルにある docker imageを docker-hub や ECRに pushする
  • docker pull = docker-hub や ECRにある docker imageをローカルにコピーする

docker imageソースコード に読み替えると、ほぼ gitと同じ、というか明らかに gitを意識した作りです。 ここで重要なのは、docker imageは差分(レイヤー)で管理され、差分でダウンロード可能である点です。実にエコです。

http://enakai00.hatenablog.com/entry/20140802/1406958412

Docker hub & github

同じく Docker hub も github をもろに意識したものです。何度も言いますが、 Docker hub は Dockerfile の差分を保持しているものではなく、 docker imageの差分を保持しています。大事なのは docker image です。 Dockerfileは docker imageをつくるためのただのヘルパーです。

上記にも触れましたが、OSSのお試し環境として docker image の提供は極めて有益で、使い方ビデオを youtoube に上げるぐらいなら、 docker image を Docker hub に pushしたほうがより利用者にわかりやすいです。ものにもよりますが、今後のOSSの提供者としては、githubでソース公開 & バクトラッキングは当然、 dockerhubで機能・追加機能の紹介とやるのが良いでしょう2

Git & GitHub がやったことをOSイメージ = 本当の意味でのランタイムで実現したのがDockerです。このDocker Imageの取り回しのしやすさが起爆剤となり

  • CI/CD
  • IaC
  • 高速デプロイ
  • 開発・本番の共通化
  • ローカル開発

という数えきれないメリットを生み出した。

コンテナ化のデメリット

正直言って無いです。
あるにはありますが、メリットに対してデメリットが薄過ぎる。
マイクロサービス化の弊害は無視します、前述の通り コンテナ化 ≠ マイクロサービス化 なんで。

パフォーマンス劣化

パフォーマンスは軽微とはいうものの、当然劣化します。 ただし、私の世の中に対する感覚から言えば、ここで言われるパフォーマンス劣化は語ることすらナンセンスです。

何故か?
現状を見れば答えはあります。まだオンプレとかいう言葉がなかった頃、仮想環境(VMWareなど)で動かすほうがマイノリティーだった頃があります(この自体は体験している)。クラウドコンピューティングなんて影もカタチもなかった。
それから仮想環境が動かすのが当たり前になった。 理由はパフォーマンスの劣化よりも得るもののほうが大きかったから。
クラウドコンピューティングが出始めたころも、「こんなもの、開発でしか使えねー」と言われていたらしい。一見仮想環境よりも更にコスト効率悪いしね。
だけど、そんな上っ面のコストよりも深層で得られる見えづらいコストに対するメリットがあまりにデカかった。高いけど売れる という本当の価値。
コンテナ(Dockerと言い換えられる)も全く同じ、「開発はいいんだけどねー」だった、始まった頃は。だけど今はどう?

もちろんすべてのコンピューティング分野において、パフォーマンス劣化を受け入れられるわけはないのは知っているけど、ほぼ無視できるレベル。
むしろ仮想化のコストはバカ高だけど、コンテナならイケるというパターンも(正直レアだと思うけど)考えられる。

学習コスト

Dockerは低いと思います。問題はオーケストレーションかなと。予備知識なしだと複雑すぎるので、苦戦するところもあると思う。
まずはローカル環境のDockerを弄り倒すことから、それだけでも十分利を得られるはずです。

まとめ

  1. Docker Image が起爆剤となり、現存するいろんな問題を解決していった (= Docker Image をまず知る)
  2. Dockerだから〇〇しなければいけない制約は何一つない (= やりたいからやる、やりたい方法を選ぶ)
  3. Dockerが開発環境だけなんてもったいない!

最後に
オーケストレーションは置いといて、今現在、Dockerを使わない手はない。



1.私はベストプラクティスという言葉は大嫌い、なんか偉そうに感じませんか?「何がベストかは俺が決めるんや、アホ扱いするな!」といつも思う


2.私の提言みたいに書きましたが、すでに世の中がそうなってます。

元記事はこちら

2018年なぜ私達はコンテナ/Dockerを使うのか