Контейнеризация TypeScript приложений с Docker: полный гайд

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

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

Начать курс

Почему контейнеризация TypeScript приложений — это маст-хев для современного разработчика

Представьте ситуацию: вы написали крутое TypeScript-приложение на своём MacBook, всё работает идеально. Вы заливаете код на сервер под Ubuntu — и получаете кучу ошибок. Знакомо? Проблема в различии окружений: версии Node.js, системные библиотеки, переменные среды. Docker решает эту боль раз и навсегда. Контейнеризация TypeScript приложений позволяет упаковать код вместе со всеми зависимостями в изолированный контейнер, который запустится одинаково на любом сервере, в облаке или на локальной машине коллеги.

В этой статье мы разберём, как правильно контейнеризировать TypeScript-приложение с помощью Docker. Вы узнаете не только базовые шаги, но и продвинутые техники: мультистейдж-билды, оптимизацию размера образа, кэширование зависимостей и работу с переменными окружения. Погнали!

Что такое Docker и зачем он TypeScript-разработчику

Docker — это платформа для создания, доставки и запуска приложений в контейнерах. Контейнер — это лёгкая, автономная среда, которая содержит всё необходимое для работы вашего TypeScript-приложения: код, рантайм (Node.js), системные инструменты, библиотеки и настройки.

Преимущества для TypeScript-проектов очевидны:

  • Воспроизводимость окружения — больше никаких «у меня работает» и «упало на продакшене».
  • Изоляция — каждое приложение работает в своём контейнере, не мешая другим сервисам.
  • Масштабирование — легко запустить 10 экземпляров вашего TypeScript-сервера через Docker Compose или Kubernetes.
  • Простота деплоя — один образ можно запустить на любой платформе: AWS, Google Cloud, DigitalOcean или локально.

Предварительные требования

Перед тем как начать, убедитесь, что у вас установлены:

  • Docker — скачайте с официального сайта (работает на Windows, macOS, Linux).
  • Node.js версии 18 или выше (для компиляции TypeScript).
  • TypeScript — установлен глобально или локально в проекте.

В качестве примера мы возьмём простое Express-приложение на TypeScript. Но подход универсален: вы можете контейнеризировать любой TypeScript-проект — от Telegram-бота до NestJS-сервера.

Структура проекта

Для начала создадим минимальную структуру TypeScript-приложения:

my-typescript-app/
├── src/
│   └── index.ts
├── package.json
├── tsconfig.json
└── Dockerfile

Файл src/index.ts будет содержать простой HTTP-сервер:

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

app.get('/', (req, res) => {
  res.send('Hello from TypeScript + Docker!');
});

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

Файл tsconfig.json с базовыми настройками:

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

Пишем первый Dockerfile для TypeScript приложения

Самый простой способ — сделать одноэтапный билд. Но мы сразу пойдём по правильному пути и создадим мультистейдж-билд. Это позволит уменьшить финальный образ в несколько раз.

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

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

Разберём каждый этап:

  • builder — устанавливаем все зависимости (включая devDependencies), копируем исходники и компилируем TypeScript в JavaScript.
  • production — берём только скомпилированные файлы из первого этапа и устанавливаем только продакшен-зависимости. Это резко уменьшает размер образа.

Сборка и запуск контейнера

Собираем образ командой:

docker build -t my-typescript-app .

Запускаем контейнер:

docker run -p 3000:3000 -d my-typescript-app

Флаг -p 3000:3000 пробрасывает порт контейнера на хост. Теперь открываем браузер и видим Hello from TypeScript + Docker!. Вуаля! Вы только что успешно выполнили контейнеризацию TypeScript приложения.

Оптимизация Docker образа: кэширование зависимостей

Одна из частых ошибок новичков — копировать все файлы до установки зависимостей. Каждое изменение в исходниках будет сбрасывать кэш Docker и переустанавливать npm пакеты. Правильный подход — копировать package.json отдельно:

COPY package*.json ./
RUN npm install
COPY . .

Так Docker будет переустанавливать зависимости только когда меняется package.json. Это экономит минуты при каждой сборке.

Использование .dockerignore

Создайте файл .dockerignore в корне проекта, чтобы не копировать лишние файлы в образ:

node_modules
dist
.git
*.md
.env

Это ускоряет сборку и уменьшает размер образа.

Работа с переменными окружения в Docker и TypeScript

В реальных проектах вы будете использовать переменные окружения: API-ключи, строки подключения к БД, порты. В TypeScript-приложении мы уже используем process.env.PORT. При запуске контейнера передаём их через флаг -e:

docker run -p 3000:3000 -e PORT=4000 -d my-typescript-app

Для продакшена удобнее использовать файл .env и запускать через docker run --env-file .env .... Или, если вы используете Docker Compose, пропишите переменные в docker-compose.yml:

version: '3.8'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - PORT=3000
      - NODE_ENV=production

Docker Compose для TypeScript приложений

Если ваше приложение состоит из нескольких сервисов (например, TypeScript-бекенд + PostgreSQL + Redis), Docker Compose — иде

Блоги

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