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

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

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

Начать курс

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

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

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

Прежде чем думать о Kubernetes, нужно убедиться, что ваше приложение готово к запуску в контейнере. Создадим простое Express-приложение на TypeScript. Убедитесь, что в корне проекта есть package.json, tsconfig.json и точка входа src/index.ts.

// 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}`);
});

Важный нюанс: в production мы не используем ts-node. Поэтому в package.json добавьте скрипт сборки:

"scripts": {
  "build": "tsc",
  "start": "node dist/index.js"
}

После выполнения npm run build в папке dist появится скомпилированный JavaScript. Именно эту папку мы будем копировать в Docker-образ.

Шаг 2: Создание Docker-образа с минимальным размером

Для production-деплоя критически важен размер образа. Используем multi-stage сборку: сначала компилируем TypeScript в контейнере с полным SDK, затем копируем результат в лёгкий образ на базе node:18-alpine.

# Dockerfile
# Stage 1: Build
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY tsconfig.json ./
COPY src/ ./src/
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
EXPOSE 3000
CMD ["node", "dist/index.js"]

Соберите образ и проверьте локально:

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

Откройте http://localhost:3000 — вы должны увидеть приветствие.

Шаг 3: Манифесты Kubernetes — Deployment и Service

Теперь перенесём наш образ в кластер. Для этого понадобятся два базовых манифеста: Deployment (управляет репликами и обновлениями) и Service (обеспечивает сетевой доступ).

deployment.yaml

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

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

Примените манифесты в кластер (например, Minikube или облачный K8s):

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

Проверьте, что поды запущены:

kubectl get pods
kubectl get svc

Шаг 4: Ingress — открываем доступ извне (опционально)

Если вы используете облачный кластер или Minikube с включённым Ingress-контроллером, можно настроить Ingress для маршрутизации трафика по доменному имени.

# 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.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: ts-app-service
            port:
              number: 80

Примените Ingress и добавьте запись в /etc/hosts (для локального теста):

kubectl apply -f ingress.yaml
# Добавьте в /etc/hosts: 127.0.0.1 ts-app.local

Теперь приложение доступно по адресу http://ts-app.local. Kubernetes автоматически балансирует нагрузку между двумя репликами и перезапускает под при падении.

Заключение: что дальше?

Мы разобрали базовый пайплайн деплоя TypeScript-приложения в Kubernetes: от написания кода до публикации через Ingress. Этот подход масштабируется на микросервисную архитектуру, CI/CD и автоматическое масштабирование (HPA).

Рекомендуем изучить дополнительные темы:

  • ConfigMap и Secrets для управления конфигурацией
  • PersistentVolume для работы с базой данных
  • Helm-чарты для шаблонизации манифестов
  • Мониторинг через Prometheus и Grafana

Помните: Kubernetes — мощный, но сложный инструмент. Начните с малого, автоматизируйте сборку образов через GitHub Actions и постепенно внедряйте продви

Блоги

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