Jenkins 마스터하기: 파이프라인 초보에서 DevOps 영웅까지 🎭
Source: Dev.to
소개
적절한 CI/CD 파이프라인이 없던 시절을 떠올려 보세요 – 개발자들이 마치 디지털 카우보이처럼 코드를 수동으로 배포하고, 변경 사항이 사용자에게 폭발하지 않기를 바라던 어두운 시절이었습니다.
그때 등장한 Jenkins – 천재와 혼돈을 동시에 지닌 새로운 디지털 집사입니다. 원래는 Hudson이라는 이름이었지만(Oracle 변호사들이 파티를 망쳤죠), Jenkins는 2011년부터 개발자들의 삶을 자동화해 왔습니다. 재미있는 사실: Jenkins의 마스코트는 바로 “Jenkins”라는 이름의 집사입니다.
오늘은 여러분을 파이프라인 초보에서 CI/CD 기사로 변신시켜 드릴 겁니다. 자동화된 테스트 갑옷과 배포 초능력을 갖춘 기사 말이죠.
1. Jenkins 101: 새로운 디지털 집사와의 만남 🤖
좋은 점, 나쁜 점, 그리고 파란 공
Jenkins는 색깔이 있는 공에 대한 독특한 집착이 있습니다:
- 초록은 성공을 의미합니다.
- 파랑도 성공을 의미합니다(복잡합니다).
- 빨강은 “이력서를 업데이트할 때다”를 의미합니다.
Jenkins 커뮤니티에서는 파란색과 초록색 표시를 두고 한때 뜨거운 논쟁이 있었습니다.
Jenkins 생존 키트
pipeline {
agent any
stages {
stage('Hello World') {
steps {
echo 'Welcome to Jenkins, brave soul!'
script {
def courage = "maximum"
echo "Setting courage level to: ${courage}"
}
}
}
}
}
덜 알려진 사실: Jenkins에는 1,800개가 넘는 플러그인이 있습니다 – 스위스 군용 나이프 공장보다도 다양하죠! Slack과 연동하고 싶나요? 플러그인이 있습니다. 화성에 배포하고 싶나요? 아마도 플러그인이 있을 겁니다(아직 화성은 아니지만…).
설치: 소환 의식
# Docker 방식 (현명한 사람들을 위해)
docker run -p 8080:8080 -p 50000:50000 jenkins/jenkins:lts
# 전통 방식 (용감한 사람들을 위해)
sudo apt update
sudo apt install openjdk-11-jdk
wget -q -O - https://pkg.jenkins.io/debian/jenkins.io.key | sudo apt-key add -
sudo sh -c 'echo deb https://pkg.jenkins.io/debian binary/ > /etc/apt/sources.list.d/jenkins.list'
sudo apt update && sudo apt install jenkins
프로 팁: Jenkins는 관리자 비밀번호를 보물보다 깊은 파일에 숨겨 두고 인사합니다. 🗝️
2. 파이프라인 아키텍처: 코드를 프로덕션으로 연결하는 고속도로 🛣️
단계: 조립 라인 작업자들
파이프라인 단계는 각각 고유한 성격을 가진 조립 라인 작업자라고 생각하면 됩니다:
- Build Bob – 코드를 컴파일하고 누락된 의존성을 불평합니다.
- Test Terry – 카페인에 취한 QA 엔지니어처럼 열정적으로 테스트를 실행합니다.
- Deploy Diana – 코드를 프로덕션에 배포합니다(성공률은 다양합니다).
예시 파이프라인
pipeline {
agent any
environment {
DOCKER_IMAGE = "myapp:${env.BUILD_NUMBER}"
DEPLOY_ENV = "staging"
}
stages {
stage('Checkout') {
steps {
git branch: 'main', url: 'https://github.com/yourcompany/awesome-app.git'
}
}
stage('Build & Test') {
parallel {
stage('Build') {
steps {
sh 'mvn clean compile'
echo "Build completed! Bob is happy! 😊"
}
}
stage('Unit Tests') {
steps {
sh 'mvn test'
publishTestResults testResultsPattern: 'target/test-reports/*.xml'
}
post {
always {
echo "Terry finished testing (with varying degrees of success)"
}
}
}
stage('Security Scan') {
steps {
sh 'mvn dependency-check:check'
echo "Security scan complete - no known vulnerabilities found! 🔒"
}
}
}
}
}
}
놀라운 사실: 병렬 실행을 활용하면 빌드 시간을 60 % 이상 단축할 수 있습니다 – 마치 여러 조립 라인이 동시에 가동되는 것과 같습니다.
Jenkinsfile: 파이프라인의 DNA
Jenkinsfile은 파이프라인의 유전 코드입니다. 이를 레포지토리에 보관하고 Pipeline‑as‑Code(코드로서의 파이프라인)로 다루세요. 이는 인프라를 코드로 관리하는 Infrastructure‑as‑Code보다 더 멋진 사촌이죠.
3. 제로에서 히어로까지: 실전 파이프라인 구현 🦸♂️
완전한 파이프라인: 현대적인 걸작
pipeline {
agent any
environment {
DOCKER_REGISTRY = "your-registry.com"
APP_NAME = "awesome-app"
STAGING_SERVER = "staging.awesome-app.com"
PRODUCTION_SERVER = "awesome-app.com"
}
stages {
stage('Preparation') {
steps {
cleanWs()
git branch: "${BRANCH_NAME}", url: 'https://github.com/yourcompany/awesome-app.git'
script {
env.BUILD_VERSION = "${env.BUILD_NUMBER}-${env.GIT_COMMIT.take(7)}"
}
}
}
stage('Build & Quality Gates') {
parallel {
stage('Application Build') {
steps {
sh 'mvn clean package -DskipTests'
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
}
stage('Code Quality') {
steps {
sh 'mvn sonar:sonar'
echo "SonarQube analysis complete - code quality checked! ✨"
}
}
stage('Dependency Audit') {
steps {
sh 'mvn dependency-check:check'
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'target',
reportFiles: 'dependency-check-report.html',
reportName: 'Dependency Check Report'
])
}
}
}
}
stage('Testing Symphony') {
parallel {
stage('Unit Tests') {
steps {
sh 'mvn test'
publishTestResults testResultsPattern: 'target/test-reports/*.xml'
}
}
stage('Integration Tests') {
steps {
sh 'mvn integration-test'
echo "Integration tests passed - components are playing nice! 🤝"
}
}
stage('API Tests') {
steps {
sh 'npm install && npm run api-tests'
publishTestResults testResultsPattern: 'api-test-results.xml'
}
}
}
}
stage('Containerization') {
steps {
script {
def image = docker.build("${env.DOCKER_REGISTRY}/${env.APP_NAME}:${env.BUILD_VERSION}")
docker.withRegistry("https://${env.DOCKER_REGISTRY}", 'docker-registry-credentials') {
image.push()
image.push('latest')
}
echo "Docker image ${image.id} pushed to ${env.DOCKER_REGISTRY}"
}
}
}
stage('Deploy to Staging') {
steps {
sh """
ssh user@${STAGING_SERVER} '
docker pull ${env.DOCKER_REGISTRY}/${env.APP_NAME}:${env.BUILD_VERSION}
docker run -d --rm -p 8080:8080 ${env.DOCKER_REGISTRY}/${env.APP_NAME}:${env.BUILD_VERSION}
'
"""
echo "Deployed ${APP_NAME} to staging."
}
}
stage('Approval') {
steps {
input message: 'Promote to production?', ok: 'Deploy'
}
}
stage('Deploy to Production') {
steps {
sh """
ssh user@${PRODUCTION_SERVER} '
docker pull ${env.DOCKER_REGISTRY}/${env.APP_NAME}:${env.BUILD_VERSION}
docker run -d --rm -p 80:8080 ${env.DOCKER_REGISTRY}/${env.APP_NAME}:${env.BUILD_VERSION}
'
"""
echo "Deployed ${APP_NAME} to production."
}
}
}
post {
always {
cleanWs()
echo 'Workspace cleaned.'
}
success {
mail to: 'team@example.com',
subject: "✅ Successful build ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: "Great job! The pipeline completed successfully."
}
failure {
mail to: 'team@example.com',
subject: "❌ Failed build ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: "Something went wrong. Check the Jenkins console for details."
}
}
}
이 파이프라인이 보여주는 내용:
- 병렬 단계를 통한 빠른 피드백 제공.
- SonarQube를 이용한 코드 품질 검사.
- 의존성 감사와 HTML 보고서 생성.
- Docker를 활용한 컨테이너화 및 사설 레지스트리로 이미지 푸시.
- 스테이징 배포, 수동 승인, 그리고 프로덕션 배포.
- 빌드 후 작업으로 정리 및 알림 전송.