Dockerfilelar yozish bo'yicha qo'llanma
Kirish
Dockerfile — bu Docker image yaratish uchun yoziladigan instruksiyalar fayli. Uni oddiy qilib aytganda, "serverga dastur o'rnatish uchun qo'llanma" deb tushunish mumkin — faqat bu qo'llanmani odam emas, Docker o'zi bajaradi.
Nima uchun Dockerfile yoza bilish muhim?
- Takrorlanuvchi muhit — Dockerfile orqali yaratilgan image har qanday serverda bir xil ishlaydi. "Mening kompyuterimda ishladi" muammosi yo'qoladi.
- Versiya nazorati — Dockerfile kodingiz bilan birga Git'da saqlanadi. Kim qachon nima o'zgartirganini kuzatish mumkin.
- Avtomatlashtirish — CI/CD pipeline'larda Docker image avtomatik build va deploy qilinadi.
Ushbu qo'llanmada biz Dockerfile'ning barcha asosiy instruksiyalarini, multi-stage build, layer caching, xavfsizlik amaliyotlari va production-ready namunalarni ko'rib chiqamiz.
Dockerfile instruksiyalari
FROM — Base image tanlash
Har bir Dockerfile FROM bilan boshlanadi. Bu instruksiya imagengiz qaysi asosiy imagega asoslanishini belgilaydi.
FROM <image>[:<tag>] [@<digest>]Misollar:
# Eng oxirgi versiya (tavsiya etilmaydi — noaniq)
FROM node
# Aniq versiya (tavsiya etiladi)
FROM node:20-alpine
# Digest orqali (eng aniq — image content hash bo'yicha)
FROM node@sha256:a1b2c3d4...Production uchun muhim qoidalar:
- Hech qachon
latesttag ishlatmang — bugun ishlayotgan image ertaga boshqa versiyaga o'zgarib, loyihangiz buzilishi mumkin. - Alpine variantlarni afzal ko'ring —
node:20-alpine(50MB) vanode:20(350MB) orasida katta farq bor. Kichik image = tezroq build, kamroq xavfsizlik zaifliklari. - Aniq versiya belgilang —
python:3.12-slim,golang:1.22-alpinekabi.
LABEL — Image metadata
LABEL instruksiyasi image haqidagi ma'lumotlarni (metadata) qo'shish uchun ishlatiladi. Eskirgan MAINTAINER o'rniga LABEL ishlatiladi.
FROM node:20-alpine
LABEL maintainer="Otabek Ismoilov <ismoilovdev@gmail.com>"
LABEL version="1.0"
LABEL description="DevOps Journey API service"Image labellarini ko'rish uchun: docker inspect --format='{{json .Config.Labels}}' image_name
WORKDIR — Working directory
WORKDIR konteyner ichidagi working directory'ni belgilaydi. Bundan keyingi barcha RUN, COPY, CMD va boshqa instruksiyalar shu directory'da bajariladi.
FROM python:3.12-slim
WORKDIR /app
# Endi COPY, RUN buyruqlari /app papkasida ishlaydi
COPY requirements.txt .
RUN pip install -r requirements.txtRUN cd /app emas, WORKDIR /app ishlatiladi. Sababi: RUN cd /app faqat o'sha bitta RUN instruksiyasi ichida ishlaydi, keyingi instruksiyada yana root papkaga qaytadi. WORKDIR esa barcha keyingi instruksiyalar uchun amal qiladi.
Agar papka mavjud bo'lmasa, Docker uni avtomatik yaratadi.
COPY va ADD — Fayllarni copy qilish
COPY — host mashinadagi fayllarni image ichiga ko'chiradi. Oddiy va tushunarli.
# Bitta fayl ko'chirish
COPY package.json /app/
# Barcha fayllarni ko'chirish
COPY . /app/
# Bir nechta fayl ko'chirish
COPY package.json package-lock.json /app/ADD — COPY bilan bir xil, lekin qo'shimcha imkoniyatlari bor:
- URL'dan fayl yuklab olish
.tar.gzarxivlarni avtomatik ochish
# Arxivni avtomatik ochib ko'chiradi
ADD app.tar.gz /app/
# URL'dan yuklab oladi
ADD https://example.com/config.json /app/Qoida: Agar arxiv ochish yoki URL'dan yuklash kerak bo'lmasa — doimo COPY ishlatiladi. ADD ning "yashirin" funksiyalari kutilmagan natijalar berishi mumkin. Ko'pchilik hollarda COPY yetarli va xavfsizroq.
RUN — Command bajarish
RUN instruksiyasi image build jarayonida buyruqlarni bajaradi — paket o'rnatish, fayllarni tayyorlash, kompilyatsiya qilish va boshqalar.
FROM ubuntu:24.04
# Yomon usul — har bir RUN alohida layer yaratadi
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y git
RUN apt-get clean
# Yaxshi usul — bitta layer, kichikroq image
RUN apt-get update && apt-get install -y \
curl \
git \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*Nima uchun buyruqlarni birlashtirish kerak?
Dockerfile'dagi har bir instruksiya (RUN, COPY, ADD) image'ga yangi layer qo'shadi. Ko'p layer = katta image hajmi. Shuning uchun:
- O'zaro bog'liq buyruqlarni
&&bilan birlashtiring apt-get cleanvarm -rf /var/lib/apt/lists/*bilan keshni tozalang- Keraksiz fayllarni o'sha layer ichida o'chiring (keyingi layerda o'chirish hajmni kamaytirmaydi!)
ENV — Environment variables
ENV konteyner ichidagi environment variable'larni belgilaydi. Bu qiymatlar build jarayonida ham, konteyner ishlayotganda ham mavjud bo'ladi.
FROM node:20-alpine
ENV NODE_ENV=production
ENV PORT=3000
# ENV qiymatlari keyingi instruksiyalarda ishlatilishi mumkin
EXPOSE $PORT
CMD ["node", "server.js"]ENV bilan belgilangan qiymatlar konteyner ishlayotganda docker run -e PORT=4000 orqali override qilinishi mumkin.
ARG — Build-time variables
ARG faqat build jarayonida mavjud bo'lgan variable'larni belgilaydi. Konteyner ishlayotganda ular mavjud bo'lmaydi.
# Default qiymat bilan ARG
ARG NODE_VERSION=20
FROM node:${NODE_VERSION}-alpine
ARG APP_VERSION=1.0.0
LABEL version="${APP_VERSION}"Build qilishda ARG qiymatini o'zgartirish:
docker build --build-arg NODE_VERSION=18 --build-arg APP_VERSION=2.0.0 -t myapp .ARG va ENV farqi:
ARG— faqat build vaqtida ishlaydi, konteyner ichida ko'rinmaydiENV— build vaqtida ham, konteyner ichida ham ishlaydi
Hech qachon ARG orqali maxfiy ma'lumotlar (parol, token) bermang! Build tarixida (docker history) ko'rinib qoladi.
CMD va ENTRYPOINT — Container startup
Bu ikki instruksiya konteyner ishga tushganda qaysi buyruq bajarilishini belgilaydi.
CMD — default buyruq. docker run da boshqa buyruq berilsa, override bo'ladi.
FROM python:3.12-slim
CMD ["python", "app.py"]# CMD ishlaydi — python app.py
docker run myapp
# CMD override bo'ladi — bash ochiladi
docker run myapp bashENTRYPOINT — asosiy buyruq. Override bo'lmaydi, faqat argumentlar qo'shiladi.
FROM python:3.12-slim
ENTRYPOINT ["python", "app.py"]# ENTRYPOINT ishlaydi — python app.py
docker run myapp
# Argument qo'shiladi — python app.py --debug
docker run myapp --debugENTRYPOINT + CMD birgalikda — eng kuchli kombinatsiya:
FROM nginx:alpine
# ENTRYPOINT — asosiy buyruq (o'zgarmaydi)
ENTRYPOINT ["nginx", "-g", "daemon off;"]
# CMD — default argumentlar (override mumkin)
CMD ["-c", "/etc/nginx/nginx.conf"]# Default config bilan: nginx -g "daemon off;" -c /etc/nginx/nginx.conf
docker run mynginx
# Boshqa config bilan: nginx -g "daemon off;" -c /custom/nginx.conf
docker run mynginx -c /custom/nginx.confQachon qaysi birini ishlatish kerak?
- Faqat
CMD— oddiy ilovalar uchun, konteyner ichida turli buyruqlar bajarish kerak bo'lganda ENTRYPOINT+CMD— production servislari uchun. ENTRYPOINT asosiy dasturni ishga tushiradi, CMD default parametrlar beradi- Faqat
ENTRYPOINT— konteyner faqat bitta aniq dasturni bajarishi kerak bo'lganda
EXPOSE — Port documentation
EXPOSE Docker'ga konteyner qaysi portlarni tinglashini bildiradi. Lekin bu portni ochmaydi — faqat dokumentatsiya sifatida xizmat qiladi.
FROM node:20-alpine
EXPOSE 3000
CMD ["node", "server.js"]Haqiqatda portni ochish uchun docker run -p ishlatiladi:
# Konteynerning 3000-portini hostning 8080-portiga ulash
docker run -p 8080:3000 myapp
# Barcha EXPOSE qilingan portlarni ochish
docker run -P myappVOLUME — Persistent data
VOLUME konteyner ichida persistent data saqlash uchun mount point yaratadi. Konteyner o'chirilsa ham, volume'dagi ma'lumotlar saqlanib qoladi.
FROM postgres:16-alpine
# Postgres ma'lumotlar bazasi fayllari shu yerda saqlanadi
VOLUME /var/lib/postgresql/dataRuntime'da volume ulash:
# Host papkasini ulash
docker run -v /host/data:/var/lib/postgresql/data postgres
# Docker named volume
docker run -v pgdata:/var/lib/postgresql/data postgresQachon VOLUME ishlatiladi?
- Ma'lumotlar bazalari (PostgreSQL, MySQL, MongoDB)
- Log fayllar
- Upload fayllar
- Konteynerlar o'rtasida almashiladigan ma'lumotlar
USER — Secure user
USER instruksiyasi konteyner ichida qaysi foydalanuvchi nomidan buyruqlar bajarilishini belgilaydi.
FROM node:20-alpine
WORKDIR /app
COPY --chown=node:node . .
RUN npm ci --only=production
# Root'dan node foydalanuvchisiga o'tish
USER node
EXPOSE 3000
CMD ["node", "server.js"]Hech qachon production'da konteynerlarni root sifatida ishlatmang!
Agar konteynerda xavfsizlik zaifligi topilsa, root huquqli konteyner buzg'unchiga host serverga ham kirish imkonini berishi mumkin. Doimo USER instruksiyasi orqali root'siz foydalanuvchiga o'ting.
HEALTHCHECK — Container health check
HEALTHCHECK Docker'ga konteyner ichidagi ilova to'g'ri ishlayotganini tekshirish usulini beradi.
FROM node:20-alpine
WORKDIR /app
COPY . .
RUN npm ci --only=production
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget --spider --quiet http://localhost:3000/health || exit 1
CMD ["node", "server.js"]Parametrlar:
--interval=30s— har 30 soniyada tekshiradi--timeout=5s— 5 soniya ichida javob kelmasa, muvaffaqiyatsiz--start-period=10s— ilova ishga tushishi uchun 10 soniya kutadi--retries=3— 3 marta muvaffaqiyatsiz bo'lsa, konteynerunhealthydeb belgilanadi
# Container health status ko'rish
docker ps
# STATUS ustunida: healthy, unhealthy yoki startingHEALTHCHECK nima uchun kerak?
Konteyner "ishlab turgan" bo'lishi mumkin, lekin ichidagi ilova xato berishi yoki to'xtab qolishi mumkin. HEALTHCHECK orqali Docker (va orchestratorlar — Kubernetes, Docker Swarm) muammo borligini aniqlaydi va konteyneringizni qayta ishga tushiradi.
.dockerignore — Fayllarni exclude qilish
.dockerignore fayli Docker build kontekstiga kirmasligi kerak bo'lgan fayllarni belgilaydi. Bu .gitignore bilan bir xil ishlaydi.
# Version control
.git
.gitignore
# Dependencies (image ichida qayta o'rnatiladi)
node_modules
vendor
__pycache__
# IDE va OS fayllari
.vscode
.idea
*.swp
.DS_Store
Thumbs.db
# Docker fayllari
Dockerfile
docker-compose.yml
.dockerignore
# Maxfiy fayllar
.env
.env.local
*.pem
*.key
# Test va dokumentatsiya
tests
docs
README.md
LICENSE.dockerignore ishlatmaslik oqibatlari:
node_modules(yuzlab MB) har safar build kontekstga ko'chiriladi — build sekinlashadi.gitpapkasi (butun tarix) imagega kirib ketadi — hajm oshadi.envfayli (parollar, tokenlar) imagega kirib ketadi — xavfsizlik muammosi!- Har qanday fayl o'zgarganda Docker keshi bekor bo'ladi — build qayta boshlanadi
Multi-stage Build
Multi-stage build — professional Dockerfile yozishning eng muhim texnikasi. U bitta Dockerfile ichida bir nechta bosqich (stage) yaratish imkonini beradi. Natijada yakuniy image faqat kerakli fayllarni o'z ichiga oladi.
Muammo: Go dasturini kompilyatsiya qilish uchun Go compiler (1GB+) kerak. Lekin tayyor binary faylni ishga tushirish uchun compiler kerak emas. Agar bitta stage ishlatilsa, yakuniy imageda keraksiz compiler qoladi.
Yechim: Multi-stage build.
# ===== 1-BOSQICH: Build =====
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/server .
# ===== 2-BOSQICH: Production =====
FROM alpine:3.19
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --from=builder /app/server .
USER appuser
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD wget --spider --quiet http://localhost:8080/health || exit 1
ENTRYPOINT ["./server"]Natija: Build image ~1GB, yakuniy image ~15MB!
Multi-stage build afzalliklari:
- Kichik image hajmi — yakuniy imageda faqat binary va runtime bor
- Xavfsizlik — source code, build toollar, test fayllar yakuniy imagega kirmaydi
- Tezlik — kichik image tezroq pull va deploy qilinadi
Layer Caching — Build tezligini oshirish
Docker har bir instruksiyani alohida layer sifatida keshlaydi. Agar instruksiya o'zgarmagan bo'lsa, Docker keshdan oladi va qayta bajarmaydi. Buni to'g'ri ishlatish build tezligini bir necha marta oshiradi.
Yomon tartib — kod o'zgarganda barcha dependency'lar qayta o'rnatiladi:
FROM node:20-alpine
WORKDIR /app
# Barcha fayllar o'zgarsa, npm install ham qayta ishlaydi
COPY . .
RUN npm install
CMD ["node", "server.js"]Yaxshi tartib — dependency fayllar alohida ko'chiriladi:
FROM node:20-alpine
WORKDIR /app
# 1-qadam: Faqat dependency fayllarni ko'chirish
COPY package.json package-lock.json ./
RUN npm ci --only=production
# 2-qadam: Ilova kodini ko'chirish
COPY . .
CMD ["node", "server.js"]Nima uchun bu tezroq?
package.json kamdan-kam o'zgaradi, lekin ilova kodi tez-tez o'zgaradi. Yuqoridagi tartibda:
- Kod o'zgarganda — faqat
COPY . .qadamidan boshlab qayta build bo'ladi npm cikeshdan olinadi (sekundlar)- Dependency o'zgarganda —
npm ciqayta ishlaydi
Asosiy qoida: Kamroq o'zgaradigan narsalarni Dockerfile'ning yuqori qismida, tez o'zgaradiganlarni pastda joylashtiring.
Production-ready Dockerfile namunalari
Node.js (Express/NestJS)
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
# --- Production ---
FROM node:20-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --from=builder --chown=appuser:appgroup /app/package.json ./
USER appuser
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget --spider --quiet http://localhost:3000/health || exit 1
CMD ["node", "dist/main.js"]Python (FastAPI/Django)
FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
# --- Production ---
FROM python:3.12-slim
RUN groupadd -r appgroup && useradd -r -g appgroup appuser
WORKDIR /app
COPY --from=builder /install /usr/local
COPY --chown=appuser:appgroup . .
USER appuser
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')" || exit 1
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]Go (Gin/Fiber)
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o server .
# --- Production ---
FROM alpine:3.19
RUN apk --no-cache add ca-certificates \
&& addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --from=builder /app/server .
USER appuser
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD wget --spider --quiet http://localhost:8080/health || exit 1
ENTRYPOINT ["./server"]Java Spring Boot (Maven)
FROM maven:3.9-eclipse-temurin-21-alpine AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn package -DskipTests -B
# --- Production ---
FROM eclipse-temurin:21-jre-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
RUN chown -R appuser:appgroup /app
USER appuser
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
CMD wget --spider --quiet http://localhost:8080/actuator/health || exit 1
ENTRYPOINT ["java", "-jar", "app.jar"].NET (ASP.NET Core)
FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS builder
WORKDIR /app
COPY *.csproj .
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish
# --- Production ---
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --from=builder /app/publish .
USER appuser
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget --spider --quiet http://localhost:8080/health || exit 1
ENTRYPOINT ["dotnet", "MyApp.dll"]Rust
FROM rust:1.77-alpine AS builder
RUN apk add --no-cache musl-dev
WORKDIR /app
COPY Cargo.toml Cargo.lock ./
RUN mkdir src && echo "fn main() {}" > src/main.rs && cargo build --release && rm -rf src
COPY src ./src
RUN cargo build --release
# --- Production ---
FROM alpine:3.19
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --from=builder /app/target/release/myapp .
USER appuser
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD wget --spider --quiet http://localhost:8080/health || exit 1
ENTRYPOINT ["./myapp"]Best Practices — Xulosa
| Qoida | Yomon | Yaxshi |
|---|---|---|
| Base image | FROM node | FROM node:20-alpine |
| Layer caching | COPY . . keyin RUN npm install | COPY package*.json . keyin RUN npm ci |
| User | root (default) | USER appuser |
| Build | Single-stage | Multi-stage build |
| Health check | HEALTHCHECK yo'q | HEALTHCHECK --interval=30s ... |
| Image size | Cache tozalanmagan | rm -rf /var/lib/apt/lists/* |
| Secrets | .env imageda | .dockerignore + runtime env |
| Instructions | Ko'p RUN qatorlar | && bilan birlashtirilgan |
Qo'shimcha Dockerfile namunalarini devops-tools (opens in a new tab) repositoriyasidan topishingiz mumkin.
Qo'shimcha
Qo'shimcha Resurslar
- Docker rasmiy Dockerfile reference (opens in a new tab)
- Docker rasmiy best practices (opens in a new tab)
- Linux Serverlarga Docker o'rnatish (opens in a new tab)
- Docker Compose (opens in a new tab)
Sana: 2023.11.25(2023-yil 25-noyabr)
Oxirgi yangilanish: 2026.02.12(2026-yil 12-fevral)
Muallif: Otabek Ismoilov
| Telegram (opens in a new tab) | GitHub (opens in a new tab) | LinkedIn (opens in a new tab) |
|---|