Docker / Node.js апп containerize хийх

Node.js апп containerize хийх

Энэ хичээлд жинхэнэ Express аппликейшнийг Docker-т тохируулна. Development болон production хоёр орчинд ажиллах Dockerfile бичнэ.

Апп бэлдэх

Энгийн Express апп:

код
myapp/
├── src/
│   └── index.ts
├── package.json
├── tsconfig.json
└── .dockerignore

src/index.ts

typescript
import express from "express";

const app = express();
const PORT = process.env.PORT ?? 3000;

app.use(express.json());

app.get("/health", (_req, res) => {
  res.json({ status: "ok", timestamp: Date.now() });
});

app.get("/", (_req, res) => {
  res.json({ message: "Сайн уу, Docker!" });
});

app.listen(PORT, () => {
  console.log(`Сервер ${PORT} порт дээр ажиллаж байна`);
});

package.json

json
{
  "name": "myapp",
  "scripts": {
    "dev": "ts-node-dev src/index.ts",
    "build": "tsc",
    "start": "node dist/index.js"
  },
  "dependencies": {
    "express": "^4.18.2"
  },
  "devDependencies": {
    "@types/express": "^4.17.21",
    "typescript": "^5.3.3",
    "ts-node-dev": "^2.0.0"
  }
}

.dockerignore файл

node_modules болон бусад шаардлагагүй файлыг image-д оруулахгүй байхад .dockerignore ашиглана:

код
node_modules
dist
.git
.gitignore
*.md
.env
.env.*
npm-debug.log*
coverage/
.nyc_output/

.dockerignore байхгүй бол COPY . . тушаал node_modules-ийг хуулж, layer cache буруу болно.

Production Dockerfile

dockerfile
# ── Stage 1: builder ──────────────────────────
FROM node:20-alpine AS builder

WORKDIR /app

# Эхлээд package.json хуулна — layer cache ашиглах
COPY package*.json ./
RUN npm ci

COPY tsconfig.json ./
COPY src/ ./src/
RUN npm run build

# ── Stage 2: production ───────────────────────
FROM node:20-alpine AS production

# Аюулгүй байдал: root биш хэрэглэгчээр ажиллуулна
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

COPY --from=builder /app/dist ./dist

# Өмчлөгчийг тохируулна
RUN chown -R appuser:appgroup /app
USER appuser

EXPOSE 3000

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

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

Development Dockerfile

Хөгжүүлэлтэд hot reload шаардлагатай. Dockerfile.dev нэртэй тусдаа файл хийнэ:

dockerfile
FROM node:20-alpine

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .

EXPOSE 3000

CMD ["npm", "run", "dev"]
bash
# Development container ажиллуулах
docker build -f Dockerfile.dev -t myapp:dev .
docker run -p 3000:3000 -v $(pwd)/src:/app/src myapp:dev

-v $(pwd)/src:/app/src — src фолдерийг mount хийснээр файл өөрчлөгдөхөд container дотор шууд тусгагдана.

docker-compose.yml — development

yaml
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - ./src:/app/src
    environment:
      - NODE_ENV=development
    restart: unless-stopped
bash
docker compose up

Build ба ажиллуулах

bash
# Production image build
docker build -t myapp:latest .

# Container ажиллуулах
docker run -d -p 3000:3000 --name myapp myapp:latest

# Ажиллаж байгаа эсэх шалгах
curl http://localhost:3000/health

node_modules layer оновчлол

Layer cache ажиллахын тулд дараалал чухал:

dockerfile
# ✅ Зөв: package.json өөрчлөгдөхгүй бол npm install дахин ажиллахгүй
COPY package*.json ./
RUN npm ci
COPY . .

# ❌ Буруу: src файл өөрчлөгдөх бүрт npm install дахин ажиллана
COPY . .
RUN npm ci

Environment variable тохируулах

dockerfile
ENV NODE_ENV=production
ENV PORT=3000

Эсвэл container ажиллуулахдаа:

bash
docker run -e NODE_ENV=production -e PORT=8080 -p 8080:8080 myapp

Image хэмжээ шалгах

bash
docker images myapp
# REPOSITORY   TAG       IMAGE ID       SIZE
# myapp        latest    abc123def456   112MB

node:20-alpine + multi-stage ашигласнаар 100–150MB хүртэл буурна.

Дараагийн хичээлд:

Python аппликейшнийг (FastAPI) Docker-т тохируулна — requirements.txt, virtual env шаардлагагүй болох тухай.