Configuration Hot Reload #
Restart Pod setiap kali konfigurasi berubah menyebabkan downtime singkat dan mengganggu koneksi yang sedang berjalan. Hot reload memungkinkan aplikasi memperbarui konfigurasinya tanpa perlu restart — Pod tetap berjalan, koneksi tidak terputus, dan perubahan konfigurasi langsung berlaku. Namun hot reload tidak selalu lebih baik dari restart; ada trade-off yang perlu dipahami.
Cara Kubernetes Memperbarui ConfigMap Volume #
Saat ConfigMap yang di-mount sebagai volume diperbarui, Kubernetes secara otomatis memperbarui file di dalam container — tanpa restart Pod. Mekanismenya menggunakan atomic symlink swap:
Sebelum update:
/etc/config/
..data → ..2024_01_15_10_00_00/ (symlink ke direktori lama)
app.yaml → ..data/app.yaml (symlink ke file)
ConfigMap diperbarui via: kubectl apply -f new-configmap.yaml
Proses update (kubelet sync period, default ~1 menit):
1. Kubernetes buat direktori timestamp baru: ..2024_01_15_11_00_00/
2. Tulis file baru ke direktori baru
3. Atomik: update symlink ..data ke direktori baru
4. File lama masih ada sampai dibersihkan
Setelah update:
/etc/config/
..data → ..2024_01_15_11_00_00/ (symlink ke direktori baru)
app.yaml → ..data/app.yaml (masih symlink yang sama, tapi sekarang menunjuk ke file baru)
Perubahan ini terjadi tanpa restart container. Tapi aplikasi tetap harus membaca ulang file untuk mendapat konfigurasi baru.
Pola 1: inotify — Deteksi Perubahan File di Aplikasi #
Cara paling langsung: aplikasi secara aktif memantau perubahan file konfigurasi menggunakan inotify (Linux kernel facility) atau abstraksi di atasnya.
# Python: menggunakan watchdog library
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import yaml, threading
class ConfigHandler(FileSystemEventHandler):
def __init__(self, app):
self.app = app
def on_modified(self, event):
if event.src_path.endswith('app.yaml'):
self.app.reload_config()
class App:
def __init__(self):
self.config = self.load_config()
self.start_config_watcher()
def load_config(self):
with open('/etc/config/app.yaml') as f:
return yaml.safe_load(f)
def reload_config(self):
try:
new_config = self.load_config()
self.config = new_config
print(f"Config reloaded: {self.config}")
except Exception as e:
print(f"Failed to reload config, keeping old: {e}")
def start_config_watcher(self):
handler = ConfigHandler(self)
observer = Observer()
observer.schedule(handler, '/etc/config/', recursive=False)
observer.start()
// Go: menggunakan fsnotify
import "github.com/fsnotify/fsnotify"
func watchConfig(configPath string, onReload func()) {
watcher, _ := fsnotify.NewWatcher()
defer watcher.Close()
watcher.Add(filepath.Dir(configPath))
for {
select {
case event := <-watcher.Events:
// Kubernetes update symlink, bukan file langsung
// Pantau event Create dan Chmod selain Write
if event.Op&(fsnotify.Create|fsnotify.Write|fsnotify.Chmod) != 0 {
onReload()
}
}
}
}
Pola 2: SIGHUP Signal untuk Reload #
Banyak server (nginx, haproxy, prometheus) mendukung reload konfigurasi via signal SIGHUP — tanpa restart proses, tanpa memutus koneksi aktif:
# Kubernetes bisa kirim signal ke container via lifecycle hook
# atau via sidecar yang mengirim signal saat file berubah
spec:
containers:
- name: nginx
image: nginx:1.25
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/conf.d
lifecycle:
# Saat konfigurasi di-update dan Pod di-restart (graceful):
preStop:
exec:
command: ["/usr/sbin/nginx", "-s", "quit"]
# Kirim SIGHUP ke nginx untuk reload konfigurasi tanpa restart
kubectl exec deployment/nginx -- nginx -s reload
# atau:
kubectl exec deployment/nginx -- kill -HUP 1
Untuk otomatisasi, gunakan sidecar yang memantau perubahan ConfigMap dan kirim signal ke container utama.
Pola 3: Sidecar Config Watcher #
Sidecar container yang bertugas memantau perubahan file dan mengirim signal ke container utama:
spec:
volumes:
- name: config
configMap:
name: app-config
containers:
# Container utama
- name: nginx
image: nginx:1.25
volumeMounts:
- name: config
mountPath: /etc/nginx/conf.d
# Sidecar config watcher
- name: config-reloader
image: jimmidyson/configmap-reload:v0.9.0
args:
- --volume-dir=/etc/nginx/conf.d # direktori yang dipantau
- --webhook-url=http://localhost:9113/-/reload # endpoint reload
# atau kirim signal:
# - --webhook-method=POST
volumeMounts:
- name: config
mountPath: /etc/nginx/conf.d
readOnly: true
Pola 4: Polling Periodik #
Untuk aplikasi yang tidak mendukung file watching, bisa gunakan polling periodik — cek perubahan setiap N detik:
import threading, yaml, hashlib, time
class ConfigPoller:
def __init__(self, config_path, on_change, interval=30):
self.config_path = config_path
self.on_change = on_change
self.interval = interval
self.last_hash = self._hash_file()
threading.Thread(target=self._poll, daemon=True).start()
def _hash_file(self):
with open(self.config_path, 'rb') as f:
return hashlib.md5(f.read()).hexdigest()
def _poll(self):
while True:
time.sleep(self.interval)
current_hash = self._hash_file()
if current_hash != self.last_hash:
self.last_hash = current_hash
self.on_change()
Kapan Restart Pod Lebih Baik dari Hot Reload #
Hot reload tidak selalu tepat. Ada situasi di mana restart Pod lebih aman dan lebih predictable:
Restart Pod lebih baik jika:
Konfigurasi startup yang kompleks:
→ Beberapa framework membaca konfigurasi hanya saat startup
→ Memaksa hot reload bisa menyebabkan state yang tidak konsisten
→ Contoh: thread pool size, connection pool configuration
Perubahan yang memerlukan re-initialization:
→ Ganti database host → semua koneksi harus di-reconnect
→ Hot reload partial lebih berbahaya dari restart bersih
Aplikasi yang tidak dirancang untuk hot reload:
→ Memaksa hot reload di aplikasi yang tidak mendukungnya
bisa menyebabkan behavior yang tidak terduga
Secret yang berubah:
→ Env var dari Secret tidak auto-update → harus restart Pod
→ Volume mount Secret auto-update, tapi aplikasi tetap harus support reload
Cara trigger restart yang controlled:
kubectl rollout restart deployment/api -n production
→ Rolling restart — Pod baru dimulai sebelum yang lama dihapus
→ Zero downtime jika replicas > 1 dan readinessProbe dikonfigurasi
Trigger Restart Otomatis saat ConfigMap Berubah #
Untuk aplikasi yang tidak mendukung hot reload, bisa gunakan annotation checksum untuk trigger rolling restart saat ConfigMap berubah:
spec:
template:
metadata:
annotations:
# Checksum ConfigMap — berubah saat ConfigMap berubah → rolling restart
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
Ini pola umum di Helm chart — saat ConfigMap diperbarui, checksum berubah, annotation Pod berubah, dan Kubernetes otomatis melakukan rolling restart Deployment.
Ringkasan #
- Kubernetes auto-update volume ConfigMap via symlink swap — file dalam container diperbarui tanpa restart Pod dalam ~1 menit; tapi aplikasi harus membaca ulang file.
- inotify/fsnotify untuk deteksi perubahan langsung — lebih efisien dari polling; perhatikan bahwa Kubernetes update symlink bukan file langsung, pantau event Create dan Chmod juga.
- SIGHUP untuk server yang mendukung — nginx, haproxy, prometheus mendukung reload via SIGHUP; kirim signal tanpa restart proses utama, koneksi aktif tidak terputus.
- Sidecar config watcher sebagai solusi universal —
configmap-reloadsidecar yang memantau direktori dan mengirim HTTP webhook atau signal saat file berubah.- Restart Pod untuk konfigurasi startup yang kompleks — tidak semua konfigurasi cocok di-reload secara hot; perubahan yang memerlukan re-initialization lebih aman dengan restart bersih.
- Helm checksum annotation untuk auto-restart — pola umum di Helm chart untuk trigger rolling restart Deployment saat ConfigMap berubah, tanpa perlu intervensi manual.
← Sebelumnya: ConfigMap vs Secret Berikutnya: Multi-Environment Configuration →