Slide 1

Slide 1 text

© LayerX Inc. 実践 DevOps チーム全員でインフラを管理する @shnjtk 2021/10/29 JAWS-UG コンテナ支部 #20

Slide 2

Slide 2 text

© LayerX Inc. 自己紹介 高江 信次 (Shinji Takae) 株式会社LayerX CTO室 リードエンジニア LayerX インボイスの開発メンバーとして主にインフラを担当 コーポレートエンジニア的な業務も一部兼任 好きなAWSサービス 2 AWS Fargate Amazon Aurora Lambda

Slide 3

Slide 3 text

© LayerX Inc. 今日話すこと スピードを落とさず効率的にサービスを開発するために LayerX インボイスの開発チームが一体となって取り組んでいる インフラの管理方法 3

Slide 4

Slide 4 text

© LayerX Inc. アジェンダ ● 開発チーム構成と普段の開発の様子 ● チームとして達成したいこと ● 実践していること ● まとめ 4

Slide 5

Slide 5 text

© LayerX Inc. 開発チーム構成 5 LayerX インボイス LayerX ワークフロー インフラ開発・デザイン・ QA AI-OCR

Slide 6

Slide 6 text

© LayerX Inc. 普段の開発の様子 ● インフラの全体的な設計や開発など大掛かりな作業は基本的に インフラ担当が行う ● 軽微な変更はアプリ担当が自分で対応することもある ● IaC化する前に、テスト的に管理画面から手動でリソースを作ることもある ● 手動で作って不要になったリソースの削除やIaC化はインフラ担当が行う ● 結果的に、チーム全員が自然とインフラに関わっている 6

Slide 7

Slide 7 text

© LayerX Inc. 達成したいこと ● インフラ開発がボトルネックになって開発スピードが落ちるのを防ぐ ● 最終的に必要となるリソースはIaCで管理する 7

Slide 8

Slide 8 text

© LayerX Inc. 実践していること ● IaCリポジトリのディレクトリ構成とファイルの命名規則 ● タグ付けによるIaCリポジトリの明確化 ● 再利用性を意識したリソース定義 ● CI/CDの自動化とtfstateのバージョン管理 ● plan実行時の差分を減らす工夫 ● ツールの使い分け 8

Slide 9

Slide 9 text

© LayerX Inc. IaCリポジトリのディレクトリ構成 9 invoice-infra ├── aws_cloudwatch_logs.tf ├── aws_ecs.tf ├── aws_iam_ecs.tf ├── aws_iam_lambda.tf ├── aws_kms.tf ├── aws_rds.tf ├── aws_route53.tf ├── aws_s3.tf ├── aws_secrets.tf ├── buildspec.yml ├── data.tf ├── datadog_dashboard_ecs.tf ├── datadog_integration.tf ├── datadog_monitor_ecs.tf ├── datadog_monitor_rds.tf ├── datadog_synthetics_test.tf ├── env │ ├── dev.tfvars │ ├── prd.tfvars │ └── stg.tfvars ├── locals.tf ├── provider.tf └── variables.tf (一部抜粋) ● リポジトリ直下に.tfファイルをフラットに配置 ● 環境変数は.tfvarsファイルで定義して envディレクトリに配置 ○ terraformコマンド実行時に引数で指定 ● プロジェクト固有の定数はlocals.tfで定義

Slide 10

Slide 10 text

© LayerX Inc. Terraformファイルの命名規則 ● (provider)_(resource)_(target).tf ○ 例: aws_iam_ecs.tf、aws_iam_lambda.tf ● targetがなかったり、自明な場合は省略 ○ 例: aws_rds.tf、aws_kms.tf ● 目的 ○ インフラのコードに普段はあまり関わらないメンバーであっても、コードを変更する際にどのファイル を編集すればいいか一目で分かる ● 上記はあくまで一例 ○ チーム内で一貫性があって、変更したい目的のファイルをすぐに特定できればよい 10

Slide 11

Slide 11 text

© LayerX Inc. タグ付けによるIaCリポジトリの明確化 ● default_tagsを利用して、各リソースを管理してい るIaCリポジトリがどれであるかを示すタグを付与 する ● 目的 ○ アプリ担当がリソースに変更を加えたい場合に IaCリポジトリがすぐに分かる ○ これが付与されていないものは手動で作ったテスト用リ ソースであると判断できる → リソース棚卸し時の削除対象 11 locals { service_id = "invoice" managed_by = "invoice-infra" } provider "aws" { region = “ap-northeast-1” default_tags { tags = { service_id = local.service_id managed_by = local.managed_by env = var.env } } } locals.tf provider.tf

Slide 12

Slide 12 text

© LayerX Inc. 再利用性を意識したリソース定義 ● アプリ開発メンバーがインフラに変更 を加えるケースの例 ○ S3 bucketを追加したい ○ IAM policyを変更したい ○ DynamoDB tableを追加したい ● なるべくコピペしやすいようにlocals やvarを使って共通部分は そのまま使えるようにする ● 暗号化設定や非公開設定など、守っ てほしい部分も漏れなく カバーされるようにリソース定義を隣 接させておく 12 resource "aws_s3_bucket" "csv_files" { bucket = "${local.service_id}-${var.env}-csv-files" acl = "private" versioning { enabled = true } server_side_encryption_configuration { rule { apply_server_side_encryption_by_default { kms_master_key_id = aws_kms_key.main.arn sse_algorithm = "aws:kms" } } } } resource "aws_s3_bucket_public_access_block" "csv_files" { bucket = aws_s3_bucket.csv_files.id block_public_acls = true block_public_policy = true ignore_public_acls = true restrict_public_buckets = true }

Slide 13

Slide 13 text

© LayerX Inc. CI/CDの自動化とtfstateのバージョン管理 ● plan/applyの実行は自動化する ○ planやapplyの結果をチームで共有することにより レビューしやすくなる ● tfstateファイルは必ずリモートバックエンドで保管しバージョ ン管理を有効にする ○ バージョン管理することで、もし何かあった場合でも tfstateをロール バックすることができる ○ 「何かあってもすぐに元に戻せる」という安心感があることで 失敗を恐れずにインフラを変更できる 13 PR plan apply tfstate

Slide 14

Slide 14 text

© LayerX Inc. plan実行時に差分を減らす工夫 14 例: data sourceが参照しているリソースを変更した場合 resource "aws_s3_bucket" "csv_files" { bucket = "csv-files" tags = { foo = “bar” # -> “baz” に変更すると... } } data “aws_iam_policy_document” “csv_reader” { statement { effect = “Allow” actions = [“s3:GetObject”] resources = [“${aws_s3_bucket.csv_files.arn}/*”] } } resource “aws_iam_policy” “csv_reader” { name = “csv-reader” policy = data.aws_iam_policy_document.csv_reader.json } # aws_s3_bucket.sample will be updated in-place ~ resource "aws_s3_bucket" "csv_files" { ~ tags = { ~ "foo" = "bar" -> "baz" } # (config refers to values not yet known) <= data "aws_iam_policy_document" "csv_reader" { ~ id = "232721XXXX" -> (known after apply) ~ json = jsonencode( { - Statement = [ - { - Action = "s3:GetObject" - Effect = "Allow" - Resource = "arn:aws:s3:::csv-files/*" - Sid = "" }, ] - Version = "2012-10-17" } ) -> (known after apply) - version = "2012-10-17" -> null } # aws_iam_policy.sample will be updated in-place ~ resource "aws_iam_policy" "csv_reader" { id = "arn:aws:iam::XXX:policy/csv-reader" name = "csv-reader" ~ policy = jsonencode( { - Statement = [ - { - Action = "s3:GetObject" - Effect = "Allow" - Resource = "arn:aws:s3:::csv-files/*" - Sid = "" }, ] - Version = "2012-10-17" } ) -> (known after apply) } Plan: 0 to add, 2 to change , 0 to destroy.

Slide 15

Slide 15 text

© LayerX Inc. plan実行時に差分を減らす工夫 15 resource "aws_s3_bucket" "csv_files" { bucket = "csv-files" tags = { foo = “bar” # -> “baz” に変更すると... } } resource "aws_iam_policy" "csv_reader" { name = "csv-reader" policy = jsonencode({ Version = "2012-10-17" Statement = [{ Effect = "Allow" Action = ["s3:GetObject"] Resource = ["${aws_s3_bucket.csv_files.arn}/*"] }] }) } Terraform will perform the following actions: # aws_s3_bucket.sample will be updated in-place ~ resource "aws_s3_bucket" "csv_files" { id = “csv-files" ~ tags = { ~ "foo" = "bar" -> "baz" } ~ tags_all = { ~ "foo" = "bar" -> "baz" } # (9 unchanged attributes hidden) # (1 unchanged block hidden) } Plan: 0 to add, 1 to change, 0 to destroy. 対策: jsonencodeでインライン化する

Slide 16

Slide 16 text

© LayerX Inc. ツールの使い分け ● 基本的にはTerraformを使用してリソースを管理する ● Lambda関数はケース・バイ・ケースで使い分ける ○ jsファイル1つで済む程度の軽いものであればTerraform ○ パッケージインストールや複雑なビルドが必要なものは AWS CDK ● AWS CDKを使う場合は対象をLambda関数だけにする ○ 厳密には、Lambda関数とそれをデプロイするためのCloudFormation stack ○ Lambda関数に付与するIAM role/policyや、その他必要なリソースはTerraformで管理 ● 目的 ○ Lambda関数はアプリ担当が変更を加えることが多く、デプロイの際に関数以外のことを意識しなくても 済むように ○ リソースはそれぞれ関連(参照)している場合が多く、生成や変更の順序に依存性があったりするので、 そういった点はTerraformで解決する 16

Slide 17

Slide 17 text

© LayerX Inc. まとめ ● 誰でもインフラ開発ができるように、一貫性のあるルールを設けて シンプルなファイル構成、再利用性の高いリソース定義にしよう ● タグを活用してリソースの管理状況を可視化しよう ● CI/CD環境を構築して処理を自動化し、チームメンバーがレビューできる ようにしよう ● plan実行時の差分を減らすためにコードをリファクタしよう ● ツールは1つに絞らず適材低所で採用しよう 17 開発スピードを落とさず、IaCもきちんと行うために: