[쿠버네티스 어나더 클래스 (지상편) - Sprint 2] 14. Helm과 Kustomize 비교하며 사용-2Tech/Kubernetes(K8s)2025. 6. 16. 20:05
Table of Contents
* 본 게시물은 쿠버네티스 어나더 클래스 (지상편) - Sprint 1, 2 강의와 강의 자료를 바탕으로 작성되었습니다.
Helm과 Kustomize 비교

- Helm은 `helm create {project}` 명령어를 사용하면, 필요한 구조를 자동으로 생성
- Kustomize는 필요한 폴더 구조를 직접 만들어야 함
- kustomization.yaml 파일에 배포할 파일을 지정하고 공통 값을 설정할 수 있음
- ex ) commonLabels 속성에 작성된 내용은 모든 배포되는 파일의 label에 적용
- overlays: 오버레이 될 파일을 저장하는 디렉터리
- kustomization.yaml 파일에 배포할 파일을 지정하고 공통 값을 설정할 수 있음
Kustomize 배포
// Jenkinsfile 일부
stage('커스터마이즈 템플릿 확인') {
steps {
// K8S 배포
sh "kubectl kustomize ./${CLASS_NUM}/deploy/kustomize/api-tester/overlays/${params.PROFILE}"
}
}
stage('커스터마이즈 배포') {
steps {
// K8S 배포
input message: '배포 시작', ok: "Yes"
// Namespace 배포
sh "kubectl apply -f ./${CLASS_NUM}/deploy/kubectl/namespace-${params.PROFILE}.yaml"
// Overlays에 정의된 Resources 배포
sh "kubectl apply -k ./${CLASS_NUM}/deploy/kustomize/api-tester/overlays/${params.PROFILE}"
}
}
- Overlays를 지정해서 배포해주는 이유는 선택된 overlays 폴더의 kustomization.yaml 파일에 base 파일 경로와 배포해야 할 YAML 파일들이 아래와 같이 지정되어 있음
# ../overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: anotherclass-222-dev
commonLabels:
version: 2.0.0
# 관련된 Base 파일 경로를 지정
resources:
- ../../base
# 배포할 Overlays 파일 선택
patches:
- path: configmap.yaml
- path: deployment-spec.yaml
- path: deployment-ver.yaml
- path: secret.yaml
- path: service.yaml
Helm 배포
// Jenkinsfile 일부
stage('헬름 템플릿 확인') {
steps {
// K8S 배포
// values.yaml 파일을 기본적으로 사용
// -f 옵션으로 환경에 맞는 values.yaml을 지정하여 overlay 시킴
sh "helm template api-tester-${CLASS_NUM} ./${CLASS_NUM}/deploy/helm/api-tester" +
" -f ./${CLASS_NUM}/deploy/helm/api-tester/values-${params.PROFILE}.yaml -n anotherclass-222-${params.PROFILE}"
// --set replicaCount='3' --set port='80' --set profile='dev' --set nodeport='32223'
}
}
stage('헬름 배포') {
steps {
input message: '배포 시작', ok: "Yes"
// namespace 배포
sh "kubectl apply -f ./${CLASS_NUM}/deploy/kubectl/namespace-${params.PROFILE}.yaml"
// Resources 배포
sh "helm upgrade api-tester-${CLASS_NUM} ./${CLASS_NUM}/deploy/helm/api-tester" +
" -f ./${CLASS_NUM}/deploy/helm/api-tester/values-${params.PROFILE}.yaml" +
" -n anotherclass-222-${params.PROFILE} --install" // --create-namespace
}
}
배포 Pipeline 구축 후, 마주하게 되는 고민들
중요 파일 노출
- kubectl을 사용하기 위한 인증서 파일
- Jenkins Credentials에 등록해 사용하는 것으로 해결 가능
- Docker를 사용하기 위한 인증 정보 파일 config.json
- Jenkins Credentials에 등록해 배포할 때만 로그인하고, 완료되면 로그아웃 하는 방식으로 해결 가능
- 또는, docker-credentials-helpers를 적용해 config.json을 직접 암호화하는 방식도 사용됨
- Kubernetes config 파일을 Jenkins Credentials에 등록
Dashboard > Jenkins 관리 > Credentials > System > global Credentials (unrestricted) > Add Credentials
(Secret file 선택)

기존 CI/CD 서버에 저장되어 있던 인증서 삭제
# k8s 인증 파일 임시 백업
mv ~/.kube/config ~/.kube/config_bak
kubectl get pods -A
# 혹은, 삭제
rm ~/.kube/config
- Docker 인증 정보를 Jenkins Credentials에 등록
Dashboard > Jenkins 관리 > Credentials > System > global Credentials (unrestricted) > Add Credentials

CI/CD 서버의 Docker 로그아웃
# docker 로그아웃
docker logout
# docker 인증 정보 확인
cat ~/.docker/config.json
- Jenkins 파일 작성 시, Credentials 사용법
// Docker 사용
steps {
script{
// 각각 USERNAME, PASSWORD 라는 변수로 저장
withCredentials([usernamePassword(credentialsId: 'docker_password', passwordVariable: 'PASSWORD', usernameVariable: 'USERNAME')]) {
sh "echo " + '${PASSWORD}' + " | docker login -u " + '${USERNAME}' + " --password-stdin"
// Kubernetes config 사용
steps {
// 암호화로 관리된 config가 들어감, 'KUBECONFIG' 라는 변수로 저장
withCredentials([file(credentialsId: 'k8s_master_config', variable: 'KUBECONFIG')]) {
sh "kubectl apply -f ./2224/deploy/kubectl/namespace-dev.yaml --kubeconfig " + '${KUBECONFIG}'
sh "helm upgrade api-tester-2224 ./2224/deploy/helm/api-tester -f ./2224/deploy/helm/api-tester/values-dev.yaml" +
" -n anotherclass-222-dev --install --kubeconfig " + '${KUBECONFIG}'
Namespace는 배포와 별도로 관리
- Namespace에는 여러 개의 App이 구동되는 경우도 발생할 수 있음
- 만약, App을 내릴 때, Namespace를 함께 지워버리게 되면 실행 중이던 다른 App들도 함께 내려가버림
stage('네임스페이스 생성') { // 배포시 apply로 Namespace 생성 or 배포와 별개로 미리 생성 (추후 삭제시 별도 삭제)
steps {
withCredentials([file(credentialsId: 'k8s_master_config', variable: 'KUBECONFIG')]) {
sh "kubectl apply -f ./2224/deploy/kubectl/namespace-dev.yaml --kubeconfig " + '"${KUBECONFIG}"'
...
stage('헬름 배포') {
steps {
그래서, 위와 같이 Jenkinsfile에서 Step을 나누어 관리하거나
일반적으로는 Namespace를 한 번 만들면 건들 일이 별로 없기 때문에, kubectl을 통해 미리 생성하거나, Namespace를 관리하기 위한 Pipeline을 따로 만들기도 함
Helm의 부가 기능
- 원래는 배포 완료 후, Pod가 완전히 기동되기 까지 기다려야 했음
- `helm {command} --wait` 명령처럼 wait 옵션을 사용하면 Pod 기동을 체크하고 있다가, 기동이 완료되면 배포 완료를 알림
(하지만, 무한히 확인하면 CI/CD 서버의 리소스가 낭비되므로 timeout 시간을 꼭 지정해줘야 함)
stage('헬름 배포') {
steps {
withCredentials([file(credentialsId: 'k8s_master_config', variable: 'KUBECONFIG')]) {
sh "helm upgrade api-tester-2224 ./2224/deploy/helm/api-tester -f ./2224/deploy/helm/api-tester/values-dev.yaml" +
...
" --wait --timeout=10m" + // 최대 10분으로 설정
배포를 했지만, Pod upgrade가 진행되지 않은 경우
- upgrade는 새 버전 Deployment의 template 속성이 수정되어야 발생
- 때문에, template 속성 아래 `metadata.annotations` 속성을 두어, 새로운 배포마다 랜덤값을 생성해 upgrade를 유발하도록 함
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
spec:
template:
metadata:
annotations:
rollme: {{ randAlphaNum 5 | quote }} // 항상 새 배포를 위해 랜덤값 적용
Container Image Tag
- 예시 )
- api-tester:latest == api-tester (자동으로 최신 버전을 가져옴)
- api-tester:v1.0.0 (x), api-tester:1.0.0 (o)
숫자만 이용해서 나타내는 것이 정석
환경 별 배포의 차이
- 개발 환경 -> 잦은 배포로 Versioning 하는 것이 무의미
- image: api-tester:latest (항상 최신버전)
pullPolicy: Always (항상 hub에서 이미지를 가져옴) - 만약, 이전 버전으로 Roll Back을 원할 경우
- image: api-tester:1.0.1-{date} -> 배포마다 새로운 태그를 다는 것으로 해결
pullPolicy: IfNotPresent -> 같은 버전을 가져올 수 있으므로, IfNotPresent로 설정
(Node에 이미지가 있으면 그것을 먼저 사용하고, 없으면 Hub를 확인해 다운로드)
- image: api-tester:1.0.1-{date} -> 배포마다 새로운 태그를 다는 것으로 해결
- image: api-tester:latest (항상 최신버전)
- 검증 환경, 운영 환경 -> 계획된 배포로 Versioning이 필수
- image: api-tester:1.0.1 (배포하고자 하는 버전을 명시)
pullPolicy: IfNotPresent
- image: api-tester:1.0.1 (배포하고자 하는 버전을 명시)
Docker Image의 Tag에서 말하는 latest는 마지막 배포일까, 최신 안정화 버전을 의미할까?
1. 실제로는 마지막 배포 버전을 의미
2. 하지만, 사용자는 최신 안정화 버전을 예상하고 다운로드 받음
3. 때문에, 작은 프로젝트에서는 마지막 배포 버전을 생각하며 사용할 수 있지만, 대부분의 DockerHub에 공개된 Image의 latest 버전은 최신 안정화 버전을 의미
- Jenkinsfile에서 Versioning
// Jenkinsfile 일부
environment {
APP_VERSION = '1.0.1'
BUILD_DATE = sh(script: "echo `date +%y%m%d.%d%H%M`", returnStdout: true).trim()
// 위에 date 포맷 오류가 있어요. %y%m%d.%H%M%S가 맞습니다)
TAG = "${APP_VERSION}-" + "${BUILD_DATA}"
stage('컨테이너 빌드 및 업로드') {
steps {
script{
// 도커 빌드
sh "docker build ./2224/build/docker -t 1pro/api-tester:${TAG}"
sh "docker push 1pro/api-tester:${TAG}"
stage('헬름 배포') {
steps {
withCredentials([file(credentialsId: 'k8s_master_config', variable: 'KUBECONFIG')]) {
sh "helm upgrade api-tester-2224 ./2224/deploy/helm/api-tester -f ./2224/deploy/helm/api-tester/values-dev.yaml" +
...
" --set image.tag=${TAG}" // Deployment의 Image에 태그 값 주입
- latest 버전을 업로드할 때는?
# 따로 latest 버전을 만들어 배포
docker tag 1pro/api-tester:1.0.1-231220.171834 1pro/api-tester:latest
docker push 1pro/api-tester:latest
CI/CD를 계속하다 보면..
- Container Images가 Server에 계속 쌓이고, 나중에 Disk 공간 부족으로 Server가 죽을 수 있음
- 때문에, CI/CD 서버에서는 이미지를 Docker Hub에 업로드하고 삭제가 필요함
stage('컨테이너 빌드 및 업로드') {
steps {
script{
// 도커 빌드
sh "docker build ./${CLASS_NUM}/build/docker -t ${DOCKERHUB_USERNAME}/api-tester:${TAG}"
sh "docker push ${DOCKERHUB_USERNAME}/api-tester:${TAG}"
sh "docker rmi ${DOCKERHUB_USERNAME}/api-tester:${TAG}" // 이미지 삭제
그럼, k8s Node에 쌓이는 Images는?
- 배포를 진행하다 보면, 각 Nodes는 Docker Hub에서 Images를 다운로드 받아 Pod를 생성하기 때문에 Images가 쌓일 수 잇음
- k8s에서는 Kubernetes Garbage Collection이 존재해 사용하지 않는 Images를 주기적으로 자동 삭제해줌
// GC 속성 추가하기
[root@k8s-master ~]# vi /var/lib/kubelet/config.yaml
-----------------------------------
imageMinimumGCAge : 3m // 이미지 생성 후 해당 시간이 지나야 GC 대상이 됨 (Default : 2m)
imageGCHighThresholdPercent : 80 // Disk가 80% 위로 올라가면 GC 수행 (Default : 85)
imageGCLowThresholdPercent : 70 // Disk가 70% 밑으로 떨어지면 GC 수행 안함(Default : 80)
-----------------------------------
// kubelet 재시작
[root@k8s-master ~]# systemctl restart kubelet
'Tech > Kubernetes(K8s)' 카테고리의 다른 글
| [쿠버네티스 어나더 클래스 (지상편) - Sprint 2] 15. ArgoCD 빠르게 레벨업-2 (0) | 2025.06.18 |
|---|---|
| [쿠버네티스 어나더 클래스 (지상편) - Sprint 2] 15. ArgoCD 빠르게 레벨업-1 (0) | 2025.06.17 |
| [쿠버네티스 어나더 클래스 (지상편) - Sprint 2] 13. Helm과 Kustomize 비교하며 사용-1 (0) | 2025.06.14 |
| [쿠버네티스 어나더 클래스 (지상편) - Sprint 2] 12. Jenkins Pipeline (기초부터 Blue/Green까지 (0) | 2025.06.12 |
| [쿠버네티스 어나더 클래스 (지상편) - Sprint 2] 11. 배포를 시작하기 전에 반드시 알아야 할 것들 (강의를 보고) (2) | 2025.06.11 |
@ONE_ :: 정호원
잘못된 정보가 있다면 말씀해주세요!