[AEWS 2기] EKS CI/CD

EKS 스터디 CloudNet@팀의 AEWS 2기에 작성된 자료를 베이스로 작성된 블로깅입니다.

Amazon EKS (myeks) 윈클릭 배포

# 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

이런 메세지가 나오고 

콘솔상에서 확인을 하면 cloudforamtion에서 다음과 같은 스택들이 나오면 배포가 완료된것으로 생각하면됩니다. 

 

bastioin host하나와 node group으로 인해서 생성된 인스턴스 세개가 확인될겁니다. 

 

환경설정

# 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=onthelook.co.kr
echo "export MyDomain=onthelook.co.kr" >> /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"

도커허브 

https://hub.docker.com/

 

Docker Hub Container Image Library | App Containerization

Increase your reach and adoption on Docker Hub With a Docker Verified Publisher subscription, you'll increase trust, boost discoverability, get exclusive data insights, and much more.

hub.docker.com

위 링크에서 계정이 없다면 가입을 해줍니다. 

 

웹 서버 도커 이미지 생성 후 도커 컨테이너 실행

# ubuntu 이미지 다운로드
docker pull ubuntu:20.04
docker images

도커로 ubuntu images를 다운받아줍니다. 

 

# 실습을 위한 디렉터리 생성 및 이동
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"]

실습을 위한 디렉토리를 만들어주고, Dockerfile을 생성해줍니다. 

 

# 이미지 빌드
docker build -t myweb:v1.0.0 .
docker images
docker image history myweb:v1.0.0
docker image inspect myweb:v1.0.0 | jq

# 컨테이너 실행
docker run -d -p 80:80 --rm --name myweb myweb:v1.0.0
docker ps
curl localhost

# 웹 접속 확인
curl -s ipinfo.io/ip | awk '{ print "myweb = http://"$1"" }'

빌드가 잘 되어서 이미지가 생성되었는지 확인해줍니다. 

컨테이너를 실행하고 잘 작동하는지 확인해줍니다. 

 

#
DHUB=<도커 허브 계정>
docker tag myweb:v1.0.0 $DHUB/myweb:v1.0.0
docker images

# 도커 허브 로그인
docker login
Username: <자신의 ID>
Password: <암호>
## 로그인 정보는 /[계정명]/.docker/config.json 에 저장됨. docker logout 시 삭제됨
## cat /root/.docker/config.json | jq

# push 로 이미지를 저장소에 업로드
docker push $DHUB/myweb:v1.0.0

이미지의 이름을 제 도커허브 계정의 이름과 합쳐서 바꿔줍니다.

도커허브에 로그인을 하고, 방금 빌드한 도커 이미지를 도커허브에 업로드해줍니다. 

 

도커허브 콘솔에서도 해당 이미지 확인 가능합니다. 

 

# 컨테이너 종료
docker rm -f myweb
docker ps

# 로컬 이미지 삭제
docker rmi $DHUB/myweb:v1.0.0
docker images

# 
docker run -d -p 80:80 --rm --name myweb $DHUB/myweb:v1.0.0
docker iamges

# 확인
docker ps
curl localhost
curl -s ipinfo.io/ip | awk '{ print "myweb = http://"$1"" }'

# 삭제
docker rm -f myweb

로컬 이미지를 삭제하고, 도커 허브에서 해당 이미지를 다시 다운받은 뒤, 잘 작동하는지 확인합니다. 

잘 되네요


Jenkins

젠킨스는 소프트웨어 개발 프로세스를 자동화하는 데 사용되는 오픈소스 서버입니다. 빌드, 테스트, 배포 등 다양한 작업을 자동화하여 개발 효율성을 높이고 코드 품질을 보장하는 데 도움을 줍니다.

Jenkins 소개 : 지속적인 통합과 배포 → Work flow를 제어 - Link

  1. 최신 코드 가져오기 : 개발을 위해 중앙 코드 리포지터리에서 로컬 시스템으로 애플리케이션의 최신 코드를 가져옴
  2. 단위 테스트 구현과 실행 : 코드 작성 전 단위 테스트 케이스를 먼저 작성
  3. 코드 개발 : 실패한 테스트 케이스를 성공으로 바꾸면서 코드 개발
  4. 단위 테스트 케이스 재실행 : 단위 테스트 케이스 실행 시 통과(성공!)
  5. 코드 푸시와 병합 : 개발 소스 코드를 중앙 리포지터리로 푸시하고, 코드 병합
  6. 코드 병합 후 컴파일 : 변경 함수 코드가 병함되면 전체 애플리케이션이 컴파일된다
  7. 병합된 코드에서 테스트 실행 : 개별 테스트뿐만 아니라 전체 통합 테스트를 실행하여 문제 없는지 확인
  8. 아티팩트 배포 : 애플리케이션을 빌드하고, 애플리케이션 서버의 프로덕션 환경에 배포
  9. 배포 애플리케이션의 E-E 테스트 실행 : 셀레늄 Selenium과 같은 User Interface 자동화 도구를 통해 애플리케이션의 전체 워크플로가 정상 동작하는지 확인하는 종단간 End-to-End 테스트를 실행.
  • The leading open source automation server, Jenkins provides hundreds of plugins to support building, deploying and automating any project.
  • Continuous Integration Server + Continuous Development, Build, Test, Deploy
  • 소프트웨어 개발 프로세스의 다양한 단계자동화하는 도구로서 중앙 소스 코드 리포지터리에서 최신 코드 가져오기, 소스 코드 컴파일, 단위 테스트 실행, 산출물을 다양한 유형으로 패키징, 산출물을 여러 종류의 환경으로 배포하기 등의 기능을 제공.
  • 젠킨스는 아파치 톰캣처럼 서블릿 컨테이너 내부에서 실행되는 서버 시스템이다. 자바로 작성됐고, 소프트웨어 개발과 관련된 다양한 도구를 지원.
  • 젠킨스는 DSL Domain Specific Language (jenkins file)로 E-E 빌드 수명 주기 단계를 구축한다.
  • 젠킨스는 파이프라인이라고 부르는 스크립트를 작성할 수 있는데, 이를 사용해서 각 빌드 단계마다 젠킨스가 수행할 태스트 및 하위 태스크의 순서를 정의.
    • 순차적이고 종속적인 단계가 시작부터 끝까지 실행되면 최종적으로 사용자가 실행할 수 있는 빌드가 생성됨.
    • 만약 빌드 프로세스를 진행하는 중에 특정 단계에서 실패가 발생하며, 이 단계의 출력 결과를 사용하는 다음 단계는 실행되지 않으며 빌드 프로세스 전체가 실패한다.
  • 다양한 Plugins 연동
    • Build Plugins : Maven, Ant, Gradle …
    • VCS Plugins : Git, SVN …
    • Languages Plugins : Java, Python, Node.js …
  • CI(지속적 제공)/CD(지속적 배포) 워크플로 예제

https://www.facebook.com/groups/jenkinskorea/


 

설치 및 설정 

# 실습 편리를 위해서 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

# 젠킨스 설치
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" }'

젠킨스 설치 후 작동하는지 확인합니다. 

위 주소로 접근해서 젠킨스에 들어갑니다.

 

위 경로에 초기 비밀번호가 있다고 알려주네요 

cat으로 확인하여 접근합니다.

 

그 다음 Install suggested plugins를 클릭하여 진행합니다.

 

클릭하면 열심히 설치가 이루어집니다. 기다려줍니다.

유저 설정을 해줍니다.

접속한 주소와 일치하는지 확인한 후 Savd and Finish를 눌러 진행합니다.

이제 준비가 되었다네요 Strat using Jenkins 눌러줍니다.

다 설정하면 이런 대시보드 화면에 접근할 수 있습니다. 


대시보드에 보이는 젠킨스 주요 개념

아이템 (Item): 젠킨스 작업의 기본 단위

젠킨스에서 아이템은 작업의 최소 단위를 의미하며, 빌드, 테스트, 배포 등 다양한 작업들을 정의하고 관리하는 데 사용됩니다. 아이템은 크게 다음과 같은 종류로 나눌 수 있습니다.

프로젝트

하나 이상의 빌드, 테스트, 배포 단계를 포함하는 아이템의 집합입니다. 프로젝트는 서로 다른 코드 저장소 또는 빌드 도구를 사용하는 여러 작업들을 하나로 묶어 관리하는 데 유용합니다.

빌드

소스 코드를 컴파일하고 실행 가능한 코드로 만드는 과정을 정의하는 아이템입니다. 빌드 아이템에는 빌드 도구, 소스 코드 위치, 환경 변수 등 다양한 설정을 포함할 수 있습니다.

파이프라인

여러 빌드, 테스트, 배포 단계들을 순서대로 정의하는 아이템입니다. 파이프라인은 워크플로를 시각적으로 표현하고 자동화된 작업들을 효율적으로 관리하는 데 도움이 됩니다.

특정 시간 또는 이벤트에 따라 자동으로 실행되는 작업을 정의하는 아이템입니다. 잡은 주기적으로 실행되는 백업 작업이나 시스템 관리 작업 등을 자동화하는 데 사용할 수 있습니다.

 

아이템 활용 방법

새로운 아이템 만들기

젠킨스 웹 UI에서 "새로운 아이템 만들기" 버튼을 클릭하여 원하는 아이템 종류를 선택하고 설정을 입력합니다.

아이템 편집

기존 아이템을 편집하려면 아이템 목록에서 원하는 아이템을 선택하고 "편집" 버튼을 클릭합니다.

아이템 삭제

아이템을 삭제하려면 아이템 목록에서 원하는 아이템을 선택하고 "삭제" 버튼을 클릭합니다.

사람 (People): 젠킨스 사용자 관리

사람 아이템은 젠킨스 사용자를 관리하고 권한을 부여하는 데 사용됩니다. 젠킨스에는 다음과 같은 기본 사용자 역할이 정의되어 있습니다.

- Anonymous: 인증되지 않은 사용자로서 젠킨스 대시보드만 볼 수 있습니다.

- Authenticated User: 로그인된 사용자로서 빌드 실행, 작업 관리 등 기본적인 작업을 수행할 수 있습니다.

- Job Builder: 빌드, 파이프라인, 잡 등을 생성하고 편집할 수 있는 권한을 가진 사용자입니다.

- Admin: 젠킨스 서버 설정, 사용자 관리, 플러그인 설치 등 모든 권한을 가진 사용자입니다.

사람 아이템 활용 방법

- 새로운 사용자 만들기: 젠킨스 웹 UI에서 "사용자 관리" 탭을 선택하고 "새로운 사용자 만들기" 버튼을 클릭하여 사용자 이름, 비밀번호, 역할 등을 설정합니다.

- 사용자 편집: 기존 사용자를 편집하려면 사용자 목록에서 원하는 사용자를 선택하고 "편집" 버튼을 클릭합니다.

- 사용자 삭제: 사용자를 삭제하려면 사용자 목록에서 원하는 사용자를 선택하고 "삭제" 버튼을 클릭합니다.

 

젠킨스 관리 (Jenkins Administration): 전역 설정 관리

젠킨스 관리 아이템은 젠킨스 서버의 전역 설정을 관리하는 데 사용됩니다. 설정에는 다음과 같은 내용이 포함됩니다.

- 일반 설정: 젠킨스 서버 이름, URL, 포트 번호 등 기본적인 설정을 관리합니다.

- 보안 설정: 사용자 인증, 권한 관리, 보안 정책 등을 설정합니다.

- 시스템 설정: 빌드 실행 환경, 네트워크 설정, 자원 할당 등을 설정합니다.

- 플러그인 관리: 젠킨스에 설치된 플러그인을 관리하고 업데이트합니다.

- 업데이트 센터: 젠킨스 서버 및 플러그인의 최신 버전을 확인하고 업데이트합니다.

 

젠킨스 관리 아이템 활용 방법

- 전역 설정 보기: 젠킨스 웹 UI에서 "시스템 관리" 탭을 선택하면 젠킨스 서버의 모든 전역 설정을 확인하고 변경할 수 있습니다.

- 특정 설정 편집: 원하는 설정 카테고리 (예: 일반, 보안, 시스템 등)를 선택하고 설정 항목을 편집합니다.

- 설정 저장: 변경한 설정을 저장하려면 "저장" 버튼을 클릭합니다.

 

젠킨스 활용 팁

- 젠킨스 플러그인을 활용하여 젠킨스 기능을 확장하고 사용자 정의 워크플로를 구축할 수 있습니다.

- 젠킨스는 다양한 CI/CD 도구와 통합될 수 있어 개발 프로세스를 효율적으로 자동화할 수 있습니다.

- 젠킨스를 사용하여 코드 품질을 향상시키고 배포 속도를 단축하며 개발 프로세스의 투명성을 확보할 수 있습니다.


Manage Jenkins에서 First-Project를 생성합니다.

Manage Jenkins -> Tools -> JDK installations 섹션에서 Add JDK를 선택 해줍니다.

- Name에는 jdk-17

- JAVA_HOME에는 /usr/lib/jvm/java-17-amazon-corretto.x86_64

값을 입력 후 Save 버튼을 클릭합니다.

 

New Item 클릭 후 My-First-Project를 이름에 넣어줍니다. 

그 후 Freestyle project를 클릭한 후 하단에 OK를 눌러줍니다. 

그 후 Build Steps를 클릭하고, Add build step을 클릭한 뒤 Execute shell을 클릭해줍니다. 

Command에 간단하게 문장이 출력되어 확인할 수 있도록 echo "Aws Workshop Study"을 입력해줍니다. 

그 후 Save와 Apply를 해줍니다.

좌측의 Build Now를 클릭해줍니다.

빌드 확인은 좌측 하단에 빌드 히스토리에서 화살표를 클릭하고 Console Output을 클릭하여 확인합니다. 

아까 넣었던 Aws Workshop Study 메세지와 함께

Finished: SUCCESS 로그를 확인하여 성공했음을 확인했습니다. 

 

프로젝트를 다시 클릭하고 좌측에서 Configure -> Build Environment -> Build Steps에서

- java -version

- whoami

- touch hello.txt

추가하고 Save를 해줍니다.

 

좌측에서 Build Now를 클릭하여 실행을 해주고, Consoule Output을 다시한번 확인해줍니다.

다음과같은 결과를 확인할 수 있었습니다. 

 

#
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

 

(june@onthelook:default) [root@myeks-bastion ~]# tree /var/lib/jenkins/workspace/First-Project
/var/lib/jenkins/workspace/First-Project
- hello.txt
0 directories,
1 file
(june@onthelook:default) [root@myeks-bastion ~]#

Jenkin를 설치한 Bastion EC2에서 tree /var/lib/jenkins/workspace/First-Project 명령어를 실행하면, hello.txt 파일이 /var/lib/jenkins 내 workspace 에서 프로젝트 내에 파일이 저장된다는 것을 확인할 수 있습니다. 


Jenkin에서 Docker 사용 : Docker-Project

사전 준비 

# jenkins 유저로 docker 사용 가능하게 설정
grep -i jenkins /etc/passwd
usermod -s /bin/bash jenkins
grep -i jenkins /etc/passwd

# jenkins 유저 전환
su - jenkins
whoami
pwd
docker info
exit

#
chmod 666 /var/run/docker.sock
usermod -aG docker jenkins

# Jeknins 유저로 확인
su - jenkins
docker info

# Dockerhub로 로그인 하기
docker login
Username: <자신의 계정명>
Password: <자신의 암호>

# myweb:v2.0.0 컨테이너 이미지 생성을 위한 Dockerfile 준비
# 실습을 위한 디렉터리 생성 및 이동
mkdir -p ~/myweb2 && cd ~/myweb2

# Dockerfile 파일 생성
vi Dockerfile
FROM ubuntu:20.04
ENV TZ=Asia/Seoul VERSION=2.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"]

vi Dockerfile
FROM ubuntu:20.04
ENV TZ=Asia/Seoul VERSION=2.0.0 NICK=gasida
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

 

루트 사용자(root) 권한으로 다음과 같은 명령어를 실행했습니다.

1. jenkins 사용자 확인:

- grep -i jenkins /etc/passwd

- 이 명령은 /etc/passwd 파일에서 "jenkins"라는 문자열을 대소문자 구분 없이 검색합니다.

- 출력 결과는 다음과 같이 나타납니다.  jenkins:x:995:991:Jenkins Automation Server:/var/lib/jenkins:/bin/false

- 이를 통해 시스템에 jenkins 사용자가 존재하며 홈 디렉터리가 /var/lib/jenkins이고 기본 쉘이 /bin/false임을 확인했습니다.

2. jenkins 사용자 쉘 변경:

- usermod -s /bin/bash jenkins

- 이 명령은 usermod 명령을 사용하여 jenkins 사용자의 기본 쉘을 /bin/bash로 변경합니다.

- /bin/false는 명령어 실행을 제한하는 쉘이므로 이를 일반적인 사용자 쉘인 /bin/bash로 변경했습니다.

3. 변경 확인:

- grep -i jenkins /etc/passwd

- 이 명령은 다시 한 번 /etc/passwd 파일을 검색하여 변경 사항을 확인합니다.

- 이제 출력 결과는 다음과 같이 나타납니다.

- jenkins:x:995:991:Jenkins Automation Server:/var/lib/jenkins:/bin/bash

- jenkins 사용자의 기본 쉘이 /bin/bash로 변경되었음을 확인했습니다.

4. jenkins 사용자 로그인:

- su - jenkins

- 이 명령은 su 명령을 사용하여 jenkins 사용자로 로그인합니다.

5. 로그인 확인 (jenkins 사용자 perspective):

- whoami

- 이 명령은 현재 로그인한 사용자 이름을 표시합니다.

- 출력 결과는 jenkins이어야 하며, 이는 성공적으로 jenkins 사용자로 로그인했음을 확인합니다.

- pwd

- 이 명령은 현재 위치한 디렉터리 경로를 표시합니다.

- 출력 결과는 /var/lib/jenkins이어야 하며, 이는 jenkins 사용자의 홈 디렉터리임을 확인합니다.

6. docker 정보 확인 (실패):

- docker info

- 이 명령은 Docker 데몬의 정보를 표시합니다.

- 하지만 이 경우에는 "permission denied"라는 오류 메시지가 발생했습니다.

 /var/run/docker.sock 파일에 대해 jenkins 사용자가 액세스할 수 있어야 합니다.  이를 설정하고 다시 shell에 접속하여 docker info를 실행하면 잘 실행될 것인데, 그 과정을 이제 진행합니다. 

 

7. Docker 소켓 권한 변경

- chmod 666 /var/run/docker.sock

- 주의 : 이 명령은 /var/run/docker.sock 파일의 권한을 모든 사용자에게 읽기, 쓰기 권한을 부여합니다. 이는 보안상 위험할 수 있으니 주의해야 합니다.

8. jenkins 사용자에게 docker 그룹 추가:

- usermod -aG docker jenkins

- 이 명령은 usermod 명령을 사용하여 jenkins 사용자를 docker 그룹에 추가합니다.

- 이를 통해 jenkins 사용자가 Docker 명령어를 실행할 수 있는 권한을 부여합니다.

9. jenkins 사용자로 재 로그인:

- su - jenkins

- 이 명령은 다시 한 번 jenkins 사용자로 로그인합니다.

10. Docker 정보 확인 (성공):

- docker info

- 이 명령은 이제 Docker 데몬의 정보를 성공적으로 표시합니다.

- 이는 jenkins 사용자가 이제 Docker 명령어를 실행할 수 있음을 의미합니다.

 

myweb:v2.0.0 컨테이너 이미지 생성을 위한  mkdir -p ~/myweb2 && cd ~/myweb2 디렉토리 생성 및 이동 후 Dockerfile 도커파일을 vi 명령을 사용해 생성해줍니다. 

 

새 도커 프로젝트 생성 

다시 Jenkins 대시보드 화면으로 돌아와줍니다. 그리고 New Item을 클릭하고 Docker-Project라는 이름과 Freestyle project를 선택하고 OK를 눌러줍니다. 

 

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

그 후 Configure를 선택하고, Build step을 눌러줍니다. Execute shell을 클릭하고 첫번째에는 위 커멘드를 넣어주고 

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

Add build Steps를 누른뒤 Execute shell을 한번 더 선택해주고 두번째 커멘드박스에는 위 커멘드를 넣어줍니다. 그리고 세이브 

빌드를 실행하고, Console Output을 확인하면 Docker build할때의 로그 그대로 나와줍니다. 

모니터링한다고 하나 더 만들어놓은 쉘에서 이미지가 첫번째 커멘드처럼 myweb:v2.0.0  태그를 기반으로 빌드되고,

두번째  커멘드처럼 80번 포트와  myweb:v2.0.0 이미지를 기반으로 실행된것을 확인할 수 있습니다. 

curl localhost

잘 실행되는 것도 확인했습니다. 


클린업

docker rm -f myweb
docker rmi myweb:v2.0.0

Github 저장소 연동 

https://github.com/gasida/aews-cicd 이 github 레포지토리를 일단 Fork해줍니다. 

Jenkins대시보드에 들어갑니다.

New Item을 클릭하고 Trigger-Project 이름으로 Freestyle project를 생성합니다.

This project is parameterized 옵션을 선택하고, Add parameter 버튼을 통해 파라미터를 추가할 수 있습니다. 

 

String parameter로 VERSION에 대해서는 v1.0.0 값을, NICK 이름에 대해서는 본인의 닉네임 값을 추가해줍니다.

 

좌측에서 Source Code Management를 선택해줍니다. 그리고 Git을 선택하여 아까 Fork한 저장소 URL을 지정해줍니다.

branch는 */main으로 (master -> main으로 변경) 설정

Additional Behaviours에서 Sparse Checkout paths를 추가, Path 값은 1로 설정해줍니다.

스크롤을 조금 더 내려서 Build Triggers에서 Poll SCM을 선택하고, Schedule에 "* * * * *" 값을 입력해줍니다.

cd /var/lib/jenkins/myweb2
rm -rf Dockerfile
wget https://raw.githubusercontent.com/$NICK/aews-cicd/main/1/Dockerfile
docker build -t myweb:$VERSION .
docker run -d -p 80:80 --rm --name myweb myweb:$VERSION

그리고 빌드 스탭에서 execute shell을 선택하고 이 두개의 커멘드를 추가해줍니다. 

그리고 SAVE


GitHub 저장소에서 1/Dockerfile 에 대해 버전 정보와 닉네임을 편집하여 커밋을 하고, Trigger를 발생시켜보겠습니다.

 

 

 

FROM ubuntu:20.04
ENV TZ=Asia/Seoul VERSION=1.3.0 NICK=gasida
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"]

기존 도커파일은 다음과 같은데 

 FROM ubuntu:20.04
ENV TZ=Asia/Seoul VERSION=1.1.1 NICK=crowssnest
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"]

다음과 같이 수정합니다. 

그리고 커밋해줍니다. 

 

잠시 후 jenkins 콘솔에서 확인하면 실패로 기록된것을 확인할 수 있습니다. 

빌드 환경 설정: 빌드는 /var/lib/jenkins/workspace/Trigger-Project 디렉터리에서 수행되고 있으며, 사용되는 git 버전은 2.40.1입니다.

Git 리포지토리 정보 설정: 빌드는 https://github.com/crowss-nest/aews-cicd.git Git 리포지토리에서 소스 코드를 가져옵니다.

소스 코드 가져오기: 빌드는 성공적으로 리포지토리에서 최신 커밋 (9ccd249f9c625c80665d4a29ba292a8f4b3d0fbb)을 가져옵니다.

Dockerfile 다운로드 실패: 빌드는 /var/lib/jenkins/myweb2 디렉터리에 있는 기존 Dockerfile을 삭제하고 https://raw.githubusercontent.com/crowssnest/aews-cicd/main/1/Dockerfile 에서 새로운 Dockerfile을 다운로드하려고 시도합니다.

 

빌드가 잘 되었습니다.

Execute shell을 다음과 같이 수정했습니다. 

Dockerfile 경로 오류

- 첫 번째 스크립트는 /var/lib/jenkins/myweb2 디렉토리로 이동하고 Dockerfile을 다운로드했습니다.

- 하지만 두 번째 스크립트는 /var/lib/jenkins/workspace/Trigger-Project 디렉토리에서 Dockerfile을 찾으려고 시도했습니다.

- 이는 두 스크립트 간에 경로 불일치가 발생하여 Dockerfile을 찾지 못하고 빌드가 실패했습니다.

 

수정된 스크립트 분석

이 수정을 통해 경로 불일치 해결: 첫 번째 스크립트와 두 번째 스크립트 모두 /var/lib/jenkins/myweb2 디렉토리를 사용하도록 변경되어 경로 불일치가 해결되었습니다.

잘 실행되는 것 확인했습니다. 


클린업

docker rm -f myweb
docker rmi myweb:v1.9.9
docker rmi myweb:v1.0.0

 


Jenkins pipeline

Jenkins 파이프라인: 심층 가이드

Jenkins 파이프라인은 지속적인 통합 및 배포(CI/CD) 프로세스를 자동화하고 관리하는 강력한 도구입니다. 코드 형태로 정의되는 파이프라인은 코드 리포지토리에 저장되어 버전 관리가 가능하며, 팀원들 간에 쉽게 공유하고 협업할 수 있습니다.

파이프라인의 장점

- 코드: 애플리케이션 CI/CD 프로세스를 코드 형식으로 작성하여 중앙 리포지토리에 저장할 수 있습니다. 이를 통해 버전 관리가 가능하고 팀원들 간에 쉽게 공유하고 협업할 수 있습니다.

- 내구성: Jenkins 서비스가 의도적으로 또는 우발적으로 재시작되더라도 파이프라인은 문제없이 유지됩니다.

- 일시 중지 가능: 파이프라인 실행 중 사람의 승인이나 입력을 기다리기 위해 중단하거나 기다리는 것이 가능합니다.

- 다양성: 분기, 반복, 병렬 처리 등 다양한 CI/CD 요구 사항을 지원합니다.

 

주요 용어

파이프라인: 전체 빌드 프로세스를 정의하는 코드입니다.

노드: 파이프라인을 실행하는 시스템입니다.

스테이지: 특정 단계에서 수행되는 작업들의 정의입니다.

스텝: 파이프라인의 특정 단계에서 수행되는 단일 작업을 의미합니다.

 

파이프라인 구성 방식

Jenkins 파이프라인은 다음과 같은 세 가지 방식으로 구성할 수 있습니다.

1. Pipeline Script:

- 일반적인 방식으로 Jenkins 파이프라인을 생성합니다.

- Shell Script를 직접 작성하여 빌드하는 방식입니다.

- 가장 유연하고 맞춤 설정 가능한 방식이지만, 코드 작성 및 관리가 복잡할 수 있습니다.

2. Classic UI를 통한 구성:

- Jenkins의 클래식 UI를 통해 기본적인 파이프라인을 직접 입력할 수 있습니다.

- 코드 작성 경험이 없는 사용자에게 적합하지만, 기능이 제한적이고 유지 관리가 어려울 수 있습니다.

3. SCM을 통한 Pipeline Script 구성:

- 사전 작성된 Jenkinsfile을 버전 관리 저장소에 보관하고, 빌드 시작 시 파이프라인 프로젝트에서 호출하여 실행하는 방식입니다.

- 코드 리포지토리에 파이프라인 정의를 저장하여 버전 관리 및 협업을 용이하게 합니다.

- 가장 권장되는 방식이며, 코드 작성 및 유지 관리가 비교적 용이합니다.

Jenkinsfile을 이용한 설정

Jenkinsfile은 파이프라인 정의를 코드 형태로 작성하는 데 사용되는 파일입니다. YAML 형식으로 작성되며, 파이프라인의 각 단계, 스테이지, 스텝을 정의합니다.

Jenkinsfile을 사용하면 다음과 같은 이점이 있습니다.

통합 및 배포 설정을 소스 코드에 포함: 소스 코드에 CI/CD 설정을 포함하면 문서화가 용이하고, 코드와 함께 버전 관리가 가능합니다.

팀원 간 협업: 코드 리포지토리에 저장된 Jenkinsfile은 팀원들 간에 쉽게 공유하고 협업할 수 있습니다.

재현성: Jenkinsfile을 사용하면 동일한 CI/CD 프로세스를 다른 환경에서도 쉽게 재현할 수 있습니다.

 

Blue Ocean 기반 설정

Blue Ocean은 Jenkins의 새로운 UI이며, 시각적으로 파이프라인을 구성하는 데 사용할 수 있습니다. Blue Ocean UI를 사용하면 다음과 같은 작업을 수행할 수 있습니다.

- 파이프라인의 각 단계 및 스테이지를 시각적으로 표시

- 파이프라인 실행 상태 및 이력 확인

- 파이프라인 문제점 진단 및 해결

- 파이프라인 성능 분석

Blue Ocean UI를 사용하면 코드 작성 경험이 없는 사용자도 쉽게 파이프라인을 구성하고 관리할 수 있습니다.

 

파이프라인 구문

Jenkins 파이프라인은 선언형 구문과 스크립트형 구문 두 가지 방식으로 작성할 수 있습니다.

1. 선언형 파이프라인 (권장)

선언형 파이프라인은 YAML 형식으로 작성되는 최신 파이프라인 구문입니다. 다음과 같은 특징을 가지고 있습니다.

- 간편한 작성: 명확하고 간결한 구문으로 쉽게 작성할 수 있습니다.

- 최신 문법: Jenkins에서 적극적으로 지원하는 최신 문법입니다.

- 단계 정의 필수: 각 단계를 명확하게 정의해야 하며, 단계 정의는 필수입니다.

- 시각화: Blue Ocean UI에서 시각적으로 표시되어 이해하기 쉽습니다.

pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                sh 'mvn clean install'
            }
        }
        stage('Test') {
            steps {
                sh 'mvn verify'
            }
        }
        stage('Deploy') {
            steps {
                sh 'scp target/my-app.war server:~/myapp.war'
                sh 'ssh server \'sudo systemctl restart myapp\''
            }
        }
    }
}

 

2. 스크립트형 파이프라인

스크립트형 파이프라인은 Groovy 기반 스크립트 형식으로 작성되는 기존 파이프라인 구문입니다. 다음과 같은 특징을 가지고 있습니다.

- 커스텀 작업 용이: 복잡한 커스텀 작업을 수행하는 데 유용합니다.

- 복잡도 높음: 선언형 파이프라인에 비해 코드 작성 및 이해가 어려울 수 있습니다.

- 단계 정의 선택 사항: 단계 정의는 필수가 아니지만, 명확하게 정의하는 것이 좋습니다.

- 시각화: Blue Ocean UI에서 시각적으로 표시되지만, 선언형 파이프라인만큼 명확하지 않을 수 있습니다.

node {
    stage('Build') {
        sh 'mvn clean install'
    }
    stage('Test') {
        sh 'mvn verify'
    }
    stage('Deploy') {
        sh 'scp target/my-app.war server:~/myapp.war'
        sh 'ssh server \'sudo systemctl restart myapp\''
    }
}

선택 가이드

- 새로운 프로젝트: 선언형 파이프라인 사용을 권장합니다.

- 기존 프로젝트: 이미 스크립트형 파이프라인을 사용하고 있다면, 선언형 파이프라인으로 점진적으로 전환하는 것을 고려해 볼 수 있습니다.

- 복잡한 커스텀 작업: 스크립트형 파이프라인이 더 적합할 수 있습니다.

 

Jenkins 파이프라인 활용 사례

Jenkins 파이프라인은 다양한 CI/CD 프로세스를 자동화하는 데 사용할 수 있습니다.

- 소스 코드 변경 시 자동 빌드 및 테스트: 소스 코드 변경 시 자동으로 빌드 및 테스트를 수행하여 빠른 피드백을 제공합니다.

- 지속적 배포: 테스트를 통과한 코드를 자동으로 배포 환경에 배포합니다.

- 인프라 자동화: 인프라 프로비저닝 및 구성 관리를 자동화합니다.

- 데이터 파이프라인: 데이터 수집, 처리, 분석, 저장 등의 데이터 파이프라인을 자동화합니다.

Jenkins 파이프라인은 팀의 효율성을 높이고 코드 품질을 개선하며, 빠른 배포 속도를 달성하는 데 도움이 됩니다.

 

추가 정보

- Jenkins 파이프라인 공식 문서: https://www.jenkins.io/doc/book/pipeline/syntax/

 

Pipeline Syntax

Jenkins – an open source automation server which enables developers around the world to reliably build, test, and deploy their software

www.jenkins.io


Jenkins Pipeline 실습

Jenkins 대시보드에 들어가서 새로운 Item을 클릭합니다.

Name: First-Pipeline을 넣어주고 이번에는 pipeline을 클릭하여 OK 해줍니다. 

pipeline {
    agent any

    stages {
        stage('정보 확인') {
            steps {
                echo 'Hello World'
                sh 'java -version'
            }
        }
        stage('가라 배포') {
            steps {
                echo "Deployed successfully!";
            }
        }
    }
}

파이프라인 Script에는 위 내용을 넣어줍니다.

그리고 ConsoleOutput을 확인해보면 다음과 같습니다. 

 

다시 파이프라인에서 configure를 누르고, pipeline script를 넣었던 곳에서 다른 내용을 넣어줍니다. 

pipeline {
    agent any
    environment { 
        STUDYNAME = 'AEWS'
    }
    stages {
        stage('연습') {
            environment { 
                mykey = 'abcd'
            }
            steps {
                echo "${STUDYNAME}";
                sh 'echo ${mykey}'
            }
        }
    }

 

위에서 환경변수를 선언해주면 밑에서 참조가 가능한지 봅니다.

빌드 실행 후 Echo로 환경변수로 넣었던 AEWS가 잘 나와주는것 확인했습니다. environment로 넣었던 환경변수가 참조가 된다는거네요 

다시 Jenkins 대시보드로 돌아와서 Jenkins관리를 클릭하고, Tools를 클릭해줍니다.

위의 Gradle Ant Maven 등등에 대해서 path가 선언이 된게 Tools라고 생각하면 됩니다. 

이번에는 Maven에 대해서 해보겠습니다. 

pipeline {
    agent any
    tools {
        maven 'maven_3.8.7' 
    }
    stages {
        stage('Example') {
            steps {
                sh 'mvn --version'
            }
        }
    }
}

 

Tools에서 선언된 이름이 Manage Jenkins -> Tools에서  설정된 이름과 동일해야 합니다. 

위와같이 설정하고, 스크립트를 넣어줍니다. 

그리고 빌드를 하고 결과 output을 확인하면 다음과 같습니다. 

maven 3.8.7버전을 잘 가져와서 mvn --version에서 출력해준 것을 확인 가능합니다. 

 

Jenkins의 pipeline Syntax를 사용하고 Sample step에서 sh: Shell Script를 선택 한 뒤 그냥 명령어를 넣으면, Generate pipeline script를 클릭하면, 사용할 수 있는 형태로 변환해줍니다.


Jenkins with Kubernetes

Jenkins가 설치되어있는 bastion 인스턴스 환경에서 사전 준비를 해줍니다. 

# jenkins 사용자에서 아래 작업 진행
whoami
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

이렇게 kubectl 명령이 가능하도록 설정해놓습니다. 

이렇게되면 jenkins유저가 쿠버를 사용할 준비가 되어있다는겁니다. 

 

github에서 포크한 디렉토리에서 3 - Deploy - deployment-svc.yaml에서 containers에서 image에 제 도커허브 계정이름을 Myweb앞에 넣어줍니다. 

 

도커허브에 올라와있는 위 이미지 입니다. 

K8s-1라는 이름으로 pipeline을 선택하고 OK를 눌러줍니다. 

 

pipeline {
    agent any

    tools {
        jdk 'jdk-17'
    }

    environment {
        DOCKERHUB_USERNAME = 'gasida'
        GITHUB_URL = 'https://github.com/gasida/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"
            }
        }
    }
}

파이프라인 스크립트에 위 내용을 넣어줍니다. 

    environment {
        DOCKERHUB_USERNAME = 'crowssnest'
        GITHUB_URL = 'https://github.com/crowss-nest/aews-cicd.git'
        // deployment-svc.yaml -> image: gasida/myweb:v1.0.0        
        DIR_NUM = '3'
    }

주의할점은 위 부분에 본인의 정보로 바꿔줘야합니다. 

파이프라인을 실행해보겠습니다. 

지금 빌드를 클릭하여 build를 실행하면 오른쪽에 pipeline이 생성되며 실시간으로 build/deploy 진행 상황을 확인할 수 있습니다.

 jenkins 사용자 shell에서 kubectl gete pods 명령으로 해당 파드 배포 확인가능합니다. 

 

 

watch -d kubectl get pod,svc,ep

모니터링을 위해 터미널을 하나 할당해줍니다. 

 

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

접속용 파드 생성합니다. 생성 후 Pod/netpod 확인가능합니다. 

#
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

# 작업공간 확인
tree /var/lib/jenkins/workspace/k8s-1
cat /var/lib/jenkins/workspace/k8s-1/Dockerfile

이렇게 확인 가능합니다. 

 

클린업 

kubectl delete deploy,svc myweb

Argo CD

Gemini한테 ArgoCD가 뭔지 물어봤어요~

Argo CD란 무엇인가요?

Argo CD는 Kubernetes를 위한 선언적 GitOps 지속적 제공(CD) 도구입니다.

쉽게 말해, Argo CD는 Git 리포지토리에 정의된 원하는 애플리케이션 상태를 자동으로 Kubernetes 클러스터에서 구현해주는 도구라고 생각하면 됩니다.

즉, 개발자는 Git 리포지토리에 애플리케이션 정의, 구성 및 환경을 코드로 작성하고, Argo CD가 이 코드를 기반으로 실제 Kubernetes 클러스터에서 원하는 상태를 유지하도록 합니다.

 

Argo CD를 사용하면 다음과 같은 이점을 얻을 수 있습니다.

- 자동화된 배포: 수동 작업 없이 애플리케이션을 Kubernetes 클러스터에 배포하고 업데이트할 수 있습니다.

- 선언적 관리: Git 리포지토리에 원하는 애플리케이션 상태를 정의하면 Argo CD가 그 상태를 유지하도록 합니다.

- 지속적 동기화: 클러스터 상태가 Git 리포지토리에 정의된 상태와 일치하는지 지속적으로 확인하고 필요에 따라 동기화합니다.

- 보안 강화: Git 리포지토리 기반 코드 검토 및 승인 프로세스를 통해 배포 프로세스를 보안 강화할 수 있습니다.

- 롤백 및 재현 가능성: 이전 버전으로 롤백하거나 동일한 환경을 다른 클러스터에 재현할 수 있습니다.

 

Argo CD 작동 방식

Argo CD는 다음과 같은 주요 구성 요소로 작동합니다.

- Git 리포지토리: 애플리케이션 정의, 구성 및 환경을 포함하는 Git 리포지토리입니다.

- Argo CD 서버: Git 리포지토리를 모니터링하고 Kubernetes 클러스터와 동기화하는 서버입니다.

- Kubernetes 클러스터: 애플리케이션이 실행되는 Kubernetes 클러스터입니다.

Argo CD 서버는 Git 리포지토리를 지속적으로 모니터링하고 리포지토리에 변경 사항이 감지되면 Kubernetes 클러스터에서 원하는 상태를 반영하도록 작업을 수행합니다.

예를 들어, Git 리포지토리에 새로운 애플리케이션 정의가 추가되면 Argo CD 서버는 Kubernetes 클러스터에 해당 애플리케이션을 배포합니다.

또한, Git 리포지토리에서 애플리케이션 구성이 변경되면 Argo CD 서버는 Kubernetes 클러스터에서 해당 구성을 업데이트합니다.

 

Argo CD 주요 기능

Argo CD는 다음과 같은 다양한 기능을 제공합니다.

- 다양한 애플리케이션 유형 지원: Helm 차트, Kustomization YAML, Manifests 등 다양한 유형의 애플리케이션을 지원합니다.

- 애플리케이션 그룹 관리: 여러 애플리케이션을 그룹화하여 함께 배포하고 관리할 수 있습니다.

- 환경별 배포: 개발, 테스트, 프로덕션 등 여러 환경에 애플리케이션을 배포할 수 있습니다.

- 롤백 및 재현 가능성: 이전 버전으로 롤백하거나 동일한 환경을 다른 클러스터에 재현할 수 있습니다.

- 클러스터 액세스 제어: RBAC(Role-Based Access Control)을 사용하여 Argo CD 서버에 대한 액세스를 제어할 수 있습니다.

- 웹 콘솔 및 API: Argo CD는 웹 콘솔과 API를 통해 사용할 수 있습니다.

 

Argo CD 사용 사례

Argo CD는 다양한 사용 사례에 활용될 수 있습니다.

- 웹 애플리케이션 배포: 웹 애플리케이션 코드, 구성 및 환경을 Git 리포지토리에 저장하고 Argo CD를 사용하여 Kubernetes 클러스터에 자동으로 배포하고 관리할 수 있습니다.

- 마이크로서비스 배포: 마이크로서비스 아키텍처를 기반으로 구축된 애플리케이션을 Argo CD를 사용하여 Kubernetes 클러스터에 배포하고 관리할 수 있습니다.

- 데이터베이스 배포: 데이터베이스 이미지, 구성 및 환경을 Git 리포지토리에 저장하고 Argo CD를 사용하여 Kubernetes 클러스터에 자동으로 배포


Argo CD 설치 

# 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

# 최초 접속 암호 확인
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d ;echo

helm을 사용해서 Argo CD를 설치해줍니다 .

대시보드 화면에 들어오면 이렇습니다.

 

(june@onthelook:default) [root@myeks-bastion ~]# kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d ;echo

위 명령으로 나온 비밀번호로 로그인 합니다. 아이디는 admin입니다. 

- Application Name : first-myweb
- Project Name : default
- SYNC POLICY : Manual
    - AUTO-CREATE NAMESPACE : 클러스터에 네임스페이스가 없을 시 argocd에 입력한 이름으로 자동 생성
    - APPLY OUT OF SYNC ONLY : 현재 동기화 상태가 아닌 리소스만 배포
- PRUNE PROPAGATION POLICY
    - foreground : 부모(소유자, ex. deployment) 자원을 먼저 삭제함
    - background  : 자식(종속자, ex. pod) 자원을 먼저 삭제함
    - orphan  : 고아(소유자는 삭제됐지만, 종속자가 삭제되지 않은 경우) 자원을 삭제함
- AUTO-CREATE-NAMESPACE
- SOURCE
    - Repository URL : https://github.com/crowss-nest/aews-cicd.git
    - Revision : main
    - Path : 3/deploy
- DESTINATION
    - Cluster URL : https://kubernetes.default.svc
    - Namespace : first

중앙의 create application을 클릭해서 위 정보로 create를 눌러 생성합니다.

 

 

현재는 outofsync상태입니다. 

모든 리소스를 알아서 파악해서 디스플레이 해줍니다. 

 

Sync를 누르고 Synchronize를 눌러서 배포해줍니다. 

watch -d kubectl get deploy -n first --show-labels

위 명령어로 watch를 걸어서 변화를 감지합니다. 

기존에는 없는 네임스페이스이기 때문에 아무것도 감지가 안되다가 

 

싱크를 누르니 새로운 리소스들이 보이고

새로운 파드 네개가 생성된것을 확인할 수 있습니다. 

 

깃헙에서 4개였던 레플리카의 갯수를 두개로 변경해보겠습니다.

아직 변화가 없습니다. 

3분에 한번씩 변화를 체크하는데, 지금은 그 주기가 되지 않아서 그렇습니다. refresh를 통해서 즉시 반영 가능합니다 .

refresh 후 변경사항 즉시 확인 가능하고 싱크를 누르시면 

파드의 갯수도 즉시 두개로 변경되는것 확인 가능합니다.


ArgoCD CLI

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

아르고 CD를 설치해줍니다. 

 

argocd version

설치 확인합니다. 

 

argocd login argocd.$MyDomain

 

위 명령 후 Username과 Password으로 로그인합니다

 

kubectl config get-contexts -o name

위의 명령어를 입력해 cluster의 name을 출력합니다.

 

kubectl config get-contexts -o name
admin@myeks.ap-northeast-2.eksctl.io
argocd cluster add admin@myeks.ap-northeast-2.eksctl.io

이 명령은 Argo CD가 지정한 Kubernetes 클러스터를 관리할 수 있도록 설정하는 과정을 포함합니다. 

1. ServiceAccount "argocd-manager" 생성: Kubernetes에서는 ServiceAccount를 사용하여 파드(Pod)가 Kubernetes API에 접근할 때 사용하는 계정입니다. 여기서 "argocd-manager"라는 이름의 ServiceAccount가 "kube-system" 네임스페이스 안에 생성되었습니다. 이 계정을 통해 Argo CD가 클러스터를 관리할 수 있습니다.

2. ClusterRole "argocd-manager-role" 생성: ClusterRole은 클러스터 전체에 적용되는 권한을 정의합니다. "argocd-manager-role"이라는 Role을 생성함으로써, ServiceAccount가 클러스터의 자원에 접근할 수 있는 권한을 부여받게 됩니다.

3. ClusterRoleBinding "argocd-manager-role-binding" 생성: ClusterRoleBinding은 특정 ClusterRole을 하나 이상의 사용자(여기서는 ServiceAccount)에게 연결합니다. 이 설정을 통해 "argocd-manager" ServiceAccount가 "argocd-manager-role"이라는 ClusterRole에 정의된 권한을 사용할 수 있게 됩니다.

4. Bearer Token Secret 생성: Kubernetes에서는 API에 접근할 때 사용할 수 있는 토큰을 포함한 Secret을 생성합니다. "argocd-manager" ServiceAccount를 위한 Bearer Token이 생성되어 API 인증에 사용될 수 있습니다.

5. 클러스터 추가 완료: Argo CD가 클러스터를 관리할 준비가 완료되었으며, 설정된 ServiceAccount를 통해 클러스터 리소스에 접근할 수 있습니다.


Application 생성 with CLi

kubectl config set-context --current --namespace=argocd

 argocd cluster로 변경합니다.

argocd app create guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --dest-server https://kubernetes.default.svc --dest-namespace default

Application을 추가합니다.

 

아르고cd 콘솔에서 확인해보면 새로운 application이 생성된것 확인 가능합니다. 

argocd app list

cli로도 간편하게 확인 가능합니다.

argocd app get guestbook

해당 application에 대해 상세정보 확인도 가능합니다.

 

argocd app sync guestbook

위 명령으로 싱크를 시켜줍니다.

콘솔에서 확인해보면 파드 생성된것 확인 가능합니다. 

클린업

argocd app delete guestbook

콘솔에서 확인하면 모두 클린업 되어있습니다. 


Argo Rollouts

Argo Rollouts는 컨트롤러와 커스텀 리소스 정의(CRD)로 구성된 Kubernetes 도구입니다. 좀 더 발전된 배포 기능을 제공하여 Kubernetes에서 애플리케이션을 보다 안전하고 쉽게 관리할 수 있도록 해줍니다.

핵심 기능

- 블루-그린 및 카나리 배포: 기존 버전과 새로운 버전을 동시에 실행하여 변경 사항의 영향을 확인하고 문제 발생 시 쉽게 롤백할 수 있습니다.

- 단계별 트래픽 전환: 사용자 정의 속도와 정책에 따라 새로운 버전으로의 트래픽 전환 속도를 조절할 수 있습니다.

 

 

- 자동화된 롤백 및 프로모션: 문제 발생 시 자동으로 롤백하거나 새로운 버전으로 자동 승격 전환합니다.

- 외부 메트릭 조회 및 분석: 다양한 제공자의 메트릭 정보를 확인하여 핵심 성능 지표(KPI)를 기반으로 자동 프로모션이나 롤백을 실행할 수 있습니다.

- 통합 지원: 인그레스 컨트롤러와 서비스 메쉬와 통합되어 트래픽 흐름을 정밀하게 제어할 수 있습니다.

Argo Rollouts의 장점:

- 배포 위험 감소: 새로운 버전으로 인한 문제를 줄이고 안전하게 배포할 수 있도록 합니다.

- 다운타임 최소화: 기존 버전을 유지하면서 새로운 버전을 배포하여 서비스 가동 시간을 유지할 수 있습니다.

- 배포 자동화: CI/CD 파이프라인에 통합하여 수동 작업을 줄이고 효율성을 높일 수 있습니다.

- 보안 강화: 악의적인 이미지 배포로부터 애플리케이션을 보호합니다.

- 사용 편의성: 초보자도 쉽게 사용할 수 있도록 설계되었습니다.

 

Argo Rollouts 사용법:

1. Argo Rollouts 설치: Helm 또는 kubectl을 사용하여 Kubernetes 클러스터에 Argo Rollouts를 설치합니다.

2. 매니페스트 정의: YAML 매니페스트를 사용하여 배포하려는 애플리케이션과 배포 전략을 정의합니다.

3. 배포 적용: Argo Rollouts CLI 또는 사용자 인터페이스를 사용하여 매니페스트를 적용하고 배포를 시작합니다.

4. 모니터링 및 관리: Argo Rollouts는 배포 진행 상황을 보여주고 필요한 경우 수동으로 개입할 수 있도록 도구를 제공합니다.

 

Argo Rollouts의 아키텍처

Argo Rollouts는 다음과 같은 핵심 구성 요소로 이루어져 있습니다.

- Argo Rollouts 컨트롤러: 배포 프로세스를 자동으로 제어하는 중앙 구성 요소입니다.

- Rollout 리소스: 배포 설정을 정의하는 YAML 파일입니다.

- 레플리카 세트: 이전 버전과 새로운 버전의 애플리케이션을 실행하는 데 사용되는 Kubernetes 객체입니다.

- 인그레스/서비스: 애플리케이션에 대한 트래픽을 라우팅하는 Kubernetes 객체입니다.

- 분석 템플릿 및 분석 실행: 롤백이나 프로모션 결정을 위한 기준을 설정하는 리소스입니다.

- 메트릭 제공자: Prometheus, Datadog 등 외부 시스템에서 메트릭 정보를 가져오는 역할을 합니다.

- 명령줄 인터페이스(CLI) 및 사용자 인터페이스(UI): Argo Rollouts를 사용하기 위한 도구입니다.


Rollouts 배포 전략

Argo Rollouts의 대표적인 배포 전략에는 Blue/Green, Canary의 두가지 배포 방식이 있습니다.

Blue/Green

블루그린 배포

블루그린 배포는 **기존 버전(Blue)과 새로운 버전(Green)**을 동시에 실행하면서 새로운 버전의 안정성을 검증하고 필요하면 쉽게 롤백할 수 있는 전략입니다. 마치 두 개의 환경을 번갈아 사용하는 것처럼 작동한다고 생각하면 됩니다.

블루그린 배포의 장점:

- 높은 안전성: 문제 발생 시 롤백이 용이하여 서비스 가동 시간을 유지할 수 있습니다.

- 변경 사항 테스트 용이: 새로운 버전을 별도의 환경에서 테스트하여 실제 배포 전에 문제를 파악할 수 있습니다.

- 단계별 배포: 트래픽을 점진적으로 새로운 버전으로 전환하여 시스템에 가해지는 영향을 최소화할 수 있습니다.

블루그린 배포의 단점:

- 더 복잡한 환경: 기존 버전과 새로운 버전을 모두 관리해야 하기 때문에 복잡성이 높아집니다.

- 더 많은 리소스 필요: 두 개의 별도 환경을 운영하기 때문에 리소스 소비가 증가합니다.

카나리 배포 

카나리 배포

카나리 배포는 새로운 버전을 일부 사용자에게만 배포하여 실제 사용 환경에서 테스트하고 문제가 없는지 확인한 후 전체 사용자에게 배포하는 전략입니다. 마치 새롭게 발견한 땅을 탐험하는 카나리아 새를 보내는 것처럼 조심스럽게 새로운 버전을 도입한다고 생각하면 됩니다.

카나리 배포의 장점:

- 낮은 위험: 일부 사용자에게만 영향을 미치기 때문에 문제 발생 시 피해 범위를 제한할 수 있습니다.

- 빠른 피드백: 실제 사용자로부터 빠르게 피드백을 수집하여 문제를 신속하게 해결할 수 있습니다.

- 지속적인 배포: 새로운 버전을 지속적으로 배포하고 개선할 수 있습니다.

카나리 배포의 단점:

- 더 복잡한 설정: 카나리 배포를 위한 트래픽 분할 및 모니터링 시스템이 필요합니다.

- 테스트 시간 지연: 전체 사용자에게 배포하기 전에 테스트 시간이 더 걸릴 수 있습니다.

 

블루그린 배포 vs 카나리 배포:

선택 기준:

- 새로운 버전의 안정성에 대한 확신도가 높다면: 블루그린 배포

- 새로운 버전의 안정성에 대한 확신도가 낮거나 빠른 피드백이 필요하다면: 카나리 배포

- 두 전략의 장점을 결합하여 사용하는 경우도 있습니다.

Argo Rollouts는 블루그린 및 카나리 배포를 포함한 다양한 배포 전략을 지원하며, 사용자 정의 속도, 트래픽 전환, 롤백 정책 등을 설정하여 보다 안전하고 효율적인 애플리케이션 배포를 가능하게 합니다.

 

ArgoRollouts 설치

namespace 생성

kubectl create ns argo-rollouts

 

argo-rollouts 네임스페이스를 생성해줍니다. 

 

#
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

argorollout 생성 후 확인 합니다.

 

aws ec2 로드밸런서 콘솔에서 확인하면, 프로비저닝중인 argorollout 로드밸런서 확인이 가능합니다. 

 

 

https://argorollouts.<자신의 도메인>/rollouts/

다음과 같은 패턴으로 들어갈 수 있습니다. 

지금은 아무 리소스도 없으니 당연히 이렇습니다. 

ArgoRollouts cli 설치 

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

cli도 지원하니 cli설치도 해줍니다. 

 

kubectl argo rollouts version

설치 후 확인은 위 명령어로 합니다.

설치 잘 되네요 

 

ArgoRollouts 배포 실습 

canary 

spec:
  replicas: 5
  strategy:
    canary:
      steps:
      - setWeight: 20
      - pause: {}
      - setWeight: 40
      - pause: {duration: 10}
      - setWeight: 60
      - pause: {duration: 10}
      - setWeight: 80
      - pause: {duration: 10}

신규버전 20퍼 - 잠시멈춤 - 신규버전 40퍼 - 잠시멈춤 - 신규버전 60퍼 -잠시멈춤 - 신규버전 80퍼 까지 하는 시나리오 입니다.  

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

파드가 바로 생겨주는 것 확인가능합니다. 

 

kubectl argo rollouts get rollout rollouts-demo

cli에서 해당 rollouts 확인 가능합니다 .

argo rollouts 도메인에서도 namespace default 전환 후 확인 가능합니다. 

클릭하면 자세한 진행상황 확인이 가능합니다. 

 

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

위 명령으로 새로운 이미지 셋팅을  합니다. 

신규이미지 revision 2가 생겼습니다.  현재는 revision 2가 20퍼센트 받아들인 상황이고,  revision 1은 80퍼센트를 받아들입니다. 

현재 첫번째 step에선 pause 상태의 시간을 정해두지 않아서 멈춰있습니다. 

그 다음 버전으로 가도 된다고 한다면 위의 promote를 클릭하면 그 다음 스탭으로 진행합니다. Revision 2는 40퍼센트 Revision 1은 60퍼센트를 받아들입니다. 

\

그대로 놔두면 Revision2로 모든 가중치가 옮겨갑니다. 

JUNE .

20'S LIFE IN SYDNEY and BUSAN

    이미지 맵

    DevOps Study/AWS 다른 글

    이전 글

    다음 글