Series MapLesson 22 / 35
Focus mode active/Press Alt+Shift+R to toggle/Esc to exit
Deepen PracticeOrdered learning track

NGINX in Containers

NGINX in Docker and Containerized Runtime

Memahami NGINX official image, config mounting, env substitution, non-root container, read-only filesystem, health check, reload, graceful shutdown, dan sidecar pattern.

6 min read1158 words
PrevNext
Lesson 2235 lesson track20–29 Deepen Practice
#docker#container#nginx-image#sidecar+2 more

Part 022 — NGINX in Docker and Containerized Runtime

1. Tujuan Part Ini

Menjalankan NGINX di container bukan sekadar:

docker run nginx

Dalam enterprise production system, NGINX di container harus dipahami sebagai komponen runtime yang punya lifecycle, filesystem, signal handling, config injection, secret handling, logging, health check, security context, resource limit, dan deployment semantics.

Part ini membahas NGINX saat berjalan di Docker/Kubernetes/container runtime, terutama untuk konteks:

reverse proxy di depan Java/JAX-RS service
NGINX sidecar
NGINX ingress controller
static asset container
local integration testing
platform-managed proxy
cloud/on-prem/hybrid deployment

Target utamanya adalah mampu mereview containerized NGINX secara production-ready.


2. Mental Model: NGINX Container Is Not a Mini VM

Container bukan VM kecil. Container adalah proses dengan filesystem, namespace, cgroup, network namespace, dan lifecycle yang dikontrol orchestrator.

Untuk NGINX, implikasinya:

PID 1 matters
signal handling matters
stdout/stderr logging matters
read-only filesystem matters
mounted config matters
mounted secret matters
resource limit matters
health check matters
rolling update matters
graceful shutdown matters

Jika NGINX berjalan baik di VM, belum tentu perilakunya aman di Kubernetes.

Contoh perbedaan penting:

AreaVM/Bare MetalContainer/Kubernetes
Config fileLocal disk/server managementImage, ConfigMap, mounted volume, generated config
LogFile di /var/log/nginxstdout/stderr atau sidecar collector
SecretFile permission/manual deploySecret volume, cert-manager, CSI, external secret
Reloadsystemctl/service reloadsignal ke process, controller reload, rollout
Healthmanual/systemdliveness/readiness/startup probe
Resourcehost-levelcgroup request/limit
Shutdownadmin controlledorchestrator sends SIGTERM

3. Official NGINX Image Mental Model

Official NGINX image biasanya menyediakan:

nginx binary
base OS image
default nginx.conf
default server config
entrypoint scripts
log symlink to stdout/stderr
html root default

Common layout:

/etc/nginx/nginx.conf
/etc/nginx/conf.d/default.conf
/usr/share/nginx/html
/var/log/nginx/access.log
/var/log/nginx/error.log
/var/cache/nginx
/var/run

Dalam production, default config jarang cukup.

Checklist saat memakai image:

Apakah base image diset eksplisit dengan tag version?
Apakah default server dihapus/diganti?
Apakah config dipin lewat image atau mounted volume?
Apakah running user root atau non-root?
Apakah image discan vulnerability?
Apakah log keluar ke stdout/stderr?
Apakah temp/cache directory writable?

4. Version Pinning

Anti-pattern:

FROM nginx:latest

Masalah:

build tidak reproducible
minor/patch behavior bisa berubah tanpa review
security scan sulit ditelusuri
rollback tidak deterministik

Lebih baik:

FROM nginx:1.27-alpine

Atau sesuai standard internal:

FROM <internal-registry>/base/nginx:<approved-version>

Prinsip:

production image harus dapat direbuild dan menghasilkan behavior yang dapat diprediksi.

Internal verification:

Cek image tag di Dockerfile/Helm values.
Cek apakah image berasal dari registry internal.
Cek vulnerability scan policy.
Cek upgrade cadence NGINX.

5. Config Packaging Strategy

Ada beberapa cara memasukkan config NGINX ke container.

Option 1: Bake Config into Image

FROM nginx:1.27-alpine
COPY nginx.conf /etc/nginx/nginx.conf
COPY conf.d/ /etc/nginx/conf.d/

Benefit:

immutable artifact
config terversi bersama image
lebih mudah direproduksi

Risk:

perubahan config butuh rebuild image
kurang fleksibel untuk environment-specific override
secret tidak boleh dibake ke image

Option 2: Mount Config as Volume

Di Kubernetes biasanya memakai ConfigMap.

volumeMounts:
  - name: nginx-config
    mountPath: /etc/nginx/conf.d
volumes:
  - name: nginx-config
    configMap:
      name: nginx-config

Benefit:

config mudah diganti via GitOps/ConfigMap
cocok untuk environment-specific routing

Risk:

config drift jika tidak dikelola GitOps
reload behavior harus jelas
invalid config dapat membuat pod gagal
mount path bisa menimpa default config tanpa sengaja

Option 3: Generate Config at Startup

Menggunakan template dan environment substitution.

nginx.conf.template -> envsubst -> nginx.conf -> nginx -g 'daemon off;'

Benefit:

satu image untuk banyak environment
simple variable substitution

Risk:

runtime error baru terlihat saat startup
secret bisa bocor via env
template logic sulit direview jika terlalu kompleks

6. Environment Substitution

NGINX config native tidak membaca environment variable langsung di semua context seperti aplikasi biasa.

Pattern umum:

envsubst '${UPSTREAM_HOST} ${UPSTREAM_PORT}' \
  < /etc/nginx/templates/default.conf.template \
  > /etc/nginx/conf.d/default.conf

nginx -g 'daemon off;'

Template:

upstream app_backend {
    server ${UPSTREAM_HOST}:${UPSTREAM_PORT};
}

server {
    listen 8080;

    location /api/ {
        proxy_pass http://app_backend;
    }
}

Risiko:

missing env menghasilkan config invalid atau target kosong
nilai env tidak tervalidasi
escaping buruk bisa menghasilkan config injection
startup script terlalu pintar dan sulit diaudit

Production advice:

Validasi config setelah template dirender.
Jangan simpan private key atau secret sensitif sebagai env jika bisa memakai Secret volume.
Gunakan allowlist variable yang disubstitusi.
Fail fast jika variable wajib tidak ada.

7. Config Validation in Container

Sebelum NGINX start atau reload:

nginx -t

Di Dockerfile/CI:

docker run --rm <image> nginx -t

Dengan custom config:

docker run --rm \
  -v "$PWD/nginx.conf:/etc/nginx/nginx.conf:ro" \
  <image> nginx -t

Di Kubernetes/GitOps pipeline:

render Helm chart
extract ConfigMap
run nginx -t against rendered config
fail CI if invalid

Prinsip:

Invalid NGINX config tidak boleh pertama kali ditemukan oleh production pod.

8. Running NGINX in Foreground

Di container, NGINX harus berjalan di foreground.

Umum:

nginx -g 'daemon off;'

Jika daemon mode aktif, container dapat exit atau lifecycle menjadi tidak jelas.

Mental model:

container hidup selama main process hidup
main process harus NGINX master process atau entrypoint yang benar-benar menunggu NGINX

Anti-pattern:

service nginx start
sleep infinity

Masalah:

orchestrator tidak melihat process NGINX sebenarnya
signal handling buruk
crash NGINX bisa tersembunyi
shutdown tidak graceful

9. PID 1 and Signal Handling

Dalam container, process utama menjadi PID 1. PID 1 punya perilaku khusus terhadap signal dan child process.

Untuk NGINX, signal penting:

SIGTERM -> graceful shutdown request dari orchestrator
SIGQUIT -> graceful shutdown NGINX
SIGHUP  -> reload config
SIGUSR1 -> reopen logs

Dalam Kubernetes, saat pod dihentikan:

Kubernetes mengirim SIGTERM
menunggu terminationGracePeriodSeconds
jika belum selesai, SIGKILL

Jika entrypoint script tidak meneruskan signal ke NGINX, shutdown bisa tidak graceful.

Checklist:

Apakah NGINX process menerima SIGTERM?
Apakah entrypoint memakai exec?
Apakah ada preStop hook?
Apakah terminationGracePeriodSeconds cukup untuk long-lived connection?

Entrypoint pattern:

#!/bin/sh
set -eu

nginx -t
exec nginx -g 'daemon off;'

exec penting agar NGINX menggantikan shell process dan menerima signal langsung.


10. Graceful Shutdown

Graceful shutdown berarti NGINX berhenti menerima connection baru dan memberi waktu connection aktif selesai.

Dalam Kubernetes, graceful shutdown dipengaruhi oleh:

readiness probe
preStop hook
terminationGracePeriodSeconds
cloud load balancer deregistration delay
Ingress controller behavior
upstream Java service readiness
long-lived WebSocket/SSE connections

Problem umum:

pod menerima SIGTERM
readiness belum berubah menjadi false
load balancer masih mengirim traffic
NGINX mulai shutdown
client melihat connection reset/502

Mitigation pattern:

mark pod not ready
wait short drain period
then stop NGINX gracefully

Contoh conceptual Kubernetes lifecycle:

lifecycle:
  preStop:
    exec:
      command: ["/bin/sh", "-c", "sleep 10; nginx -s quit"]
terminationGracePeriodSeconds: 60

Catatan:

Nilai sleep dan grace period harus diverifikasi dengan platform behavior, bukan dicopy.

11. Reload Inside Container

Reload config:

nginx -s reload

Atau:

kill -HUP <nginx-master-pid>

Reload NGINX biasanya zero-downtime secara konsep:

master load config baru
jika valid, worker baru dibuat
worker lama menyelesaikan request aktif
worker lama keluar

Tetapi dalam container/Kubernetes, reload perlu governance:

Siapa yang trigger reload?
Bagaimana config change dideteksi?
Apakah ConfigMap update otomatis terlihat di volume?
Apakah reload terjadi setelah file benar-benar update?
Apakah invalid config dicegah?
Apakah controller melakukan reload sendiri?

Untuk NGINX Ingress Controller, jangan menganggap kita mengelola reload manual. Controller biasanya generate config dan reload berdasarkan Ingress/ConfigMap changes.


12. Read-Only Filesystem

Security hardening umum:

securityContext:
  readOnlyRootFilesystem: true

Tetapi NGINX butuh lokasi writable untuk:

pid file
cache/temp files
client body temp
proxy temp
fastcgi/uwsgi/scgi temp jika dipakai

Jika root filesystem read-only, perlu mount writable untuk path tertentu.

Contoh conceptual:

volumeMounts:
  - name: nginx-cache
    mountPath: /var/cache/nginx
  - name: nginx-run
    mountPath: /var/run
volumes:
  - name: nginx-cache
    emptyDir: {}
  - name: nginx-run
    emptyDir: {}

Failure mode:

open() "/var/run/nginx.pid" failed
mkdir() "/var/cache/nginx/client_temp" failed
permission denied
read-only file system
pod crashloop

13. Non-Root Container

Running as root meningkatkan risiko blast radius jika container compromise.

Kubernetes hardening:

securityContext:
  runAsNonRoot: true
  runAsUser: 101
  allowPrivilegeEscalation: false
  capabilities:
    drop:
      - ALL

Issue utama:

port <1024 butuh privilege
file ownership untuk config/cache/temp
pid path permission
log path permission

Solusi umum:

listen di port non-privileged seperti 8080
Service/Ingress/LB expose port 80/443 di luar container
chown writable directories di image build
mount volume dengan permission sesuai

Contoh:

server {
    listen 8080;
}

Jangan memaksa container root hanya agar bisa bind port 80.


14. Linux Capabilities

Untuk bind port 80/443 sebagai non-root, kadang orang menambahkan capability:

capabilities:
  add:
    - NET_BIND_SERVICE

Namun dalam Kubernetes, sering lebih aman:

container listen 8080/8443
Service expose 80/443

Prinsip:

Kurangi privilege jika tidak benar-benar dibutuhkan.

Internal verification:

Cek apakah container berjalan root.
Cek capability tambahan.
Cek apakah privileged mode dipakai.
Cek apakah port rendah sebenarnya diperlukan di dalam container.

15. Health Check

NGINX container perlu health check yang memeriksa readiness, bukan hanya process alive.

Basic endpoint:

server {
    listen 8080;

    location = /healthz {
        access_log off;
        return 200 "ok\n";
    }
}

Kubernetes probe:

readinessProbe:
  httpGet:
    path: /healthz
    port: 8080
  periodSeconds: 10
  timeoutSeconds: 2

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  periodSeconds: 30
  timeoutSeconds: 2

Tetapi health check harus sesuai peran NGINX.

Jika NGINX adalah reverse proxy, ada dua jenis health:

NGINX process health
upstream reachability health

Jangan selalu mencampur keduanya.

Jika readiness bergantung pada upstream, maka outage backend bisa membuat NGINX pod unready dan memicu cascading traffic instability.

Design question:

Apakah proxy harus tetap ready saat upstream down untuk mengembalikan 503 yang jelas?
Atau harus dikeluarkan dari LB jika upstream tidak reachable?

Jawabannya bergantung pada arsitektur.


16. Logging to stdout/stderr

Dalam container, log idealnya keluar ke stdout/stderr agar collector platform mengambilnya.

Pattern umum:

access_log /dev/stdout main;
error_log  /dev/stderr warn;

Atau official image bisa men-symlink file log ke stdout/stderr.

Anti-pattern:

log hanya ke file lokal container
log hilang saat pod restart
log tidak dikumpulkan collector
log volume penuh

Untuk production:

Gunakan structured log jika memungkinkan.
Jangan log PII/sensitive token.
Pastikan request_id/correlation_id ada.
Pastikan request_time dan upstream_response_time tersedia.

17. ConfigMap Volume Behavior

Di Kubernetes, ConfigMap volume dapat update secara eventual, bukan instant transactional reload.

Important behavior:

ConfigMap object update tidak otomatis berarti NGINX reload.
Mounted file bisa berubah setelah delay.
NGINX tidak membaca config baru sampai reload.
SubPath mount biasanya tidak menerima update otomatis seperti directory mount.

Common failure:

ConfigMap berubah
pod tidak reload
traffic masih memakai config lama
operator mengira perubahan sudah live

Atau:

ConfigMap berubah
reload otomatis terjadi
config invalid
pod crash/reload loop

Production pattern:

Config changes lewat GitOps.
Render dan validate di CI.
Rollout restart atau controller-managed reload jelas.
Rollback jelas.

18. Secret Volume and TLS Key Handling

TLS private key tidak boleh dibake ke image.

Pattern:

volumes:
  - name: tls-secret
    secret:
      secretName: nginx-tls
volumeMounts:
  - name: tls-secret
    mountPath: /etc/nginx/tls
    readOnly: true

NGINX config:

ssl_certificate     /etc/nginx/tls/tls.crt;
ssl_certificate_key /etc/nginx/tls/tls.key;

Considerations:

certificate rotation membutuhkan reload
file permission harus cocok dengan runAsUser
secret exposure harus diaudit
external secret/cert-manager ownership harus jelas

Internal verification:

Cek apakah TLS secret dikelola cert-manager, cloud cert manager, Vault, atau manual.
Cek rotation runbook.
Cek apakah NGINX reload saat secret berubah.
Cek apakah private key pernah masuk image/repo/log.

19. Container Resource Request and Limit

NGINX container perlu resource request/limit yang realistis.

resources:
  requests:
    cpu: "250m"
    memory: "256Mi"
  limits:
    cpu: "1"
    memory: "512Mi"

Tapi angka harus berdasarkan traffic shape.

Resource dipengaruhi oleh:

RPS
active connections
TLS termination
compression
buffering
large payload
structured logging
WAF module
HTTP/2 streams
WebSocket/SSE

Risk CPU limit terlalu rendah:

CPU throttling
p99 latency naik
NGINX terlihat healthy tapi lambat

Risk memory limit terlalu rendah:

OOMKilled
pod restart
connection reset
sporadic 502/503

Risk ephemeral storage tidak diperhatikan:

temp file penuh
pod evicted
large upload/download gagal

20. Sidecar Pattern

NGINX sidecar berarti NGINX berjalan dalam pod yang sama dengan aplikasi.

Pattern:

client -> Service -> Pod
                 -> NGINX container -> Java container localhost:8080

Use case:

TLS termination lokal
static asset serving di samping app
legacy app path rewrite
local auth/filtering
protocol adaptation sederhana
membatasi exposure aplikasi

Benefit:

NGINX dan app deploy bersama
localhost communication
config per-service
blast radius lebih kecil daripada global ingress config

Risk:

resource contention dengan Java container
observability lebih kompleks
sidecar crash memengaruhi app pod
config duplication antar service
security boundary tidak sama dengan separate proxy
scaling NGINX mengikuti scaling app, bukan traffic edge

Untuk Java/JAX-RS service, sidecar berguna jika ada kebutuhan proxy lokal yang sangat spesifik. Tetapi jangan menggunakan sidecar untuk menggantikan platform ingress tanpa alasan kuat.


21. Init Container for Config Preparation

Init container bisa dipakai untuk menyiapkan config sebelum NGINX start.

Contoh use case:

fetch template dari internal source
render config
validate generated config
copy certificate bundle
prepare static asset

Pattern:

init container writes to shared emptyDir
NGINX container mounts same emptyDir read-only

Risk:

startup dependency bertambah
failure init container membuat pod tidak start
logic konfigurasi tersembunyi dari reviewer
config generation sulit direproduksi lokal

Prinsip:

Init container boleh dipakai, tetapi config generation harus deterministic dan tervalidasi.

22. Local Testing with Docker Compose

Docker Compose berguna untuk menguji NGINX di depan Java/JAX-RS service secara lokal.

Contoh:

services:
  nginx:
    image: nginx:1.27-alpine
    ports:
      - "8080:8080"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - app

  app:
    image: local-jaxrs-app:dev
    expose:
      - "8080"

NGINX config:

events {}

http {
    upstream app_backend {
        server app:8080;
    }

    server {
        listen 8080;

        location /api/ {
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass http://app_backend;
        }
    }
}

Compose tidak sama dengan Kubernetes, tetapi berguna untuk menguji:

proxy_pass
header forwarding
path rewrite
body size
basic timeout
local TLS
large upload/download
WebSocket/SSE behavior dasar

Jangan menganggap Compose sudah memvalidasi cloud LB, Kubernetes Service, IngressClass, NetworkPolicy, atau DNS production.


23. Docker Networking Pitfalls

Dalam Docker Compose:

service name menjadi DNS hostname
localhost dari NGINX container berarti NGINX container sendiri, bukan host dan bukan app container

Common mistake:

proxy_pass http://localhost:8080;

Jika aplikasi berada di container lain, ini salah.

Benar:

proxy_pass http://app:8080;

Dalam Kubernetes sidecar, localhost bisa benar jika NGINX dan Java container berada dalam pod yang sama.

same pod -> same network namespace -> localhost bisa menunjuk container lain di pod
separate pod -> gunakan Service DNS

Mental model:

Makna localhost bergantung pada network namespace.

24. Container Image Hardening

Checklist hardening:

[ ] Pin image version.
[ ] Gunakan registry internal jika diwajibkan.
[ ] Jalankan vulnerability scanning.
[ ] Drop unnecessary Linux capabilities.
[ ] runAsNonRoot jika memungkinkan.
[ ] readOnlyRootFilesystem jika memungkinkan.
[ ] Writable mount hanya untuk path yang dibutuhkan.
[ ] Jangan bake secret ke image.
[ ] Jangan include debug tools berlebihan di production image kecuali policy mengizinkan.
[ ] Remove default config/server yang tidak dipakai.
[ ] Expose hanya port yang diperlukan.
[ ] Log ke stdout/stderr.

Trade-off:

Image minimal lebih aman, tetapi debugging production bisa lebih sulit.
Solusi biasanya debug pod terpisah, bukan memasukkan semua tool ke image NGINX production.

25. NGINX as Ingress Controller Container

Jika NGINX dipakai sebagai Ingress Controller, kita tidak hanya menjalankan NGINX biasa.

Ada controller process yang:

watch Kubernetes API
membaca Ingress/Service/Endpoint/Secret/ConfigMap
menghasilkan konfigurasi NGINX
melakukan reload
mengekspor metrics
menjalankan admission webhook jika ada

Karena itu, debugging ingress controller harus mencakup:

controller logs
nginx logs
generated nginx.conf
Kubernetes events
IngressClass
ConfigMap
annotations
webhook validation
RBAC permission
Service/EndpointSlice state

Jangan mengedit file config manual di pod ingress controller dan menganggap itu solusi permanen. Perubahan akan hilang saat controller reconcile atau pod restart.


26. Failure Modes in Containerized NGINX

Failure: CrashLoopBackOff

Kemungkinan:

invalid nginx.conf
missing mounted file
permission denied
read-only filesystem issue
port binding permission
missing env substitution variable
secret not mounted

Debug:

kubectl logs <pod>
kubectl describe pod <pod>
kubectl exec <pod> -- nginx -t

Failure: Pod Ready but Traffic Fails

Kemungkinan:

health endpoint tidak menguji proxy path
wrong upstream DNS
Service selector salah
NetworkPolicy block
proxy_pass ke localhost yang salah
TLS secret mismatch

Failure: ConfigMap Updated but Behavior Unchanged

Kemungkinan:

NGINX belum reload
subPath mount tidak update
controller belum reconcile
GitOps belum sync
pod lama masih serving traffic

Failure: 502 During Rollout

Kemungkinan:

SIGTERM tidak graceful
readiness/draining buruk
upstream Java pod belum ready
cloud LB masih mengirim traffic ke terminating pod

Failure: Permission Denied

Kemungkinan:

runAsNonRoot tanpa file ownership benar
read-only filesystem tanpa writable temp path
secret volume permission tidak cocok
listen port privileged

27. Java/JAX-RS Backend Considerations

NGINX container di depan Java service harus menjaga beberapa hal:

Host header
X-Forwarded-For
X-Forwarded-Host
X-Forwarded-Proto
Forwarded header
request body size
timeout alignment
streaming behavior
real client IP
base path/rewrite
redirect URL correctness

Jika NGINX sidecar dan Java container dalam pod yang sama:

NGINX dapat proxy ke localhost:8080
Java service tidak perlu expose langsung ke cluster jika Service hanya target NGINX port
resource contention harus dihitung
readiness harus mempertimbangkan dua container

Readiness design:

NGINX ready tapi Java not ready -> request bisa 502/503
Java ready tapi NGINX not ready -> pod tidak menerima traffic
keduanya harus punya probe yang masuk akal

28. AWS/Azure/On-Prem Container Runtime Considerations

AWS/EKS

Verifikasi:

EKS node OS/cgroup behavior
ALB/NLB target health check
security group to pod/node
IRSA jika controller butuh AWS API
ACM/cert-manager integration
CloudWatch logs/metrics

Azure/AKS

Verifikasi:

AKS node pool resource
Azure Load Balancer/Application Gateway health probe
Managed identity jika controller butuh Azure API
Key Vault/CSI secret integration
Azure Monitor log collection

On-Prem/Hybrid

Verifikasi:

container runtime standard
private registry
internal CA bundle
corporate proxy env
NO_PROXY for cluster internal services
firewall/load balancer health check path
air-gapped image distribution

29. PR Review Checklist

Gunakan checklist ini saat mereview Dockerfile, Helm chart, Kubernetes manifest, atau config containerized NGINX.

[ ] Apakah image version dipin?
[ ] Apakah default server/config yang tidak perlu dihapus?
[ ] Apakah config masuk lewat image, ConfigMap, template, atau generated controller? Apakah jelas?
[ ] Apakah nginx -t dijalankan di CI?
[ ] Apakah container berjalan foreground dengan daemon off?
[ ] Apakah entrypoint memakai exec agar signal diteruskan?
[ ] Apakah shutdown/drain behavior jelas?
[ ] Apakah readiness/liveness probe benar?
[ ] Apakah log ke stdout/stderr?
[ ] Apakah runAsNonRoot digunakan jika memungkinkan?
[ ] Apakah readOnlyRootFilesystem digunakan jika memungkinkan?
[ ] Apakah writable temp/cache/run path tersedia?
[ ] Apakah secret tidak dibake ke image?
[ ] Apakah TLS secret rotation membutuhkan reload?
[ ] Apakah resource request/limit realistis?
[ ] Apakah ephemeral storage dipertimbangkan untuk buffering/upload/download?
[ ] Apakah Docker networking/localhost usage benar?
[ ] Apakah sidecar pattern memang dibutuhkan?
[ ] Apakah rollback jelas?

30. Internal Verification Checklist

Untuk konteks CSG/team internal, verifikasi sebelum menyimpulkan arsitektur:

[ ] Apakah NGINX dijalankan sebagai standalone container, sidecar, ingress controller, atau platform-managed component?
[ ] Image NGINX berasal dari mana?
[ ] Apakah versi NGINX dipin?
[ ] Apakah memakai NGINX open source, NGINX Plus, ingress-nginx, atau NGINX Inc controller?
[ ] Di mana config utama berada: image, ConfigMap, Helm chart, Kustomize, atau generated controller?
[ ] Bagaimana config divalidasi sebelum deploy?
[ ] Bagaimana reload dilakukan?
[ ] Apakah ada rollout restart saat ConfigMap berubah?
[ ] Apakah container non-root?
[ ] Apakah root filesystem read-only?
[ ] Path mana yang writable?
[ ] Bagaimana TLS secret dipasang?
[ ] Bagaimana certificate rotation dilakukan?
[ ] Apakah log dikirim ke stdout/stderr dan dikumpulkan observability platform?
[ ] Apakah readiness/liveness probe menguji hal yang tepat?
[ ] Apakah resource limit pernah menyebabkan throttling/OOMKilled?
[ ] Apakah ada preStop hook dan terminationGracePeriodSeconds?
[ ] Apakah ada incident sebelumnya terkait 502 saat deploy/restart?
[ ] Apakah sidecar NGINX dipakai di service tertentu?
[ ] Apakah corporate proxy/NO_PROXY memengaruhi container startup atau outbound call?

31. Production Heuristics

Beberapa aturan praktis:

Jangan gunakan nginx:latest di production.
Jangan bake secret atau private key ke image.
Jangan mengandalkan file log lokal container.
Jangan menjalankan NGINX sebagai root hanya untuk bind port 80.
Jangan memakai ConfigMap update tanpa mekanisme reload yang jelas.
Jangan menganggap liveness sama dengan readiness.
Jangan membuat health check bergantung pada upstream tanpa memahami cascading effect.
Jangan mengedit config manual di ingress controller pod.
Jangan memakai sidecar jika problem sebenarnya milik platform ingress/gateway.
Jangan mengaktifkan read-only filesystem tanpa menyediakan writable temp/cache/run path.

32. Ringkasan

NGINX di container adalah kombinasi dari:

NGINX process model
container lifecycle
filesystem mount
secret/config injection
signal handling
health check
resource limit
logging model
orchestrator rollout behavior
security context

Senior engineer perlu melihat containerized NGINX bukan hanya dari config file, tetapi dari runtime contract:

bagaimana start
bagaimana validate config
bagaimana receive traffic
bagaimana log
bagaimana reload
bagaimana shutdown
bagaimana rotate secret
bagaimana recover
bagaimana rollback

NGINX container yang production-ready bukan yang "berhasil start", tetapi yang:

aman dioperasikan
mudah diobservasi
predictable saat rollout
jelas saat failure
minimal privilege
selaras dengan Java/JAX-RS backend
selaras dengan Kubernetes/cloud/on-prem traffic flow
Lesson Recap

You just completed lesson 22 in deepen practice. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.

Continue The Track

Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.