Linux-komentorivin ja Bash-komentosarjojen hallinta · Oppitunti

Keveiden Dockerfile-tiedostojen ja shell-entripointien kirjoittaminen

Kirjoita monivaiheisia koontiskriptejä ja vankkoja entrypoint-sovittimia, joissa on signaalien käsittely ja määritysten mallipohjat.

Oppitunti 1/413 vaihetta

Keveiden Dockerfile-tiedostojen ja shell-entripointien kirjoittaminen on ilmainen Linux-komentorivin ja Bash-komentosarjojen hallinta-oppitunti CoddyKitissä. Tämä on oppitunti 1/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Linux-komentorivin ja Bash-komentosarjojen hallinta-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Linux-komentorivin ja Bash-komentosarjojen hallinta-kurssilla on yhteensä 4 oppituntia.

Miksi kevyet Dockerfile-tiedostot ovat tärkeitä DevOpsissa

Tuotantoympäristöissä jokaisella Docker-imagen megatavulla on hintansa: lataukset ovat hitaampia, hyökkäyspinta suurempi ja rekisterin tallennustilaa kuluu hukkaan. Kevyet Dockerfile-tiedostot yhdessä vankkojen shell-entrypoint-skriptien kanssa ovat kypsän DevOps-käytännön tunnusmerkkejä.

  • Monivaiheiset koonnit erottavat koonnin aikana tarvittavat työkalut lopullisesta ajonaikaisesta imagesta ja pienentävät sen kokoa huomattavasti.
  • Entrypoint-skriptit ovat pieniä shell-skriptejä, jotka valmistelevat kontit: ne muodostavat asetustiedostot mallipohjista, tarkistavat ympäristömuuttujat, käsittelevät signaalit ja suorittavat lopuksi pääprosessin exec-komennolla.
  • Yhdessä ne muodostavat luotettavien ja siirrettävien konttityökuormien perustan Kubernetes-, ECS- ja bare metal -ympäristöissä.

Tässä oppitunnissa käsitellään molemmat osa-alueet alusta loppuun käyttäen tuotantokelpoisia malleja, jotka voitte ottaa suoraan käyttöön putkissanne.

Monivaiheisen Dockerfile-tiedoston rakenne

Monivaiheinen Dockerfile-tiedosto käyttää useita FROM-ohjeita. Jokainen vaihe on erillinen kerrosjoukko, ja seuraavaan vaiheeseen kopioidaan vain tarvittavat artefaktit.

  • Vaihe 0 (builder): asentaa kääntäjät, testien suorittajat ja koonnin riippuvuudet.
  • Vaihe 1 (runtime): alkaa minimaalisesta perustasta (esimerkiksi alpine tai distroless) ja kopioi vain käännetyt binäärit tai sovelluspaketit.
  • Lopullinen image ei sisällä gcc- tai make-ohjelmaa eikä lähdekoodia, ellette kopioi niitä sinne erikseen.

Käyttäkää COPY-ohjeessa määritettä --from=<stage> tiedostojen siirtämiseen vaiheiden välillä. Nimetkää vaiheet määritteellä AS <name>, jotta Dockerfile on helpompi lukea ja voitte kohdistaa koonnin valittuun vaiheeseen komennolla 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"]

Kerrosten minimointi ja välimuistin mitätöinti

Jokainen RUN-, COPY- ja ADD-ohje luo uuden kerroksen. Huonosti järjestetyt ohjeet mitätöivät koontivälimuistin tarpeettomasti, mikä hidastaa CI-putkia.

  • Kopioikaa riippuvuusmanifestit (package.json, go.mod, requirements.txt) ennen lähdekoodin kopioimista, jotta riippuvuuksien asennus voidaan välimuistittaa erikseen.
  • Ketjuttakaa toisiinsa liittyvät komennot komennolla && ja siivotkaa samassa RUN-kerroksessa, jotta paketinhallinnan välimuisti ei jää välivaiheiden kerroksiin.
  • Käyttäkää paketinhallintaohjelmissa asetusta --no-cache ja poistakaa listatiedostot asennuksen jälkeen.
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"]

BuildKit-salaisuudet ja SSH-välitys

Yksityiset rekisterit, SSH-avaimet ja API-tunnukset eivät saa koskaan päätyä image-kerroksiin. Docker BuildKit tarjoaa kaksi turvallista mekanismia:

  • --secret: liittää salaisuustiedoston yhden RUN-vaiheen ajaksi ilman, että se tallentuu kerrokseen. Tiedostoon pääsee polun /run/secrets/<id> kautta.
  • --ssh: välittää isäntäkoneen SSH-agentin socketin koontiin, jolloin git clone voi todentaa käyttäjän ilman yksityisten avainten upottamista imageen.

Ottakaa BuildKit käyttöön asetuksella DOCKER_BUILDKIT=1 tai komennolla docker buildx build. Direktiivi # syntax=docker/dockerfile:1 ottaa nämä ominaisuudet käyttöön.

# 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 .

Vankan entrypoint-skriptin kirjoittaminen

Entrypoint-skripti on shell-skripti, joka asetetaan Dockerfile-tiedostossa ENTRYPOINT-ohjeen arvoksi. Sen tehtävänä on valmistella ajonaikainen ympäristö ennen hallinnan luovuttamista pääprosessille.

Hyvin jäsennelty skripti noudattaa tätä järjestystä:

  • Vaihe 1: Asettakaa set -euo pipefail, jotta mikä tahansa virhe keskeyttää suorituksen heti.
  • Vaihe 2: Tarkistakaa pakolliset ympäristömuuttujat ja keskeyttäkää suoritus nopeasti informatiivisen viestin kera.
  • Vaihe 3: Muodostakaa asetustiedostot ympäristömuuttujien pohjalta.
  • Vaihe 4: Rekisteröikää signaalinkäsittelijät hallittua sammutusta varten.
  • Vaihe 5: exec "$@" — korvatkaa shell pääprosessilla, jotta PID 1 on sovellus eikä entrypoint-skripti.

Lopullinen exec on ratkaisevan tärkeä: ilman sitä Kubernetesin tai Docker-ajonaikaisen ympäristön lähettämät signaalit eivät välity lapsiprosessille.

#!/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 "$@"

Asetusten mallintaminen envsubst-komennolla

envsubst (GNU:n gettext-paketista, joka on Alpinella saatavilla nimellä gettext) korvaa mallipohjatiedoston ${VAR}-paikkamerkit niidenhetkisillä ympäristömuuttujien arvoilla.

  • Toimittakaa imageen *.tmpl-muotoinen asetusten mallipohja; entrypoint-skripti muodostaa siitä lopullisen tiedoston käynnistyksen yhteydessä.
  • Välittäkää muuttujaluettelo envsubst-komennolle eksplisiittisesti, jotta se ei vahingossa laajenna toisiinsa liittymättömiä dollarimerkkejä (esimerkiksi nginxin säännöllisissä lausekkeissa).
  • Kirjoittakaa muodostettu tiedosto kirjoitettavissa olevaan polkuun, kuten /tmp-hakemistoon tai erilliseen asetustaltioon.
#!/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 "$@"

Signaalien käsittely ja hallittu sammutus

Kontit vastaanottavat SIGTERM-signaalin, kun Kubernetes, ECS tai docker stop pysäyttää ne. Jos entrypoint-skripti on PID 1 eikä välitä signaaleja eteenpäin, pääprosessi lopetetaan SIGKILL-signaalilla odotusajan päätyttyä, mikä voi aiheuttaa pyyntöjen katoamista tai tietojen vioittumista.

  • Käyttäkää trap-komentoa SIGTERM- ja SIGINT-signaalien vastaanottamiseen skriptissä.
  • Välittäkää signaali lapsiprosessin PID:lle komennolla kill -TERM "$child".
  • Käyttäkää komentoa wait "$child" odottamaan lapsiprosessin päättymistä ja välittäkää sen paluuarvo eteenpäin.
  • Vaihtoehtoisesti voitte korvata shellin kokonaan komennolla exec. Tällöin käyttöjärjestelmä toimittaa signaalit suoraan lapsiprosessille, eikä trap-komentoa tarvita. Tämä on suositeltu malli yksinkertaisissa tapauksissa.
#!/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 $?

tinin käyttäminen minimaalisena init-prosessina

Kun kontti käynnistää lapsiprosesseja (esimerkiksi työntekijöitä haarauttavan shellin), tarvitsette varsinaisen init-prosessin zombie-prosessien keräämiseen. tini on kontteja varten suunniteltu erittäin pieni init-binääri.

  • Lisätkää tini imageen ja asettakaa se entrypoint-skriptin kääreeksi.
  • Se kerää zombie-lapsiprosessit, välittää signaalit oikein ja päättyy lapsiprosessin paluuarvolla.
  • Docker sisältää valmiin tinin, jonka voi ottaa käyttöön komennolla docker run --init, mutta sen upottaminen imageen varmistaa toiminnan yhdenmukaisuuden eri ajonaikaisissa ympäristöissä (Kubernetes, ECS ja muut).
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"]

Suorittaminen ilman pääkäyttäjän oikeuksia

root-käyttäjänä (UID 0) toimivat kontit ovat merkittävä tietoturvariski: kontista pakeneminen antaa täydet oikeudet isäntäkoneeseen. Vaihtakaa aina etuoikeudettomaan käyttäjään ennen pääprosessin suorittamista.

  • Luokaa Dockerfile-tiedostossa erillinen järjestelmäkäyttäjä ja -ryhmä komennoilla addgroup / adduser (Alpine) tai groupadd / useradd (Debian).
  • Vaihtakaa sovellustiedostojen omistajuus komennolla COPY --chown=appuser:appgroup. Tämä on tehokkaampaa kuin erillinen RUN chown -kerros.
  • Vaihtakaa käyttäjää USER-ohjeella. Tämä käyttäjä periytyy entrypoint-skriptille ja CMD:lle.
  • Kubernetesin securityContext.runAsNonRoot: true kieltäytyy käynnistämästä imagea, joka toimii edelleen pääkäyttäjänä.
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"]

Imagen kuntotarkistukset ja valmiuskyselyt

Kubernetesin elossaolo- ja valmiuskyselyt määritetään manifesteissa, mutta voitte lisätä Dockerfile-tiedostoon myös HEALTHCHECK-ohjeen erillisiä docker run- ja Docker Compose -ympäristöjä varten.

  • HEALTHCHECK --interval=10s --timeout=3s --start-period=15s --retries=3 CMD ...
  • Käyttäkää HTTP-palveluissa komentoja curl --fail tai wget -qO-. Muiden kuin HTTP-taustapalvelujen tapauksessa tarkistakaa socket yhteydellä /dev/tcp/localhost/PORT.
  • Asentakaa vain tarvittavat työkalut: distroless-imageihin ei kannata lisätä curl-ohjelmaa pelkästään kuntotarkistuksia varten. Käyttäkää tarkoitukseen suunniteltua kyselybinääriä tai sovelluksen omaa kuntotarkistusbinääriä.
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

Kaikki yhteen: tuotantokäyttöön sopiva entrypoint-skripti

Seuraava on täydellinen tuotantokäyttöön sopiva entrypoint-skripti, joka yhdistää kaikki tämän oppitunnin mallit: ympäristömuuttujien tarkistuksen, asetusten mallintamisen, signaalien välityksen ja hallinnan luovuttamisen exec-komennolla. Tätä mallia käytetään tosielämän Node.js-, Python- ja Go-mikropalveluissa, jotka on otettu käyttöön Kubernetesissa.

  • Jokainen osio on kommentoitu itseään dokumentoivaksi mallipohjaksi.
  • Skripti on alle 50 riviä pitkä — entrypoint-skriptien tulee olla yksinkertaisia ja helposti tarkastettavia.
  • Huomatkaa lopullinen exec "$@": kun kaikki valmistelut on tehty, shell korvataan sovellusprosessilla, jolloin siitä tulee PID 1 ja se vastaanottaa kaikki käyttöjärjestelmän signaalit suoraan.
#!/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 "$@"

Tietotesti: signaalien käsittely entrypoint-skripteissä

Testatkaa, miten hyvin ymmärrätte signaalien käsittelyn konttien entrypoint-skripteissä.

Kertaus: kevyet Dockerfile-tiedostot ja shell-entrypoint-skriptit

Olette käsitelleet tuotantokonttien kirjoittamisen koko kokonaisuuden:

  • Monivaiheiset koonnit käyttävät useita FROM-ohjeita pitääkseen kääntäjät ja koontityökalut poissa lopullisesta imagesta. Näin syntyvät kevyet ja minimaaliset ajonaikaiset kerrokset.
  • Kerrosten järjestys — riippuvuusmanifestit kopioidaan ennen lähdekoodia — maksimoi välimuistiosumat ja nopeuttaa CI-putkia.
  • BuildKit-salaisuudet ja SSH-liitännät pitävät tunnistetiedot poissa imagen historiasta rikkomatta todennusta vaativia koonteja.
  • Entrypoint-skriptit tarkistavat ympäristömuuttujat, muodostavat asetustiedostot envsubst-komennolla ja luovuttavat hallinnan sovellukselle komennolla exec "$@".
  • Signaalien käsittely edellyttää joko exec-komentoa, jolloin sovellus on PID 1, tai nimenomaista trap + kill + wait -mallia, kun käytössä on taustatöitä.
  • tini lisää zombie-prosessien keräämisen ja varmistaa signaalien oikean välityksen, kun kontti käynnistää useita prosesseja.
  • Pääkäyttäjättömät käyttäjät ja HEALTHCHECK-ohjeet täydentävät turvallisen ja havainnoitavan imagen, joka soveltuu Kubernetesin tuotantotyökuormiin.

Kun yhdistätte nämä mallit johdonmukaisesti, imaget ovat pienempiä, ne otetaan käyttöön nopeammin ja ne toimivat huomattavasti luotettavammin tuotanto-olosuhteissa.

Aloita maksutta

Opi Bash tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
22
Oppitunnit
88

Usein kysytyt kysymykset

Onko oppitunti ”Keveiden Dockerfile-tiedostojen ja shell-entripointien kirjoittaminen” ilmainen?

Kyllä – oppitunnin ”Keveiden Dockerfile-tiedostojen ja shell-entripointien kirjoittaminen” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Linux-komentorivin ja Bash-komentosarjojen hallinta-kurssin, päivitä CoddyKit PROhon. Linux-komentorivin ja Bash-komentosarjojen hallinta-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Keveiden Dockerfile-tiedostojen ja shell-entripointien kirjoittaminen”?

Kirjoita monivaiheisia koontiskriptejä ja vankkoja entrypoint-sovittimia, joissa on signaalien käsittely ja määritysten mallipohjat. Harjoittelet Linux-komentorivin ja Bash-komentosarjojen hallinta-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Linux-komentorivin ja Bash-komentosarjojen hallinta-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Linux-komentorivin ja Bash-komentosarjojen hallinta-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 1/4.

Kuinka kauan ”Keveiden Dockerfile-tiedostojen ja shell-entripointien kirjoittaminen”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Linux-komentorivin ja Bash-komentosarjojen hallinta-oppitunnilla?

Kyllä. Jokainen Linux-komentorivin ja Bash-komentosarjojen hallinta-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Keveiden Dockerfile-tiedostojen ja shell-entripointien kirjoittaminen
  2. Määritysten mallintaminen envsubstilla ja heredoc-rakenteilla
  3. Pilviresurssien skriptaus CLI-työkaluilla ja jq:lla
  4. Kuntotarkistukset, valmiusportit ja odotussilmukat
← Takaisin: Linux-komentorivin ja Bash-komentosarjojen hallinta