はじめに
本記事では、Terraform でEKSのGitOps パイプラインのデモ環境を構築する手順とデモした内容について、記載しています。
GitOps について学習する時の参考になれば幸いです。
GitOps とは
引用:
GitOpsは、次の2つに要約できます。
- Kubernetesおよびその他のクラウドネイティブテクノロジーのオペレーティングモデル。コンテナ化されたクラスターとアプリケーションのGitのデプロイ、管理、モニタリングを統合する一連のベストプラクティスを提供します。
- アプリケーションを管理するための開発者エクスペリエンスへの道。ここでは、エンドツーエンドのCICDパイプラインとGitワークフローが操作と開発の両方に適用されます。
Terraform で構築する全体構成図
構成の概要
GitOps は、下記のコンポーネントで構成しています。
機能 | コンポーネント名 | 説明 |
---|---|---|
ソースの管理 | CodeCommit | アプリのソースとKubernetes のマニフェストを管理します。 |
イメージの管理 | ECR | アプリのイメージを管理します。 |
CI | CodePipeline + CodeBuild | アプリのソースの変更をトリガーにして、イメージをビルドし、ECR にプッシュします。 プッシュ後、イメージの差し替えをマニフェストのリポジトリにプルリクエストします。 |
CD | Argo CD | マニフェストの変更を監視し、変更を検出すると、Kubernetes の実行環境に反映します。 |
Terraform のコードと構成
$ tree aws-tf-eks-gitops-demo
aws-tf-eks-gitops-demo
├── eks-gitops-demo-app
│ ├── Dockerfile
│ └── index.html
├── eks-gitops-demo-k8s
│ ├── deployment.yaml
│ └── service.yaml
├── main.tf
├── modules
│ └── ci
│ ├── buildspec.yml
│ ├── cloudwatch_event.tf
│ ├── cloudwatch_logs.tf
│ ├── codebuild.tf
│ ├── codecommit.tf
│ ├── codepipeline.tf
│ ├── ecr.tf
│ ├── iam.tf
│ ├── iam_https_user.tf
│ ├── outputs.tf
│ ├── s3.tf
│ └── variables.tf
├── outputs.tf
├── provider.tf
└── versions.tf
デモ環境を構築するメインのファイル
locals {
aws_profile = "YOUR AWS ACCOUNT PROFILE NAME"
aws_region = "ap-northeast-1"
}
module "ci" {
source = "./modules/ci"
# PREFIX
prefix = "eks-gitops"
# ENVIRONMENT PREFIX
env = "demo"
# IMAGE CODECOMMIT REPOSITORY NAME
codecommit_repository_for_image = "eks-gitops-demo-app"
# BRANCH NAME
branch_name = "master"
# ECR REPOSITORY NAME
ecr_name = "eks-gitops-demo-app"
# K8S CODECOMMIT REPOSITORY NAME
codecommit_repository_for_k8s = "eks-gitops-demo-k8s"
}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "3.14.2"
# VPC NAME
name = "eks-gitops-demo-vpc"
# VPC CIDR
cidr = "10.0.0.0/16"
# SUBNET
azs = ["ap-northeast-1a", "ap-northeast-1c"]
public_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
private_subnets = ["10.0.3.0/24", "10.0.4.0/24"]
# NAT GATEWAY
enable_nat_gateway = true
single_nat_gateway = true
# DNS
enable_dns_hostnames = true
}
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "18.26.0"
# EKS CONTROL PLANE
cluster_name = "eks-gitops-demo"
cluster_version = "1.22"
cluster_endpoint_private_access = false
cluster_endpoint_public_access = true
# EKS CLUSTER VPC AND SUBNETS
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
# EKS MANAGED NODE GROUPS
eks_managed_node_groups = {
gitops-demo = {
desired_size = 2
instance_types = ["t3.small"]
}
}
node_security_group_additional_rules = {
admission_webhook = {
description = "Admission Webhook"
protocol = "tcp"
from_port = 0
to_port = 65535
type = "ingress"
source_cluster_security_group = true
}
ingress_node_communications = {
description = "Ingress Node to node"
protocol = "tcp"
from_port = 0
to_port = 65535
type = "ingress"
self = true
}
egress_node_communications = {
description = "Egress Node to node"
protocol = "tcp"
from_port = 0
to_port = 65535
type = "egress"
self = true
}
}
}
data "aws_eks_cluster" "cluster" {
name = module.eks.cluster_id
}
data "aws_eks_cluster_auth" "cluster" {
name = module.eks.cluster_id
}
GitOps パイプラインのデモ環境の構築
前提条件
- Terraform がセットアップされていること
- kubectl がセットアップされていること
- AWS CLI がセットアップされていること
- Argo CDのCLI がセットアップされていること
動作確認環境
$ terraform version
Terraform v1.1.9
$ aws --version
aws-cli/2.7.12 Python/3.9.11 Darwin/19.6.0 exe/x86_64 prompt/off
$ kubectl version --client --short
Client Version: v1.21.2
$ argocd version
argocd: v2.4.3+471685f.dirty
EKS クラスターのセットアップ
Terraform を実行します。
$ terraform init
$ terraform plan
$ terraform apply
結果:
Apply complete! Resources: 72 added, 0 changed, 0 destroyed.
下記コマンドを実行し、Terraform のoutput を控えておきます。
$ terraform output
結果:
CODECOMMIT_IMAGE_REPOSITORY_URL = "https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/eks-gitops-demo-app"
CODECOMMIT_INFRA_REPOSITORY_URL = "https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/eks-gitops-demo-k8s"
ECR_REPOSITORY_URL = "[AWSアカウントID].dkr.ecr.ap-northeast-1.amazonaws.com/eks-gitops-demo-app"
app_name = "eks-gitops-demo-app"
argocd_sync_password = <sensitive>
argocd_sync_username = <sensitive>
eks_cluster_name = "eks-gitops-demo"
構築したEKSクラスターに接続できることを確認します。
$ aws eks update-kubeconfig \
--region ap-northeast-1 \
--name eks-gitops-demo \
--profile [YOUR AWS ACCOUNT PROFILE NAME]
結果:
Added new context arn:aws:eks:ap-northeast-1:[AWSアカウントID]:cluster/eks-gitops-demo to /Users/*****/.kube/config
マニフェストファイルをリポジトリにプッシュ
下記2つのマニフェストファイルを terraform output
のCODECOMMIT_INFRA_REPOSITORY_URL
先(マニフェストのリポジトリ)にプッシュします。
※[AWSアカウントId]
を自環境に変更します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: eks-gitops-demo-app
spec:
replicas: 2
selector:
matchLabels:
app: eks-gitops-demo-app
template:
metadata:
labels:
app: eks-gitops-demo-app
spec:
containers:
- name: eks-gitops-demo-app
image: [AWSアカウントId].dkr.ecr.ap-northeast-1.amazonaws.com/eks-gitops-demo-app:latest
ports:
- name: http
containerPort: 80
apiVersion: v1
kind: Service
metadata:
name: eks-gitops-demo-app
spec:
type: LoadBalancer
selector:
app: eks-gitops-demo-app
ports:
- port: 80
targetPort: http
Argo CDのセットアップ
kubectl コマンドを使って、Argo CDをデプロイします。
$ kubectl create namespace argocd
結果:
namespace/argocd created
$ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
Argo CDのPod が稼働していることを確認します。
$ kubectl get pod -n argocd
結果:
NAME READY STATUS RESTARTS AGE
argocd-application-controller-0 1/1 Running 0 25s
argocd-applicationset-controller-5f7d8fffb7-s2n6n 1/1 Running 0 26s
argocd-dex-server-c6dcf7fdb-6qqll 1/1 Running 0 26s
argocd-notifications-controller-544ff7766d-pljxl 1/1 Running 0 26s
argocd-redis-75bdb869bf-8b2tv 1/1 Running 0 26s
argocd-repo-server-649b4b66bd-4g22t 0/1 Running 0 26s
argocd-server-5df946ff78-zq5tl 0/1 Running 0 26s
下記コマンドで、Argo CDの管理者用のデフォルトのパスワードを取得します。
$ kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo
結果:
Argo CDの管理者用のデフォルトのパスワード
下記コマンドで、ローカルポートをArgo CDサーバーにポートフォワードします。
$ kubectl port-forward svc/argocd-server -n argocd 8080:443
結果:
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
下記コマンドで、Argo CDサーバーにログインします。
$ argocd login localhost:8080 \
--username admin \
--password [Argo CD管理者用のデフォルトのパスワード] \
--insecure \
--port-forward-namespace argocd
結果:
'admin:login' logged in successfully
Context 'localhost:8080' updated
下記コマンドで、Argo CDからマニフェストのリポジトリにHTTPS 接続する時に使用するIAMの情報を参照します。
$ terraform output argocd_sync_username
結果:
ユーザー名
$ terraform output argocd_sync_password
結果:
パスワード
下記コマンドで、マニフェストのリポジトリをArgo CDサーバーに追加します。
$ CODECOMMIT_INFRA_REPOSITORY_URL=https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/eks-gitops-demo-k8s
$ argocd repo add ${CODECOMMIT_INFRA_REPOSITORY_URL} \
--username ユーザー名 \
--password パスワード
結果:
Repository 'https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/eks-gitops-demo-k8s' added
Argo CDのアプリケーションとマニフェストのリポジトリを同期させる設定をします。
$ kubectl create namespace eks-gitops-demo-app
結果:
namespace/eks-gitops-demo-app created
$ argocd app create eks-gitops-demo-app \
--repo ${CODECOMMIT_INFRA_REPOSITORY_URL} \
--revision master \
--path ./ \
--dest-server https://kubernetes.default.svc \
--dest-namespace eks-gitops-demo-app \
--sync-policy automated \
--auto-prune
結果:
application 'eks-gitops-demo-app' created
アプリケーションの同期設定が登録されていることを確認します。
$ argocd app list
NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET
eks-gitops-demo-app https://kubernetes.default.svc eks-gitops-demo-app default Synced Healthy Auto-Prune <none> https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/eks-gitops-demo-k8s ./ master
ブラウザで https://localhost:8080
にアクセスして、Argo CDのGUIに接続します。
項目 | 入力内容 |
---|---|
username | admin |
Password | Argo CDの管理者用のデフォルトのパスワード |
GUI上でもアプリケーションが表示されていることを確認します。
これで、GitOps パイプラインのデモ環境の構築が完了です。
GitOps パイプラインのデモ環境の実行
構築したデモ環境で、アプリケーションをデプロイします。
アプリのソースをリポジトリにプッシュ
下記2つのファイルを terraform output
のCODECOMMIT_INFRA_REPOSITORY_URL
先(アプリのソースのリポジトリ)にプッシュします。
FROM nginx:latest
WORKDIR /usr/share/nginx/html
COPY index.html index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>GitOps Demo</title>
</head>
<body>
<h1>GitOps Demo App v1</h1>
</body>
</html>
CodeBuild の実行
アプリのソースのリポジトリの変更をトリガーにCodePipeline が開始され、CodeBuild が実行されます。
イメージをECR をプッシュ
CodeBuild で、イメージがビルドされ、ECRにプッシュされます。
マニフェストのリポジトリにプルリクエスト
CodeBuild で、ECRにプッシュされたイメージを差し替えするためのプルリクエストをマニフェストのリポジトリに送信します。
マージ
マニフェストのリポジトリへのプルリクエストの内容を確認して、マージします。
デプロイ
Argo CDが、マニフェストのリポジトリの変更を検知すると、Kubernetes の実行環境に反映します。
$ kubectl get pod,svc,deploy -n eks-gitops-demo-app
NAME READY STATUS RESTARTS AGE
pod/eks-gitops-demo-app-7f54cfd78-cpcqm 1/1 Running 0 101s
pod/eks-gitops-demo-app-7f54cfd78-wmbcj 1/1 Running 0 98s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/eks-gitops-demo-app LoadBalancer 172.20.232.32 a3114a987111542a2affe40c67071c69-111111111.ap-northeast-1.elb.amazonaws.com 80:30146/TCP 17m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/eks-gitops-demo-app 2/2 2 2 17m
動作確認
下記コマンドで出力されたEXTERNAL-IP のLaoadBalancer のDNS名を確認します。
% kubectl get svc -n eks-gitops-demo-app
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
eks-gitops-demo-app LoadBalancer 172.20.232.32 a3114a987111542a2affe40c67071c69-111111111.ap-northeast-1.elb.amazonaws.com 80:30146/TCP 18m
ブラウザでLaoadBalancer のDNS名にHTTPアクセスして、アプリケーションがデプロイされたことを確認します。
NetWork
これで、GitOps パイプラインを使ったアプリケーションのデプロイが完了です。
リソースのクリーンアップ
マニフェストファイルのリポジトリのservice.yaml
を削除して、Kubernetes の環境からELBを削除し、下記コマンドで確認します。
$ kubectl get svc -n eks-gitops-demo-app
No resources found in eks-gitops-demo-app namespace.
下記のコマンドで、すべてのリソースを削除します。
$ terraform destroy
Destroy complete! Resources: 72 destroyed.
さいごに
GitOps パイプラインの入門的な内容ですが、参考になれば幸いです。