PlayStationTM Network での Container 導入事例
PSNの開発と運用はグローバルでいくつかの拠点で行われている。
各拠点が機能を区切って担当している。
東京拠点がゲーム機能を担当。
PS4販売昨年で7000万台以上、ゲームプレイ時間は1週間に8億時間以上。
PSNアクティブユーザー8000万人以上、70カ国にサービス提供。
東京拠点でフルスクラッチでコンテナのCI/CDを実現してサービスインした話。
尖った事や斬新な事は行っていない。
東京拠点の規模
100近いサービスがあり、数千のEC2インスタンスが起動している。
Dev,Ops,Secのチーム構成。
上記のチーム構造だとシステムの構造そのものになってしまう -> コンウェイの法則。
サービスデリバーなどを考えると、EC2インスタンスにとっても開発と運用で違う技術を使ってしまったり、開発が作ったものを組織をまたぐために、一度リリースしてデプロイの準備をしてデプロイを行う。このような仕組みは悪くはない、DevとOpsそれぞれの成果でちゃんと機能するが、100近いサービスがある為、デプロイするのに1つのサービスが1日以上かかる場合がある。例えば100個1日1デプロイすると単純計算で100日かかってしまう。しんどい。
ユーザーにより多くの体験を届けたい。1サービスに1デリバーだと、そんなに多くの体験を届ける事が出来ない。
この時サービスをデリバーする部署が新設された。
(3人のエンジニアが立候補。現在は10名程度のチーム)
目標
外にフォーカスしたCI/CDの仕組みを作る。
アベイラビリティは非常に重要。速度だけを求めるのではなく、アベイラビリティを下げることなく、迅速かつ効率的にサービスをデリバーすることで、1日に100回のリリースとデプロイが出来、本番運用可能な基盤構築を目指した。
開発から運用まで分かれていたものを最適化を図る。
セキュリティも全てにおいて、最優先に扱う。
企画(プロジェクトヘイクト)
へイクトCI/CD。
コンテナの作成、開発、デプロイ、運用に至る全てを提供する。
継続的インテグレーション、継続的又は手動のデプロイ、コンテナの実行環境(開発、本番)、Dockerのベースイメージ、セキュリティにオペレーショナル・エクセレンスが済んだものを構築するプロジェクト。
目標にセキュリティが出てくるのは、セキュリティは重要で、セキュリティに問題が起こると、ユーザーがゲームを楽しむことが出来なくなる。7日間で8億時間なので、1日落ちてしまったら、1億時間ゲームを楽しむ事が出来なくなる。ユーザーに安心して遊んでほしいので、ユーザーのプライバシーを全力で守る。
方針
シンプルかつ必要最低限に。
本当に必要なものだけを作る。
少しのコードを書いて、動かせばそこから運用が始まる。
本当に最後まで運用出来るのか?をちゃんと確認しないと作成しない。
マネージド・サービスを活用する。
色々不便があるが、出来ない事があっても、実はそれは要らなかったりする。
ベンダーロックインに常に意識しているが、それでも便利に利用している。
結果的にAWSの薄いラッパーやフレームワークを作っていることが多い。
迷ったら目標を思い出す。例えば、何かの選択肢があったら、それは1日100回デプロイ出来る選択肢なのか考えたり、あまり悩まずまずは動かしてみようというスタンスだった。
なぜコンテナか
2016年当時、コンテナインスタンスとファンクションがあった。
当時のファンクションはあまり汎用的ではなかった。
AWSが面倒見てくれるのであれば、放おっておけば機能拡張してくれるだろうと思い、
コンテナにフォーカスすることにした。
システム構成
コンテナ基盤
* ECS
* ECR
* ALB
* Route53のサービスディスカバリは未使用
なぜECSなのか
2016年当時はk8s,swamが発展途上だと思った。
一番大切に考えたのがコンテナ化する事。
Dockerを採用してDocker化する事に注力し、将来どこかの時点で、オーケストレーションツールを切り替えるにしても、その時コストは低く抑えられるだろうと考え判断した。
運用監視
ログ、メトリクスをAWSに集約。
ログはkinesisからS3、メトリクスはCloudwatch、これらを処理するのはLambda。
コンテナからはFluentdで送信。
失って良いようなものはS3に、失っていけないようなものは、kinesisからkinesis firefoceに。
CI/CD
Githubの裏でcodepipelineで簡易フレームワークを作成。
エンジニアがコードをcheckinすると、Lambdaがhookされ、Lambdaがcodepipelineをhookし、テスト、DockerImageのマニュピレーションし、一番最後にステージング環境にデプロイする。
いろんな箇所にCodeBuildを使用している。(最初はECSを使用していた)
これらの情報をユーザーにフィードバックする。
ポイント
AWS Well-Architected Frameworkを使用して、設計の良い目次になった。
見逃しているポイントに気付く事が出来る。
基盤の環境構成のポイント
ステージング、本番環境を完全に同一にした。
異なるのはインスタンス数の差異のみ。
ステージング環境と本番環境の構成が違う事によって、構成の違いによる問題を早く気付く事が出来る。又、CloudFormationを使用しているので、容易にデプロイする事が出来る。
Subnet設計は、AWSVPCModeを使用すると、インスタンス数に更に上に乗せるコンテナまですべてEMIを使ってしまい、LambdaVPCとかを使うと更にインスタンス数より多くのIPアドレスを使用する。こんなにたくさんIPアドレスを使用するからサブネットを大きくすれば良いのかと思うかもしれないが、AWSのサービス毎にアタッチ出来るサブネット数が違ったり、巨大なサブネットを作成してしまうと、NatGatewayが分散出来ないので、NatGatewayに障害が起きてしまうと、サブネットが全滅してしまう可能性がある。それらを考慮して、あまりサブネットをアタッチ出来ないEMPは、大きめのサブネットを使用し、ECSタスクに使用するサブネットは、たくさんうまい具合に分散出来るようなサイズでIPアドレスをたくさん持つように設定を実施した。
ホスト
高速で安定した起動を優先した。
AMIは高速ということでGoldenAMIを使用している。
ECSクラスタは、単一の共通クラスタを作成した。(管理が簡単、リソース効率がいい)
クラスタにはオートスケーリンググループを設定し、スケールイン・アウトしている。
ENI数1インスタンスごとに最大アタッチ数が異なるので、CPUやメモリだけでなくENIも気にしている。
ECSタスクの設定は、全インスタンスで共通のリソース設定にした。
例えばどのサービスであってもTomcatはCPU1コア、メモリ2GBにすると、非常にチューニング、サイジングが簡単になり、性能はスケールアウトで、最適化したいときは後でやればいいと思った。
PersistのAutoScaleは、標準のメトリクスで足りないものが多い。
コンテナ単位で、セッション数、コネクション数だったり、ミドルウェアのスレッド数、コネクション数を取って、スケールイン・アウトを行っているが、設定は慎重に行っている。たくさんのメトリクスがあり、それぞれのメトリクスごとに、スケールアウトがするが、他のCPUをたくさん使用しているのに、メモリをあまり使わなくなったからスケールインをして良いわけではないので、すべてのアラームが収まった時だけスケールインする仕組みを導入している。
PipelineはPRとPushとReleaseの3種類。Githubのライフサイクルに近い。
アプリケーションのビルドとテストをして、DockerImageを作成して、開発環境に登録するものと、ステージング環境までデプロイするもの、本番環境のレジストリにイメージを登録するものがある。PipelineはGitBranchモデルを適用しているので、git-flowを適用しているので、git-flowでうまく動作するように、主要ブランチ毎のPipelineを作成した。1つのpipelineの中で、2度実行すると追い越しが出来なく、3つ目は処理が捨てられたりするので、なるべくbranch、pipelineを分けるようにしている。
デベロッパーへのフィードバックはSlackで情報を集約。
AWSはUIが弱い。デベロッパーエクスペリエンスの向上にはGithub、Slackに情報を集めるのが良い。
サービスデリバーは役割により、異なる人数、異なるソリューションがある。
Devの人は、ステージング環境までのCDパイプラインは、開発者はGithubのマージでデプロイをする、Codepipelineと、ECSのサービスアップデートを用いている。
本番環境のデプロイは、慎重に行う必要があるが、Opsの人は信頼性とガバナンスも非常に重視する。例えば既存の変更管理のプロセスに合致するプロセスが必要で、このような事をマニュアルで扱う独自実装ツールを足して実装した。
本番環境のデプロイツールは、CLIのstep functionのワークフローを使用している。
step functionから実行されるECSやLambda functionは、CloudformationでECSや色々なサービスを操作している。
カナリーテスト、BlueGreenDeployment、AutoScaling、承認者による承認プロセスは、独自実装する必要があった。
なにか問題があればロールバックするし、任意のバージョンにも戻る事が出来る。
進め方
本体の開発をして、一番最初のテストベットは、社内利用サービスを1つ移行してみた。
何か問題が起こってもいつでも切り戻しが可能なのと社内だけで影響範囲が済むから。
次に本番への移行を実施。
3つのサービスを移行した。
なぜすでに本番で動作しているサービスかと言うと、問題があった時、すぐに地盤を切り戻す事が出来るから。
最後のステップとして、最初からコンテナで開発するネイティブ開発を実施した。
やってみて
約2年間かかった。
基盤調査からアーキテクチャ設計と開発までに9ヶ月かかった。
ここから1度サービスを置いてみて、ひたすらチューニングした期間は10ヶ月。
最初の移行サービスのDockerlize期間は7ヶ月。
一番最後のネイティブ開発は、最初のサービスをステージング環境に導入するまで2ヶ月かかった。
Dev,Ops,Secのチームの役割が変わってきた。
一番最初はすべて自分達でやっていたが、徐々にOpsの人に入ってもらい、まずは使ってもらうことにした。最後にDevとOpsがPipelineもコンテナもサービスの構築運用も全部DevとOpsの人が出来るように、自分達で運用出来るところまでもっていった。
組織
たくさんの人との連携が必要だった。
Dockerの導入するときに難しいのは、境界が複雑で曖昧になる。
コンテナやOSにミドルが含まれてしまう、だいたいOSやミドルはOpsが担当することが多いが、デプロイを一部Devが行う点で、DevとOpsの境界が複雑と曖昧になる。なので多くの人と議論を行い、多くの人と理解、協力を得る必要があるので、Dev、Ops、Secの人たちを最初からたくさん巻き込んだ。
Dev
一番最初に巻き込んだ。開発者は新しい事にチャレンジするのに積極的だったが、一番最初に基盤を作って、何か動くというところまで持っていかないと、何もないところから使ってみてと言われても出来ないので、まずアーキテクトの方、今の仕組みに詳しいと協力しながら基盤を作成し、その後に実際にサービスを持っている部に協力してもらった。
最後に基盤に導入すると、既存のフレームワークだったり、既存のソフトウェアのコンポーネントを変えなければならない。環境変数の設定、ECSTaskのIAMロールの対応など。
内製のフレームワークをメンテしてる部に対応してもらった。
開発マネジメントの工数確保は非常に重要。それとは別にスクラムチームの参加があった。
Ops
技術好きが多く、コンテナに興味津々だった。
インフラチームを巻き込んだのは勿論だが、サービス運用チームは、運用マネージャーのアドバイスを受けて、サービス運用チーム内で、有志を募い8名のエンジニアが参加するワーキング・グループを作成し、有志なのでモチベーションが高かったので、元々タスクを持っていたオートスケーリングを実現したり、トラブルが起きた時のhotfix対応どうするか、など巻き取ってOpsのチームが進めてくれた。
AWSの人には導入前後に助けてもらった。
Sec
セキュリティはとても重要だが、最初からちゃんとしたセキュリティを導入すると、導入コスト、作業コストが下がる。最初に相談した時からSecの人は協力してくれた。
セキュリティはとてもむずかしい。専門知識が必要。
インスタンスとコンテナでどうハンドリングを異なるようにするのか。
コンテナの攻撃事例って例えばどういうものがあるのか。
セキュリティのオペレーションにはどんな変更があるのか。
上記らを一緒に相談し、解決した。
Dev,Ops,Secと、分かれた組織であっても、すべての要素が必要だったので、すべて必要な人を最初から巻き込んだのが、今回うまくいった原因だと思っている。
作成したシステムは仕組みが根本から違う。
導入は非常に大変。
開発も運用もみんなの理解を高める必要がある。
伝え広める為に、毎月デモデーを開催し、DevとOpsの人に任意で参加してもらい、進捗、課題、の状況を共有した。
一番最初はCIPipelineの話をした。
開発スクラムの人と一緒に、実際に開発するトライアルを実施し、進捗、課題、の状況を共有し、フィードバックももらうようなコミュニケーションを取った。
専用のSlackチャンネルを用意して、開発、運用の人達とのコミュニケーションの場にしている。
学習コストは非常に高い。
スクラムチームの学習コストを上げるためのオンボーディングプログラムを開発して実施した。
Pipelineを容易に設定出来るスキャフォールディングツールの提供とかそれらを使用したコンテナ開発のハンズオンの実施など。
リスク
リスクを管理して小さくしながら進めた。
一番最初にテストベットを作成し、テストベット移行はOpsの人に任せた。
テストベットから11ヶ月後、2018年3月にお知らせ系のサービスをデプロイした。
2ヶ月後にトロフィー系のサービスをデプロイした。
この時、タスクの数が一気に増えた。
タスク数5、1タスク3コンテナで動作して、1500コンテナが動作。
リスクを減らす為にステージング環境から本番環境へ。
コンテナのサイズは全環境同じで、タスク数が環境毎に異なるくらい。
アプリケーションの設定やネットワークの設定には多少差異がある。
慎重に進める為にやったこと、やらなかったこと
やったこと
移行手順の整理、レビュー
サイジング
何が起きるかわからなかったので余分なキャパシティを確保
カットオーバーの期限
どういう条件になったらサービス運用するのか
パフォーマンスにどういう違いがあるのか
いざという時の為に既存サービスに戻す手順
やらなかったこと
オートスケーリング、まず基盤を動かしてみる。オートスケーリングをやらない代わりに余剰キャパシティを確保した。
結果
トラブルはあったがユーザーに影響はなく、エラーの変動もなく、問題なく進行することが出来た。
トラブルはステージング環境で全て解決出来た。
問題が起こった例
- コンテナが落ちた
- コンテナが生成出来なかった
- クライアントから接続出来なかった
- ALBが同じVPCの中のNodeでしか動けないので、コンテナが登録出来なかった
- 本番環境でも問題が起きたが、リトライと自動復旧で、対処出来た
達成できたこと
速度。今まで1日かかっていたものが、Githubへのマージから、ステージング環境へのデプロイまで、20分で出来るようになった。(テストが長いともっと時間がかかるが、自分達で作成した本番環境へのデプロイツールや、そもそもコンテナの起動が早いので、Opsがする作業も含めて2.5倍早くなっている。
インスタンスからコンテナに変わることで、今までサービスの起動が分単位だったのが、秒単位になった。
ALBのヘルスチェックが結構時間がかかってしまう。
Docker、コンテナ、serverless、は、エンジニアを元気にする。
Slackチャンネルでの盛り上がり、ログインを簡略化するツールの作成してコントリビュートしてもらった。
課題
開発者の開発自体の加速の体験。
ラップトップPCで開発していて開発が早くなったという体験はなかった。
AWSはクライアントへのリーチが弱い。
k8sも良いかもしれない。
コンテナ化したら、今までインスタンスで動いていたものが、コンテナ専用のアーキテクチャを導入しないといけない。たくさんの依存関係がある場合、依存先もコンテナ化しないといけない。テストも大変になる。サービスのデカップリング、コンテナデザイン、service mesh、アプリケーションアーキテクチャの検討もしなくてはいけなくなる。
AWSのサービスをCI化しようとしたら、AWS用のコンテナがない。テスト実行時、マネージドサービスを動作させるのは辛い。
Opsの調査で見るべき箇所が増えた。ログも分散してしまったので、ログを集約したい。
共用クラスタのような複数クラスタをどうやってコスト配分すれば良いのかが今問題になっている。
見やすくなったが、何が問題なのかわからないのも新しい課題である。
AWSのサービスはたくさんありすぎて困っている。どう理解してどう使用するか、AWS提供の機能とかは、簡単なのが多いが、どうしても必要となったら自分達で作る必要がある。AWSの世界では多く便利であるが、Dockerの世界では別のものを作らないといけない。AWSのコンポーネントは似たようなものがあるがどれを使ったらいいのか困る。
AWSの変化は本当に早い。マネージドサービスを導入して、仕組みを作りそのまま放っておけば良いのではなく、継続的に変更をキャッチアップすることが必要。
Bootstrap機構、環境変数の持ち回し、デプロイツール、LaptopPCからタスクを起動するツール、セキュリティのインテグレーション、 ログ周りetc...コンテナ周りは色々作成した。
今後
変化への対応をどうしていくか、2014年に今の環境になっているとはまったく想像していなかった。
未来を予測するのはかなり難しい。
来年、 コンテナとfunction、どちらが優勢になっているかわからない。
変化を受け入れる、変化する前提で進める。
変化しにくいものから交渉していく。
オーケストレーションツールよりもDocker化から。
作りすぎないこと。作れば変化を妨げる。そこから運用が始まる。
捨てる勇気をもつこと。マネージドサービスに同じような機能があったら、マネージドサービスに作ったものを捨ててでも移行しても良い。新しいデファクトスタンダードが出てきたら、勇気をもって採用するのも必要。
Dev/Ops/Sec、CI/CDの流れは、人の変化を必要とする。
DevにしてもOpsにしてもSecにしても、1つとして欠かさず全ての要素が必要。ますます重要になってくる。
CI/CDの流れは、Dev/Ops/Secの境界線を曖昧にし複雑にする。変化に備える必要があるが、人の変化はとても時間がかかる。Devの人はOpsを、Opsの人はSecを、と言ったような自分の持っていない要素を持つ人を見つけたり、何か新しい事へのチャレンジ、一緒に取り組む仲間を見つけると良い。
コミュニケーションはとても重要。
多くの価値を作る事にたくさん時間をかける為に、コンテナとserverlessは非常に良い味方になる。
ビズリーチ社のサービスを支える AmazonECS と AWS Batch の活用事例
ハーモスの事例
コンテナ化前後のアーキテクチャ
- CF
- ALB
- EC2 -> ECSTask
- SQS
- RDS
- ElastiCache
ECSを利用するためにECR、Cloudwatch、Lambdaが必須で必要。
ECSについて
マネージドオーケストレーションサービス。
コンテナ毎(実際はtask毎)、EC2のインスタンスプロファイルで、アクセス制御が可能。
0ダウンタイムでデプロイが可能。
スケジュールもしくはCloudwatchアラームを組み合わせてオートスケールが可能。
ECSの概念
クラスタ: コンテナインスタンスをまとめたもの。コンテナのホストとなるコンピューティング環境の単位。
コンテナインスタンス: クラスタとして扱われるEC2インスタンス。EC2エージェントとDockerが含まれるECS用のAMIで起動。
タスク: 1まとめにして扱われるコンテナ、web,appをまとめて起動する時にタスク内に、2つのコンテナを入れる形になる。DockerComposeと似たような概念。
タスク定義: タスクの設定ファイルのようなもので、image,port,volumeを定義する。docker-compose.ymlに書くようなもの。
サービス: タスクを管理するもの。クラスタとかタスク数とかデプロイ戦略みたいなものを定義するもの。
ECSクラスタは、EC2エージェントとDockerが入ったEC2を管理し、
EC2上には、タスクが動作していて、
タスク内には、複数のコンテナが入っており、
同じタスクをまとめたものがサービス。
コンテナ化して良かった事
アプリケーションの成果物が本番でもローカルでも同じになった。
これまで環境毎にビルドしてデプロイをしていたので、同じだろうけど同じかどうかわからない状態だった。
リソースを共有出来て、効率的なリソースの使い方が出来るようになった。
水平スケールが容易なので、コンテナを並列に並べることが可能。
インフラコードと、コンピューティングリソースからのアプリケーションの分離が出来るようになった。
それまではterraformとかAnsibleとか使っていたが、どうしてもアプリケーションを起動するための設定やコードが入ってしまって、
アプリケーションなのに、インフラエンジニアが触らなければいけなかったが、
完全にアプリケーションとインフラが分離出来るようになり、
immutable infrastructureで、Ansibleは使用しなくて良くなったし、
ロールバックやBlueGreenDeploymentが可能になった。
サービスの規模感
ECSサービス数: 30
ECSタスク: 45
EC2インスタンス: 24
上記は最低限で、これにAutoScalingすると増加する。
リソースが共用するようになったので、モジュール毎にクラスタを分類した。
CPUを多く使用するものと、バッチ的な常時起動しなくていいものと、それ以外で分類した。
クラスタのインスタンスタイプもそれに応じて構築した。
CPUを多く使用するECSクラスタは、CPU強めのECSクラスタを使用して、主にオンライン非同期系の多めのAPIを動作させていて、画像処理やアプリケーションジョインしているものはホスト的にあまりスケールアウトしたくない為、シビアなオートスケールの設定をしている。
メモり多めで安めのインスタンスを使用したECSクラスタを使用して、オンライン同期系の軽めのAPIとか、非同期系の処理(画面からの一括操作、メール送信処理)を動作させていて、気軽にスケールアウト出来るようにしている。
バッチ処理は、最初はバッチ用のクラスタを作成していたが、AWSBatchが後発で出たので、AWSBatchを使用して、定時バッチ、ファイル系の処理をしている。
AWS Batchの概要
ECSとジョブを登録するキューがセットになっているもの。
ジョブキューにジョブページを送信する事で、ジョブ(ECSのタスクと一緒のもの)を起動する事が出来る。
ECSクラスタとジョブキューがあり、ジョブ定義をキューに入れるとジョブが動く。
AWSBatchの良いところ
単純なバッチ処理基盤としてすごい便利。
EC2の管理がまず不要。
スポットインスタンスが使用出来る。
リトライ処理が自動で楽。
処理の成功失敗がダッシュボードで見れる。
料金は実行時間のみ。
AWSBatchの使い所
Lambdaにさせるには重いような処理。
ドキュメントのPDF化処理。
アップロードされたファイルのウィルススキャン処理。
論理削除したデータの物理削除。
AWSBatchの残念な所
Cloudwatchの処理結果をCloudwatchで見れない。
インスタンス、コンテナを起動するので、起動までに1分くらい時間がかかる。Lambdaのような俊敏性はない。常にコンテナインスタンスを起動させておいても数十秒かかる。
環境について
コンテナ化して環境が作成しやすくなったので、既存の環境に加え、
PR(プルリクエスト)環境、ステージング環境を作成した。
マイクロサービス化しており、1つのモジュールだけを修正するのに、他のモジュールを起動させないと開発出来ない状態だったので、ローカル環境での開発は、開発対象となるモジュールをローカルで実行し、それ以外はPR環境にアクセスして使用するという仕組みにした。
PR環境は、PullRequest毎に環境のサブセットを作成して機能テストを行えるようにした。
PR環境用のECSクラスタを作成。
スポットインスタンス上で作成されているので、割安で運用している。
開発環境は本番と同じ構成になっている。
結合テスト、システムテストに使用。
EC2スポットフリートを使用していてコストを抑えている。
ステージング環境と本番環境は同じ構成。EC2スポットフリートは使用していない。
CI
テスト実行後、Dockerイメージを作成し、ECRにpushし、CIはタスク定義を更新する。
その後、ECSが勝手にタスクの更新をする(ECRからイメージを取得し、クラスタに配置)。
環境毎にDockerイメージは同じだが、ホスト名やDBのクレデンシャルとかは、環境毎に差分があるので、
それらはParameterStoreなどに入れて、docker-entrypoint.shの中で読み込むようにしている。
デプロイオプションで、サービスの定義であるタスク数、最小並列数を指定している。
最小並列数を100%にしておくと、必ずタスク数は3は確保してくれて、タスクを更新すると、一旦新しいタスクが増えて、古いタスクがその後シャットダウンして0ダウンタイムが出来る。
タスク配置戦略
用途に合わせて選択しないと、うまくスケール出来ない。
bin packは、タスクのCPUやメモりの使用量で可能な限り1つのインスタンスに詰め込むタイプ。
spreadは、条件を指定して、均等に分散して配置するタイプ。
randomは、用途不明。
Rollback
簡単で、コンソール画面から前のタスクを指定して選択するだけで、rollbackされる。
メトリクス
サービスごとのCPUとメモりの使用率を取得している。
コンテナ内のメトリクスを取得したい場合は、Datadogを使用して監視している。
オートスケール
taskのオートスケールと、コンテナインスタンスのオートスケールの2つがある。
AutoScalingグループでする。
Cloudwatchアラームを使用して、メモりとかCPUの使用量をトリガーにして、スケールアウト/インしている。
オートスケールは難しい。
コンテナインスタンスとタスクの増減を合うようにしないといけない。
オートスケーリンググループでスケールアウトしないと、タスクが起動出来ないとか、
オートスケーリンググループでスケーリングすると、その上で起動していたタスクが落ちるとかあるが、
スケールインする時に、コンテナインスタンスが落ちる際にフックして、停止を止めておく事が可能なので、
その間タスクを他のコンテナインスタンスに移動させて、移動し終わったら、コンテナインスタンスを落とす処理(ドレイニング処理)を頑張って書いた。
オートスケーリンググループでスケーリングした後に、負荷がフラフラしていると、スケールインスケールアウトを繰り返すので、閾値の調整が難しかった。
とにかく調整が面倒。
オートスケールは数十秒のタイムラグがあるので、瞬間的なバーストには対応出来ないが、
toBのサービスは瞬間的なバーストは少ないので、スケジュールでスケールさせといた方が良い。
ログ
CloudwatchLogsに流している。
ECS上のタスクとかAWSBatchのジョブから、直接ログをCloudwatchLogsに流して、
それをLambdaで取得し、Fluentdで、KibanaやSlackやS3に流している。
(あまり良くない)
今後はCloudwatchLogsからKineis fireforceにして、S3に入れて、S3から次のアクションにするという流れにしたいと思っている。
ログの形式は、LTSVが以前の主流だったと思うが、JSONにしておくと、ロググループが指定出来るから便利。
ロググループは、ログを横断的に検索出来るようにする為、プロダクトの単位くらい、ざっくり指定しておくのが吉で、細かくすると管理が面倒になる。
logstream名のprefixが付いてくるので、prefixでどの環境のどのタスクなのかわかれば仕分けをすることが出来る。
JSONにしておいた方が良いのは、JSONカラムでフィルターをすることが出来るから。
JSONの中に、インスタンスIDとか、アプリケーションのバージョン、ログのIDを入れておくと良い。
その他のサービスについて
Bizreach Service
運用系のサーバーがECS,アプリケーション本体もECSに移行中。
バッチ系もAWSBatchを使用し、MySQLからRedshitやBigQueryにLinkage処理や、MySQLダンプ処理や、不定期に発生する運用処理もしている。
スタンバイ
ElasticBeansTalk上でコンテナ化されている。
ECSの移行を検討中。
下記移行理由。
* ElasticBeansTalkはECS上で動作しているので、結局ECSを知る必要があるから。
* ElasticBeansTalkは1アプリケーション毎にALBが1つ起動するので、ALBの数が膨大になってしまう。
* 1アプリケーション1EC2インスタンスになって、コストメリットがない。
* ElasticBeansTalk、EC2、ECS全てモニタリングしなければいけない。
統括
全社としてログの基盤と監視は統一した方が良いと思っている。
ECSを1年間運用したが、特に大きな問題はなかった。
サービスが停止して困った事がなかったし、アプリの問題で落ちても勝手に再起動してくれて安心感がある。
アプリのロールバックは、1分程でロールバックされるので、リリースする勇気が持てた。
ECSの残念な点は、オートスケールが中途半端で調整するのが大変。
EC2の存在を意識する必要があり、割と頻繁にECSエージェントをアップデートしなければいけなかったり、
インスタンスタイプや台数を考えないといけない。
ECSエージェントがバグっていると、全部アップデートするのに大変。
タスクの起動に失敗すると、ひたすら再起動する。再起動の間隔は調整が出来るが、勝手にロールバックするオプションがあると良いと思った。
ECS・EKS・Fagateについて
ECSの足りない点はk8sで解決出来る。
AWSにはEKSがある。
FagateはECS、EKSのクラスタ管理の部分をマネージドする、コンテナインスタンスを管理を自動化してくれてオートスケーリングが楽になるサービス。
ECSの使い分けとして、リザーブドインスタンスやSpotFreetなどでコスト削減したい場合や、コンテナ毎にアクセス制御したい場合。
EKSの使い分けとして、マルチクラウドを視野に入れている場合。
Fagateの使い分けとして、費用より運用の手間を無くしたい場合。
Startup Tech Talks 仮想マシン、コンテナ、関数、Kubernetes on AWS の活用方法と展望
k8s概要
- Googleのborg
- コンテナオーケストレーションシステム
- 2014年公開、2016年にv1.0のproduction ready
なぜk8sを使用するべきじゃないのか -> なぜコンテナなのか
スタートアップの課題
生産性が上がらない。
組織が大きくなると、チーム間の調整コストが高くなり、意思決定の摩擦、プログラミング言語の相違、宗教戦争を持ち出すetc...いろんな人がいる。エンジニアが足りない。人件費が高騰。この流れで、マイクロサービスアーキテクチャ、リモートワークが最近流行っている感じがする。
マイクロサービスアーキテクチャにすると、機能毎ではなくサービス毎に同期し、サービス間はAPIを使用し疎結合にして、チームが独立して働くことが可能になり、上記の解決になるのではないか、そういう文脈で取り上げられている。
リモートワークは分散チームの流れで、Slackやコミュニケーションツールを使用し、Githubだけで開発する会社も出てきた。これらツールが増えてきたおかげで、必ずしも東京にチームがいなくても同じサービスをみんなで作ることが出来るようになった。エンジニアが足りない問題を解決するのではないか?
我々はコンピュータ上でビジネスをしている以上、作ったソフトウェアをコンピュータ上で動作させる事は絶対避けて通れないので、それをどの抽象レイヤーでやるか。
仮想マシン、コンテナ、etcそれらの違いはそもそも何?
バージョンサービスアーキテクチャだと、仮想マシン、コンテナ関数そんな違いがある。
仮想マシンは、物理マシーンで動いているが意識することは少ない。
1マシーンで複数プロジェクトで動かしたりして、複数チームのサービスが1つの仮想マシンにうっかり乗ってしまい、「この機能だけこのサーバーが停止している、個別にスケジューリング出来ると嬉しい」とか、そのようなモチベーションが高まり、コンテナをやりたいとなる。
コンテナはコンテナイメージから作る。仮想マシンと似ている。物理マシーンか仮想マシン上でコンテナは動作する。上記のような事象はコンテナでも起こりうるが、VMと同じように、この機能だけコンテナを分割したいとなる。
その先にあるのは関数。スクリプトやバイナリから関数と呼ばれる単位でデプロイする。それらは、LambdaといったPaaS上で動作する。関数になると上記のような事象はない。
関数をデプロイの単位とした。それまでは違っていた。
マシーンにデプロイしたいのは、application bundle。これまでの悩みが解決される。
PaaSで済むならPaaSがベスト。
何で今更関数ではなく、コンテナなのか
運用ツールの違いからわかる。
仮想マシンはイメージから物理マシンで動作するので、コンフィグレーションマネジメントchef、ansibleを使用してインフラコードで運用する。
コンテナイメージは物理・仮想マシンで動作するので、Docker・ECS・k8sで運用する。
関数は作成してバイナリ化して、動作するのは、仮想マシン、コンテナ、Lambda、OpenFaaS、etc...
関数の管理はどうしたらいいのかわからない。
関数のオーケストレーションシステムの最適解はまだない。
だから個人的にはコンテナを使用している。
ツールが少なくて運用が大変だから。逆にツールが揃ってなくても問題ない小さなマイクロサービスであればどんどん使用するべき。
上記を使用基準にして欲しい。
コンテナオーケストレーションはなぜいるのか
コンテナをデプロイするのにsshだけでは済まないから。
コンテナが落ちた時に他のノードに自動移動したい場合、
EC2であればAutoScalingGroupがあるが、コンテナの場合は?
コンテナをロードバランサーにつなぎたい場合、
EC2であればALBがあるが、コンテナの場合は?
サーバーのリソース内でコンテナ数を増やしたい場合、
AWSであれば、小さいEC2インスタンスを並べてASGでオートスケーリング出来るが、コンテナの場合は?
AWSのコンテナオーケストレーションはECSとk8sの2つのソリューションがある。
ECSは、コンテナデプロイだけだったが、今は下記の機能が増えた。
初期にIAMロール対応し、同じインスタンスに違うIAMロールのコンテナが動作可能。
コンテナのヘルスチェック。
サービスディスカバリ(LoadBalancer)。
k8sも同じ。
運用面では違いがある。
ECSでは、AMIがあるので、DockerとかECSエージェントの相性が良いかのデバッグしなくても良いので、ビジネスに集中出来る。
k8sだと自分達で選定しないといけない。
ECSは、大きな会社で大規模なECSクラスタを構築している事例があり、それを運用するOSSツールも公開してくれている、日本でも採用事例が多いので、トラブルシューティングしやすい。機能も少ないのもいい(機能が増えるとアップグレードが大変だから)
k8sは、専用AMIはない、マネージド・サービスもない、日本での採用事例がない、情報が少ないのでデバッグも大変、k8sを使える人材を育てるのも大変。
k8sは、ECSより機能が多い。
k8sの機能
コンテナデプロイ
サービスディスカバリ
ロードバランサー
kubectl: fruentd,sshコマンドみたいなやつ
helm: パッケージマネージャー(wordpressをコマンド1発で入れたり出来る)
k8sを構築するのは大変だが、便利なAPIがたくさんある。
k8sはlinuxに例えられる。
k8sのAPIはlinuxのシステムコール。
k8sのシステムもk8sのAPIをコールするようにGolangで実装されているので、
自分達でAPIを使用してk8sを実装することも可能。
それらをサポートする便利なライブラリもあり(nodejs,java,golang)、
認証やバリデーションやDBにもなりうる。
豊富な周辺ツールもある。
メタコントローラー: bluegreenデプロイ出来るもの
squash: デバッガー(エラーが起きた時どこのコンテナが何でエラーが発生したのか把握するのに便利)
k8sの使い所
コンテナの運用は勝手にやってくれる。
Lambda、ECSより汎用的。
コンテナの運用を自動化したい。
k8sのAPIとSDKがあり、他のクラウドで作成されたツールをそのまま適応出来るので、自分達で作り込まなくてもちょっとしたPaaSみたいなものは作成出来る。
コンテナオーケストレーションというより、分散システムフレームワーク。
k8sで動作するFaaSもある。
PaaSで済まないならk8s上でFaaSを選ぶのもあり。
そのぶん激しく学習コストが高い。
Linuxをすべてわからないのに使用しているのと同じように、k8sを使用するとはそういうレベル。
コンテナをプロセスと見立てると、linuxはk8s。裏でEC2インスタンス何千台あるか不明だが、1つのPCと見立てた時に、OSはk8sで、システムコールはAPI。
躊躇するなら採用はするな。
freeeでの利用例
新規サービスはk8s化。
既存サービスはまずDocker化から、必ずしもk8s化しない。
目的は運用の効率化なので、既存が自動化されているなら、無理にk8sする必要はない。
新規サービスは自動化する暇がないので、最初からk8s化。
しかし、学習コストが高いので、オンボーディング勉強会を開催している。
可能な限り作り込まない。
k8sで動作するPaaSはないので、自動化する余地があるが、ツールを作るリソースはないので、自社で開発することはせず、OSSのメンテナーになるとか、メジャーなOSSを使用するとか、自社で持たず自動化を進めている。
EKS
k8sのコントロールプレーン(etcd,k8sのsystemとか)をマネージドするサービス。
EC2は自分で用意する。
k8sの封鎖された内部ネットワークがVPCでマネージドされる。
GCP、Azureだったらフルマネージする(但しカスタマイズ性が制限される)
未来の話
k8sが規格化されてくる。
k8sクラスタの運用が楽になってくる。
デバッグツールなどが増えてk8s上のアプリの運用が楽になってくる。
我々が求めるものはサーバーレスだけど、裏側はk8sだったりするかも。
まとめ
抽象レベルを意識できるように
正しいツールを選べるように
k8sは銀の弾丸ではない
コンテナだったらコンテナオーケストレーション
ファンクションの運用の選択肢が定まったら...?
将来的にk8sになっていくので、学習目的なら早めにやっといて損はないが、ビジネス利用が計画的に。