
# YAML 파일 다운로드
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/K8S/eks-oneclick6.yaml
# CloudFormation 스택 배포
예시) aws cloudformation deploy --template-file eks-oneclick6.yaml --stack-name myeks --parameter-overrides KeyName=kp-gasida SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32 MyIamUserAccessKeyID=AKIA5... MyIamUserSecretAccessKey='CVNa2...' ClusterBaseName=myeks --region ap-northeast-2
# CloudFormation 스택 배포 완료 후 작업용 EC2 IP 출력
aws cloudformation describe-stacks --stack-name myeks --query 'Stacks[*].Outputs[0].OutputValue' --output text
# 작업용 EC2 SSH 접속
ssh -i ~/.ssh/kp-gasida.pem ec2-user@$(aws cloudformation describe-stacks --stack-name myeks --query 'Stacks[*].Outputs[0].OutputValue' --output text)
or
ssh -i ~/.ssh/kp-gasida.pem root@$(aws cloudformation describe-stacks --stack-name myeks --query 'Stacks[*].Outputs[0].OutputValue' --output text)
~ password: qwe123
# default 네임스페이스 적용
kubectl ns default
# 노드 정보 확인 : t3.medium
kubectl get node --label-columns=node.kubernetes.io/instance-type,eks.amazonaws.com/capacityType,topology.kubernetes.io/zone
# ExternalDNS
MyDomain=<자신의 도메인>
echo "export MyDomain=<자신의 도메인>" >> /etc/profile
MyDomain=gasida.link
echo "export MyDomain=gasida.link" >> /etc/profile
MyDnzHostedZoneId=$(aws route53 list-hosted-zones-by-name --dns-name "${MyDomain}." --query "HostedZones[0].Id" --output text)
echo $MyDomain, $MyDnzHostedZoneId
curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/aews/externaldns.yaml
MyDomain=$MyDomain MyDnzHostedZoneId=$MyDnzHostedZoneId envsubst < externaldns.yaml | kubectl apply -f -
# kube-ops-view
helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set env.TZ="Asia/Seoul" --namespace kube-system
kubectl patch svc -n kube-system kube-ops-view -p '{"spec":{"type":"LoadBalancer"}}'
kubectl annotate service kube-ops-view -n kube-system "external-dns.alpha.kubernetes.io/hostname=kubeopsview.$MyDomain"
echo -e "Kube Ops View URL = http://kubeopsview.$MyDomain:8080/#scale=1.5"
# AWS LB Controller
helm repo add eks https://aws.github.io/eks-charts
helm repo update
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
# gp3 스토리지 클래스 생성
kubectl apply -f https://raw.githubusercontent.com/gasida/PKOS/main/aews/gp3-sc.yaml
# 노드 보안그룹 ID 확인
NGSGID=$(aws ec2 describe-security-groups --filters Name=group-name,Values=*ng1* --query "SecurityGroups[*].[GroupId]" --output text)
aws ec2 authorize-security-group-ingress --group-id $NGSGID --protocol '-1' --cidr 192.168.1.100/32
# 사용 리전의 인증서 ARN 확인
CERT_ARN=`aws acm list-certificates --query 'CertificateSummaryList[].CertificateArn[]' --output text`
echo $CERT_ARN
# repo 추가
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
# 파라미터 파일 생성 : PV/PVC(AWS EBS) 삭제에 불편하니, 4주차 실습과 다르게 PV/PVC 미사용
cat <<EOT > monitor-values.yaml
prometheus:
prometheusSpec:
podMonitorSelectorNilUsesHelmValues: false
serviceMonitorSelectorNilUsesHelmValues: false
retention: 5d
retentionSize: "10GiB"
ingress:
enabled: true
ingressClassName: alb
hosts:
- prometheus.$MyDomain
paths:
- /*
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN
alb.ingress.kubernetes.io/success-codes: 200-399
alb.ingress.kubernetes.io/load-balancer-name: myeks-ingress-alb
alb.ingress.kubernetes.io/group.name: study
alb.ingress.kubernetes.io/ssl-redirect: '443'
grafana:
defaultDashboardsTimezone: Asia/Seoul
adminPassword: prom-operator
defaultDashboardsEnabled: false
ingress:
enabled: true
ingressClassName: alb
hosts:
- grafana.$MyDomain
paths:
- /*
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN
alb.ingress.kubernetes.io/success-codes: 200-399
alb.ingress.kubernetes.io/load-balancer-name: myeks-ingress-alb
alb.ingress.kubernetes.io/group.name: study
alb.ingress.kubernetes.io/ssl-redirect: '443'
alertmanager:
enabled: false
EOT
cat monitor-values.yaml | yh
# 배포
kubectl create ns monitoring
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack --version 57.2.0 \
--set prometheus.prometheusSpec.scrapeInterval='15s' --set prometheus.prometheusSpec.evaluationInterval='15s' \
-f monitor-values.yaml --namespace monitoring
# Metrics-server 배포
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# 프로메테우스 ingress 도메인으로 웹 접속
echo -e "Prometheus Web URL = https://prometheus.$MyDomain"
# 그라파나 웹 접속 : 기본 계정 - admin / prom-operator
echo -e "Grafana Web URL = https://grafana.$MyDomain"
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# echo -e "Prometheus Web URL = https://prometheus.$MyDomain"
Prometheus Web URL = https://prometheus.22joo.shop
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# echo -e "Grafana Web URL = https://grafana.$MyDomain"
Grafana Web URL = https://grafana.22joo.shop
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# k get ingress -n monitoring
NAME CLASS HOSTS ADDRESS PORTS AGE
kube-prometheus-stack-grafana alb grafana.22joo.shop myeks-ingress-alb-1775769576.ap-northeast-2.elb.amazonaws.com 80 84s
kube-prometheus-stack-prometheus alb prometheus.22joo.shop myeks-ingress-alb-1775769576.ap-northeast-2.elb.amazonaws.com 80 84s

# ubuntu 이미지 다운로드
docker pull ubuntu:20.04
docker images
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 20.04 33985b2ba010 7 days ago 72.8MB
# 실습을 위한 디렉터리 생성 및 이동
mkdir -p /root/myweb && cd /root/myweb
# Dockerfile 파일 생성
vi Dockerfile
FROM ubuntu:20.04
ENV TZ=Asia/Seoul VERSION=1.0.0 NICK=<자신의 닉네임>
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
sed -i 's/archive.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
sed -i 's/security.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
apt-get update && apt-get install -y apache2 figlet && \
echo "$NICK Web Server $VERSION<br>" > /var/www/html/index.html && \
echo "<pre>" >> /var/www/html/index.html && \
figlet AEWS Study >> /var/www/html/index.html && \
echo "</pre>" >> /var/www/html/index.html
EXPOSE 80
CMD ["usr/sbin/apache2ctl", "-DFOREGROUND"]
(leeeuijoo@myeks:default) [root@myeks-bastion myweb]# cat Dockerfile
FROM ubuntu:20.04
ENV TZ=Asia/Seoul VERSION=1.0.0 NICK=euijoo
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
sed -i 's/archive.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
sed -i 's/security.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
apt-get update && apt-get install -y apache2 figlet && \
echo "$NICK Web Server $VERSION<br>" > /var/www/html/index.html && \
echo "<pre>" >> /var/www/html/index.html && \
figlet AEWS Study >> /var/www/html/index.html && \
echo "</pre>" >> /var/www/html/index.html
EXPOSE 80
CMD ["usr/sbin/apache2ctl", "-DFOREGROUND"]
# 이미지 빌드
docker build -t myweb:v1.0.0 .
docker images
docker image history myweb:v1.0.0
docker image inspect myweb:v1.0.0 | jq
(leeeuijoo@myeks:default) [root@myeks-bastion myweb]# docker images | grep my
myweb v1.0.0 138734a9d166 11 seconds ago 237MB
# 컨테이너 실행
docker run -d -p 80:80 --rm --name myweb myweb:v1.0.0
docker ps
curl localhost
(leeeuijoo@myeks:default) [root@myeks-bastion myweb]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b68b66c90632 myweb:v1.0.0 "usr/sbin/apache2ctl…" 4 seconds ago Up 2 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp myweb
(leeeuijoo@myeks:default) [root@myeks-bastion myweb]# curl localhost
euijoo Web Server 1.0.0<br>
<pre>
_ _______ ______ ____ _ _
/ \ | ____\ \ / / ___| / ___|| |_ _ _ __| |_ _
/ _ \ | _| \ \ /\ / /\___ \ \___ \| __| | | |/ _` | | | |
/ ___ \| |___ \ V V / ___) | ___) | |_| |_| | (_| | |_| |
/_/ \_\_____| \_/\_/ |____/ |____/ \__|\__,_|\__,_|\__, |
|___/
</pre>
# 웹 접속 확인
curl -s ipinfo.io/ip | awk '{ print "myweb = http://"$1"" }'
# 설정
DHUB=leeeuijoo
docker tag myweb:v1.0.0 $DHUB/myweb:v1.0.0
docker images
(leeeuijoo@myeks:default) [root@myeks-bastion myweb]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
leeeuijoo/myweb v1.0.0 138734a9d166 2 minutes ago 237MB
myweb v1.0.0 138734a9d166 2 minutes ago 237MB
ubuntu 20.04 33985b2ba010 7 days ago 72.8MB
(leeeuijoo@myeks:default) [root@myeks-bastion myweb]#
# 도커 허브 로그인
docker login
Username: <자신의 ID>
Password: <암호>
## 로그인 정보는 /[계정명]/.docker/config.json 에 저장됨. docker logout 시 삭제됨
## cat /root/.docker/config.json | jq
(leeeuijoo@myeks:default) [root@myeks-bastion myweb]# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: leeeuijoo
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
# push 로 이미지를 저장소에 업로드
docker push $DHUB/myweb:v1.0.0
(leeeuijoo@myeks:default) [root@myeks-bastion myweb]# docker push $DHUB/myweb:v1.0.0
The push refers to repository [docker.io/leeeuijoo/myweb]
13e0c15d39a0: Pushed
106e8431b412: Mounted from library/ubuntu
v1.0.0: digest: sha256:a80ac1ced9ea7f057077c5eb15b7e92001329488c356539bc0f0387bf88a4777 size: 741

# 컨테이너 종료
docker rm -f myweb
docker ps
# 로컬 이미지 삭제
docker rmi $DHUB/myweb:v1.0.0
docker images
# Container 실행
docker run -d -p 80:80 --rm --name myweb $DHUB/myweb:v1.0.0
docker iamges
(leeeuijoo@myeks:default) [root@myeks-bastion myweb]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
leeeuijoo/myweb v1.0.0 138734a9d166 5 minutes ago 237MB
myweb v1.0.0 138734a9d166 5 minutes ago 237MB
ubuntu 20.04 33985b2ba010 7 days ago 72.8MB
# 확인
docker ps
curl localhost
curl -s ipinfo.io/ip | awk '{ print "myweb = http://"$1"" }'
(leeeuijoo@myeks:default) [root@myeks-bastion myweb]# curl localhost
euijoo Web Server 1.0.0<br>
<pre>
_ _______ ______ ____ _ _
/ \ | ____\ \ / / ___| / ___|| |_ _ _ __| |_ _
/ _ \ | _| \ \ /\ / /\___ \ \___ \| __| | | |/ _` | | | |
/ ___ \| |___ \ V V / ___) | ___) | |_| |_| | (_| | |_| |
/_/ \_\_____| \_/\_/ |____/ |____/ \__|\__,_|\__,_|\__, |
|___/
</pre>
# 삭제
docker rm -f myweb
Jenkins 소개 : 지속적인 통합과 배포 → Work flow를 제어 - Link
CI(지속적 제공)/CD(지속적 배포) 워크플로 시나리오
소프트웨어 개발 프로세스의 다양한 단계를 자동화하는 도구로서 중앙 소스 코드 리포지터리에서 최신 코드 가져오기, 소스 코드 컴파일, 단위 테스트 실행, 산출물을 다양한 유형으로 패키징, 산출물을 여러 종류의 환경으로 배포하기 등의 기능을 제공.
젠킨스는 아파치 톰캣처럼 서블릿 컨테이너 내부에서 실행되는 서버 시스템이다. 자바로 작성됐고, 소프트웨어 개발과 관련된 다양한 도구를 지원.
젠킨스는 DSL Domain Specific Language (jenkins file)로 E-E 빌드 수명 주기 단계를 구축한다.
젠킨스는 파이프라인이라고 부르는 스크립트를 작성할 수 있는데, 이를 사용해서 각 빌드 단계마다 젠킨스가 수행할 태스트 및 하위 태스크의 순서를 정의.
# 실습 편리를 위해서 root 계정 전환
sudo su -
# Add required dependencies for the jenkins package
# https://docs.aws.amazon.com/corretto/latest/corretto-17-ug/amazon-linux-install.html
sudo yum install fontconfig java-17-amazon-corretto -y
java -version
alternatives --display java
JAVA_HOME=/usr/lib/jvm/java-17-amazon-corretto.x86_64
echo $JAVA_HOME
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# echo $JAVA_HOME
/usr/lib/jvm/java-17-amazon-corretto.x86_64
# 젠킨스 설치
sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io-2023.key
sudo yum upgrade
sudo yum install jenkins -y
sudo systemctl daemon-reload
sudo systemctl enable jenkins && sudo systemctl start jenkins # 다소 시간 걸림
sudo systemctl status jenkins

# 초기 암호 확인
sudo systemctl status jenkins
cat /var/lib/jenkins/secrets/initialAdminPassword
# 접속 주소 확인
curl -s ipinfo.io/ip | awk '{ print "Jenkins = http://"$1":8080" }'




Jenkins 관리 → Tools 진입


첫번째 Item(Project) 생성






java -version → Apply 저장whoamitouch hello.txt

find / -name First-Project
/var/lib/jenkins/jobs/First-Project
/var/lib/jenkins/workspace/First-Project
# 프로젝트(job, item) 별 작업 공간 확인
tree /var/lib/jenkins/workspace/First-Project
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# tree /var/lib/jenkins/workspace/First-Project
/var/lib/jenkins/workspace/First-Project
└── hello.txt
0 directories, 1 file
Docker 사용 : Docker-Project
# jenkins 유저로 docker 사용 가능하게 설정
grep -i jenkins /etc/passwd
usermod -s /bin/bash jenkins
grep -i jenkins /etc/passwd
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# grep -i jenkins /etc/passwd
jenkins:x:995:991:Jenkins Automation Server:/var/lib/jenkins:/bin/false
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# usermod -s /bin/bash jenkins
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# grep -i jenkins /etc/passwd
jenkins:x:995:991:Jenkins Automation Server:/var/lib/jenkins:/bin/bash
# jenkins 유저 전환 (Docker 권한이 있지 않습니다.)
su - jenkins
whoami
pwd
docker info
exit
-bash-4.2$ docker info
Client:
Context: default
Debug Mode: false
Plugins:
buildx: Docker Buildx (Docker Inc., v0.0.0+unknown)
Server:
ERROR: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/info": dial unix /var/run/docker.sock: connect: permission denied
errors pretty printing info
-bash-4.2$ exit
logout
# 권한 부여
chmod 666 /var/run/docker.sock
usermod -aG docker jenkins
# Jeknins 유저로 확인
su - jenkins
docker info
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# su - jenkins
Last login: Thu Apr 18 20:39:02 KST 2024 on pts/0
-bash-4.2$ docker info
Client:
Context: default
Debug Mode: false
Plugins:
buildx: Docker Buildx (Docker Inc., v0.0.0+unknown)
Server:
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 5
# Dockerhub로 로그인 하기
docker login
Username: <자신의 계정명>
Password: <자신의 암호>
-bash-4.2$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: leeeuijoo
Password:
WARNING! Your password will be stored unencrypted in /var/lib/jenkins/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
# myweb:v2.0.0 컨테이너 이미지 생성을 위한 Dockerfile 준비
# 실습을 위한 디렉터리 생성 및 이동
mkdir -p ~/myweb2 && cd ~/myweb2
-bash-4.2$ pwd
/var/lib/jenkins/myweb2
# Dockerfile 파일 생성
vi Dockerfile
FROM ubuntu:20.04
ENV TZ=Asia/Seoul VERSION=2.0.0 NICK=euijoo
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
sed -i 's/archive.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
sed -i 's/security.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
apt-get update && apt-get install -y apache2 figlet && \
echo "$NICK Web Server $VERSION<br>" > /var/www/html/index.html && \
echo "<pre>" >> /var/www/html/index.html && \
figlet AEWS Study >> /var/www/html/index.html && \
echo "</pre>" >> /var/www/html/index.html
EXPOSE 80
CMD ["usr/sbin/apache2ctl", "-DFOREGROUND"]
-bash-4.2$ cat Dockerfile
FROM ubuntu:20.04
ENV TZ=Asia/Seoul VERSION=2.0.0 NICK=euijoo
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
sed -i 's/archive.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
sed -i 's/security.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
apt-get update && apt-get install -y apache2 figlet && \
echo "$NICK Web Server $VERSION<br>" > /var/www/html/index.html && \
echo "<pre>" >> /var/www/html/index.html && \
figlet AEWS Study >> /var/www/html/index.html && \
echo "</pre>" >> /var/www/html/index.html
EXPOSE 80
CMD ["usr/sbin/apache2ctl", "-DFOREGROUND"]
# 모니터링
watch -d 'docker images; echo; docker ps'
-----------
# (참고) 이미지 빌드
docker build -t myweb:v2.0.0 -f /var/lib/jenkins/myweb2/Dockerfile
# (참고) 컨테이너 실행
docker run -d -p 80:80 --rm --name myweb myweb:v2.0.0
item : Docker-Project , freestyle

cd /var/lib/jenkins/myweb2
docker build -t myweb:v2.0.0 .

docker run -d -p 80:80 --rm --name myweb myweb:v2.0.0

docker images
docker ps
curl localhost
-bash-4.2$ curl localhost
euijoo Web Server 2.0.0<br>
<pre>
_ _______ ______ ____ _ _
/ \ | ____\ \ / / ___| / ___|| |_ _ _ __| |_ _
/ _ \ | _| \ \ /\ / /\___ \ \___ \| __| | | |/ _` | | | |
/ ___ \| |___ \ V V / ___) | ___) | |_| |_| | (_| | |_| |
/_/ \_\_____| \_/\_/ |____/ |____/ \__|\__,_|\__,_|\__, |
|___/
</pre>


docker rm -f myweb
docker rmi myweb:v2.0.0
Git Hub 활용









docker rm -f myweb
docker rmi myweb:v1.9.9
docker rmi myweb:v1.0.0
Jenkins 작업 (프로젝트, Job, Item) : 3가지 유형의 지시 사항 포함
작업을 수행하는 시점 Trigger
작업을 구성하는 단계별 태스크 Built step
태스크가 완료 후 수행할 명령 Post-build action
파이프라인 Pipeline : CD 파이프라인을 구현하고 통합할 때 사용하는 플러그인 스크립트 모음

Jenkinsfile manually, which you can commit to your project’s source control repository.

파이프라인 2가지 구문 : 선언형 파이프라인(권장)과 스크립트형 파이프라인

pipeline {
agent any # Execute this Pipeline or any of its stages, on any available agent.
stages {
stage('Build') { # Defines the "Build" stage.
steps {
// # Perform some steps related to the "Build" stage.
}
}
stage('Test') {
steps {
//
}
}
stage('Deploy') {
steps {
//
}
}
}
}
node { # Execute this Pipeline or any of its stages, on any available agent.
stage('Build') { # Defines the "Build" stage. stage blocks are optional in Scripted Pipeline syntax. However, implementing stage blocks in a Scripted Pipeline provides clearer visualization of each stage's subset of tasks/steps in the Jenkins UI.
// # Perform some steps related to the "Build" stage.
}
stage('Test') {
//
}
stage('Deploy') {
//
}
}
Pipeline 실습



pipeline {
agent any
stages {
stage('Compile') {
steps {
echo "Compiled successfully!";
sh 'sleep 1'
}
}
stage('JUnit') {
steps {
echo "JUnit passed successfully!";
sh 'sleep 1'
}
}
stage('Code Analysis') {
steps {
echo "Code Analysis completed successfully!";
sh 'sleep 1'
}
}
stage('Deploy') {
steps {
echo "Deployed successfully!";
sh 'sleep 1'
}
}
}
post {
always {
echo "This will always run"
}
success {
echo "This will run when the run finished successfully"
}
failure {
echo "This will run if failed"
}
unstable {
echo "This will run when the run was marked as unstable"
}
changed {
echo "This will run when the state of the pipeline has changed"
}
}
}


1. Secret text 방식을 이용
비권장 방식
pipeline {
agent any
stages {
stage('remote ssh') {
steps {
sh 'sshpass -p qwe123 ssh root@10.10.1.1 hostname'
}
}
}
}
권장 방식

pipeline {
agent any
environment {
SSHPW_CREDS = credentials('vmsshpw')
}
stages {
stage('remote ssh') {
steps {
sh('echo ${SSHPW_CREDS}')
sh('echo ${SSHPW_CREDS_PSW}')
sh('sshpass -p $SSHPW_CREDS_PSW ssh root@10.10.1.1 hostname')
}
}
}
}
2. Secret file 방식을 이용
scp root@<작업용EC2_공인IP>:/root/.kube/config .
# 아래 확인을 위해 모니터링
watch -d kubectl get pod
Jenkins → Credentials → Add → Secret file : File(업로드), ID(k8sconfig)
item : secretk8s (pipiline)
pipeline {
agent any
environment {
MY_KUBECONFIG = credentials('k8sconfig')
}
stages {
stage('remote k8s api') {
steps {
sh("kubectl --kubeconfig $MY_KUBECONFIG get pods -A")
sh("kubectl --kubeconfig $MY_KUBECONFIG run nginx --image nginx --port=80")
}
}
}
}
Jenkins 에서 k8s 사용을 위한 사전 준비
# jenkins 사용자에서 아래 작업 진행
whoami
mkdir ~/.kube
bash-4.2$ whoami
jenkins
bash-4.2$ mkdir ~/.kube
# root 계정에서 아래 복사 실행
cp ~/.kube/config /var/lib/jenkins/.kube/config
chown jenkins:jenkins /var/lib/jenkins/.kube/config
# jenkins 사용자에서 aws eks 사용(sts 호출 등)을 위한 자격증명 설정
aws configure
AWS Access Key ID [None]: AKIA5ILF2###
AWS Secret Access Key [None]: ###
Default region name [None]: ap-northeast-2
# jenkins 사용자에서 kubectl 명령어 사용 확인
kubectl get pods -A # 출력되지 않는다면 AWS Configure 이후 다시 시도 해보시면 됩니다.
bash-4.2$ kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system aws-load-balancer-controller-5f7b66cdd5-gf9p5 1/1 Running 0 141m
kube-system aws-load-balancer-controller-5f7b66cdd5-gq72z 1/1 Running 0 141m
kube-system aws-node-dnqqz 2/2 Running 0 155m
kube-system aws-node-tc7ss 2/2 Running 0
...
Pipeline 으로 Deployment/Service 배포




pipeline {
agent any
tools {
jdk 'jdk-17'
}
environment {
DOCKERHUB_USERNAME = 'leeeuijoo'
GITHUB_URL = 'https://github.com/Leeeuijooo/aews-cicd.git'
// deployment-svc.yaml -> image: gasida/myweb:v1.0.0
DIR_NUM = '3'
}
stages {
stage('Container Build') {
steps {
// 릴리즈파일 체크아웃
checkout scmGit(branches: [[name: '*/main']],
extensions: [[$class: 'SparseCheckoutPaths',
sparseCheckoutPaths: [[path: "/${DIR_NUM}"]]]],
userRemoteConfigs: [[url: "${GITHUB_URL}"]])
// 컨테이너 빌드 및 업로드
sh "docker build -t ${DOCKERHUB_USERNAME}/myweb:v1.0.0 ./${DIR_NUM}"
sh "docker push ${DOCKERHUB_USERNAME}/myweb:v1.0.0"
}
}
stage('K8S Deploy') {
steps {
sh "kubectl apply -f ./${DIR_NUM}/deploy/deployment-svc.yaml"
}
}
}
}


# 배포
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
name: netpod
labels:
app: pod
spec:
containers:
- name: netshoot-pod
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
EOF
kubectl exec -it netpod -- curl myweb:8080
kubectl exec -it netpod -- curl myweb:8080 | grep Web
while true; do kubectl exec -it netpod -- curl myweb:8080 | grep Web; echo; done
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# kubectl exec -it netpod -- curl myweb:8080
aews Web Server 1.0.0<br>
<pre>
_ _______ ______ ____ _ _
/ \ | ____\ \ / / ___| / ___|| |_ _ _ __| |_ _
/ _ \ | _| \ \ /\ / /\___ \ \___ \| __| | | |/ _` | | | |
/ ___ \| |___ \ V V / ___) | ___) | |_| |_| | (_| | |_| |
/_/ \_\_____| \_/\_/ |____/ |____/ \__|\__,_|\__,_|\__, |
|___/
</pre>
# 작업공간 확인
tree /var/lib/jenkins/workspace/k8s-1
/var/lib/jenkins/workspace/k8s-1
└── 3
├── deploy
│ └── deployment-svc.yaml
└── Dockerfile
cat /var/lib/jenkins/workspace/k8s-1/3/Dockerfile
bash-4.2$ cat /var/lib/jenkins/workspace/k8s-1/3/Dockerfile
FROM ubuntu:20.04
ENV TZ=Asia/Seoul MYVERSION=1.0.0 NICK=aews
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
sed -i 's/archive.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
sed -i 's/security.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
apt-get update && apt-get install -y apache2 figlet && \
echo "$NICK Web Server $MYVERSION<br>" > /var/www/html/index.html && \
echo "<pre>" >> /var/www/html/index.html && \
figlet AEWS Study >> /var/www/html/index.html && \
echo "</pre>" >> /var/www/html/index.html
EXPOSE 80
CMD ["usr/sbin/apache2ctl", "-DFOREGROUND"]
kubectl delete deploy,svc myweb
# helm 설치
cat <<EOT > argocd-values.yaml
global:
domain: argocd.$MyDomain
configs:
params:
server.insecure: true
controller:
metrics:
enabled: true
serviceMonitor:
enabled: true
server:
ingress:
enabled: true
controller: aws
ingressClassName: alb
hostname: "argocd.$MyDomain"
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/backend-protocol: HTTP
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":80}, {"HTTPS":443}]'
alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN
alb.ingress.kubernetes.io/ssl-redirect: '443'
aws:
serviceType: ClusterIP
backendProtocolVersion: GRPC
metrics:
enabled: true
serviceMonitor:
enabled: true
repoServer:
metrics:
enabled: true
serviceMonitor:
enabled: true
applicationSet:
metrics:
enabled: true
serviceMonitor:
enabled: true
notifications:
metrics:
enabled: true
serviceMonitor:
enabled: true
EOT
kubectl create ns argocd
helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd argo/argo-cd --version 6.7.11 -f argocd-values.yaml --namespace argocd
# 확인
kubectl get ingress,pod,svc -n argocd
kubectl get crd | grep argo
applications.argoproj.io 2024-04-14T08:12:16Z
applicationsets.argoproj.io 2024-04-14T08:12:17Z
appprojects.argoproj.io 2024-04-14T08:12:16Z
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# kubectl get ingress,pod,svc -n argocd
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress.networking.k8s.io/argocd-server alb argocd.22joo.shop 80 72s
NAME READY STATUS RESTARTS AGE
pod/argocd-application-controller-0 1/1 Running 0 72s
pod/argocd-applicationset-controller-85d64c6b7f-xqsx5 1/1 Running 0 72s
pod/argocd-dex-server-7746bdfd75-bvq5t 1/1 Running 0 72s
pod/argocd-notifications-controller-64d9b554f4-8fdn9 1/1 Running 0 72s
pod/argocd-redis-554fbc6587-h2zz6 1/1 Running 0 72s
pod/argocd-repo-server-664698cb66-jb7km 1/1 Running 0 72s
pod/argocd-server-5b56b9b7b7-kzfc6 1/1 Running 0 72s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/argocd-application-controller-metrics ClusterIP 10.100.248.252 <none> 8082/TCP 73s
service/argocd-applicationset-controller ClusterIP 10.100.48.81 <none> 7000/TCP 73s
service/argocd-applicationset-controller-metrics ClusterIP 10.100.130.155 <none> 8080/TCP 73s
service/argocd-dex-server ClusterIP 10.100.164.163 <none> 5556/TCP,5557/TCP 73s
service/argocd-notifications-controller-metrics ClusterIP 10.100.108.152 <none> 9001/TCP 73s
service/argocd-redis ClusterIP 10.100.109.130 <none> 6379/TCP 73s
service/argocd-repo-server ClusterIP 10.100.229.241 <none> 8081/TCP 73s
service/argocd-repo-server-metrics ClusterIP 10.100.125.137 <none> 8084/TCP 73s
service/argocd-server ClusterIP 10.100.7.85 <none> 80/TCP,443/TCP 73s
service/argocd-server-grpc ClusterIP 10.100.55.12 <none> 80/TCP,443/TCP 73s
service/argocd-server-metrics ClusterIP 10.100.134.83 <none> 8083/TCP 73s
# 최초 접속 암호 확인
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d ;echo
https://argocd.<자신의도메인> admin / <최초 접속 암호>

OutOfSync application state and optionally takes corrective action. It is responsible for invoking any user-defined hooks for lifecycle events (PreSync, Sync, PostSync)App 배포 with Directory






# 모니터링
kubectl get deploy,svc -n first --show-labels
watch -d kubectl get deploy -n first --show-labels

(leeeuijoo@myeks:default) [root@myeks-bastion ~]# k get deployments -n first
NAME READY UP-TO-DATE AVAILABLE AGE
myweb 4/4 4 4 39s

결론 : GitOps를 하려거든 대상(k8s)에서 변경하지 말고, 소스(git)에서 변경하자!
# 아래 추가
kubectl edit deploy -n first myweb
...
labels:
add: label-test
add2: k8s-test
...

Argo CD CLI 로 Sample Application 배포해보기
#
curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd
rm -f argocd-linux-amd64
#
argocd version
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# argocd version
argocd: v2.8.16+a5ae7bd
BuildDate: 2024-04-15T09:10:52Z
GitCommit: a5ae7bd16143814dc8560da0e476905ed1d46628
GitTreeState: clean
GoVersion: go1.20.14
Compiler: gc
Platform: linux/amd64
FATA[0000] Argo CD server address unspecified
#
argocd login argocd.$MyDomain
Username: admin
Password: ###
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# argocd login argocd.$MyDomain
Username: admin
Password:
'admin:login' logged in successfully
Context 'argocd.22joo.shop' updated
#
kubectl config get-contexts -o name
admin@myeks.ap-northeast-2.eksctl.io
argocd cluster add admin@myeks.ap-northeast-2.eksctl.io
y 입력
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# kubectl config get-contexts -o name
leeeuijoo@myeks.ap-northeast-2.eksctl.io
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# argocd cluster add leeeuijoo@myeks.ap-northeast-2.eksctl.io
WARNING: This will create a service account `argocd-manager` on the cluster referenced by context `leeeuijoo@myeks.ap-northeast-2.eksctl.io` with full cluster level privileges. Do you want to continue [y/N]? y
INFO[0005] ServiceAccount "argocd-manager" created in namespace "kube-system"
INFO[0005] ClusterRole "argocd-manager-role" created
INFO[0005] ClusterRoleBinding "argocd-manager-role-binding" created
INFO[0010] Created bearer token secret for ServiceAccount "argocd-manager"
Cluster 'https://CD9F85D8A31E7837D62866530AF74422.gr7.ap-northeast-2.eks.amazonaws.com' added
#
argocd app list
NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# argocd app list
NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET
#
kubectl config set-context --current --namespace=argocd
argocd app create guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --dest-server https://kubernetes.default.svc --dest-namespace default
#
argocd app list
NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET
argocd/guestbook https://kubernetes.default.svc default default OutOfSync Missing <none> <none> https://github.com/argoproj/argocd-example-apps.git guestbook
(leeeuijoo@myeks:argocd) [root@myeks-bastion ~]# argocd app list
NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET
argocd/guestbook https://kubernetes.default.svc default default OutOfSync Missing <none> <none> https://github.com/argoproj/argocd-example-apps.git guestbook

#
argocd app get guestbook
(leeeuijoo@myeks:argocd) [root@myeks-bastion ~]# argocd app get guestbook
Name: argocd/guestbook
Project: default
Server: https://kubernetes.default.svc
Namespace: default
URL: https://argocd.22joo.shop/applications/guestbook
Repo: https://github.com/argoproj/argocd-example-apps.git
Target:
Path: guestbook
SyncWindow: Sync Allowed
Sync Policy: <none>
Sync Status: OutOfSync from (d7927a2)
Health Status: Missing
GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
Service default guestbook-ui OutOfSync Missing
apps Deployment default guestbook-ui OutOfSync Missing
# 모니터링
watch -d kubectl get pod,svc,ep
#
argocd app sync guestbook


(leeeuijoo@myeks:argocd) [root@myeks-bastion ~]# argocd app sync guestbook
TIMESTAMP GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
2024-04-18T23:24:56+09:00 Service default guestbook-ui Synced Healthy
2024-04-18T23:24:56+09:00 apps Deployment default guestbook-ui Synced Healthy
2024-04-18T23:24:57+09:00 Service default guestbook-ui Synced Healthy service/guestbook-ui unchanged
2024-04-18T23:24:57+09:00 apps Deployment default guestbook-ui Synced Healthy deployment.apps/guestbook-ui unchanged
Name: argocd/guestbook
Project: default
Server: https://kubernetes.default.svc
Namespace: default
URL: https://argocd.22joo.shop/applications/guestbook
Repo: https://github.com/argoproj/argocd-example-apps.git
Target:
Path: guestbook
SyncWindow: Sync Allowed
Sync Policy: <none>
Sync Status: Synced to (d7927a2)
Health Status: Healthy
Operation: Sync
Sync Revision: d7927a27b4533926b7d86b5f249cd9ebe7625e90
Phase: Succeeded
Start: 2024-04-18 23:24:56 +0900 KST
Finished: 2024-04-18 23:24:57 +0900 KST
Duration: 1s
Message: successfully synced (all tasks run)
GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
Service default guestbook-ui Synced Healthy service/guestbook-ui unchanged
apps Deployment default guestbook-ui Synced Healthy deployment.apps/guestbook-ui unchanged
argocd app delete guestbook
Are you sure you want to delete 'guestbook' and all its resources? [y/n] y
# ns default 로 변경
kubectl ns default
Advanced Deploy
Blue / Green 전략, Canary 배포가 가능합니다.
Blue/Green



#
cat <<EOT > argorollouts-values.yaml
dashboard:
enabled: true
ingress:
enabled: true
ingressClassName: alb
hosts:
- argorollouts.$MyDomain
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/backend-protocol: HTTP
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":80}, {"HTTPS":443}]'
alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN
alb.ingress.kubernetes.io/ssl-redirect: '443'
EOT
kubectl create ns argo-rollouts
helm install argo-rollouts argo/argo-rollouts --version 2.35.1 -f argorollouts-values.yaml --namespace argo-rollouts
# 확인
kubectl get all -n argo-rollouts
kubectl get crd | grep argo
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# kubectl get crd | grep argo
analysisruns.argoproj.io 2024-04-18T14:29:57Z
analysistemplates.argoproj.io 2024-04-18T14:29:57Z
applications.argoproj.io 2024-04-18T13:34:41Z
applicationsets.argoproj.io 2024-04-18T13:34:41Z
appprojects.argoproj.io 2024-04-18T13:34:40Z
clusteranalysistemplates.argoproj.io 2024-04-18T14:29:57Z
experiments.argoproj.io 2024-04-18T14:29:57Z
rollouts.argoproj.io 2024-04-18T14:29:57Z
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# kubectl get all -n argo-rollouts
NAME READY STATUS RESTARTS AGE
pod/argo-rollouts-7647d689d6-kdlfk 0/1 Running 0 14s
pod/argo-rollouts-7647d689d6-sjrxl 0/1 Running 0 14s
pod/argo-rollouts-dashboard-79d489cfc7-6d8lt 1/1 Running 0 14s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/argo-rollouts-dashboard ClusterIP 10.100.234.43 <none> 3100/TCP 14s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/argo-rollouts 0/2 2 0 14s
deployment.apps/argo-rollouts-dashboard 1/1 1 1 14s
NAME DESIRED CURRENT READY AGE
replicaset.apps/argo-rollouts-7647d689d6 2 2 0 14s
replicaset.apps/argo-rollouts-dashboard-79d489cfc7 1 1 1 14s
https://argorollouts.<자신의 도메인>/rollouts/
#
curl -LO https://github.com/argoproj/argo-rollouts/releases/download/v1.6.4/kubectl-argo-rollouts-linux-amd64
chmod +x ./kubectl-argo-rollouts-linux-amd64
mv ./kubectl-argo-rollouts-linux-amd64 /usr/local/bin/kubectl-argo-rollouts
# 설치 확인
kubectl argo rollouts version
(leeeuijoo@myeks:default) [root@myeks-bastion ~]# kubectl argo rollouts version
kubectl-argo-rollouts: v1.6.4+a312af9
BuildDate: 2023-12-11T18:31:15Z
GitCommit: a312af9f632b985ec13f64918b918c5dcd02a15e
GitTreeState: clean
GoVersion: go1.20.12
Compiler: gc
Platform: linux/amd64
spec:
replicas: 5
strategy:
canary:
steps:
- setWeight: 20
- pause: {} # 20 흘리고 40
- setWeight: 40
- pause: {duration: 10}
- setWeight: 60
- pause: {duration: 10}
- setWeight: 80
- pause: {duration: 10}
# Run the following command to deploy the initial Rollout and Service:
kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-rollouts/master/docs/getting-started/basic/rollout.yaml
kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-rollouts/master/docs/getting-started/basic/service.yaml


(leeeuijoo@myeks:default) [root@myeks-bastion ~]# kubectl argo rollouts get rollout rollouts-demo
Name: rollouts-demo
Namespace: default
Status: ✔ Healthy
Strategy: Canary
Step: 8/8
SetWeight: 100
ActualWeight: 100
Images: argoproj/rollouts-demo:blue (stable)
Replicas:
Desired: 5
Current: 5
Updated: 5
Ready: 5
Available: 5
NAME KIND STATUS AGE INFO
⟳ rollouts-demo Rollout ✔ Healthy 59s
└──# revision:1
└──⧉ rollouts-demo-687d76d795 ReplicaSet ✔ Healthy 59s stable
├──□ rollouts-demo-687d76d795-4r9cj Pod ✔ Running 59s ready:1/1
├──□ rollouts-demo-687d76d795-b5dsh Pod ✔ Running 59s ready:1/1
├──□ rollouts-demo-687d76d795-dzbjz Pod ✔ Running 59s ready:1/1
├──□ rollouts-demo-687d76d795-svrsp Pod ✔ Running 59s ready:1/1
└──□ rollouts-demo-687d76d795-x4jrr Pod ✔ Running 59s ready:1/1
kubectl argo rollouts get rollout rollouts-demo --watch

#
watch -d kubectl get pod -n argocd -l app=rollouts-demo -owide --show-labels
# Run the following command to update the rollouts-demo Rollout with the "yellow" version of the container:
kubectl argo rollouts set image rollouts-demo rollouts-demo=argoproj/rollouts-demo:yellow



# 아래 입력 혹은 UI에서 Promote Yes 클릭
kubectl argo rollouts promote rollouts-demo
#
kubectl argo rollouts get rollout rollouts-demo --watch


#
kubectl argo rollouts set image rollouts-demo rollouts-demo=argoproj/rollouts-demo:red
#
kubectl argo rollouts abort rollouts-demo
#
kubectl argo rollouts set image rollouts-demo rollouts-demo=argoproj/rollouts-demo:yellow
