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

Poolにおける足を止めないシステム基盤構築

 Poolにおける足を止めないシステム基盤構築

F811665799e1139b63140b72f3e8631f?s=128

Genki Sugawara

May 15, 2022
Tweet

More Decks by Genki Sugawara

Other Decks in Technology

Transcript

  1. Poolにおける 開発の足を止めないシステム基盤構築 1

  2. 自己紹介 菅原 元気 株式会社カンム SRE @sgwr_dts @winebarrel 好きな技術 / /

    / / は勉強中 2
  3. 3

  4. 資産運用のハードルを下げる 投資ができるクレカを発行 予定利回り年率1% 決済還元1% https://pool-card.jp/ 4

  5. 本日話したいこと 既存のプロダクトで感じていた課題を解決するため コンテナなど社内では使ってこなかった技術スタックを使って Poolのシステム基盤を構築しました。 既存の技術とは大きく異なるシステムで 安全かつスピーディーに開発を行うために意識したところなどを 課題を踏まえながら振り返ります。 5

  6. アジェンダ 決済サービスの簡単な解説 Poolの採用技術 Poolのシステム構成 デプロイ Terraform オペレーション モニタリング まとめ 6

  7. 決済サービスの簡単な解説 7

  8. カード関連会社の関係 8

  9. カード利用の流れ 9

  10. オーソリ(仮売上処理)・クリアリング(売上精算) 利⽤者 お店 国際ブランドネットワーク Pool オーソリ カード利⽤ カード利⽤ オーソリ電⽂ オーソリ電⽂

    承認 承認 カード利⽤完了 カード利⽤完了 数⽇後 クリアリング 確定売上 確定売上 クリアリング電⽂ クリアリング電⽂ 利⽤者 お店 国際ブランドネットワーク Pool 10
  11. Poolの採用技術 実装(バックエンド) Go インフラ Amazon ECS (Fargate) Amazon Aurora (PostgreSQL)

    AWS Step Functions サービス間通信 gRPC 11
  12. Poolの採用技術 CI GitHub Actions モニタリング Datadog インフラ管理 Terraform DBマイグレーション sqldef

    12
  13. Poolのシステム構成 13

  14. 既存システムの課題 EC2インスタンスの保守 OSのアップデート パッケージのアップデート ログインユーザーの管理 バッチ EC2上でcron Ansibleの適用が手間 →コンテナを中心としたシステムの構築 14

  15. APIサーバ・バッチ 15

  16. オーソリ・クリアリング 16

  17. Poolのサーバ構成 ECS (Fargate) SREの少なさからEKSは不採用 基本的にコンテナ化 オーソリサーバもコンテナ化 クリアリング電文受信のため最低限のEC2(Windowsサーバ) プロビジョニングはPacker Chefにできないか調査中 バッチ処理はStep

    Functionsでコンテナ実行 プロダクション・ステージングでAWSアカウントを分けている 17
  18. バッチ Step FunctionsからECSタスクを実行 EventBridgeで定期実行 Windowsバイナリ実行もStep Functions できるだけ処理をAWSに寄せる ワークフローはterraformで定義 EventBridgeと合わせてモジュール化し記述をシ ンプルに

    Failした場合、SNS経由でDatadogに通知 18
  19. バッチ resource "aws_sfn_state_machine" "xxx" { name = "xxx" role_arn =

    aws_iam_role.state_machine.arn definition = jsonencode({ StartAt = "Run ECS Task", States = { "Run ECS Task" = { Type = "Task" Resource = "arn:aws:states:::ecs:runTask.sync" Parameters = { LaunchType = "FARGATE" EnableExecuteCommand = true NetworkConfiguration = { ... } Cluster = ... TaskDefinition = ... Overrides = { ContainerOverrides = [ { Name = "app" Command = [ ... ] Environment = { ... } }, 19
  20. バッチ module "app_cron" { source = "../modules/cron" name = "app-cron"

    cluster_arn = aws_ecs_cluster.app.arn subnet_ids = [for sn in aws_subnet.app : sn.id] definitions = { "batch" = { command  = ["./batch-cli", "xxx"] environment = [ { Name = "INPUT_FILE", "Value.$" = "$.INPUT_FILE" }, ] input = { INPUT_FILE = "" } schedule_expression = "cron(5 15 * * ? *)" task_definition = "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/batch" security_groups = [ ... ] task_roles = [ ... ] }, 20
  21. Step Functions AWSのAPIはだいたい何でも実行できる Session ManagerでPowerShellを実行など ワークフローの記述は冗長 待ち合わせ・失敗の処理などに数ステップ必要になる 入出力加工用のJSONPathが貧弱 @ ..

    , : ? * がサポートされない 使える関数が限られている HTTPを直接リクエストできない Lambda経由・SNS経由…etc サーバレスのメリットが大きい Step FunctionsのDXは改善したい 21
  22. デプロイ 22

  23. 既存システムの課題 テストの実行とデプロイが分離 デプロイは手作業で Ansibleの実行 AMI作成 インスタンスのサービスイン 手間がかかる・ミスが起きる →GitHub Actionsを使ったデプロイの高速化 23

  24. GitHub Actions 24

  25. GitHub Actions 25

  26. テスト・デプロイ GitHub Actions releaseブランチなしのGit Flow masterが直接プロダクションにリリースされる OpenID ConnectでAWSのクレデンシャルを取得 同じワークフローでプロダクション・ステージングを実行 AWS_ACCOUNT:

    ${{ (github.ref == 'refs/heads/master' && '123456789012') || '210987654321' }} DBマイグレーションはCodeBuild経由で実行 Dockerイメージ不要でVPCにアクセスできるようにするため 26
  27. テスト・デプロイ ECSへのデプロイはecspresso https://github.com/kayac/ecspresso Windowsへのデプロイ CIでビルドしたバイナリをS3にアップロード Session ManagerでWindows上でスクリプトを実行 S3→Windows バッチ用ECSタスク定義 バージョン未指定の場合、latestが実行される

    ecspresso run でタスク定義の更新+動作確認 27
  28. ECSタスク定義 / ├── lib │ ├── datadog.libsonnet │ └── utils.libsonnet

    ├── prd │ ├── pool-app │ │ ├── api │ │ │ ├── ecs-service-def.jsonnet │ │ │ ├── ecs-task-def.jsonnet │ │ │ └── ecspresso.yml │ │ ├── batch │ │ │ └── ... │ │ ├── common │ │ │ ├── api-container.libsonnet │ │ │ └── container-common.libsonnet │ │ └── external-service │ │ └── sendgrid.libsonnet │ └── pool-card │ ├── ... └── stg ├── ... 28
  29. ECSタスク定義 local datadog = import '../../../lib/datadog.libsonnet'; local utils = import

    '../../../lib/utils.libsonnet'; local apiCommon = import '../common/api-container.libsonnet'; { containerDefinitions: [ utils.objectToArray(apiCommon { environment+: { USE_CLIENT: 'true', }, secrets+: { CLIENT_SECRET: '{{ tfstate `aws_secretsmanager_secret.secret.arn` }}:secret::', }, logConfiguration: datadog.logConfiguration(...), }), datadog.agentContainer, datadog.fluentBitContainer, ], cpu: '256', executionRoleArn: '{{ tfstate `aws_iam_role.task_execution_role.id` }}', family: 'api', memory: '512', networkMode: 'awsvpc', requiresCompatibilities: ['FARGATE'], taskRoleArn: '{{ tfstate `aws_iam_role.task_role.id` }}', } 29
  30. ECSタスク定義 jsonnetで定義 タイムリーにecspressoがjsonnetサポート https://sfujiwara.hatenablog.com/entry/ecspresso-v1.7.0 Datadog Agentなどのサイドカーや共通部分は.libsonnetに切り出し コードの重複をなくす Terraformリソースの参照はecspressoのtfstateプラグインを利用 直接のIDの記述をなくして可読性を向上 30

  31. リリース 31

  32. リリース 32

  33. リリース @kabot pr-release <repo name> でリリース用PR作成 masterにマージされたらリリース 手作業のミスをなくし、masterに入るPRをわかりやすく Slackボットは自作 Hubotの更新が止まっていたので…

    Bolt+Slackソケットモード Hubot/Rubotyの設計を踏襲 PRの作成はボットがgit-pr-releaseを実行 https://github.com/x-motemen/git-pr-release 33
  34. Terraform 34

  35. 既存システムの課題 各種インフラリソースがコード化されていない AWS、PostgreSQLロール… リソース管理まわりオペレーションの委譲がしにくい 強力な権限を渡すか、SREが作業する →Terraformによるコード化・作業の委譲 35

  36. Terraform pool/ ├── aws │ ├── modules │ ├── prd

    │ │ ├── ecs.tf │ │ ├── rds.tf │ │ ├── s3.tf │ │ └── ... │ └── stg ├── datadog │ ├── prd │ │ ├── moniter.tf │ │ └── ... │ └── stg ├── pagerduty │ └── prd │ ├── service.tf │ └── ... └── postgresql ├── prd │ ├── app-db │ │ ├── app_user.tf │ │ └── ...terraform.tf │ └── card-db └── stg 36
  37. Terraform Pool以外のサービスのTerraformも含まれるモノレポ AWSに限らずDatadog/PagerDuty/PostgreSQLも管理 モジュールはなるべく使わない方針 コードを追いやすい リソースの相互参照がしやすい リソースの変更を局所化できる 環境ごとのコードの記述量が多くなるのが課題 記述量の削減のために for_each

    を積極的に使用 37
  38. Terraform resource "aws_subnet" "pool" { for_each = { ap-northeast-1a =

    "10.50.0.0/24", ap-northeast-1b = "10.50.1.0/24", } vpc_id = aws_vpc.pool.id cidr_block = each.value availability_zone = each.key tags = { Name = "pool-${each.key}" } } resource "aws_route_table" "pool" { for_each = aws_subnet.pool vpc_id = aws_vpc.pool_app_prd.id } resource "aws_route_table_association" "pool" { for_each = aws_subnet.pool subnet_id = each.value.id route_table_id = aws_route_table.pool[each.value.availability_zone].id } 38
  39. Terraform PRで terraform plan だけGitHub Actionsで実行 結果はPRにコメント 開発者がPR経由でリソースの変更の提案を行える applyはSREが手動で実行 terraform

    apply の自動化は課題 ステージング環境については開発者にapply可能な権限を付与 ステージング環境は開発者が自由に操作できる 39
  40. オペレーション 40

  41. 既存システムの課題 基本的には管理画面での操作 まれにCLIを操作するオペレーションが発生する 管理用コマンドの実行 ネットワークの疎通確認 どうしても必要なDBの操作 サービスコンテナへのECS Exec セキュリティ上よくない オペレーション用EC2インスタンス

    管理コストがかかる →demitasというツールを作成 41
  42. demitas 42

  43. demitas https://github.com/winebarrel/demitas https://tech.kanmu.co.jp/entry/2021/12/14/100000 ecspressoのラッパー サービスと同じVPC・サブネット・SGで作業用タスクを起動 作業が終わったらタスクは破棄 コンテナ経由のポートフォワーディングも可能 kubectl run kubectl

    port-forward をイメージして作成 43
  44. demitas $ demitas-exec -e bash Start ECS task... ECS task

    is running: 9b71b0c7e090f7e0ac8a7bc4fbf051a7 The Session Manager plugin was installed successfully. Use the AWS CLI to start a session. Starting session with SessionId: ecs-execute-command-5daee3efe79819c1 root@ip-10-50-0-10:/# 44
  45. demitas サービスのコンテナにログインすることなくVPC内作業が可能 使い捨てのコンテナなので自由にパッケージを入れられる タイミングによってはECSタスクが残ったままになる クリーニングが課題 実装がきれいではないのでリファクタリングしたい 45

  46. モニタリング 46

  47. 既存システムの課題 通知や情報が分散している ログがEC2サーバ上 Slackチャンネルへの通知、PagerDutyへの通知 SaaSが分散している Sentry、Mackerel →Datadogによる一元管理 47

  48. モニタリング 基本的にDatadog 一部PagerDuty モニターはTerraformで管理 閾値の変更が誰でもしやすくなる ログもDatadogに送信 Live Tailも可能でログの検索性が向上 APMやエラートラッキングとの紐付けで調査がしやすく Datadogの保持期間以上はS3に

    48
  49. アラート PagerDutyとSlackに通知 すべてのアラートはPagerDutyでインシデント化 アラートのアサイン漏れを防ぐ 緊急度の高くないものはLow Urgencyで Log Urgencyはoncall-statusでOS Xのデスクトップに通知 https://github.com/mtougeron/oncall-status

    通知メッセージにはRunbookのリンクを含める 誰でもインシデントに対応できるように 49
  50. まとめ システム構成 コンテナ化で管理コストの削減 デプロイ GitHub Actionsでのデプロイの高速化 Terraform コード化による適切な作業の委譲 オペレーション demitasによる安全で自由度の高い作業の実現

    モニタリング Datadogでの一元管理やアラートの集約で効率化 50
  51. We are hiring! https://team.kanmu.co.jp/ 51