Notification & Reporting #
Pipeline yang selesai tanpa memberitahu siapapun adalah pipeline yang berjalan di kekosongan. Tim perlu tahu saat deployment berhasil, dan perlu tahu lebih cepat lagi saat deployment gagal. Tapi notifikasi yang berlebihan adalah noise yang diabaikan — sama buruknya dengan tidak ada notifikasi. Artikel ini membahas cara membangun sistem notifikasi yang informatif tanpa menjadi spam, dan laporan yang memberikan visibilitas nyata atas aktivitas deployment.
Notifikasi Slack yang Informatif #
# roles/notify/tasks/slack.yml
---
- name: Kirim notifikasi Slack
uri:
url: "{{ slack_webhook_url }}"
method: POST
body_format: json
body:
attachments:
- color: "{{ 'good' if status == 'success' else 'danger' }}"
title: >
{{ '✅' if status == 'success' else '❌' }}
{{ title }}
fields:
- title: Environment
value: "{{ env | upper }}"
short: true
- title: Versi
value: "{{ app_version }}"
short: true
- title: Waktu
value: "{{ ansible_date_time.iso8601 }}"
short: true
- title: Oleh
value: "{{ deployed_by | default('CI Pipeline') }}"
short: true
- title: Detail
value: "{{ detail | default('') }}"
short: false
footer: "Ansible Deployment"
ts: "{{ ansible_date_time.epoch }}"
delegate_to: localhost
run_once: true
no_log: true
when: slack_webhook_url is defined
Penggunaan di playbook deployment:
# Di post_tasks playbook deploy
post_tasks:
- name: Notifikasi deployment sukses
include_role:
name: notify
tasks_from: slack.yml
vars:
status: success
title: "Deployment Berhasil — {{ app_name }}"
detail: >
Versi {{ app_version }} sukses di-deploy ke
{{ ansible_play_hosts | length }} server.
run_once: true
rescue:
- name: Notifikasi deployment gagal
include_role:
name: notify
tasks_from: slack.yml
vars:
status: failure
title: "Deployment GAGAL — {{ app_name }}"
detail: >
{{ ansible_failed_result.msg | default('Error tidak diketahui') }}
di {{ inventory_hostname }}
run_once: true
Notifikasi Email untuk Summary Harian #
# playbooks/daily-deployment-summary.yml
---
- name: Generate dan kirim summary deployment harian
hosts: localhost
vars:
log_file: /var/log/deployments.log
report_date: "{{ ansible_date_time.date }}"
tasks:
- name: Baca log deployment hari ini
shell: "grep {{ report_date }} {{ log_file }} || echo 'Tidak ada deployment hari ini'"
register: today_deployments
changed_when: false
- name: Hitung statistik deployment
set_fact:
total_deployments: "{{ today_deployments.stdout_lines | select('search', 'SUCCESS|ROLLBACK|FAILED') | list | length }}"
successful_deployments: "{{ today_deployments.stdout_lines | select('search', 'SUCCESS') | list | length }}"
failed_deployments: "{{ today_deployments.stdout_lines | select('search', 'FAILED|ROLLBACK') | list | length }}"
- name: Kirim email summary
community.general.mail:
host: "{{ smtp_host }}"
port: "{{ smtp_port | default(587) }}"
username: "{{ smtp_username }}"
password: "{{ vault_smtp_password }}"
to: "{{ deployment_report_recipients }}"
subject: "Deployment Summary {{ report_date }} — {{ successful_deployments }}/{{ total_deployments }} sukses"
subtype: html
body: |
<h2>Deployment Summary {{ report_date }}</h2>
<table border="1" cellpadding="5">
<tr><td><b>Total Deployment</b></td><td>{{ total_deployments }}</td></tr>
<tr><td><b>Sukses</b></td><td style="color:green">{{ successful_deployments }}</td></tr>
<tr><td><b>Gagal/Rollback</b></td><td style="color:red">{{ failed_deployments }}</td></tr>
</table>
<h3>Detail:</h3>
<pre>{{ today_deployments.stdout }}</pre>
no_log: true
Deployment Changelog Otomatis #
Generate changelog antara versi yang lama dan yang baru:
# tasks/generate-changelog.yml
---
- name: Generate changelog antara versi
shell: |
git log \
v{{ previous_version }}..v{{ current_version }} \
--oneline \
--no-merges \
--format="- %h %s (%an)"
args:
chdir: "{{ app_src_dir }}"
register: changelog_raw
changed_when: false
delegate_to: localhost
- name: Set changelog fact
set_fact:
deployment_changelog: "{{ changelog_raw.stdout }}"
- name: Kirim changelog ke Slack
uri:
url: "{{ slack_webhook_url }}"
method: POST
body_format: json
body:
text: "*Changelog v{{ previous_version }} → v{{ current_version }}*"
attachments:
- color: good
text: "{{ deployment_changelog | truncate(2000) }}"
delegate_to: localhost
no_log: true
when:
- deployment_changelog | length > 0
- slack_webhook_url is defined
Update Deployment Status di Sistem Eksternal #
# Catat deployment di Jira
- name: Tambahkan komentar di Jira issues yang ada di changelog
uri:
url: "https://company.atlassian.net/rest/api/3/issue/{{ item }}/comment"
method: POST
user: "{{ jira_username }}"
password: "{{ vault_jira_token }}"
force_basic_auth: true
body_format: json
body:
body:
type: doc
version: 1
content:
- type: paragraph
content:
- type: text
text: "Deployed to {{ env }} in version {{ app_version }}"
status_code: [201, 400] # 400 jika issue tidak ditemukan — tidak masalah
loop: "{{ jira_issues_in_changelog }}"
no_log: true
when: jira_issues_in_changelog | length > 0
# Catat deployment di Datadog sebagai event
- name: Catat deployment event di Datadog
uri:
url: "https://api.datadoghq.com/api/v1/events"
method: POST
headers:
DD-API-KEY: "{{ vault_datadog_api_key }}"
body_format: json
body:
title: "Deployment: {{ app_name }} v{{ app_version }}"
text: "Deploy ke {{ env }} oleh {{ deployed_by | default('pipeline') }}"
tags:
- "env:{{ env }}"
- "service:{{ app_name }}"
- "version:{{ app_version }}"
alert_type: info
source_type_name: ansible
delegate_to: localhost
no_log: true
Dashboard Deployment History #
# playbooks/generate-deployment-report.yml
---
- name: Generate HTML deployment report
hosts: localhost
tasks:
- name: Baca semua log deployment
slurp:
src: /var/log/deployments.log
register: raw_log
- name: Parse log deployment
set_fact:
deployments: >-
{{ raw_log.content | b64decode | split('\n')
| select('match', '.*SUCCESS|.*FAILED|.*ROLLBACK')
| list }}
- name: Generate HTML report
template:
src: deployment-report.html.j2
dest: /var/www/html/deployments/index.html
- name: Deploy report ke server internal
copy:
src: /var/www/html/deployments/index.html
dest: /var/www/reports/deployments.html
remote_src: false
Ringkasan #
- Notifikasi Slack yang informatif mencantumkan: environment, versi, waktu, siapa yang deploy, dan (saat gagal) pesan error yang jelas.
- Gunakan
run_once: trueuntuk notifikasi di playbook multi-host — cegah satu notifikasi per host saat play berjalan di banyak server.- Summary harian via email lebih baik dari notifikasi per-deployment untuk lingkungan staging yang sering deploy — kurangi noise sambil tetap memberikan visibilitas.
- Changelog otomatis dari
git logantara dua versi memberikan konteks ke tim tentang apa yang berubah — sangat berguna untuk review pasca-deployment.- Integrasikan deployment event ke Datadog/New Relic/Grafana sebagai annotation — langsung terlihat di dashboard metrik kapan deployment terjadi dan korelasinya dengan perubahan metrik.
- Notifikasi yang baik tidak mengganggu — kirim notifikasi sukses ke channel deployment, notifikasi gagal ke channel yang juga dimonitor on-call duty.
← Sebelumnya: Artifact Management Berikutnya: Best Practice →