Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

reireias
October 12, 2020

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

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

reireias

October 12, 2020
Tweet

More Decks by reireias

Other Decks in Technology

Transcript

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

    View Slide

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

    View Slide

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

    View Slide

  4. 目次
    1. AWSの基本
    ○ Region
    ○ Availability Zone
    ○ VPC/Subent
    2. ECS
    ○ ECSの概念
    ○ Fargate
    ○ スペックとスケール
    ○ ログ
    ○ デプロイ

    View Slide

  5. 1. AWSの基本

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  9. 一般的なMulti-AZ構成
    Region (ap-northeast-1)
    AZ-C
    AZ-A
    Aurora(Writer) Aurora(Replica)
    ECS
    ALB
    ECS
    簡略化のためにAZ2つで説明
    どっちかのAZが落ちてもサービ
    スは稼働する構成
    ただし、Region全体のネット
    ワーク障害などの場合は死ぬ
    AZ間通信の場合、AZ内通信に
    くらべて、10ms程度レイテンシ
    が発生する

    View Slide

  10. AZ間通信のレイテンシがネックになる例(実話)
    1回のSQL実行が5msのクエリがあったと仮定する。
    このクエリを1000回実行するようなN+1の実装をしてしまった。
    5ms * 1000回なので、5000msで応答する計算になる。
    ローカルで計測してもその程度だった。
    まあまあ重いページなので、5秒は許容範囲としリリースした。
    リリース後、「2回に1回くらいの頻度で、エラーになる」という問い合わせが入ってしまっ
    た。
    AZ間通信の場合、1回の通信ごとに10ms程度のレイテンシが発生する。
    →1000回の通信では、10秒のレイテンシが発生する。
    →レスポンスに15秒かかってしまい、タイムアウト。

    View Slide

  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

    View Slide

  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

    View Slide

  13. 2. ECS

    View Slide

  14. 目次
    1. AWSの基本
    ○ Region
    ○ Availability Zone
    ○ VPC/Subent
    2. ECS
    ○ ECSの概念
    ○ Fargate
    ○ スペックとスケール
    ○ ログ
    ○ デプロイ

    View Slide

  15. 2.1. ECSの概念

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  19. AWSマネジメントコンソールで確認
    ECSクラスター
    ECSサービス
    ECSタスク

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  23. タスク定義と他リソースの関係
    ECSサービスは属性として以下を持つ
    ● 使用するタスク定義とそのリビジョン
    ● 希望するタスク数
    Task Definition
    Revision 10
    Service
    Task
    Revision 1
    ...
    Task
    Task
    Task
    Revision 10のタスク定義で4タスク起動する設定にした例

    View Slide

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

    View Slide

  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)

    View Slide

  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
    ※ 実際に運用しているサービスの名前とは微妙に異なります

    View Slide

  27. 2.2. Fargate

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  31. 比較
    Fargate EC2
    スケーリング速度 速い EC2の起動の分遅い
    管理コスト 低 高
    EC2の管理も自前
    コスト 低 デプロイ時のキャパシティ的に
    メモリの料金に無駄が出る
    ssh可能 (基本的に)不可能 可能

    View Slide

  32. スケーリング速度
    Fargateのほうが倍程度速い
    EC2の場合は
    インスタンスの起動→クラスターへ登録→イメージのpull→コンテナ起動という流れ
    Fargateの場合は
    ENIの設定→イメージのpull→コンテナ起動という流れ
    インスタンス起動はインスタンスタイプにもよるが、2分程度かかるが、FargateのENIの
    設定は10秒程度で終わる

    View Slide

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

    View Slide

  34. コスト
    CPUやメモリサイズで見ると、EC2とFargateにそこまで大きなコスト差はない
    ただし、デプロイ設定によってはEC2が大きな損をすることになる
    デフォルト設定である、デプロイ時のコンテナが2倍起動する設定にした場合、通常起動
    するタスクのCPUとメモリの2倍が収まるサイズのEC2インスタンスを用意する必要があ

    これは、現在のCPU/メモリ使用量ではなく、タスクの最大のCPU/メモリ使用量がEC2上
    に空いていなければタスクを起動しないというECSの特性に起因する
    この問題はデプロイ時に一時的にタスクの数が少なくなることを許容すれば回避可能

    View Slide

  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を用
    意する必要があり、無駄コストとなる

    View Slide

  36. ssh可能か
    起動タイプEC2の場合は、EC2へssh→ `docker exec` でコンテナへ接続できる
    Fargateの場合は、マネージドサービスなのでssh接続ができない
    sshをSessionManagerに置き換えても同じ
    Twitterでこんな意見も見た

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  41. ECSのスペック
    ECSでスペックを指定できる箇所を起動タイプ別に以下に示す
    Fargate EC2
    Task
    Fargate
    Container Container
    必須
    - CPU
    - メモリ
    FargateはTaskのCPUとメモリ
    のスペックで確保される
    任意
    - CPU/メモリ
    - 予約メモリ
    EC2 Instance
    必須
    - インスタンスタイプ
    Task
    Container Container
    Task
    Container
    任意
    - CPU/メモリ
    - 予約メモリ
    必須
    - メモリ
    任意
    - CPU

    View Slide

  42. 注意点
    ● メモリ使用量100%になると、コンテナが落ちる
    ○ dockerのOOM Killerが発動し、コンテナが落ちる
    ○ 基本的にどのコンテナも必須なので、 1つのコンテが落ちたらタスク全体が落ちる設定が多い
    ● 起動タイプEC2の場合、空きがないとタスクは起動しない
    ○ タスクサイズ分のCPU/メモリの空きがEC2に無いと起動しない
    ○ この空きは現在の使用量ではなく、タスクサイズで計算される
    ○ 例:メモリ4GBのEC2上では、メモリ1.5GBのタスクは起動直後のメモリ消費が 100MBであっても、2
    つまでしか起動できない

    View Slide

  43. ECSのスケーリング
    起動タイプFargateのオートスケーリングを設定できる箇所
    タスクの数をスケール可能
    スケーリングのトリガーはCPUとかメモリとか、CloudWatchで取得できる値ならなんでも
    Fargate
    Container Container
    Task
    Fargate
    Container Container
    Task

    View Slide

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

    View Slide

  45. 注意点:よくある失敗
    元々の状態
    EC2メモリ4GB + メモリ1.5GBのタスク1つ
    スケールアウトして下記の状態となった
    EC2メモリ4GB + メモリ1.5GBのタスク2つ
    この状態だと、空きメモリは `4GB - 1.5GB * 2 = 1GB` しかない
    デプロイ時のmaxを200%にしていると、デプロイ時に新規にタスクが起動できないた
    め、デプロイがエラーになって終了する
    →起動タイプEC2の場合、EC2とタスクの両方のスケーリングを正しく設定する必要が
    ある(無駄コストを払わないようにこれを実現するのはかなり複雑なのでFargateを使お
    う)

    View Slide

  46. 2.4. ログ

    View Slide

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

    View Slide

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

    View Slide

  49. ログの見方①
    同じECSサービス→同じロググループへ出

    コンテナ名がログストリームのprefixに設定さ
    れている

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  53. 2.5. デプロイ

    View Slide

  54. ECSのデプロイ
    デプロイの仕組みというよりは、デプロイ時に発生する有名な問題の話を紹介
    デプロイ自体はタスク定義の項で紹介したように以下の流れで行われる
    ● 最新のソースコードでDockerイメージを作成
    ● ECRにimageをpush
    ● タスク定義に上記イメージを使用する新しいリビジョンを追加
    ● ECSサービスで利用するタスク定義のリビジョンを最新に更新
    ● あとはECSが設定に基づき新しいタスクを起動し、古いタスクを停止
    余談:上記処理はどこから実行しても良いので、GitHub Actionsからデプロイする仕組
    みも実験中

    View Slide

  55. 問題:ECSデプロイ時にassetsの参照で404エラー
    デプロイしている最中にサービスにアクセスすると、jsやcss等のassets系のGETリクエ
    ストが一定確率で404エラーになる問題
    何も対策せずに、デフォルトのECSのデプロイ設定でRailsをデプロイすると発生する

    View Slide

  56. 仕組み
    Task
    Container V1
    Task
    Container V2
    ① htmlを新バージョンのアプリか
    ら取得(1/2の確率で発生)
    デプロイ中に新旧両方のバージョンが
    ロードバランサーに紐づくタイミングで発
    生する
    ② htmlに記載されたcssを旧バー
    ジョンのアプリに取りに行く
    ③ 新バージョンのアプリの asset
    pipelineで作成されたcssは存在し
    ないので404を返す assets pipelineを使っているRailsが複数バージョン混
    在するとエラーになるという当たり前の話
    ELB

    View Slide

  57. 対策
    メジャーな対策を2つ紹介する
    現在社内ではどちらのパターンも存在しているが、今後は対策2の方を採用していく見
    込み
    対策1. assetsファイルをCloudFrontで配信
    対策2. CodeDeployで一括でトラフィック切り替え

    View Slide

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

    View Slide

  59. 対策1. assetsファイルをCloudFrontで配信
    Task
    Container V1
    Task
    Container V2
    ドメインを別にしている亜種パターンもある
    assets.example.com example.com

    View Slide

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

    View Slide

  61. 対策2. CodeDeployで一括でトラフィック切り替え
    Task
    Container V1
    Task
    Container V2
    ELB
    Task
    Container V1
    Task
    Container V2
    ELB
    CodeDeployというAWSサービスと連携してECSへデプロイすることで、新旧バージョン
    が混在する瞬間を発生させずに、トラフィックを一括で切り替える
    タスクがいくつあっても一括で新旧
    のバージョンへの
    トラフィックが切り替わる

    View Slide

  62. 対策案2. のメリット
    ロールバックができる
    デプロイがCodeDeployに管理されるため、ECSサービスのタスク定義のリビジョン指定
    ではなく、CodeDeployからロールバックを指示することになる
    とはいえ、CodeDeployのロールバックもシンプルなのでワンボタンでロールバックでき

    案1よりコストに優れる
    案1はCloudFrontが必須だが、こちらは任意なので管理画面とかにも気軽に使える

    View Slide

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

    View Slide

  64. Fin.

    View Slide