주니어 개발자 1호

[Chapter 5]쿠버네티스 스터디 4주차 - ( CD - 지속적배포 ) 본문

Server 관련

[Chapter 5]쿠버네티스 스터디 4주차 - ( CD - 지속적배포 )

No_1 2022. 7. 22. 22:15

지속적 배포란?

continuous delivery ( cd ) , 즉 공유 저장소에서 통합하는 개발자가 가장 많이 사용하는 자동화 서버 해당 챕터에서는 Jenkins을 사용하여 파이프라인 설정

Jenkins는 빌드, 테스트, 배포 파이브라인을 유연하게 조정할 수 있는 오픈소스 자동화 서버 Kubernetes Engine은 컨테이너를 위한 강력한 클러스터 관리자 및 조정 시스템인 Kubernetes의 호스팅 버전입니다.

이점:

  • 빌드 프로세스에서 컨테이너를 사용하는 경우 하나의 가상 호스트로 여러 운영체제에서 작업이 가능합니다.
  • Kubernetes Engine은 임시 빌드 실행자를 제공하여 각 빌드가 이전 빌드와 동일한 정리된 환경에서 실행되도록 합니다.
    • 빌드 실행자가 갖는 임시적 성격으로 인해 Kubernetes Engine 클러스터는 빌드가 활발하게 실행될 때만 사용되므로 일괄 처리 작업과 같은 다른 클러스터 작업에 그대로 리소스를 사용할 수 있습니다.
    • 빌드 실행자가 몇 초 안에 시작됩니다.
  • Kubernetes Engine은 Google 글로벌 부하 분산기를 활용하여 웹 트래픽을 사용자의 인스턴스로 라우팅합니다. 부하 분산기는 SSL 종료를 처리하고, Google 백본 네트워크를 통해 사용자의 현재 위치에서 가장 가까운 지점으로부터 가장 빠른 경로를 활용하여 사용자를 웹 프런트엔드로 라우팅하는 글로벌 IP 주소를 제공합니다.

Kubernetes Engine이란?

Kubernetes Engine은 컨테이너를 위한 강력한 클러스터 관리자 및 조정 시스템인 Kubernetes 의 Google Cloud 호스팅 버전입니다. Kubernetes는 노트북에서 고가용성 멀티노드 클러스터, 가상 머신에서 베어 메탈까지 다양한 환경에서 실행할 수 있는 오픈소스 프로젝트입니다. 앞서 언급했듯이 Kubernetes 앱은 컨테이너 로 구축되며 실행을 위해 필요한 모든 종속성과 라이브러리와 함께 번들로 제공되는 경량 애플리케이션입니다. 이러한 기본 구조 덕분에 Kubernetes 애플리케이션은 고가용성과 안정성을 갖추고 빠른 배포가 가능하여 클라우드 개발자에게 이상적인 프레임워크라고 할 수 있습니다.

Jenkins 주의 사항

Jenkins를 설치핧 때 값 파일을 템플릿으로 사용하여 설정에 필요한 값을 제공할 수 있습니다. 사용자 지정 값 파일을 사용하여 Kubernetes 클라우드를 자동으로 구성하고 다음 필수 플러그인을 설치, 추가합니다.

  • Kubernetes:1.29.4
  • Workflow-multibranch:latest
  • Git:4.7.1
  • Configuration-as-code:1.51
  • Google-oauth-plugin:latest
  • Google-source-plugin:latest
  • Google-storage-plugin:lates

Helm이란?

Helm이란 Kubernetes 패키지 관리를 도와주는 패키지매니저, yaml 파일의 모음 yaml은 chart라고 한다.

장점

  1. 복잡성 관리
  2. 쉬운 업데이트
  3. 간단한 공유
  4. 롤백

실습할 내용

  1. Jenkins 애플리케이션을 Kubernetes Engine 클러스터에 프로비저닝하기
  2. Helm Package Manager 를사용하여 Jenkins 애플리케이션 설정하기
  3. Jenkins 애플리케이션의 기능 살펴보기
  4. Jenkins 파이프라인 생성 및 실습

도움을 주는 요소

코드

저장소 복제

# 지역 설정
gcloud config set compute/zone us-east1-d

# 코드 복제
gsutil cp gs://spls/gsp051/continuous-deployment-on-kubernetes.zip .

# zip 압축풀기
unzip continuous-deployment-on-kubernetes.zip

# 디렉토리 진입
cd continuous-deployment-on-kubernetes

Jenkins 프로비저닝하기

# 클러스터 생성
gcloud container clusters create jenkins-cd \\
--num-nodes 2 \\
--machine-type n1-standard-2 \\
--scopes "<https://www.googleapis.com/auth/source.read_write,cloud-platform>"

# 클러스터 확인
gcloud container clusters list

# 클러스터의 사용자 인증 정보 가져오기
gcloud container clusters get-credentials jenkins-cd

# Kubernets Engine은 이 사용자 인증 정보를 사용하여, 새로 프로비저닝된 클러스터에
# 엑세스 합니다. 연결할 수 있는지 확인
kubectl cluster-info

Helm 설정

# Helm의 안정적인 차트(yaml)저장소 추가
helm repo add jenkins <https://charts.jenkins.io>

# 저장소 최신 상태 확인
helm repo update

# 결과 값
...Successfully got an update from the "jenkins" chart repository
Update Complete. ⎈Happy Helming!⎈

Jenkins 구성 및 설치

# 사용자 정의 값 파일 다운로드
gsutil cp gs://spls/gsp330/values.yaml jenkins/values.yaml

# Helm CLI를 사용하여 구성 설정으로 차트를 배포
# 디렉토리 진입 -> jenkins/value.yaml 이 진행명령어
helm install cd jenkins/jenkins -f jenkins/values.yaml --wait

# 이때 아래 명령어를 통해 password get
kubectl exec --namespace default -it svc/cd-jenkins -c jenkins -- /bin/cat /run/secrets/additional/chart-admin-password && echo

# port forwarding 이후 site config 
kubectl port-forward svc/jenkins 8080:8080

# pods 확인
kubectl get pods

# 클러스터에 전개할 수 있도록 Jenkins 서비스 계정 구성
kubectl create clusterrolebinding jenkins-deploy --clusterrole=cluster-admin --serviceaccount=default:cd-jenkins

# 출력 수신
clusterrolebinding.rbac.authorization.k8s.io/jenkins-deploy created

# Jenkins UI 포트 전달
export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/component=jenkins-master" -l "app.kubernetes.io/instance=cd" -o jsonpath="{.items[0].metadata.name}")
kubectl port-forward $POD_NAME 8080:8080 >> /dev/null &

# Jenkins 구성 확인
kubectl get svc

# 결과
NAME               CLUSTER-IP     EXTERNAL-IP   PORT(S)     AGE
cd-jenkins         10.35.249.67   <none>        8080/TCP    3h
cd-jenkins-agent   10.35.248.1    <none>        50000/TCP   3h
kubernetes         10.35.240.1    <none>        443/TCP     9h

Jenkins 에 연결하기

# Jenkins 차트는 자동으로 관리자 비밀번호를 만듭니다. 이를 검색하려면 아래 명령어 실행
printf $(kubectl get secret cd-jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo

# terminal 우측 상단에 preview on port:8080 을 클릭하여 preview
# 이후 admin , 획득한 password를 통해 로그인 가능

현재 애플리케이셔의 이해

  • 백엔드: port 8080을 수신대기 ec2에서 메타데이터를 json형식으로 반환
  • 프론트엔드: 서비스를 쿼리하고 결과 json을 사용자 인터페이스에 렌더링

애플리케이션 배포

2개의 다른 환경에서 배포를 실시함

  • 프로덕션: 사용자가 액세스 하는 실제사이트
  • 카나리아: 사용자 트래픽 중 일정 비율을 수용하는 소규모 사이트 ( 테스트용도의 )
# 디렉토리 이동
cd sample-app

# 네임 스페이스 생성, 배포를 논리적으로 격리
kubectl create ns production

# 프로덕션 배포 생성
kubectl apply -f k8s/production -n production

# 카나리 배포 생성
kubectl apply -f k8s/canary -n production

# 서비스 생성
kubectl apply -f k8s/services -n production

# scale 확장 4개의 복제본이 항상 실행되게 replica 4 세팅
kubectl scale deployment gceme-frontend-production -n production --replicas 4

# 프론트 5개의 포드, 프로덕션 4개의 포드, 카나리아 릴리스 1개 포드 실행확인
kubectl get pods -n production -l app=gceme -l role=frontend

# 백엔드 2개의 포드, 프로덕션 1 , 카나리아 1 확인
kubectl get pods -n production -l app=gceme -l role=backend

# 외부 서비스 ip 검색
kubectl get service gceme-frontend -n production

# external-ip 확인
NAME            TYPE          CLUSTER-IP     EXTERNAL-IP     PORT(S)  AGE
gceme-frontend  LoadBalancer  10.79.241.131  104.196.110.46  80/TCP   5h

# 프론트엔드 서비스 부하 분산기 IP를 환경변수 FRONTENT_SERVICE_IP 에 저장
export FRONTEND_SERVICE_IP=$(kubectl get -o jsonpath="{.status.loadBalancer.ingress[0].ip}" --namespace=production services gceme-frontend)

# 버전 확인 - 결과 1.0.0
curl http://$FRONTEND_SERVICE_IP/version

Jenkins 파이프라인 만들기

# 샘플 앱 소스코드 호스팅 장소 만들기
gcloud source repos create default

# git 설치
git init

# 디렉토리 초기화
git config credential.helper gcloud.sh

# git remote 추가
git remote add origin <https://source.developers.google.com/p/$DEVSHELL_PROJECT_ID/r/default>

# git config 설정
git config --global user.email "[EMAIL_ADDRESS]"
git config --global user.name "[USERNAME]"

# git add 
git add .

# git commit 
git commit -m "Initial commit"

# git push 
git push origin master

이후 Jenkins 사용자 인증 정보를 추가한다.

 

Jenkins 작업 구성

 

개발 환경 만들기

  1. 개발 브랜치 생성
git checkout -b new-feature

# 터미널 편집기에서 Jenkinsfile을 엽니다.
vi Jenkinsfile

# 편집 
#-> 입력 
i
---- 
PROJECT = "REPLACE_WITH_YOUR_PROJECT_ID"
APP_NAME = "gceme"
FE_SVC_NAME = "${APP_NAME}-frontend"
CLUSTER = "jenkins-cd"
CLUSTER_ZONE = "us-east1-d"
IMAGE_TAG = "gcr.io/${PROJECT}/${APP_NAME}:${env.BRANCH_NAME}.${env.BUILD_NUMBER}"
JENKINS_CRED = "${PROJECT}"
---

# 저장 후 종료
:wq

사이트 수정하기

# html.go 파일 열어서 수정
vi html.go

# 입력
i

#  blue  ->  orange로 변경
# 이전 <div class="card blue">
<div class="card orange">

# 저장 후 종료
:wq

# main.go 수정 
vi main.go

# 입력
i

# version 수정
# 변경 전 const version string = "1.0.0"

const version string = "2.0.0"

# 저장 후 종료
:wq

파이프라인 정의 수정 하기

이 파이프라인을 정의하는 Jenkinsfile은 Jenkins Pipeline Groovy 구문으로 작성됩니다. Jenkinsfile을 사용하면 빌드 파이프라인 전체에 걸쳐 소스 코드와 함께 사용되는 단일 파일로 표현할 수 있습니다. 파이프라인은 병렬화와 같은 강력한 기능을 지원하며 사용자의 직접 승인을 요청합니다.

배포 시작

# 변경 사항 커밋 후 푸쉬
git add Jenkinsfile html.go main.go
git commit -m "Version 2.0.0"
git push origin new-feature

이후 개발 환경 빌드가 시작됩니다. Jenkins 사용자 인터페이스로 이동하여 new-feature 브랜치의 빌드가 시작되었는지 확인을 합니다.

빌드가 실행되었으면 사이드바에서 콘솔 결과를 확인합니다.

몇 분 동안 빌드 결과를 추적하면서 kubectl --namespace=new-feature apply...  메시지가 시작되는지 지켜봅니다. new-feature 브랜치가 이제 클러스터에 배포됩니다.

카나리아 릴리스 배포

# 브랜치 생성 후 푸시
git checkout -b canary
git push origin canary

# 5개 요청중 하나는 버전 2.0.0이 반환되어야 합니다 ( 5개 replica 중 1개는 카나리아 ) 
export FRONTEND_SERVICE_IP=$(kubectl get -o \\
jsonpath="{.status.loadBalancer.ingress[0].ip}" --namespace=production services gceme-frontend)

while true; do curl http://$FRONTEND_SERVICE_IP/version; sleep 1; done

프로덕션에 배포

# git branch 변경 , canary merge , push 
git checkout master
git merge canary
git push origin master

# 이후 카나리와 유사하게 마스터 파이프라인 확인
export FRONTEND_SERVICE_IP=$(kubectl get -o \\
jsonpath="{.status.loadBalancer.ingress[0].ip}" --namespace=production services gceme-frontend)

while true; do curl http://$FRONTEND_SERVICE_IP/version; sleep 1; done

# 결과

gcpstaging9854_student@qwiklabs-gcp-df93aba9e6ea114a:~/continuous-deployment-on-kubernetes/sample-app$ while true; do curl http://$FRONTEND_SERVICE_IP/version; sleep 1; done
2.0.0
2.0.0
2.0.0
2.0.0
2.0.0
2.0.0
^C

마지막 질문

참고 사항

젠킨슨: https://cloud.google.com/architecture/jenkins-on-kubernetes-engine

Helm: https://helm.sh/ko/