Belajar Jenkins - Studi Kasus Complete Production-Grade Enterprise Pipeline
Episode 20 of 21

Belajar Jenkins - Studi Kasus Complete Production-Grade Enterprise Pipeline

Episode penutup series ini menyajikan studi kasus arsitektur pipeline enterprise yang terpadu, dari webhook SCM, provisioning pod build dinamis di Kubernetes, hingga deployment production dan notifikasi Slack. Kita juga menulis Jenkinsfile lengkap delapan tahap serta checklist security hardening untuk Jenkins controller.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Pendahuluan

Ini episode terakhir series Belajar Jenkins. Di 19 episode sebelumnya kita membangun keterampilan dari instalasi, pipeline as code, agent, secrets, Docker, shared library, JCasC, hingga troubleshooting. Sekarang kita merangkai semuanya menjadi satu arsitektur pipeline enterprise yang utuh — alur yang benar-benar dipakai tim DevOps di perusahaan berskala besar.

Kita akan membangun pipeline yang memenuhi alur berikut:

  1. SCM event trigger — webhook memicu Multibranch Pipeline saat ada push atau pull request.
  2. Dynamic agent provisioning — cluster Kubernetes membuat pod build berisi Node.js, SonarScanner, dan Docker CLI.
  3. Checkout & quality analysis — git checkout, scan SonarQube, dan quality gate harus lulus.
  4. Test & build — unit test, coverage JaCoCo, lalu multi-stage Docker build.
  5. Registry & security scan — push image ke private registry, lalu scan kerentanan dengan Trivy.
  6. Staging deploy & E2E test — deploy ke namespace staging lalu jalankan Cypress.
  7. Manual approval gate — release manager menyetujui via step input.
  8. Production deploy & notification — rolling update ke namespace production, notifikasi Slack, dan pod build dibersihkan otomatis.

Arsitektur Pipeline Enterprise

Kuncinya adalah pemisahan tanggung jawab. Jenkins controller hanya mengorkestrasi; semua pekerjaan berat berjalan di pod agent Kubernetes yang dibuat dan dihapus per build (episode 3). Sumber kebenaran untuk deployment ada di chart Helm (episode 16), kualitas dikontrol SonarQube (episode 14), dan keamanan image dijaga Trivy. Setiap tahap bisa gagal dan menghentikan alur lebih awal — jangan pernah melanjutkan ke production jika kualitas atau keamanan belum lulus.

Jenkinsfile Lengkap

Berikut Jenkinsfile utuh untuk alur di atas. Repository aplikasi berisi source code Node.js, folder chart/ berisi Helm chart, dan pipeline dijalankan sebagai Multibranch Pipeline.

JenkinsJenkinsfile pipeline enterprise
pipeline {
    agent {
        kubernetes {
            yaml '''
apiVersion: v1
kind: Pod
spec:
  containers:
    - name: build
      image: node:20-alpine
      command: ['sleep', 'infinity']
    - name: sonar
      image: sonarsource/sonar-scanner-cli:11
      command: ['sleep', 'infinity']
    - name: docker
      image: docker:27
      command: ['sleep', 'infinity']
      volumeMounts:
        - name: docker-sock
          mountPath: /var/run/docker.sock
  volumes:
    - name: docker-sock
      hostPath:
        path: /var/run/docker.sock
'''
        }
    }
    options {
        timestamps()
        timeout(time: 60, unit: 'MINUTES')
        disableConcurrentBuilds()
    }
    environment {
        IMAGE = 'registry.example.com/my-app'
        TAG = "1.0.${BUILD_NUMBER}"
    }
    stages {
        stage('Checkout & SonarQube Scan') {
            steps {
                checkout scm
                container('sonar') {
                    sh 'sonar-scanner -Dsonar.projectKey=my-app'
                }
            }
        }
        stage('Quality Gate') {
            steps {
                withSonarQubeEnv('SonarQube') {
                    sh 'echo "Menunggu quality gate..."'
                }
                timeout(time: 5, unit: 'MINUTES') {
                    waitForQualityGate abortPipeline: true
                }
            }
        }
        stage('Test & Build') {
            steps {
                container('build') {
                    sh 'npm ci'
                    sh 'npm run test:coverage'
                    sh 'npm run build'
                }
            }
            post {
                success {
                    junit 'coverage/report.xml'
                    jacoco execPattern: '**/jacoco.exec'
                }
            }
        }
        stage('Push Image & Trivy Scan') {
            steps {
                container('docker') {
                    docker.withRegistry('https://registry.example.com', 'registry-creds') {
                        sh "docker build -t ${IMAGE}:${TAG} ."
                        sh "docker push ${IMAGE}:${TAG}"
                    }
                }
                container('build') {
                    sh "trivy image --severity HIGH,CRITICAL --exit-code 1 ${IMAGE}:${TAG}"
                }
            }
        }
        stage('Deploy Staging & E2E') {
            steps {
                withKubeConfig(credentialsId: 'kubeconfig-staging', serverUrl: 'https://k8s-staging.example.com') {
                    sh "helm upgrade --install my-app ./chart --namespace staging --set image.repository=${IMAGE} --set image.tag=${TAG}"
                }
                sh 'npm run test:e2e -- --base-url=https://staging.example.com'
            }
        }
        stage('Manual Approval') {
            when { branch 'main' }
            steps {
                input message: 'Approve production deployment?', submitter: 'release-manager'
            }
        }
        stage('Deploy Production') {
            when { branch 'main' }
            steps {
                withKubeConfig(credentialsId: 'kubeconfig-prod', serverUrl: 'https://k8s-prod.example.com') {
                    sh "helm upgrade --install my-app ./chart --namespace production --set image.repository=${IMAGE} --set image.tag=${TAG} --wait"
                }
            }
        }
    }
    post {
        success {
            slackSend(color: 'good', message: "Deploy ${env.JOB_NAME} #${env.BUILD_NUMBER} berhasil ke production")
        }
        failure {
            emailext(to: 'release@example.com', subject: "Pipeline gagal: ${env.JOB_NAME}", body: "Cek log: ${env.BUILD_URL}")
        }
        cleanup {
            cleanWs()
        }
    }
}

Alur Kerja per Tahap

  • Webhook SCM: repositori terdaftar sebagai Multibranch Pipeline; setiap push atau pull request otomatis memicu pipeline di branch masing-masing. Branch selain main hanya berjalan sampai staging.
  • Agent dinamis: Kubernetes plugin membuat pod dengan tiga container — build (default), sonar, dan docker. Setelah build selesai, pod otomatis dihancurkan, sehingga tidak ada resource yang tertinggal.
  • Kualitas: waitForQualityGate memblokir pipeline jika SonarQube memberi hasil gagal. Atur quality gate SonarQube agar auto-pass pada project non-prod, supaya pipeline tidak menggantung selamanya.
  • Build & scan: Dockerfile multi-stage menghasilkan image ramping. Trivy dengan --exit-code 1 membuat pipeline gagal jika ditemukan kerentanan HIGH atau CRITICAL.
  • Staging & E2E: aplikasi di-deploy ke namespace staging, lalu Cypress dijalankan melawan base URL staging. Ini adalah gerbang terakhir sebelum approval.
  • Approval manual: step input menghentikan pipeline di branch main sampai release manager menyetujui.
  • Production: helm upgrade --install dengan flag --wait melakukan rolling update dan menunggu pod siap sebelum pipeline dinyatakan sukses, lalu Slack memberi kabar.

Warning

Mount host docker.sock di pod agent memudahkan build image, tapi memberi akses root ke node. Di environment yang ketat, gunakan Docker-in-Docker (DinD) atau runner khusus ber-privilege, dan pastikan pod agent tidak pernah menerima job dari pengguna tidak tepercaya.

Checklist Kesiapan Produksi & Security Hardening

Terakhir, checklist yang wajib dipenuhi sebelum Jenkins controller dinyatakan production-ready:

  • Controller tidak menjalankan build — semua pekerjaan berjalan di agent; controller hanya orkestrasi.
  • Tutup akses anonim — matikan anonymous read; semua akses butuh login.
  • RBAC — gunakan Role Strategy dengan role terpisah: admin, developer, dan release manager.
  • Autentikasi terpusat — SSO via LDAP, AD, SAML, atau OIDC, bukan user database terpisah.
  • Semua rahasia di credentials store — pakai withCredentials dan jangan pernah menyimpan secret di Jenkinsfile.
  • Kunci kubeconfig — kredensial cluster hanya untuk job tertentu, dengan context terbatas per namespace.
  • TLS di ujung public — jalankan Jenkins di belakang reverse proxy HTTPS (misal Nginx), jangan expose plain HTTP.
  • Kelola plugin — update plugin rutin, hapus plugin yang tidak dipakai, dan pantau keamanan.
  • Backup terjadwal + uji DR — ThinBackup atau snapshot berkala, dengan restore yang diuji kuartalan.
  • Monitoring & alert — Prometheus Metrics plugin untuk queue, executor, dan JVM; alert aktif di Grafana.
  • Network isolation — batasi akses jaringan controller dan agent hanya ke yang diperlukan (registry, SCM, cluster).

Penutup

Di episode ini kita merangkai semuanya menjadi studi kasus pipeline enterprise:

  • Webhook SCM memicu Multibranch Pipeline untuk setiap branch dan pull request.
  • Pod build dinamis di Kubernetes menjalankan checkout, SonarQube, test, dan build Docker.
  • Image di-scan Trivy sebelum masuk private registry dan dideploy ke staging.
  • Quality gate, E2E, dan approval manual menjadi tiga gerbang keamanan sebelum production.
  • Rolling update ke production, notifikasi Slack, dan cleanup otomatis menutup alur.
  • Checklist security hardening memastikan controller aman dan siap produksi.

Dari episode 0 hingga 20, kalian sekarang memiliki bekal lengkap membangun, mengamankan, memantau, dan memecahkan masalah Jenkins di skala enterprise. Jangan berhenti di sini — coba terapkan di proyek nyata, otomasi hal kecil dulu, lalu naikkan kompleksitasnya. Selamat membangun pipeline production-grade kalian sendiri!

Belajar Jenkins - Studi Kasus Complete Production-Grade Enterprise Pipeline | Belajar Jenkins