Instruksiyalar — WORKDIR, ENV, ARG, EXPOSE, USER, ENTRYPOINT

~20 daq · Docker · Dockerfile — o'z image ingiz

Muammodan boshlaylik

O'tgan darsdagi Dockerfile ishlaydi. Lekin savollar:

  • Ilova root sifatida ishlayapti — xavfsizmi?
  • Build paytida versiya raqamini qanday uzatish kerak?
  • CMD va ENTRYPOINT — farqi nima?
  • Konteyner "tirik", lekin ilova qotib qolgan — Docker buni qanday biladi?

Bu darsda Dockerfile ning qolgan muhim instruksiyalarini ko'ramiz.


ENV — muhit o'zgaruvchilari

ENV NODE_ENV=production \
    PORT=3000

Build paytida ham (RUN larda), konteyner ishlaganda ham mavjud. Standart qiymat sifatida — docker run -e PORT=8080 uni almashtiradi (10-dars).

[!WARNING] Maxfiy qiymatlar (parol, kalit) — ENV da hech qachon. Ular image qatlamida qoladi va docker inspect / docker history da ko'rinadi.


ARG — build vaqtidagi o'zgaruvchilar

ARG NODE_VERSION=22
FROM node:${NODE_VERSION}-alpine

ARG APP_VERSION=dev
ENV APP_VERSION=${APP_VERSION}
docker build --build-arg NODE_VERSION=20 --build-arg APP_VERSION=1.4.2 -t ilova:1.4.2 .
ARG ENV
Qachon mavjud Faqat build paytida Build va ishlash paytida
Qanday beriladi --build-arg -e (run) yoki Dockerfile
Konteynerda ko'rinadimi Yo'q (agar ENV ga ko'chirilmasa) Ha

ARG ham maxfiy ma'lumot uchun emas — u docker history da ko'rinadi. Build paytidagi maxfiy ma'lumot (masalan, xususiy npm token) — RUN --mount=type=secret (39-dars).


EXPOSE — qaysi port

EXPOSE 3000

Faqat hujjat (9-dars): "bu image 3000-portni tinglaydi". Portni ochmaydi — -p kerak. Lekin yozing: Dockerfile ni o'qigan odam darhol tushunadi.


USER — root siz ishlash

Standart holatda konteyner ichidagi jarayon — root. Ilovada zaiflik topilsa — hujumchi konteyner ichida root bo'ladi, va konteynerdan qochish zaifligi bilan birga — butun server.

FROM node:22-alpine
WORKDIR /app
COPY --chown=node:node package*.json ./
RUN npm ci --omit=dev
COPY --chown=node:node . .

USER node

CMD ["node", "src/index.js"]
  • Rasmiy node image larida tayyor node foydalanuvchisi bor
  • USER node — undan keyingi barcha buyruqlar va konteyner jarayoni — node sifatida
  • COPY --chown=node:node — fayllar node ga tegishli bo'lsin (yozish kerak bo'lsa)

Boshqa image larda foydalanuvchi yaratish:

RUN addgroup -S ilova && adduser -S ilova -G ilova      # Alpine
# RUN groupadd -r ilova && useradd -r -g ilova ilova    # Debian
USER ilova

[!INFO] Root bo'lmagan foydalanuvchi 1024 dan kichik portlarni (80, 443) tinglay olmaydi. Ilovani 3000 yoki 8080 da ishga tushiring; tashqarida -p 80:8080.


CMD va ENTRYPOINT

Ikkalasi ham "konteyner ishga tushganda nima bajarilsin". Farqi — docker run dagi argumentlar bilan munosabatda.

# Faqat CMD
CMD ["node", "server.js"]
docker run ilova                 # node server.js
docker run ilova sh              # sh — CMD to'liq almashtirildi
# ENTRYPOINT + CMD
ENTRYPOINT ["node"]
CMD ["server.js"]
docker run ilova                 # node server.js
docker run ilova seed.js         # node seed.js — faqat CMD qismi almashtirildi
  • ENTRYPOINT — doim bajariladigan dastur
  • CMD — unga standart argumentlar

Image "bitta asbob" bo'lsa (CLI vosita) — ENTRYPOINT. Oddiy ilova — faqat CMD yetarli.

Exec va shell shakli

CMD ["node", "server.js"]       # ✅ exec shakli — JSON massiv
CMD node server.js              # ⚠️ shell shakli — /bin/sh -c "node server.js"

Shell shaklida asosiy jarayon — sh, Node emas. docker stop yuborgan SIGTERM signali Node ga yetib bormaydi — ilova to'g'ri yopilmaydi, Docker 10 soniya kutib, uni majburan o'ldiradi. Doim exec shakli (JSON massiv) ishlating.

Entrypoint skript

Ishga tushishdan oldin tayyorgarlik kerak bo'lsa (migratsiyalar, bazani kutish):

#!/bin/sh
# docker-entrypoint.sh
set -e
echo "Migratsiyalar..."
npx prisma migrate deploy
exec "$@"        # ← CMD ni bajarish; exec — jarayon PID 1 bo'lib qolsin
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["node", "dist/main.js"]

exec "$@" — muhim: skript o'rniga ilova asosiy jarayon bo'ladi va signallarni oladi. Rasmiy mysql, postgres image lari aynan shu naqsh bilan ishlaydi.


HEALTHCHECK — ilova haqiqatan sog'lommi

Konteyner Up — lekin ilova qotib qolgan yoki baza ulanishini yo'qotgan bo'lishi mumkin. Docker buni bilmaydi.

HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
  CMD wget -qO- http://localhost:3000/health || exit 1

Ilovada:

app.get('/health', (req, res) => res.json({ holat: 'ok' }));
docker ps
# STATUS: Up 2 minutes (healthy)
# STATUS: Up 5 minutes (unhealthy)

Compose (28-dars) va orkestratorlar unhealthy konteynerni qayta ishga tushiradi yoki unga trafik yubormaydi.

Alpine da curl yo'q — wget bor. Yoki Node ning o'zi bilan: CMD node -e "fetch('http://localhost:3000/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))".


Boshqalari

LABEL org.opencontainers.image.source="https://github.com/kompaniya/ilova" \
      org.opencontainers.image.version="1.4.2"

VOLUME /app/data          # ma'lumot papkasi (19-dars; odatda Compose da beriladi)

SHELL ["/bin/bash", "-c"] # RUN uchun shell ni almashtirish

STOPSIGNAL SIGINT         # stop paytida qaysi signal

ADD — COPY ga o'xshash, lekin URL dan yuklaydi va arxivlarni avtomatik ochadi. Kutilmagan xatti-harakat tufayli — oddiy nusxalash uchun doim COPY.


To'liq misol

FROM node:22-alpine

ARG APP_VERSION=dev
ENV NODE_ENV=production \
    PORT=3000 \
    APP_VERSION=${APP_VERSION}

WORKDIR /app

COPY --chown=node:node package.json package-lock.json ./
RUN npm ci --omit=dev && npm cache clean --force

COPY --chown=node:node src/ ./src/

USER node
EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD wget -qO- http://localhost:3000/health || exit 1

CMD ["node", "src/index.js"]

Nima uchun shunday?

Nima uchun exec shaklidagi CMD signallar uchun muhim?

Linux da konteynerning asosiy jarayoni — PID 1. docker stop faqat PID 1 ga SIGTERM yuboradi. Shell shaklida PID 1 — sh, va sh odatda signalni bolasiga (Node ga) uzatmaydi. Natijada ilova "ishni tugat" xabarini olmaydi: ochiq so'rovlar uziladi, bazaga yozilayotgan ma'lumot yarim qoladi, va har bir stop 10 soniya davom etadi. Exec shaklida Node — o'zi PID 1, signalni to'g'ridan-to'g'ri oladi va to'g'ri yopiladi (graceful shutdown).


Xulosa

Eslab qoling:

  • ENV — build va ishlash paytida; ARG — faqat build paytida (--build-arg)
  • Maxfiy ma'lumot — ENV da ham, ARG da ham emas
  • EXPOSE — hujjat
  • USER — root siz; COPY --chown; 1024 dan katta portlar
  • ENTRYPOINT — dastur, CMD — standart argumentlar
  • Doim exec shakli: CMD ["node", "app.js"]; entrypoint skriptda exec "$@"
  • HEALTHCHECK — ilova haqiqatan ishlayaptimi
  • COPY, ADD emas

Keyingi dars

14-dars: Qatlamlar va kesh — tez build uchun tartib