メドピア AWS勉強会 ECS編 / MedPeer AWS Seminar ECS

C64b68250b52ce67490c28110d622603?s=47 reireias
October 12, 2020

メドピア AWS勉強会 ECS編 / MedPeer AWS Seminar ECS

メドピア社内で定期的に開催しているAWSに関する勉強会を開催しています。本資料はそのうちのECSに関する回のものです。

C64b68250b52ce67490c28110d622603?s=128

reireias

October 12, 2020
Tweet

Transcript

  1. AWS勉強会 ECS編 メドピア株式会社 CTO室 SRE 侘美 怜

  2. 注意 本資料はメドピア社内で実施した勉強会の資料を外部公開向けに一部修正したものに なります。 講師の説明が無いと理解しづらい図などがありますのでご注意ください。

  3. 目的 ECSの仕組み・概念を理解する Fargateとは何かを理解する ECSのスケーリングについて理解する ECSのデプロイ時の挙動を理解する ECSのログの閲覧方法を理解する

  4. 目次 1. AWSの基本 ◦ Region ◦ Availability Zone ◦ VPC/Subent

    2. ECS ◦ ECSの概念 ◦ Fargate ◦ スペックとスケール ◦ ログ ◦ デプロイ
  5. 1. AWSの基本

  6. 概念 Region Availability Zone VPC(Virtual Private Cloud) Subnet

  7. Region AWSが展開する世界各地のロケーションのこと AWSの各種リソースは指定したRegionの中に作られる(例外あり) メドピアでは東京リージョン(ap-northeast-1)を使っている

  8. Availability Zone リージョン内に複数あるデータセンターのこと 東京リージョンには3つのAZがある(ap-northeast-1a, 1c, 1d) 同時に複数のAZが落ちることはほぼないため、サービスを複数AZにまたがって構築す ることで、高い可用性を実現する Region (ap-northeast-1)

    AZ-A AZ-C AZ-D
  9. 一般的なMulti-AZ構成 Region (ap-northeast-1) AZ-C AZ-A Aurora(Writer) Aurora(Replica) ECS ALB ECS

    簡略化のためにAZ2つで説明 どっちかのAZが落ちてもサービ スは稼働する構成 ただし、Region全体のネット ワーク障害などの場合は死ぬ AZ間通信の場合、AZ内通信に くらべて、10ms程度レイテンシ が発生する
  10. AZ間通信のレイテンシがネックになる例(実話) 1回のSQL実行が5msのクエリがあったと仮定する。 このクエリを1000回実行するようなN+1の実装をしてしまった。 5ms * 1000回なので、5000msで応答する計算になる。 ローカルで計測してもその程度だった。 まあまあ重いページなので、5秒は許容範囲としリリースした。 リリース後、「2回に1回くらいの頻度で、エラーになる」という問い合わせが入ってしまっ た。

    AZ間通信の場合、1回の通信ごとに10ms程度のレイテンシが発生する。 →1000回の通信では、10秒のレイテンシが発生する。 →レスポンスに15秒かかってしまい、タイムアウト。
  11. VPC(Virtual Private Cloud) 仮想的なネットワーク空間 複数のAZをまたぐように作成できる production環境とstaging環境は別のVPCとすることで、ネットワーク的に分離する設計 が一般的 Region (ap-northeast-1) AZ-A

    AZ-C AZ-D VPC 10.0.0.0/16
  12. Subnet VPCの中に作るサブ的なネットワーク空間 VPC内にEC2やRDSを作成する際に指定が必須になる Subnet単位でアクセスを制限したりする Availability Zone 1a Availability Zone 1c

    Availability Zone 1d VPC Private subnet 10.0.130.0/24 Public subnet 10.0.30.0/24 Private subnet 10.0.120.0/24 Public subnet 10.0.20.0/24 Private subnet 10.0.110.0/24 Public subnet 10.0.10.0/24
  13. 2. ECS

  14. 目次 1. AWSの基本 ◦ Region ◦ Availability Zone ◦ VPC/Subent

    2. ECS ◦ ECSの概念 ◦ Fargate ◦ スペックとスケール ◦ ログ ◦ デプロイ
  15. 2.1. ECSの概念

  16. ECSとは Elastic Container Service Dockerコンテナの実行や管理を行うことができるサービス メドピア社内のサービスは一部の古いサービスを除き、ほぼこれで運用されている Kubernetesとは別物 Kubernetesはもっと複雑で、ロードバランサーやストレージ等様々なリソースを管理でき る

  17. ECSの概念 ECSクラスター ECSサービス ECSタスク定義 ECSタスク Dockerコンテナ

  18. クラスター/サービス/タスク/コンテナの関係 Cluster Service A Task A Container A Container B

    Service B Task A Container A Container B Task B Container C Task B Container C
  19. AWSマネジメントコンソールで確認 ECSクラスター ECSサービス ECSタスク

  20. タスク定義 ECSサービスがECSタスクを起動する 際の設定が書かれたリソース 「どんなコンテナをどんな設定で起動す るか」が書かれている デプロイする度に新しいリビジョンが作ら れる(新しいイメージが指定されている)

  21. タスク定義を確認する AWSマネジメントコンソール上で現在作成されたタスク定義を確認できる 作成元のコードは社内のサービスによって管理されている場所が異なる • 比較的最近のプロジェクト等はterraformのリポジトリに入っている • ecs-cliを使ってプロジェクトは、docker-compose.yml形式に変換されたものがrails のリポジトリ内に入っている 例をマネジメントコンソールと実装で見てみる 参考:https://github.com/aws/amazon-ecs-cli

  22. マネジメントコンソールで紹介

  23. タスク定義と他リソースの関係 ECSサービスは属性として以下を持つ • 使用するタスク定義とそのリビジョン • 希望するタスク数 Task Definition Revision 10

    Service Task Revision 1 ... Task Task Task Revision 10のタスク定義で4タスク起動する設定にした例
  24. タスク定義とデプロイ ECSのデプロイは通常以下の方式で行う 1. 新しいDockerイメージをビルドする 2. 新しいDockerイメージを利用するタスク定義のリビジョンを作成する 3. ECSサービスで使用するタスク定義を最新のリビジョンに更新する 4. ECSサービスがコンテナを置き換える

  25. タスク定義とデプロイ ① Dockerイメージをビルド ② タスク定義の新リビジョンの作成 ③ ECSサービスのタスク定義指定を更新 ④ ECSサービスがタスクを置き換える Task

    Definition Revision 10 Service Task(10) Image Image Revision 11 Task(10) Task(11) Task(11) Task Definition Revision 10 Service Task(10) Image Image Revision 11 Task(10) Task Definition Revision 10 Service Task(10) Image Image Revision 11 Task(10) Task Definition Revision 10 Service Task(10) Image Image Task(10)
  26. 実際の構成の例 ECSクラスター ECSサービス 起動タイプ ECSタスク (数) Dockerコンテナ prd-app prd-app Fargate

    prd-app (4) - nginx - rails - datadog prd-api prd-api Fargate prd-api (4) - nginx - rails - datadog prd-admin prd-admin EC2 prd-admin (1) - nginx - rails - datadog prd-worker prd-worker Fargate prd-worker (2) - worker(sidekiq) - datadog ※ 実際に運用しているサービスの名前とは微妙に異なります
  27. 2.2. Fargate

  28. Fargateとは? Fargateとは、ECSサービスに指定する起動タイプの1種 起動タイプにはFargateとEC2がある

  29. 起動タイプEC2 ECSサービスの起動タイプをEC2に設定するとタスクはECSクラスターに登録された EC2インスタンスのDockerデーモン上で実行される このEC2インスタンスは自前で用意しなければならない 1つのEC2インスタンス上でCPUやメモリが足りていれば複数のタスクを実行することが できる EC2インスタンス Task A Container

    A Container B Task B Container C
  30. 起動タイプFargate Fargateはマネージドなコンテナ実行環境 起動タイプにFargateを指定した場合、タスクはFargate上で実行される FargateのスペックはCPUとメモリを指定でき、サイズに比例して料金がかかる Fargate Task A Container A Container

    B Task B Container C Fargate
  31. 比較 Fargate EC2 スケーリング速度 速い EC2の起動の分遅い 管理コスト 低 高 EC2の管理も自前

    コスト 低 デプロイ時のキャパシティ的に メモリの料金に無駄が出る ssh可能 (基本的に)不可能 可能
  32. スケーリング速度 Fargateのほうが倍程度速い EC2の場合は インスタンスの起動→クラスターへ登録→イメージのpull→コンテナ起動という流れ Fargateの場合は ENIの設定→イメージのpull→コンテナ起動という流れ インスタンス起動はインスタンスタイプにもよるが、2分程度かかるが、FargateのENIの 設定は10秒程度で終わる

  33. 管理コスト EC2の方が管理対象が増える SRE的には令和の時代にEC2インスタンスの管理はやりたくない(個人の感想) EC2インスタンスのインスタンスタイプ設定、OS、スケーリング管理等がFargateに比べ ると余計に必要になる ECSタスクで利用するCPU、メモリとタスク数からEC2のインスタンスタイプを決定する 等の設計のコストも高い EC2にどのようにタスクを配置するか等も設計しなければならない (先日これをミスって503エラーを出してしまった) 一方でFargateはタスク1つ1つのCPU、メモリサイズを決めるだけで良い

  34. コスト CPUやメモリサイズで見ると、EC2とFargateにそこまで大きなコスト差はない ただし、デプロイ設定によってはEC2が大きな損をすることになる デフォルト設定である、デプロイ時のコンテナが2倍起動する設定にした場合、通常起動 するタスクのCPUとメモリの2倍が収まるサイズのEC2インスタンスを用意する必要があ る これは、現在のCPU/メモリ使用量ではなく、タスクの最大のCPU/メモリ使用量がEC2上 に空いていなければタスクを起動しないというECSの特性に起因する この問題はデプロイ時に一時的にタスクの数が少なくなることを許容すれば回避可能

  35. コスト Fargate EC2 Fargate Task A cpu: 256 mem: 512

    EC2 cpu 512, mem: 1024 Task A cpu: 256 mem: 512 デプロイ中 デプロイ後 Fargate Task A cpu: 256 mem: 512 Fargate newTask A cpu: 256 mem: 512 Fargate newTask A cpu: 256 mem: 512 EC2 cpu 512, mem: 1024 Task A cpu: 256 mem: 512 newTask A cpu: 256 mem: 512 EC2 cpu 512, mem: 1024 newTask A cpu: 256 mem: 512 平常時にタスクの倍のスペックの EC2を用 意する必要があり、無駄コストとなる
  36. ssh可能か 起動タイプEC2の場合は、EC2へssh→ `docker exec` でコンテナへ接続できる Fargateの場合は、マネージドサービスなのでssh接続ができない sshをSessionManagerに置き換えても同じ Twitterでこんな意見も見た

  37. sshする運用を廃止して Fargateを使おう

  38. とはいえ、現実は... 社内でよくある例 adminクラスターは起動タイプEC2でssh(SessionManager)接続できるようにしておき、 appクラスターはFargateにする adminのタスクはCPU/メモリ共に小さいし、タスク数も少ないのでEC2に余計にコストが かかる点も微々たるもの ただし、社内の最新のイケてるプロジェクトは完全Fargateのみである

  39. 余談:stgはEC2、prdはFargate→ダメゼッタイ 社内でよくある構成でした 理由は、昔Fargateにリザーブドプラン(料金を前払いして割り引きする仕組み)が無かっ たため(今はある) ここ半年で2件ほど、Fargateでしか発生しない不具合を踏んだケースが発生 1件はsassc-rubyのバグ 1件はEC2とFargateの構成差によるRole関連の見落とし 本番環境とステージング環境は最大限努力して同一の環境にしましょう

  40. 2.3. スペックとスケール

  41. ECSのスペック ECSでスペックを指定できる箇所を起動タイプ別に以下に示す Fargate EC2 Task Fargate Container Container 必須 -

    CPU - メモリ FargateはTaskのCPUとメモリ のスペックで確保される 任意 - CPU/メモリ - 予約メモリ EC2 Instance 必須 - インスタンスタイプ Task Container Container Task Container 任意 - CPU/メモリ - 予約メモリ 必須 - メモリ 任意 - CPU
  42. 注意点 • メモリ使用量100%になると、コンテナが落ちる ◦ dockerのOOM Killerが発動し、コンテナが落ちる ◦ 基本的にどのコンテナも必須なので、 1つのコンテが落ちたらタスク全体が落ちる設定が多い •

    起動タイプEC2の場合、空きがないとタスクは起動しない ◦ タスクサイズ分のCPU/メモリの空きがEC2に無いと起動しない ◦ この空きは現在の使用量ではなく、タスクサイズで計算される ◦ 例:メモリ4GBのEC2上では、メモリ1.5GBのタスクは起動直後のメモリ消費が 100MBであっても、2 つまでしか起動できない
  43. ECSのスケーリング 起動タイプFargateのオートスケーリングを設定できる箇所 タスクの数をスケール可能 スケーリングのトリガーはCPUとかメモリとか、CloudWatchで取得できる値ならなんでも Fargate Container Container Task Fargate Container

    Container Task
  44. ECSのスケーリング 起動タイプEC2のオートスケーリングを設定できる箇所 タスクの数とEC2インスタンスの数の両方をスケール可能 Container Container Task Container Container Task EC2

  45. 注意点:よくある失敗 元々の状態 EC2メモリ4GB + メモリ1.5GBのタスク1つ スケールアウトして下記の状態となった EC2メモリ4GB + メモリ1.5GBのタスク2つ この状態だと、空きメモリは

    `4GB - 1.5GB * 2 = 1GB` しかない デプロイ時のmaxを200%にしていると、デプロイ時に新規にタスクが起動できないた め、デプロイがエラーになって終了する →起動タイプEC2の場合、EC2とタスクの両方のスケーリングを正しく設定する必要が ある(無駄コストを払わないようにこれを実現するのはかなり複雑なのでFargateを使お う)
  46. 2.4. ログ

  47. ECSのログ ECSではDockerコンテナの標準出力がCloudWatch LogsというAWSのサービスへ送 信される 起動タイプEC2の場合、ssh接続しdockerコマンドを実行できるが、docker logsコマンド でコンテナのログを見ることはできないので注意

  48. ログの見方① 直接CloudWatch Logsへ移動し確認する方法

  49. ログの見方① 同じECSサービス→同じロググループへ出 力 コンテナ名がログストリームのprefixに設定さ れている

  50. ログの見方② ECSの画面からコンテナを指定して、CloudWatch Logsを開くことも可能 クラスター→サービス→タスク→コンテナ→CloudWatchのログを表示

  51. ログの見方③ ECSの画面上でもログを確認することができる クラスター→サービス→タスク→Logsタブ→コンテナを指定 ここだけログが降順で並ぶので注意

  52. ECSにおけるログ出力設定の注意 標準出力と標準エラー出力の使い分けができない jsonにすると検索性がよくなる(らしい) CloudWatch Logsはログの量で課金されるので、ログレベルは `:info` にすることを徹 底していきたい

  53. 2.5. デプロイ

  54. ECSのデプロイ デプロイの仕組みというよりは、デプロイ時に発生する有名な問題の話を紹介 デプロイ自体はタスク定義の項で紹介したように以下の流れで行われる • 最新のソースコードでDockerイメージを作成 • ECRにimageをpush • タスク定義に上記イメージを使用する新しいリビジョンを追加 •

    ECSサービスで利用するタスク定義のリビジョンを最新に更新 • あとはECSが設定に基づき新しいタスクを起動し、古いタスクを停止 余談:上記処理はどこから実行しても良いので、GitHub Actionsからデプロイする仕組 みも実験中
  55. 問題:ECSデプロイ時にassetsの参照で404エラー デプロイしている最中にサービスにアクセスすると、jsやcss等のassets系のGETリクエ ストが一定確率で404エラーになる問題 何も対策せずに、デフォルトのECSのデプロイ設定でRailsをデプロイすると発生する

  56. 仕組み Task Container V1 Task Container V2 ① htmlを新バージョンのアプリか ら取得(1/2の確率で発生)

    デプロイ中に新旧両方のバージョンが ロードバランサーに紐づくタイミングで発 生する ② htmlに記載されたcssを旧バー ジョンのアプリに取りに行く ③ 新バージョンのアプリの asset pipelineで作成されたcssは存在し ないので404を返す assets pipelineを使っているRailsが複数バージョン混 在するとエラーになるという当たり前の話 ELB
  57. 対策 メジャーな対策を2つ紹介する 現在社内ではどちらのパターンも存在しているが、今後は対策2の方を採用していく見 込み 対策1. assetsファイルをCloudFrontで配信 対策2. CodeDeployで一括でトラフィック切り替え

  58. 対策1. assetsファイルをCloudFrontで配信 Task Container V1 Task Container V2 /assets 等のパスはS3から取得す

    るように設定 新バージョンをデプロイする直前 にassets系ファイルをアップロード する デプロイ中は、CloudFrontから新旧両方の バージョンのassetsファイルを取得できるよう にする方法 S3に無限にassetsが溜まっていかないよう に、デプロイの最後、旧バージョンのコンテナ が停止した後で、古い assetsファイルを消す CloudFront S3 Bucket
  59. 対策1. assetsファイルをCloudFrontで配信 Task Container V1 Task Container V2 ドメインを別にしている亜種パターンもある assets.example.com

    example.com
  60. 対策1. のデメリット ロールバックができない ECSはタスク定義のリビジョンが残るため、本来であれば簡単な操作で1つ前のリビジョ ンにロールバックできる しかし、S3に前のバージョンのassetsファイルが無いため、ロールバックするとassets系 ファイルの取得がすべて404エラーになってしまう S3上に古いバージョンのassetsを残すようにすればよいが、コストが増えたり定期的に 消す仕組みの管理など複雑になりがち

  61. 対策2. CodeDeployで一括でトラフィック切り替え Task Container V1 Task Container V2 ELB Task

    Container V1 Task Container V2 ELB CodeDeployというAWSサービスと連携してECSへデプロイすることで、新旧バージョン が混在する瞬間を発生させずに、トラフィックを一括で切り替える タスクがいくつあっても一括で新旧 のバージョンへの トラフィックが切り替わる
  62. 対策案2. のメリット ロールバックができる デプロイがCodeDeployに管理されるため、ECSサービスのタスク定義のリビジョン指定 ではなく、CodeDeployからロールバックを指示することになる とはいえ、CodeDeployのロールバックもシンプルなのでワンボタンでロールバックでき る 案1よりコストに優れる 案1はCloudFrontが必須だが、こちらは任意なので管理画面とかにも気軽に使える

  63. 備考:カナリアデプロイに関して カナリアデプロイを行う場合は、新旧両方のassetsファイルを配信する必要があります。 CodeDeployに備わっているカナリアデプロイの機能を利用する場合は、案1、案2とは 異なる構成を検討する必要があります。

  64. Fin.