AWS EKSクラスタでArmコンテナを動かす方法

この記事では、AWS EKSクラスタArmアーキテクチャのコンテナを動かす方法について説明します。Armコンテナは、特にコスト効率が求められるワークロードに適しています。ここでは、Terraformを使用してEKSクラスタをセットアップし、Javaアプリケーション(Spring Boot)をArmコンテナでデプロイする手順を紹介します。

EKSクラスタのセットアップ

VPNとEKSクラスタの定義

まず、Terraformを使用してEKSクラスタをセットアップします。以下は、基本的なTerraform構成の例です。ここでのポイントは、instance_typeにt4g.mediumのようにArmのインスタンスタイプを指定し、Armインスタンスを使用するためにami_typeAL2_ARM_64に設定することです。

main.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region  = "us-west-2"
}

data "aws_availability_zones" "available" {
  filter {
    name   = "opt-in-status"
    values = ["opt-in-not-required"]
  }
}

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"

  name = "eks-vpc"
  cidr = "10.0.0.0/16"

  azs             = slice(data.aws_availability_zones.available.names, 0, 3)
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

  enable_nat_gateway = true
  enable_vpn_gateway = true

  public_subnet_tags = {
    "kubernetes.io/role/elb" = 1
  }

  private_subnet_tags = {
    "kubernetes.io/role/internal-elb" = 1
  }
}

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 19.0"

  cluster_name    = "awesome-service-cluster"
  cluster_version = "1.28"

  vpc_id                         = module.vpc.vpc_id
  subnet_ids                     = module.vpc.private_subnets
  cluster_endpoint_public_access = true

  eks_managed_node_groups = {
    main = {
      name = "main-node-group"

      instance_types = ["t4g.medium"]
      capacity_type  = "SPOT"

      min_size     = 1
      max_size     = 3
      desired_size = 2

      ami_type = "AL2_ARM_64"
    }
  }
}

ECRリポジトリの定義

次に、以下のようにECRリポジトリを作成します。ここは通常のECRリポジトリの設定と同じです。

ecr.tf
resource "aws_ecr_repository" "backend" {
  name                 = "awesome-service-backend"
  image_tag_mutability = "MUTABLE"

  image_scanning_configuration {
    scan_on_push = true
  }

  encryption_configuration {
    encryption_type = "AES256"
  }

  tags = {
    Name        = "awesome-service-backend"
    Environment = "production"
  }
}

resource "aws_ecr_lifecycle_policy" "backend" {
  repository = aws_ecr_repository.backend.name

  policy = jsonencode({
    rules = [
      {
        rulePriority = 1
        description  = "Keep last 10 images"
        selection = {
          tagStatus     = "tagged"
          tagPrefixList = ["v"]
          countType     = "imageCountMoreThan"
          countNumber   = 10
        }
        action = {
          type = "expire"
        }
      },
      {
        rulePriority = 2
        description  = "Remove untagged images after 7 days"
        selection = {
          tagStatus   = "untagged"
          countType   = "sinceImagePushed"
          countUnit   = "days"
          countNumber = 7
        }
        action = {
          type = "expire"
        }
      }
    ]
  })
}

上記のファイルを作成したら、tfファイルのあるディレクトリで以下のコマンドを実行してKubernetesクラスタを構築します。

terraform init
terraform apply

ArmコンテナのビルドとECRへのプッシュ

Dockerファイルの作成

Armコンテナをビルドするには、Dockerfileで適切なベースイメージを指定します。以下は、Spring Bootアプリケーションの例です。(Spring Bootのプロジェクトの作成やアプリケーションの作成は省略します。)

Dockerfile
# ビルドステージ
FROM maven:3.9-eclipse-temurin-17 AS build
WORKDIR /app

# pom.xmlをコピーして、依存ファイルを先にダウンロードする。(キャッシュ活用のため)
COPY pom.xml .
RUN mvn dependency:go-offline -B

# ソースコードをコピーしてビルド
COPY src ./src
RUN mvn clean package -DskipTests -B

# 実行ステージ
FROM eclipse-temurin:17-jre-jammy
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

DockerイメージのビルドとECRへのプッシュ

以下のコマンドを使用して、Armコンテナイメージをビルドし、ECRにプッシュします。ここでは、Docker Buildxを使用してマルチプラットフォームビルドを行います。

# ECRにログイン
aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin <your_account_id>.dkr.ecr.us-west-2.amazonaws.com

# Dockerイメージのビルドとプッシュ
if ! docker buildx inspect multiplatform-builder > /dev/null 2>&1; then
    docker buildx create --name multiplatform-builder --use --platform linux/amd64,linux/arm64
else
    docker buildx use multiplatform-builder
fi
docker buildx inspect --bootstrap

docker buildx build --platform linux/arm64 -t <your_account_id>.dkr.ecr.us-west-2.amazonaws.com/awesome-service-backend:latest --push .

Kubernetesマニフェストの作成とデプロイ

最後に、Kubernetesマニフェストを作成して、EKSクラスタにデプロイします。以下は、Deploymentの例です。(ServiceやIngressの設定も必要に応じて追加してください。)

backend-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: backend
  template:
    metadata:
      labels:
        app: backend
    spec:
      containers:
      - name: backend
        image: <your_account_id>.dkr.ecr.us-west-2.amazonaws.com/awesome-service-backend:latest
        ports:
        - containerPort: 8080

このマニフェストを適用して、EKSクラスタにデプロイします。

kubectl apply -f backend-deployment.yaml

Armインスタンスを使用する上での注意点

Armインスタンスを使用する場合、以下の点に注意してください。

  • Armアーキテクチャに対応したコンテナイメージを使用する必要があります。
  • 一部のライブラリやツールがArmで動作しない場合があります。事前に確認してください。
  • パフォーマンスや互換性の問題が発生する可能性があるため、十分なテストを行ってください。

特にパフォーマンスについては、resource requestslimits を設定する方法は、x86インスタンスと同様ですが、CPUのクロックは公開されていないため、実際のパフォーマンスを測定しながら適切な値を設定することをお勧めします。まずは、24/7で稼働する必要はあるが、高いパフォーマンスは求められないワークロードから始めると良いでしょう。

まとめ

この記事では、AWS EKSクラスタでArmコンテナを動かす方法について説明しました。Terraformを使用してEKSクラスタをセットアップし、Armインスタンスを利用することで、コスト効率の高い環境を構築できます。さらに、Docker Buildxを活用してArmコンテナイメージをビルドし、ECRにプッシュする手順も紹介しました。これにより、Spring BootアプリケーションをArmアーキテクチャで実行できるようになります。ぜひ試してみてください。