# Cara Membuat Healthcheck Docker dan Memilih Restart Policy

> Cara membuat healthcheck Docker: tulis cek-nya, pahami status starting, healthy, dan unhealthy, pakai --wait saat deploy, dan batas restart policy.

URL: https://www.matthewswong.com/id/learn/devops-from-zero/docker-healthcheck-restart-policy/

DevOps dari nol · Pelajaran 23 dari 25 · Ditinjau pada 18 Oktober 2026 · Oleh Matthews Wong (https://www.matthewswong.com/id/about/)

> Healthcheck Docker adalah perintah yang dijalankan Docker di dalam container secara berkala: exit 0 berarti healthy, exit 1 berarti unhealthy. Statusnya dimulai dari starting, menjadi healthy saat cek pertama lolos, dan unhealthy setelah sejumlah kegagalan berturut-turut. Restart policy adalah hal terpisah: ia hanya bereaksi saat proses berhenti, jadi container yang unhealthy tetap berjalan.

## Setelah pelajaran ini, Anda bisa

- Menulis health check di Dockerfile, file Compose, atau perintah docker run, lalu membaca status dan log-nya dengan docker inspect.
- Menghitung dari interval, timeout, retries, start_period, dan start_interval seberapa cepat container menjadi healthy, dan berapa lama kegagalan baru terlihat.
- Memilih restart policy, dan menjelaskan apa yang bereaksi terhadap status health (depends_on, --wait, Swarm) dan apa yang tidak.

## Siapa yang bereaksi saat container menjadi unhealthy

Sebuah service Compose dengan health check berpindah dari starting ke healthy, yang melepas docker compose up --wait dan service yang bergantung padanya. Saat aplikasinya hang, statusnya menjadi unhealthy dan tidak ada yang me-restart; hanya proses yang berhenti yang memicu restart policy.

1. **Kenali bagiannya.** Satu project Compose. web punya health check dan restart: unless-stopped. worker menunggu web healthy, dan deploy menjalankan docker compose up --wait.
2. **Starting: masa tenggang.** web dimulai dengan status starting. Selama start_period 20 detik, Docker menjalankan cek setiap start_interval, default 5 detik, dan kegagalan di masa ini tidak dihitung.

   ```
   start_period: 20s
   ```
3. **Sekali lolos: healthy.** Cek pertama yang lolos membuat web healthy. --wait selesai dengan exit 0, dan Compose menjalankan worker, yang menunggu condition: service_healthy.

   ```
   condition: service_healthy
   ```
4. **Tiga kali gagal berturut-turut.** Aplikasinya hang. Setiap cek kini menunggu timeout 5 detik, lalu cek berikutnya jalan 30 detik kemudian. Setelah tiga kegagalan berturut-turut, web menjadi unhealthy.

   ```
   retries: 3
   ```

   *Tebak:* web sekarang unhealthy dan punya restart: unless-stopped. Apa yang dilakukan Docker berikutnya? (Me-restart web / Tidak ada: web tetap berjalan, unhealthy / Menghentikan worker)
5. **Unhealthy hanya sebuah label.** Tidak ada yang di-restart. Restart policy bereaksi saat proses berhenti, dan proses yang hang belum berhenti. worker juga tetap jalan: Compose hanya mengecek health saat menjalankannya.

   *Tebak:* Sekarang prosesnya crash dan berhenti dengan exit code 1. Apa yang terjadi? (Tetap mati: toh sudah unhealthy / Menyala lagi, dan status health kembali ke starting)
6. **Exit itu lain cerita.** Proses berhenti dengan exit code 1, dan itulah yang diawasi restart policy. unless-stopped menyalakan web lagi setelah jeda singkat, dan status health-nya kembali starting.

   ```
   restart: unless-stopped
   ```

## Apa itu healthcheck Docker?

Healthcheck Docker adalah perintah yang dijalankan Docker di dalam container yang sedang berjalan secara berkala, untuk menanyakan apakah aplikasinya masih berfungsi. Exit code 0 berarti healthy dan 1 berarti unhealthy; 2 dicadangkan, jadi jangan dipakai. Dalam uji coba, cek yang berhenti dengan exit 127 karena perintahnya tidak ada juga dihitung gagal. Jawabannya menjadi status di container, yang ditampilkan docker ps sebagai (healthy) atau (unhealthy).

Anda bisa mendeklarasikannya di tiga tempat. Di Dockerfile, HEALTHCHECK [OPTIONS] CMD command menanamkannya ke image; hanya yang terakhir yang berlaku, dan HEALTHCHECK NONE mematikan cek warisan dari base image. Di Compose, healthcheck: menimpa nilai dari image. test-nya berupa list yang diawali CMD, CMD-SHELL, atau NONE, string biasa berarti CMD-SHELL, dan disable: true mematikan ceknya. Di docker run, keluarga flag --health-cmd melakukan hal yang sama, dan --no-healthcheck mematikannya.

CMD menjalankan programnya langsung, tanpa shell, jadi binary itu harus ada di image. CMD-SHELL menjalankan string lewat shell default container, sehingga bisa memakai || exit 1, tetapi butuh shell di image. Docker menyimpan 4096 byte pertama dari output setiap cek, dan docker inspect menampilkannya; di situlah Anda membaca kenapa sebuah cek gagal.

## Bagaimana status health berubah dari waktu ke waktu?

Setiap container yang punya cek dimulai dengan status starting. Docker menjalankan cek pertama satu interval setelah container start, dan setiap cek berikutnya satu interval setelah cek sebelumnya selesai. Cek yang melewati timeout dihitung gagal, dan Docker mematikannya. Setelah gagal sebanyak retries kali berturut-turut, statusnya menjadi unhealthy, dan cek berikutnya yang lolos membuatnya healthy lagi. Default-nya 30 detik untuk interval dan timeout, 3 kali retries, dan tanpa start period.

start_period adalah masa tenggang untuk aplikasi yang lambat booting. Kegagalan di dalamnya tidak dihitung ke retries, dan Docker menjalankan cek setiap start_interval, default 5 detik, bukan setiap interval; start_interval butuh Docker Engine 25.0 atau lebih baru. Cek pertama yang lolos di masa ini langsung mengakhirinya: sejak itu, setiap kegagalan dihitung.

Setiap perubahan status memunculkan event health_status, jadi docker events menampilkan healthy, lalu unhealthy, lalu healthy lagi, bukan setiap cek. docker inspect menampilkan FailingStreak, yaitu jumlah kegagalan beruntun saat ini, dan log hasil terbaru: dalam uji coba di Docker Engine 29.8.1, log itu menyimpan lima hasil terakhir.

## Seberapa cepat cek di situs ini bereaksi?

Cek di situs ini berjalan setiap 30 detik dengan timeout 5 detik, 3 kali retries, dan start period 20 detik, tanpa start_interval. Kalau hanya melihat interval, cek pertama seolah baru jalan 30 detik kemudian. Kenyataannya tidak: di dalam start period, Docker mengecek setiap 5 detik. Dalam uji coba memakai container nginx dengan angka yang persis sama, cek pertama jalan 5 detik setelah container start, dan docker compose up --wait selesai dalam sekitar 6 detik.

Arah sebaliknya lebih lambat. Dengan jarak 30 detik antar cek, tiga kegagalan berturut-turut butuh sekitar satu setengah menit: dalam uji coba yang sama, cek yang langsung gagal membuat container unhealthy 90 detik setelah aplikasinya rusak. Aplikasi yang hang butuh waktu lebih lama lagi, karena setiap cek yang gagal menunggu timeout 5 detik dulu. Rilis yang ceknya gagal sejak detik pertama menjadi unhealthy, dan membuat --wait gagal, setelah sekitar 80 detik.

Angka-angka itu adalah kompromi. Interval yang lebih pendek lebih cepat mendeteksi, tetapi lebih sering menjalankan proses di dalam container; retries yang lebih banyak tahan terhadap lambat sesaat, tetapi menunda alarm. Pilih angkanya berdasarkan berapa lama Anda sanggup melayani error sebelum ada yang bereaksi.

## Apakah Docker me-restart container yang unhealthy?

Tidak, tidak dengan sendirinya. Dokumentasi Docker mendefinisikan setiap restart policy berdasarkan cara container berhenti, dan referensi HEALTHCHECK hanya menjelaskan sebuah status tanpa tindakan apa pun. Dalam uji coba di Docker Engine 29.8.1, container nginx dengan restart: unless-stopped tetap unhealthy lebih dari satu menit, dengan failing streak 13 dan RestartCount 0, dan terus menjawab setiap request dengan 403.

Swarm mode adalah pengecualiannya. Di sana, jika container milik sebuah service gagal health check, task-nya berakhir, lalu orchestrator menghapusnya dan membuat penggantinya; pelajaran 19 membahas hal ini. Dengan Docker biasa atau Compose di satu host, harus ada pihak lain yang bertindak atas status unhealthy: deploy yang menunggu healthy, monitor yang memberi Anda alert, atau script buatan sendiri.

## Apa saja di Compose yang bereaksi terhadap health?

Ada dua, dan keduanya hanya berlaku saat Compose sedang menjalankan service. depends_on dengan condition: service_healthy membuat Compose menunggu cek milik dependency lolos sebelum menjalankan service yang bergantung padanya. Bentuk singkatnya, berupa list nama saja, hanya menunggu sampai dependency start: dokumentasi Compose menyebut bahwa saat startup, Compose tidak menunggu container siap, hanya menunggu container berjalan.

docker compose up --wait menunggu service berjalan atau healthy, otomatis berjalan dalam mode detached, dan berhenti dengan error jika ada yang menjadi unhealthy; --wait-timeout memberi batas waktu. Dalam uji coba, dependency yang ceknya tidak pernah lolos membuat service yang bergantung padanya hanya dibuat tanpa pernah dijalankan, dan bahkan up -d tanpa --wait gagal dengan pesan dependency failed to start.

Begitu service sudah jalan, Compose tidak lagi mengawasi. Dalam uji coba yang sama, service yang bergantung tetap berjalan setelah dependency-nya menjadi unhealthy. depends_on juga menerima restart: true, yang me-restart service yang bergantung saat Compose sendiri me-restart atau memperbarui dependency, bukan saat container runtime yang melakukannya.

## Restart policy mana yang sebaiknya dipilih?

Restart policy memberi tahu daemon Docker apa yang harus dilakukan saat proses di container berhenti. no, yang merupakan default, tidak pernah me-restart. on-failure hanya me-restart setelah exit code bukan nol, dan on-failure:3 menyerah setelah tiga kali percobaan. always me-restart setelah exit apa pun. unless-stopped sama saja, kecuali container yang Anda hentikan sendiri tetap mati, bahkan setelah daemon di-restart.

Ada dua aturan yang berlaku untuk semuanya. Container yang Anda hentikan dengan docker stop tetap mati sampai daemon di-restart atau Anda menyalakannya lagi, jadi restart policy tidak akan melawan Anda. Lalu, Docker menunggu sebelum setiap restart, mulai dari 100 ms dan berlipat dua sampai satu menit, lalu kembali ke awal begitu container berjalan selama 10 detik. Dalam uji coba, container yang berhenti setiap 2 detik sudah di-restart 8 kali setelah 30 detik.

Restart daemon termasuk saat server reboot, karena Debian dan Ubuntu menyalakan Docker saat boot. always dan unless-stopped menyalakan kembali container yang tadinya berjalan, dan dari keduanya, hanya always yang juga menghidupkan container yang sudah Anda hentikan. on-failure melihat exit code terakhir. Dokumentasi Docker menyebut policy ini tidak me-restart saat daemon di-restart, dan dalam uji coba itu benar untuk container yang berhenti dengan exit 0; container yang di-kill, dengan exit code 137, menyala lagi, bahkan yang dihentikan secara manual.

Untuk web service di satu server, unless-stopped adalah pilihan yang umum, dan itu yang dipakai situs ini: crash akan pulih, dan docker stop untuk maintenance tetap berlaku walau server reboot. Jangan membungkus container itu lagi dengan systemd atau supervisor; dokumentasi Docker memperingatkan bahwa menggabungkan restart policy dengan process manager di host menimbulkan konflik.

## Kenapa situs ini mengecek robots.txt dengan wget ke 127.0.0.1?

Karena isi image-nya. Stage runtime-nya memakai node:20-alpine, yang punya wget dari BusyBox tetapi tidak punya curl, dan bentuk exec CMD tidak butuh shell. --spider hanya mengecek apakah URL-nya ada, dengan exit 0 jika ada; dalam uji coba, ia tetap mengirim GET. --no-verbose dan --tries=1 adalah opsi GNU wget yang diterima BusyBox walau tidak tercantum di help-nya, jadi yang menentukan adalah timeout dan retries milik Docker. robots.txt adalah route ringan yang membuktikan server Node menjawab, bukan bahwa setiap halaman ter-render.

127.0.0.1 ditulis secara eksplisit dengan sengaja. Cek berjalan di dalam container, tempat localhost dipetakan ke 127.0.0.1 sekaligus ::1, dan wget BusyBox mencoba ::1 lebih dulu. Aplikasinya listen di 0.0.0.0, yang hanya mencakup IPv4, jadi dalam uji coba di node:20-alpine, wget ke localhost:3000 mendapat Connection refused, sedangkan request yang sama ke 127.0.0.1:3000 lolos.

## Konfigurasi nyata di balik pelajaran ini

`docker-compose.yml:10`

```yaml
    restart: unless-stopped
```

Satu baris ini menentukan apa yang terjadi setelah proses berhenti. Crash membuat container menyala lagi setelah jeda singkat, dan docker stop untuk maintenance membuatnya tetap mati, bahkan setelah reboot. Status unhealthy tidak mengubah apa pun di sini, karena prosesnya belum berhenti.

`docker-compose.yml:29-42`

```yaml
    healthcheck:
      test:
        [
          "CMD",
          "wget",
          "--no-verbose",
          "--tries=1",
          "--spider",
          "http://127.0.0.1:3000/robots.txt",
        ]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 20s
```

Baca angka-angka ini sebagai garis waktu. Di dalam start period 20 detik, Docker mengecek setiap 5 detik, yaitu start_interval default, jadi container baru sudah healthy dalam hitungan detik. Setelah itu cek jalan setiap 30 detik dan menyerah setelah 5 detik, jadi tiga kegagalan berturut-turut butuh sekitar 90 detik sebelum tampil sebagai unhealthy. Bentuk exec menjalankan wget BusyBox tanpa shell, ke 127.0.0.1 milik container itu sendiri.

`.github/workflows/deploy.yml:241-244`

```bash
            docker compose up -d --remove-orphans || {
              docker rm -f matthewswong-portfolio 2>/dev/null || true
              docker compose up -d --remove-orphans
            }
```

up -d selesai begitu container start, jadi health check tidak pernah menentukan apakah langkah ini lolos. Fallback-nya menangani bentrok nama container saat peralihan pertama. Kalau Anda menambahkan --wait, tambahkan di kedua baris up: dalam uji coba dengan file berisi satu service, --wait yang hanya ada di baris pertama gagal, fallback menjalankan rilis yang sama lagi tanpa menunggu, dan script-nya selesai dengan sukses.

`.github/workflows/deploy.yml:329-332`

```yaml
      # The container answers within seconds of `up -d`; this short pause
      # saves most runs from spending a retry on a 502.
      - name: Wait for the new container
        run: sleep 20
```

Job setelah deploy menunggu berdasarkan jam, bukan berdasarkan health: 20 detik, dan script-nya mengulang jika situs masih menjawab 502. Itu cukup untuk sekadar memberi tahu mesin pencari, karena meleset sekali tidak banyak ruginya. Deploy yang harus tahu rilisnya berfungsi sebaiknya menunggu health check, dengan docker compose up --wait; container uji dengan angka yang sama sudah healthy dalam sekitar 6 detik.

## Yang sering rusak

- **Unhealthy berjam-jam, dan tidak terjadi apa-apa.** Cek yang gagal hanya mengubah status dan memunculkan event. Container tidak di-restart, tidak dihentikan, dan trafik tetap diarahkan ke sana, jadi aplikasi yang rusak terus melayani error sampai ada yang melihat. Buat sesuatu bertindak: --wait saat deploy, monitor yang memberi alert dari status itu atau dari URL di luar, atau Swarm mode, yang mengganti task yang container-nya gagal dicek.
- **Connection refused di log health, padahal aplikasinya jalan.** Ceknya memanggil localhost, wget BusyBox mencoba ::1 lebih dulu, sedangkan aplikasinya listen di 0.0.0.0, yang hanya IPv4. Log-nya berisi can't connect to remote host: Connection refused di setiap cek. Tulis 127.0.0.1 di cek, seperti situs ini, atau buat aplikasinya juga listen di IPv6.
- **curl: not found, di setiap cek.** Cek yang disalin dari tutorial memanggil curl, padahal image-nya tidak punya: node:20-alpine membawa wget BusyBox tanpa curl. Dalam uji coba, log-nya menampilkan /bin/sh: curl: not found dengan exit code 127, dan container menjadi unhealthy padahal aplikasinya menjawab dengan baik. Pakai tool yang ada di image, dan uji dulu perintah persisnya dengan docker exec.
- **Crash loop yang tidak ada habisnya.** always dan unless-stopped me-restart container yang langsung berhenti, terus-menerus, dengan jeda yang makin panjang sampai satu menit. docker ps menampilkan Restarting, dan RestartCount terus naik. Baca docker logs untuk mencari penyebabnya, dan untuk job yang memang boleh menyerah, pakai on-failure dengan batas, misalnya on-failure:3.

### Apa yang dilakukan setiap restart policy, menurut dokumentasi Docker dan hasil uji di Docker Engine 29.8.1 dan 29.9.1.

| Policy | Exit dengan kode 0 | Exit dengan error | Setelah daemon di-restart atau reboot | Berjalan tetapi unhealthy |
| --- | --- | --- | --- | --- |
| no (default) | Tetap mati | Tetap mati | Tetap mati | Tetap berjalan |
| on-failure[:N] | Tetap mati | Di-restart, maksimal N kali | Menyala lagi hanya jika exit code terakhirnya bukan 0 | Tetap berjalan |
| always | Di-restart | Di-restart | Menyala lagi, walau sudah Anda hentikan | Tetap berjalan |
| unless-stopped | Di-restart | Di-restart | Menyala lagi, kecuali sudah Anda hentikan | Tetap berjalan |

## Coba sendiri

Anda hanya butuh Docker dan curl di laptop; semua port tetap di 127.0.0.1 dan semua nama container diawali hc- atau health-lab. Anda akan melihat cek menjadi healthy, merusaknya, memulihkannya, menahan start Compose dengannya, lalu membuat container crash di bawah setiap policy.

1. Jalankan nginx dengan health check yang meniru milik situs ini, dengan angka waktu yang lebih pendek. Jalankan docker ps langsung dan sekali lagi 10 detik kemudian: starting, lalu healthy.

   ```bash
   docker run -d --name hc-web --restart unless-stopped -p 127.0.0.1:8090:80 \
     --health-cmd "wget --no-verbose --tries=1 --spider http://127.0.0.1/" \
     --health-interval 5s --health-timeout 3s --health-retries 3 --health-start-period 10s \
     nginx:alpine
   docker ps --filter name=hc-web --format '{{.Names}} {{.Status}}'
   ```
2. Baca catatan health-nya: status, failing streak saat ini, serta exit code dan output dari setiap cek terbaru.

   ```bash
   docker inspect --format '{{.State.Health.Status}} streak={{.State.Health.FailingStreak}}' hc-web
   docker inspect --format '{{range .State.Health.Log}}{{.ExitCode}} {{.Output}}{{end}}' hc-web
   ```
3. Rusak dengan menghapus halaman yang dicek. Sekitar 15 detik kemudian statusnya unhealthy, tetapi nginx masih menjawab (403) dan RestartCount tetap 0, walau memakai unless-stopped.

   ```bash
   docker exec hc-web rm /usr/share/nginx/html/index.html
   # about 15 seconds later:
   docker ps --filter name=hc-web --format '{{.Names}} {{.Status}}'
   curl -I http://127.0.0.1:8090/
   docker inspect --format 'restarts={{.RestartCount}}' hc-web
   ```
4. Pulihkan. Satu cek yang lolos sudah cukup untuk kembali healthy. Daftar event menampilkan setiap perubahan status, bukan setiap cek; jika baris healthy terakhir belum muncul, jalankan lagi beberapa detik kemudian.

   ```bash
   docker exec hc-web sh -c 'echo ok > /usr/share/nginx/html/index.html'
   # about 10 seconds later:
   docker inspect --format '{{.State.Health.Status}}' hc-web
   docker events --since 5m --until 0s --filter container=hc-web --filter event=health_status
   ```
5. Buat folder kosong bernama health-lab dan simpan ini sebagai compose.yaml. CHECK_PATH memungkinkan Anda merusak cek dari command line, dan worker menunggu api healthy.

   ```bash
   services:
     api:
       image: nginx:alpine
       restart: unless-stopped
       ports:
         - "127.0.0.1:8091:80"
       healthcheck:
         test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1/${CHECK_PATH:-}"]
         interval: 5s
         timeout: 3s
         retries: 3
         start_period: 10s
     worker:
       image: alpine:3
       command: sleep 600
       depends_on:
         api:
           condition: service_healthy
   ```
6. Di folder itu, jalankan dengan --wait: exit 0 dalam hitungan detik. Lalu jalankan lagi dengan cek yang tidak mungkin lolos. Setelah sekitar 20 detik Compose mencetak dependency failed to start, exit 1, dan worker hanya Created tanpa pernah dijalankan.

   ```bash
   docker compose up -d --wait; echo "exit=$?"
   docker compose ps
   docker compose down
   CHECK_PATH=missing docker compose up -d --wait; echo "exit=$?"
   docker compose ps -a
   ```
7. Buat container crash di bawah tiga policy, masing-masing berhenti setelah 2 detik. Sekitar 20 detik kemudian: no punya 0 restart, on-failure:3 menyerah di angka 3, dan always terus jalan. Lalu hentikan yang always secara manual: ia tetap mati.

   ```bash
   docker run -d --name hc-no --restart no alpine:3 sh -c 'sleep 2; exit 1'
   docker run -d --name hc-onf --restart on-failure:3 alpine:3 sh -c 'sleep 2; exit 1'
   docker run -d --name hc-always --restart always alpine:3 sh -c 'sleep 2; exit 0'
   # about 20 seconds later:
   docker inspect --format '{{.Name}} restarts={{.RestartCount}}' hc-no hc-onf hc-always
   docker stop hc-always
   docker ps -a --filter name=hc- --format '{{.Names}} {{.Status}}'
   ```
8. Bersihkan container-nya, lalu, di dalam health-lab, project Compose-nya.

   ```bash
   docker rm -f hc-web hc-no hc-onf hc-always
   docker compose down
   ```

## Kuis singkat

1. **Cek di situs ini punya interval: 30s dan start_period: 20s, tanpa start_interval. Kapan cek pertama jalan setelah container start?**
   A. Setelah 30 detik, satu interval
   B. Setelah sekitar 5 detik, karena start period mengecek setiap start_interval
   C. Setelah 20 detik, saat start period berakhir
   Jawaban: B. Di dalam start period, Docker menjalankan cek setiap start_interval, default 5 detik di Engine 25.0 ke atas. Dalam uji coba dengan angka ini, cek pertama jalan 5 detik setelah start, dan --wait selesai dalam sekitar 6 detik.

2. **Sebuah container dengan restart: on-failure:3 hang dan sudah unhealthy selama sepuluh menit. Berapa kali Docker me-restart-nya?**
   A. Tiga kali, lalu menyerah
   B. Sekali, setelah cek ketiga gagal
   C. Tidak sekali pun: prosesnya tidak pernah berhenti
   Jawaban: C. Restart policy bereaksi saat proses berhenti, sedangkan proses yang hang masih berjalan. Unhealthy hanyalah status; di Docker biasa, harus ada pihak lain, seperti monitor atau deploy yang menunggu, yang bertindak.

3. **Sebuah image berbasis Alpine mengecek wget --spider http://localhost:3000/, dan aplikasinya listen di 0.0.0.0. Log health berisi Connection refused, padahal aplikasinya menjawab. Apa yang salah?**
   A. wget BusyBox mencoba ::1 lebih dulu, dan aplikasinya hanya listen di IPv4
   B. Health check berjalan di host, tempat port 3000 tidak di-publish
   C. --spider harus mengunduh seluruh file dulu
   Jawaban: A. Di dalam container, localhost dipetakan ke 127.0.0.1 dan ::1, dan wget BusyBox mencoba ::1 lebih dulu. Tidak ada yang listen di sana, jadi ceknya gagal. Tulis 127.0.0.1, seperti cek di situs ini.

## Pikirkan dulu

- **Apa arti exit code 0, 1, dan 2 bagi health check?** 0 berarti healthy, 1 berarti unhealthy, dan 2 dicadangkan, jadi jangan dipakai. Dalam uji coba, kode bukan nol lainnya, seperti 127 untuk perintah yang tidak ada, juga dihitung gagal.
- **worker punya depends_on: api dengan condition: service_healthy. Satu jam setelah startup, api menjadi unhealthy. Apa yang dilakukan Compose?** Tidak ada. Compose hanya mengecek kondisi itu saat menjalankan service. Dalam uji coba, service yang bergantung tetap berjalan setelah dependency-nya menjadi unhealthy.
- **Anda menghentikan container dengan docker stop, lalu server reboot. Apakah ia menyala lagi dengan always? Dengan unless-stopped?** Dengan always, ya: penghentian manual hanya berlaku sampai daemon di-restart. Dengan unless-stopped, tidak: ia tetap mati sampai Anda menyalakannya sendiri. Perbedaan itulah alasan memilih unless-stopped untuk service yang kadang Anda hentikan untuk maintenance.

## Pelajari lebih dalam

- [NestJS Health Checks with Terminus for Kubernetes & Docker](https://www.matthewswong.com/id/blog/nestjs-terminus-health-checks/)
- [Load Balancer Nginx di Produksi: Konfigurasi, Health Check, dan Failover](https://www.matthewswong.com/id/blog/load-balancer-production-config/)
- [Docker Swarm: Orkestrasi Container untuk Tim Kecil](https://www.matthewswong.com/id/blog/docker-swarm-orchestration/)

## Sumber

- [Dokumentasi Docker: referensi Dockerfile, HEALTHCHECK](https://docs.docker.com/reference/dockerfile/#healthcheck)
- [Dokumentasi Docker: referensi service Compose (healthcheck, restart, depends_on)](https://docs.docker.com/reference/compose-file/services/)
- [Dokumentasi Docker: menjalankan container secara otomatis (restart policy)](https://docs.docker.com/engine/containers/start-containers-automatically/)
- [Dokumentasi Docker: docker container run (flag --health-*, jeda restart)](https://docs.docker.com/reference/cli/docker/container/run/)
- [Dokumentasi Docker: docker compose up (--wait, --wait-timeout)](https://docs.docker.com/reference/cli/docker/compose/up/)
- [Dokumentasi Docker: mengatur urutan startup di Compose](https://docs.docker.com/compose/how-tos/startup-order/)
- [Dokumentasi Docker: docker system events (health_status)](https://docs.docker.com/reference/cli/docker/system/events/)
- [Dokumentasi Docker: docker container ls (filter health)](https://docs.docker.com/reference/cli/docker/container/ls/)
- [Dokumentasi Docker: cara kerja service di Swarm mode](https://docs.docker.com/engine/swarm/how-swarm-mode-works/services/)
- [Dokumentasi Docker: langkah setelah instalasi di Linux (start saat boot)](https://docs.docker.com/engine/install/linux-postinstall/)
- [Bantuan perintah BusyBox (wget --spider)](https://busybox.net/downloads/BusyBox.html)

---

- HTML version: https://www.matthewswong.com/id/learn/devops-from-zero/docker-healthcheck-restart-policy/
- English: https://www.matthewswong.com/en/learn/devops-from-zero/docker-healthcheck-restart-policy/
- Site index for agents: https://www.matthewswong.com/llms.txt
- Sitemap: https://www.matthewswong.com/sitemap.xml
- API description (OpenAPI): https://www.matthewswong.com/openapi.json
