0Pricing
Linux Command Line & Bash Scripting Mastery · Pelajaran

Menulis Dockerfile dan Entrypoint Shell yang Ringkas

Buat skrip build multi-tahap dan shim entrypoint yang tangguh dengan penanganan sinyal serta templating konfigurasi.

Menulis Dockerfile dan Entrypoint Shell yang Ringkas adalah pelajaran Linux Command Line & Bash Scripting Mastery gratis di CoddyKit. Ini adalah pelajaran 1 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Linux Command Line & Bash Scripting Mastery, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Linux Command Line & Bash Scripting Mastery mencakup 4 pelajaran total.

Mengapa Dockerfile Ringkas Penting bagi DevOps

Di lingkungan produksi, setiap megabita dalam image Docker memiliki biaya: pengambilan image menjadi lebih lambat, permukaan serangan lebih luas, dan penyimpanan registry terbuang. Dockerfile yang ringkas, dipadukan dengan entrypoint shell yang tangguh, merupakan ciri praktik DevOps yang matang.

  • Build multi-tahap memisahkan alat saat build dari image runtime akhir sehingga ukurannya berkurang secara drastis.
  • Shim entrypoint adalah skrip shell kecil yang menyiapkan container: membuat template berkas konfigurasi, memvalidasi variabel lingkungan, menangani sinyal, lalu menjalankan proses utama dengan exec.
  • Keduanya menjadi tulang punggung beban kerja container yang andal dan portabel di Kubernetes, ECS, serta lingkungan bare-metal.

Pelajaran ini membahas kedua disiplin tersebut secara menyeluruh, dengan pola siap produksi yang dapat langsung Anda terapkan dalam pipeline Anda.

Anatomi Dockerfile Multi-Tahap

Dockerfile multi-tahap menggunakan beberapa instruksi FROM. Setiap tahap merupakan kumpulan lapisan yang terisolasi; Anda hanya menyalin artefak yang diperlukan ke tahap berikutnya.

  • Tahap 0 (builder): memasang kompiler, pelaksana pengujian, dan dependensi build.
  • Tahap 1 (runtime): dimulai dari basis minimal (misalnya alpine, distroless) dan hanya menyalin biner terkompilasi atau bundel aplikasi.
  • Image akhir tidak pernah berisi gcc, make, atau kode sumber kecuali Anda menyalinnya secara eksplisit.

Gunakan --from=<stage> dalam COPY untuk mengambil berkas lintas batas tahap. Beri nama tahap dengan AS <name> agar mudah dibaca dan dapat dipilih secara selektif menggunakan docker build --target.

# ---- Stage 0: builder ----
FROM golang:1.22-alpine AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags='-s -w' -o /app/server ./cmd/server

# ---- Stage 1: runtime ----
FROM gcr.io/distroless/static-debian12
COPY --from=builder /app/server /server
ENTRYPOINT ["/server"]

Meminimalkan Lapisan dan Membatalkan Cache

Setiap instruksi RUN, COPY, dan ADD membuat lapisan baru. Urutan instruksi yang buruk akan membatalkan cache build secara tidak perlu sehingga pipeline CI menjadi lambat.

  • Salin manifes dependensi (package.json, go.mod, requirements.txt) sebelum menyalin kode sumber agar pemasangan dependensi di-cache secara terpisah.
  • Gabungkan perintah yang berkaitan dengan && dan lakukan pembersihan pada lapisan RUN yang sama agar cache paket tidak tertinggal di lapisan perantara.
  • Gunakan --no-cache pada pengelola paket dan hapus berkas daftar setelah pemasangan.
FROM python:3.12-slim AS builder
WORKDIR /app

# 1. Install deps first (cached until requirements change)
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt

# 2. Copy source (cache busted only when code changes)
COPY src/ ./src/

FROM python:3.12-slim
COPY --from=builder /install /usr/local
COPY --from=builder /app/src /app/src
WORKDIR /app
CMD ["python", "-m", "src.main"]

Rahasia BuildKit dan Penerusan SSH

Registry privat, kunci SSH, dan token API tidak boleh muncul di lapisan image. Docker BuildKit menyediakan dua mekanisme yang aman:

  • --secret: memasang berkas rahasia di dalam satu langkah RUN tanpa memasukkannya ke dalam lapisan. Akses melalui /run/secrets/<id>.
  • --ssh: meneruskan soket agen SSH dari host ke dalam proses build sehingga git clone dapat melakukan autentikasi tanpa menyematkan kunci privat.

Aktifkan BuildKit dengan DOCKER_BUILDKIT=1 atau melalui docker buildx build. Direktif # syntax=docker/dockerfile:1 membuka fitur-fitur ini.

# syntax=docker/dockerfile:1
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./

# Mount NPM token as a secret — never stored in the image
RUN --mount=type=secret,id=npm_token \
    NPM_TOKEN=$(cat /run/secrets/npm_token) \
    npm ci --prefer-offline

# Usage at build time:
# DOCKER_BUILDKIT=1 docker build \
#   --secret id=npm_token,src=~/.npmrc-token \
#   -t myapp:latest .

Menulis Shim Entrypoint yang Tangguh

Shim entrypoint adalah skrip shell yang ditetapkan sebagai ENTRYPOINT dalam Dockerfile. Tugasnya adalah menyiapkan lingkungan runtime sebelum menyerahkan kendali kepada proses utama.

Shim yang terstruktur dengan baik mengikuti urutan berikut:

  • Langkah 1: Tetapkan set -euo pipefail agar setiap kegagalan segera menghentikan proses.
  • Langkah 2: Validasi variabel lingkungan yang wajib diisi dan hentikan proses dengan cepat disertai pesan yang membantu.
  • Langkah 3: Buat template berkas konfigurasi dari variabel lingkungan.
  • Langkah 4: Daftarkan penangan sinyal untuk penghentian yang tertib.
  • Langkah 5: exec "$@" — ganti shell dengan proses utama agar PID 1 adalah aplikasi, bukan shim.

exec terakhir sangat penting: tanpa itu, sinyal yang dikirim oleh Kubernetes atau runtime Docker tidak akan diteruskan ke proses anak.

#!/usr/bin/env bash
set -euo pipefail

# Step 2: validate required env vars
REQUIRED_VARS=(DATABASE_URL APP_SECRET PORT)
for var in "${REQUIRED_VARS[@]}"; do
  if [[ -z "${!var:-}" ]]; then
    echo "[entrypoint] ERROR: required env var '$var' is not set" >&2
    exit 1
  fi
done

# Step 3: template config (see next scene)

# Step 4: signal handling (see scene after that)

# Step 5: hand off to CMD
exec "$@"

Membuat Template Konfigurasi dengan envsubst

envsubst (dari paket GNU gettext, tersedia di Alpine sebagai gettext) mengganti placeholder ${VAR} dalam berkas template dengan nilai variabel lingkungan saat ini.

  • Sertakan template konfigurasi *.tmpl dalam image; entrypoint akan merendernya saat startup.
  • Berikan daftar variabel secara eksplisit kepada envsubst agar tanda dolar yang tidak berkaitan (misalnya dalam regex nginx) tidak ikut diperluas.
  • Tulis berkas hasil render ke jalur yang dapat ditulisi seperti /tmp atau volume konfigurasi khusus.
#!/usr/bin/env bash
# Template: /etc/nginx/conf.d/app.conf.tmpl contains:
# server { listen ${NGINX_PORT}; server_name ${SERVER_NAME}; ... }

export NGINX_PORT=${NGINX_PORT:-8080}
export SERVER_NAME=${SERVER_NAME:-localhost}

envsubst '${NGINX_PORT} ${SERVER_NAME}' \
  < /etc/nginx/conf.d/app.conf.tmpl \
  > /etc/nginx/conf.d/app.conf

echo "[entrypoint] nginx config rendered:"
grep -E 'listen|server_name' /etc/nginx/conf.d/app.conf

exec "$@"

Menangani Sinyal dan Penghentian yang Tertib

Container menerima SIGTERM saat dihentikan oleh Kubernetes, ECS, atau docker stop. Jika shim entrypoint Anda adalah PID 1 dan tidak meneruskan sinyal, proses utama akan dihentikan dengan SIGKILL setelah masa tenggang — sehingga permintaan dapat terputus atau data rusak.

  • Gunakan trap untuk menangkap SIGTERM dan SIGINT dalam shim.
  • Teruskan sinyal ke PID anak menggunakan kill -TERM "$child".
  • Gunakan wait "$child" untuk menunggu hingga proses anak keluar, lalu teruskan kode keluarnya.
  • Atau, gunakan exec untuk mengganti shell sepenuhnya — dengan begitu, OS mengirimkan sinyal langsung ke proses anak dan trap tidak diperlukan. Ini adalah pola yang disarankan untuk kasus sederhana.
#!/usr/bin/env bash
set -euo pipefail

# Start main process in background
"$@" &
child=$!

# Forward SIGTERM and SIGINT to the child
trap 'echo "[entrypoint] caught SIGTERM, forwarding..."; kill -TERM "$child"' TERM
trap 'echo "[entrypoint] caught SIGINT, forwarding...";  kill -INT  "$child"' INT

# Wait for child to exit and capture its exit code
wait "$child"
exit $?

Menggunakan tini sebagai Proses Init Minimal

Saat container Anda membuat proses anak (misalnya shell yang menggandakan proses pekerja), Anda memerlukan init sungguhan untuk membersihkan proses zombie. tini adalah biner init kecil yang dirancang khusus untuk container.

  • Tambahkan tini ke image Anda dan tetapkan sebagai pembungkus entrypoint.
  • Proses ini membersihkan anak zombie, meneruskan sinyal dengan benar, dan keluar dengan kode status anak.
  • Docker menyediakan tini bawaan yang diaktifkan dengan docker run --init, tetapi menyematkannya dalam image memastikan perilakunya konsisten di berbagai runtime (Kubernetes, ECS, dan sebagainya).
FROM node:20-alpine

# Install tini for proper signal handling and zombie reaping
RUN apk add --no-cache tini

WORKDIR /app
COPY --chown=node:node . .
RUN npm ci --omit=dev

USER node

# tini wraps CMD; forwards SIGTERM and reaps zombies
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "server.js"]

Menjalankan Proses sebagai Pengguna Non-Root

Container yang berjalan sebagai root (UID 0) merupakan risiko keamanan besar: pelolosan dari container memberikan akses penuh ke host. Selalu beralih ke pengguna tanpa hak istimewa sebelum menjalankan proses utama.

  • Buat pengguna dan grup sistem khusus dalam Dockerfile dengan addgroup / adduser (Alpine) atau groupadd / useradd (Debian).
  • Ubah kepemilikan berkas aplikasi dengan COPY --chown=appuser:appgroup — lebih efisien daripada lapisan RUN chown terpisah.
  • Beralih ke pengguna tersebut dengan instruksi USER. Entrypoint dan CMD mewarisi pengguna ini.
  • Kubernetes securityContext.runAsNonRoot: true akan menolak memulai image yang masih berjalan sebagai root.
FROM python:3.12-slim

# Create non-root user
RUN groupadd --gid 1001 appgroup && \
    useradd --uid 1001 --gid appgroup --shell /bin/bash --create-home appuser

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy app files with correct ownership in a single layer
COPY --chown=appuser:appgroup src/ ./src/
COPY --chown=appuser:appgroup entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

USER appuser

ENTRYPOINT ["/entrypoint.sh"]
CMD ["python", "-m", "src.main"]

Pemeriksaan Kesehatan dan Probe Kesiapan dalam Image

Probe liveness dan readiness Kubernetes ditentukan dalam manifes, tetapi Anda juga dapat menyertakan HEALTHCHECK dalam Dockerfile untuk lingkungan mandiri docker run dan Docker Compose.

  • HEALTHCHECK --interval=10s --timeout=3s --start-period=15s --retries=3 CMD ...
  • Gunakan curl --fail atau wget -qO- untuk layanan HTTP; untuk daemon non-HTTP, periksa soket dengan /dev/tcp/localhost/PORT.
  • Pasang hanya yang diperlukan: dalam image distroless, hindari menambahkan curl hanya untuk pemeriksaan kesehatan — gunakan biner probe khusus atau biner kesehatan milik aplikasi.
FROM nginx:1.27-alpine

COPY nginx.conf /etc/nginx/nginx.conf
COPY dist/ /usr/share/nginx/html/

# Lightweight health check using bash TCP pseudo-device
# (no curl needed — works on any image with bash)
HEALTHCHECK --interval=15s --timeout=5s --start-period=10s --retries=3 \
  CMD bash -c 'exec 3<>/dev/tcp/localhost/80 && echo -e "GET /health HTTP/1.0\r\n" >&3 && cat <&3 | grep -q "200 OK"' || exit 1

EXPOSE 80

Menyatukan Semuanya: Entrypoint Produksi

Berikut adalah shim entrypoint lengkap siap produksi yang menggabungkan semua pola dari pelajaran ini: validasi lingkungan, pembuatan template konfigurasi, penerusan sinyal, dan serah-terima dengan exec. Pola ini digunakan dalam layanan mikro Node.js, Python, dan Go di dunia nyata yang diterapkan pada Kubernetes.

  • Setiap bagian diberi komentar sehingga berfungsi sebagai template yang mendokumentasikan dirinya sendiri.
  • Shim ini dijaga agar kurang dari 50 baris — entrypoint harus sederhana dan mudah diaudit.
  • Perhatikan exec "$@" terakhir: setelah semua persiapan selesai, shell digantikan oleh proses aplikasi sehingga menjadi PID 1 dan menerima semua sinyal OS secara langsung.
#!/usr/bin/env bash
# entrypoint.sh — production-grade container entrypoint shim
set -euo pipefail

# ── 1. Validate required environment variables ──────────────────
REQUIRED=(DATABASE_URL APP_SECRET PORT LOG_LEVEL)
for var in "${REQUIRED[@]}"; do
  [[ -n "${!var:-}" ]] || { echo "[entrypoint] FATAL: $var is not set" >&2; exit 1; }
done

# ── 2. Set safe defaults for optional variables ─────────────────
export HOST=${HOST:-0.0.0.0}
export WORKERS=${WORKERS:-2}

# ── 3. Render config template ───────────────────────────────────
if [[ -f /etc/app/app.conf.tmpl ]]; then
  envsubst '${DATABASE_URL} ${PORT} ${LOG_LEVEL} ${HOST}' \
    < /etc/app/app.conf.tmpl \
    > /etc/app/app.conf
  echo "[entrypoint] config rendered at /etc/app/app.conf"
fi

# ── 4. Wait for dependent services (optional, fast) ─────────────
if [[ -n "${WAIT_FOR_HOST:-}" ]]; then
  echo "[entrypoint] waiting for ${WAIT_FOR_HOST}:${WAIT_FOR_PORT:-5432}..."
  until bash -c "exec 3<>/dev/tcp/${WAIT_FOR_HOST}/${WAIT_FOR_PORT:-5432}" 2>/dev/null; do
    sleep 1
  done
  echo "[entrypoint] dependency ready"
fi

# ── 5. Hand off to CMD (PID 1 becomes the application) ──────────
echo "[entrypoint] starting: $*"
exec "$@"

Uji Pemahaman: Penanganan Sinyal dalam Entrypoint

Uji pemahaman Anda tentang penanganan sinyal dalam skrip entrypoint container.

Ringkasan: Dockerfile Ringkas dan Entrypoint Shell

Anda telah membahas seluruh tumpukan penulisan container produksi:

  • Build multi-tahap menggunakan beberapa instruksi FROM untuk menjaga kompiler dan alat build tetap berada di luar image akhir, sehingga menghasilkan lapisan runtime yang ringkas dan minimal.
  • Pengurutan lapisan — salin manifes dependensi sebelum kode sumber — memaksimalkan cache hit dan mempercepat pipeline CI.
  • Rahasia BuildKit dan pemasangan SSH menjaga kredensial tetap berada di luar riwayat image tanpa mengganggu build terautentikasi.
  • Shim entrypoint memvalidasi variabel lingkungan, membuat template berkas konfigurasi dengan envsubst, dan menyerahkan kendali kepada aplikasi melalui exec "$@".
  • Penanganan sinyal memerlukan exec (agar aplikasi menjadi PID 1) atau pola eksplisit trap + kill + wait saat pekerjaan latar belakang digunakan.
  • tini menambahkan pembersihan zombie dan penerusan sinyal yang benar saat container membuat beberapa proses.
  • Pengguna non-root dan instruksi HEALTHCHECK melengkapi image yang aman dan mudah dipantau, siap untuk beban kerja produksi Kubernetes.

Gabungkan pola-pola ini secara konsisten agar image Anda lebih kecil, lebih cepat diterapkan, dan jauh lebih tangguh dalam kondisi produksi.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Menulis Dockerfile dan Entrypoint Shell yang Ringkas” gratis?

Ya — teks lengkap “Menulis Dockerfile dan Entrypoint Shell yang Ringkas” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Linux Command Line & Bash Scripting Mastery, upgrade ke CoddyKit PRO. Kursus Linux Command Line & Bash Scripting Mastery mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Menulis Dockerfile dan Entrypoint Shell yang Ringkas”?

Buat skrip build multi-tahap dan shim entrypoint yang tangguh dengan penanganan sinyal serta templating konfigurasi. Kamu berlatih Linux Command Line & Bash Scripting Mastery dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai Linux Command Line & Bash Scripting Mastery?

Tidak diperlukan pengalaman sebelumnya. Linux Command Line & Bash Scripting Mastery di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 1 dari 4.

Berapa lama pelajaran “Menulis Dockerfile dan Entrypoint Shell yang Ringkas” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran Linux Command Line & Bash Scripting Mastery ini?

Ya. Setiap pelajaran Linux Command Line & Bash Scripting Mastery menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Menulis Dockerfile dan Entrypoint Shell yang Ringkas
  2. Membuat Template Konfigurasi dengan envsubst dan heredoc
  3. Membuat Skrip Resource Cloud dengan CLI dan jq
  4. Probe Kesehatan, Gerbang Kesiapan, dan Loop Tunggu
← Kembali ke Linux Command Line & Bash Scripting Mastery