Appearance
Docker容器化部署实战
这篇文档讲的是“一个典型 Web 项目如何落成一套可运行的容器化部署”。重点不是某个具体技术栈,而是应用、数据库、Nginx、Compose 之间怎么配合。
1. 适用场景
这套方案适合:
- 单机服务器部署
- 测试环境 / 预发布环境
- 中小型项目的生产环境
- 需要快速复制环境的场景
它不解决的事情包括:
- K8s 集群编排
- 大规模弹性扩缩
- 服务网格与多集群治理
如果你现在还在单机或单项目阶段,这篇文档已经足够实用。
2. 一个典型的部署结构
以“应用 + MySQL + Nginx”为例,容器化后的结构通常是:
text
用户请求
|
v
Nginx
|
v
App Container
|
v
MySQL Container职责拆分如下:
- App:运行你的业务程序
- MySQL:持久化业务数据
- Nginx:统一入口、反向代理、静态资源、HTTPS
这比“把所有东西都塞进一个容器”更容易维护,也更方便单独重启和排障。
3. 发布模式先想清楚
容器化部署大致有两种常见模式:
3.1 服务器上现编译现构建
流程:
- 上传源码
- 在服务器执行
docker build - 构建镜像并启动
优点:
- 流程直观
- 适合早期验证
缺点:
- 服务器要装构建依赖
- 构建结果容易受环境影响
- 慢
3.2 本地或 CI 先发布,再构建运行镜像
流程:
- 在本地或流水线先完成发布
- 上传发布产物
- 用运行时镜像打包
优点:
- 更符合生产实践
- 服务器更干净
- 镜像更小
经验上:
开发测试阶段可以接受“服务器现构建”,长期方案更推荐“先发布再进镜像”。
4. 项目目录建议
text
deploy/
├── app/ # 应用发布产物
├── nginx/
│ └── default.conf # Nginx 配置
├── mysql/
│ └── data/ # MySQL 数据目录
├── Dockerfile # 应用镜像
└── docker-compose.yml # 整套编排配置这样做的好处:
- 部署目录职责清晰
- 迁移方便
- 备份时知道该备份什么
5. 应用镜像怎么写
这里给一个通用运行时版本的 Dockerfile 思路,适合“已经有发布产物”的场景。
dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY . /app
EXPOSE 80
ENTRYPOINT ["dotnet", "YourApp.dll"]这类 Dockerfile 的特点:
- 简单
- 稳定
- 适合服务器只负责运行
如果你想在镜像内完成 restore / build / publish,则应使用多阶段构建。那部分更适合看工具侧的 ASP.NET项目Docker构建指南。
6. Compose 编排示例
下面是一份单机可落地的 Compose 示例:
yaml
services:
app:
build:
context: ./app
dockerfile: ../Dockerfile
container_name: app-service
restart: unless-stopped
depends_on:
- mysql
networks:
- app-net
mysql:
image: mysql:8.0
container_name: app-mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: YourStrongPassword
MYSQL_DATABASE: app_db
volumes:
- ./mysql/data:/var/lib/mysql
networks:
- app-net
nginx:
image: nginx:1.25
container_name: app-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- app
networks:
- app-net
networks:
app-net:
driver: bridge6.1 这份配置的关键点
- 三层职责拆开
- 数据库数据挂载到宿主机
- Nginx 只负责入口
- 服务之间通过容器名访问
7. Nginx 反向代理怎么写
nginx
server {
listen 80;
server_name _;
location / {
proxy_pass http://app:80;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}7.1 这里最重要的一点
proxy_pass 里通常写的是:
nginx
http://app:80而不是 localhost。
因为这里的 app 是 Compose 中定义的服务名,容器间通过同一网络里的服务名互相访问。
8. 应用连接数据库时要改什么
最常见的错误,是应用配置里数据库地址还写着:
text
127.0.0.1
localhost容器化后通常要改成:
text
mysql例如:
json
"ConnectionStrings": {
"Default": "server=mysql;port=3306;database=app_db;user=root;password=YourStrongPassword;"
}记住:
容器里写
localhost,通常指向的是当前容器自己,不是 MySQL 容器。
9. 实际部署流程
9.1 启动
bash
docker compose up -d --build9.2 查看运行状态
bash
docker compose ps9.3 看日志
bash
docker compose logs
docker compose logs -f app
docker compose logs -f nginx9.4 停止并保留数据
bash
docker compose down如果你已经做了 volume 挂载,MySQL 数据不会因为 down 就丢。
10. 这类部署最容易踩的坑
10.1 数据库没挂载
结果:容器一删,数据全没。
解决:
yaml
volumes:
- ./mysql/data:/var/lib/mysql10.2 应用先启动,数据库还没就绪
depends_on 只保证启动顺序,不保证数据库已经可以接受连接。
解决思路:
- 应用层做重试
- 或数据库加健康检查
10.3 Nginx 配置里写错服务名
例如 Compose 里叫 app,Nginx 里写成 app-service 或 localhost,就会直接 502。
10.4 把敏感信息写死在 Compose
例如数据库密码直接硬编码在 docker-compose.yml。
更稳的做法:
- 用
.env - 用环境变量注入
- 或用单独配置文件挂载
11. 什么时候该从 Compose 升级
如果你出现下面这些需求,就说明单机 Compose 可能开始吃力了:
- 多台服务器统一编排
- 自动扩容
- 滚动发布
- 服务发现复杂
- 统一健康检查与自愈
这时候再考虑 K8s,不要过早上集群。
12. 一句话总结
Docker 容器化部署的核心,不是把程序“塞进容器里”,而是把应用、数据库、网关和数据持久化的职责拆清楚,再用 Compose 组织成一套可复制、可迁移、可排障的部署结构。
