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
•
Applications → Generate 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 생성
•
Dashboard → My 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 관리 → System → Jenkins Location
◦
Jenkins URL: http://jenkins.${MyDomain}:8080
◦
Apply → Save
[Jenkins Web UI] Freestyle Project 간단 사용
•
새로운 Item 추가
◦
Name: First-Project
◦
Freestyle project (Select)
◦
OK
•
Configure → Build 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-Project → Configure → Build 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
•
Configure → Triggers
◦
Generic Webhook Trigger (Check)
▪
Token: qwer1234
•
Configure → Build 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 진입 → Settings → Webhooks
◦
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 관리 → Nodes → New 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
•
Configure → Triggers
◦
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 생성
•
Dashboard → My 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 Info → UPDATE 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 진입 → Settings → Webhooks
◦
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 실습을 마칩니다.
수고하셨습니다 :)