介绍:为什么要容器化 TypeScript 应用程序?
现代软件开发离不开容器化。Docker 已成为在隔离环境中打包、交付和运行应用程序的事实标准。与 TypeScript(JavaScript 的严格类型超集)结合使用时,Docker 提供了可预测性、可移植性,并简化了 CI/CD 流程。
在本文中,我们将探讨如何正确容器化 TypeScript 应用程序:从基本的 Dockerfile 到使用 docker-compose 和多阶段构建的生产就绪构建。您将学习如何避免常见错误、减小镜像大小并加速部署。
基础:Docker 中的 TypeScript 和 Node.js
TypeScript 是一种编译为 JavaScript 的语言。这意味着要在容器中运行 TypeScript 应用程序,我们需要先编译源代码,然后使用 Node.js 执行生成的 JavaScript。Docker 非常适合自动化此过程。
创建一个简单的 TypeScript 应用程序
首先,让我们创建一个最小的 TypeScript 应用程序。项目结构:
my-ts-app/├── src/│ └── index.ts├── package.json├── tsconfig.json└── Dockerfilesrc/index.ts:
import express, { Request, Response } from 'express';
const app = express();const PORT = process.env.PORT || 3000;
app.get('/', (req: Request, res: Response) => { res.json({ message: 'Hello from TypeScript + Docker!' });});
app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`);});package.json:
{ "name": "my-ts-app", "version": "1.0.0", "scripts": { "build": "tsc", "start": "node dist/index.js", "dev": "ts-node src/index.ts" }, "dependencies": { "express": "^4.18.2" }, "devDependencies": { "@types/express": "^4.17.21", "@types/node": "^20.11.0", "typescript": "^5.3.3", "ts-node": "^10.9.2" }}tsconfig.json:
{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true }, "include": ["src/**/*"]}基本 Dockerfile
第一个,最简单的 Dockerfile 版本:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]这个 Dockerfile 复制了整个项目,安装了依赖项,编译了 TypeScript 并启动了应用程序。然而,这种方法有缺点:镜像大小很大,并且层缓存效率低下。
优化:多阶段构建和减小大小
对于生产环境,建议使用多阶段构建。这允许将构建和执行阶段分开,在最终镜像中只保留必要的文件。
具有多阶段构建的生产 Dockerfile
# Stage 1: BuildFROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./RUN npm ci --only=production
COPY . .RUN npm run build
# Stage 2: ProductionFROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./distCOPY --from=builder /app/node_modules ./node_modulesCOPY --from=builder /app/package.json ./
EXPOSE 3000
USER node
CMD ["node", "dist/index.js"]这种方法的好处:
- 更小的镜像大小 — 最终层只包含编译后的代码和生产依赖项。
- 安全性 — 容器中不保留 TypeScript 源代码、dev