Введение: почему 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