Kem Intensif DevOps · Pelajaran

Menulis Dockerfile dan Titik Masuk Shell yang Ringkas

Tulis skrip binaan berbilang peringkat dan shim titik masuk yang teguh dengan pengendalian isyarat serta templat konfigurasi

Pelajaran 1 daripada 413 langkah

Menulis Dockerfile dan Titik Masuk Shell yang Ringkas ialah pelajaran Kem Intensif DevOps percuma di CoddyKit. Ini ialah pelajaran 1 daripada 4. Sebanyak 3 pelajaran dalam laluan pembelajaran ini boleh dibaca sepenuhnya secara percuma — selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan praktikal dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Kem Intensif DevOps, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Kem Intensif DevOps merangkumi sejumlah 4 pelajaran.

Mengapa Dockerfile Ringkas Penting untuk DevOps

Dalam persekitaran produksi, setiap megabait dalam imej Docker mempunyai kos: penarikan yang lebih perlahan, permukaan serangan yang lebih besar dan storan pendaftaran yang terbuang. Dockerfile ringkas yang digabungkan dengan titik masuk skrip shell yang kukuh merupakan ciri amalan DevOps yang matang.

  • Binaan berbilang peringkat mengasingkan alat masa binaan daripada imej masa jalan akhir, lalu mengurangkan saiz dengan ketara.
  • Shim titik masuk ialah skrip shell kecil yang menyediakan bekas: shim ini menghasilkan templat fail config, mengesahkan pemboleh ubah persekitaran, mengendalikan isyarat dan akhirnya melaksanakan proses utama.
  • Bersama-sama, kedua-duanya membentuk tunjang beban kerja bekas yang boleh dipercayai dan mudah alih dalam Kubernetes, ECS dan persekitaran pelayan fizikal.

Pelajaran ini merangkumi kedua-dua disiplin dari hujung ke hujung, dengan corak bertaraf produksi yang boleh anda masukkan terus ke dalam saluran paip anda.

Anatomi Dockerfile Berbilang Peringkat

Dockerfile berbilang peringkat menggunakan berbilang arahan FROM. Setiap peringkat ialah set lapisan yang terasing; anda hanya menyalin artifak yang diperlukan ke dalam peringkat seterusnya.

  • Peringkat 0 (builder): memasang pengkompil, pelaksana ujian dan kebergantungan binaan.
  • Peringkat 1 (runtime): bermula daripada asas minimum (contohnya alpine, distroless) dan hanya menyalin perduaan yang telah dikompil atau himpunan aplikasi.
  • Imej akhir tidak mengandungi gcc, make atau kod sumber melainkan anda menyalinnya secara jelas.

Gunakan --from=<stage> dalam COPY untuk mengambil fail merentasi sempadan peringkat. Namakan peringkat dengan AS <name> supaya lebih mudah dibaca dan disasarkan secara terpilih 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"]

Meminimumkan Lapisan dan Membatalkan Cache

Setiap arahan RUN, COPY dan ADD menghasilkan lapisan baharu. Susunan arahan yang kurang baik membatalkan cache binaan tanpa keperluan, lalu melambatkan saluran paip CI.

  • Salin manifes kebergantungan (package.json, go.mod, requirements.txt) sebelum menyalin kod sumber supaya pemasangan kebergantungan dicache secara berasingan.
  • Rantaikan arahan yang berkaitan dengan && dan lakukan pembersihan dalam lapisan RUN yang sama supaya cache pakej tidak tertinggal dalam lapisan perantaraan.
  • Gunakan --no-cache dalam pengurus pakej dan buang fail senarai selepas 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"]

Rahsia BuildKit dan Pemajuan SSH

Pendaftaran peribadi, kunci SSH dan token API tidak boleh sekali-kali muncul dalam lapisan imej. Docker BuildKit menyediakan dua mekanisme selamat:

  • --secret: memasang fail rahsia dalam satu langkah RUN tanpa memasukkannya ke dalam lapisan. Akses melalui /run/secrets/<id>.
  • --ssh: memajukan soket ejen SSH hos ke dalam binaan supaya git clone boleh mengesahkan identiti tanpa membenamkan kunci peribadi.

Dayakan BuildKit dengan DOCKER_BUILDKIT=1 atau melalui docker buildx build. Arahan # syntax=docker/dockerfile:1 membuka ciri-ciri 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 Titik Masuk yang Kukuh

Shim titik masuk ialah skrip shell yang ditetapkan sebagai ENTRYPOINT dalam Dockerfile. Tugasnya adalah menyediakan persekitaran masa jalan sebelum menyerahkan kawalan kepada proses utama.

Shim yang distrukturkan dengan baik mengikut susunan ini:

  • Langkah 1: Tetapkan set -euo pipefail supaya sebarang kegagalan menghentikan pelaksanaan lebih awal.
  • Langkah 2: Sahkan pemboleh ubah persekitaran yang diperlukan dan gagal dengan segera bersama mesej yang membantu.
  • Langkah 3: Hasilkan templat fail config daripada pemboleh ubah persekitaran.
  • Langkah 4: Daftarkan pengendali isyarat untuk penutupan yang lancar.
  • Langkah 5: exec "$@" — gantikan shell dengan proses utama supaya PID 1 ialah aplikasi, bukannya shim.

exec terakhir amat penting: tanpanya, isyarat yang dihantar oleh Kubernetes atau masa jalan Docker tidak dimajukan kepada 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 "$@"

Penghasilan Templat Config dengan envsubst

envsubst (daripada pakej GNU gettext, yang tersedia dalam Alpine sebagai gettext) menggantikan ruang letak ${VAR} dalam fail templat dengan nilai semasa pemboleh ubah persekitarannya.

  • Sertakan templat config *.tmpl dalam imej; titik masuk menghasilkan fail tersebut semasa permulaan.
  • Hantar senarai pemboleh ubah secara jelas kepada envsubst supaya ia tidak mengembangkan tanda dolar yang tidak berkaitan secara tidak sengaja (contohnya dalam ungkapan biasa NGINX).
  • Tulis fail yang telah dihasilkan ke laluan yang boleh ditulis seperti /tmp atau volum config 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 "$@"

Pengendalian Isyarat dan Penutupan yang Lancar

Bekas menerima SIGTERM apabila dihentikan oleh Kubernetes, ECS atau docker stop. Jika shim titik masuk anda ialah PID 1 dan tidak memajukan isyarat, proses utama akan dimatikan dengan SIGKILL selepas tempoh ihsan — lalu menyebabkan permintaan tercicir atau kerosakan data.

  • Gunakan trap untuk menangkap SIGTERM dan SIGINT dalam shim.
  • Majukan isyarat kepada PID anak menggunakan kill -TERM "$child".
  • Gunakan wait "$child" untuk menunggu sehingga proses anak keluar, kemudian teruskan kod keluarnya.
  • Sebagai pilihan, gunakan exec untuk menggantikan shell sepenuhnya — kemudian OS menghantar isyarat terus kepada proses anak dan trap tidak diperlukan. Inilah corak pilihan untuk kes mudah.
#!/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 Minimum

Apabila bekas anda menghasilkan proses anak (contohnya shell yang menggandakan proses pekerja), anda memerlukan init sebenar untuk mengutip semula proses zombi. tini ialah perduaan init kecil yang direka khusus untuk bekas.

  • Tambahkan tini ke dalam imej anda dan tetapkannya sebagai pembungkus titik masuk.
  • Ia mengutip semula proses anak zombi, memajukan isyarat dengan betul dan keluar dengan kod status proses anak.
  • Docker disertakan dengan tini terbina dalam yang diaktifkan menggunakan docker run --init, tetapi membenamkannya dalam imej memastikan tingkah laku konsisten merentasi masa jalan (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 sebagai Pengguna Bukan Root

Bekas yang berjalan sebagai root (UID 0) merupakan risiko keselamatan yang besar: pelarian bekas memberikan akses penuh kepada hos. Sentiasa tukar kepada pengguna tanpa keistimewaan sebelum melaksanakan proses utama.

  • Cipta pengguna dan kumpulan sistem khusus dalam Dockerfile dengan addgroup / adduser (Alpine) atau groupadd / useradd (Debian).
  • Tukar pemilikan fail aplikasi dengan COPY --chown=appuser:appgroup — lebih cekap berbanding lapisan RUN chown yang berasingan.
  • Tukar kepada pengguna tersebut dengan arahan USER. Titik masuk dan CMD mewarisi pengguna ini.
  • Kubernetes securityContext.runAsNonRoot: true akan enggan memulakan imej 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 Kesihatan dan Probe Kesediaan dalam Imej

Probe keaktifan dan kesediaan Kubernetes ditakrifkan dalam manifes, tetapi anda juga boleh membenamkan HEALTHCHECK dalam Dockerfile untuk persekitaran docker run kendiri dan Docker Compose.

  • HEALTHCHECK --interval=10s --timeout=3s --start-period=15s --retries=3 CMD ...
  • Gunakan curl --fail atau wget -qO- untuk perkhidmatan HTTP; bagi daemon bukan HTTP, uji soket dengan /dev/tcp/localhost/PORT.
  • Pasang hanya perkara yang diperlukan: dalam imej distroless, elakkan menambah curl hanya untuk pemeriksaan kesihatan — gunakan perduaan probe yang direka khusus atau perduaan kesihatan aplikasi sendiri.
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

Menggabungkan Semuanya: Titik Masuk Produksi

Berikut ialah shim titik masuk lengkap bertaraf produksi yang menggabungkan semua corak daripada pelajaran ini: pengesahan pemboleh ubah persekitaran, penghasilan templat config, pemajuan isyarat dan penyerahan kawalan melalui exec. Corak ini digunakan dalam perkhidmatan mikro Node.js, Python dan Go dunia sebenar yang digunakan pada Kubernetes.

  • Setiap bahagian diberikan komen untuk berfungsi sebagai templat yang mendokumenkan dirinya sendiri.
  • Shim ini dikekalkan di bawah 50 baris — titik masuk hendaklah ringkas dan mudah diaudit.
  • Perhatikan exec "$@" terakhir: selepas semua persediaan selesai, shell digantikan dengan proses aplikasi supaya proses itu menjadi PID 1 dan menerima semua isyarat 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 "$@"

Semakan Pengetahuan: Pengendalian Isyarat dalam Titik Masuk

Uji pemahaman anda tentang pengendalian isyarat dalam skrip titik masuk bekas.

Imbas Kembali: Dockerfile Ringkas dan Titik Masuk Shell

Anda telah merangkumi keseluruhan susunan penghasilan bekas produksi:

  • Binaan berbilang peringkat menggunakan berbilang arahan FROM untuk mengeluarkan pengkompil dan alat binaan daripada imej akhir, lalu menghasilkan lapisan masa jalan yang ringkas dan minimum.
  • Susunan lapisan — salin manifes kebergantungan sebelum kod sumber — memaksimumkan cache yang sepadan dan mempercepatkan saluran paip CI.
  • Rahsia dan pelekap SSH BuildKit menghalang kelayakan daripada masuk ke dalam sejarah imej tanpa menjejaskan binaan yang disahkan.
  • Shim titik masuk mengesahkan pemboleh ubah persekitaran, menghasilkan templat fail config dengan envsubst dan menyerahkan kawalan kepada aplikasi melalui exec "$@".
  • Pengendalian isyarat memerlukan sama ada exec (supaya aplikasi menjadi PID 1) atau corak trap + kill + wait yang jelas apabila kerja latar digunakan.
  • tini menambah pengutipan semula proses zombi dan pemajuan isyarat yang betul apabila bekas menghasilkan berbilang proses.
  • Pengguna bukan root dan arahan HEALTHCHECK melengkapkan imej yang selamat serta boleh dipantau, dan bersedia untuk beban kerja produksi Kubernetes.

Gabungkan corak ini secara konsisten supaya imej anda lebih kecil, lebih pantas digunakan dan jauh lebih kukuh dalam keadaan produksi.

Percuma untuk bermula

Pelajari Kem Intensif DevOps dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
142
Pelajaran
568

Soalan Lazim

Adakah pelajaran “Menulis Dockerfile dan Titik Masuk Shell yang Ringkas” percuma?

Ya — sebanyak 3 pelajaran dalam laluan pembelajaran Kem Intensif DevOps, termasuk “Menulis Dockerfile dan Titik Masuk Shell yang Ringkas”, boleh dibaca sepenuhnya secara percuma di web ini. Selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan interaktif dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Kursus Kem Intensif DevOps merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “Menulis Dockerfile dan Titik Masuk Shell yang Ringkas”?

Tulis skrip binaan berbilang peringkat dan shim titik masuk yang teguh dengan pengendalian isyarat serta templat konfigurasi Anda berlatih Kem Intensif DevOps menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan Kem Intensif DevOps?

Tiada pengalaman terdahulu diperlukan. Pembelajaran Kem Intensif DevOps di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 1 daripada 4.

Berapa lamakah pelajaran “Menulis Dockerfile dan Titik Masuk Shell yang Ringkas” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran Kem Intensif DevOps ini?

Ya. Setiap pelajaran Kem Intensif DevOps menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. Menulis Dockerfile dan Titik Masuk Shell yang Ringkas
  2. Menyediakan Templat Konfigurasi dengan envsubst dan heredoc
  3. Menskripkan Sumber Awan melalui CLI dan jq
  4. Probe Kesihatan, Gerbang Kesediaan dan Gelung Menunggu
← Kembali ke Kem Intensif DevOps