Buku anggaran di compose.yaml kini dibaca oleh dua pihak dengan minat yang berbeda. Compose membaca limits untuk memasang pagar cgroups pada container yang diciptakan; pihak kedua membaca angka yang sama untuk keputusan yang jauh lebih awal — bahkan sebelum container diciptakan sama sekali. Sejauh ini seluruh container toko hidup di satu mesin yang kita pilih sendiri: laptop Budi, lalu server staging. Begitu aplikasi bertumbuh melewati satu mesin, pertanyaan “di mana container ini hidup” berpindah tangan ke penjadwal milik orchestrator, dan deploy.resources memang ditulis untuk pembaca itu. Membangun cluster sungguhan adalah urusan Section Orchestration dan Ekosistem pada Chapter Docker Swarm; hari ini kita cukup memahami cara penjadwal membaca anggaran kita, karena dua blok angka itu berarti dua hal yang berbeda di matanya.

Penjadwal dan Kapasitas yang Dilaporkan #

Kerja penjadwal sederhana diucapkan, sulit dilakukan: setiap kali sebuah task — istilah Swarm untuk unit kerja yang dijadwalkan — minta tempat tinggal, penjadwal harus memilih satu node dari kumpulan node yang tersedia. Bahan pertimbangannya bukan pemakaian sesaat; penjadwal tidak membaca docker stats dan tidak tahu bahwa node-1 sedang sibuk. Bahan pertimbangannya adalah pembukuan dua kolom: kapasitas terpasang yang dilaporkan tiap node (jumlah CPU dan RAM), serta jumlah reservasi task yang sudah duduk di node itu.

Untuk mencicipi aritmetikanya, tim toko menyewa tiga VM kecil 4 GB dan menggelar cluster uji:

bash
$ docker node ls

Output yang Dihasilkan:

text
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
x7kq9vz2r4m8p1j6h3b5c0d9e *   node-1     Ready     Active         Leader           29.9.0
b2m8n4p6q1s3t5u7w9y1a3c5e     node-2     Ready     Active                          29.9.0
k4r6t8v1w3x5y7z9a2c4e6g8i     node-3     Ready     Active                          29.9.0

Mari kita telaah tabel tiga node tersebut:

  1. ID sepanjang 25 karakter — identitas node di cluster; tanda * dan kolom MANAGER STATUS bernilai Leader menandakan perintah ini dijalankan dari node-1, sang manajer yang mengambil seluruh keputusan penjadwalan.
  2. Kolom yang tidak tampak justru yang terpenting — kapasitas CPU dan RAM tiap node tidak dicetak di tabel ini; angka itu tersimpan di metadata node dan dilaporkan ke penjadwal. Ketiga VM uji melaporkan 4 vCPU dan 4 GB RAM.
  3. ENGINE VERSION 29.9.0 — ketiga node menjalankan Engine yang sama, syarat cluster yang sehat; beda versi besar antar node adalah sumber kejutan yang tidak kita bahas hari ini.

Satu Service Dua Blok Angka #

Service yang akan kita taruh di cluster uji bernama rata-harian — agregator penjualan harian yang tim rencanakan sebagai beban ringan berreplika banyak. Definisinya memuat kedua blok angka yang kini mulai bercerai pekerjaannya:

yaml
services:
  rata-harian:
    image: toko-api:2.1
    command: ["node", "rata.js"]
    deploy:
      replicas: 6
      resources:
        limits:
          cpus: "0.50"
          memory: 256M
        reservations:
          cpus: "0.25"
          memory: 128M

Mari kita telaah tiga keputusan pada blok deploy tersebut:

  1. replicas: 6 — enam task akan diciptakan dari service ini, dan masing-masing task adalah satu keputusan penempatan terpisah bagi penjadwal.
  2. limits cpus 0.50 dan memory 256M — pagar keras per task, dijalankan cgroups di node tempat task mendarat; nilai ini dibaca setelah penempatan, saat container sudah hidup.
  3. reservations cpus 0.25 dan memory 128M — angka yang dibaca penjadwal sebelum task diciptakan; inilah yang menentukan node mana yang dianggap muat.

Reservasi adalah Bahasa Penjadwal #

Bagi penjadwal, satu-satunya pertanyaan yang dijawab reservasi adalah “apakah muat”. Cara menghitungnya pembukuan sederhana: kapasitas node dikurangi jumlah reservasi seluruh task yang sudah ditempatkan di node itu menghasilkan sisa; task baru hanya boleh mendarat bila reservasinya tidak melebihi sisa. Service dengan reservasi 256 MB hanya akan mendarat di node yang sisanya masih 256 MB atau lebih — bukan di node yang RAM-nya memang besar, melainkan di node yang pembukuan-nya masih longgar.

Perbedaan dua blok itu paling jelas dirangkum dalam tabel berikut:

Aspeklimitsreservations
Siapa membacanyacgroups di node tempat container hiduppenjadwal Swarm saat memilih node
Kapan dihitungsepanjang umur container, saat eksekusisekali, saat task hendak ditempatkan
Peranpagar keras — dilanggar berarti throttle atau OOMpembukuan kapasitas — “node ini masih muat?”
Bila angkanya kalahcontainer melambat atau matitask ditolak dan menunggu node yang muat

Alur lengkap keputusan penjadwal dapat digambar ringkas:

Mari kita telaah diagram di atas: jalur kiri adalah kehidupan normal — pemeriksaan “apakah muat” di tiap node, task ditempatkan, dan barulah setelah itu limit mulai ditegakkan cgroups. Jalur kanan adalah kegagalan penempatan yang bukan galat aplikasi: task tidak mati dan tidak mengulang crash loop, ia hanya menunggu hingga ada node yang longgar atau reservasi service lain dicabut.

Aritmetika Penempatan yang Menolak #

Sekarang kita isi buku kas cluster uji. Ketiga node melaporkan 4 GB, dan task-task sebelumnya sudah meninggalkan reservasi di sana-sini:

NodeRAM terpasangReservasi sudah dudukSisa menurut penjadwal
node-14 GB3,5 GB0,5 GB
node-24 GB2,2 GB1,8 GB
node-34 GB3,8 GB0,2 GB

Enam task rata-harian masing-masing membawa reservasi 128 MB, dan penjadwal menyebarkannya menjadi dua task ke node-1 (256 MB), tiga task ke node-2 (384 MB), dan satu task ke node-3 (128 MB) — sebaran yang sengaja tidak menumpuk, karena satu node tumbang seharusnya tidak membawa serta separuh service. Setelah debatnya selesai, sisa pembukuan berubah: node-1 bersisa 256 MB, node-2 bersisa sekitar 1,46 GB, dan node-3 bersisa 77 MB.

Lalu datang service laporan-bulanan — agregator berat yang hanya menyala di awal bulan:

yaml
services:
  laporan-bulanan:
    image: toko-laporan:1.0
    deploy:
      replicas: 1
      resources:
        limits:
          cpus: "2.0"
          memory: 3G
        reservations:
          cpus: "1.0"
          memory: 1536M

Reservasi 1536 MB tidak muat di mana pun: node-1 hanya bersisa 256 MB, node-2 bersisa 1,46 GB, node-3 bersisa 77 MB. Perhatikan bahwa limit 3G tidak pernah dihitung — penjadwal tidak memandangnya sama sekali — dan satu-satunya task service itu pun menunggu dengan pesan yang bisa kita baca:

bash
$ docker service ps laporan-bulanan

Output yang Dihasilkan:

text
ID             NAME                IMAGE              NODE   DESIRED STATE   CURRENT STATE            ERROR
u8f2kq7vz2x4   laporan-bulanan.1   toko-laporan:1.0          Running         Rejected 12 seconds ago   "no suitable node (3 nodes unavailable due to insufficient resources)"

Mari kita telaah penolakan pada baris itu:

  1. Rejected, bukan Failed — aplikasinya tidak pernah dijalankan; penolakan terjadi sebelum container diciptakan, sehingga tidak ada log aplikasi yang bisa diselidiki.
  2. Pesan no suitable node merinci alasannya — tiga node tidak tersedia karena sumber daya kurang; kalimatnya merangkum seluruh aritmetika pembukuan di atas.
  3. Jalan keluarnya tiga macam — turunkan reservasi service, bebaskan kapasitas node dengan menurunkan reservasi service lain, atau tambah node baru; task akan ditempatkan otomatis begitu salah satu terpenuhi.
  4. Keinginan tetap tercatat — kolom DESIRED STATE bernilai Running: keadaan yang diinginkan tetap hidup, dan penjadwal akan terus mencoba menempatkannya setiap saat. Kontras antara desired state dan kenyataan adalah cara kerja orchestrator yang akan kita bedah tuntas di Section Orchestration dan Ekosistem.

cpus dalam Satuan vCPU #

Nilai cpus di Swarm adalah jumlah vCPU dalam satuan desimal — 0.50 berarti setengah core, 0.25 seperempat. Pecahan sah penuh karena CPU memang dibagi waktu: dua task ber-reservasi 0.25 vCPU bisa berbagi satu core tanpa saling menunggu. Penjadwal ikut menjumlahkan kolom ini dengan cara yang sama seperti memori: enam task rata-harian memesan total 1,5 vCPU, dibandingkan 4 vCPU yang dilaporkan tiap node. Ketika kita menulis --cpus 1.5 pada chapter-chapter awal Section ini, satuan dan artinya sama persis — yang baru hanyalah penjadwal yang kini ikut berhitung.

Penjadwal menjumlahkan reservasi dengan disiplin seorang akuntan: tiap task memesan kursi, tiap node menghitung kursi terisi, dan penempatan ditolak begitu ruang habis. Tetapi tidak ada akuntan untuk limits — total limit seluruh service boleh melampaui kapasitas seluruh node, dan tidak satu penjadwal pun protes. Praktik itu punya nama, overcommit, dan konsekuensinya datang bukan dari penjadwal melainkan dari kernel di dalam node. Chapter Overcommit dan Noisy Neighbor membedah kapan komitmen yang melebihi kapasitas itu aman, dan bagaimana mengenali saat ia mulai menyengat.

Referensi #