Home
home

5장 실습 - Amazon EKS - CI/CD 구성하기

1. 기본 환경 배포

이번 실습은 IAM 사용자 계정을 통해 관리 콘솔에 접근하고 액세스 키를 활용해 awscli 도구를 사용합니다.
해당 작업을 수행하지 않았다면 아래 토글을 확장해 작업을 선행하고 본격적인 실습에 들어갑니다.
IAM 사용자 생성 및 액세스 키 생성

1.1. Terraform을 통한 기본 인프라 배포

Terraform을 통한 기본 인프라 배포에 앞서 SSH 키 페어, IAM User Access Key ID, IAM User Secret Access Key를 미리 확인하고 메모해 둡니다.
Terraform으로 기본 인프라 배포
cd cnaee_class_tf/ch5
Bash
복사
# 실습 디렉터리 경로 진입
export TF_VAR_KeyName=[각자 ssh keypair] export TF_VAR_MyIamUserAccessKeyID=[각자 iam 사용자의 access key id] export TF_VAR_MyIamUserSecretAccessKey=[각자 iam 사용자의 secret access key] export TF_VAR_SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32
Bash
복사
# Terraform 환경 변수 저장
terraform init terraform plan nohup sh -c "terraform apply -auto-approve" > create.log 2>&1 &
Bash
복사
# Terraform 배포
Note:  nohup으로 백그라운드로 실행하도록 변경했습니다. Terraform 배포가 완료되면 정상적으로 자원 생성이 되었는지 확인을 합니다.(cat create.log)
Terraform을 통한 기본 인프라 배포가 완료되면 관리 콘솔에서 생성된 인프라들을 확인합니다.
Note: 
AWS 관리 콘솔에 로그인 할 땐 IAM 사용자 계정으로 진행합니다.

1.2. 기본 정보 확인 및 설정

Terraform 배포가 완료 후 출력되는 Output 정보에서 퍼블릭 IP 주소를 확인합니다.
해당 IP로 EKS 관리용 인스턴스(myeks-bastion)에 SSH로 접속하고 아래 명령어를 통해 정보를 확인합니다.
Note:
myeks-bastion-1의 OS 변경으로 SSH 접근에 대한 계정을 ubuntu로 지정합니다.
(ssh -i ~/.ssh/XXXX.pem ubuntu@X.X.X.X)
[Bastion-1] 기본 설정 및 확인
aws eks update-kubeconfig \ --region $AWS_DEFAULT_REGION \ --name $CLUSTER_NAME
Shell
복사
# EKS 클러스터 인증 정보 업데이트
kubens default
Bash
복사
# kubens default 설정
echo $AWS_DEFAULT_REGION echo $CLUSTER_NAME echo $VPCID echo $PublicSubnet1,$PublicSubnet2,$PublicSubnet3 echo $PrivateSubnet1,$PrivateSubnet2,$PrivateSubnet3
Bash
복사
# 변수 호출 종합
eksctl get cluster
Bash
복사
# eksctl을 통한 eks cluster 정보 확인
eksctl get nodegroup \ --cluster $CLUSTER_NAME \ --name ${CLUSTER_NAME}-node-group
Bash
복사
# eksctl을 통한 노드 그룹 정보 확인
kubectl get node -owide
Bash
복사
# kubectl을 통한 노드 정보 확인
PublicN1=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2a -o jsonpath={.items[0].status.addresses[0].address}) PublicN2=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2b -o jsonpath={.items[0].status.addresses[0].address}) PublicN3=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2c -o jsonpath={.items[0].status.addresses[0].address}) echo "export PublicN1=$PublicN1" >> /etc/profile echo "export PublicN2=$PublicN2" >> /etc/profile echo "export PublicN3=$PublicN3" >> /etc/profile echo $PublicN1, $PublicN2, $PublicN3
Bash
복사
# 노드 IP 변수 선언
for node in $PublicN1 $PublicN2 $PublicN3; \ do \ ssh -i ~/.ssh/kp_node.pem -o StrictHostKeyChecking=no ec2-user@$node hostname; \ done
Bash
복사
# 노드에 ssh 접근 확인
MyDomain=[각자 도메인]; echo $MyDomain echo "export MyDomain=$MyDomain" >> /etc/profile
Bash
복사
# 각자의 도메인 변수 선언

2. CI 파이프라인 구성

EKS 환경에서 CI 파이프라인 구성을 위한 다양한 요소를 설치하고 실습합니다.

2.1. SCM 도구 - Gogs 구성

helm으로 Gogs 설치
kubectl create ns cicd
Bash
복사
# cicd 네임스페이스 생성
git clone https://github.com/cloudneta/gogs-helm-chart.git
Bash
복사
# git clone - gogs helm
helm install gogs ./gogs-helm-chart \ --namespace cicd \ --set service.http.serviceType=LoadBalancer \ --set service.http.externalHost=gogs.${MyDomain} \ --set service.http.svc_annotations."service\.beta\.kubernetes\.io/aws-load-balancer-type"=nlb \ --set service.http.svc_annotations."service\.beta\.kubernetes\.io/aws-load-balancer-scheme"=internet-facing \ --set service.http.svc_annotations."service\.beta\.kubernetes\.io/aws-load-balancer-nlb-target-type"=ip
Bash
복사
# gogs 설치 (helm install)
while true; do \ aws elbv2 describe-load-balancers \ --query 'LoadBalancers[*].[LoadBalancerName,State.Code]' \ --output table; \ done
Bash
복사
# elb 생성 확인 (Ctrl + Z로 중지)
kubectl annotate service -n cicd gogs-gogs-http "external-dns.alpha.kubernetes.io/hostname=gogs.$MyDomain" echo -e "Gogs URL = http://gogs.$MyDomain:3000"
Bash
복사
# externalDNS 설정 및 Gogs URL 출력
Note:
출력되는 Gogs URL로 웹 페이지 접근을 합니다. (ExternalDNS로 Route 53 등록까지 약간의 대기가 발생합니다.)
[Gogs Web UI] 첫 실행을 위한 Gogs 설치
Database Type: SQLite3
Domain: gogs.${MyDomain}
Application URL: http://gogs.${MyDomain}:3000/
Admin Account Settings (Toggle Open)
Username: cicd
Password: qwer1234
Confirm Password: qwer1234
Admin Email: abc@abc.com
Install Gogs (Button Click)
gogs 파드 정보 확인
kubectl get pod -n cicd
Bash
복사
# gogs 파드 확인
GOGS_POD=$(kubectl get pods -n cicd -l "app=gogs-gogs" -o jsonpath="{.items[0].metadata.name}") echo "export GOGS_POD=$GOGS_POD" >> /etc/profile; echo $GOGS_POD
Bash
복사
# gogs 파드 이름 변수 선언
kubectl exec -it $GOGS_POD -n cicd -- apk add tree kubectl exec -it $GOGS_POD -n cicd -- tree /data
Bash
복사
# gogs 파드 디렉터리 구조 확인(tree)
kubectl exec -it $GOGS_POD -n cicd -- cat /data/gogs/conf/app.ini
Bash
복사
# gogs 파드 설정 확인
[Gogs Web UI] Personal Access Token(PAT) 생성
우측 상단 아이콘Your Settings
ApplicationsGenerate New Token (Button Click)
Token Name: cicd
Generate Token (Button Click)
액세스 토큰 값 복사
GOGS_TOKEN=[토큰 값 붙여 넣기] echo "export GOGS_TOKEN=$GOGS_TOKEN" >> /etc/profile; echo $GOGS_TOKEN
Bash
복사
# gogs 액세스 토큰 값 변수 선언
[Gogs Web UI] 신규 Repository 생성
DashboardMy Repositories+
Repository Name: dev-repo
Visibility: This repository is Private (Check)
.gitignore: Python
Readme: Default
Initialize this repository with selected files and template (Check)
Create Repository (Button Click)
DEV_REPO_PATH=gogs.${MyDomain}:3000/cicd/dev-repo.git echo "export DEV_REPO_PATH=$DEV_REPO_PATH" >> /etc/profile; echo $DEV_REPO_PATH
Bash
복사
# DEV_REPO_PATH 변수 선언
kubectl exec -it $GOGS_POD -n cicd -- tree /data/git -L 4
Bash
복사
# gogs 파드 /data/git 구조 확인(depth 4)
Gogs 실습을 위한 저장소 설정
git config --global user.name "cicd" git config --global user.email "abc@abc.com" git config --global init.defaultBranch master git config --global --list
Bash
복사
# git global 설정 및 확인
git clone http://$GOGS_TOKEN@$DEV_REPO_PATH
Bash
복사
# git clone - dev-repo
tree dev-repo -a cd dev-repo
Bash
복사
# 대상 디렉터리 구조 및 진입
git branch
Bash
복사
# git branch 확인
cat > server.py <<EOF from flask import Flask import os app = Flask(__name__) with open("VERSION", "r") as f: version = f.read().strip() @app.route("/") def home(): return f"Welcome to CNAEE CICD Hands-On!! - v{version}\n" if __name__ == "__main__": app.run(host="0.0.0.0", port=8080) EOF
Bash
복사
# server.py 생성
cat > Dockerfile <<EOF FROM python:3.9-slim WORKDIR /app COPY server.py . COPY VERSION . RUN pip install flask CMD ["python", "server.py"] EOF
Bash
복사
# Dockerfile 생성
echo "0.0.1" > VERSION cat VERSION
Bash
복사
# VERSION 파일 생성
git add . git commit -m "Add dev-repo files" git push -u origin master
Bash
복사
# git add/commit/push

2.2. 컨테이너 이미지 저장소 - Amzon ECR 구성

ECR Private Repository 생성
aws ecr describe-repositories
Bash
복사
# ecr private repository 확인
aws ecr create-repository \ --repository-name private/myapp \ --region ap-northeast-2 \ --image-tag-mutability MUTABLE \ --image-scanning-configuration scanOnPush=false
Bash
복사
# ecr private repository 생성
ECR Private Registry 로그인
aws ecr get-login-password \ --region ${AWS_DEFAULT_REGION} | docker login \ --username AWS \ --password-stdin ${ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com
Bash
복사
# ecr private에 로그인
cat ~/.docker/config.json | jq
Bash
복사
# ecr private 인증 정보
이미지 - build & tag & push
docker build -t private/myapp:0.0.1 .
Bash
복사
# 이미지 빌드
docker tag private/myapp:0.0.1 \ ${ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/private/myapp:0.0.1
Bash
복사
# 이미지 태그 추가
docker push \ ${ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/private/myapp:0.0.1
Bash
복사
# 이미지 Push
aws ecr describe-images \ --repository-name private/myapp \ --region ${AWS_DEFAULT_REGION}
Bash
복사
# ECR Repo에 이미지 확인
노드 그룹의 Instance Profile 확인
aws iam list-attached-role-policies \ --role-name ${CLUSTER_NAME}-node-group-eks-node-group \ --output table
Bash
복사
# 노드의 Instance Profile에 정의된 IAM Policy 확인
aws iam get-policy-version \ --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly \ --version-id v3 | jq
Bash
복사
# AmazonEC2ContainerRegistryReadOnly 정보 확인
디플로이먼트와 서비스 생성
cd; cat >myapp.yaml <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: myapp-deployment namespace: default spec: replicas: 3 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - name: myapp-container image: ${ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/private/myapp:0.0.1 ports: - containerPort: 8080 --- apiVersion: v1 kind: Service metadata: name: myapp-service namespace: default spec: selector: app: myapp ports: - protocol: TCP port: 8080 targetPort: 8080 type: LoadBalancer EOF cat myapp.yaml | yh
Bash
복사
# myapp.yaml 파일 생성
kubectl create -f myapp.yaml
Bash
복사
# 디플로이먼트와 서비스 생성
kubectl get pod,svc
Bash
복사
# 파드와 서비스 확인
while true; do \ aws elbv2 describe-load-balancers \ --query 'LoadBalancers[*].[LoadBalancerName,State.Code]' \ --output table; \ done
Bash
복사
# elb 생성 확인 (Ctrl + Z로 중지)
MYAPP_ADDR=$(kubectl get svc myapp-service -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') echo "export MYAPP_ADDR=$MYAPP_ADDR" >> /etc/profile; echo $MYAPP_ADDR
Bash
복사
# 서비스 LB 도메인을 변수 선언
curl ${MYAPP_ADDR}:8080
Bash
복사
# myapp 접속
while true; do curl ${MYAPP_ADDR}:8080; date; echo '---'; sleep 1; done
Bash
복사
# [신규 터미널] myapp 접속 모니터링
소스 코드 변경 및 업데이트
cd dev-repo
Bash
복사
# 대상 디렉터리 구조 및 진입
echo "0.0.2" > VERSION; cat VERSION
Bash
복사
# VERSION 파일 수정
git add VERSION git commit -m "Change VERSION file" git push -u origin master
Bash
복사
# git add/commit/push
이미지 - build & tag & push
docker build -t private/myapp:0.0.2 .
Bash
복사
# 이미지 빌드
docker tag private/myapp:0.0.2 \ ${ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/private/myapp:0.0.2
Bash
복사
# 이미지 태그 추가
docker push \ ${ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/private/myapp:0.0.2
Bash
복사
# 이미지 Push
aws ecr describe-images \ --repository-name private/myapp \ --region ${AWS_DEFAULT_REGION}
Bash
복사
# ECR Repo에 이미지 확인
디플로이먼트와 서비스 재생성
cd sed -i 's/0.0.1/0.0.2/g' myapp.yaml cat myapp.yaml | yh
Bash
복사
# myapp.yaml 파일 수정
kubectl apply -f myapp.yaml
Bash
복사
# 디플로이먼트 업데이트
kubectl get pod
Bash
복사
# 파드 확인
생성 자원 삭제
kubectl delete -f myapp.yaml
Bash
복사
# 생성 자원 삭제 (디플로이먼트 & 서비스)

2.3. Jenkins 설치 및 확인

helm으로 Jenkins 설치
helm repo add jenkins https://charts.jenkins.io helm repo update
Bash
복사
# helm repo 추가
helm install jenkins jenkins/jenkins \ --namespace cicd \ --version 5.8.16 \ --set controller.serviceType=LoadBalancer \ --set controller.jenkinsUriPrefix="/" \ --set controller.csrf.defaultCrumbIssuer.enabled=true \ --set controller.securityRealm.createAdminUser=true \ --set controller.admin.username=admin \ --set controller.admin.password=qwer1234 \ --set persistence.enabled=false \ --set controller.serviceAnnotations."service\.beta\.kubernetes\.io/aws-load-balancer-type"=nlb \ --set controller.serviceAnnotations."service\.beta\.kubernetes\.io/aws-load-balancer-scheme"=internet-facing \ --set controller.serviceAnnotations."service\.beta\.kubernetes\.io/aws-load-balancer-nlb-target-type"=ip \ --set controller.probes.startupProbe.httpGet.path="/login" \ --set controller.probes.livenessProbe.httpGet.path="/login" \ --set controller.probes.readinessProbe.httpGet.path="/login"
Bash
복사
# jenkins 설치 (helm install)
Warning:
간단한 실습 환경이라 영구 볼륨을 연결하지 않았습니다.
그로 인해 파드가 종료되면 Jenkins 데이터는 삭제됩니다.
kubectl get all -n cicd
Bash
복사
# cicd 네임스페이스 자원 확인
while true; do \ aws elbv2 describe-load-balancers \ --query 'LoadBalancers[*].[LoadBalancerName,State.Code]' \ --output table; \ done
Bash
복사
# elb 생성 확인 (Ctrl + Z로 중지)
kubectl annotate service -n cicd jenkins "external-dns.alpha.kubernetes.io/hostname=jenkins.$MyDomain" echo -e "Jenkins URL = http://jenkins.$MyDomain:8080"
Bash
복사
# externalDNS 설정 및 Jenkins URL 출력
Note:
출력된 Jenkins URL로 접근하여 로그인합니다. (admin/qwer1234)
[Jenkins Web UI] Jenkins URL 수정
Warning:
최초 Jenkins 관리 메뉴로 진입하면 상단에 “역방향 프록시 설정이 잘못된 것으로 파악되었습니다”가 출력됩니다.
Jenkins 내부적으로 요청을 처리하는 주소는 Jenkins URL로 해당 값이 기본적으로 http://jenkins:8080으로 설정돼서 문제가 발생했습니다.
Jenkins 관리SystemJenkins Location
Jenkins URL: http://jenkins.${MyDomain}:8080
Apply → Save
[Jenkins Web UI] Freestyle Project 간단 사용
새로운 Item 추가
Name: First-Project
Freestyle project (Select)
OK
ConfigureBuild Steps
Add build step (Toggle Open)
Execute shell (Click)
Command
echo "Welcome to First Project"
Bash
복사
Apply → Save
Note:
빌드를 수행하기 전에 Dashboard → Jenkins 관리 → Nodes로 진입해서 작업 수행 노드를 확인합니다.
while true; do kubectl get pod -n cicd; date; done
Bash
복사
# [신규 터미널] cicd 네임스페이스에 파드 모니터링
First-Project지금 빌드
Builds → #1 → Console Output
First-ProjectConfigureBuild Steps
Add build step (Toggle Open)
Execute shell (Click)
Command
java -version whoami cat /etc/os-release
Bash
복사
Apply → Save
First-Project지금 빌드
Builds → #2 → Console Output
kubectl exec -it jenkins-0 -c jenkins -n cicd \ -- find / -name First-Project
Bash
복사
# jenkins 파드 디렉터리 구조 확인
kubectl exec -it jenkins-0 -c jenkins -n cicd \ -- ls -l /var/jenkins_home/jobs/First-Project
Bash
복사
kubectl exec -it jenkins-0 -c jenkins -n cicd \ -- cat /var/jenkins_home/jobs/First-Project/builds/1/log
Bash
복사
kubectl exec -it jenkins-0 -c jenkins -n cicd \ -- cat /var/jenkins_home/jobs/First-Project/builds/2/log
Bash
복사
[Jenkins Web UI] Git & Webhook Plugin 설치
Jenkins 관리Plugins
Installed plugins → git (Search)
Available plugins → webhook (Search)
Generic Webhook Trigger (Check)
Install
Warning:
Gogs Plugin도 있지만 보안 이슈에 따라 경고 메시지 출력되고 있습니다.
Generic Webhook Trigger로 대체해서 설치합니다.
[Jenkins Web UI] 신규 Project 생성 후 Generic Webhook Trigger 설정
새로운 Item 추가
Name: Webhook-Project
Freestyle project (Select)
OK
ConfigureTriggers
Generic Webhook Trigger (Check)
Token: qwer1234
ConfigureBuild Steps
Add build step (Toggle Open)
Execute shell (Click)
Command
echo "Gogs Webhook Trigger was Successful!"
Bash
복사
Apply → Save
[Gogs Web UI] Gogs(dev-repo)에서 Webhook 설정
dev-repo 진입 → SettingsWebhooks
Add a new webhook: Gogs (Select)
Payload URL
http://[JENKINS_URL]/generic-webhook-trigger/invoke?token=qwer1234
Bash
복사
triggered: Just the push event
Add webhook (Button Click)
dev-repo에서 파일 수정 후 Push
while true; do kubectl get pod -n cicd; date; done
Bash
복사
# [신규 터미널] cicd 네임스페이스에 파드 모니터링
cd ~/dev-repo echo "0.0.3" > VERSION git add . git commit -m "Change VERSION file" git push -u origin master
Bash
복사
# VERSION 파일 수정 후 git add/commit/push
Note:
[Jenkins] Webhook-Project에서 Build 정보를 확인합니다.
[Gogs] dev-repo에서 Settings → Webhooks → Recent Deliveries 정보를 확인합니다.

2.4. Jenkins - CI 파이프라인 구성

Bastion Host에 Jenkins Agent 설치
cd; mkdir jenkins-agent cd jenkins-agent
Bash
복사
# jenkins-agent 디렉터리 생성 및 진입
apt update apt install -y openjdk-17-jre-headless
Bash
복사
# JRE17 설치
Jenkins 관리NodesNew Node
Node Name: Bastion-Agent
Type: Permanent Agent (Select)
Create
Remote root directory: /root/jenkins-agent
Labels: Bastion-Agent
Save
Bastion-Agent (Click)
Run from agent command line: (Unix)
Secret 값 복사
JENKINS_SECRET=[각자 시크릿 값]
Bash
복사
# jenkins-agent secret 변수 선언
curl -sO http://jenkins.${MyDomain}:8080/jnlpJars/agent.jar
Bash
복사
# jenkins-agent JAR 파일 다운로드
nohup java -jar agent.jar -url http://jenkins.ongja2.click:8080/ \ -secret ${JENKINS_SECRET} \ -name "Bastion-Agent" \ -webSocket -workDir "/root/jenkins-agent" > jenkins-agent.log 2>&1 &
Bash
복사
# jenkins-agent 실행 (nohup 백그라운드 실행)
ps aux | grep agent.jar
Bash
복사
# agent.jar 실행 프로세스 (중지할 때 kill -9 PID)
[Jenkins Web UI] Credential 생성 (gogs 인증)
Jenkins 관리Credentials
global (Click) → Add Credentials
Kind: Username with Password
Username: cicd
Password: qwer1234
ID: gogs-id
[Jenkins Web UI] Pipeline 생성 및 설정
새로운 Item 추가
Name: CICD-Pipeline
Pipeline (Select)
OK
ConfigureTriggers
Generic Webhook Trigger (Check)
Token: qwer1234
Pipeline
Definition → Pipeline script from SCM (Select)
SCM → Git (Select)
Repository URL → [각자 dev-repo URL]
Credentials → cicd/****** (Select)
Script Path: Jenkinsfile
Apply → Save
파이프 라인 - Jenkinsfile 생성
cd ~/dev-repo
Bash
복사
# dev-repo 디렉터리 진입
cat >Jenkinsfile <<EOF pipeline { agent { label 'Bastion-Agent' } environment { AWS_REGION = "ap-northeast-2" ECR_REPO = "private/myapp" ECR_URI = "\${env.ACCOUNT_ID}.dkr.ecr.\${env.AWS_REGION}.amazonaws.com/\${env.ECR_REPO}" } stages { stage('Checkout dev-repo') { steps { git branch: 'master', credentialsId: 'gogs-id', url: 'http://gogs.${MyDomain}:3000/cicd/dev-repo.git' } } stage('Read VERSION File') { steps { script { env.IMAGE_TAG = sh(script: 'cat VERSION', returnStdout: true).trim() echo "Image Tag: \${env.IMAGE_TAG}" } } } stage('Build') { steps { sh "docker build -t \${env.ECR_REPO}:\${env.IMAGE_TAG} ." } } stage('Login to AWS ECR') { steps { sh "aws ecr get-login-password --region \${env.AWS_REGION} | docker login --username AWS --password-stdin \${env.ECR_URI}" } } stage('Push to ECR') { steps { script { sh "docker tag \${env.ECR_REPO}:\${env.IMAGE_TAG} \${env.ECR_URI}:\${env.IMAGE_TAG}" sh "docker push \${env.ECR_URI}:\${env.IMAGE_TAG}" } } } } } EOF
Bash
복사
# Jenkinsfile 생성 (CI 파이프 라인 정의)
dev-repo에서 파일 수정 후 Push
echo "0.0.4" > VERSION git add . git commit -m "Change VERSION file & Add Jenkinsfile" git push -u origin master
Bash
복사
# VERSION 파일 수정 후 git add/commit/push
tree ~/jenkins-agent/
Bash
복사
# jenkins-agent 디렉터리 구조 (tree)
aws ecr list-images \ --repository-name private/myapp \ --region ${AWS_DEFAULT_REGION}
Bash
복사
# ecr에 구성된 이미지 태그 확인
Git Push가 발생되면 Webhook이 트리거되고 Jenkins Pipeline에 의해 자동으로 ECR에 이미지가 저장됩니다.

3. GitOps 및 CD 파이프라인 구성

EKS 환경에서 CD 파이프라인 구성을 위한 다양한 요소를 설치하고 실습합니다.

3.1. Gogs Repository 생성

[Gogs Web UI] 신규 Repository 생성
DashboardMy Repositories+
Repository Name: devops-repo
Visibility: This repository is Private (Check)
.gitignore: Python
Readme: Default
Initialize this repository with selected files and template (Check)
Create Repository (Button Click)
OPS_REPO_PATH=gogs.${MyDomain}:3000/cicd/devops-repo.git echo "export OPS_REPO_PATH=$OPS_REPO_PATH" >> /etc/profile; echo $OPS_REPO_PATH
Bash
복사
# OPS_REPO_PATH 변수 선언
kubectl exec -it $GOGS_POD -n cicd -- tree /data/git -L 4
Bash
복사
# gogs 파드 /data/git 구조 확인(depth 4)
Gogs 실습을 위한 git clone
cd; git clone http://$GOGS_TOKEN@$OPS_REPO_PATH cd devops-repo
Bash
복사
# git clone - devops-repo
git branch
Bash
복사
# git branch 확인

3.2. ArgoCD 설치 및 확인

helm으로 ArgoCD 설치
helm repo add argo https://argoproj.github.io/argo-helm helm repo update
Bash
복사
# helm repo 추가
export CERT_ARN=$(aws acm list-certificates --region ap-northeast-2 --query "CertificateSummaryList[?DomainName=='*.${MyDomain}'].CertificateArn" --output text) echo "export CERT_ARN=$CERT_ARN" >> /etc/profile; echo $CERT_ARN
Bash
복사
# CERT ARN 변수 선언
helm install argocd argo/argo-cd \ --namespace cicd \ --version 7.8.5 \ --set global.domain="argocd.$MyDomain" \ --set server.ingress.enabled=true \ --set server.ingress.controller=aws \ --set server.ingress.ingressClassName=alb \ --set server.ingress.hostname="argocd.$MyDomain" \ --set server.ingress.annotations."alb\.ingress\.kubernetes\.io/scheme"=internet-facing \ --set server.ingress.annotations."alb\.ingress\.kubernetes\.io/target-type"=ip \ --set server.ingress.annotations."alb\.ingress\.kubernetes\.io/backend-protocol"=HTTPS \ --set server.ingress.annotations."alb\.ingress\.kubernetes\.io/listen-ports"="[{\"HTTP\":80}\,{\"HTTPS\":443}]" \ --set server.ingress.annotations."alb\.ingress\.kubernetes\.io/certificate-arn"="$CERT_ARN" \ --set server.ingress.annotations."alb\.ingress\.kubernetes\.io/ssl-redirect"=443 \ --set server.aws.serviceType=ClusterIP \ --set server.aws.backendProtocolVersion=GRPC \ --set dex.enabled=false \ --set notifications.enabled=false
Bash
복사
# ArgoCD 설치 (helm install)
kubectl get all -n cicd
Bash
복사
# cicd 네임스페이스 자원 확인
while true; do \ aws elbv2 describe-load-balancers \ --query 'LoadBalancers[*].[LoadBalancerName,State.Code]' \ --output table; \ done
Bash
복사
# elb 생성 확인 (Ctrl + Z로 중지)
echo -e "ArgoCD URL = https://argocd.$MyDomain"
Bash
복사
# ArgoCD URL 출력
kubectl -n cicd get secret argocd-initial-admin-secret \ -o jsonpath="{.data.password}" | base64 -d; echo
Bash
복사
# admin의 초기 암호 출력 (복사)
Note:
출력된 ArgoCD URL로 접근하여 로그인합니다. (admin/출력된 암호)
ArgoCD는 기본적으로 TLS 동작을 수행하여 Ingress로 ALB를 구성 후 인증서를 등록했습니다.
ArgoCD 초기 암호 변경
User InfoUPDATE PASSWORD (Button Click)
Current Password: [초기 암호 값]
New Password: qwer1234
Confirm New Password: qwer1234
SAVE NEW PASSWORD (Button Click)
ArgoCD CLI 설치
cd ARGO_VER=2.14.2 curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/download/v${ARGO_VER}/argocd-linux-amd64 install -m 555 argocd-linux-amd64 /usr/local/bin/argocd rm argocd-linux-amd64
Bash
복사
# ArgoCD CLI 설치
argocd version
Bash
복사
# ArgoCD 버전 확인
argocd login argocd.${MyDomain}
Bash
복사
# ArgoCD CLI 로그인
argocd cluster list
Bash
복사
# ArgoCD 클러스터 정보 확인
Note:
현재 ArgoCD에 애플리케이션이 하나도 없어 클러스터 모니터링을 하지 않습니다.
argocd app list
Bash
복사
# ArgoCD에 애플리케이션 리스트 확인
argocd repo list
Bash
복사
# ArgoCD에 연결된 Repository 리스트 확인
ArgoCD에 Repository 연결
argocd repo add http://gogs.${MyDomain}:3000/cicd/devops-repo.git \ --username cicd \ --password qwer1234 \ --name devops-repo
Bash
복사
# ArgoCD에 Repository 추가
argocd repo list
Bash
복사
# ArgoCD에 연결된 Repository 리스트 확인
Note:
ArgoCD Web UI에서 Settings → Repositories에서 생성된 Repo를 확인할 수 있습니다.

3.3. ArgoCD - GitOps 테스트(수동)

devops-repo에서 manifests 구성 및 git push
cd ~/devops-repo mkdir manifests tree
Bash
복사
# manifests 디렉터리 생성
cat >./manifests/myapp-deployment.yaml <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: myapp-deployment namespace: default spec: replicas: 3 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - name: myapp-container image: ${ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/private/myapp:0.0.4 ports: - containerPort: 8080 EOF cat ./manifests/myapp-deployment.yaml | yh
Bash
복사
# myapp-deployment.yaml 파일 생성
cat >./manifests/myapp-service.yaml <<EOF apiVersion: v1 kind: Service metadata: name: myapp-service namespace: default spec: selector: app: myapp ports: - protocol: TCP port: 8080 targetPort: 8080 type: LoadBalancer EOF cat ./manifests/myapp-service.yaml | yh
Bash
복사
# myapp-service.yaml 파일 생성
git add . git commit -m "Add k8s myapp manifests" git push -u origin master
Bash
복사
# git add/commit/push
ArgoCD에 애플리케이션 추가
kubectl get cm argocd-cm -n cicd -o yaml | yh
Bash
복사
# ArgoCD ConfigMap 확인
argocd app create myapp-test \ --repo http://gogs.${MyDomain}:3000/cicd/devops-repo.git \ --path manifests \ --dest-server https://kubernetes.default.svc \ --dest-namespace default \ --sync-policy automated
Bash
복사
# ArgoCD app 생성 (myapp-test)
kubectl get pod,deploy,svc
Bash
복사
# default 네임스페이스 파드 확인
argocd app list
Bash
복사
# ArgoCD app 리스트 확인
argocd cluster list
Bash
복사
# ArgoCD 클러스터 리스트 확인
argocd app get myapp-test
Bash
복사
# ArgoCD app 확인
MYAPP_ADDR=$(kubectl get svc myapp-service -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') echo "export MYAPP_ADDR=$MYAPP_ADDR" >> /etc/profile; echo $MYAPP_ADDR
Bash
복사
# 서비스 LB이 도메인 변수 선언
curl ${MYAPP_ADDR}:8080
Bash
복사
# myapp 접속
while true; do curl ${MYAPP_ADDR}:8080; date; echo '---'; sleep 1; done
Bash
복사
# [신규 터미널] myapp 접속 모니터링
MYAPP_ADDR 변수 선언 전에 이미 신규 터미널이 열려있었다면, source /etc/profile 명령을 입력하고 다시 모니터링 명령을 시도해 주세요.
dev-repo에 파일 수정 후 Push
cd ~/dev-repo echo "0.0.5" > VERSION git add . git commit -m "Change VERSION file" git push -u origin master
Bash
복사
# VERSION 파일 수정 후 git add/commit/push
aws ecr list-images \ --repository-name private/myapp \ --region ${AWS_DEFAULT_REGION}
Bash
복사
# ecr에 구성된 이미지 태그 확인
[수동] devops-repo에서 파일 수정 후 Push
cd ~/devops-repo sed -i 's/0.0.4/0.0.5/g' ./manifests/myapp-deployment.yaml cat ./manifests/myapp-deployment.yaml | yh
Bash
복사
# myapp-deployment.yaml 파일 수정
git add ./manifests git commit -m "Change manifests/myapp-deployment.yaml" git push -u origin master
Bash
복사
# git add/commit/push (devops-repo)
Note:
수동으로 devops-repo에 파일을 수정한 후 ArgoCD Web UI와 콘솔 모니터링을 통해 파드의 이미지 업데이트를 확인합니다.
[Gogs Web UI] Gogs(devops-repo)에서 Webhook 설정
devops-repo 진입 → SettingsWebhooks
Add a new webhook: Gogs (Select)
Payload URL
https://argocd.${MyDomain}/api/webhook
Bash
복사
triggered: Just the push event
Add webhook (Button Click)
대상 Webhook 진입 → Test Delivery (Button Click)
devops-repo Webhook을 통한 ArgoCD 자원 배포
cd ~/dev-repo echo "0.0.6" > VERSION git add . git commit -m "Change VERSION file" git push -u origin master
Bash
복사
# VERSION 파일 수정 후 git add/commit/push
aws ecr list-images \ --repository-name private/myapp \ --region ${AWS_DEFAULT_REGION}
Bash
복사
# ecr에 구성된 이미지 태그 확인
cd ~/devops-repo sed -i 's/0.0.5/0.0.6/g' ./manifests/myapp-deployment.yaml cat ./manifests/myapp-deployment.yaml | yh
Bash
복사
# myapp-deployment.yaml 파일 수정
git add ./manifests git commit -m "Change manifests/myapp-deployment.yaml" git push -u origin master
Bash
복사
# git add/commit/push (devops-repo)

3.4. Jenkins - CD 파이프라인 구성

파이프 라인 - Jenkinsfile 수정
cd ~/dev-repo cat >Jenkinsfile <<EOF pipeline { agent { label 'Bastion-Agent' } environment { AWS_REGION = "ap-northeast-2" ECR_REPO = "private/myapp" ECR_URI = "\${env.ACCOUNT_ID}.dkr.ecr.\${env.AWS_REGION}.amazonaws.com/\${env.ECR_REPO}" } stages { stage('Checkout dev-repo') { steps { git branch: 'master', credentialsId: 'gogs-id', url: 'http://gogs.${MyDomain}:3000/cicd/dev-repo.git' } } stage('Read VERSION File') { steps { script { env.IMAGE_TAG = sh(script: 'cat VERSION', returnStdout: true).trim() echo "Image Tag: \${env.IMAGE_TAG}" } } } stage('Build') { steps { sh "docker build -t \${env.ECR_REPO}:\${env.IMAGE_TAG} ." } } stage('Login to AWS ECR') { steps { sh "aws ecr get-login-password --region \${env.AWS_REGION} | docker login --username AWS --password-stdin \${env.ECR_URI}" } } stage('Push to ECR') { steps { script { sh "docker tag \${env.ECR_REPO}:\${env.IMAGE_TAG} \${env.ECR_URI}:\${env.IMAGE_TAG}" sh "docker push \${env.ECR_URI}:\${env.IMAGE_TAG}" } } } stage('Checkout devops-repo') { steps { git branch: 'master', credentialsId: 'gogs-id', url: 'http://gogs.${MyDomain}:3000/cicd/devops-repo.git' } } stage('Update ArgoCD Manifests') { steps { withCredentials([usernamePassword(credentialsId: 'gogs-id', usernameVariable: 'GOGSCRD_USR', passwordVariable: 'GOGSCRD_PSW')]) { script { sh """ sed -i 's|image: .*|image: \${env.ECR_URI}:\${env.IMAGE_TAG}|' manifests/myapp-deployment.yaml git add manifests/myapp-deployment.yaml git config user.name "cicd" git config user.email "abc@abc.com" git commit -m "Update image to \${env.IMAGE_TAG}" git push http://\$GOGSCRD_USR:\$GOGSCRD_PSW@gogs.${MyDomain}:3000/cicd/devops-repo.git master """ } } } } } } EOF
Bash
복사
# Jenkinsfile의 파이프라인 수정 (CD 파이프라인 추가)
dev-repo에서 파일 수정 후 Push
echo "0.0.7" > VERSION git add . git commit -m "Change VERSION file & Add Jenkinsfile" git push -u origin master
Bash
복사
# VERSION 파일 수정 후 git add/commit/push
Note:
CI/CD 파이프라인에 의해 ArgoCD Web UI와 콘솔 모니터링을 통해 파드의 이미지 업데이트를 확인합니다.

4. 실습 환경 삭제

5장 Amazon EKS CI/CD 실습 환경 삭제와 Terraform 삭제 작업을 진행합니다.

4.1. 실습 자원 삭제

ArgoCD에 애플리케이션 삭제
argocd app delete myapp-test
Bash
복사
# ArgoCD app 생성 (myapp-test)
kubectl get pod,deploy,svc
Bash
복사
# default 네임스페이스 자원 확인
argocd app list
Bash
복사
# ArgoCD app 리스트 확인
helm 대상 삭제 (gogs,jenkins,argocd)
helm uninstall gogs -n cicd helm uninstall jenkins -n cicd helm uninstall argocd -n cicd
Bash
복사
# helm uninstall (gogs,jenkins,argocd)
kubectl get all -n cicd
Bash
복사
# cicd 네임스페이스 자원 확인
ECR Private Repository 삭제
aws ecr delete-repository \ --region ap-northeast-2 \ --repository-name private/myapp \ --force
Bash
복사
# ecr private repository 삭제
aws ecr describe-repositories
Bash
복사
# ecr private repository 확인
[관리 콘솔] Route 53 레코드 삭제
9개의 레코드 삭제
gogs 3개
jenkins 3개
argocd 3개

4.2. Terraform 삭제

Terraform 자원 삭제
nohup sh -c "terraform destroy -auto-approve" > delete.log 2>&1 &
Bash
복사
# terraform 자원 삭제
Warning:
nohup으로 백그라운드로 실행하도록 변경했습니다. Terraform 삭제가 완료되면 정상적으로 자원 삭제 되었는지 확인을 합니다.(cat delete.log)
여기까지 5장의 첫 번째 실습인 Amazon EKS CI/CD 실습을 마칩니다.
수고하셨습니다 :)