Kalau anda dah sampai bab ni, tahniah — anda dah melepasi tahap beginner! Bab ini adalah untuk anda yang dah selesa dengan Ansible asas dan monitoring, dan nak naik satu level lagi.
Kita akan belajar tentang CI/CD (Continuous Integration/Continuous Deployment), Ansible Roles yang lebih teratur, skrip penyelenggaraan automatik, dan cara buat dokumentasi yang generate sendiri. Ini bukan benda wajib untuk homelab, tapi percayalah — bila anda dah biasa, anda tak akan mahu balik ke cara lama.
Apa yang anda akan belajar:
Nota Beginner: Bab ini ialah upgrade kepada asas yang sudah stabil. Kalau anda masih baru dengan Docker atau Ansible, tak mengapa untuk tangguhkan bahagian ini dahulu. Balik bila anda dah selesa dengan bab-bab sebelumnya.
Kalau anda pernah guna GitHub Actions, Gitea Actions akan terasa sangat familiar. Bezanya, semua berjalan dalam homelab anda sendiri. Tiada bergantung pada cloud, tiada limit minutes.
Bayangkan: anda push code ke Gitea, dan secara automatik, code tu dibina, diuji, dan di-deploy ke server anda. Semua tanpa anda perlu SSH manual.
# docker-compose.yml - Gitea dengan Runner services: gitea: image: gitea/gitea:latest container_name: gitea ports: - "3000:3000" - "2222:22" environment: USER_UID: 1000 USER_GID: 1000 GITEA__actions__ENABLED: "true" volumes: - ./gitea/data:/data restart: unless-stopped gitea-runner: image: gitea/act_runner:latest container_name: gitea-runner environment: GITEA_INSTANCE_URL: "http://gitea:3000" GITEA_RUNNER_REGISTRATION_TOKEN: "token_pendaftaran_anda" GITEA_RUNNER_NAME: "homelab-runner" volumes: - /var/run/docker.sock:/var/run/docker.sock - ./runner/data:/data depends_on: - gitea restart: unless-stopped
Ini contoh workflow yang paling asas. Bila anda push ke branch main, ia akan build Docker image dan deploy:
main
# .gitea/workflows/deploy.yml name: Deploy ke Homelab on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout kod uses: actions/checkout@v4 - name: Bina imej Docker run: | docker build -t app:latest . - name: Deploy ke pelayan run: | docker compose -f docker-compose.prod.yml up -d - name: Pemberitahuan run: | curl -d "Deploy berjaya: ${{ github.sha }}" \ http://ntfy.lab.local/deployments
Nota Beginner: Perhatikan step terakhir — ia hantar notification bila deploy berjaya. Ini amalan yang baik supaya anda sentiasa tahu apa yang berlaku dalam homelab.
Ini contoh workflow yang lebih praktikal — backup harian yang berjalan secara automatik:
# .gitea/workflows/backup.yml name: Backup Harian on: schedule: - cron: '0 3 * * *' # Setiap hari jam 3 pagi jobs: backup: runs-on: ubuntu-latest steps: - name: Backup pangkalan data run: | docker exec nextcloud-db mysqldump \ -u root -p$DB_ROOT_PASS nextcloud \ > /backup/nextcloud-db-$(date +%Y%m%d).sql - name: Backup konfigurasi Docker run: | tar czf /backup/docker-config-$(date +%Y%m%d).tar.gz \ /opt/docker/ - name: Muat naik ke NAS run: | rsync -av /backup/ nas:/mnt/pool/backups/gitea-runner/ - name: Bersihkan backup lama run: | find /backup/ -name "*.sql" -mtime +7 -delete find /backup/ -name "*.tar.gz" -mtime +7 -delete
Dalam bab sebelumnya, kita guna playbook biasa. Sekarang, kita naik taraf ke Roles — cara yang lebih teratur untuk susun Ansible code. Macam susun baju dalam almari berbanding campak semua dalam satu laci.
roles/ ├── common/ │ ├── tasks/ │ │ └── main.yml │ ├── handlers/ │ │ └── main.yml │ ├── templates/ │ │ └── sshd_config.j2 │ └── defaults/ │ └── main.yml ├── docker/ │ ├── tasks/ │ │ └── main.yml │ ├── handlers/ │ │ └── main.yml │ └── templates/ │ └── daemon.json.j2 └── monitoring/ ├── tasks/ │ └── main.yml └── templates/ └── prometheus.yml.j2
Ini contoh role untuk install dan configure Docker. Tulis sekali, guna untuk semua server:
# roles/docker/tasks/main.yml --- - name: Pasang kebergantungan Docker apt: name: - ca-certificates - curl - gnupg state: present update_cache: yes - name: Tambah kunci GPG Docker apt_key: url: https://download.docker.com/linux/ubuntu/gpg state: present - name: Tambah repositori Docker apt_repository: repo: "deb https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable" state: present - name: Pasang Docker apt: name: - docker-ce - docker-ce-cli - containerd.io - docker-compose-plugin state: present update_cache: yes - name: Tambah pengguna ke kumpulan docker user: name: "{{ ansible_user }}" groups: docker append: yes - name: Konfigurasi Docker daemon template: src: daemon.json.j2 dest: /etc/docker/daemon.json notify: restart docker - name: Pastikan Docker berjalan service: name: docker state: started enabled: yes
// roles/docker/templates/daemon.json.j2 { "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" }, "default-address-pools": [ { "base": "172.17.0.0/12", "size": 24 } ], "storage-driver": "overlay2", "live-restore": true }
# roles/docker/handlers/main.yml --- - name: restart docker service: name: docker state: restarted
Nota Beginner: Perhatikan notify: restart docker dalam task konfigurasi. Ini bermakna Docker hanya akan restart kalau config memang berubah. Kalau config sama, ia tak restart — jimat downtime.
notify: restart docker
# roles/monitoring/tasks/main.yml --- - name: Cipta pengguna node_exporter user: name: node_exporter shell: /bin/false system: yes create_home: no - name: Muat turun Node Exporter get_url: url: "https://github.com/prometheus/node_exporter/releases/download/v{{ node_exporter_version }}/node_exporter-{{ node_exporter_version }}.linux-amd64.tar.gz" dest: /tmp/node_exporter.tar.gz - name: Ekstrak Node Exporter unarchive: src: /tmp/node_exporter.tar.gz dest: /usr/local/bin/ remote_src: yes extra_opts: - --strip-components=1 - --wildcards - "*/node_exporter" - name: Cipta perkhidmatan systemd copy: content: | [Unit] Description=Node Exporter After=network.target [Service] User=node_exporter ExecStart=/usr/local/bin/node_exporter Restart=always [Install] WantedBy=multi-user.target dest: /etc/systemd/system/node_exporter.service - name: Aktifkan dan mulakan Node Exporter systemd: name: node_exporter state: started enabled: yes daemon_reload: yes
Semua role digabungkan dalam satu playbook utama. Satu command, semua server dikonfigurasikan:
# playbooks/site.yml - Playbook utama --- - name: Konfigurasi semua pelayan hosts: all become: yes roles: - common - monitoring - name: Konfigurasi host Docker hosts: docker_hosts become: yes roles: - docker - name: Deploy stack Docker hosts: docker_hosts become: yes tasks: - name: Salin docker-compose.yml copy: src: ../docker/docker-compose.yml dest: /opt/docker/docker-compose.yml - name: Salin fail .env template: src: ../docker/.env.j2 dest: /opt/docker/.env mode: '0600' - name: Mulakan stack Docker shell: | cd /opt/docker && docker compose pull && docker compose up -d
Ini skrip “all-in-one” yang saya jalankan setiap minggu. Ia update sistem, bersihkan Docker, check disk health, dan hantar laporan. Set and forget:
#!/bin/bash # /usr/local/bin/weekly-maintenance.sh # Jalankan setiap Ahad jam 4 pagi LOG="/var/log/maintenance.log" echo "=== Penyelenggaraan Mingguan: $(date) ===" >> "$LOG" # 1. Kemas kini sistem echo "Mengemas kini sistem..." >> "$LOG" apt update && apt upgrade -y >> "$LOG" 2>&1 # 2. Kemas kini kontena Docker echo "Mengemas kini kontena Docker..." >> "$LOG" cd /opt/docker docker compose pull >> "$LOG" 2>&1 docker compose up -d >> "$LOG" 2>&1 # 3. Bersihkan Docker echo "Membersihkan Docker..." >> "$LOG" docker system prune -af --volumes >> "$LOG" 2>&1 # 4. Bersihkan log lama echo "Membersihkan log..." >> "$LOG" journalctl --vacuum-time=30d >> "$LOG" 2>&1 find /var/log -name "*.gz" -mtime +30 -delete # 5. Periksa kesihatan cakera echo "Memeriksa kesihatan cakera..." >> "$LOG" for disk in /dev/sd?; do smartctl -H "$disk" >> "$LOG" 2>&1 done # 6. Periksa penggunaan storan echo "Penggunaan storan:" >> "$LOG" df -h >> "$LOG" 2>&1 # 7. Periksa ZFS (jika ada) if command -v zpool &> /dev/null; then echo "Status ZFS:" >> "$LOG" zpool status >> "$LOG" 2>&1 fi # 8. Hantar laporan SUMMARY=$(tail -50 "$LOG") curl -d "$SUMMARY" http://ntfy.lab.local/maintenance echo "=== Penyelenggaraan selesai: $(date) ===" >> "$LOG"
# Tambah ke crontab sudo crontab -e 0 4 * * 0 /usr/local/bin/weekly-maintenance.sh
Nota Beginner: Perhatikan docker system prune -af --volumes dalam skrip tu. Ini akan padam semua image, container, dan volume yang tak digunakan. Bagus untuk jimat disk space, tapi pastikan semua container penting anda memang running sebelum jalankan skrip ni.
docker system prune -af --volumes
Ini skrip kecil tapi sangat berguna. Ia check semua sijil SSL anda dan alert kalau ada yang nak tamat:
#!/bin/bash # /usr/local/bin/check-ssl-expiry.sh DOMAINS=( "cloud.lab.local" "git.lab.local" "vault.lab.local" "grafana.lab.local" ) for domain in "${DOMAINS[@]}"; do EXPIRY=$(echo | openssl s_client -servername "$domain" \ -connect "$domain:443" 2>/dev/null | \ openssl x509 -noout -enddate 2>/dev/null | \ cut -d= -f2) if [ -n "$EXPIRY" ]; then DAYS_LEFT=$(( ($(date -d "$EXPIRY" +%s) - $(date +%s)) / 86400 )) if [ "$DAYS_LEFT" -lt 30 ]; then curl -d "Amaran: Sijil SSL untuk $domain tamat dalam $DAYS_LEFT hari!" \ http://ntfy.lab.local/ssl-alerts fi fi done
Sekarang anda dah ada Grafana dari bab sebelumnya, jom buat dashboard yang lebih power.
Cipta papan pemuka Grafana yang menunjukkan keseluruhan homelab anda dalam satu pandangan:
Panel Disyorkan:
Nak buat dashboard yang lebih interaktif? Guna variabel supaya anda boleh tukar antara server dengan satu klik:
# Variabel 'host' Type: Query Data source: Prometheus Query: label_values(node_uname_info, instance) # Gunakan dalam panel: node_cpu_seconds_total{instance="$host"}
Tandakan peristiwa penting pada graf Grafana. Contohnya, bila deploy berlaku, anda boleh nampak tepat pada graf kalau ada kesan ke prestasi:
# Hantar anotasi apabila deploy berlaku curl -X POST http://grafana.lab.local/api/annotations \ -H "Authorization: Bearer api-key-anda" \ -H "Content-Type: application/json" \ -d '{ "text": "Deploy v1.2.3", "tags": ["deploy", "production"] }'
Ini perkara yang saya belajar dengan cara yang susah. Mula-mula setup monitoring, saya alert SEMUA benda. CPU naik sikit — alert. Disk usage naik 1% — alert. Hasilnya? Saya abaikan semua notification sebab terlalu banyak.
Jangan buat macam saya. Konfigurasi amaran dengan bijak:
# Tahap amaran: # 1. Info — Log sahaja, tiada pemberitahuan # 2. Warning — Pemberitahuan sekali, boleh ditunggu # 3. Critical — Pemberitahuan segera, perlu tindakan # Contoh peraturan: rules: # CRITICAL: Pelayan tidak boleh diakses - alert: ServerDown expr: up == 0 for: 2m severity: critical # WARNING: CPU tinggi (mungkin beban sementara) - alert: HighCPU expr: cpu_usage > 90 for: 15m # Tunggu 15 minit sebelum amaran severity: warning # INFO: Cakera hampir penuh (masih ada masa) - alert: DiskAlmostFull expr: disk_usage > 80 for: 1h severity: info
Setup saluran pemberitahuan mengikut keutamaan. Tak semua alert perlu bunyi telefon anda:
Kritikal → Telegram + Ntfy (push notification) Amaran → Telegram sahaja Info → Log ke Grafana sahaja Jadual: Waktu kerja (8am-10pm): Semua pemberitahuan Malam (10pm-8am): Kritikal sahaja
Nota Beginner: Rule of thumb saya — kalau alert tu tak memerlukan tindakan segera, ia sepatutnya warning atau info, bukan critical. Critical bermakna “bangun tidur sekarang dan fix.”
Pernah tak seseorang tanya “server tu spec apa?” dan anda kena SSH satu-satu untuk check? Ansible CMDB selesaikan masalah tu:
# Pasang ansible-cmdb pip install ansible-cmdb # Kumpul fakta dari semua host ansible -i inventory/hosts.yml all -m setup --tree /tmp/facts # Jana laporan HTML ansible-cmdb /tmp/facts > homelab-inventory.html
Laporan ini mengandungi: - Senarai semua pelayan dengan spesifikasi - Versi OS dan kernel - Alamat IP dan MAC - Saiz RAM dan storan - Perisian yang dipasang
Skrip ni scan rangkaian anda dan generate dokumen secara automatik. Jalankan sebulan sekali dan anda sentiasa ada dokumentasi terkini:
#!/bin/bash # generate-network-doc.sh echo "# Dokumentasi Rangkaian Homelab" > network-doc.md echo "Dijana: $(date)" >> network-doc.md echo "" >> network-doc.md echo "## Peranti Aktif" >> network-doc.md nmap -sn 10.0.0.0/24 | grep "report\|MAC" >> network-doc.md echo "" >> network-doc.md echo "## Port Terbuka (Pelayan Utama)" >> network-doc.md nmap -sV 10.0.20.20 >> network-doc.md echo "" >> network-doc.md echo "## Rekod DNS" >> network-doc.md dig axfr lab.local @10.0.0.2 >> network-doc.md 2>/dev/null echo "" >> network-doc.md echo "## Kontena Docker" >> network-doc.md ssh admin@10.0.20.20 "docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'" >> network-doc.md
Wah, bab yang panjang! Tapi anda dah sampai penghujung. Jom recap apa yang kita dah cover:
Automasi yang baik membebaskan masa anda untuk belajar perkara baru dan menambah projek baru ke homelab. Daripada habiskan masa buat kerja berulang, anda boleh fokus pada eksperimen dan pembelajaran.
Percayalah, bila anda dah rasa nikmat automasi yang berjalan lancar, anda takkan mahu balik ke cara manual lagi. Selamat mengautomasikan!