Rolling Update

Rolling Update #

Deployment ke production yang menyebabkan downtime adalah hal yang tidak bisa diterima. Kubernetes menyediakan mekanisme rolling update bawaan — container lama digantikan container baru secara bertahap, memastikan selalu ada instance yang melayani traffic. Tapi rolling update yang benar-benar aman membutuhkan lebih dari sekadar kubectl set image — ia butuh health check yang proper, rollback otomatis saat terjadi masalah, dan orkestrasi yang memastikan semua langkah terjadi dalam urutan yang benar. Ansible memberikan kontrol penuh atas semua ini.

Anatomi Rolling Update yang Aman #

Langkah rolling update yang aman:

1. Backup state saat ini (catat versi yang sedang berjalan)
2. Verifikasi target image tersedia di registry
3. Update Deployment dengan image baru
4. Monitor rollout — tunggu setiap Pod baru siap sebelum lanjut
5. Jalankan smoke test setelah rollout selesai
6. Jika smoke test gagal → rollback otomatis ke versi sebelumnya
7. Notifikasi tim tentang hasil deployment

Implementasi Rolling Update dengan Ansible #

# playbooks/rolling-update.yml
---
- name: Rolling update aplikasi ke versi baru
  hosts: localhost
  vars:
    app_name: myapp
    app_namespace: production
    new_version: "{{ version | mandatory }}"   # -e version=2.2.0

  tasks:
    - name: Catat versi yang sedang berjalan (untuk rollback)
      kubernetes.core.k8s_info:
        kubeconfig: "{{ k8s_kubeconfig }}"
        kind: Deployment
        name: "{{ app_name }}"
        namespace: "{{ app_namespace }}"
      register: current_deployment

    - name: Simpan versi saat ini sebagai fact rollback
      set_fact:
        rollback_image: >-
          {{ current_deployment.resources[0].spec.template.spec.containers[0].image }}          

    - name: Debug — tampilkan versi saat ini dan target
      debug:
        msg:
          - "Versi saat ini: {{ rollback_image }}"
          - "Target versi: {{ app_image }}:{{ new_version }}"

    - name: Update image Deployment
      kubernetes.core.k8s:
        kubeconfig: "{{ k8s_kubeconfig }}"
        state: present
        definition:
          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: "{{ app_name }}"
            namespace: "{{ app_namespace }}"
          spec:
            template:
              metadata:
                annotations:
                  # Annotation ini memaksa Pod restart meski image tag sama
                  deployment-time: "{{ ansible_date_time.iso8601 }}"
              spec:
                containers:
                  - name: "{{ app_name }}"
                    image: "{{ app_image }}:{{ new_version }}"

    - name: Monitor rollout hingga selesai
      kubernetes.core.k8s_rollout_status:
        kubeconfig: "{{ k8s_kubeconfig }}"
        name: "{{ app_name }}"
        namespace: "{{ app_namespace }}"
        kind: Deployment
        timeout: 300
      register: rollout_status

    - name: Jalankan smoke test setelah rollout
      uri:
        url: "https://{{ app_domain }}/health"
        status_code: 200
        timeout: 10
      register: smoke_test
      retries: 5
      delay: 10

    - name: Rollback jika smoke test gagal
      command: >
        kubectl rollout undo deployment/{{ app_name }}
        -n {{ app_namespace }}
        --kubeconfig {{ k8s_kubeconfig }}        
      when: smoke_test.status != 200

    - name: Gagalkan playbook jika rollback dilakukan
      fail:
        msg: >
          Smoke test gagal setelah update ke {{ new_version }}!
          Rollback ke {{ rollback_image }} sudah dilakukan.
          Periksa log untuk investigasi lebih lanjut.          
      when: smoke_test.status != 200

Rollback Manual #

- name: Rollback ke versi sebelumnya
  hosts: localhost
  tasks:
    - name: Undo deployment ke revisi sebelumnya
      command: >
        kubectl rollout undo deployment/{{ app_name }}
        -n {{ app_namespace }}
        --kubeconfig {{ k8s_kubeconfig }}        
      register: rollback_result

    - name: Tunggu rollback selesai
      kubernetes.core.k8s_rollout_status:
        kubeconfig: "{{ k8s_kubeconfig }}"
        name: "{{ app_name }}"
        namespace: "{{ app_namespace }}"
        kind: Deployment
        timeout: 180

    - name: Verifikasi versi setelah rollback
      kubernetes.core.k8s_info:
        kubeconfig: "{{ k8s_kubeconfig }}"
        kind: Pod
        namespace: "{{ app_namespace }}"
        label_selectors:
          - "app={{ app_name }}"
      register: pod_info

    - name: Tampilkan image yang berjalan setelah rollback
      debug:
        msg: "Pod {{ item.metadata.name }} berjalan dengan image: {{ item.spec.containers[0].image }}"
      loop: "{{ pod_info.resources }}"
      loop_control:
        label: "{{ item.metadata.name }}"

Deployment Multi-Service yang Berurutan #

Saat aplikasi terdiri dari beberapa service yang saling bergantung, urutan update penting:

# playbooks/full-stack-update.yml
---
- name: Update full stack dengan urutan yang benar
  hosts: localhost
  vars:
    target_version: "{{ version | mandatory }}"

  tasks:
    # 1. Update database schema terlebih dahulu
    - name: Jalankan migrasi database
      kubernetes.core.k8s:
        kubeconfig: "{{ k8s_kubeconfig }}"
        state: present
        definition:
          apiVersion: batch/v1
          kind: Job
          metadata:
            name: "db-migration-{{ target_version | replace('.', '-') }}"
            namespace: production
          spec:
            template:
              spec:
                restartPolicy: Never
                containers:
                  - name: migration
                    image: "{{ app_image }}:{{ target_version }}"
                    command: ["python", "manage.py", "migrate"]

    - name: Tunggu migrasi database selesai
      kubernetes.core.k8s_info:
        kubeconfig: "{{ k8s_kubeconfig }}"
        kind: Job
        name: "db-migration-{{ target_version | replace('.', '-') }}"
        namespace: production
      register: migration_job
      until: >
        migration_job.resources[0].status.succeeded is defined and
        migration_job.resources[0].status.succeeded == 1        
      retries: 30
      delay: 10

    # 2. Update backend API
    - name: Update backend API
      kubernetes.core.k8s:
        kubeconfig: "{{ k8s_kubeconfig }}"
        state: present
        definition:
          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: backend-api
            namespace: production
          spec:
            template:
              spec:
                containers:
                  - name: backend-api
                    image: "{{ api_image }}:{{ target_version }}"

    - name: Tunggu backend API rollout
      kubernetes.core.k8s_rollout_status:
        kubeconfig: "{{ k8s_kubeconfig }}"
        name: backend-api
        namespace: production
        kind: Deployment
        timeout: 300

    # 3. Baru update frontend (setelah backend siap)
    - name: Update frontend
      kubernetes.core.k8s:
        kubeconfig: "{{ k8s_kubeconfig }}"
        state: present
        definition:
          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: frontend
            namespace: production
          spec:
            template:
              spec:
                containers:
                  - name: frontend
                    image: "{{ frontend_image }}:{{ target_version }}"

Ringkasan #

  • Catat versi yang sedang berjalan sebelum update — ini memungkinkan rollback yang tepat jika ada masalah.
  • Gunakan k8s_rollout_status untuk menunggu rollout selesai — jangan lanjutkan ke smoke test sebelum semua Pod baru siap.
  • Implementasikan rollback otomatis jika smoke test gagal — pipeline deployment yang baik tidak butuh intervensi manual untuk kasus ini.
  • Untuk multi-service, perhatikan urutan update: migrasi database dulu, baru backend, baru frontend — urutan terbalik bisa menyebabkan error runtime.
  • maxUnavailable: 0 dan maxSurge: 1 di Deployment strategy untuk zero-downtime — Kubernetes tidak akan terminate Pod lama sebelum Pod baru siap.
  • Simpan history rollout dengan kubectl rollout history — Kubernetes menyimpan beberapa revisi terakhir yang bisa di-rollback kapan saja.

← Sebelumnya: Cluster Maintenance   Berikutnya: CI/CD Integration →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact