AWS EKSの環境構築とArgoCDでの継続的デプロイをIaC化する
JetBrainsのJunieに依頼しながら、Terraformで構築してみる。
EKSクラスタをEKSモジュールで構築する
terraformディレクトリにEKSのクラスタを作成するコードを書いてください。EKSはt4g.mediumのスポットインスタンスを使って、リージョンはus-west-2 に作成してください。Terraform AWS modulesを使用してください。
使っているバージョンが古い点以外は問題なく作成できていそう。バージョンを更新して、以下を実行する。
terraform init
terraform apply
以下のエラーが発生。
│ Error: creating EKS Node Group (lean-saas-eks:spot-node-group-20250518014934718300000011): operation error EKS: CreateNodegroup, https response error StatusCode: 400, RequestID: 4ca4f8de-c9a5-42cd-99f3-f8b4b5609984, InvalidParameterException: [t4g.medium] is not a valid instance type for requested amiType AL2023_x86_64_STANDARD
│
│ with module.eks.module.eks_managed_node_group["spot_nodes"].aws_eks_node_group.this[0],
│ on .terraform/modules/eks/modules/eks-managed-node-group/main.tf line 308, in resource "aws_eks_node_group" "this":
│ 308: resource "aws_eks_node_group" "this" {
│
弱気になって、Armインスタンスからx86インスタンス(t3a.medium)に変更して再度apply。
ここまでの結果はこちら。
クラスタの動作確認
terraforomのoutputsに以下の表示があるので、実行する。
configure_kubectl = "aws eks update-kubeconfig --region us-west-2 --name lean-saas-eks"
$ kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system aws-node-g7fq7 2/2 Running 0 4m41s
kube-system aws-node-x6p6n 2/2 Running 0 4m39s
kube-system coredns-5449774944-h64mz 1/1 Running 0 24m
kube-system coredns-5449774944-tfvsg 1/1 Running 0 24m
kube-system kube-proxy-j2n4b 1/1 Running 0 4m39s
kube-system kube-proxy-jkj4c 1/1 Running 0 4m41s
$ eksctl get nodegroup --cluster lean-saas-eks
CLUSTER NODEGROUP STATUS CREATED MIN SIZE MAX SIZEDESIRED CAPACITY INSTANCE TYPE IMAGE ID ASG NAME TYPE
lean-saas-eks spot-node-group-20250518020521810000000001 ACTIVE 2025-05-18T02:05:24Z 1 3 2t3a.medium AL2023_x86_64_STANDARD eks-spot-node-group-20250518020521810000000001-7ccb7091-c00f-ff44-c95d-d5bd49313ef3 managed
$ kubectl get services -A
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 172.20.0.1 <none> 443/TCP 28m
kube-system eks-extension-metrics-api ClusterIP 172.20.114.10 <none> 443/TCP 28m
kube-system kube-dns ClusterIP 172.20.0.10 <none> 53/UDP,53/TCP,9153/TCP 26m
Jenieに以下を依頼する。
sample/sample-nginx ディレクトリに nginxのインスタンスをLoadBalancer経由でインターネットに公開する、Kubernetesのマニフェストファイルを作成してください。
READMEを作成してくれているので実行する
# Configure kubectl to connect to your EKS cluster
aws eks update-kubeconfig --region us-west-2 --name lean-saas-eks
# Apply the manifest
kubectl apply -f nginx.yaml
# Check the deployment status
kubectl get deployment nginx
# Check the service status and get the external IP/hostname
kubectl get service nginx
# Get the external IP/hostname
export SERVICE_IP=$(kubectl get service nginx -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
# Access Nginx
curl http://$SERVICE_IP
実行結果は以下の通り。
$ curl http://$SERVICE_IP
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
後片付けの方法まで記載してある。
kubectl delete -f nginx.yaml
ここまでの結果はこちら
AWS Load Balancer Controllerをインストールする
TerraformにHelmプロバイダを追加してください。
バージョンを最新化する。
TerraformでHelmチャートを使用してaws-load-balancer-controllerをインストールしてください。aws_iam_policy は https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.11.0/docs/install/iam_policy.json を使うようにしてください。
バージョンを最新化してapplyする。
以下のエラーが発生。
╷
│ Error: Invalid function argument
│
│ on alb_controller.tf line 14, in resource "aws_iam_policy" "aws_load_balancer_controller":
│ 14: policy = file("${path.module}/iam_policy.json")
│ ├────────────────
│ │ while calling file(path)
│ │ path.module is "."
│
│ Invalid value for "path" parameter: no file exists at "./iam_policy.json"; this function works only with files that
│ are distributed as part of the configuration source code, so if this file will be created by a resource in this
│ configuration you must instead obtain this result from an attribute of that resource.
╵
terraform applyを実行すると以下のエラーが発生しました。
╷
│ Error: Invalid function argument
│
│ on alb_controller.tf line 14, in resource "aws_iam_policy" "aws_load_balancer_controller":
│ 14: policy = file("${path.module}/iam_policy.json")
│ ├────────────────
│ │ while calling file(path)
│ │ path.module is "."
│
│ Invalid value for "path" parameter: no file exists at "./iam_policy.json"; this function works only with files that
│ are distributed as part of the configuration source code, so if this file will be created by a resource in this
│ configuration you must instead obtain this result from an attribute of that resource.
╵
どうもdataリソースを使って定義してくれないので、自分で定義を編集する。
data "http" "aws_load_balancer_controller_policy_json" {
url = "https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.11.0/docs/install/iam_policy.json"
}
resource "aws_iam_policy" "aws_load_balancer_controller" {
name = "AWSLoadBalancerControllerIAMPolicy"
description = "IAM policy for AWS Load Balancer Controller"
policy = data.http.aws_load_balancer_controller_policy_json.body
}
applyしてインストール結果の確認。
$ 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 44s
$ ubectl get pods -n kube-system | grep aws-load-balancer-controller
aws-load-balancer-controller-89f854dcd-tj79h 1/1 Running 0 112s
aws-load-balancer-controller-89f854dcd-zkczx 1/1 Running 0 112s
ここまでの結果はこちら。
AWS Load Balancerを使ってコンテナを公開する。
sample/sample-nginx-alb ディレクトリに nginxのインスタンスをAWS ALB経由でインターネットに公開する、Kubernetesのマニフェストファイルを作成してください。
動作確認。
$ export ALB_ADDRESS=$(kubectl get ingress nginx-ingress -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
$ curl http://$ALB_ADDRESS
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
AWSコンソールでロードバランサーを調べるとちゃんと、ロードバランサータイプが Application になっていた。
ArgoCDをインストールする
TerraformでHelmチャートを使用して、ArgoCDをインストールしてください。ArgoCDはALBでインターネットからHTTPSでアクセスできるようにしてください。
バージョンを最新のものに変更する。ACM証明書のドメインを指定する部分があったのでドメイン名を指定する。
# Create an ACM certificate for HTTPS
resource "aws_acm_certificate" "argocd" {
domain_name = "argocd.t-horie.com" # Replace with your actual domain
validation_method = "DNS"
applyしてもACM証明書が保留中のままになる。
ACM証明書のステータスが「保留中の検証」になっています。何を確認すれば良いですか?
Terraformに追加する内容をdocsに書いてきたのでtfファイルに追加する。
再度、applyすると発行済になった。しかし、Route53の設定されていないのでアクセスできない。
TerraformでRoute53にArgoCDのドメインを追加してください。
ALBのDNS名がわからないようなので、手動で修正。
# Create a Route53 record for the ArgoCD domain
resource "aws_route53_record" "argocd" {
# 中略
# This is a placeholder. In a real-world scenario, you would need to get the ALB hostname dynamically.
# For now, we're using a pattern that matches how AWS ALB Controller typically names the ALB.
# You should replace this with the actual ALB hostname after the ALB is created.
records = ["k8s-argocdalbgroup-dfd66c57f7-418058172.us-west-2.elb.amazonaws.com"]
terraform applyを実行したところ、以下のエラーが発生しました。
╷
│ Error: Invalid index
│
│ on outputs.tf line 116, in output "argocd_route53_record_target":
│ 116: value = aws_route53_record.argocd.records[0]
│
│ Elements of a set are identified only by their value and don't have any separate index or key to select with, so it's
│ only possible to perform operations across all elements of the set.
╵
修正してもらって、applyを実行。以下を実行してadminのパスワードを確認。
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath='{.data.password}' | base64 -d
outputsのArgoCDのURLをブラウザで開いて、adminのアカウントでログイン。

ここまでの結果はこちら。
ArgoCDの動作確認
sample/sample-nginx-alb をArgoCDのアプリケーションとしてTerraformで登録してください。
リポジトリのURLを指定する。
resource "kubernetes_manifest" "nginx_alb_application" {
manifest = {
# 中略
spec = {
project = "default"
source = {
repoURL = "https://github.com/horie-t/lean-saas-tech.git" # Replace with your actual repository URL
sample/sample-nginx-alb/application.yaml ファイルが不要になったので削除する。
applyを実行する。ArgoCDにアプリケーションが追加される。

nginx-ingressの部分にアプリケーションを開くためのリンクがあるのでクリックする。

ここまでの結果はこちら。
プライベートECRリポジトリからデプロイ
TerraformでECR リポジトリを作成し、EKSからアクセスできるようにしてください。
apply。
スタムのnginxのイメージを作成する。
docker run -p 8080:80 nginx:latest
別ターミナルで動作確認。
$ curl http://localhost:8080/
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5af29a47396f nginx:latest "/docker-entrypoint.…" 12 seconds ago Up 12 seconds 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp gifted_gates
$ docker exec hopeful_banzai bash -c 'sed -i "s/Welcome to nginx!/Welcome to customized nginx!/" /usr/share/nginx/html/index.html'
$ curl http://localhost:8080/
<!DOCTYPE html>
<html>
<head>
<title>Welcome to customized nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to customized nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
$ docker commit hopeful_banzai horie-t/nginx:custom1.0
$ docker tag horie-t/nginx:custom1.0 lean-saas-eks-app-repository:latest XXXXXXXXXXXX.dkr.ecr.us-west-2.amazonaws.com/lean-saas-eks-app-repository:latest
$ docker push XXXXXXXXXXXX.dkr.ecr.us-west-2.amazonaws.com/lean-saas-eks-app-repository:latest
ここまでの結果はこちら。
ECRリポジトリイメージの動作確認
イメージのURLを変更。
@@ -17,7 +17,7 @@ spec:
spec:
containers:
- name: nginx
- image: nginx:1.21
+ image: 269376826173.dkr.ecr.us-west-2.amazonaws.com/lean-saas-eks-app-repository:latest
ports:
- containerPort: 80
resources:
ArgoCDのSyncボタンでsyncする。

アプリケーションの画面が変更される。

ここまでの結果はこちら。
ArgoCDのGitHubリポジトリをプライベートにする
GitHubで argocd-repo の名前のプライベートリポジトリを作成する。
このリポジトリで以下のデプロイを定義する
apiVersion: apps/v1
kind: Deployment
metadata:
name: private-app
namespace: default
labels:
app: private-app
spec:
replicas: 2
selector:
matchLabels:
app: private-app
template:
metadata:
labels:
app: private-app
spec:
containers:
- name: private-app
image: 269376826173.dkr.ecr.us-west-2.amazonaws.com/lean-saas-eks-app-repository:latest
ports:
- containerPort: 80
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: private-app
namespace: default
labels:
app: private-app
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app: private-app
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: private-app-ingress
namespace: default
annotations:
kubernetes.io/ingress.class: "alb"
alb.ingress.kubernetes.io/scheme: "internet-facing"
alb.ingress.kubernetes.io/target-type: "ip"
alb.ingress.kubernetes.io/healthcheck-protocol: "HTTP"
alb.ingress.kubernetes.io/healthcheck-port: "traffic-port"
alb.ingress.kubernetes.io/healthcheck-path: "/"
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}]'
alb.ingress.kubernetes.io/group.name: "private-app-alb-group"
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: private-app
port:
number: 80
TerraformでArgoCDがGitHubのプライベートリポジトリ horie-t/argocd-repo のアプリケーションをデプロイできるようにしてください。
Terraformのvariableに github_token が追加されたので以下のようにしてapplyする。GitHubのTokenはclassicでrepoのFull controllを与える。(Fingradeのread-onlyだとArgoCDがwriteできないとエラーになる。
export TF_VAR_github_token="your-github-token"
terraform apply
ここまでの結果はこちら