DevOps & Cloud

Jenkins: CI/CD Automation — Pipeline, Plugins, Agents & Credentials

TOKEN

Pelajari Jenkins CI/CD dari nol — Declarative & Scripted Pipeline, Jenkinsfile, plugins essential, distributed agents, credentials management, shared libraries, dan automation best practices

1. Pengenalan Jenkins

Jenkins adalah automation server open-source yang paling banyak digunakan untuk Continuous Integration (CI) dan Continuous Delivery (CD). Dibuat oleh Kohsuke Kawaguchi pada 2011 (fork dari Hudson), Jenkins telah menjadi standar industri untuk CI/CD dengan lebih dari 1,800+ plugins yang tersedia.

Jenkins memungkinkan developer mengotomasi seluruh siklus build, test, dan deployment. Dengan Jenkins, setiap kali developer push kode ke repository, Jenkins secara otomatis mengambil kode tersebut, menjalankan build, menjalankan test, dan men-deploy hasilnya ke environment yang diinginkan.

Mengapa Jenkins?

Keunggulan Penjelasan
Open SourceGratis, komunitas besar, dokumentasi lengkap
Plugin Ecosystem1,800+ plugins untuk integrasi dengan hampir semua tool
ExtensibleBisa dikustomisasi dengan Groovy scripting
DistributedBisa menjalankan jobs di banyak agent/server
Pipeline as CodeDefine pipeline dalam Jenkinsfile di repository
CommunityDukungan komunitas yang sangat besar
Self-hostedKontrol penuh atas infrastruktur CI/CD
Diagram: Jenkins Architecture
┌─────────────────────────────────────────────────────────────────┐
│                      JENKINS ARCHITECTURE                        │
│                                                                  │
│  ┌────────────────────────────────────────────────────────────┐ │
│  │                   JENKINS CONTROLLER                       │ │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐ │ │
│  │  │ Web UI   │  │ Pipeline │  │  Plugin  │  │  Job     │ │ │
│  │  │ (8080)   │  │ Engine   │  │  Manager │  │ Scheduler│ │ │
│  │  └──────────┘  └──────────┘  └──────────┘  └──────────┘ │ │
│  └──────────┬─────────────┬─────────────┬────────────────────┘ │
│             │             │             │                        │
│             ▼             ▼             ▼                        │
│  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐            │
│  │  Agent 1     │ │  Agent 2     │ │  Agent 3     │            │
│  │  (Linux)     │ │  (Windows)   │ │  (Docker)    │            │
│  │  - Build     │ │  - Test      │ │  - Build     │            │
│  │  - Deploy    │ │  - Package   │ │  - Deploy    │            │
│  └──────┬───────┘ └──────┬───────┘ └──────┬───────┘            │
│         │                │                │                      │
│         ▼                ▼                ▼                      │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │              SCM (Git/SVN) + Docker Registry             │  │
│  │              Artifacts Repository (Nexus/Artifactory)    │  │
│  └──────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘

2. Instalasi & Setup

Instalasi Jenkins dengan Docker

Bash
# ===========================
# INSTALL JENKINS (DOCKER)
# ===========================

# Jalankan Jenkins LTS dengan Docker
docker run -d \
  --name jenkins \
  -p 8080:8080 \
  -p 50000:50000 \
  -v jenkins_home:/var/jenkins_home \
  -v /var/run/docker.sock:/var/run/docker.sock \
  jenkins/jenkins:lts-jdk17

# Cek initial admin password
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword

# Buka browser: http://localhost:8080
# Masukkan initial admin password
# Install suggested plugins
# Buat admin user

# ===========================
# DOCKER COMPOSE SETUP
# ===========================
# docker-compose.yml untuk Jenkins
YAML — docker-compose.yml
# docker-compose.yml — Jenkins Setup
version: "3.8"
services:
  jenkins:
    image: jenkins/jenkins:lts-jdk17
    container_name: jenkins
    restart: unless-stopped
    ports:
      - "8080:8080"
      - "50000:50000"
    volumes:
      - jenkins_home:/var/jenkins_home
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - JAVA_OPTS=-Djenkins.install.runSetupWizard=true
    user: root  # Hanya untuk development!

  # SonarQube untuk code quality (opsional)
  sonarqube:
    image: sonarqube:community
    container_name: sonarqube
    ports:
      - "9000:9000"
    volumes:
      - sonarqube_data:/opt/sonarqube/data
    environment:
      - SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true

volumes:
  jenkins_home:
  sonarqube_data:

Instalasi di Ubuntu/Debian

Bash
# Install Java (prasyarat)
sudo apt update
sudo apt install -y openjdk-17-jdk

# Tambah Jenkins repository
curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | \
  sudo tee /usr/share/keyrings/jenkins-keyring.asc > /dev/null

echo "deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
  https://pkg.jenkins.io/debian-stable binary/" | \
  sudo tee /etc/apt/sources.list.d/jenkins.list > /dev/null

# Install Jenkins
sudo apt update
sudo apt install -y jenkins

# Start Jenkins
sudo systemctl start jenkins
sudo systemctl enable jenkins

# Cek status
sudo systemctl status jenkins

# Initial password
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
💡 Tips

Untuk production, jangan jalankan Jenkins sebagai root. Buat user khusus jenkins dengan akses terbatas. Gunakan reverse proxy (Nginx/Apache) di depan Jenkins untuk SSL termination dan keamanan tambahan.

3. Jenkinsfile: Declarative Pipeline

Declarative Pipeline adalah sintaks yang direkomendasikan untuk Jenkins Pipeline. Ditulis dalam format terstruktur dengan Groovy DSL, lebih mudah dibaca dan di-maintain dibanding Scripted Pipeline.

Basic Declarative Pipeline

Groovy — Jenkinsfile
// Jenkinsfile — Declarative Pipeline
// BeebaneLabs - Jenkins Tutorial

pipeline {
    agent any

    // Environment variables
    environment {
        APP_NAME = 'myapp'
        DOCKER_IMAGE = "registry.example.com/${APP_NAME}"
        NODE_VERSION = '20'
    }

    // Build tools
    tools {
        nodejs "${NODE_VERSION}"
    }

    // Pipeline options
    options {
        timeout(time: 30, unit: 'MINUTES')
        timestamps()
        buildDiscarder(logRotator(numToKeepStr: '10'))
        disableConcurrentBuilds()
    }

    // Pipeline triggers
    triggers {
        pollSCM('H/5 * * * *')  // Cek Git setiap 5 menit
    }

    stages {
        // ===== CHECKOUT =====
        stage('Checkout') {
            steps {
                checkout scm
                sh 'git log --oneline -5'
            }
        }

        // ===== INSTALL =====
        stage('Install Dependencies') {
            steps {
                sh 'npm ci --cache .npm'
            }
        }

        // ===== BUILD =====
        stage('Build') {
            steps {
                sh 'npm run build'
            }
            post {
                success {
                    archiveArtifacts artifacts: 'dist/**', fingerprint: true
                }
            }
        }

        // ===== TEST =====
        stage('Test') {
            parallel {
                stage('Unit Test') {
                    steps {
                        sh 'npm run test:unit -- --coverage'
                    }
                    post {
                        always {
                            junit 'test-results/*.xml'
                            publishHTML(target: [
                                reportDir: 'coverage/lcov-report',
                                reportFiles: 'index.html',
                                reportName: 'Coverage Report'
                            ])
                        }
                    }
                }
                stage('Lint') {
                    steps {
                        sh 'npm run lint'
                    }
                }
            }
        }

        // ===== SECURITY SCAN =====
        stage('Security Scan') {
            steps {
                sh 'npm audit --audit-level=high || true'
            }
        }

        // ===== DOCKER BUILD =====
        stage('Docker Build') {
            when {
                branch 'main'
            }
            steps {
                script {
                    docker.withRegistry("https://registry.example.com", 'registry-credentials') {
                        def image = docker.build("${DOCKER_IMAGE}:${env.BUILD_NUMBER}")
                        image.push()
                        image.push('latest')
                    }
                }
            }
        }

        // ===== DEPLOY =====
        stage('Deploy') {
            when {
                branch 'main'
            }
            steps {
                input message: 'Deploy to production?',
                      ok: 'Deploy',
                      submitter: 'admin,devops'
                sh '''
                    ssh deploy@production-server \
                      "cd /app && docker compose pull && docker compose up -d"
                '''
            }
        }
    }

    // Pipeline-wide post actions
    post {
        success {
            slackSend(
                channel: '#builds',
                color: 'good',
                message: "✅ ${env.JOB_NAME} #${env.BUILD_NUMBER} - SUCCESS"
            )
        }
        failure {
            slackSend(
                channel: '#builds',
                color: 'danger',
                message: "❌ ${env.JOB_NAME} #${env.BUILD_NUMBER} - FAILED"
            )
        }
        always {
            cleanWs()  // Cleanup workspace
        }
    }
}

Pipeline Directives Reference

Directive Fungsi Scope
agentDi mana job dijalankanpipeline / stage
stagesKumpulan stage berurutanpipeline
stageSatu tahap dalam pipelinestages
stepsAksi yang dijalankanstage
environmentEnvironment variablespipeline / stage
toolsBuild tools (Maven, Node, dll)pipeline / stage
optionsPipeline options (timeout, retry)pipeline / stage
triggersJadwal eksekusi pipelinepipeline
whenKondisi eksekusi stagestage
inputManual approval gatestage
parallelStage berjalan paralelstage
postAksi setelah stage/pipeline selesaipipeline / stage

4. Scripted Pipeline

Scripted Pipeline menggunakan sintaks Groovy penuh, memberikan fleksibilitas maksimum tetapi lebih kompleks. Cocok untuk pipeline yang memerlukan logika tingkat lanjut.

Groovy — Scripted Pipeline
// Jenkinsfile — Scripted Pipeline
// Fleksibilitas penuh dengan Groovy

node('linux') {
    def app
    def version

    try {
        // ===== CHECKOUT =====
        stage('Checkout') {
            checkout scm
            version = sh(script: 'git describe --tags --always', returnStdout: true).trim()
            echo "Building version: ${version}"
        }

        // ===== BUILD =====
        stage('Build') {
            // Conditional logic
            if (env.BRANCH_NAME == 'main') {
                sh 'npm ci --production'
            } else {
                sh 'npm ci'
            }
            sh 'npm run build'
        }

        // ===== TEST =====
        stage('Test') {
            // Parallel execution
            parallel(
                'Unit Tests': {
                    sh 'npm run test:unit'
                },
                'Integration Tests': {
                    sh 'npm run test:integration'
                },
                'Lint': {
                    sh 'npm run lint'
                }
            )
        }

        // ===== DOCKER BUILD =====
        stage('Docker Build') {
            if (env.BRANCH_NAME == 'main') {
                docker.withRegistry('https://registry.example.com', 'registry-creds') {
                    app = docker.build("myapp:${version}")
                    app.push()
                    app.push('latest')
                }
            }
        }

        // ===== DEPLOY =====
        stage('Deploy') {
            if (env.BRANCH_NAME == 'main') {
                def proceed = input(
                    message: 'Deploy to production?',
                    ok: 'Deploy',
                    parameters: [
                        string(name: 'ENVIRONMENT', defaultValue: 'production')
                    ]
                )
                echo "Deploying to: ${proceed}"
                sh "./deploy.sh ${proceed} ${version}"
            }
        }

    } catch (e) {
        currentBuild.result = 'FAILURE'
        throw e
    } finally {
        // Cleanup
        cleanWs()

        // Notification
        if (currentBuild.result == 'FAILURE') {
            slackSend(color: 'danger', message: "Build failed: ${env.JOB_NAME}")
        }
    }
}

Declarative vs Scripted

Aspek Declarative Scripted
Sintaks🟢 Terstruktur, mudah dibaca🟡 Groovy penuh
Validasi🟢 Bisa di-validate sebelum run🔴 Runtime error
Flexibility🟡 Terbatas pada directive🟢 Sangat fleksibel
Learning Curve🟢 Lebih mudah🟡 Butuh Groovy knowledge
Rekomendasi🟢 Utama🟡 Untuk kasus kompleks

5. Essential Plugins

Jenkins memiliki lebih dari 1,800 plugins. Berikut plugin-plugin yang paling sering digunakan:

Must-Have Plugins

Plugin Fungsi Kategori
Blue OceanModern UI untuk pipeline visualizationUI
PipelineSupport untuk JenkinsfileCore
GitGit integrationSCM
Docker PipelineBuild & deploy Docker imagesDocker
SSH AgentInject SSH keys ke pipelineSecurity
Credentials BindingInject credentials ke buildSecurity
SonarQube ScannerCode quality analysisQuality
Slack NotificationNotify ke SlackNotification
Publish HTMLPublish HTML reportsReporting
JUnitTest report integrationTesting
NodeJSNode.js tool installationBuild Tools
Job DSLProgrammatically create jobsAutomation
Role-Based AuthorizationAccess control per roleSecurity
Parameterized TriggerTrigger other jobs with parametersPipeline

Install Plugins

Text
# Install plugins via Jenkins UI:
# 1. Buka Manage Jenkins > Plugins > Available plugins
# 2. Cari plugin yang diinginkan
# 3. Centang dan klik "Install without restart"
# 4. Restart Jenkins setelah semua plugin terinstall

# Atau via Jenkins CLI:
java -jar jenkins-cli.jar -s http://localhost:8080/ \
  -auth admin:password \
  install-plugin blueocean \
  docker-workflow \
  pipeline-stage-view \
  slack \
  sonar \
  nodejs

# Restart setelah install
java -jar jenkins-cli.jar -s http://localhost:8080/ \
  -auth admin:password safe-restart

6. Distributed Agents/Nodes

Jenkins mendukung distributed builds — menjalankan jobs di server terpisah (agents/nodes). Ini memungkinkan Anda menjalankan build di berbagai OS, membagi beban, dan mengisolasi environment.

Agent Types

Agent Type Konfigurasi Cocok Untuk
anyGunakan agent mana saja yang tersediaSimple jobs
agent { label 'linux' }Agent dengan label tertentuTargeted jobs
agent { docker { ... } }Jalankan di Docker containerIsolated environment
agent { node { label '...' } }Specific nodeHardware-specific

Setup Distributed Agent

Bash
# ===========================
# SETUP REMOTE AGENT
# ===========================

# 1. Di Jenkins UI: Manage Jenkins > Nodes > New Node
# 2. Isi nama node, pilih "Permanent Agent"
# 3. Set:
#    - Remote root directory: /var/jenkins
#    - Labels: linux, docker
#    - Launch method: Launch agents via SSH
#    - Host: agent-host.example.com
#    - Credentials: SSH key

# Atau via command line (agent side):
# Download agent.jar dari Jenkins controller
curl -O http://jenkins:8080/jnlpJars/agent.jar

# Connect agent
java -jar agent.jar \
  -url http://jenkins:8080/ \
  -secret @secret-file \
  -name "my-agent" \
  -workDir "/var/jenkins"

# ===========================
# DOCKER AGENT
# ===========================
# Jenkinsfile: Jalankan di Docker container

Using Docker Agents di Jenkinsfile

Groovy — Docker Agent
// Jalankan pipeline di Docker container
pipeline {
    agent {
        docker {
            image 'node:20-alpine'
            args '-v /tmp:/tmp -e NODE_ENV=test'
        }
    }
    stages {
        stage('Test') {
            steps {
                sh 'node --version'
                sh 'npm ci'
                sh 'npm test'
            }
        }
    }
}

// Multiple agents per stage
pipeline {
    agent none
    stages {
        stage('Build') {
            agent {
                docker { image 'node:20-alpine' }
            }
            steps {
                sh 'npm run build'
            }
        }
        stage('Test') {
            agent {
                docker { image 'cypress/included:13.6.0' }
            }
            steps {
                sh 'npx cypress run'
            }
        }
        stage('Deploy') {
            agent {
                label 'deploy-server'
            }
            steps {
                sh './deploy.sh'
            }
        }
    }
}
💡 Tips

Gunakan label yang deskriptif untuk agents: linux, docker, gpu, deploy. Ini memudahkan penempatan jobs ke agent yang tepat. Gunakan Docker agents untuk isolasi yang lebih baik — setiap build mendapat container bersih.

7. Credentials Management

Jenkins Credentials menyimpan secrets secara terenkripsi dan menyediakannya ke pipeline tanpa mengekspos ke logs.

Jenis Credentials

Tipe Penggunaan Contoh
Username with PasswordGit auth, Docker registrycredentials('git-creds')
SSH Username with KeySSH ke serversshagent(['ssh-key'])
Secret TextAPI keys, tokenscredentials('api-token')
Secret FileJSON key, certificatecredentials('service-account')

Menggunakan Credentials di Pipeline

Groovy — Credentials Usage
// Menggunakan credentials di Jenkinsfile
pipeline {
    agent any
    environment {
        // Secret text → environment variable
        API_TOKEN = credentials('my-api-token')
        // Username/password → USERN dan PASSW
        REGISTRY_CREDS = credentials('docker-registry')
    }
    stages {
        stage('Git Clone') {
            steps {
                // Git credentials via credential-id
                git url: 'https://gitlab.com/private/repo.git',
                    branch: 'main',
                    credentialsId: 'git-ssh-key'
            }
        }

        stage('Docker Push') {
            steps {
                // Username/password credentials
                sh 'echo $REGISTRY_CREDS_PSW | docker login -u $REGISTRY_CREDS_USR --password-stdin'
                sh 'docker build -t myapp .'
                sh 'docker push myapp'
            }
        }

        stage('Deploy') {
            steps {
                // SSH credentials
                sshagent(credentials: ['deploy-ssh-key']) {
                    sh 'ssh deploy@server "cd /app && ./update.sh"'
                }
            }
        }

        stage('API Call') {
            steps {
                // Secret text credential
                sh '''
                    curl -H "Authorization: Bearer $API_TOKEN" \
                         https://api.example.com/deploy
                '''
            }
        }

        stage('Using Secret File') {
            steps {
                withCredentials([file(credentialsId: 'gcloud-key', variable: 'GCloud_KEY')]) {
                    sh 'gcloud auth activate-service-account --key-file=$GCloud_KEY'
                }
            }
        }
    }
}
⚠️ Peringatan

Jangan pernah echo atau print credentials di pipeline script. Jenkins otomatis menyensor credential values di logs, tetapi pastikan Anda juga tidak menyimpannya ke file yang bisa diakses. Gunakan withCredentials block agar credentials hanya tersedia di scope yang tepat.

8. Shared Libraries

Shared Libraries memungkinkan Anda reuse pipeline code di antara banyak project. Ini sangat penting untuk organisasi dengan banyak repositories.

Struktur Shared Library

Text — Directory Structure
# Shared Library Repository Structure
(jenkins-shared-library/)
├── vars/                      # Global variables/functions
│   ├── buildNodeApp.groovy    # Callable dari Jenkinsfile
│   ├── deployToK8s.groovy
│   ├── sendNotification.groovy
│   └── standardPipeline.groovy
├── src/                       # Groovy classes
│   └── com/
│       └── beebanelabs/
│           └── ci/
│               └── Docker.groovy
├── resources/                 # Non-Groovy files
│   └── templates/
│       └── k8s-deployment.yml
└── README.md
Groovy — Shared Library Functions
// vars/buildNodeApp.groovy — Reusable build function
def call(Map config = [:]) {
    def nodeVersion = config.nodeVersion ?: '20'
    def buildCommand = config.buildCommand ?: 'npm run build'

    pipeline {
        agent {
            docker { image "node:${nodeVersion}-alpine" }
        }
        environment {
            NODE_ENV = config.environment ?: 'production'
        }
        stages {
            stage('Install') {
                steps {
                    sh 'npm ci --cache .npm'
                }
            }
            stage('Build') {
                steps {
                    sh buildCommand
                }
            }
            stage('Test') {
                steps {
                    sh 'npm test'
                }
            }
        }
        post {
            always {
                cleanWs()
            }
        }
    }
}

// vars/sendNotification.groovy
def call(String status = 'SUCCESS', String channel = '#builds') {
    def color = status == 'SUCCESS' ? 'good' : 'danger'
    def emoji = status == 'SUCCESS' ? '✅' : '❌'

    slackSend(
        channel: channel,
        color: color,
        message: "${emoji} ${env.JOB_NAME} #${env.BUILD_NUMBER} - ${status}"
    )
}

Menggunakan Shared Library

Groovy — Using Shared Library
// Jenkinsfile — Menggunakan shared library
// Konfigurasi library: Manage Jenkins > System > Global Pipeline Libraries

@Library('jenkins-shared-library@main') _

// Method 1: Langsung gunakan fungsi
buildNodeApp(
    nodeVersion: '20',
    buildCommand: 'npm run build:prod',
    environment: 'production'
)

// Method 2: Custom pipeline dengan shared function
pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                // Fungsi dari shared library
                buildAndTest(nodeVersion: '20')
            }
        }
        stage('Deploy') {
            steps {
                deployToK8s(
                    namespace: 'production',
                    imageTag: env.BUILD_NUMBER
                )
            }
        }
    }
    post {
        failure {
            sendNotification('FAILURE')
        }
        success {
            sendNotification('SUCCESS')
        }
    }
}

9. Docker Integration

Jenkins memiliki integrasi Docker yang sangat baik. Anda bisa build images, push ke registry, dan bahkan menjalankan pipeline di dalam Docker containers. Lihat tutorial Docker Dasar dan Docker Compose Advanced untuk konsep dasar.

Groovy — Docker Pipeline
// Docker integration di Jenkinsfile
pipeline {
    agent any
    environment {
        REGISTRY = 'registry.example.com'
        IMAGE_NAME = "${REGISTRY}/myapp"
    }
    stages {
        stage('Build Image') {
            steps {
                script {
                    // Build Docker image
                    def image = docker.build("${IMAGE_NAME}:${env.BUILD_NUMBER}",
                        "--build-arg VERSION=${env.BUILD_NUMBER} .")

                    // Push ke registry
                    docker.withRegistry("https://${REGISTRY}", 'registry-credentials') {
                        image.push()
                        image.push('latest')
                    }
                }
            }
        }

        stage('Test in Container') {
            steps {
                // Jalankan test di container
                docker.image('node:20-alpine').inside {
                    sh 'npm ci'
                    sh 'npm test'
                }
            }
        }

        stage('Deploy with Docker Compose') {
            steps {
                sshagent(['deploy-key']) {
                    sh """
                        ssh deploy@server '
                            cd /app
                            export IMAGE_TAG=${env.BUILD_NUMBER}
                            docker compose -f docker-compose.prod.yml pull
                            docker compose -f docker-compose.prod.yml up -d
                            docker system prune -f
                        '
                    """
                }
            }
        }

        stage('Multi-Container Test') {
            steps {
                // Jalankan dengan service containers
                docker.image('node:20-alpine').inside(
                    '--link postgres:postgres --link redis:redis'
                ) {
                    sh 'npm run test:integration'
                }
            }
        }
    }
    post {
        always {
            // Cleanup Docker images lama
            sh 'docker image prune -f'
        }
    }
}

10. Best Practices & Tips

Jenkinsfile Best Practices

Groovy — Best Practices
// ===========================
// BEST PRACTICES
// ===========================

pipeline {
    agent any

    // 1. SELALU set timeout
    options {
        timeout(time: 30, unit: 'MINUTES')
        timestamps()
        buildDiscarder(logRotator(
            artifactNumToKeepStr: '5',
            numToKeepStr: '20'
        ))
        disableConcurrentBuilds()
    }

    // 2. SELALU gunakan post actions
    post {
        always {
            // Cleanup workspace
            cleanWs()
            // Publish test results
            junit allowEmptyResults: true, testResults: '**/test-results/*.xml'
        }
        failure {
            // Notifikasi
            emailext(
                subject: "FAILED: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
                body: '${DEFAULT_CONTENT}',
                to: 'team@example.com'
            )
        }
    }

    stages {
        stage('Build') {
            steps {
                // 3. JANGAN hardcode credentials
                // ❌ sh 'docker login -u admin -p secret'
                // ✅ withCredentials([...]) { sh 'docker login ...' }

                // 4. JANGAN swallow errors
                // ❌ sh 'npm test || true'
                // ✅ sh 'npm test' (biarkan fail jika test gagal)

                // 5. SELALU archive artifacts penting
                sh 'npm run build'
            }
            post {
                success {
                    archiveArtifacts artifacts: 'dist/**', fingerprint: true
                }
            }
        }

        stage('Test') {
            steps {
                // 6. Parallel test untuk kecepatan
                parallel(
                    'Unit': { sh 'npm run test:unit' },
                    'Integration': { sh 'npm run test:integration' },
                    'Lint': { sh 'npm run lint' }
                )
            }
        }
    }
}

Jenkins Administration Tips

Area Tip Prioritas
BackupBackup JENKINS_HOME secara berkala🔴 Kritis
SecurityEnable CSRF protection, matrix auth🔴 Kritis
MonitoringMonitor disk space, executor usage🟡 Tinggi
PerformanceRotate build logs, limit artifact retention🟡 Tinggi
UpdatesUpdate Jenkins & plugins secara berkala🟡 Tinggi
AccessImplementasikan RBAC (Role-Based Access Control)🟡 Tinggi

11. Quiz Pemahaman

Uji pemahaman Anda tentang Jenkins:

1. Apa perbedaan utama antara Declarative dan Scripted Pipeline?

2. Apa fungsi dari Jenkins Agent/Node?

3. Mengapa credentials tidak boleh di-hardcode di Jenkinsfile?

4. Apa fungsi Shared Libraries di Jenkins?

5. Apa fungsi keyword input di Jenkinsfile?

🔍 Zoom
100%
🎨 Tema