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

7周年を迎えたサロンスタッフ予約サービス「minimo」におけるコンテナ移行で得られたCDKのノウハウ

yukiarrr
October 29, 2021

 7周年を迎えたサロンスタッフ予約サービス「minimo」におけるコンテナ移行で得られたCDKのノウハウ

来年1月で8周年を迎えるサロンスタッフ予約サービス「minimo」において、Amazon ECS・AWS CDKを利用したコンテナ移行を行いました。
本セッションでは、その事例とともに、移行時に得られたノウハウを紹介できればと思います。

https://github.com/yukiarrr/ecsk
なお、上記が最後に紹介した対話形式でdocker execしたり、ECSとローカル間でファイルをコピーしあえるツールです。
自動化をする際のデバッグにどうぞ~

yukiarrr

October 29, 2021
Tweet

More Decks by yukiarrr

Other Decks in Technology

Transcript

  1. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG 自己紹介 • 株式会社ミクシィ所属 ‣ minimoには1年ほど前にJoin ‣ コンテナ移行、Go言語移行などを担当

    • よく触るのはAWSとUnity ‣ 最近はCDKやECSと戯れたり • 趣味はゲーム・なろう漁り IUUQTNJYJDPKQ
  2. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG minimo紹介 • 1月で8周年を迎えるサービス! • 美容師やネイリスト、アイデザイナー などを検索・予約できるアプリ •

    サロンスタッフを直接予約&やり取り することができる • 最近では動画投稿機能なども追加 • (採用強化中です) IUUQTNJOJNPEFMKQJOGP
  3. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG 移行理由 • ローカル環境ではdockerが導入されていた • 特別インフラのコード化や自動化がなされていたわけではないので、手順の 複雑化やそれによる属人化 •

    開発環境を気楽に増減したい ‣ EC2で固定数インスタンスを用意した形式(例: dev1~dev5)で、増減させ ようとするとやや手間 ‣ デプロイがCLI経由のため、エンジニア以外はデプロイも難しい • その他、SSH前提やライフサイクル、肥大化における課題
  4. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG オーケストレーション • ECS ‣ ECSは他のAWSサービスと組み合わせて利用するため、ECS自体はシンプルで学 習コストが低い ‣

    minimoの他サービスでECSを利用している ‣ (個人的にはバージョンを意識せずに済むのが特に嬉しい) • EKS ‣ 社内含めポピュラーで、Kubernetesの機能やエコシステムを活かしやすい ‣ Reconciliation LoopでGitOpsもしやすく、minimoの課題解決に繋がる • 学習コストやすでにECSを利用していることが決め手となり、ECSを採用
  5. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG ECSのデプロイツール • 数が多い…(良い意味) • 手軽に個別URLの開発環境を構築できるようにしたい(ECSだけでなくALBな ども取り扱ってほしい) •

    また元々インフラのコード化があまりされていなかったので、ECS周辺以外を コードとして管理できるのは魅力 • 比較は「第2回 AWS Fargate かんたんデプロイ選手権」も参考 • minimoは専属のインフラチームが存在せず、アプリケーションコードを書き 慣れているメンバーが多い • 以上から、AWS CDKを選定する
  6. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG 課題 • 元々はdev1,dev2のように、事前に用意された環境にデプロイする仕組み で、数に限りがあり、空きがないと動作検証ができない • とはいえ新しく作ろうにも、すべき手順が多く難しい •

    常駐されているため、常に一定のコストが発生 • どのPR、どのcommit時点でデプロイしているか判断がつかない • CLIからのデプロイのためサーバーエンジニア依存で、気楽に検証がしづらい • 開発環境間でDBが共通なため、好き勝手に弄るわけにはいかない
  7. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG もっと詳しく • PRにコマンドをコメントするだけで、PRごとにレビュー用の環境が構築され る(マージすると自動で破棄) • 必要な時、必要な分だけ確保できる仕組み •

    「PR固有のDBを用意する」などの様々なオプション付き • コメント式のため、不要なPRでは環境を構築せずに済む ‣ 加えて、どのcommit時点でデプロイしたかが一目瞭然 • これができるのもプログラミング言語で手続き的にインフラを構築できる CDKの恩恵(…)
  8. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG ローリングアップデート • ECSのデフォルトがローリングアップデート • タスク起動などの失敗時に自動でロールバックするサーキットブレーカーが 追加された ‣

    CFnでECSを管理していた場合、以前までは失敗時に停止→再起動→停止… の無限ループになっていたので、とてもありがたい機能 ‣ ただし、閾値は最小10・最大200で変更ができないため、開発環境などで Desired Countを1としている場合などはなかなかロールバックしない • デプロイが遅い場合、大体はderegistration_delay.timeout_secondsが原因
  9. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG Blue/Greenデプロイメント • 現在稼働しているものとは別にリソースを用意し、全体の何%を流すかなどの 戦略を元に新旧の入れ替えを実施する ‣ その性質上、負荷のコントロールやトラブル時のロールバックが容易 •

    deploymentControllerがCODE_DEPLOYまたはEXTERNALで可能(大体の人 はCODE_DEPLOYではないだろうか) • CFnでもECSのBlue/Greenデプロイメントができるようになった ‣ マクロを利用して作られており、EXTERNALを指定する ‣ そのため、ロールバック時はCFnの更新をキャンセルする
  10. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG Blue/Greenデプロイメントの検討理由 • CFnでもBlue/Greenデプロイメントが可能となったことから、CDK下でも管 理できるようになった • ローリングアップデートにおける課題 ‣

    何%だけ新に流すといった細かいコントロールはできない ‣ タスク起動時のhealthcheck以外は動作保証するものではない ‣ Blue/Greenに比べ、ロールバックするまでに時間がかかる ‣ バージョンの混在 ‣ 特定のタスクに負荷が偏ることがある
  11. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG CFnでのBlue/Greenデプロイメントの問題 • そもそもCDKでの対応はまだ完了していない ‣ https://github.com/aws/aws-cdk/issues/1559 ‣ とはいえ、L1などを活用すればCDKでも実装することが可能

    • AWS::ECS::TaskDefinitionとAWS::ECS::TaskSet以外の更新を含めることができない • 他スタックからの値インポートなどができない(クロススタック参照封じ) • ならEXTERNALで自力という方法も頭をよぎったが、EXTERNALの場合はサービス のAuto Scalingがサポートされないといった問題もある • とはいえCODE_DEPLOYにすると、CFnからはupdate-serviceできなくなる
  12. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG CFnでのBlue/Greenデプロイメント方針 ๏他からの参照はせずAWS::ECS::TaskDefinitionまたはAWS::ECS::TaskSetの みの更新になるようスタック分割でき、Auto Scalingを自前で対応するか、 利用しない方法を模索できる ➡ Perform

    ECS blue/green deployments through CodeDeploy using AWS CloudFormationを参考に構築する ๏上記の運用が難しい場合 ➡ 途中までCDKでリソースを作成し、CodeDeployはマネコンやCLIなどを利 用してデプロイするようにする
  13. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG ローリングアップデートでの対策 • ローリングアップデートでは厳しいかと言われると、そんなことはない • ローリングアップデートを利用して真っ先に顕著な課題となるのが負荷の偏り ‣ 特定のタスクに負荷が偏るなどして、デプロイ時にレスポンスが悪化

    • この対策として特に効果が高いもの ‣ ALBでLORアルゴリズムに変更(LBが未処理のリクエスト数が最も少ないタ ーゲットにリクエストを送信するようになる) ‣ 不格好だが、entrypoint.sh等で適当なリクエストをかけるなどして、ター ゲットグループ入り前にwarmupさせることが効果的なプロダクトも
  14. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG CDKでのコーディング • 「プログラミング言語で手続き的にインフラを構築」というのは、メンテで きないコードを生む危険がある • 構成管理の観点から考えると、宣言的が望ましい •

    CDK自体は宣言的だが、構文を利用できるがゆえに手続き的になり、結果的 に把握しづらいコードが生み出される可能性がある • 手続き的に書くこと自体は悪くなく、ただ無秩序に書かれ分散していると辛 いという話なので、チームでコーディング規約を定めることが大事 • (せめて最低限、Constructのidの命名規則だけでも決めておけると良い)
  15. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG ディレクトリ構成 • スタック分割時のレイヤーを元にディレク トリを分割 • その下にリソースごとのディレクトリ及び constructs.tsを作成し、そこにConstruct

    を宣言する • 環境ごとにリソースのパラメータ等を変更 する場合は、個別にディレクトリを切る • constructs.tsをstack.tsから参照し、 stack.tsがbin以下で呼ばれる形 • スタックは環境別に作られる(Stack- production、Stack-staging、など) ECSアプリケーションレイヤー ネットワークレイヤー 環境ごとの差異を吸収する どの環境でも同じ手続きを踏む
  16. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG 参照の仕組み • クロススタック参照を用いて、レイヤーごとの依存関係に従い手動で参照 ‣ 例えばネットワークレイヤーで作成したHostedZoneのidをcdk.CfnOutputでエクスポート、ア プリケーションレイヤーなどのHostedZoneを必要とするレイヤーではcdk.Fn.importValueを使 いインポートする

    • なぜCDKの機能を用いてプログラミング的に参照しないのか ‣ https://github.com/aws/aws-cdk/issues/3414 ‣ 上記とは別に、例えばFugaStackがHogeStackで作成されたhostedZoneをインポートして hostedZone.addXXXというようにリソースを追加更新した場合、この処理をFugaStackで記述 したにもかかわらず、HogeStackの管理下にその追加分のリソースが置かれるといった現象が 発生してしまう プログラミング的な参照
  17. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG CFnでScheduled Tasksを管理する場合 CFnの管理下に置かれるAWS::Events::Ruleの数が多くなってくると、 APIのRate exceededに接触する • あるスタックにてScheduled

    Tasksをコード管理している場合 • CFnは互いに依存関係のないリソースに関しては、並列作成&更新を試みる関 係上、AWS::Events::Ruleが同時更新されると、DescribeClustersのAPI制限 に接触する可能性がある • 対策として、DenpendsOnで依存関係を定義し、同時更新数を制御する (CDKになるので正確にはaddDependency)
  18. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG CDKでScheduled Tasksを管理する場合 Scheduled Tasksのイメージ更新と実行時のタイミングが重なった際に is not authorizedになりRunTaskが失敗してしまう

    • 同じくあるスタックにてScheduled Tasksをコード管理している場合 • Scheduled TasksがECSとCloudWatch Eventsの2サービスに跨っている影響 もあり、イメージ更新のデプロイで変更される対象が2リソースとなり、片方 が更新済みで片方が更新待ちのタイミングでcronトリガーされるとRunTask が失敗してしまう • 対策として、更新される2リソースのうち(RuleとPolicy)、Policy側のイメ ージタグを*に変更し、イメージ更新時に片方の更新が走らないようにする
  19. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG CDKデプロイの注意点 cdk deployのデプロイを並列化させる際、一つ前の状態に巻き戻ってし まう可能性がある • CDKのコードをgit管理しCI/CDを組んでいる場合、cdk deployが連続することがある

    • CDKではUPDATE_IN_PROGRESSなスタックとの差分チェックをUPDATE後の状態で行ってく れるため、cdk deployを並列化することが可能 • その際、順序が入れ替わらないようcommitのタイムスタンプなどをDynamoDB等で要管理 • ただ、それでも--allを使用していると、全スタックに一度しかタイムスタンプのチェックが 走らないことになるので、巻き戻ってしまう可能性がある • 対策として、--exclusivelyでスタックごとにタイムスタンプを管理する(それ以外の手段と して最も手っ取り早いのは完全な排他制御だが、モノレポ度合いで速度低下)
  20. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG CFnでSecrets Managerを取り扱う場合 原因が判明した際に頭を抱えるものです ECSでSecrets Managerを参照しようとすると、unable to pull

    secrets or registry authが発生しコンテナが起動しない • 一見するとただ権限がないだけに見える • だがどう見ても権限は足りている(のにエラーは消えず) • Secrets ManagerのARNの末尾にハイフン+6文字の識別子が追加されるが、もしシ ークレット名の末尾がハイフン+6文字の文字列(-secret、など)だった場合、そ れを完全なARNとみなしてしまい、結果エラーに繋がっていた • そのため、-secretsなど6文字にしなければ解決(実装&調査&解決されていたチー ムメンバーに圧倒的感謝)
  21. &RS\ULJKW & PL[L,QF$OOULJKWVUHVHUYHG ツールの紹介 インタラクティブにECS API(run-task, etc)を呼び出したり、ECSとロー カル間でファイルをコピーしたり、 ログを見たりするツールを作りました https://github.com/yukiarrr/ecsk

    • 今回のような自動化の仕組みを作る際のデバッグ等で使用 • runには-itや--rm相当の機能を用意 • これ系には珍しいcpも実装(双方向にファイル転送可) • 必要な情報は対話形式で選択肢が表示されるため、Webコンソールで確認すると いった作業が発生しない • 直近ではタスクのフィルタリング対象にIPアドレスを追加