从入门走到生产环境:Docker 容器化笔记
别急着给从入门走到生产环境:Docker 容器化笔记下定义,先看这次卡在哪。
这次做 Docker 容器化改造,从入门到生产环境,。
基础 Docker
第一个容器
# 运行第一个容器
docker run hello-world
# 运行交互式容器
docker run -it ubuntu bash
# 后台运行容器
docker run -d nginx
# 查看运行的容器
docker ps
# 查看所有容器
docker ps -a
# 停止容器
docker stop <container-id>
# 删除容器
docker rm <container-id>
构建镜像
# Dockerfile
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]
# 构建镜像
docker build -t myapp:latest .
# 查看镜像
docker images
# 删除镜像
docker rmi myapp:latest
Docker Compose
基础配置
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://postgres:password@db:5432/myapp
depends_on:
- db
- redis
db:
image: postgres:13
environment:
- POSTGRES_PASSWORD=password
volumes:
- db-data:/var/lib/postgresql/data
redis:
image: redis:alpine
volumes:
- redis-data:/data
volumes:
db-data:
redis-data:
# 启动服务
docker-compose up -d
# 查看日志
docker-compose logs -f app
# 停止服务
docker-compose down
# 重启服务
docker-compose restart app
生产环境
多阶段构建
# 构建阶段
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 生产阶段
FROM node:16-alpine AS production
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY package*.json ./
RUN npm ci --only=production
EXPOSE 3000
CMD ["node", "dist/index.js"]
健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 3s
retries: 3
start_period: 10s
资源限制
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
安全最佳实践
非 root 用户
FROM node:16-alpine
WORKDIR /app
# 创建非 root 用户
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
# 复制文件并设置权限
COPY --chown=nodejs:nodejs . .
# 切换到非 root 用户
USER nodejs
CMD ["node", "index.js"]
最小化镜像
FROM node:16-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
FROM node:16-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM node:16-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
# 只安装运行时依赖
RUN apk add --no-cache dumb-init
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "dist/index.js"]
扫描漏洞
# 使用 Trivy 扫描
trivy image myapp:latest
# 使用 Anchore 扫描
docker run --rm anchore/anchore-engine:latest analyze --image myapp:latest --tag myapp:latest
# 使用 Clair 扫描
clairctl analyze myapp:latest
踩过的坑
坑一:镜像太大
镜像太大,拉取慢,启动慢。
解决:使用多阶段构建和最小化基础镜像。
# 使用 Alpine 基础镜像
FROM node:16-alpine
# 清理不必要的文件
RUN apt-get update && apt-get install -y \
&& rm -rf /var/lib/apt/lists/*
# 不要安装调试工具
# RUN apk add --no-cache strace gdb # 不要这样做
坑二:权限问题
容器内权限不对,导致启动失败。
解决:正确设置文件权限。
# 设置文件权限
COPY --chown=1001:1001 . /app
USER 1001
坑三:日志问题
容器日志没有正确配置,难以排查问题。
解决:配置日志输出和轮转。
# 配置应用日志输出到 stdout
ENV LOGGING_LEVEL=info
ENV LOGGING_FORMAT=json
# 或使用日志收集器
RUN apk add --no-cache dumb-init
ENTRYPOINT ["dumb-init", "--"]
写在最后
Docker 容器化这东西,不只是打包,是标准化。
解决了:
- 环境一致性
- 部署简化
- 资源隔离
带来了:
- 学习成本
- 安全问题
- 监控问题
使用之前先评估:
- 项目规模
- 团队能力
- 安全要求
不是所有应用都需要容器化,有时候传统部署更简单。
这次 Docker 容器化改造花了一个月,从入门到生产环境。改造完成后,部署时间从 30 分钟降到 5 分钟,环境问题减少了 80%。
可用性说明:本文发布于 2021 年 7 月,距今已超过五年。文中涉及的软件版本、接口、下载地址、命令参数和操作界面可能已经发生变化,部分方案在当前环境下可能失效。请结合官方最新文档核对后再操作,生产环境使用前务必先行验证。
版权声明: 本文首发于 指尖魔法屋-从入门走到生产环境:Docker 容器化笔记(https://blog.thinkmoon.cn/post/99-docker-containerization-beginner-production-practice/) 转载或引用必须申明原指尖魔法屋来源及源地址!
评论
使用 GitHub 账号登录后即可留言,支持 Markdown。