목차
안녕하세요, 13년차의 서버실 운영자입니다. 오늘은 많은 분들이 고민하고 계실 법한 주제, 바로 Jenkins on Kubernetes 마이그레이션 경험담을 풀어보려고 합니다. 사실 저도 기존 Jenkins 환경을 운영하면서 여러 가지 페인 포인트(Pain Point)를 겪었거든요. 빌드가 몰리면 서버 리소스가 부족하고, 특정 에이전트(Agent)에 문제가 생기면 전체 파이프라인이 멈추고… 이런 경험, 혹시 여러분도 있으신가요?
클라우드 네이티브(Cloud-Native) 환경으로의 전환은 이제 선택이 아닌 필수가 되어가고 있습니다. CI/CD(Continuous Integration/Continuous Deployment, 지속적 통합/지속적 배포) 파이프라인의 핵심인 Jenkins 역시 예외는 아니죠. 기존 VM 기반의 Jenkins를 Kubernetes(쿠버네티스) 위로 옮기면서 얻게 된 이점과, 그 과정에서 겪었던 삽질 경험을 솔직하게 공유해 드릴게요. 이 글이 여러분의 Jenkins Kubernetes 마이그레이션 여정에 멘토 같은 역할을 해주었으면 좋겠습니다.
Jenkins on Kubernetes 아키텍처는 효율적인 CI/CD 파이프라인을 위한 핵심입니다. 동적 에이전트가 필요할 때마다 생성되어 리소스를 최적화합니다.
Jenkins on Kubernetes, 왜 필요할까요?
기존 Jenkins는 보통 고정된 마스터(Master)와 여러 개의 에이전트(Agent) 서버로 구성됩니다. 작업이 많아지면 에이전트 서버를 증설해야 하고, 사용하지 않을 때도 리소스를 계속 점유하죠. 특정 에이전트에 문제가 생기면 해당 에이전트에서 동작하는 모든 작업이 실패할 수 있으니 정말 골치 아픈 거거든요.
하지만 Jenkins on Kubernetes 환경은 다릅니다. 쉽게 말해, 필요한 순간에만 에이전트(Agent)를 띄워서 작업을 처리하고, 끝나면 바로 없애는 방식입니다. Jenkins 마스터는 Kubernetes 클러스터 내의 컨트롤러(Controller)로 동작하고, CI/CD 파이프라인 작업이 필요할 때마다 Kubernetes Pod(파드) 형태로 에이전트를 동적으로 생성합니다. 작업이 완료되면 해당 Pod는 자동으로 소멸됩니다. 이게 바로 클라우드 네이티브 CI/CD의 핵심 장점 중 하나예요.
✅ 주요 장점
- 탄력적인 확장성 (Elastic Scalability): 빌드 요청이 폭증해도 Kubernetes가 알아서 에이전트 Pod를 늘려줍니다.
- 리소스 효율성 (Resource Efficiency): 작업이 없을 때는 에이전트 Pod가 존재하지 않으므로 불필요한 리소스 낭비가 없습니다.
- 고가용성 (High Availability): Kubernetes의 자체 복구(Self-healing) 기능 덕분에 에이전트 Pod에 문제가 생겨도 다른 Pod로 대체되어 안정성이 높아집니다.
- 선언적 구성 (Declarative Configuration): Jenkinsfile(젠킨스파일)과 JCasC(Jenkins Configuration as Code)를 통해 CI/CD 파이프라인과 Jenkins 자체 구성을 코드로 관리할 수 있습니다.
Jenkins Kubernetes 마이그레이션, 실전 구현 단계
자, 그럼 이제 제가 실제로 어떻게 Jenkins 현대화를 진행했는지 단계별로 알려드릴게요. 처음엔 어디서부터 손대야 할지 막막했는데, 하나씩 해나가다 보니 길이 보이더라고요.
1. Kubernetes 클러스터 준비
가장 먼저 할 일은 Jenkins를 올릴 Kubernetes 클러스터를 준비하는 겁니다. 클라우드 환경에서는 AWS EKS(Elastic Kubernetes Service), Azure AKS(Azure Kubernetes Service), Google GKE(Google Kubernetes Engine) 같은 관리형 서비스를 이용하는 게 편합니다. 저는 홈랩에서 K3s 클러스터를 운영하고 있어서 그걸 활용했어요. 온프레미스(On-premise) 환경이라면 kubeadm이나 OpenShift 등을 고려할 수 있겠죠.
2. Helm을 이용한 Jenkins 설치
Kubernetes에 애플리케이션을 배포하는 가장 일반적인 방법 중 하나가 Helm(헬름) 차트입니다. Jenkins도 공식 Helm 차트를 제공하고 있어서 쉽게 설치할 수 있어요. 물론, 설치 전에 PersistentVolume(영구 볼륨)과 PersistentVolumeClaim(영구 볼륨 클레임)을 설정해서 Jenkins 설정과 데이터를 보존할 수 있도록 해야 합니다. 이 부분이 제일 중요해요. 데이터 날리면 대형사고잖아요?
# Helm 리포지토리 추가
helm repo add jenkins https://charts.jenkins.io
helm repo update
# values.yaml 파일 커스터마이징 (예시)
# persistentVolume 셋팅, resource limit, ingress 설정 등
# 자세한 내용은 공식 Helm 차트 문서를 참고하세요!
# Jenkins 설치
helm install jenkins -f my-jenkins-values.yaml jenkins/jenkins -n jenkins --create-namespace
위 명령어는 기본적인 설치 예시입니다. 실제 운영 환경에서는 `my-jenkins-values.yaml` 파일에 Ingress(인그레스, 외부 트래픽 진입점), 리소스 제한(Resource Limits), 플러그인 설정 등을 상세하게 정의해야 해요. 이 파일 하나로 Jenkins의 거의 모든 설정을 제어할 수 있거든요.
Helm `values.yaml` 파일은 Jenkins 배포의 핵심입니다. 여기서 영구 스토리지, 리소스, 에이전트 설정을 세밀하게 제어할 수 있습니다.
3. Kubernetes Cloud Plugin 설정
Jenkins 마스터가 Kubernetes 클러스터와 통신하며 동적 에이전트를 생성하려면 Kubernetes Cloud Plugin(쿠버네티스 클라우드 플러그인)을 설치하고 설정해야 합니다. Jenkins UI에서 'Jenkins 관리' → '시스템 설정' → '클라우드' 섹션으로 이동해서 Kubernetes 클러스터 정보를 입력합니다. 이때 Service Account(서비스 어카운트)와 RBAC(Role-Based Access Control) 설정을 통해 Jenkins가 Kubernetes API에 접근할 수 있도록 권한을 부여하는 것이 매우 중요합니다.
여기서 Pod Template(파드 템플릿)을 정의하게 되는데, 이 템플릿이 바로 동적 에이전트 Pod의 설계도입니다. 어떤 도커(Docker) 이미지를 사용할지, 얼마나 많은 CPU와 메모리를 할당할지, 필요한 도구들은 무엇인지 등을 정의하죠. 예를 들어, Node.js 빌드가 필요하면 Node.js 런타임이 포함된 이미지를 지정하는 식이에요.
4. Jenkinsfile 업데이트
기존 Jenkinsfile도 약간의 수정이 필요할 수 있어요. 특히 `agent any`나 `agent { label 'my-fixed-agent' }` 같은 부분을 `agent { kubernetes { yaml '''...''' } }` 형태로 바꿔서 동적 Pod를 사용하도록 유도해야 합니다.
// 기존 Jenkinsfile (예시)
// pipeline {
// agent any
// stages {
// stage('Build') {
// steps {
// sh 'npm install'
// sh 'npm build'
// }
// }
// }
// }
// Kubernetes 동적 에이전트를 사용하는 Jenkinsfile (예시)
pipeline {
agent {
kubernetes {
// Kubernetes Pod 템플릿을 직접 정의
yaml """
apiVersion: v1
kind: Pod
spec:
containers:
- name: jnlp
image: jenkins/inbound-agent:4.11.2-1
resources:
limits:
memory: "512Mi"
cpu: "500m"
- name: nodejs
image: node:16-alpine
command: ["cat"]
tty: true
resources:
limits:
memory: "1Gi"
cpu: "1000m"
"""
defaultContainer 'nodejs' // 이 컨테이너에서 스크립트 실행
}
}
stages {
stage('Build Frontend') {
steps {
container('nodejs') { // 'nodejs' 컨테이너에서 실행
sh 'npm install'
sh 'npm run build'
}
}
}
stage('Package Docker Image') {
// 다른 컨테이너 또는 스크립트 실행
}
}
}
위 Jenkinsfile 예시처럼, 하나의 Pod 안에 여러 컨테이너를 띄워서 각 컨테이너의 역할을 분리할 수 있어요. 예를 들어, `nodejs` 컨테이너에서 프론트엔드 빌드를 하고, `maven` 컨테이너에서 백엔드를 빌드하는 식이죠. 이 덕분에 빌드 환경을 더욱 유연하게 구성할 수 있거든요.
5. Configuration as Code (JCasC) 적용
Jenkins 설정을 UI에서 하나하나 하는 건 사실 귀찮고 실수를 유발하기 쉽습니다. JCasC(Jenkins Configuration as Code)는 Jenkins의 모든 설정을 YAML(야믈) 파일로 관리할 수 있게 해줘요. 이 파일을 버전 관리 시스템(VCS)에 커밋(Commit)해두면, Jenkins 인스턴스를 새로 띄우거나 설정을 변경할 때 코드로 관리할 수 있어서 매우 편리합니다. 저도 이걸 적용하고 나서 "이거 진짜 편하더라고요!"라고 감탄했었어요. Jenkins 현대화의 필수 요소라고 생각합니다.
⚠️ 주의사항 및 트러블슈팅
마이그레이션 과정에서 저도 꽤 삽질 좀 했습니다. 여러분은 저 같은 시행착오를 겪지 않으시길 바라며 몇 가지 팁을 공유합니다.
- Persistent Volume(PV) 설정: Jenkins 마스터의 홈 디렉토리(`JENKINS_HOME`)는 반드시 영구 볼륨으로 설정해야 합니다. 안 그러면 Jenkins Pod가 재시작될 때마다 모든 설정과 플러그인이 날아가는 대참사가 발생합니다. 😱
- 리소스 제한 (Resource Limits): 에이전트 Pod 템플릿에 CPU와 메모리 리소스 제한을 명확하게 설정해야 합니다. 너무 적으면 빌드가 실패하고, 너무 많으면 클러스터 리소스가 고갈될 수 있어요.
- 이미지 크기 및 빌드 시간: 동적 에이전트에 사용할 도커 이미지는 필요한 도구만 포함하여 최대한 가볍게 만드는 것이 좋습니다. 이미지가 너무 크면 Pod가 스케줄링(Scheduling)되고 컨테이너(Container)가 시작되는 시간이 길어져 빌드 성능에 악영향을 줄 수 있거든요.
- 네트워크 문제: Jenkins 마스터에서 GitHub, Nexus, SonarQube 등 외부 서비스에 접근할 수 있는지, 또는 그 반대로 외부에서 Ingress를 통해 Jenkins UI에 접근할 수 있는지 네트워크 설정을 꼼꼼히 확인해야 합니다.
- RBAC 권한: Jenkins 컨트롤러가 Kubernetes API에 접근할 수 있도록 적절한 Role(역할)과 RoleBinding(역할 바인딩)을 가진 Service Account를 생성하고 연결해야 합니다. 권한 부족으로 Pod 생성이 안 되는 경우가 많아요.
✅ 검증 및 마이그레이션 결과
모든 설정을 마치고 파이프라인을 실행하면, Jenkins 대시보드에서 동적으로 생성되는 에이전트 Pod들을 확인할 수 있습니다. Kubernetes 클러스터에서도 `kubectl get pods -n jenkins` 명령어로 새로운 Pod들이 생성되었다가 작업 완료 후 사라지는 것을 볼 수 있을 거예요. 드디어 됐다! 하고 외쳤던 순간이 기억나네요. 🎉
Jenkins 대시보드에서 동적 에이전트의 효율적인 동작을 확인하는 것은 마이그레이션 성공의 중요한 지표입니다.
Jenkins Kubernetes 마이그레이션을 통해 저희 팀은 다음과 같은 이점들을 누릴 수 있었습니다.
- 빌드 시간 단축: 필요한 리소스를 즉시 할당받아 빌드 시간이 단축되었습니다.
- 운영 비용 절감: 유휴 리소스가 없어 불필요한 클라우드 비용을 줄일 수 있었어요.
- 안정성 향상: 특정 에이전트 문제로 인한 빌드 실패가 줄어들고, Kubernetes의 복원력 덕분에 전체 시스템의 안정성이 높아졌습니다.
- CI/CD 파이프라인 관리의 용이성: JCasC와 Jenkinsfile을 통해 파이프라인과 Jenkins 자체를 코드로 관리하게 되면서, 변경 사항 추적 및 재현성이 크게 향상되었습니다.
Jenkins on Kubernetes 마이그레이션은 탄력적 확장성, 비용 효율성, 그리고 안정성을 동시에 달성하는 효과적인 방법입니다.
마무리하며: 클라우드 네이티브 CI/CD의 미래
오늘은 제가 직접 경험했던 Jenkins on Kubernetes 마이그레이션 사례를 공유해 드렸습니다. 처음엔 VM 기반 Jenkins 환경에 익숙해서 변화가 어렵게 느껴졌지만, 클라우드 네이티브 환경으로의 전환은 분명 더 나은 CI/CD 파이프라인을 위한 투자라고 생각해요.
물론 Jenkins 외에도 Argo CD(아르고 CD)나 Tekton(텍톤) 같은 훌륭한 클라우드 네이티브 CI/CD 도구들이 많이 있습니다. 하지만 기존 Jenkins 환경에 익숙하고, 점진적인 Jenkins 현대화를 원한다면 Kubernetes 위로 Jenkins를 옮기는 것이 좋은 시작점이 될 수 있다고 확신합니다.
이 글이 여러분의 인프라 여정에 작은 도움이 되었기를 바랍니다. 다음번에는 또 다른 삽질 경험과 해결책으로 찾아오겠습니다. 궁금한 점이나 공유하고 싶은 경험이 있다면 언제든지 댓글 남겨주세요! 😉
'IT > Cloud' 카테고리의 다른 글
| [Cloud] Datadog 비용 폭탄 피하기: 실전 최적화 전략과 절감 사례 (0) | 2026.06.18 |
|---|---|
| [Cloud] Zero Trust 아키텍처 도입 1년, 예상치 못한 보안 강화와 운영 부담 (0) | 2026.06.18 |
| [Podman] 프로덕션 운영 시 흔한 문제 해결 및 보안 강화 체크리스트 (1) | 2026.06.13 |
| [Cloud] Azure 비용 최적화: 숨겨진 지출 항목 5가지와 절감 전략 (0) | 2026.06.10 |
| [Cloud] GitHub Actions CI/CD 파이프라인, 흔한 실패 원인과 디버깅 전략 (0) | 2026.06.10 |
| [인프라 보안] Vault를 활용한 민감 정보 관리: 실전 사례와 팁 (0) | 2026.06.09 |