Skip to content

Docker 容器化部署实战

发布时间:2024-03-05 08:00
最后编辑:2024-03-05 08:00
全文大约 0 字(读完需 1 分钟)

"在我电脑上能跑啊。"

这句话大概是程序员最常说的遗言了。Docker 就是为了解决这个问题而生的。

以下是我部署个人项目时积累的一些实战经验,不是从文档里抄的,是真踩过坑的。

一个能用的 Dockerfile

先看一个 Node.js 项目的典型 Dockerfile:

docker
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

看着简单,但里面有几个容易忽略的细节。

先复制 package.json 再复制代码

很多教程把 COPY . . 写在前面,一步到位。

问题是:你改了一行业务代码,Docker 就要重新 npm install。因为文件变了,缓存失效。

先复制 package.json,装完依赖再复制代码,这样只要依赖不变,npm install 那层就走缓存。构建速度能快好几倍。

npm ci 而不是 npm install

npm ci 严格按照 package-lock.json 安装,速度更快,结果更可预测。生产环境用这个更靠谱。

用 alpine 镜像

node:18 的镜像有 900MB+,node:18-alpine 只有 100MB 出头。体积差了近 10 倍。

除非你的项目依赖一些需要 glibc 的原生模块,否则都推荐用 alpine。

Docker Compose 编排

单个容器跑个 Demo 可以,正经项目一般是 App + 数据库 + 缓存,这时候需要 Compose:

yaml
version: '3.8'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      - db
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/mydb

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

几个注意事项:

  • depends_on 只保证启动顺序,不保证数据库"准备好了"。如果 App 启动时数据库还没初始化完,会报连接错误。需要在应用层做重试
  • Volume 要声明,否则容器重建后数据就没了
  • 数据库密码用环境变量传入,别硬编码在配置里

我踩过的坑

.dockerignore 忘了写

第一次构建,镜像整整 2GB。后来发现把 node_modules.git 都打进去了。

加个 .dockerignore

node_modules
.git
.env
*.log

镜像立刻缩到 200MB。

时区问题

容器默认是 UTC 时区,日志里的时间和本地差八小时。排查问题的时候差点疯了。

解决方案是在 Dockerfile 里加一行:

docker
RUN apk add --no-cache tzdata
ENV TZ=Asia/Shanghai

健康检查没配

容器"启动了"不代表"能用了"。App 可能还在初始化数据库连接。

Compose 里可以加 healthcheck:

yaml
healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
  interval: 30s
  timeout: 10s
  retries: 3

部署流程

我现在的部署流程:

  1. 本地开发用 Docker Compose,保证环境一致
  2. 推代码到 GitHub
  3. 服务器上 git pull && docker compose up -d --build
  4. 完事

虽然没有 CI/CD 那么自动化,但对个人项目来说够用了。等项目大了再上 GitHub Actions。

最后

Docker 入门不难,难的是把各种细节处理好。

上面这些坑我每个至少浪费了半小时,写下来希望别人能少走弯路。

Built with ❤️ using VitePress v2 & Vue & Vite