A detailed backend reference

Container, mengirim kode Anda beserta dunianya.

Versi Sederhana

Penelusuran dari prinsip dasar tentang cara kode backend dikemas dan dijalankan di produksi, dari fitur kernel yang membuat container (namespaces dan cgroups), lewat image Docker, layer, dan multi-stage build, ke orkestrasi Kubernetes (pod, deployment, service, probe, autoscaling), dan keluar ke pipeline CI/CD serta rollout zero-downtime. Ditulis bukan hanya menyebut apa fungsi tiap bagian, tapi kenapa ia ada dan bagaimana ia bekerja di dalamnya. Contoh aplikasi di Go dan Python.

Linux namespaces + cgroups Docker / OCI Kubernetes 21 sections
Part I / Why Containers Exist
01

Masalah yang Dipecahkan Container

Setiap konsep container belakangan di manual ini adalah jawaban atas satu rasa sakit yang berulang: kode yang berjalan di satu mesin gagal di mesin lain karena kedua mesin tidak identik. Laptop Anda punya Python 3.11, server punya 3.9; build Anda mengasumsikan library sistem yang tidak ada di produksi; environment variable di-set di sini dan tidak di-set di sana. Hasilnya lelucon tertua di perangkat lunak, "tapi berfungsi di mesin saya", dan ia bukan lelucon, ia kelas pemadaman.

Akar masalahnya program yang berjalan tidak pernah hanya source code-nya. Ia kode plus seluruh lingkungan tak terlihat: runtime bahasa dan versi persisnya, library pihak ketiga, paket sistem, konfigurasi, path file, dan dependensi level OS. Secara tradisional Anda mereproduksi lingkungan itu manual di setiap mesin, langkah instalasi, skrip setup, halaman wiki yang tidak pernah diperbarui siapa pun, dan setiap penyimpangan antar lingkungan menjadi bug yang hanya muncul di satu tempat.

Before containers, deploying software was like mailing a recipe and hoping the recipient's kitchen has the same oven, the same pans, and the same brand of flour. Containers mail the entire kitchen, oven, pans, ingredients, pre-measured, sealed in a box that runs the same way wherever you open it.
The deployment gap
A program is code plus an environment, and the environment is what drifts
WITHOUT containers, same code, different worlds your laptop app + Python 3.11 libs A, B (v2) ✓ works the server app + Python 3.9 libs A (v1), no B ✗ breaks "works on my machine" WITH a container, the environment travels with the code container image app + runtime + libs + config laptop ✓ staging ✓ prod ✓
A container packages the application and its entire runtime environment into one immutable artifact, so "the thing that runs" is byte-identical everywhere.

Tiga masalah, satu solusi

  • Dependency hell & drift: runtime dan library persisnya dibakar ke dalam, jadi tidak ada "langkah instalasi" yang bisa salah dan tidak ada ketimpangan versi antar lingkungan.
  • Isolasi: dua aplikasi yang butuh versi bertentangan dari library yang sama bisa berjalan berdampingan di satu host, masing-masing di kotak tertutupnya sendiri, tanpa saling mengganggu.
  • Kepadatan & portabilitas: container cukup ringan untuk dikemas banyak ke satu mesin dan dipindah bebas antara laptop, CI, dan cloud mana pun, fondasi yang dibangun orkestrasi (Bagian IV) dan CI/CD modern (Bagian V).
The one idea

Container membuat "yang berjalan di produksi" identik dengan "yang Anda bangun dan uji." Segala hal lain, image, Docker, Kubernetes, pipeline, adalah mesin untuk membangun, mengirim, dan menjalankan artefak identik itu di skala.

02

Container vs Mesin Virtual

Pertanyaan naluriahnya "bukankah ini cuma mesin virtual?" Jawabannya mengungkap apa sebenarnya container itu. VM me-virtualisasi perangkat keras: hypervisor mengemulasi seluruh mesin, dan tiap VM menjalankan sistem operasi lengkapnya sendiri, kernelnya sendiri, di atasnya duduk library dan aplikasi Anda. Container me-virtualisasi sistem operasi: semua container di satu host berbagi satu kernel host, dan isolasi ditegakkan fitur kernel alih-alih mengemulasi perangkat keras terpisah.

The decisive difference
VMs each ship a full OS; containers share one kernel
Virtual Machines Containers App A bins / libs Guest OS + kernel App B bins / libs Guest OS + kernel Hypervisor Host OS + kernel Physical hardware App A bins/libs no kernel App B bins/libs no kernel App C bins/libs no kernel Container runtime (e.g. containerd) ONE shared Host OS kernel Physical hardware No per-app guest OS means containers start in milliseconds, weigh megabytes not gigabytes, and you can pack far more of them onto the same hardware.
A VM's unit of isolation is a whole emulated computer; a container's is a process group fenced off by the kernel. That single architectural choice explains every practical difference below.
DimensiMesin VirtualContainer
Mengisolasi denganMengemulasi perangkat keras (hypervisor)Fitur kernel (namespaces + cgroups)
OS per instanceOS tamu penuh + kernel sendiriBerbagi kernel host; tanpa OS tamu
UkuranGigabyteMegabyte
Waktu mulaiDetik sampai menit (boot OS)Milidetik (mulai proses)
Kepadatan per hostPuluhanRatusan sampai ribuan
Kekuatan isolasiLebih kuat (kernel terpisah)Lebih lemah (kernel bersama), kompromi nyata
The shared-kernel tradeoff

Berbagi satu kernel yang membuat container ringan dan kelemahan keamanan utama mereka: escape level kernel memengaruhi setiap container di host, sementara VM punya batas lebih tebal. Inilah kenapa platform multi-tenant sering menjalankan container di dalam VM, dan kenapa keamanan container (bagian 17, dan bab keamanan) fokus pada least privilege, user non-root, dan membuang capabilities. Container adalah isolasi, bukan sandbox keamanan keras secara default.

03

Apa Sebenarnya Container Itu

Di-demistifikasi: container hanyalah proses Linux normal (atau beberapa) yang diberi tahu kernel untuk diisolasi. Tidak ada objek "container" di kernel, sihirnya tiga fitur Linux lama yang digabung sehingga proses percaya ia punya mesin untuk dirinya sendiri. Memahami ketiganya menghapus semua misteri dan menjelaskan setiap batas dan perilaku yang akan Anda temui.

The three ingredients
A container = namespaces + cgroups + a filesystem image
Namespaces WHAT IT CAN SEE / pid, its own process tree/ net, its own interfaces/ mnt, its own mounts/ uts/ipc/user, hostname, ... cgroups WHAT IT CAN USE / CPU shares / quota/ memory limit/ I/O bandwidth/ pids count Union FS WHAT IT RUNS ON / the image's layers/ read-only base + libs/ thin writable top layer/ its private root "/" Combine the three and an ordinary process is convinced it owns the machine, that illusion is a container.

1. Namespaces: ilusi sendirian

Namespace mempartisi resource kernel global sehingga proses hanya melihat irisan miliknya. PID namespace membuat proses utama container percaya ia PID 1 tanpa saudara; network namespace memberinya interface dan port sendiri; mount namespace memberinya pandangan file system sendiri. Dari dalam, ia tampak seperti mesin privat. Dari host, ia hanya proses dengan label tambahan, ps di host melihat semuanya.

2. cgroups: menegakkan batas

Namespace menyembunyikan sisa sistem; control group (cgroups) membatasi berapa banyak yang boleh dikonsumsi proses, CPU, memori, I/O, jumlah proses. Inilah yang menghentikan satu container melaparkan tetangganya, dan persis mekanisme yang digerakkan Kubernetes saat Anda men-set resource requests dan limits (bagian 17). Lewati batas memori dan kernel OOM killer menghentikan container, status OOMKilled yang terkenal.

3. Image file system: root-nya sendiri

Terakhir proses butuh file: / sendiri dengan runtime, library, dan biner Anda. Itu berasal dari image, dilapiskan ke mount namespace sebagai root file system container (bagian 04). Proses tidak bisa melihat file host, hanya milik image, plus apa pun yang Anda mount eksplisit (bagian 09).

Why "Linux containers" specifically

Namespaces dan cgroups fitur kernel Linux, jadi container aslinya teknologi Linux. Docker di macOS atau Windows diam-diam menjalankan VM Linux ringan dan container Anda hidup di dalamnya, itulah kenapa "container" di Mac Anda sebenarnya Linux-di-dalam-VM di balik layar. Artefaknya portabel; fitur kernel yang ia butuhkan milik Linux.

Part II / Docker / Images & Containers
04

Image, Layer & Union Filesystem

Dua kata sering dikacaukan, jadi kunci dulu. Image adalah template immutable di disk, file system terkemas plus metadata (apa yang dijalankan, port mana, env). Container adalah instance berjalan dari image, image dihidupkan sebagai proses terisolasi (bagian 03). Hubungannya persis class-ke-objek: satu image, banyak container.

An image is to a container what a class is to an object, or what a baked, frozen meal is to the same meal reheated on your plate. You build the image once; you run many identical containers from it.

Image adalah tumpukan layer read-only

Bagian cerdasnya bagaimana image menyimpan file system-nya: sebagai tumpukan layer, masing-masing satu set perubahan file, ditumpuk union filesystem yang menggabungkannya menjadi / koheren tunggal. Setiap instruksi di build Anda menambah satu layer (bagian 05). Layer immutable dan di-alamat-kan oleh konten, jadi layer identik disimpan sekali dan dibagikan lintas image, jika sepuluh image memakai base yang sama, base itu hidup di disk dan bepergian lewat jaringan hanya sekali.

Union filesystem
Read-only layers shared across containers, each with its own thin writable top
IMAGE = read-only layers (shared) L4 COPY app binary +2 MB L3 pip/go install deps +40 MB L2 apt-get runtime libs +25 MB L1 base image (e.g. debian) 50 MB these four layers are stored once & shared CONTAINERS add a writable top writable (C1) writable (C2) both share the same read-only layers below copy-on-write A container reads straight from the shared layers. The instant it modifies a file, that file is copied up into its own writable layer, the image underneath is never touched. That writable layer is ephemeral: delete the container and those changes vanish (sec 09 for persistence).
Layer sharing is why pulling your second image based on the same runtime is nearly instant, and why image size is dominated by your base choice (sec 07).
The writable layer is not storage

Apa pun yang ditulis container ke file system-nya sendiri mati bersama container. Log, upload, file database yang ditulis "di dalam" hilang saat restart. Data persisten harus hidup di volume (bagian 09) atau layanan eksternal. Ephemeralitas ini fitur, inilah yang membuat container sekali pakai dan bisa diganti, tapi ia jebakan pemula yang paling umum.

05

Dockerfile

Dockerfile resep yang membangun image: urutan instruksi, dieksekusi atas ke bawah, masing-masing menghasilkan satu layer (bagian 04). docker build membacanya, menjalankan tiap langkah, dan meng-cache hasilnya. Karena file-nya teks polos di repo Anda, build Anda reproducible dan bisa direview, lingkungan menjadi kode. Ini service web yang sama di-container-kan di Go dan Python:

# FROM picks the base image, the first (bottom) layer. Pin a version, never :latest
FROM golang:1.22

# WORKDIR sets the working dir for the instructions that follow (and at runtime)
WORKDIR /app

# Copy dependency manifests FIRST and download, this layer caches across code edits (sec 7)
COPY go.mod go.sum ./
RUN go mod download

# Now copy the source and build the binary
COPY . .
RUN go build -o /server ./cmd/server

# Document the port the app listens on (metadata; publishing happens at run time sec 8)
EXPOSE 8080

# CMD is the default command run when a container starts from this image
CMD ["/server"]
# Pin a slim base, smaller and fewer CVEs than the full image
FROM python:3.11-slim

WORKDIR /app

# Copy the manifest FIRST so the dependency layer caches across code edits (sec 7)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Then copy the application code
COPY . .

EXPOSE 8080

# Exec form (JSON array), runs the process directly as PID 1, so signals work (sec  graceful shutdown)
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8080"]
InstruksiFungsinya
FROMBase image, layer awal. Semua dibangun di atasnya.
WORKDIRMen-set (dan membuat) direktori saat ini untuk langkah berikutnya dan saat runtime.
COPY / ADDSalin file dari build context Anda ke image. Prefer COPY; ADD punya perilaku URL/tar yang mengejutkan.
RUNJalankan perintah saat build (instal deps, kompilasi), membakar hasilnya ke layer.
ENVSet environment variable yang dibakar ke image (default config, bagian 16).
EXPOSEMendokumentasikan port listening. Informatif; tidak mem-publish-nya (bagian 08).
ENTRYPOINT / CMDYang berjalan saat container mulai. ENTRYPOINT = executable, CMD = argumen default.
Build context & RUN vs CMD

Dua kebingungan yang sering. Build context adalah direktori yang Anda arahkan ke docker build, semua isinya dikirim ke builder, jadi context yang bengkak (mis. node_modules, folder .git) memperlambat build; pangkas dengan .dockerignore (bagian 07). Dan RUN dieksekusi saat build (dibakar ke image) sementara CMD/ENTRYPOINT dieksekusi saat run (saat container mulai). Mencampurnya kesalahan awal klasik.

06

Multi-Stage Build

Teknik paling berdampak tunggal untuk image produksi. Masalahnya: membangun butuh tool berat (kompiler, SDK penuh, dependensi dev build-time) yang tidak dibutuhkan aplikasi yang berjalan. Kirim semuanya dan image Anda besar dan penuh permukaan serangan. Multi-stage build memakai satu stage untuk membangun dan stage kedua yang bersih yang hanya menyalin artefak jadi, toolchain-nya dibuang.

Multi-stage
Build in a heavy stage, copy only the artifact into a tiny final image
STAGE 1 / builder (discarded) golang:1.22 / python full + compiler / full SDK+ build dependencies+ your source tree+ intermediate objects /server (the only keeper) ~900 MB, thrown away after build COPY --from STAGE 2 / final (shipped) distroless / alpine /server ~15 MB, binary + minimal runtime only
# ---- Stage 1: build with the full Go toolchain ----
FROM golang:1.22 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
# static binary, no libc dependency, perfect for a scratch/distroless final image
RUN CGO_ENABLED=0 go build -o /server ./cmd/server

# ---- Stage 2: tiny runtime, no compiler, non-root ----
FROM gcr.io/distroless/static:nonroot
COPY --from=builder /server /server   # copy ONLY the artifact across stages
EXPOSE 8080
USER nonroot:nonroot                  # never run as root (sec 17, security)
ENTRYPOINT ["/server"]
# Result: a ~10-15 MB image with no shell, no package manager, minimal CVEs
# ---- Stage 1: install deps into a venv with build tools available ----
FROM python:3.11 AS builder
WORKDIR /app
RUN python -m venv /venv
ENV PATH="/venv/bin:$PATH"
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt   # may compile native wheels here

# ---- Stage 2: slim runtime, copy the ready venv, run non-root ----
FROM python:3.11-slim
COPY --from=builder /venv /venv          # copy ONLY the built virtualenv
ENV PATH="/venv/bin:$PATH"
WORKDIR /app
COPY . .
RUN useradd -m app && chown -R app /app
USER app                                 # non-root (sec 17)
EXPOSE 8080
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8080"]

Go mengompilasi ke satu biner statis, jadi stage akhir bisa hampir kosong (distroless/scratch). Python butuh interpreter, jadi keuntungannya datang dari menyalin virtualenv yang sudah dibangun ke base -slim alih-alih membawa kompilernya.

Why this matters in production

Image lebih kecil menarik lebih cepat (autoscaling dan rollout lebih cepat, bagian 18), lebih murah disimpan dan ditransfer, dan mengecilkan permukaan serangan dramatis, image distroless tidak punya shell untuk dipakai penyerang. Multi-stage build default untuk image layanan serius mana pun.

07

Optimasi Image & Layer Caching

Dua tuas membuat build cepat dan image ramping, dan keduanya mengikuti langsung dari model layer (bagian 04). Yang pertama urutan cache; yang kedua pilihan base image plus memangkas yang Anda salin.

Urutkan instruksi dari yang paling jarang berubah ke paling sering berubah

Docker meng-cache tiap layer dan memakainya ulang di build berikutnya selama instruksi itu dan semua sebelumnya tidak berubah. Begitu input satu layer berubah, layer itu dan setiap layer sesudahnya dibangun ulang. Jadi aturan emasnya: taruh yang jarang berubah (memasang dependensi) sebelum yang berubah di setiap commit (menyalin source Anda). Itulah kenapa setiap Dockerfile di atas menyalin manifest dependensi dan memasangnya sebelum menyalin source penuh, Anda mengedit kode terus tapi dependensi jarang, jadi layer instalasi mahal tetap ter-cache.

Cache invalidation
Change one layer and everything below it rebuilds
deps BEFORE code, good COPY . . + build ↻ rebuilt RUN install deps ✓ CACHED COPY manifest ✓ CACHED FROM base ✓ CACHED edit code -> only the top layer rebuilds (seconds) code BEFORE deps, bad RUN install deps ↻ rebuilt COPY . . ↻ busts cache FROM base ✓ CACHED edit code -> deps reinstall every time (minutes)

Pilih base kecil & salin lebih sedikit

  • Base image: varian -slim membuang ratusan MB; alpine mungil (musl libc, waspadai kompatibilitas); distroless hanya mengirim aplikasi Anda dan runtime-nya tanpa shell atau package manager (paling aman). Pilih yang terkecil yang menjalankan aplikasi Anda.
  • .dockerignore: menjaga sampah keluar dari build context dan image (build lebih cepat, image lebih kecil, tanpa secret bocor masuk).
  • Gabungkan RUN yang berhubungan & bersihkan di layer yang sama: menghapus cache di layer belakangan tidak mengecilkan image (byte-nya masih hidup di layer awal); bersihkan di dalam RUN yang sama.
.dockerignore / trim the build context
.git
node_modules
*.md
.env            # never bake secrets into an image (sec 16)
**/__pycache__
*.log
dist/
.vscode/
Cleanup must be in the same layer

RUN apt-get install ... di satu baris dan RUN rm -rf /var/lib/apt/lists/* di baris berikutnya tidak mengurangi ukuran, file-nya masih ada di layer instalasi. Rantai keduanya: RUN apt-get update && apt-get install -y X && rm -rf /var/lib/apt/lists/* supaya pembersihan terjadi sebelum layer disegel.

08

Runtime, Registry & Tag

Anda sudah membangun image, sekarang jalankan, bagikan, dan beri versi. Tiga perintah mencakup 90% pemakaian harian, dan tiga konsep (registry, tag, runtime) membingkai siklus hidupnya.

the everyday Docker lifecycle
# BUILD an image from the Dockerfile in . and name:tag it
docker build -t myapp:1.4.0 .

# RUN a container from it:
#   -d detached  -p host:container publishes a port  -e sets an env var (sec 16)
docker run -d -p 8080:8080 -e DATABASE_URL=$DB myapp:1.4.0

# Inspect & debug
docker ps                      # running containers
docker logs -f <id>            # stream stdout/stderr (your app should log there sec logging)
docker exec -it <id> sh        # shell INTO a running container to poke around
docker stop <id>               # sends SIGTERM, then SIGKILL after a grace period (sec graceful shutdown)

# SHARE via a registry
docker tag  myapp:1.4.0 registry.example.com/team/myapp:1.4.0
docker push registry.example.com/team/myapp:1.4.0     # upload
docker pull registry.example.com/team/myapp:1.4.0     # download (what prod/K8s does)

Registry, repository, tag

Registry server penyimpan image (Docker Hub, GitHub Container Registry, AWS ECR, Google Artifact Registry). Repository image bernama di dalamnya; tag label untuk versi spesifik (myapp:1.4.0). Push mengunggah layer Anda; pull mengunduhnya, dan berkat layer ber-alamat-konten (bagian 04), hanya layer yang belum dimiliki registry yang bergerak lewat kabel. Siklus push/pull ini serah terima antara build Anda (bagian 19) dan tempat image berjalan (Bagian IV).

The image lifecycle
Build once, push to a registry, pull anywhere to run
docker buildDockerfile push Registrystores tagged layers pull CI runs tests staging production (K8s)
Never deploy :latest

latest hanya tag yang bergerak; ia tidak berarti "terbaru" dan tidak memberi tahu apa yang berjalan. Dua mesin menarik :latest berselang sehari bisa mendapat image berbeda, persis non-reproducibility yang ingin dimatikan container. Tag dengan versi immutable atau git commit SHA (myapp:1.4.0, myapp:git-9f2c1a) supaya container yang berjalan memetakan ke source persis.

OCI: the standard underneath

"Docker image" singkatan, formatnya distandarkan Open Container Initiative (OCI), itulah kenapa image yang dibangun Docker berjalan di runtime lain (containerd, CRI-O, Podman) dan di Kubernetes tanpa Docker terpasang. Anda membangun ke spesifikasi, bukan ke satu vendor.

Part III / Multi-Container & Local Dev
09

Networking & Volume

Dua kebutuhan muncul begitu Anda menjalankan lebih dari mainan: container harus bicara satu sama lain, dan sebagian data harus lebih awet dari container. Docker menjawabnya dengan network dan volume, dan keduanya langsung mengisi celah yang ditinggalkan model isolasi (bagian 03) dan layer writable ephemeral (bagian 04).

Networking: dari terisolasi ke terhubung

Secara default tiap container punya network namespace sendiri, jadi ia tidak bisa melihat yang lain. Taruh container di bridge network user-defined yang sama dan Docker memberi mereka LAN virtual privat plus DNS bawaan: container mencapai yang lain cukup dengan namanya (http://db:5432). Ini fondasi service discovery, dan itulah kenapa Compose (bagian 10) dan Kubernetes (bagian 15) membiarkan service saling mengalamati dengan nama alih-alih IP rapuh. Terpisah, port publishing (-p 8080:8080) melubangi host ke container supaya dunia luar bisa menjangkaunya.

Container networking
A user-defined network gives name-based discovery; a published port exposes one service
bridge network: appnet api:8080 db:5432 connect to "db" host :8080 -> api :8080 (published) db is NOT published, private to the network

Volume: data yang bertahan

Karena layer writable container dihancurkan bersama container (bagian 04), apa pun yang harus persisten, file database, upload pengguna, hidup di volume: penyimpanan yang dikelola Docker (atau host) dan di-mount ke container, terlepas dari siklus hidupnya. Hapus dan buat ulang container; volume dan datanya tetap. Ada dua rasa: named volume (dikelola Docker, default untuk data sungguhan) dan bind mount (direktori host dipetakan masuk, berguna di pengembangan untuk mengedit kode langsung tanpa rebuild).

MekanismePakai untuk
Named volume -v dbdata:/var/lib/postgresql/dataData aplikasi persisten yang dikelola Docker, database, cache yang ingin Anda simpan.
Bind mount -v ./src:/app/srcLive reload saat dev, edit di host, lihat perubahan di container seketika.
tmpfsData scratch sensitif yang hanya di RAM, tidak pernah ditulis ke disk.
Stateless containers, stateful volumes

Perlakukan container sebagai sekali pakai dan simpan semua state tahan lama di volume atau layanan terkelola eksternal. Di Kubernetes khususnya, pola yang berlaku stateless app container (mudah di-scaling dan diganti, bagian 18) dengan state didorong ke database terkelola atau persistent volume. Jika mematikan container kehilangan data, desainnya membocorkan state ke tempat yang salah.

10

Docker Compose

Menjalankan aplikasi nyata berarti beberapa container, API, database, cache, mungkin worker (setup bab task-queue), dengan network, volume, env, dan urutan mulai yang tepat. Merangkainya manual dengan banyak perintah docker run membosankan dan rawan error. Docker Compose mendeklarasikan seluruh stack lokal dalam satu file YAML dan menaikkannya dengan satu perintah. Ia standar untuk pengembangan lokal dan deployment single-host sederhana.

compose.yaml / an API (your Go or Python service), Postgres, and Redis
services:
  api:
    build: .                      # build the image from the local Dockerfile (sec 5/6)
    ports:
      - "8080:8080"               # publish to the host (sec 9)
    environment:                  # config via env, not baked in (sec 16)
      DATABASE_URL: postgres://app:secret@db:5432/app   # reach "db" by name (sec 9 DNS)
      REDIS_URL: redis://cache:6379
    depends_on:
      db:
        condition: service_healthy   # wait until the DB passes its healthcheck
      cache:
        condition: service_started

  db:
    image: postgres:16
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: app
    volumes:
      - dbdata:/var/lib/postgresql/data   # named volume = data survives restarts (sec 9)
    healthcheck:                          # so depends_on can wait for readiness
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 5s
      retries: 5

  cache:
    image: redis:7

volumes:
  dbdata:                          # declared once, referenced above
running the stack
docker compose up -d        # build (if needed) + start everything in the background
docker compose ps           # status of all services
docker compose logs -f api  # tail one service's logs
docker compose down         # stop & remove containers + network (volumes kept)
docker compose down -v      # ...and delete the volumes too (fresh DB)
Compose vs Kubernetes

Compose untuk satu host: hebat untuk dev lokal dan deployment kecil, tapi ia tidak menjadwalkan lintas mesin, menyembuhkan diri, atau autoscale. Begitu Anda butuh banyak node, restart otomatis, update bergulir, dan scaling horizontal, Anda sudah melampaui Compose dan ingin orkestrator (Bagian IV). Model mentalnya terbawa: service Compose memetakan dekat ke Deployment + Service Kubernetes.

Where we are
From one container to a fleet, the road into orchestration
1 containerdocker run many, one hostdocker compose fleet, many nodesKubernetes -> Part IV
Part IV / Kubernetes / Orchestration
11

Kenapa Orkestrasi

Docker memberi Anda container; ia tidak, dengan sendirinya, menjalankannya andal lintas banyak mesin. Begitu Anda punya puluhan container di armada server, muncul set masalah baru yang tidak bisa dipecahkan docker run mana pun, dan orkestrasi lapisan yang memecahkannya. Kubernetes (sering "K8s") standar de facto.

Masalah di skala armadaYang dilakukan orkestrator
Mesin mana yang harus ditempati tiap container?Scheduling: menempatkan container di node berdasarkan CPU/memori tersedia.
Container (atau seluruh node) mati jam 3 pagi.Self-healing: me-restart container yang crash, menjadwal ulang dari node mati, otomatis.
Lonjakan lalu lintas; Anda butuh lebih banyak salinan, lalu lebih sedikit.Scaling: menjalankan N replika dan menambah/menghapusnya sesuai permintaan (bagian 18).
Container datang dan pergi; IP mereka berubah.Service discovery + load balancing: alamat stabil yang menyebar ke replika sehat (bagian 15).
Kirim versi baru tanpa downtime.Rolling update & rollback: mengganti replika bertahap, kembali saat gagal (bagian 18).
Config & secret berbeda per lingkungan.Manajemen config: menyuntikkan setelan/secret tanpa membangun ulang image (bagian 16).

Gagasan inti: deklaratif, desired state

Pergeseran pola pikir yang membuat Kubernetes klik: Anda tidak mengeluarkan perintah imperatif ("mulai container di sini"). Anda mendeklarasikan desired state ("aku mau 5 replika image ini, terjangkau di alamat ini") dan Kubernetes terus bekerja membuat kenyataan cocok. Jika container mati, aktual turun ke 4, dan control loop melihat celahnya dan memulai yang lain, tanpa Anda melakukan apa pun. Anda mendeskripsikan apa; Kubernetes menangani bagaimana dan menjaganya tetap benar.

Imperative is telling a driver every turn. Declarative is giving a destination to a self-correcting autopilot: drift off course, a crash, a dead node, and it steers back on its own, continuously, without new instructions.
Reconciliation in one line

Semuanya di Kubernetes adalah control loop yang membandingkan desired state (yang Anda deklarasikan) dengan actual state (yang berjalan) dan mengambil tindakan menutup celah. Internalisasi loop itu dan seluruh sistem, Deployment, scaling, penyembuhan, rollout, menjadi satu gagasan yang diterapkan berulang-ulang.

12

Arsitektur Kubernetes

Klaster Kubernetes dua jenis mesin: control plane (otak yang memutuskan apa yang harus berjalan) dan set worker node (otot tempat container sebenarnya berjalan). Anda hanya bicara ke control plane, Anda mengirimkan desired state, dan klaster mewujudkannya.

Cluster anatomy
Control plane decides; nodes run; the reconciliation loop connects them
CONTROL PLANE, the brain api-serverthe one front door schedulerpicks a node controller-mgrruns the loops etcdthe source of truth all state lives in etcd; everything talks via the api-server WORKER NODE 1, the muscle kubelet kube-proxy (networking) pod pod pod WORKER NODE 2 pod pod pod you: kubectl applydesired state (YAML) api-server writes your desired state to etcd; controllers + scheduler reconcile it onto nodes; kubelets run the pods. kubelets continuously report actual state back, closing the loop.
KomponenPeran
api-serverSatu-satunya titik masuk. Setiap baca/tulis state klaster melewatinya (kubectl Anda, setiap komponen).
etcdKey-value store terdistribusi yang memegang seluruh state klaster, sumber kebenaran.
schedulerMemutuskan node mana yang ditempati pod baru, berdasarkan resource requests dan batasan.
controller-managerMenjalankan loop rekonsiliasi (controller Deployment, dll.) yang menggerakkan aktual menuju desired.
kubeletAgen di tiap node; memulai/menghentikan container dan melaporkan kesehatannya ke api-server.
kube-proxyMemprogram networking node supaya virtual IP Service merutekan ke pod yang tepat (bagian 15).
You rarely run this yourself

Kubernetes terkelola (GKE, EKS, AKS) mengoperasikan control plane untuk Anda, jadi dalam praktik Anda berinteraksi dengan klaster murni lewat api-server via kubectl dan YAML. Mengetahui bagian-bagiannya tetap penting untuk debugging, "pod stuck in Pending" biasanya scheduler tidak menemukan node dengan ruang (bagian 17).

13

Pod

Pod unit atomik Kubernetes, hal terkecil yang ia jadwalkan. Yang penting, Anda tidak men-deploy container langsung; Anda men-deploy pod, dan pod membungkus satu atau lebih container yang selalu di-lokasi-bersama di node yang sama dan berbagi network namespace dan penyimpanan. Container dalam pod saling menjangkau di localhost dan bisa berbagi volume ter-mount, mereka satu unit kooperatif.

Biasanya pod memegang tepat satu container (aplikasi Anda). Kasus multi-container adalah pola sidecar: pembantu di samping aplikasi utama, log shipper, metrik exporter, atau proxy service-mesh (Envoy dari bab gRPC bagian 19). Sidecar berbagi network pod jadi ia bisa mengamati atau mem-proxy lalu lintas aplikasi secara transparan.

Pod internals
Containers in a pod share one network & can share storage
POD, shares one IP & lifecycle app container:8080 sidecarlog shipper / proxy localhost one pod IP / same node / live and die together
Pods are mortal and disposable

Pod ephemeral: ia bisa dibunuh dan diganti kapan pun (kegagalan node, scale-down, rollout), dan penggantinya mendapat IP baru. Jadi Anda tidak pernah hard-code IP pod dan tidak pernah mengandalkan pod spesifik bertahan. Persis inilah kenapa Service ada (bagian 15), memberi alamat stabil di depan set pod yang terus berubah, dan kenapa Anda membiarkan Deployment mengelola pod alih-alih membuatnya langsung (bagian 14).

14

Deployment & ReplicaSet

Anda hampir tidak pernah membuat pod manual, pod telanjang tidak diganti jika mati. Gantinya Anda mendeklarasikan Deployment: "jaga N replika template pod ini berjalan, selalu." Deployment mengelola ReplicaSet, yang satu-satunya tugas menjaga jumlah replika, dan ReplicaSet mengelola pod. Ini loop rekonsiliasi (bagian 11) dibuat konkret: deklarasikan 5, pod mati, aktual jadi 4, controller memulai yang baru, self-healing, gratis.

The ownership chain
Deployment -> ReplicaSet -> Pods, kept at the desired count
Deploymentreplicas: 3 manages ReplicaSetkeeps count = 3 pod ✓ running pod ✓ running pod ✗ died ->controller recreates it Actual fell to 2, desired is 3 -> the gap is detected and a fresh pod is started, automatically.
deployment.yaml / declare 3 replicas of your image
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 3                 # desired state: always keep 3 pods
  selector:
    matchLabels: { app: api } # which pods this Deployment owns
  template:                   # the POD TEMPLATE stamped out for each replica
    metadata:
      labels: { app: api }
    spec:
      containers:
        - name: api
          image: registry.example.com/team/myapp:1.4.0   # pinned tag, never :latest (sec 8)
          ports:
            - containerPort: 8080
          # resources, env, and probes go here too, see sec 16 and sec 17
driving it with kubectl
kubectl apply -f deployment.yaml     # submit desired state (declarative)
kubectl get pods -l app=api          # see the 3 pods it created
kubectl scale deployment/api --replicas=10   # change desired count -> controller adds 7
kubectl rollout status deployment/api        # watch a new version roll out (sec 18)
kubectl rollout undo  deployment/api          # roll back to the previous version (sec 18)
Other workload kinds

Deployment untuk aplikasi stateless (kasus umum). Ada saudara untuk bentuk lain: StatefulSet untuk aplikasi ber-state yang butuh identitas/penyimpanan stabil (database), DaemonSet untuk menjalankan satu pod per node (agen log/metrik), dan Job/CronJob untuk run-to-completion dan tugas terjadwal (sisi batch dari bab task-queue). Gagasan rekonsiliasi yang sama, jaminan berbeda.

15

Service & Ingress

Pod fana dan IP mereka berganti (bagian 13), jadi Anda tidak bisa mengarahkan lalu lintas ke pod. Service perbaikannya: virtual IP dan nama DNS yang stabil di depan set pod dinamis, dengan load balancing bawaan. Ia memakai label selector untuk melacak "semua pod dengan app: api", saat pod datang dan pergi, set endpoint sehat Service diperbarui otomatis, dan pemanggil tidak pernah menyadarinya. Ini service discovery Kubernetes, dan itulah kenapa satu service mengalamati yang lain dengan nama (http://api), persis seperti Compose di satu host (bagian 9).

Service abstraction
A stable address that load-balances across whatever pods currently match
callerhttp://api Service: apistable IP + DNS / selector app=api pod (app=api) ✓ pod (app=api) ✓ pod removed, dropped Only Ready pods (per readiness probe sec 17) receive traffic; the rest are pulled from rotation.

Tipe Service & Ingress

Service ClusterIP (default) hanya terjangkau di dalam klaster, pas untuk panggilan antar-layanan. Untuk menerima lalu lintas dari luar, Anda memakai Service LoadBalancer (cloud menyediakan load balancer eksternal, satu per service, mahal di skala) atau, jauh lebih umum untuk HTTP, Ingress: satu titik masuk L7 yang merutekan berdasarkan host dan path ke banyak Service pendukung. Ingress tempat TLS termination dan routing host/path hidup, pintu depan publik klaster, dan rumah alami untuk edge REST yang dijelaskan di bab gRPC (bagian 18-19 di sana).

EksposurTerjangkau dariPakai untuk
ClusterIPHanya di dalam klasterAntar-layanan (kebanyakan service internal)
NodePortSebuah port di setiap nodeAkses eksternal dasar/dev
LoadBalancerInternet (LB cloud)Satu service TCP/UDP diekspos langsung
IngressInternet, via aturan L7Routing host/path HTTP + TLS untuk banyak service lewat satu titik masuk
service.yaml + ingress.yaml
apiVersion: v1
kind: Service
metadata:
  name: api               # other pods reach this as http://api (cluster DNS)
spec:
  selector: { app: api }  # front the pods labelled app=api (from the Deployment sec 14)
  ports:
    - port: 80            # the Service port callers use
      targetPort: 8080    # the containerPort it forwards to
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: edge
spec:
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api          # route external HTTP to the api Service
                port: { number: 80 }
The full path of a request

Klien eksternal -> Ingress (TLS, routing host/path) -> Service (IP stabil, load-balance) -> Pod sehat -> container Anda. Setiap hop menambah satu perhatian, routing, penemuan, kerja sebenarnya, dan bersama-sama mereka cara satu paket dari internet mencapai satu replika aplikasi Anda.

16

Config, Secret & Environment

Image harus agnostik lingkungan: image yang sama yang diuji berjalan di dev, staging, dan prod, hanya konfigurasi yang berbeda (URL database, feature flag, kredensial). Jadi konfigurasi disuntikkan saat run time, tidak pernah dibakar ke image. Ini bentuk containerized dari aturan inti bab manajemen config, dan ekspresi klasik twelve-factor "config in the environment." Kubernetes menyediakan dua objek: ConfigMap untuk setelan non-rahasia dan Secret untuk nilai sensitif.

Config injection
One image, many environments, config supplied from outside
one tested imagemyapp:1.4.0 dev+ ConfigMap-dev + Secret-dev staging+ ConfigMap-stg + Secret-stg production+ ConfigMap-prod + Secret-prod
configmap + secret, injected as env vars
apiVersion: v1
kind: ConfigMap
metadata: { name: api-config }
data:
  LOG_LEVEL: "info"
  FEATURE_NEW_CHECKOUT: "true"
---
apiVersion: v1
kind: Secret
metadata: { name: api-secrets }
type: Opaque
stringData:                       # plaintext here; stored base64-encoded in etcd
  DATABASE_URL: "postgres://app:secret@db:5432/app"
---
# ...inside the Deployment's container spec (sec 14):
#   envFrom:
#     - configMapRef: { name: api-config }    # all keys -> env vars
#     - secretRef:    { name: api-secrets }   # secret keys -> env vars
# Your app then reads os.Getenv("LOG_LEVEL") / os.environ["DATABASE_URL"] (sec config chapter)
Secrets are not encrypted by default

Secret Kubernetes hanya di-encode base64 di etcd, tidak dienkripsi, base64 encoding, bukan proteksi. Untuk keamanan nyata aktifkan encryption at rest untuk etcd, kunci RBAC supaya sedikit identitas yang bisa membaca Secret, dan untuk sistem sensitif pakai manajer eksternal (Vault, cloud secret store, atau Secrets Store CSI driver). Dan jangan pernah commit nilai secret nyata ke Git, disiplin jangan-bocorkan-kredensial yang sama dengan bab keamanan dan auth.

17

Health Probe & Manajemen Resource

Agar self-healing dan zero-downtime bekerja, Kubernetes perlu tahu dua hal tentang tiap pod: apakah ia hidup? dan apakah ia siap menerima lalu lintas? Ia tidak bisa menebak, aplikasi Anda harus memberitahunya, via probe. Dan untuk menjadwalkan dan mengisolasi dengan adil, ia perlu tahu berapa banyak CPU dan memori yang diinginkan tiap container, via requests dan limits (cgroups dari bagian 03, dimunculkan sebagai config).

Tiga probe, tiga pertanyaan

  • Liveness: "apakah proses sehat, atau macet?" Jika gagal, Kubernetes me-restart container. Menangkap deadlock dan state menggantung yang tidak akan ditangkap crash.
  • Readiness: "bisakah ia melayani request sekarang?" Jika gagal, pod ditarik dari rotasi Service-nya (bagian 15) tapi tidak di-restart. Inilah yang memungkinkan rollout zero-downtime dan backpressure: pod yang sedang memanas atau sebentar kelebihan beban berhenti menerima lalu lintas sampai pulih.
  • Startup: "apakah aplikasi yang mulai lambat selesai boot?" Menjaga probe lain supaya cold start panjang tidak disangka kegagalan.
Liveness vs readiness
Restart on liveness failure; stop sending traffic on readiness failure
kubelet probes the podGET /healthz / /ready liveness fails-> RESTART the container readiness fails-> remove from Service rotation

Requests & limits

Request jumlah yang direservasi scheduler untuk container (dan dipakai memilih node); limit plafon keras yang ditegakkan runtime via cgroups. Lewati batas CPU dan container di-throttle; lewati batas memori dan ia dibunuh (OOMKilled). Men-set keduanya dengan baik pembeda antara klaster stabil dan kekacauan tetangga berisik, dan mereka memberi makan autoscaling (bagian 18).

probes + resources in the container spec
# ...inside the Deployment's containers: entry (sec 14)
          livenessProbe:
            httpGet: { path: /healthz, port: 8080 }   # wedged? -> restart
            initialDelaySeconds: 5
            periodSeconds: 10
          readinessProbe:
            httpGet: { path: /ready, port: 8080 }      # ready for traffic? -> in/out of rotation
            periodSeconds: 5
          resources:
            requests: { cpu: "100m", memory: "128Mi" } # scheduler reserves this
            limits:   { cpu: "500m", memory: "256Mi" } # cgroup ceiling; over memory -> OOMKilled
Probes pair with graceful shutdown

Probe hanya separuh penanganan siklus hidup yang bersih. Separuh lainnya bab graceful shutdown: saat rollout atau scale-down, Kubernetes mengirim SIGTERM dan menunggu masa tenggang sebelum SIGKILL. Aplikasi Anda harus menggagalkan readiness probe seketika (hentikan lalu lintas baru), selesaikan request in-flight, lalu keluar, supaya tidak ada request yang dijatuhkan di tengah jalan. Probe memutuskan apa yang mendapat lalu lintas; graceful shutdown memutuskan bagaimana pod pergi.

18

Scaling & Rollout

Dua operasi sehari-hari menutup orkestrasi: menangani lebih banyak beban (scaling) dan mengirim versi baru tanpa downtime (rollout). Keduanya bersandar pada semua yang dibangun sejauh ini, replika, Service, readiness probe, dan keduanya ekspresi Kubernetes dari topik bab scaling.

Scaling horizontal & autoscaling

Scaling horizontal berarti menjalankan lebih banyak pod replika (lebih disukai daripada membuat satu pod lebih besar, tema horizontal-vs-vertikal dari bab scaling). Anda bisa set jumlahnya manual, atau menyerahkannya ke Horizontal Pod Autoscaler (HPA), yang memantau metrik (biasanya CPU) dan menyesuaikan replika untuk menahan target, scaling keluar di bawah beban dan kembali saat mereda. Karena app pod stateless (bagian 9), replika mana pun bisa melayani request apa pun, jadi menambah pod tinggal bekerja.

hpa.yaml / autoscale on CPU
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: { name: api }
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target: { type: Utilization, averageUtilization: 70 }  # keep avg CPU ~70%
# Requires resource requests (sec 17), utilization is measured against the request.

Rolling update & rollback

Saat Anda mengubah tag image dan menerapkan ulang, Deployment melakukan rolling update secara default: ia menaikkan pod versi baru beberapa sekaligus, menunggu tiap pod lolos probe readiness-nya (bagian 17) sebelum mengirimnya lalu lintas, dan baru setelah itu pensiunkan pod lama. Di setiap momen cukup pod sehat yang melayani, jadi pengguna tidak melihat downtime. Jika pod baru gagal readiness, rollout berhenti alih-alih merobohkan aplikasi, dan satu perintah kembali ke versi baik terakhir.

Rolling update
Replace replicas gradually, always keep a healthy serving set
start v1 v1 v1 mid-rollout v2 v1 v1 (+v2 warming) done v2 v2 v2 A new pod only takes traffic after passing readiness; old pods drain gracefully (sec 17). If v2 never becomes Ready, the rollout halts, capacity is never sacrificed.
It all comes together here

Deploy zero-downtime bukan satu fitur, ia komposisi dari replika (bagian 14), readiness probe (bagian 17), graceful shutdown, dan abstraksi Service (bagian 15) yang menjaga alamat stabil di atas set pod yang bergeser. Setiap bagian mendapat tempatnya; rollout tempat mereka membayar.

Part V / CI/CD & Production
19

Pipeline CI/CD

Container membuat artefak reproducible; CI/CD membuat jalur dari commit kode ke artefak itu berjalan di produksi otomatis. CI (Continuous Integration) paruh build-dan-verifikasi, di setiap push, bangun image, jalankan tes, pindai. CD (Continuous Delivery/Deployment) paruh pengiriman, dorong image ke registry dan rollout. Intinya menghapus langkah manual yang rawan error supaya deploy sering, kecil, dan membosankan.

The pipeline
From commit to running pod, with gates along the way
commitgit push buildimage sec 6 testunit/integ scanCVEs pushregistry sec 8 deployrollout sec 18 Each stage is a gate: a failed test or a critical CVE stops the pipeline before anything reaches production.
.github/workflows/deploy.yaml / a representative pipeline
name: ci-cd
on:
  push:
    branches: [main]

jobs:
  build-test-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run tests              # CI gate, must pass before we ship (sec testing chapter)
        run: make test               # go test ./...  |  pytest

      - name: Build image
        run: docker build -t $REGISTRY/myapp:${{ github.sha }} .   # tag = commit SHA (sec 8)

      - name: Scan image for vulnerabilities
        run: trivy image --severity HIGH,CRITICAL --exit-code 1 $REGISTRY/myapp:${{ github.sha }}

      - name: Push to registry
        run: |
          echo "$REGISTRY_TOKEN" | docker login $REGISTRY -u ci --password-stdin
          docker push $REGISTRY/myapp:${{ github.sha }}

      - name: Deploy to Kubernetes   # update the Deployment's image -> triggers a rolling update (sec 18)
        run: kubectl set image deployment/api api=$REGISTRY/myapp:${{ github.sha }}
Why tag by commit SHA

Men-tag image dengan git SHA (dan men-deploy tag persis itu) memberi tautan presisi immutable dari pod yang berjalan kembali ke source yang membangunnya, tujuan reproducibility dari bagian 8, end to end. Saat sesuatu rusak di produksi Anda tahu persis commit mana yang berjalan, dan rollback (bagian 18) tidak ambigu.

20

Strategi Deployment & GitOps

Rolling update (bagian 18) default, tapi rilis berisiko menuntut strategi yang membatasi radius ledakan, dan tim matang mengubah cara deploy dipicu sama sekali dengan GitOps.

StrategiCara kerjanyaKompromi
RollingGanti pod bertahap (default)Sederhana, zero-downtime; lama + baru berjalan sebentar bersama
Blue-greenDirikan versi baru penuh (green) di samping lama (blue), lalu alihkan semua lalu lintas sekaligusPeralihan instan & rollback instan; butuh kapasitas dua kali lipat selama cutover
CanaryKirim % kecil lalu lintas ke versi baru, amati metrik, lalu naikkanPaling aman untuk perubahan berisiko; butuh lebih banyak orkestrasi/observabilitas
Blue-green vs canary
Flip all at once, or trickle traffic and watch
blue-green, flip 100% blue v1 green v2 switch router blue->green instantly problem? flip back to blue at once canary, trickle then ramp v1-95% v2-5% watch v2's error rate & latency healthy -> 5% -> 25% -> 100% bad -> route 0% back, blast radius tiny

GitOps: Git sebagai sumber kebenaran

Pipeline di bagian 19 mendorong perubahan ke klaster. GitOps membaliknya: desired state klaster hidup sepenuhnya di repositori Git (semua manifest YAML itu), dan agen di dalam klaster (Argo CD, Flux) terus menarik dari Git dan merekonsiliasi klaster agar cocok. Ini loop rekonsiliasi bagian 11 diperluas ke deployment itu sendiri: Git adalah desired state, klaster actual state, agen menutup celah. Anda deploy dengan menggabungkan pull request; rollback dengan git revert; dan repo-nya riwayat lengkap teraudit dari setiap perubahan ke produksi.

The throughline

Perhatikan gagasan yang sama di tiga skala: container menjaga artefak identik, Deployment menjaga pod yang berjalan cocok dengan spesifikasi, dan GitOps menjaga seluruh klaster cocok dengan Git. Deklarasikan desired state, biarkan loop merekonsiliasi kenyataan, itu container dan Kubernetes turun ke bawah.

21

Crib-Sheet Produksi

Seluruh manual dipadatkan menjadi yang Anda raih saat tertekan.

KonsepSatu baris
ContainerProses terisolasi, namespaces (apa yang ia lihat) + cgroups (apa yang ia pakai) + file system image.
vs VMContainer berbagi satu kernel host; VM masing-masing mengirim OS penuh. Lebih ringan, lebih cepat, isolasi lebih lemah.
Image vs containerImage = template immutable (class); container = instance berjalan (objek).
LayerImage adalah layer read-only bertumpuk, dibagikan & di-cache; lapisan writable container ephemeral.
DockerfileResep; tiap instruksi = satu layer. RUN saat build, CMD saat run.
Multi-stageBangun di stage berat, salin hanya artefaknya ke image akhir mungil.
Urutan cacheDependensi sebelum kode, layer yang berubah membangun ulang semua di bawahnya.
Registry & tagPush/pull image berdasarkan nama:tag; pin versi atau SHA, jangan pernah :latest.
VolumeData yang harus bertahan hidup di volume, bukan layer writable container.
ComposeStack multi-container deklaratif di satu host, dev lokal.
OrkestrasiScheduling, self-healing, scaling, penemuan, rollout lintas banyak node.
DeklaratifDeklarasikan desired state; control loop merekonsiliasi aktual menuju ke sana. Seluruh model.
PodUnit terkecil; satu+ container berbagi network & storage. Fana, dapat IP baru saat diganti.
DeploymentMenjaga N replika pod berjalan; self-heal; melakukan rolling update.
ServiceIP/DNS stabil load-balancing lintas pod yang cocok, service discovery.
IngressSatu titik masuk L7: routing host/path + TLS ke banyak Service.
Config/SecretSuntikkan saat run time (ConfigMap/Secret); image sama di mana-mana. Secret tidak dienkripsi secara default.
ProbeLiveness -> restart; readiness -> masuk/keluar rotasi; startup -> jaga boot lambat.
Requests/limitsRequest = direservasi (scheduling); limit = plafon cgroup. Lewati memori -> OOMKilled.
ScalingJalankan lebih banyak replika; HPA autoscale pada metrik (butuh requests di-set).
Rollout/rollbackGanti bertahap digerbangi readiness; kubectl rollout undo mengembalikan.
CI/CDCommit -> build -> test -> scan -> push -> deploy, otomatis; tag dengan SHA.
StrategiRolling (default), blue-green (peralihan instan), canary (menetes & amati).
GitOpsGit adalah desired state; agen menarik & merekonsiliasi. Deploy dengan PR, rollback dengan revert.

Seluruh topik dalam satu tarikan napas: container mengemas aplikasi Anda dengan seluruh lingkungannya supaya "yang berjalan di prod" sama dengan "yang Anda uji" (bagian 1), dicapai dengan namespaces dan cgroups Linux, bukan VM berat (bagian 2-3). Anda membangun image sebagai layer ter-cache yang bisa dibagikan (bagian 4) dari Dockerfile (bagian 5), mengecilkan dan mengeraskannya dengan multi-stage build dan urutan cache yang baik (bagian 6-7), lalu push image ber-tag SHA ke registry (bagian 8). Secara lokal Anda merangkai beberapa container dengan network, volume, dan Compose (bagian 9-10). Di skala armada, Kubernetes merekonsiliasi desired state yang dideklarasikan ke node (bagian 11-12): Deployment menjaga replika pod tetap hidup dan self-healing (bagian 13-14), Service dan Ingress memberi pengalamatan dan routing stabil (bagian 15), ConfigMap/Secret menyuntikkan config per-lingkungan (bagian 16), probe dan resource requests/limits menggerakkan kesehatan dan scheduling (bagian 17), dan HPA plus rolling update mengirim scaling dan rilis zero-downtime (bagian 18). CI/CD mengotomasi commit->build->test->scan->push->deploy (bagian 19), dan blue-green/canary/GitOps membuat rilis aman dan teraudit (bagian 20). Satu gagasan berulang di setiap lapisan: deklarasikan desired state dan biarkan loop menjaga kenyataan cocok dengannya.

Berpijak pada dokumentasi Docker & Kubernetes / OCI image-spec / Twelve-Factor App / contoh aplikasi Go 1.22+ / Python 3.11+.