Open20

友人とペアプロでWebアプリを作る過程の記録

ピン留めされたアイテム
ねおさんねおさん

概要

以下の目的があり、エンジニアの友人を誘ってペアプロでWebアプリを作ることにしました。

  • 業務外でなにかアプリを作りたい
  • システム構成やアーキテクチャ構築レベルから考えてアプリを作りたい
  • ペアプロによって生産性が上がるかを確かめたい
  • サーバレスなアプリを作りたい
  • 今ある知識でどの程度のアウトプットを作れるか確かめたい

作業過程を書き連ねていきます。

参加者一覧

HN(敬称略) 業界歴(開始時点) 技術スタック 備考
ねおさん 4年弱 業務ではAWS, Java, Vue, TypeScript / 業務外ではAtCoder Algo(茶), Rust 筆者
Teru 5年弱 Java, VB.NET / 業務外ではVue

作るもの

メンタリストDaigo氏の著書「コミュ障でも5分で増やせる超人脈術」で紹介されていた、
「ネットワークマップ」の作成と管理を容易にするアプリ

ユーザ自身の周辺人物情報を入力し、以下を表形式で出力できるもの

  • 自分にとっての重要人物(VIP)
  • そのVIPを紹介してくれた人物(Broker)
  • 自分がそのVIPを紹介した相手(Connect)
ねおさんねおさん

1回目

以下をざっくり4時間で行った。

  • 作成物の目的の説明
  • ペアプロのメリットなどを説明
    • レビューの手戻りをなくせる
    • 会話しながらの作業により、モチベーションを維持
    • お互いの知見・考えをその場で共有できる
    • 技量に差がある場合、互いにノウハウを得られる
  • ペアプロのルール決め
    • discordの画面共有で行う。
    • 25分ごとに5分休憩し、ドライバーとナビゲーターを交代
    • 4サイクルごとに20分休憩
  • 各種ツール決め
    • Notionでタスク管理
    • 必要なドキュメンテーションはGoogleスプレッドシート
  • システム構成作成
  • Notionアカウント作成
  • TerraformCloudアカウント作成

システム構成について

AWSベースで作成することにした。

想定しているシステム構成は以下の感じ

フロントエンド

  • AWS WAF
  • Route53
  • CloudFront
  • S3
    • Reactのアーティファクトを載せる

バックエンド

  • API Gateway
  • Lambda
    • Rustで実装
  • Cognito
  • SES
    • 人脈見直しリマインダ機能を想定

DB

※暫定

  • Aurora Serverless ※v1かv2かは未定
  • TiDB Serverless

CI/CD

  • CodeCommit
  • CodeBuild
  • CodeDeploy
  • CodePipeline

運用保守系

  • CloudWatch
  • SystemManager
  • SecretsManager
ねおさんねおさん

ここまでで思ったこと

こうして書いてみると、
アーキテクチャレベルから考えたことがなく感覚でやっているので、
アーキテクチャ設計やモデリングなどは体系的に学習した方がいいかなと思った。

ねおさんねおさん

2回目までの下準備

制作用のAWSアカウントを作成
私個人のAWSからOrganizationsを有効化し、
作るアプリの開発と本番環境用のAWSアカウントと、
Identity Centerでそれらアカウントにログインできるユーザを作成
これに伴い、私個人用のIAMユーザを削除し、Identity Centerで作成したユーザを使用することにした。

ねおさんねおさん

第二回

以下をざっくり2時間で行った。

ローカル環境の有無について議論

動確のたびに開発環境を使用する場合、デプロイのロードタイムが長いため
結果、必要ということに

CodeCommitリポジトリ作成

以下四つのリポジトリをCodeCommitに作成

  • フロント用
  • バックエンド用
  • インフラ用
  • ローカル環境DB
    • DockerでローカルにPostgreSQLを構築する想定

aws-cliの設定, CodeCommitリポジトリのクローン

IdentityCenterを使用しているので、下記の手順を参考にクローン
https://dev.classmethod.jp/articles/iam-identiy-center-codecommit/

バックエンドのプロジェクトの初期化

serverless install --url https://github.com/softprops/serverless-aws-rust

フロントエンドのプロジェクト初期化

npx create-react-app  . --templete typescript
ねおさんねおさん

第三回

ざっくり1.5時間で以下を行った

dev環境作成準備

devを作ってからそれに合わせてローカルを作るべきと判断

dev環境作成にあたり、以下の流れをとる

  1. 試しにdev環境にterraformからs3バケットを作成する
  2. terraformとcodebuildでdev環境にリソースをつくるパイプラインをつくる
  3. devのリソース一式をつくる

1 試しにdev環境にterraformからs3バケットをつくる

dev環境のawsアカウントから仮のterraform用IAMユーザを作成

tfbuckendファイルを作成

backend/dev.tfbackend
bucket = ****
key    = "****dev.tfstate"
region = "ap-northeast-1"
profile = ****

tfvarsファイル作成

vars/dev.tfvars
project     = ****
environment = "dev"
domain      = ""

terraform init

terraform init -reconfigure -backend-config="backend/dev.tfbackend"
main.tf
# ------------------------
# - Variables
# ------------------------

variable "project" {
  type = string
}
variable "environment" {
  type = string
}
variable "domain" {
  type = string
}

# ------------------------
# - Terraform configuratoions
# ------------------------
terraform {
  required_version = ">1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~>3.0"
    }
  }
}

# ------------------------
# - Provider 
# ------------------------

provider "aws" {
  profile = ****
  region  = "ap-northeast-1"
} 
temps3bucket.tf
# -------------------
# S3 static bucket
# -------------------
resource "aws_s3_bucket" "s3_test_bucket" {
  bucket = "test-bucket-${var.project}-${var.environment}"
}

terraform apply

terraform apply --auto-approve -var-file vars/dev.tfvars 


tfstateがローカルに作成された

ねおさんねおさん

init時にwarnが出ていたのを見落としていた...

Initializing the backend...

Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Using previously-installed hashicorp/aws v3.76.1

╷
│ Warning: Missing backend configuration
│
│ -backend-config was used without a "backend" block in the configuration.
│
│ If you intended to override the default local backend configuration,
│ no action is required, but you may add an explicit backend block to your
│ configuration to clear this warning:
│
│ terraform {
│   backend "local" {}
│ }
│
│ However, if you intended to override a defined backend, please verify that
│ the backend configuration is present and valid.
│
╵
ねおさんねおさん

main.tfにbackendの設定を記載したら解決

main.tf
# ------------------------
# - Terraform configuratoions
# ------------------------
terraform {
  required_version = ">1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~>3.0"
    }
  }
+  backend "s3" {
+    bucket = ****
+    key    = "****dev.tfstate"
+    region = "ap-northeast-1"
+    profile = ****
+  }
}


必要な設定は.tfbackendに記載しているので空のブロックでもよかった。

main.tf
# ------------------------
# - Terraform configuratoions
# ------------------------
terraform {
  required_version = ">1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~>3.0"
    }
  }
+  backend "s3" {
+  }
}
ねおさんねおさん

DBに関する議論

Aurora Serverlessの問題点

データ層にAurora Serverlessを使うと考えていたが、以下の問題が発覚。

  • Aurora Serverless v2は非使用時にキャパシティ(ACU)を0にすることができない。最低0.5ACU
    • 東京リージョンで 1ACU/h あたり0.2 USD
    • 0.5ACUを一ヶ月換算で 0.1USD * 24h * 30d * 150 JPY/USD = 10800JPY / M
    • 個人開発で使うにはあまりにも高い
  • Aurora Serverless v1は2024年中にサービス終了する

代わりのDBを考える

代替案

  1. DynamoDB
  2. CockroachDB Serverless
  3. TiDB Serverless

DynamoDB

  • メリット
    • リソースをAWS内部で完結させることができる。
    • 従量課金制のため、個人開発の範疇では破茶滅茶な料金にはならないはず
  • デメリット
    • DynamoDB特有のデータ設計が必要

CockroachDB Serverless

https://www.cockroachlabs.com/pricing/

Free for use up to 10 GiB of storage and 50M RUs per organization per month.

  • メリット
    • NewSQL。Google Spannerのクローン
    • PostgreSQL互換のIF
    • 無料枠が大きい
    • SQLの知識を使用できる
  • デメリット
    • リソースをAWS内で完結できない
    • LambdaからCockroachDBを使用する際のコネクションなどの検証が必要

TiDB Serverless

https://pingcap.co.jp/tidb-cloud-serverless-pricing-details/

各組織で作成された5つのクラスタを無料で使用することができます。6つ目のクラスタを作成する場合は、クレジットカードを追加し、使用限度額を設定する必要があります。6つ目のクラスタを作成する前に、既に作成したクラスタをいくつか削除した場合、新しいクラスタは無料枠のクラスタとカウントされ無料となります。
上記の条件を満たしたTiDB Serverlessのクラスタに対して、毎月フリークォータが発行されます。無料枠を利用することで、お客様は1ヶ月間、行ベースのデータ5GiBと列ベースのデータ5GiBを同時に保存し、5,000万RUを消費することができます。これらのクォータを自由に割り当てて、同等の運用を実現することも可能です。

  • メリット
    • NewSQL
    • MySQL互換のIF
    • 無料枠が大きい
    • SQLの知識を使用できる
    • Cockroachと比較してQiitaなどに情報が多そう(雑感)
  • デメリット
    • リソースをAWS内で完結できない
    • LambdaからTiDBを使用する際のコネクションなどの検証が必要

結論

TiDB Serverlessを検証する方向性で一致

ねおさんねおさん

第四回

3時間で以下を行った。

dev環境Infraパイプライン作成

Codebuildプロジェクト作成

infraブランチのbuildspec.ymlを以下のように設定

buildspec.yml
version: 0.2

env:
  variables:
    TERRAFORM_VERSION: "1.7.5"

phases:
  install:
    commands:
      - curl -sL https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip > terraform.zip
      - unzip terraform.zip
      - mv terraform /usr/local/bin/
  pre_build:
    commands:
      - terraform init -backend-config="backend/${ENVIRONMENT}.tfbackend"
      - terraform validate
      - terraform plan -var-file vars/${ENVIRONMENT}.tfvars
  build:
    commands:
      - terraform apply --auto-approve -var-file vars/${ENVIRONMENT}.tfvars

{環境名}.tfvars{環境名}.tfbackendを使用するため、
環境変数で{環境名}を渡すように指定

また、Codebuildのサービスロールを使用するため、各.tfbackendからprofileの設定を削除した。

backend/dev.tfbackend
bucket = ****
key    = "****dev.tfstate"
region = "ap-northeast-1"
- profile = ****

以下は調査と試行錯誤しながら調整した。

  • pre_buildフェーズのterraformのインストール
  • CodeBuildのサービスロール
    • 初期設定の場合にinitが落ちることを確認し、backendのS3バケットへのアクセス許可を追加
    • backendのS3バケットへのアクセス許可だけ追加したとき、applyが失敗することを確認し、必要なサービスへのアクセスを許可

CodePipelineを作成

infraリポジトリのdevelopブランチの変更を検知し、
自動的にビルドプロジェクトを実行させるようにした。

次回の予定

AWSアカウントを分割しているPRD環境のInfraパイプラインを作成する。
PRD環境アカウントにCodeBuildプロジェクトとCodePipelineを作成し、
CodeBuildからDEV環境アカウントのCodeCommitリポジトリを参照させる設定を構築する。

↓の記事を参考にする予定。
https://dev.classmethod.jp/articles/codepipeline-cross-account/

ねおさんねおさん

第五回

1.5時間で以下を行った

Prd環境Infraパイプライン作成試行

下記記事を参考に一部変更して試行
https://dev.classmethod.jp/articles/codepipeline-cross-account/

ソースの受け渡しのためだけにS3バケットを使いたくないため、
Prd環境のCodeBuildプロジェクトをDev環境のCodeCommitをソースとするプロジェクトの作成を試行
また、CodeBuildが別アカウントのCodeCommitを見れるようにAssumeRoleの権限を付与

prd-codebuild.json
{
  "name": "****-infra-prd",
  "description": "cross account build project",
  "source": {
    "type": "CODECOMMIT",
    "location": "https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/****infra",
    "gitCloneDepth": 1,
    "gitSubmodulesConfig": {
      "fetchSubmodules": false
    },
    "buildspec": "",
    "insecureSsl": false
  },
  "sourceVersion": "refs/heads/master",
  "serviceRole": "arn:aws:iam::*****:role/******",
  "artifacts": {
    "type": "NO_ARTIFACTS"
  },
  "environment": {
    "type": "LINUX_CONTAINER",
    "image": "aws/codebuild/amazonlinux2-x86_64-standard:5.0",
    "computeType": "BUILD_GENERAL1_SMALL",
    "environmentVariables": [
      {
        "name": "ENVIRONMENT",
        "value": "prd",
        "type": "PLAINTEXT"
      }
    ],
    "privilegedMode": false,
    "imagePullCredentialsType": "CODEBUILD"
  }
}
aws codebuild create-project --cli-input-json file://prd-codebuild.json --profile {prd環境用profile}

リポジトリが存在するアカウントを指定できていないため(そもそもできるか要調査)
当然成功せず

リソース管理再構成案

以下の理由によりソースをGithubに移し、
パイプラインも含めてTerraformCloudで管理したほうがいいと考えた。

  • CodeBuild、ロール、ポリシー、CodePipelineを手動で作成してしまっており、管理が煩雑
  • Infra用のソースを含むリポジトリがDev環境のCodeCommitにある都合上、Infraのパイプラインがどうしても手動作成になる。

次回予定

ソースをすべてGithubに移し、Dev環境とPrd環境の各リソースをTerraformCloudで管理するように変更

ねおさんねおさん

第六回

2h近くで以下を実施

  • ソースをすべてGithubに移動
  • Dev環境とPrd環境のCodebuildプロジェクトおよびCodePipelineと、関連するIAMポリシー・ロールを削除

Githubの組織無料版の場合、ブランチ保護設定を付加することができないことが判明

次回予定

  • TerraformCloud連携
  • バックエンドパイプライン作成
ねおさんねおさん

第七回

1.5hで以下を実施

  • Terraform Cloudプロジェクトおよびワークスペースの作成

作成したTerraform Cloud Workspace

Github上のinfraリポジトリと連携
PRD環境AWSアカウントに対してはmasterブランチ、
DEV環境AWSアカウントに対してはdevelopブランチに対して下記が実施される設定を行う

  • PR作成時にplan
  • merge時にapply
    今回はDEV環境の設定のみ完了

次回予定

PRD環境workspaceの設定
バックエンドのパイプライン作成、DEV環境にお試しデプロイ

ねおさんねおさん

第八回

1.5hで以下を実施

  • TerraformCloudのPRD環境の設定
  • TerraformでバックエンドのCodeBuildプロジェクトを作成

CodeBuildプロジェクト作成時

AWSコンソール上でGithubとOAuthで接続し、
そのままTerraform上でGithubのソースを指定することができる。

次回予定

DEV環境バックエンドパイプラインの作成
バックエンドのお試しデプロイ

ねおさんねおさん

第九回

2.5hで以下を実施

バックエンドのリソース管理を変更

バックエンドに関する以下リソース群をすべてServerless Frameworkで管理する想定だった

  • Lambda
  • API Gateway
  • Cognito

しかしバックエンドとして複数のLambdaを構築する構成は、Pythonやnode.jsのように簡単にはできず、ソース管理が煩雑になる。
よって単一のLambdaでバックエンドを構築する。
このためServerlessを使用する必要性が薄くなったと判断
リソース管理はすべてTerraformに寄せる。

バックエンドの構成

lambda_webactix_webを使用し、単一のLambdaでバックエンドサーバとする
以下のサンプルを作成

Cargo.toml
[package]
name = "****"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
actix-web = "4.8.0"
lambda-web = { version = "0.2.1", features =["actix4"] }
lambda_runtime = "0.12.0"
tokio = "1.38.0"
main.rs
use lambda_web::actix_web::{self, get, App, HttpServer, Responder};
use lambda_web::{is_running_on_lambda, run_actix_on_lambda, LambdaError};

#[get("/")]
async fn hello() -> impl Responder {
    format!("Hello")
}

#[actix_web::main]
async fn main() -> Result<(), LambdaError> {
    let factory = move || App::new().service(hello);

    if is_running_on_lambda() {
        // Run on AWS Lambda
        run_actix_on_lambda(factory).await?;
    } else {
        // Local server
        HttpServer::new(factory)
            .bind("127.0.0.2:8080")?
            .run()
            .await?;
    }

    Ok(())
}

次回予定

Terraformで以下を作成および調整し、バックエンドのパイプラインを完成させる

  • Lambda
  • API Gateway
  • CodeBuild
  • CodePipeline
ねおさんねおさん

第十回

3h強で以下を実施

バックエンドパイプライン構築継続

先にソースなしのLambda作成を試みるも、
大前提としてそんなLambdaは作れない(それはそう)

resource "aws_iam_role" "backend_lambda_exec_role" {
  name = "${var.project}-${var.environment}-lambda-exec-role"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

resource "aws_lambda_function" "lambda_backend" {
  function_name = "lambda-${var.project}-${var.environment}-backend"
  role          = aws_iam_role.backend_lambda_exec_role.arn
  handler       = "bootstrap" // Rustの場合、ハンドラーは通常 "bootstrap" となります

  runtime = "provided" // カスタムランタイムの場合、"provided" を指定します

  environment {
  }
}


先にcodebuildの設定を行い、アーティファクトをs3に配置する。

# -------------------
# codebuildアーティファクト配置先S3バケットを作成
# -------------------
resource "aws_s3_bucket" "s3_artifact_backend_bucket" {
  bucket = "artifact-backend-bucket-${var.project}-${var.environment}"
}


# codebuildのポリシー
resource "aws_codebuild_project" "backend_codebuild_project" {
  name          = "${var.project}-${var.environment}-backend-project" // プロジェクトの名前
  description   = "${var.environment}-backend CodeBuild project"      // プロジェクトの説明
  build_timeout = "5"                                                 // ビルドがタイムアウトするまでの時間(分)
  service_role  = aws_iam_role.role_for_backend_codebuild.arn         // プロジェクトが使用するIAMロールのARN

  // ビルドのアーティファクト(出力)に関する設定
  artifacts {
-    type = "NO_ARTIFACTS" // アーティファクトを生成しない設定
+    type      = "S3"
+    location  = aws_s3_bucket.s3_artifact_backend_bucket.bucket
+    name      = "backend_binary.zip"
+    packaging = "ZIP"
  }

  // ビルド環境に関する設定
  environment {
    compute_type                = "BUILD_GENERAL1_SMALL"
-    image                       = "aws/codebuild/standard:4.0" // 使用するDockerイメージ
+    image                       = "rust:latest" // RustのDockerイメージ
    type                        = "LINUX_CONTAINER"
    image_pull_credentials_type = "CODEBUILD"
    privileged_mode             = true
  }

  // ソースに関する設定
  source {
    type            = "GITHUB"                                                 // ソースのタイプ
    location        = "https://github.com/******/*****.git" // ソースの場所(GitHubリポジトリのURL)
    git_clone_depth = 1                                                        // クローンするGitの深さ
  }
  source_version = var.branch // ビルド仕様ファイルのパス

+  logs_config {
+    cloudwatch_logs {
+      group_name = "****"
+    }
+  }
}

// CodeBuildプロジェクトが使用するIAMロールを作成するリソース
resource "aws_iam_role" "role_for_backend_codebuild" {
  name = "role-for-${var.project}-${var.environment}-backend-codebuild" // IAMロールの名前

  // IAMロールの信頼ポリシー
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "codebuild.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

+resource "aws_iam_role_policy" "backend_codebuild_policy" {
+  name = "${var.project}-${var.environment}-backend-codebuild-policy"
+  role = aws_iam_role.role_for_backend_codebuild.id
+
+  policy = <<EOF
+{
+  "Version": "2012-10-17",
+  "Statement": [
+    {
+      "Effect": "Allow",
+      "Action": [
+        "logs:CreateLogGroup",
+        "logs:CreateLogStream",
+        "logs:PutLogEvents"
+      ],
+      "Resource": "arn:aws:logs:*:*:*"
+    },
+    {
+      "Effect": "Allow",
+      "Action": [
+        "s3:PutObject",
+        "s3:GetObject",
+        "s3:ListBucket"
+      ],
+      "Resource": [
+        "${aws_s3_bucket.s3_artifact_backend_bucket.arn}",
+        "${aws_s3_bucket.s3_artifact_backend_bucket.arn}/*"
+      ]
+    }
+  ]
+}
+EOF
+}

ビルド時間に関する問題

ビルド成功時の所要時間が5分弱
短縮のため、compute_typeの変更及びキャッシュを検討

雑感

過去の記録から大体のベロシティが推測できそう (そもそも各タスクにストーリーポイント的な見積もりをしているわけではないが)
次回予定の欄はそれを参考に記述し、予実比較してみる
また、AWSサービスのポリシー・ロール回りの調整に大苦戦している傾向がある。
今回の構築を経て糧としたい。

次回予定

  • codebuildのキャッシュの設定
  • lambdaの作成
ねおさんねおさん

第十一回

ざっくり3hで以下を行った

codebuildのキャッシュ用S3バケットを作成

codebuildプロジェクトにキャッシュ用の設定を追加

+  // キャッシュに関する設定
+  cache {
+    type     = "S3"
+    location = aws_s3_bucket.s3_cache_bucket.bucket
+  }

前回作成したアーティファクトをもとにlambdaを作成

以下の形で作成を試みるも失敗

resource "aws_iam_role" "backend_lambda_exec_role" {
  name = "${var.project}-${var.environment}-lambda-exec-role"
  s3_bucket = aws_s3_bucket.s3_artifact_bucket.bucket
  s3_key    = "backend_binary.zip"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

resource "aws_lambda_function" "lambda_backend" {
  function_name = "lambda-${var.project}-${var.environment}-backend"
  role          = aws_iam_role.backend_lambda_exec_role.arn
  handler       = "bootstrap" // Rustの場合、ハンドラーは通常 "bootstrap" となります

  runtime = "provided" // カスタムランタイムの場合、"provided" を指定します
}


ランタイムprovidedはもう新規で使えない。provided.al2023を使えと言われる
ので変更を試みるも失敗

-  runtime = "provided" // カスタムランタイムの場合、"provided" を指定します
+ runtime = "provided.al2023"


プロバイダが古かった

# ------------------------
# - Terraform configuratoions
# ------------------------
terraform {
  required_version = ">1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
-      version = "~>3.0"
+      version = "~>5.0"
    }
  }
}

init -upgaradeを実施し、.terraform.lock.hclを更新

terraform init -upgrade


Lambda作成成功

Lambda動作確認

Lambdaのコンソールでテストを実施してみる

INIT_REPORT Init Duration: 0.23 ms	Phase: init	Status: error	Error Type: Runtime.InvalidEntrypoint
INIT_REPORT Init Duration: 9.04 ms	Phase: invoke	Status: error	Error Type: Runtime.InvalidEntrypoint
START RequestId: dd427788-f018-435e-97a1-c9fb85107c1b Version: $LATEST
RequestId: dd427788-f018-435e-97a1-c9fb85107c1b Error: Couldn't find valid bootstrap(s): [/var/task/bootstrap /opt/bootstrap]
Runtime.InvalidEntrypoint
END RequestId: dd427788-f018-435e-97a1-c9fb85107c1b
REPORT RequestId: dd427788-f018-435e-97a1-c9fb85107c1b	Duration: 10.22 ms	Billed Duration: 11 ms	Memory Size: 128 MB	Max Memory Used: 2 MB	

bootstrap置けと言われている。
アーティファクトが誤っている

lambda-webのリポジトリにサンプルのbuildspec.ymlがあるので、それをもとに修正
https://github.com/hanabu/lambda-web/blob/main/buildspec.yml

version: 0.2

phases:
  install:
    runtime-versions:
      rust: latest
  build:
    commands:
+      - rustc -V
      - cargo build --release
+      - mv target/release/d-nexus-backend bootstrap
+      - strip --strip-all bootstrap
+      - size bootstrap
+      - ldd bootstrap

artifacts:
  files:
-    - target/release/*
+    - bootstrap

再ビルドし、動作確認

{
  "version": "2.0",
  "routeKey": "$default",
  "rawPath": "/",
  "rawQueryString": "parameter1=value1&parameter1=value2&parameter2=value",
  "cookies": ["cookie1", "cookie2"],
  "headers": {
    "header1": "value1",
    "header2": "value1,value2"
  },
  "queryStringParameters": {
    "parameter1": "value1,value2",
    "parameter2": "value"
  },
  "requestContext": {
    "accountId": "123456789012",
    "apiId": "<urlid>",
    "authentication": null,
    "authorizer": {
      "iam": {
        "accessKey": "AKIA...",
        "accountId": "111122223333",
        "callerId": "AIDA...",
        "cognitoIdentity": null,
        "principalOrgId": null,
        "userArn": "arn:aws:iam::111122223333:user/example-user",
        "userId": "AIDA..."
      }
    },
    "domainName": "<url-id>.lambda-url.us-west-2.on.aws",
    "domainPrefix": "<url-id>",
    "http": {
      "method": "POST",
      "path": "/",
      "protocol": "HTTP/1.1",
      "sourceIp": "123.123.123.123",
      "userAgent": "agent"
    }
  },
  "body": "{\"query\":\"{ hello }\"}",
  "pathParameters": null,
  "isBase64Encoded": false,
  "stageVariables": null
}

動作確認成功

{
  "body": "eyJkYXRhIjp7ImhlbGxvIjoiSGVsbG8sIHdvcmxkISJ9fQ==",
  "cookies": [],
  "headers": {
    "content-type": "application/json"
  },
  "isBase64Encoded": true,
  "statusCode": 200
}

居残り

その後、以下を行った

  • ビルドマシンをdockerイメージからcodebuildで用意されているものに変更
  • buildspec.ymlのinsatllフェーズでrustをインストールするようにする
  • installしたrust自体をキャッシュするようにする
ねおさんねおさん

第十二回

おおよそ1.5時間と筆者の居残りで以下を行った。

パイプライン構築(バックエンド)

CodePipelineによる自動デプロイの構築を試行したが、失敗

最終的にはバックエンドのbuildspec.ymlを下記のように変更、
都度、Codebuildを実行することで対応することとした

buildspec.yml
version: 0.2

env:
  variables:
    DEPLOY_TARGET: "backend"

phases:
  install:
    commands:
      - if [ -f "$HOME/.cargo/env" ]; then
        echo load-env;
        . $HOME/.cargo/env;
        echo rustup-update;
        rustup update;
        else
        echo rustup-install;
        curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y;
        echo load-env;
        . $HOME/.cargo/env;
        echo install-cargo-cache;
        cargo install cargo-cache;
        fi
  build:
    commands:
      - rustc -V
      - cargo build --release
      - mv target/release/d-nexus-backend bootstrap
      - strip --strip-all bootstrap
      - size bootstrap
      - ldd bootstrap
      - zip bootstrap.zip bootstrap
  post_build:
    commands:
      - aws lambda update-function-code --function-name $DEPLOY_TARGET --zip-file fileb://bootstrap.zip

artifacts:
  files:
    - bootstrap

cache:
  paths:
    - $HOME/.cargo/env
    - $HOME/.cargo/bin/**/*
    - $HOME/.cargo/registry
    - $HOME/.cargo/git
    - target/release/deps

理由としてそもそも基本的に作業自体はペアプロするタイミングでしか行わないため、
工数をかけてまで自動デプロイを構築する旨みが薄いと判断。

ねおさんねおさん

第十三回

1.5hで以下を実施

API GatewayおよびCognito関連の構成を検討

Cognitoによるサインアップおよびログイン機能の実装方針を検討した。
下記のうち1が不可能、3のカスタマイズ性の低さから、2の方針に決定。

  1. API GatewayとCognitoを直接統合し、サインアップ・ログインAPIを提供
  2. API GatewayとCognitoの間にLambdaを挟み、サインアップ・ログインAPIを提供
  3. Cognito Hosted UIを使用

また、直近で以下を順に構築する方針にする。
Ⅰ. Cognitoユーザプールを作成
Ⅱ. API Gatewayを作成
Ⅲ. API GatewayとバックエンドのLambdaの統合と作成
Ⅳ. Cognito関連のAPI用のLambdaを別途作成

auth.tf
resource "aws_cognito_user_pool" "user_pool" {
  name = "${var.project}-${var.environment}-pool"
}

resource "aws_cognito_user_pool_client" "user_pool_client" {
  name            = "${var.project}-${var.environment}-client"
  user_pool_id    = aws_cognito_user_pool.user_pool.id
  generate_secret = true
}
backend_api.tf
resource "aws_api_gateway_rest_api" "rest_api" {
  name        = "${var.project}-${var.environment}-api"
  description = "${var.project}-${var.environment} API Gateway"
}

resource "aws_api_gateway_method" "backend_method" {
  rest_api_id   = aws_api_gateway_rest_api.rest_api.id
  resource_id   = aws_api_gateway_rest_api.rest_api.root_resource_id
  http_method   = "POST"
  authorization = "NONE"
}

resource "aws_api_gateway_integration" "backend_integration" {
  rest_api_id             = aws_api_gateway_rest_api.rest_api.id
  resource_id             = aws_api_gateway_rest_api.rest_api.root_resource_id
  http_method             = aws_api_gateway_method.backend_method.http_method
  type                    = "HTTP"
  integration_http_method = "ANY"
  uri                     = aws_lambda_function.lambda_backend.invoke_arn
}

resource "aws_api_gateway_deployment" "rest_api_deployment" {
  depends_on  = [aws_api_gateway_integration.backend_integration]
  rest_api_id = aws_api_gateway_rest_api.rest_api.id
  stage_name  = var.environment
}

resource "aws_lambda_permission" "apigw_lambda" {
  statement_id  = "AllowAPIGatewayInvoke"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.lambda_backend.function_name
  principal     = "apigateway.amazonaws.com"

  source_arn = "${aws_api_gateway_rest_api.rest_api.execution_arn}/*/*"
}

Ⅲ以降を次回に構築

ねおさんねおさん

第十四回

以下を実施

  • lambda_webクレートが使いづらかったためコンテナ化し、web-adapterを使用
  • CICDを変更
  • API Gateway再作成