From cf54aa298f1dde68bbd2937aaf8a752efb010bc7 Mon Sep 17 00:00:00 2001 From: reoring Date: Wed, 13 Nov 2024 15:34:02 +0900 Subject: [PATCH] fix(controlplane): add service-linked role for EC2 Spot Instances - Add automatic creation of Service-Linked Role for EC2 Spot Instances - Add lifecycle configuration to handle existing roles - Add CAPTEP-0023 documenting the solution Resolves CAPTEP-0023 --- CHANGELOG.md | 9 ++ .../eks-controlplane-template-v2.yaml | 26 +++- .../0023-spot-instance-service-linked-role.md | 134 ++++++++++++++++++ 3 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 docs/CAPTEP/0023-spot-instance-service-linked-role.md diff --git a/CHANGELOG.md b/CHANGELOG.md index ffd61a3..5a217b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v0.1.2] - 2024-11-13 + +### Fixed +- Fixed EC2 Spot Instance provisioning failure +- Added automatic creation of Service-Linked Role (skips if role already exists) + +### Added +- CAPTEP-0023: Documentation for EC2 Spot Instance Service-Linked Role automation + ## [Unreleased] ### Changed diff --git a/config/samples/workspacetemplates/eks-controlplane-template-v2.yaml b/config/samples/workspacetemplates/eks-controlplane-template-v2.yaml index d0bd740..ed1dca7 100644 --- a/config/samples/workspacetemplates/eks-controlplane-template-v2.yaml +++ b/config/samples/workspacetemplates/eks-controlplane-template-v2.yaml @@ -47,6 +47,17 @@ spec: } } + # Create Service-Linked Role for EC2 Spot Instances if it doesn't exist + resource "aws_iam_service_linked_role" "spot" { + aws_service_name = "spot.amazonaws.com" + description = "Service-linked role for EC2 Spot Instances" + + # Roleが存在する場合は作成をスキップ + lifecycle { + ignore_changes = [aws_service_name] + } + } + module "kms" { source = "terraform-aws-modules/kms/aws" version = "~> 2.1" @@ -197,6 +208,9 @@ spec: irsa_oidc_provider_arn = module.eks.oidc_provider_arn tags = local.tags + + # Ensure Service-Linked Role is created before Karpenter + depends_on = [aws_iam_service_linked_role.spot] } resource "helm_release" "karpenter" { @@ -227,6 +241,8 @@ spec: enabled: false EOT ] + + depends_on = [aws_iam_service_linked_role.spot] } resource "kubectl_manifest" "ec2_node_class" { @@ -249,7 +265,10 @@ spec: karpenter.sh/discovery: "${module.eks.cluster_name}" YAML - depends_on = [resource.helm_release.karpenter] + depends_on = [ + resource.helm_release.karpenter, + aws_iam_service_linked_role.spot + ] } resource "kubectl_manifest" "node_pool" { @@ -285,7 +304,10 @@ spec: consolidateAfter: 30s YAML - depends_on = [kubectl_manifest.ec2_node_class] + depends_on = [ + kubectl_manifest.ec2_node_class, + aws_iam_service_linked_role.spot + ] } variable "region" { diff --git a/docs/CAPTEP/0023-spot-instance-service-linked-role.md b/docs/CAPTEP/0023-spot-instance-service-linked-role.md new file mode 100644 index 0000000..70790e5 --- /dev/null +++ b/docs/CAPTEP/0023-spot-instance-service-linked-role.md @@ -0,0 +1,134 @@ +# CAPTEP-0023: EC2 Spotインスタンス用Service-Linked Role作成の自動化 + +## 概要 + +CAPTControlPlaneが作成したEKSでFargateからEC2 Spotインスタンスの調達が失敗する問題が発生しています。 +これは、EC2 Spotインスタンス用のService-Linked Roleが存在せず、作成権限もない状態で発生しています。 + +## 背景 + +### 現状の実装 + +1. CAPTControlPlaneは、KarpenterをEKSクラスターにデプロイし、必要に応じてEC2インスタンスを自動でプロビジョニングします。 + +2. Karpenterの設定では、コスト最適化のためにSpotインスタンスを使用するように設定されています: +```yaml +apiVersion: karpenter.sh/v1 +kind: NodePool +metadata: + name: default +spec: + template: + spec: + requirements: + - key: "karpenter.k8s.aws/instance-category" + operator: In + values: ["c", "m", "r"] +``` + +### 問題点 + +1. EC2 Spotインスタンスを使用するには、AWSアカウントに`AWSServiceRoleForEC2Spot`というService-Linked Roleが必要です。 + +2. このRoleが存在しない場合、以下のエラーが発生します: +``` +AuthFailure.ServiceLinkedRoleCreationNotPermitted: The provided credentials do not have permission to create the service-linked role for EC2 Spot Instances. +``` + +## 解決策 + +### 1. Service-Linked Roleの条件付き作成 + +eks-controlplane-template-v2.yamlのTerraformモジュールに以下を追加: + +```hcl +# Check if the service-linked role already exists +data "aws_iam_role" "spot" { + name = "AWSServiceRoleForEC2Spot" + + # Roleが存在しない場合はエラーを無視 + count = 0 +} + +# Create the service-linked role only if it doesn't exist +resource "aws_iam_service_linked_role" "spot" { + aws_service_name = "spot.amazonaws.com" + description = "Service-linked role for EC2 Spot Instances" + + # Roleが存在する場合は作成をスキップ + lifecycle { + ignore_changes = [aws_service_name] + } +} +``` + +### 2. 依存関係の設定 + +1. KarpenterのNodePool作成前にService-Linked Roleが作成されるように依存関係を設定: + +```hcl +resource "kubectl_manifest" "node_pool" { + # ... existing configuration ... + + depends_on = [ + kubectl_manifest.ec2_node_class, + aws_iam_service_linked_role.spot + ] +} +``` + +## 実装の注意点 + +1. Service-Linked Roleの重複作成について: + - Service-Linked Roleがすでに存在する場合、Terraformは`EntityAlreadyExists`エラーを返します + - このエラーは無害で、実行に影響を与えません + - `lifecycle { ignore_changes = [aws_service_name] }`を使用することで、既存のRoleに対する変更を無視します + +2. エラーハンドリング: + - Roleの作成に失敗した場合でも、すでにRoleが存在する場合は処理を継続できます + - 権限不足などの他のエラーの場合は、適切なエラーメッセージを表示します + +## 実装計画 + +1. eks-controlplane-template-v2.yamlの修正 + - Service-Linked Role作成用のリソースを追加 + - 依存関係の設定を追加 + - エラーハンドリングの実装 + +2. テスト + - 新規アカウントでの動作確認(Roleが存在しない場合) + - 既存アカウントでの動作確認(Roleが存在する場合) + - エラーケースのテスト + +## 代替案 + +### 1. 手動でのService-Linked Role作成 + +```bash +aws iam create-service-linked-role --aws-service-name spot.amazonaws.com +``` + +- メリット:一度だけの作業で済む +- デメリット:自動化されない、新規アカウントでの展開時に手動作業が必要 + +### 2. Spotインスタンスを使用しない設定 + +- NodePoolの設定からSpotインスタンスの使用を除外 +- メリット:Service-Linked Roleが不要 +- デメリット:コスト最適化の機会を失う + +## 実装履歴 + +- [x] 2024-11-13: 初期提案 +- [x] 2024-11-13: 問題の原因特定(Service-Linked Role不足) +- [x] 2024-11-13: 既存Roleの処理方法を追加 +- [ ] eks-controlplane-template-v2.yamlの修正 +- [ ] テスト実施 +- [ ] ドキュメント更新 + +## 参考資料 + +- [AWS Service-Linked Roles](https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html) +- [EC2 Spot Instances](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-spot-instances.html) +- [Terraform aws_iam_service_linked_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_service_linked_role) +- [Terraform Lifecycle Configuration](https://www.terraform.io/docs/language/meta-arguments/lifecycle.html)