CI/CD Integration

CI/CD Integration #

Menjalankan playbook secara manual dari laptop sudah cukup untuk awal. Tapi di lingkungan tim dan production yang matang, deployment harus bisa dipicu secara otomatis — setelah kode di-merge, setelah build berhasil, atau setelah approval diberikan. Mengintegrasikan Ansible ke dalam pipeline CI/CD mengubah otomasi dari alat individual menjadi bagian dari alur kerja tim yang konsisten dan auditable.

Pola Pipeline yang Direkomendasikan #

Pipeline yang baik mengikuti prinsip progressif — perubahan mengalir dari lingkungan yang paling tidak berisiko ke yang paling berisiko, dengan gate validasi di setiap tahap:

Push ke branch feature
        │
        ▼
Lint & Validate       ← ansible-lint, syntax check, molecule test
        │
        ▼
Deploy ke staging     ← otomatis setelah merge ke main
        │
        ▼
Integration test      ← verifikasi aplikasi di staging
        │
        ▼
Manual approval       ← persetujuan dari reviewer
        │
        ▼
Deploy ke production  ← hanya setelah approval
        │
        ▼
Smoke test           ← verifikasi production berjalan normal

GitHub Actions #

# .github/workflows/deploy.yml
name: Deploy dengan Ansible

on:
  push:
    branches: [main]
  workflow_dispatch:      # Bisa dipicu manual dari UI GitHub
    inputs:
      environment:
        description: "Target environment"
        required: true
        default: staging
        type: choice
        options: [staging, production]

jobs:
  validate:
    name: Lint dan Validasi
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - name: Install dependensi
        run: |
          pip install ansible ansible-lint
          ansible-galaxy install -r requirements.yml          

      - name: Cek syntax playbook
        run: ansible-playbook site.yml --syntax-check -i inventory/staging/

      - name: Jalankan ansible-lint
        run: ansible-lint site.yml

  deploy-staging:
    name: Deploy ke Staging
    needs: validate
    runs-on: ubuntu-latest
    environment: staging
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4

      - name: Setup Python dan Ansible
        run: pip install ansible

      - name: Install role dan collection
        run: ansible-galaxy install -r requirements.yml

      - name: Setup SSH key
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.STAGING_SSH_KEY }}" > ~/.ssh/id_ed25519
          chmod 600 ~/.ssh/id_ed25519          

      - name: Tulis vault password
        run: |
          echo "${{ secrets.VAULT_PASSWORD_STAGING }}" > /tmp/.vault_pass
          chmod 600 /tmp/.vault_pass          

      - name: Deploy ke staging
        run: |
          ansible-playbook -i inventory/staging/ site.yml \
            --vault-password-file /tmp/.vault_pass \
            --private-key ~/.ssh/id_ed25519          

      - name: Hapus credential setelah selesai
        if: always()
        run: |
          rm -f ~/.ssh/id_ed25519 /tmp/.vault_pass          

  deploy-production:
    name: Deploy ke Production
    needs: deploy-staging
    runs-on: ubuntu-latest
    environment:
      name: production      # Environment dengan required reviewers di GitHub
    steps:
      - uses: actions/checkout@v4

      - name: Setup dan deploy ke production
        run: |
          pip install ansible
          ansible-galaxy install -r requirements.yml
          echo "${{ secrets.PROD_SSH_KEY }}" > /tmp/id_ed25519
          echo "${{ secrets.VAULT_PASSWORD_PROD }}" > /tmp/.vault_pass
          chmod 600 /tmp/id_ed25519 /tmp/.vault_pass
          ansible-playbook -i inventory/production/ site.yml \
            --vault-password-file /tmp/.vault_pass \
            --private-key /tmp/id_ed25519
          rm -f /tmp/id_ed25519 /tmp/.vault_pass          
Di GitHub, gunakan fitur Environments untuk mendefinisikan required reviewers sebelum deployment ke production. Pipeline akan pause dan menunggu approval sebelum melanjutkan ke job deploy-production.

GitLab CI #

# .gitlab-ci.yml
stages:
  - validate
  - deploy-staging
  - test-staging
  - deploy-production

variables:
  ANSIBLE_FORCE_COLOR: "true"
  ANSIBLE_HOST_KEY_CHECKING: "false"

.ansible_setup: &ansible_setup
  before_script:
    - pip install ansible
    - ansible-galaxy install -r requirements.yml
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo "$VAULT_PASSWORD" > /tmp/.vault_pass
    - chmod 600 /tmp/.vault_pass
  after_script:
    - rm -f /tmp/.vault_pass

lint:
  stage: validate
  image: python:3.11-slim
  script:
    - pip install ansible ansible-lint
    - ansible-playbook site.yml --syntax-check -i inventory/staging/
    - ansible-lint site.yml
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

check-production:
  stage: validate
  image: python:3.11-slim
  <<: *ansible_setup
  variables:
    SSH_PRIVATE_KEY: $PROD_SSH_KEY
    VAULT_PASSWORD: $VAULT_PASS_PROD
  script:
    - ansible-playbook -i inventory/production/ site.yml
        --check --diff
        --vault-password-file /tmp/.vault_pass
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

deploy-staging:
  stage: deploy-staging
  image: python:3.11-slim
  <<: *ansible_setup
  variables:
    SSH_PRIVATE_KEY: $STAGING_SSH_KEY
    VAULT_PASSWORD: $VAULT_PASS_STAGING
  script:
    - ansible-playbook -i inventory/staging/ site.yml
        --vault-password-file /tmp/.vault_pass
  environment:
    name: staging
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

deploy-production:
  stage: deploy-production
  image: python:3.11-slim
  <<: *ansible_setup
  variables:
    SSH_PRIVATE_KEY: $PROD_SSH_KEY
    VAULT_PASSWORD: $VAULT_PASS_PROD
  script:
    - ansible-playbook -i inventory/production/ site.yml
        --vault-password-file /tmp/.vault_pass
  environment:
    name: production
  when: manual              # Harus dipicu manual — tidak otomatis
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

Artifact dan Caching #

Menyimpan output pipeline sebagai artifact dan men-cache instalasi yang mahal:

# GitHub Actions — cache pip packages
- name: Cache pip packages
  uses: actions/cache@v4
  with:
    path: ~/.cache/pip
    key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}

# GitLab CI — cache pip packages
cache:
  key: ansible-deps-$CI_COMMIT_REF_SLUG
  paths:
    - .cache/pip
    - ~/.ansible/roles

Ringkasan #

  • Pola pipeline yang baik bersifat progresif: validate → staging → approval → production — perubahan mengalir dari risiko rendah ke tinggi.
  • Simpan semua credential (SSH key, vault password) sebagai CI/CD secrets — jangan pernah hardcode di file pipeline.
  • Hapus credential segera setelah digunakan di step CI/CD — gunakan if: always() di GitHub Actions untuk memastikan cleanup tetap berjalan meski pipeline gagal.
  • Gunakan fitur Environments (GitHub) atau when: manual (GitLab) untuk memerlukan approval sebelum deployment ke production.
  • Selalu jalankan --check --diff ke production di setiap pipeline — tampilkan perubahan yang akan terjadi bahkan sebelum ada yang approve.
  • Cache instalasi Ansible dan role/collection untuk mempercepat pipeline secara signifikan.

← Sebelumnya: Rolling Update   Berikutnya: Scheduled Task →

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