🦔

AWS学びなおし(+TF)_Lambda

2025/03/06に公開

AWS Lambdaは、サーバーレスコンピューティングサービスの一つで、サーバーの管理を一切気にすることなくコードを実行できるサービスです。

基本的な概念:

  • サーバーレス: サーバーのプロビジョニングや管理はAWSが行うため、利用者はインフラの管理から解放され、コードの実行に集中できます。
  • イベント駆動: Lambda関数は、特定のイベント(例えば、S3へのファイルアップロード、API Gatewayからのリクエスト、CloudWatch Eventsによるスケジュール実行など)をトリガーとして実行されます。
  • 関数: Lambdaの実行単位は「関数」と呼ばれるコードの塊です。この関数は、Node.js、Python、Java、Go、Ruby、.NET、Custom Runtimeなど、様々なプログラミング言語で記述できます。
  • 実行環境: Lambda関数は、AWSが提供する安全で隔離された実行環境で実行されます。必要なコンピューティングリソース(CPU、メモリ)は、関数の設定に基づいて自動的に割り当てられます。
  • 従量課金: Lambdaの料金体系は、実際にコードが実行された時間と、割り当てられたメモリ量に基づいて課金される従量課金制です。コードが実行されていない間は料金は発生しません。(無料利用枠あり)

Lambdaのメリット:

  • 運用効率の向上: サーバー管理が不要なため、運用コストと手間を大幅に削減できます。
  • 高いスケーラビリティ: イベント数やリクエスト数に応じて自動的にスケールするため、トラフィックの変動に柔軟に対応できます。
  • コスト削減: 従量課金制のため、使用した分だけ料金が発生し、無駄なコストを削減できます。
  • 迅速な開発: インフラ構築の時間を削減し、開発者はビジネスロジックの実装に集中できます。

Lambdaのデメリット:

  • 実行時間制限: Lambda関数には実行時間制限(最大15分)があります。長時間処理が必要なタスクには不向きです。
  • コールドスタート: 関数が長時間実行されていない場合、最初の実行時に初期化処理が発生し、遅延(コールドスタート)が発生する可能性があります。
  • ステートレス: Lambda関数はステートレスであるため、状態を保持するには外部のストレージサービス(S3、DynamoDBなど)を利用する必要があります。
  • デバッグの難しさ: ローカル環境でのデバッグがサーバーレス環境特有の制約により、やや複雑になる場合があります。

Lambdaの料金体系:

  • リクエスト数: 関数が呼び出された回数に基づいて課金されます。
  • コンピューティング時間: 関数が実行された合計時間(ミリ秒単位)と、割り当てられたメモリ量に基づいて課金されます。
  • 無料利用枠: 毎月100万リクエストと、月間40万GB秒のコンピューティング時間が無料枠として提供されます。

Lambdaの主なユースケース:

  • APIバックエンド: API Gatewayと連携し、REST APIのバックエンドとして利用できます。
  • イベント駆動処理: S3、DynamoDB、SNSなどのAWSサービスからのイベントをトリガーとして、データ処理やワークフローの自動化に利用できます。
  • バッチ処理: 定期的なバッチ処理や、非同期タスクの実行に利用できます。
  • チャットボット: 会話型インターフェースのバックエンドとして利用できます。
  • IoTバックエンド: IoTデバイスからのデータを処理するバックエンドとして利用できます。

【実務レベルの内容と重要事項】

実務レベルの内容:

  • Lambda関数設定:

    • メモリ: 関数に割り当てるメモリ量を設定します。メモリ量を増やすと、CPU性能も向上し、処理速度が向上する場合があります。ただし、コストも増加します。
    • タイムアウト: 関数の最大実行時間を設定します。処理時間を見積もり、適切なタイムアウトを設定する必要があります。
    • 環境変数: 関数内で利用する設定値(APIキー、データベース接続情報など)を環境変数として設定できます。機密情報は暗号化して保存することが推奨されます。
    • VPC設定: Lambda関数をVPC内部のリソース(RDS、EC2など)にアクセスさせる必要がある場合、VPC設定を行う必要があります。
    • IAMロール: Lambda関数がAWSリソースにアクセスするための権限をIAMロールで定義します。必要最小限の権限を与えることがセキュリティ上のベストプラクティスです。
    • レイヤー: 複数のLambda関数で共通して利用するライブラリやランタイムをレイヤーとして分離し、デプロイサイズを削減し、管理性を向上させることができます。
    • コンテナイメージ: Lambda関数をコンテナイメージとしてデプロイできます。複雑な依存関係を持つアプリケーションや、カスタムランタイムを利用する場合に有効です。
    • Concurrency制御: 同時実行数を制御することで、ダウンストリームシステムへの負荷を調整したり、コストを最適化することができます。(予約済み concurrency、プロビジョニング済み concurrency)
    • デッドレターキュー (DLQ): 関数実行が失敗した場合に、エラー情報をDLQに送信するように設定できます。エラーハンドリングと再試行処理を実装する上で重要です。
    • モニタリングとロギング: CloudWatch Logs、CloudWatch Metricsを活用して、Lambda関数の実行状況、パフォーマンス、エラーを監視します。
  • デプロイ戦略:

    • zipファイルデプロイ: 一般的なデプロイ方法。関数コードと依存ライブラリをzipファイルにまとめてアップロードします。
    • コンテナイメージデプロイ: コンテナイメージをEcrにプッシュし、Lambda関数から参照します。
    • Blue/Greenデプロイ、カナリアリリース: 段階的なデプロイ戦略を用いて、リスクを低減し、安定したデプロイを実現できます。
    • Lambda@Edge: CloudFrontと連携し、エッジロケーションでLambda関数を実行することで、低レイテンシでコンテンツ配信を最適化できます。

重要事項:

  • セキュリティ: IAMロールによる最小権限の原則、環境変数の暗号化、VPC設定によるネットワークセキュリティなど、セキュリティ対策は非常に重要です。
  • パフォーマンス: メモリ設定、コードの最適化、コールドスタート対策(Provisioned Concurrencyなど)など、パフォーマンスチューニングは実務において重要な課題です。
  • エラーハンドリング: エラー発生時の処理(リトライ、DLQへの送信、ロギングなど)を適切に実装することで、システムの安定性を向上させることができます。
  • モニタリング: CloudWatch Logs、CloudWatch Metricsを活用した継続的なモニタリングは、問題の早期発見と解決に不可欠です。
  • コスト最適化: メモリ設定の最適化、不要な関数の削除、Concurrency制御などを通じて、コストを最適化することが重要です。
  • テスト: ユニットテスト、結合テスト、E2Eテストなど、様々なレベルでのテストを実施し、品質を確保することが重要です。

【実務でどの程度使用されるのか】

AWS Lambdaは、実務で非常に広く利用されています。

利用状況:

  • マイクロサービスアーキテクチャ: マイクロサービスのバックエンドとしてLambdaを活用することで、独立性の高い、スケーラブルなサービスを構築できます。
  • APIバックエンド: API Gatewayと組み合わせることで、サーバーレスなREST APIを容易に構築できます。Webアプリケーション、モバイルアプリケーション、外部システムとの連携など、幅広い用途で利用されています。
  • イベントドリブンアーキテクチャ: S3、DynamoDB、SNSなどのAWSサービスと連携し、イベント駆動型のシステム構築に広く利用されています。データ処理、ワークフロー自動化、リアルタイム処理など、様々なユースケースに対応できます。
  • バッチ処理: 定期的なバッチ処理や、非同期タスクの実行基盤として利用されています。スケジュール実行や、イベントトリガーによる実行など、柔軟な実行方法が可能です。
  • データパイプライン: データレイク、データウェアハウス構築において、データ抽出、変換、ロード (ETL/ELT) 処理をLambdaで実装するケースが増えています。
  • AI/ML推論: 機械学習モデルの推論エンドポイントとしてLambdaを利用し、リアルタイム推論処理を実現できます。

利用されている企業規模・業界:

スタートアップからエンタープライズ企業まで、規模や業界を問わず幅広く利用されています。特に、Webサービス、モバイルアプリケーション、金融、メディア、小売、製造など、多くの業界で採用事例があります。

Lambda採用の判断基準:

  • 開発スピード: サーバーレスであるため、インフラ構築の時間を大幅に削減でき、開発スピードを向上させたい場合に有効です。
  • スケーラビリティ: トラフィック変動に自動的に対応できるスケーラビリティが求められるシステムに適しています。
  • コスト: 従量課金制のため、初期投資を抑え、利用状況に応じたコスト最適化が可能です。
  • 運用負荷: サーバー管理から解放されるため、運用負荷を軽減したい場合に有効です。
  • イベント駆動: イベント駆動型のシステムアーキテクチャを採用する場合、Lambdaは最適な選択肢の一つとなります。

Lambdaの今後の展望:

サーバーレス技術は、クラウドコンピューティングの重要なトレンドとして、今後もますます普及していくと考えられます。Lambdaも、機能拡張、パフォーマンス向上、開発者体験の向上など、継続的な進化が期待されます。コンテナイメージサポートの強化、より高度なConcurrency制御、Observability機能の向上などが、今後の注目ポイントです。

【terraformのコードで記述する場合の基本的内容と実務レベルの内容】

terraformのコードで記述する場合の基本的内容:

resource "aws_lambda_function" "example" {
  function_name    = "my-lambda-function"
  runtime          = "python3.9"
  handler          = "lambda_function.handler"
  timeout          = 30
  memory_size      = 512
  role             = aws_iam_role.lambda_role.arn
  # zipファイルでデプロイする場合
  s3_bucket        = "my-deployment-bucket"
  s3_key           = "lambda-function.zip"

  # 環境変数
  environment {
    variables = {
      API_KEY = "your_api_key"
      DB_HOST = "your_db_host"
    }
  }
}

resource "aws_iam_role" "lambda_role" {
  name = "lambda-execution-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "lambda.amazonaws.com"
        }
      },
    ]
  })
}

resource "aws_iam_policy_attachment" "lambda_policy_attachment" {
  name       = "lambda-policy-attachment"
  roles      = [aws_iam_role.lambda_role.name]
  policy_arn = "arn:aws:iam::aws:policy/AWSLambdaBasicExecutionRole" # 基本的なLambda実行権限ポリシー
}

コードの説明:

  • aws_lambda_function リソースでLambda関数を定義します。
    • function_name: Lambda関数名
    • runtime: ランタイム環境(Python 3.9)
    • handler: エントリーポイントとなる関数名(lambda_function.pyhandler関数)
    • timeout: タイムアウト時間(秒)
    • memory_size: 割り当てるメモリ量(MB)
    • role: IAMロールのARN。Lambda関数がAWSリソースにアクセスするための権限を定義します。
    • s3_bucket, s3_key: デプロイ用zipファイルが格納されたS3バケットとキー。
    • environment: 環境変数を設定します。
  • aws_iam_role リソースでLambda関数にアタッチするIAMロールを定義します。
    • assume_role_policy: Lambdaサービスがこのロールを引き受けるためのポリシー。
  • aws_iam_policy_attachment リソースでIAMロールにポリシーをアタッチします。
    • policy_arn: AWSLambdaBasicExecutionRole は、CloudWatch Logsへの書き込みなど、基本的なLambda実行に必要な権限を持つポリシーです。

実務レベルの内容:

# 変数定義 (variables.tf)
variable "function_name" {
  type = string
  default = "my-advanced-lambda-function"
}

variable "runtime" {
  type = string
  default = "python3.9"
}

variable "handler" {
  type = string
  default = "lambda_function.handler"
}

variable "memory_size" {
  type = number
  default = 512
}

variable "timeout" {
  type = number
  default = 60
}

variable "deployment_bucket" {
  type = string
  default = "my-deployment-bucket"
}

variable "deployment_key" {
  type = string
  default = "lambda-function.zip"
}

variable "environment_variables" {
  type = map(string)
  default = {
    STAGE = "dev"
    LOG_LEVEL = "INFO"
  }
}

variable "vpc_subnet_ids" {
  type    = list(string)
  default = ["subnet-xxxxxxxxxxxxxxxxx", "subnet-yyyyyyyyyyyyyyyyy"] # VPC サブネットID
}

variable "vpc_security_group_ids" {
  type    = list(string)
  default = ["sg-xxxxxxxxxxxxxxxxx"] # VPC セキュリティグループID
}

# IAMロールとポリシー (iam.tf)
resource "aws_iam_role" "lambda_role" {
  name = "${var.function_name}-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "lambda.amazonaws.com"
        }
      },
    ]
  })
}

resource "aws_iam_policy" "lambda_policy" {
  name        = "${var.function_name}-policy"
  description = "Policy for ${var.function_name} Lambda function"
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action   = [ # 必要最小限の権限を付与
          "logs:CreateLogGroup",
          "logs:CreateLogStream",
          "logs:PutLogEvents",
          "s3:GetObject", # S3へのGetObject権限 (例)
          "dynamodb:GetItem", # DynamoDBへのGetItem権限 (例)
        ]
        Effect   = "Allow"
        Resource = "*"
      },
    ]
  })
}

resource "aws_iam_role_policy_attachment" "lambda_policy_attachment" {
  name       = "${var.function_name}-policy-attachment"
  roles      = [aws_iam_role.lambda_role.name]
  policy_arn = aws_iam_policy.lambda_policy.arn
}

# Lambda関数 (lambda.tf)
resource "aws_lambda_function" "example" {
  function_name    = var.function_name
  runtime          = var.runtime
  handler          = var.handler
  memory_size      = var.memory_size
  timeout          = var.timeout
  role             = aws_iam_role.lambda_role.arn
  s3_bucket        = var.deployment_bucket
  s3_key           = var.deployment_key

  environment {
    variables = var.environment_variables
  }

  vpc_config {
    subnet_ids         = var.vpc_subnet_ids
    security_group_ids = var.vpc_security_group_ids
  }

  # タグ付け (運用・管理のために重要)
  tags = {
    Name        = var.function_name
    Environment = var.environment_variables["STAGE"]
    ManagedBy   = "Terraform"
  }
}


# Lambda Layerの定義例 (layers.tf)
resource "aws_lambda_layer_version" "example_layer" {
  layer_name = "${var.function_name}-layer"
  s3_bucket   = var.deployment_bucket
  s3_key      = "lambda-layer.zip" # レイヤー用zipファイル
  compatible_runtimes = [var.runtime]
}

# Lambda関数にLayerを適用 (lambda.tf に追記)
resource "aws_lambda_function" "example" {
  # ... (上記 Lambda 関数の定義) ...

  layers = [
    aws_lambda_layer_version.example_layer.arn,
  ]
}

実務レベルのポイント:

  • 変数化: 関数名、ランタイム、メモリサイズ、環境変数などを変数化することで、再利用性と柔軟性を高めます。variables.tf で変数を定義し、terraform.tfvars や 環境変数で値を設定するのが一般的です。
  • モジュール化: IAMロール、ポリシー、Lambda関数などをモジュールに分割することで、コードの可読性と保守性を向上させます。
  • IAMポリシーの最小権限: Lambda関数に必要な権限のみを付与するIAMポリシーを定義します。aws_iam_policy リソースで詳細なポリシーを記述します。
  • VPC設定: VPC内のリソースにアクセスする必要がある場合は、vpc_config ブロックでVPC設定を行います。サブネットID、セキュリティグループIDを適切に設定します。
  • タグ付け: リソースに適切なタグを付与することで、運用管理、コスト管理を容易にします。tags ブロックでタグを設定します。
  • Lambda Layer: 共通ライブラリやランタイムをLayerとして分離することで、デプロイサイズの削減、管理性の向上を図ります。aws_lambda_layer_version リソースでLayerを定義し、layers 属性でLambda関数に適用します。
  • 状態管理: Terraformの状態ファイル (terraform.tfstate) を適切に管理することが重要です。S3 Backendなどを利用して、状態ファイルをリモートで安全に管理することを推奨します。
  • バージョン管理: TerraformコードをGitなどのバージョン管理システムで管理し、変更履歴を追跡できるようにします。
  • CI/CD: Terraform CloudやGitHub ActionsなどのCI/CDツールと連携することで、Terraformコードの自動テスト、デプロイを効率化できます。

上記はあくまで基本的な例です。実際の運用環境では、より複雑な構成や設定が必要になる場合があります。例えば、API Gatewayとの連携、Step Functionsとの連携、CloudWatch Eventsによるスケジュール実行設定、Concurrency制御設定、DLQ設定など、様々な設定をTerraformで記述する必要があります。また、セキュリティ、パフォーマンス、コスト最適化など、非機能要件も考慮したTerraformコードを記述することが重要です。

Discussion