Деплой TypeScript на Kubernetes: базовое руководство на практике

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: почему TypeScript и Kubernetes — идеальная пара

Современная веб-разработка требует не только качественного кода, но и надёжной инфраструктуры. TypeScript, как статически типизированная надстройка над JavaScript, позволяет создавать масштабируемые серверные приложения с минимальным количеством ошибок на этапе компиляции. Kubernetes (K8s) — стандарт де-факто для оркестрации контейнеров, обеспечивающий автоматическое развёртывание, масштабирование и управление приложениями.

В этом руководстве мы на практике разберём, как собрать простое TypeScript-приложение (Express API), упаковать его в Docker-образ и развернуть в Kubernetes-кластере. Вы получите готовые команды, файлы конфигурации и объяснение каждого шага. Материал рассчитан на разработчиков, которые уже знакомы с основами TypeScript и хотят освоить devops-процессы.

К концу статьи вы сможете самостоятельно деплоить TypeScript-проекты в production-среду с использованием Kubernetes.

1. Подготовка TypeScript-приложения к контейнеризации

1.1. Создание базового Express-сервера на TypeScript

Для демонстрации создадим минимальное API на TypeScript. Убедитесь, что у вас установлены Node.js и npm.

mkdir ts-k8s-app
cd ts-k8s-app
npm init -y
npm install express
npm install -D typescript @types/node @types/express ts-node nodemon

Создайте tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true
  },
  "include": ["src/**/*"]
}

Теперь напишем сам сервер. Создайте файл src/index.ts:

import express, { Request, Response } from 'express';

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

app.get('/health', (_req: Request, res: Response) => {
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
});

app.get('/', (_req: Request, res: Response) => {
  res.send('Hello from TypeScript on Kubernetes!');
});

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

Добавьте скрипты в package.json:

"scripts": {
  "build": "tsc",
  "start": "node dist/index.js",
  "dev": "nodemon src/index.ts"
}

Проверьте сборку: npm run build && npm start. Сервер должен запуститься на порту 3000.

1.2. Оптимизация для production

Для продакшена важно минимизировать размер образа. Добавьте .dockerignore:

node_modules
dist
.git
*.md
.env

Убедитесь, что все зависимости указаны в dependencies (не в devDependencies), если они нужны в рантайме.

2. Сборка Docker-образа для TypeScript-приложения

2.1. Написание Dockerfile

Используем многоступенчатую сборку (multi-stage build) для уменьшения размера финального образа.

# Stage 1: Build
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

# Stage 2: Production
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
EXPOSE 3000
CMD ["node", "dist/index.js"]

Ключевые моменты:

  • npm ci — быстрая и детерминированная установка зависимостей.
  • Второй слой содержит только скомпилированный JS и необходимые модули.
  • Базовый образ node:18-alpine весит всего ~120 МБ.

2.2. Сборка и проверка образа

docker build -t ts-k8s-app:latest .
docker run -p 3000:3000 ts-k8s-app:latest

Откройте http://localhost:3000/health — вы должны увидеть JSON-ответ. Если всё работает, можно пушить образ в реестр (например, Docker Hub):

docker tag ts-k8s-app:latest yourusername/ts-k8s-app:v1
docker push yourusername/ts-k8s-app:v1

3. Развёртывание в Kubernetes: манифесты и команды

3.1. Создание Deployment и Service

Kubernetes манифесты описывают желаемое состояние кластера. Создайте файл k8s/deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ts-app-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: ts-app
  template:
    metadata:
      labels:
        app: ts-app
    spec:
      containers:
      - name: ts-app
        image: yourusername/ts-k8s-app:v1
        ports:
        - containerPort: 3000
        env:
        - name: PORT
          value: "3000"
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 10

Теперь создайте Service для доступа к подам — k8s/service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: ts-app-service
spec:
  selector:
    app: ts-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000
  type: ClusterIP

Примените манифесты:

kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml

Проверьте статус:

kubectl get pods
kubectl get services

3.2. Настройка Ingress для внешнего доступа

Чтобы приложение было доступно извне (например, по домену), используйте Ingress. Создайте k8s/ingress.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ts-app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: ts-app.example.com
    http:
      paths                

Блоги

Рекомендаций по книгам