GitHub Actions #
GitHub Actions adalah platform CI/CD yang terintegrasi langsung dengan repository GitHub. Untuk tim yang sudah menggunakan GitHub, integrasi ini sangat alami — workflow didefinisikan sebagai file YAML di direktori .github/workflows/, dipicu oleh event Git (push, pull_request, merge), dan berjalan di runner yang disediakan GitHub atau runner self-hosted milik sendiri. Artikel ini membahas pola integrasi Ansible dengan GitHub Actions yang komprehensif dan aman.
Workflow Dasar: Lint dan Syntax Check #
Setiap pull request harus melewati validasi sebelum bisa di-merge:
# .github/workflows/validate.yml
name: Validate Ansible
on:
pull_request:
paths:
- '**.yml'
- '**.yaml'
- '**.j2'
- 'roles/**'
- 'playbooks/**'
- 'inventory/**'
jobs:
lint:
name: Ansible Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Cache pip packages
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: pip-${{ hashFiles('requirements.txt', 'requirements-dev.txt') }}
restore-keys: pip-
- name: Install Ansible dan lint
run: |
pip install ansible ansible-lint
ansible-galaxy install -r requirements.yml
- name: Syntax check semua playbook
run: |
for playbook in playbooks/*.yml; do
echo "Checking: $playbook"
ansible-playbook "$playbook" --syntax-check \
-i inventory/staging/ \
-e @tests/test-vars.yml
done
- name: Jalankan ansible-lint
run: ansible-lint --profile production
Molecule Test di GitHub Actions #
# .github/workflows/molecule.yml
name: Molecule Test
on:
pull_request:
paths:
- 'roles/**'
jobs:
molecule:
name: Test Role — ${{ matrix.role }}
runs-on: ubuntu-latest
strategy:
matrix:
role:
- common
- nginx
- postgresql
- docker
fail-fast: false # Lanjutkan test role lain meski satu gagal
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Cache pip
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: molecule-${{ matrix.role }}-${{ hashFiles('**/requirements*.txt') }}
- name: Install test dependencies
run: |
pip install ansible molecule molecule-plugins[docker] pytest-testinfra
ansible-galaxy install -r requirements.yml
- name: Jalankan Molecule test
run: |
cd roles/${{ matrix.role }}
molecule test
env:
PY_COLORS: '1'
ANSIBLE_FORCE_COLOR: '1'
MOLECULE_DISTRO: ubuntu2204
- name: Upload test results
uses: actions/upload-artifact@v4
if: failure()
with:
name: molecule-logs-${{ matrix.role }}
path: roles/${{ matrix.role }}/molecule/default/*.log
Deployment Multi-Environment dengan Approval #
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
tags: ['v*.*.*']
jobs:
build:
name: Build dan Push Image
runs-on: ubuntu-latest
outputs:
image_tag: ${{ steps.tag.outputs.tag }}
steps:
- uses: actions/checkout@v4
- name: Generate tag
id: tag
run: echo "tag=${GITHUB_SHA::8}" >> $GITHUB_OUTPUT
- name: Login ke registry
uses: docker/login-action@v3
with:
registry: registry.company.com
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build dan push
uses: docker/build-push-action@v5
with:
push: true
tags: |
registry.company.com/myapp:${{ steps.tag.outputs.tag }}
registry.company.com/myapp:latest
deploy-staging:
name: Deploy ke Staging
needs: build
runs-on: ubuntu-latest
environment: staging
steps:
- uses: actions/checkout@v4
- name: Setup Ansible
run: pip install ansible && ansible-galaxy install -r requirements.yml
- name: Setup credentials
run: |
install -d -m 700 ~/.ssh
echo "${{ secrets.STAGING_SSH_KEY }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
echo "${{ secrets.VAULT_PASS_STAGING }}" > /tmp/.vault_pass
chmod 600 /tmp/.vault_pass
- name: Deploy ke staging
run: |
ansible-playbook -i inventory/staging/ playbooks/deploy.yml \
-e "app_version=${{ needs.build.outputs.image_tag }}" \
--vault-password-file /tmp/.vault_pass \
--private-key ~/.ssh/deploy_key
- name: Smoke test staging
run: |
sleep 15
curl -f https://staging.company.com/health
curl -f https://staging.company.com/api/version
- name: Cleanup credentials
if: always()
run: rm -f ~/.ssh/deploy_key /tmp/.vault_pass
deploy-production:
name: Deploy ke Production
needs: [build, deploy-staging]
runs-on: ubuntu-latest
environment:
name: production # Set required reviewers di GitHub Settings → Environments
url: https://app.company.com
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/checkout@v4
- name: Setup Ansible
run: pip install ansible && ansible-galaxy install -r requirements.yml
- name: Setup credentials
run: |
install -d -m 700 ~/.ssh
echo "${{ secrets.PROD_SSH_KEY }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
echo "${{ secrets.VAULT_PASS_PROD }}" > /tmp/.vault_pass
chmod 600 /tmp/.vault_pass
- name: Deploy ke production
run: |
ansible-playbook -i inventory/production/ playbooks/deploy.yml \
-e "app_version=${{ needs.build.outputs.image_tag }}" \
--vault-password-file /tmp/.vault_pass \
--private-key ~/.ssh/deploy_key
- name: Verifikasi production
run: |
sleep 30
curl -f https://app.company.com/health
- name: Cleanup
if: always()
run: rm -f ~/.ssh/deploy_key /tmp/.vault_pass
Reusable Workflow #
Untuk menghindari duplikasi konfigurasi deployment di banyak repository:
# .github/workflows/reusable-deploy.yml (di shared repository)
name: Reusable Deploy
on:
workflow_call: # Bisa dipanggil dari workflow lain
inputs:
environment:
required: true
type: string
image_tag:
required: true
type: string
playbook:
required: false
type: string
default: playbooks/deploy.yml
secrets:
ssh_key:
required: true
vault_password:
required: true
jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
steps:
- uses: actions/checkout@v4
- name: Deploy
run: |
pip install ansible && ansible-galaxy install -r requirements.yml
echo "${{ secrets.ssh_key }}" > /tmp/deploy_key
echo "${{ secrets.vault_password }}" > /tmp/.vault_pass
chmod 600 /tmp/deploy_key /tmp/.vault_pass
ansible-playbook -i inventory/${{ inputs.environment }}/ \
${{ inputs.playbook }} \
-e "app_version=${{ inputs.image_tag }}" \
--vault-password-file /tmp/.vault_pass \
--private-key /tmp/deploy_key
rm -f /tmp/deploy_key /tmp/.vault_pass
# Di repository aplikasi — panggil reusable workflow
jobs:
deploy-staging:
uses: company/shared-workflows/.github/workflows/reusable-deploy.yml@main
with:
environment: staging
image_tag: ${{ needs.build.outputs.tag }}
secrets:
ssh_key: ${{ secrets.STAGING_SSH_KEY }}
vault_password: ${{ secrets.VAULT_PASS_STAGING }}
Self-Hosted Runner untuk Akses Private Network #
Jika managed node ada di jaringan private yang tidak bisa diakses dari internet:
# roles/github-runner/tasks/main.yml
---
- name: Download GitHub Actions runner
get_url:
url: "https://github.com/actions/runner/releases/download/v{{ runner_version }}/actions-runner-linux-x64-{{ runner_version }}.tar.gz"
dest: /home/github-runner/actions-runner.tar.gz
- name: Extract runner
unarchive:
src: /home/github-runner/actions-runner.tar.gz
dest: /home/github-runner/
remote_src: true
- name: Konfigurasi runner
command: >
/home/github-runner/config.sh
--url https://github.com/{{ github_org }}
--token {{ vault_runner_token }}
--name {{ inventory_hostname }}
--labels self-hosted,production-network
--unattended
become_user: github-runner
- name: Install dan jalankan runner sebagai service
command: /home/github-runner/svc.sh install
become: true
Ringkasan #
- Pisahkan workflow:
validate.ymluntuk PR,molecule.ymluntuk test role,deploy.ymluntuk deployment — satu workflow fokus pada satu tujuan.environmentdengan required reviewers di GitHub Settings adalah cara termudah untuk memerlukan approval sebelum deploy ke production.- Gunakan
matrixuntuk menjalankan Molecule test semua role secara paralel — jauh lebih cepat dari test satu per satu.needs:+outputs:untuk meneruskan nilai antar job — image tag yang dihasilkan build job harus tersedia di deploy job.- Reusable workflow (
workflow_call) untuk berbagi konfigurasi deployment antar repository — satu perubahan di shared workflow langsung berlaku untuk semua aplikasi.- Self-hosted runner untuk akses ke managed node di private network — runner berjalan di dalam jaringan yang sama dengan server target.