Studi Kasus & Jalan ke Produksi Cloud
Chapter penutup menyatukan semuanya: satu stack skincare-api yang mirip produksi dijalankan dengan satu perintah, lima jebakan khas dibongkar, lalu peta jelas dari image lokal ke CI/CD dan AWS.
Lima chapter sebelumnya memberi kepingan-kepingannya: mental model, image multi-stage, config dan jaringan dan volume, Compose, lalu registry dan pengerasan produksi. Chapter penutup ini merangkainya jadi satu gambar utuh, sebuah studi kasus skincare-api yang realistis, membongkar pitfall yang paling sering menjatuhkan pendatang dari JS/PHP, dan memetakan langkah dewasa berikutnya menuju cloud, sebelum menutup dengan ringkasan keseluruhan course.
Studi Kasus: Containerize Go API Skincare
Stack lengkap plus pitfalls khas developer JS/PHP
Saatnya menyatukan semua konsep menjadi satu stack lokal yang realistis: API Go, PostgreSQL, dan Redis, dijalankan dengan satu perintah.
Target kita adalah skincare-api, backend online shop skincare yang sudah kamu kenal sepanjang course ini. API ini membaca produk dari PostgreSQL, men-cache hasilnya di Redis, dan mengekspos GET /healthz agar Compose tahu kapan container siap melayani. Tujuannya bukan sekadar “bisa jalan”, tapi menyusun stack yang mirip produksi: build kecil dengan multi-stage, config lewat env, dan dependency yang digerbangi healthcheck.
Dockerfile final skincare-api
Kita pakai pola multi-stage dari Chapter 2: stage golang:1.26 untuk compile, lalu runtime distroless yang ramping dan non-root. Biner Go statis (CGO_ENABLED=0) muat di distroless/static-debian12 tanpa shell, jadi permukaan serangan tipis.
Dockerfile# --- build --- FROM golang:1.26 AS build WORKDIR /src COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app ./cmd/server # --- runtime --- FROM gcr.io/distroless/static-debian12:nonroot COPY --from=build /app /app USER nonroot:nonroot EXPOSE 8080 ENTRYPOINT ["/app"]
Perhatikan COPY go.mod go.sum lebih dulu sebelum COPY . .. Itu bukan gaya, melainkan trik cache layer: selama dependency tidak berubah, go mod download tidak dijalankan ulang walau kode handler kamu berubah ratusan kali.
Config env dan health endpoint
Aplikasi membaca semuanya dari environment, tidak ada nilai hardcode. Health endpoint dibuat ringan, tidak menyentuh database, agar cepat dan tidak ikut menumbangkan API saat DB lambat.
cmd/server/main.gopackage main import ( "net/http" "os" "github.com/kamu/skincare-backend/internal/server" ) func main() { cfg := server.Config{ Addr: ":" + envOr("PORT", "8080"), DatabaseURL: os.Getenv("DATABASE_URL"), RedisAddr: os.Getenv("REDIS_ADDR"), } http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte(`{"status":"ok"}`)) }) server.Run(cfg) }
Di Laravel, .env dibaca proses PHP saat boot; di sini env disuntik Compose ke proses container, jadi satu image yang sama bisa jalan beda config tanpa rebuild.
Arsitektur stack final
flowchart LR
Dev["curl :8080"] --> API["skincare-api\n(EXPOSE 8080)"]
API -->|appnet DNS: db:5432| DB[("postgres:17")]
API -->|appnet DNS: cache:6379| R[("redis:7")]
DB -.named volume.-> V[("pgdata")]Stack lokal skincare. API bicara ke db dan cache lewat nama service, bukan IP; data Postgres bertahan di named volume pgdata.
Compose stack final
compose.yamlservices: api: build: . ports: - "8080:8080" environment: PORT: "8080" DATABASE_URL: "postgres://app:secret@db:5432/skincare?sslmode=disable" REDIS_ADDR: "cache:6379" depends_on: db: condition: service_healthy cache: condition: service_started db: image: postgres:17 environment: POSTGRES_USER: app POSTGRES_PASSWORD: secret POSTGRES_DB: skincare volumes: - pgdata:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U app"] interval: 5s timeout: 3s retries: 5 cache: image: redis:7 volumes: pgdata:
Tidak ada version: di atas. Atribut itu sudah usang dan diabaikan Compose modern, malah memunculkan peringatan. Service bernama db dan cache, persis nama yang dipakai API di DATABASE_URL dan REDIS_ADDR, karena Compose membuat user-defined network dengan DNS antar service otomatis.
Lima pitfalls khas dan cara debug
Inilah lima jebakan yang paling sering menjatuhkan developer yang baru pindah dari npm run dev atau php artisan serve. Sebagian besar bukan bug Docker, melainkan beda mental model antara “proses di laptop” dan “proses di dalam container”, tema yang kita tanam sejak Chapter 1.
| Pitfall | Gejala | Sebab | Solusi |
|---|---|---|---|
| Localhost trap | API gagal connect DB walau Postgres “jalan” | Kode pakai localhost:5432; di dalam container, localhost = container itu sendiri, bukan host | Pakai nama service: db:5432, andalkan DNS Compose |
| Stale image | Perubahan kode tidak muncul setelah up | Lupa rebuild; Compose pakai image lama yang sudah ter-cache | docker compose up --build atau docker compose build api |
| Wrong port mapping | curl :8080 connection refused | App listen :3000 tapi mapping 8080:8080, atau urutan host:container terbalik | Samakan ports dengan port app; ingat format host:container |
| Missing env | App panic atau koneksi kosong saat start | DATABASE_URL tidak diset, os.Getenv mengembalikan string kosong | Definisikan di environment/env_file; cek docker compose config |
| Volume shadowing | File yang sudah di-build hilang di container | Bind mount menimpa direktori berisi artefak image dengan folder host kosong | Jangan mount over path build; mount hanya source yang memang perlu |
Di dalam container, 127.0.0.1 menunjuk ke container itu sendiri. Postgres ada di container lain, jadi alamatnya db:5432, bukan localhost:5432.
Jalankan docker compose config untuk melihat env final yang ter-resolve, dan docker compose logs -f api untuk membaca alasan crash sebelum menebak-nebak.
Hands-on: bangun, jalankan, cek health
Jalankan docker compose build api agar Dockerfile multi-stage dieksekusi dan layer dependency masuk cache untuk build berikutnya.
docker compose up -d menyalakan db, cache, lalu api; depends_on: condition: service_healthy menahan API sampai pg_isready lulus.
curl localhost:8080/healthz harus mengembalikan {"status":"ok"}; bila refused, periksa docker compose ps dan logs api.
Compose ke stack ini seperti resep dapur: satu file mendeklarasikan bahan (image), takaran (env), dan urutan masak (depends_on), lalu up memasaknya identik di laptop siapa pun.
Dengan ini kamu punya backend skincare yang berjalan lokal layaknya produksi mini: build ramping, dependency tergerbang sehat, dan config yang bisa dipindah tanpa menyentuh image. Inilah fondasi yang sama yang nanti diangkat ke cloud.
Topik Lanjutan dan Peta ke Deploy
Dari image lokal ke CI/CD dan AWS
Image yang jalan di laptop adalah setengah cerita; setengah lainnya adalah membawanya ke registry dan menjalankannya di cloud secara otomatis.
Setelah skincare-api containerized, langkah dewasa berikutnya adalah menghapus tahap manual. Alih-alih docker build lalu docker push dari laptop, sebuah CI pipeline melakukannya setiap kali kamu merge ke main: build image, jalankan test, lalu push ke registry. Dari registry, platform orkestrasi menarik image dan menjalankannya. Pola “build sekali, deploy artefak yang sama” ini, yang kita pelajari di Chapter 5, sudah jadi standar tim backend modern. Course ini berhenti di gerbang itu, tapi penting kamu lihat petanya supaya tahu ke mana arah berikutnya.
Peta pipeline ke AWS
flowchart LR
Push["git push main"] --> CI["CI: build + test"]
CI --> Img["docker build\n-t ...:sha"]
Img --> ECR["push ke AWS ECR\n(registry)"]
ECR --> ECS["deploy ECS Fargate\n(jalankan container)"]
ECS --> RDS[("RDS PostgreSQL")]Dari commit ke produksi. CI membangun dan menguji, mendorong image ke ECR, lalu ECS Fargate menjalankan container yang sama, terhubung ke database RDS terkelola.
Potongan-potongan yang akan kamu temui
Beberapa istilah AWS akan muncul, dan masing-masing memetakan rapi ke konsep yang sudah kamu kuasai. ECR hanyalah registry privat (seperti GHCR, tapi milik AWS). ECS Fargate adalah cara menjalankan container tanpa mengurus server. RDS adalah Postgres terkelola, pengganti container db lokalmu. Untuk konteks resmi, lihat dokumentasi Amazon ECR dan panduan AWS Fargate.
Kalau terbiasa deploy Next.js di Vercel atau Laravel via Forge, ECS Fargate adalah ide serupa untuk container: kamu serahkan artefak (image), platform yang menjalankan dan menskalakannya.
Akselerasi build: BuildKit dan cache mounts
BuildKit sudah jadi builder default, jadi kamu otomatis menikmati build paralel dan cache layer. Lebih jauh, cache mount membuat cache modul Go bertahan antar build tanpa masuk ke image final, memangkas waktu go mod download di CI.
Dockerfile (cache mount)RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ CGO_ENABLED=0 go build -o /app ./cmd/server
docker compose watch menyinkronkan perubahan source ke container dan me-rebuild saat perlu, mendekati pengalaman hot-reload npm run dev tanpa meninggalkan stack Compose.
Arah lanjutan
CI/CD pipeline
Otomatiskan build, test, dan push image bertag digest tiap merge, agar deploy reproducible dan bebas langkah manual dari laptop.
Registry dan ECR
Login ke ghcr.io atau ECR, push tag semver, dan referensikan via image@sha256: untuk image yang immutable di produksi.
ECS Fargate dan RDS
Jalankan container tanpa server, sambungkan ke Postgres terkelola RDS, dan atur scaling tanpa menyentuh OS host.
Untuk runtime, ingat kembali pilihan base image ramping seperti distroless dari Google: image kecil non-root mempercepat pull di CI dan ECS sekaligus mengecilkan permukaan serangan. Referensi perintah dan praktik terbaik lain selalu bisa kamu cek di docs.docker.com.
Tujuan course ini menanamkan fondasi container yang kokoh. Detail end-to-end ECR, ECS Fargate, dan RDS dibahas tuntas di jalur deploy lanjutan.
Ringkasan dan Poin Penting
Checklist Docker untuk backend Go
Kamu sekarang bisa mengubah biner Go menjadi container yang ramping, aman, dan reproducible, lalu menjalankannya sebagai bagian dari stack multi-service, dari laptop sampai gerbang cloud.
Mari petakan ulang perjalanan seluruh course. Kita mulai dari membedakan image (cetakan immutable) dan container (instance yang berjalan), lalu menulis Dockerfile yang sadar cache layer. Multi-stage memisahkan toolchain build dari runtime sehingga image akhir hanya berisi biner dan sertifikat. Config masuk lewat env, bukan hardcode. Networking mengandalkan DNS antar service di user-defined network. Volume menjaga data Postgres tetap hidup melewati restart. Compose merangkai semuanya, dengan healthcheck menggerbangi urutan start. Terakhir, tag dan registry membuat image bisa dibagikan, sementara non-root dan scanning menjaga keamanan.
Yang Wajib Menempel
- Image adalah cetakan immutable; container adalah instance berjalan dari image, dan registry tempat image dibagikan.
- Urutkan Dockerfile dari yang jarang berubah ke yang sering:
COPY go.mod go.sumlalugo mod downloadsebelumCOPY . .. - Multi-stage plus
CGO_ENABLED=0menghasilkan biner statis yang muat didistroless/static-debian12, kecil dan tanpa shell. - Config selalu lewat env (
environment/env_file); jangan hardcode kredensial atau alamat ke dalam image. - Di dalam container,
localhostadalah container itu sendiri; service lain dipanggil lewat nama via DNS user-defined network. - Named volume menjaga data stateful (Postgres) bertahan lintas
docker compose downdan restart. - Compose plus healthcheck dan
depends_on: condition: service_healthymemastikan API start setelah DB benar-benar siap. docker compose logs,exec, dan flag resource (--memory,--cpus) adalah alat debug dan pembatas dasar.- Pin tag semver dan referensi digest untuk deploy reproducible; jalankan sebagai non-root dan pindai dengan
docker scoutatautrivy.
Image akhir yang baik: kecil, non-root, tanpa shell bila bisa, bertag immutable, dan tidak membawa satu pun secret di dalam layer-nya.
Tiga arah langkah berikutnya
CI/CD
Pindahkan build, test, dan push image ke pipeline otomatis agar setiap merge menghasilkan artefak yang konsisten dan teruji.
AWS ECR dan ECS
Simpan image di registry ECR, lalu jalankan container di ECS Fargate yang tersambung ke Postgres terkelola RDS.
Observability dan scaling
Tambahkan metrik, log terpusat, dan health probe agar container bisa di-scale dan dipantau dengan percaya diri.
Dari sini, lanjutkan ke Docker Compose tingkat lanjut untuk environment dev yang lebih kaya, lalu rakit CI pipeline yang membangun dan menguji image setiap commit. Setelah itu, bawa skincare-api ke produksi nyata lewat AWS ECR sebagai registry dan ECS Fargate sebagai runtime, dengan RDS sebagai database. Fondasi container yang kamu kuasai di course ini adalah tiket masuk ke seluruh jalur deploy itu.