【ハンズオン】Amazon EKSをTerraformで構築してみる

はじめに
はじめまして、マイグレーションチームのwakaです。
SAAやSAPの取得を目指す際に問題としてEKSの話題が少し出るかと思いますが、概要はざっくり知っているものの実際に手を動かして触ったことが無いサービスだったので、EKSクラスター上にWebサーバを構築し、ALB経由で表示するまでの流れを実行してみたいと思います。
実行環境
- M1 mac
- aws-cli/2.7.21
- Terraform v1.3.1
- kubectl v1.23.7-eks-4721010
- helm v3.8.2
今回実現したい構成

ECRに登録したイメージを元にpodsを作成し、ALB経由で表示するというシンプルな構成を目指します。
Terraformやkubectlで使用するファイルは折りたたんでおりますので、必要に応じてクリックで表示してください。
作成手順
- 構築に使用するコマンド類の準備
- Terraformを用いてAWS上に動作環境の構築
- 作成したECRにdocker imageの登録
- ALBを使用するための準備
- kubectlを用いてEKS上に環境を構築
1. 構築に使用するコマンド類の準備
1-1. aws cliの準備
各OSに応じたcliのインストール方法は公式ドキュメント参照
~/.aws/credentialsにaws cliやTerraformで使用するためのアクセスキーを設定します。
[default] aws_access_key_id=************************************ aws_secret_access_key=************************************************************************
1-2. kubectlの準備
既にkubectlが入っているか確認します。
以下のコマンドでバージョンが表示されない場合は公式ドキュメントを参照にv1.23のインストール作業を実行してください。
kubectl version | grep Client | cut -d : -f 5
1-3. helmの準備
既にhelm入っているか確認します。
以下のコマンドでバージョンが表示されない場合は公式ドキュメントを参照にインストール作業を実行してください。
helm version
1-4. dcokerの準備
以下のコマンドでバージョンなどが表示されない場合は公式ドキュメントを参照にインストール作業を実行してください。
Cloud9などを利用している場合はこちらが参考になるかと思います。
docker info
2. Terraformを用いてAWS上に動作環境の構築
2-1. tfファイルの準備
. ├── ecr.tf ├── eks.tf ├── iam.tf ├── providers.tf └── vpc.tf
provider.tfのアカウントIDはリージョン、バケット名などは適宜書き換える必要がございます。
IAMロール用のポリシーをダウンロードします。
curl -o iam_policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.3/docs/install/iam_policy.json
ecr.tf
resource "aws_ecr_repository" "web_repository" {
name = "${local.name_prefix}-web-repository"
image_tag_mutability = "MUTABLE"
force_delete = true
image_scanning_configuration {
scan_on_push = true
}
}
eks.tf
module "eks" {
source = "terraform-aws-modules/eks/aws"
cluster_version = "1.23"
cluster_name = "${local.name_prefix}-eks"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
enable_irsa = true
eks_managed_node_groups = {
main = {
desired_size = 1
instance_types = ["t3.medium"]
}
}
}
resource "aws_security_group_rule" "allow_ingress_port" {
security_group_id = module.eks.node_security_group_id
type = "ingress"
from_port = 9443
to_port = 9443
protocol = "tcp"
source_security_group_id = module.eks.cluster_security_group_id
}
iam.tf
resource "aws_iam_role" "eks_load_balancer_controller_role" {
name = "AmazonEKSLoadBalancerControllerRole"
assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json
managed_policy_arns = [aws_iam_policy.eks_iam_policy.arn]
}
resource "aws_iam_policy" "eks_iam_policy" {
name = "AWSLoadBalancerControllerIAMPolicy"
policy = file("./iam_policy.json")
}
data "aws_iam_policy_document" "assume_role_policy" {
statement {
sid = "EKSClusterAssumeRole"
actions = ["sts:AssumeRoleWithWebIdentity"]
principals {
type = "Federated"
identifiers = ["${module.eks.oidc_provider_arn}"]
}
condition {
test = "StringEquals"
variable = "${module.eks.oidc_provider}:sub"
values = [
"system:serviceaccount:kube-system:aws-load-balancer-controller"
]
}
condition {
test = "StringEquals"
variable = "${module.eks.oidc_provider}:aud"
values = [
"sts.amazonaws.com"
]
}
}
}
providers.tf
locals {
name_prefix = "hoge"
region = "ap-northeast-1"
aws_profile = "default"
}
provider "aws" {
region = local.region
profile = local.aws_profile
}
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}
vpc.tf
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
name = "${local.name_prefix}-vpc"
cidr = "10.0.0.0/16"
azs = ["${local.region}a", "${local.region}c"]
public_subnets = ["10.0.0.0/24", "10.0.1.0/24"]
private_subnets = ["10.0.100.0/24", "10.0.101.0/24"]
enable_nat_gateway = true
public_subnet_tags = {
"kubernetes.io/role/elb" = "1"
}
private_subnet_tags = {
"kubernetes.io/role/internal-elb" = "1"
}
}
2-2. TerraformでEKSの環境を構築する
terraform init terraform plan terraform apply
applyしてからおよそ10分~15分ほどで作成が完了するかと思います。
Terraformのapply後にノードグループが設定されたEKSやECRのリポジトリなどが作成出来ていることを確認できるかと思います。
EKS

ECR

3. 作成したECRにdocker imageの登録
3-1. フォルダ構成
.
├── Dockerfile
└── src
├── index.html
└── nginx.conf
Dockerfile
FROM alpine:3.6
RUN apk update && \
apk add --no-cache nginx
ADD src /app
ADD ./src/nginx.conf /etc/nginx/conf.d/default.conf
RUN mkdir -p /run/nginx
CMD ["nginx", "-g", "daemon off;"]
nginx.conf
server {
listen 80 default_server;
listen [::]:80 default_server;
root /app;
location / {
}
}
index.html
<html>
<body>
HOGE!!
</body>
</html>
3-2. ローカル環境でサンプルのコンテナの準備
ローカル環境でイメージのビルドを行います。
docker build ./ -t sample_nginx docker run -d -p 8080:80 -it sample_nginx
私のようにM1などのarm系のCPUを使用している場合はDocker Buildxを使用してビルドを実行するとよいかと思います。
ローカルのPCでdocker run実行後にブラウザにhttp://localhost:8080/と入力するとindex.htmlに記載した内容が確認出来るかと思います。

3-3. ECRへコンテナイメージの登録
account_id、region、repository_nameはterraform applyした内容に応じて適宜変更が必要となります。
ECRへのログイン
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin {account_id}.dkr.ecr.ap-northeast-1.amazonaws.com
イメージタグとリポジトリの紐付け
docker tag sample_nginx:latest {account_id}.dkr.ecr.ap-northeast-1.amazonaws.com/{repository_name}:latest
ECRにnginxのイメージのpush
docker push {account_id}.dkr.ecr.ap-northeast-1.amazonaws.com/{repository_name}:latest
3-4. ECRへイメージが登録されているかの確認
Terraformで作成したECRのリポジトリにイメージが登録されていることが確認できるかと思います。

4. ALBを使用するための準備
EKSへのaws-load-balancer-controllerのインストールの公式ドキュメントはこちら
4-1. kubectlの向き先をEKSに変更
aws eks update-kubeconfig --region ap-northeast-1 --name {cluster_name}
kubectl config current-context
current-contextの実行結果がTerraformで作成したEKSのarnとなっていれば向き先の変更作業は完了です。
4-2. k8s用のサービスアカウントの登録
cat >aws-load-balancer-controller-service-account.yaml <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: aws-load-balancer-controller
name: aws-load-balancer-controller
namespace: kube-system
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::{account_id}:role/AmazonEKSLoadBalancerControllerRole
EOF
kubectl apply -f aws-load-balancer-controller-service-account.yaml
4-3. aws-load-balancer-controllerのインストール
eks-chartsリポジトリを追加します。
helm repo add eks https://aws.github.io/eks-charts helm repo update
helmを用いたaws-load-balancer-controllerのインストール
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName={cluster_name} \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller
4-4. podsのapplyに進む前の確認事項
- aws-load-balancer-controllerのREADYが2/2となっていること
[waka]% kubectl get deployment -n kube-system aws-load-balancer-controller NAME READY UP-TO-DATE AVAILABLE AGE aws-load-balancer-controller 2/2 2 2 11s
- aws-load-balancer-controllerのserviceaccountが登録されていること
[waka]% kubectl get serviceaccount -n kube-system | grep "aws-load-balancer-controller" aws-load-balancer-controller 1 41s
5. kubectlを用いてEKS上に環境を構築
5-1. kunbctl用yamlの準備
. ├── alb.yaml └── nginx.yaml
alb.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: sample-eks
name: sample-eks-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
spec:
ingressClassName: alb
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: sample-eks-service-target
port:
number: 80
nginx.yaml
---
apiVersion: v1
kind: Namespace
metadata:
name: sample-eks
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: sample-eks
name: eks-sample-linux-deployment
spec:
selector:
matchLabels:
app.kubernetes.io/name: sample-eks-pods
replicas: 2
template:
metadata:
labels:
app.kubernetes.io/name: sample-eks-pods
spec:
containers:
- image: 701440566517.dkr.ecr.ap-northeast-1.amazonaws.com/{repository_name}:latest
imagePullPolicy: Always
name: sample-eks-pods
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
namespace: sample-eks
name: sample-eks-service-target
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
type: NodePort
selector:
app.kubernetes.io/name: sample-eks-pods
nginx.yaml内の{account_id}と{repository_name}の内容を自身の環境の内容に変更が必要になります。
5-2. kubectlを用いて環境の構築
namespace,podsの作成
kubectl apply -f nginx.yaml
podsの動作確認
[waka]% kubectl get pods -n sample-eks -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES eks-sample-linux-deployment-7bf565f6bf-4sk85 1/1 Running 0 37s 10.0.101.31 ip-10-0-101-163.ap-northeast-1.compute.internal <none> <none> eks-sample-linux-deployment-7bf565f6bf-wm5s5 1/1 Running 0 37s 10.0.101.94 ip-10-0-101-163.ap-northeast-1.compute.internal <none> <none>
STATUSがRunningになっていればpodsの起動に成功しています。
ALBの作成、登録
kubectl apply -f alb.yaml
[waka]% kubectl describe ingress sample-eks-ingress -n sample-eks
Name: sample-eks-ingress
Labels: <none>
Namespace: sample-eks
Address: k8s-sampleek-sampleek-2b376492de-661143548.ap-northeast-1.elb.amazonaws.com
Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
Host Path Backends
---- ---- --------
*
/ sample-eks-service-target:80 (10.0.101.31:80,10.0.101.94:80)
Annotations: alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/security-groups: sg-0b5e9fd22db184041
alb.ingress.kubernetes.io/target-type: ip
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfullyReconciled 104s ingress Successfully reconciled
describe ingressで取得したAddressに表示されているELBのアドレスにアクセスすると、作成したhtmlの内容が表示されるかと思います。

5-3. 動作確認出来たらお掃除
kubectl delete -f alb.yaml terraform destroy
最後に
TerraformでEKSクラスターを作成し、kubectlを用いてEKS上にpodsを作成しALBと紐付けて表示確認を行う、という手順で動作確認を行いました。
今回はkubectlでALBを作成してpodsを紐付けましたが、TargetGroupBindingというTerraformで作成したALBにpodsを紐付けるといった処理も可能です。
また、EKSではFargateを用いての構築も可能なようですので、また後日そちらの構成で紹介が出来たらと思います。
テックブログ新着情報のほか、AWSやGoogle Cloudに関するお役立ち情報を配信中!
Follow @twitter2022年に中途入社した人です。好きなAWSサービスはLambdaです。
Recommends
こちらもおすすめ
-
TROCCO を Terraform で構築してみた
2025.11.4
Special Topics
注目記事はこちら
データ分析入門
これから始めるBigQuery基礎知識
2024.02.28

AWSの料金が 10 %割引になる!
『AWSの請求代行リセールサービス』
2024.07.16