まーぽんって誰がつけたの?

iOS→Scala→インフラなおじさん技術メモ

ECSの概念を理解しよう

※ 追記
結構ちょこちょこブクマしてもらっているので意外と需要あるのかな。
もし、記事見て分からないところあったら
Twitterなり気軽に質問してもらって大丈夫です!!

社内でインフラエンジニア増やしたいなと思ってECSの概念を理解してもらおうと思って書いたやつです。

問題を間に挟みつつ理解の手助けになればいいなと思ってます。

今更ですがDockerとは?

分かってる人はもううんざりかもしれませんが、一応復習。ECSの概念を理解するのに必要なコンテナを起動すると何が起きてるのかを再確認します。

普通の仮想サーバー

普通の仮想サーバーの場合は、sshでログインして、yumみたいなパッケージ管理システムでinstall、サービスをデーモンでバックグラウンドで起動しておくという感じですね。

f:id:masato47744:20171114163700p:plain

Dockerの場合

Dockerはコンテナという単位で何かのプロセスを起動する仕組みです。基本的には、1コンテナで1プロセスだけが動いていると思っていてください。 あるマシンの上でDocker Daemonが起動していて、そこに命令することでコンテナを起動することができます。

f:id:masato47744:20171114163712p:plain

Dockerが普通の仮想サーバーと違うのは、こんな風に仮想サーバー上でnginxサービスをデーモンで起動しておくのではなく、1つのプロセスとしてコンテナを起動しておくというところです。 この図のnginxコンテナは最後にnginxをスタートさせてそのプロセスがフォアグランドで起動しつづけています。それをdocker daemonがデーモンとして動かしているという感じです。

問題

Dockerコンテナで最後に、tail /var/log/bootstarp.logを実行するコンテナ、tail -f /var/log/bootstrap.logを実行するコンテナをdaemonモードで動かしたときにそれぞれどのような挙動になるでしょうか?具体的に言うと、

-fがついてないやつ。

FROM ubuntu

CMD ["tail", "/var/log/bootstrap.log"]

-fがついてるやつ。

FROM ubuntu

CMD ["tail", "-f", "/var/log/bootstrap.log"]

これらを、 docker run -d したときに該当のコンテナは生きてるでしょうか?死んでるでしょうか?

答えは動かして確認してみましょう。

普通のインフラの構成を見てみよう

ECSの構成に行く前に、普通のインスタンスでサーバー動かしてたころのやつってどうなってるんだというのを見ておきましょう。 例えば、 https://www.example.com っていうただ単にnginxが動いてるサーバーがあったとして、その場合はDNSがロードバランサーの名前に変換して、ロードバランサーがyum installしたnginxがデーモンで起動しているEC2インスタンスにリクエストを割り振って、レスポンスをそこからもらうっていう流れです。 Tips: 443がLBで80に変えてあるのはSSL終端(ssl terminate)と呼ばれてます。

f:id:masato47744:20171114164034p:plain

これを1台のEC2でdockerコンテナでやるとしたら?

ここで賢い人々は、よし、Dockerはコンテナがたくさんあげれるからお金を減らすためにEC2インスタンスを1台にしよう!と考えます。それを図にするとこうなります。

f:id:masato47744:20171114164203p:plain

そう、あえて意図的に赤くしましたが、同じインスタンスなので、ポートを変えてあげないといけないのです。あと、Dockerにはsudo権限みたいのを渡しておかないと80みたいなwell-known portは使わせてもらえないかも。(ここは曖昧だけどあんまり本質ではないので気にしないでください)

  • 要は、portを管理しないといけないってこと。ロードバランサーとコンテナのポートのひもづけはやらないといけない。
  • せっかくDokcerでimmutableにしたのに、結局はSSHログインしないといけないこと(Dockerデーモンに命令を出さないといけない)
  • これ、今インスタンス1台だからいいけど、増えたらどうすんの。辛くない?
  • コンテナ死んだらどうする?sshログインしてまたdocker起動しますか?

はい、これでECSのようなオーケストレーションツールが必要になってくるという訳です。

ECSの仕組み

ECSは正式名称はAmazon EC2 Container Serviceです。EC2というのが入ってるので、EC2をベースとしているのです。 ※ いつのまにか名前が変わってElastic Container Serviceになってました AWSのEC2を使って、クラスタ構成を作ってくれて、ロードバランサーのポートマッピングなどをやってくれて、コンテナの生死監視と自動復旧などをやってくれます。さっきあげた問題点が全て解決してますね。

じゃあ、ECSが内部的にはそれをどうやって実現しているか見てみましょう。結構単純です。

コンテナインスタンス

AWSのEC2のクラスタ構成を作ってくれる部分が最初ぼくは謎だったんですが、分かるとなんだそんな単純なことかってなります。 AWSのコンソール上から見えるClusterという概念。これは複数のEC2インスタンスを取りまとめてるだけなんですが、それをどうやって実現してるんでしょうか。 それは、各EC2インスタンスに、ecs-agentというdockerのコンテナを起動してるだけなんです!また、そのagentはOSSで公開されてます

f:id:masato47744:20171114164228p:plain

要はさっきの説明でnginxとか起動させてましたがそれと同列でecs-agentっていうのをコンテナとして起動してconfにcluster名を渡してあげるだけです。それだけで、人間は、クラスタというまとまった単位で管理できる訳です。

実際は、手動でインスタンスを起動してそこにecs-agentを入れてみたいなことはせずに、autoscaling groupというAWSの機能を使ってガッとインスタンスをたてて、そのときの起動スクリプトでecs-agentを動かします。

どうでしょう?簡単じゃないですか??

taskとは?

clusterが起動する理屈はわかりました。では、今度は、コンテナがどう起動しているかを見ていきます。これは、社内メンバーのまとめで気づいたんですが、ECSでは単にコンテナを起動して終了させるだけなら、TASKという概念でまかなえるのです。 Serviceという概念があることを知ってる人もいると思いますが、ここでは、単にTaskが何なのかを見ていきましょう。

f:id:masato47744:20171114164246p:plain

さっきDockerの問題のところでやったTailするだけの例に出てきてもらいましょう。tailだけを実行するコンテナを実行するための情報のことをTask Definitionといい、それをもとに、ECSがコンテナを起動してくれます。起動されたコンテナのことはTaskと呼ばれます。 Taskの場合は、コンテナが死んでようが生きていようが気にせずに、単にコンテナを動かすだけになります。この場合は、コンテナはtailコマンドを実行したあとすぐにkillされてしまいます。これがTaskの一生です。 この1回起動したら、死んでよいというのは、バッチのジョブなどに向いています。

Serviceとは?

ECSを構成する概念の一つです。 オーケストレーションツールなしでDockerだけで運用する場合の問題としてコンテナの死活管理がありましたが、それを解決するものです。

通常のWebサービス等でECSを使う場合は、下記の理由でServiceを使うことになります。

  • 基本起動しっぱなしでリクエストを待ち受けて欲しい
  • 死んだら再起動してほしい
  • 外部からの接続を受けてポートマッピングして欲しい

図に表すとこうなります。リクエストがきて、ロードバランサーで各コンテナにリクエストが振られるところまでは基本的に何も変わりがありません。ただ、各コンテナがServiceというくくりでまとめられているところが違います。

f:id:masato47744:20171114164258p:plain

では、Serviceのすごいところを説明していきます。 まず、Serviceというか、ALBというApplication Load Balancerのすごいところでもあるんですが、ポートを動的にマッピングしてくれます。 さっきのDockerの例だと、同じインスタンス内でポートがかぶらないようにと人間が気を使って設定していましたが、それはやる必要がなくサービスがやってくれます。

次に、desired count=4というところです。これはどういうことかというと、コンテナ4つたててくれーって指定しておいたら、コンテナが死んだとしても自動的に復旧してくれます!desiredとは人間が要望している数ですね。それに従って機械が何度でも復活させてくれる訳です。

もう一つ、これは完全にそうとは言えないんですが、ある程度賢くコンテナを分散して配置してくれます。この部分は設定をがんばったりしないといけないので、完璧とは言えない部分ですが、そういうこともやってくれるという訳です。

問題

ここまでを踏まえて、以下のことをやってみましょう。

  • 手動でインスタンスをたちあげてECSクラスターをたててみる
  • autoscaling groupでECSクラスターをたててみる
  • 何かサービスを動かしてみる