kubernetes-anotherclass-sprint2/2213 at main · yangwoohyeon/kubernetes-anotherclass-sprint2
[⚓쿠버네티스 어나더 클래스 (지상편) - 📗Sprint2]. Contribute to yangwoohyeon/kubernetes-anotherclass-sprint2 development by creating an account on GitHub.
github.com
Jenkins와 쿠버네티스를 이용하여 Blue/Green 배포를 진행해봤다.
Blue/Green 배포의 특징
- 무중단 배포 가능
- 운영환경에서 테스트 가능
- 빠른 롤백 지원
- 새로운 배포본의 문제점 발견시 즉시 안정된 버전으로 복구 가능해 안정적인 서비스 운영 가능
<Jenkinsfile>
pipeline {
agent any
parameters {
// GitHub 사용자명 입력
string(name: 'GITHUB_USERNAME', defaultValue: '', description: 'GitHub 사용자명을 입력하세요.')
}
environment {
// 전역값을 넣어 두시면 위 parameters 입력이 필요 없어요. (전체 Jenkinfile에서 해당 내용을 모두 수정해 놓으면 좋습니다.)
// GITHUB_USERNAME = ""
// 아래 부분 수정(x)
GITHUB_URL = "https://github.com/${GITHUB_USERNAME}/kubernetes-anotherclass-sprint2.git"
CLASS_NUM = '2213'
}
stages {
stage('Username 확인') {
steps {
script {
if (!env.GITHUB_USERNAME?.trim()) {
error "[파라미터와 함께 빌드]에 GITHUB_USERNAME를 본인의 username으로 입력해 주세요! 매번 입력이 번거롭다면 Jenkinsfile에서 parameters에 입력 항목을 삭제 하시고 environment에 전역값을 넣은 후 해당 조건문은 삭제해 주세요. "
}
}
}
}
stage('릴리즈파일 체크아웃') {
steps {
checkout scmGit(branches: [[name: '*/main']],
extensions: [[$class: 'SparseCheckoutPaths',
sparseCheckoutPaths: [[path: "/${CLASS_NUM}"]]]],
userRemoteConfigs: [[url: "${GITHUB_URL}"]])
}
}
stage('쿠버네티스 Blue배포') {
steps {
sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/blue/namespace.yaml"
sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/blue/configmap.yaml"
sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/blue/secret.yaml"
sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/blue/service.yaml"
sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/blue/deployment.yaml"
}
}
stage('배포 시작') {
steps {
input message: '수동배포 시작', ok: "Yes"
}
}
stage('쿠버네티스 Green배포') {
steps {
sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/green/deployment.yaml"
sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/green/service.yaml"
}
}
stage('전환여부 확인') {
steps {
script {
returnValue = input message: 'Green 전환?', ok: "Yes", parameters: [booleanParam(defaultValue: true, name: 'IS_SWITCHED')]
if (returnValue) {
sh "kubectl patch -n anotherclass-221 svc api-tester -p '{\"spec\": {\"selector\": {\"blue-green-no\": \"2\"}}}'"
}
}
}
}
stage('롤백 확인') {
steps {
script {
returnValue = input message: 'Blue 롤백?', parameters: [choice(choices: ['done', 'rollback'], name: 'IS_ROLLBACk')]
if (returnValue == "done") {
sh "kubectl delete -f ./${CLASS_NUM}/deploy/k8s/blue/deployment.yaml"
sh "kubectl delete -f ./${CLASS_NUM}/deploy/k8s/green/service.yaml"
sh "kubectl patch -n anotherclass-221 svc api-tester -p '{\"metadata\": {\"labels\": {\"version\": \"2.0.0\"}}}'"
sh "kubectl patch -n anotherclass-221 cm api-tester-properties -p '{\"metadata\": {\"labels\": {\"version\": \"2.0.0\"}}}'"
sh "kubectl patch -n anotherclass-221 secret api-tester-postgresql -p '{\"metadata\": {\"labels\": {\"version\": \"2.0.0\"}}}'"
}
if (returnValue == "rollback") {
sh "kubectl patch -n anotherclass-221 svc api-tester -p '{\"spec\": {\"selector\": {\"blue-green-no\": \"1\"}}}'"
}
}
}
}
}
}
1. 쿠버네티스 Blue 배포
Blue 환경(V1) 관련 네임스페이스, ConfigMap, Secret, Service, Deployment YAML을 순서대로 쿠버네티스에 적용한다.
<Blue deployment.yaml>
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: anotherclass-221
name: api-tester-1
labels:
part-of: k8s-anotherclass
component: backend-server
name: api-tester
instance: api-tester
version: 1.0.0
managed-by: kubectl
spec:
selector:
matchLabels:
part-of: k8s-anotherclass
component: backend-server
name: api-tester
replicas: 2
strategy:
type: RollingUpdate
template:
metadata:
labels:
part-of: k8s-anotherclass
component: backend-server
name: api-tester
instance: api-tester
version: 1.0.0
blue-green-no: "1"
spec:
nodeSelector:
kubernetes.io/hostname: k8s-master
containers:
- name: api-tester-1
image: 1pro/api-tester:v1.0.0
imagePullPolicy: Always
ports:
- containerPort: 8080
name: http
envFrom:
- configMapRef:
name: api-tester-properties
startupProbe:
httpGet:
path: "/startup"
port: 8080
periodSeconds: 5
failureThreshold: 24
readinessProbe:
httpGet:
path: "/readiness"
port: 8080
periodSeconds: 10
failureThreshold: 3
livenessProbe:
httpGet:
path: "/liveness"
port: 8080
periodSeconds: 10
failureThreshold: 3
resources:
requests:
memory: "100Mi"
cpu: "100m"
limits:
memory: "200Mi"
cpu: "200m"
volumeMounts:
- name: secret-datasource
mountPath: /usr/src/myapp/datasource
volumes:
- name: secret-datasource
secret:
secretName: api-tester-postgresql
위 코드는 Blue의 deployment.yaml 파일이다.
blue-green-no: "1" 레이블을 통해 Blue 환경임을 의미한다.
수동배포를 시작하고 Master Node에서 version 조회 시작해보면 v1의 api가 호출되는것을 확인 가능하다.
while true; do curl http://192.168.56.30:32214/version; sleep 1; echo ''; done;
2. 쿠버네티스 Green 배포
수동배포 시작을 하게 되면 Green배포가 되어서 v2 호출이 가능하다.
이 상황에서는 v2로 완전히 대체된것이 아니라 v1 service를 사용하고 있지만 v2 service호출이 가능한 상황 이므로, 이 때 v2로 전환하기 전 테스트를 수행해보면서 안전하게 전환할 수 있다.
이제 전환 여부 확인에서 전환을 하게 되면 v1 service는 종료되고 v2 service만 남게된다.
이 상황에서는 version조회를 하면 v2만 조회되는 것을 확인 가능하다.
만약 지금까지의 과정에서 오류가 생겼다면 Rollback을 통해 실행 전 상황으로 다시 돌아갈 수 있다.
자동배포 스크립트 사용
<Jenkinsfile>
pipeline {
agent any
parameters {
// GitHub 사용자명 입력
string(name: 'GITHUB_USERNAME', defaultValue: '', description: 'GitHub 사용자명을 입력하세요.')
}
environment {
// 전역값을 넣어 두시면 위 parameters 입력이 필요 없어요. (전체 Jenkinfile에서 해당 내용을 모두 수정해 놓으면 좋습니다.)
// GITHUB_USERNAME = ""
// 아래 부분 수정(x)
GITHUB_URL = "https://github.com/${GITHUB_USERNAME}/kubernetes-anotherclass-sprint2.git"
CLASS_NUM = '2214'
}
stages {
stage('Username 확인') {
steps {
script {
if (!env.GITHUB_USERNAME?.trim()) {
error "[파라미터와 함께 빌드]에 GITHUB_USERNAME를 본인의 username으로 입력해 주세요! 매번 입력이 번거롭다면 Jenkinsfile에서 parameters에 입력 항목을 삭제 하시고 environment에 전역값을 넣은 후 해당 조건문은 삭제해 주세요. "
}
}
}
}
stage('릴리즈파일 체크아웃') {
steps {
checkout scmGit(branches: [[name: '*/main']],
extensions: [[$class: 'SparseCheckoutPaths',
sparseCheckoutPaths: [[path: "/${CLASS_NUM}"]]]],
userRemoteConfigs: [[url: "${GITHUB_URL}"]])
}
}
stage('쿠버네티스 Blue배포') {
steps {
sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/blue/namespace.yaml"
sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/blue/configmap.yaml"
sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/blue/secret.yaml"
sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/blue/service.yaml"
sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/blue/deployment.yaml"
}
}
stage('자동배포 시작') {
steps {
input message: '자동배포 시작', ok: "Yes"
}
}
stage('쿠버네티스 Green배포') {
steps {
sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/green/deployment.yaml"
}
}
stage('Green 배포 확인중') {
steps {
script {
def returnValue
while (returnValue != "true true"){
returnValue = sh(returnStdout: true, encoding: 'UTF-8', script: "kubectl get -n anotherclass-221 pods -l instance='api-tester-2214',blue-green-no='2' -o jsonpath='{.items[*].status.containerStatuses[*].ready}'")
echo "${returnValue}"
sleep 5
}
}
}
}
stage('Green 전환 완료') {
steps {
sh "kubectl patch -n anotherclass-221 svc api-tester-2214 -p '{\"spec\": {\"selector\": {\"blue-green-no\": \"2\"}}}'"
}
}
stage('Blue 삭제') {
steps {
sh "kubectl delete -f ./${CLASS_NUM}/deploy/k8s/blue/deployment.yaml"
sh "kubectl patch -n anotherclass-221 svc api-tester-2214 -p '{\"metadata\": {\"labels\": {\"version\": \"2.0.0\"}}}'"
sh "kubectl patch -n anotherclass-221 cm api-tester-2214-properties -p '{\"metadata\": {\"labels\": {\"version\": \"2.0.0\"}}}'"
sh "kubectl patch -n anotherclass-221 secret api-tester-2214-postgresql -p '{\"metadata\": {\"labels\": {\"version\": \"2.0.0\"}}}'"
}
}
}
}
동작 과정
- 깃허브 username 확인
- 깃허브 리포지토리에서 특정 경로만 불러오기
- 쿠버네티스 Blue배포 -> 네임스페이스, configmap, secret, service, deployment 리소스 생성
- Green 배포
- Green에 배포된 파드들의 레디 상태가 모두 true일 때까지 기다림 (5초 간격으로 체크)
- Green 배포가 완료되면 트래픽을 Blue에서 Green으로 변환
- 기존 Blue deployment 제거
'DevOps > Kubernetes' 카테고리의 다른 글
kubernetes, Jenkins를 활용한 CI/CD Pipeline구축 (3) | 2025.08.09 |
---|---|
[Kubernetes] 배포 전략(Recreate/ RollingUpdate / BlueGreen / Canary) (2) | 2025.08.04 |
[kubernetes] Probe (2) | 2025.07.31 |
[Kubernetes] 쿠버네티스 오브젝트 정리 (3) | 2025.07.30 |
쿠버네티스 자동화 모니터링 환경 만들기: Loki-Stack과 Grafana 연동, 쿠버네티스 대표기능 테스트 (2) | 2025.07.29 |