案例一:ap2部署#
基础工作:使用阿里通义生成部署的docker文件和nginx文件。
1. 问题#
服务器上的 Docker 版本过旧 (1.13.1),缺少 docker-compose 命令
通过docker解决
由于网络限制,无法从 Docker Hub 拉取镜像
首先使用阿里云加速docker,本地编译vue,将编译后的前端文件打包上传;
python版本依赖问题
使用python list 得到全部包版本,交给LLM生成requirements.txt
浏览器访问前端,一直显示空白页面
清除浏览器缓存,by ctrl + shift + del
前端请求404
这个问题常见,多半是请求地址错误
2. 操作#
部署和更新#
1
2
3
4
5
6
7
8
9
10
11
12
13
| # 构建并启动服务
docker compose -f docker-compose.prod.yml up -d --build
# 查看服务状态
docker compose -f docker-compose.prod.yml ps
# 下面涉及的命令默认dockerfile文件名为docker-compose.yml
docker compose down #完全清理当前项目的容器环境,从头开始
docker compose build --no-cache frontend #重新构建名为"frontend"的服务镜像
docker compose up -d #启动所有服务并在后台运行,-d 或 --detach:后台运行模式
# 查看系统端口占用情况
netstat -tlnp | grep -E "(3000|8000)"
|
验证部署结果#
检查容器运行状态:
1
| docker compose -f docker-compose.prod.yml ps
|
测试后端 API:
1
2
3
| curl -X POST http://localhost:8000/api/standardize \
-H "Content-Type: application/json" \
-d '{"text": "北京市朝阳区某某街道123号"}'
|
测试前端页面:
1
| curl http://localhost:3000
|
未经测试的复现命令#
1
2
3
4
5
6
7
8
9
10
11
12
13
| # 在当前服务器保存镜像为tar文件
docker save -o backend.tar ap-demo-2-backend:latest
docker save -o frontend.tar ap-demo-2-frontend:latest
# 将tar文件传到其他服务器(使用scp/rsync/ftp等)
scp backend.tar frontend.tar user@other-server:/tmp/
# 在其他服务器上加载镜像
docker load -i /tmp/backend.tar
docker load -i /tmp/frontend.tar
# 验证镜像已加载
docker images | grep ap-demo-2
|
3. docker相关概念#
区分分镜像文件制作,镜像文件,和编排。
Dockerfile定义如何构建镜像(怎么做的过程定义)
镜像是一个快照是一系列的文件,这包含了程序能够运行的一切条件(系统、环境、磁盘卷等)
编排是容器如何运行和交互,如本项目中定义了前后端的接口,后端的热重启,环境变量等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| version: '3.8'
services:
backend:
build: ./backend #使用 ./backend 目录下的 Dockerfile 来构建一个镜像,并用这个镜像来创建和运行服务容器
ports:
- "8000:8000"
environment:#设置容器内的环境变量
- DASHSCOPE_API_KEY=sk-36264a12c5962603a21ecc535aec8aeb
- AMAP_KEY=c7520c6288555ca42a4ac2c5ceb9738
volumes:
- ./backend:/app #挂载后端文件,配合自定义启动命令,实现热重载,即修改服务器上后端代码,保存即可,无需重启docker
command: uvicorn main:app --host 0.0.0.0 --port 8000 --reload #自定义启动命令,使用 uvicorn 运行应用并开启热重载
#若未定义command,则将使用Dockerfile中的CMD或ENTRYPOINT作为启动命令
frontend:
build: ./frontend
ports:
- "3000:80" #服务器端口:容器内部端口
depends_on:
- backend #当前前端容器,在后端容器启动后,再启动
environment:
- NODE_ENV=production
|

区别卷挂载和热重启#
前者只是文件的同步,后者则是需要相关自定义command的支持

容器实例的创建过程#
编写DockerFile通过 docker build 生成镜像 或者 docker pull 拉取公共镜像,再 docker run 创建实际的容器实例。

注意到本项目中使用了两类nginx配置,
容器内部 nginx:专注于静态文件服务和容器间通信
服务器 nginx:专注于域名解析和外部请求路由
这里是本项目的目录结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| ap-demo/
├── backend/
│ ├── Dockerfile # 后端 Docker 配置文件
│ ├── main.py # 后端主应用文件
│ ├── llm_service.py # LLM 服务实现
│ └── requirements.txt # Python 依赖包列表
├── frontend/
│ ├── Dockerfile # 前端 Docker 配置文件
│ ├── nginx.conf # 前端容器内部 Nginx 配置
│ ├── vite.config.js # Vite 构建配置
│ ├── index.html # 前端入口 HTML 文件
│ ├── package.json # 前端依赖配置
│ └── src/ # 前端源代码目录
│ ├── App.vue # Vue 主应用组件
│ ├── main.js # 前端入口 JS 文件
│ ├── style.css # 全局样式文件
│ ├── components/ # Vue 组件目录
│ │ ├── AddressParser.vue # 地址解析主组件
│ │ └── HelloWorld.vue # 示例组件
│ ├── api/ # API 接口目录
│ │ └── address.js # 地址相关 API 调用封装
│ └── utils/ # 工具类目录
│ └── request.js # HTTP 请求封装
├── docker-compose.yml # Docker Compose 配置文件
├── docker-compose.prod.yml # 生产环境 Docker Compose 配置文件
├── ap2.amebob.cn.conf # 服务器 Nginx 域名配置文件
└── deployment-summary.md # 部署总结文档
|
前端的dockerfile
创建并配置一个 Nginx 环境,并将构建好的静态文件放入其中。
1
2
3
4
5
| FROM nginx:stable-alpine #官方的nginx镜像
COPY dist /usr/share/nginx/html #复制编译后的静态文件
COPY nginx.conf /etc/nginx/nginx.conf #复制自定义配置
EXPOSE 80 #暴露端口80,这个端口是容器内的
CMD ["nginx", "-g", "daemon off;"] #启动 Nginx 服务的命令
|
后的dockerfile
创建并配置了一个 Python 环境,并将后端代码放入其中
1
2
3
4
5
6
7
8
9
10
11
12
13
| FROM python:3.9-slim
WORKDIR /app #设置工作目录为/app
# 使用国内镜像源安装依赖
COPY requirements.txt . #复制依赖文件到/app目录下
RUN pip install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
COPY . . #将本地所有文件(除了 .dockerignore 中排除的)复制到容器的 /app 目录 包括 main.py、llm_service.py 等后端代码
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
4.Nginx代理#
注意到本项目中使用了两类nginx配置,
容器内部 nginx:专注于静态文件服务和容器间通信
服务器 nginx:专注于域名解析和外部请求路由
服务器nginx#
当用户访问 http://ap2.amebob.cn 时,Nginx 会将请求转发到本地运行的前端 Docker 容器(端口 3000),同时保留用户的原始请求信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| server {
listen 80;
server_name ap2.amebob.cn; #处理外部访问端口为80,域名为ap2.amebob.cn的请求
location / {#/表示匹配所有请求
proxy_pass http://localhost:3000; #将所有请求反向代理给前端容器映射的服务器接口3000
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;
# 确保正确传递响应头
proxy_pass_header Content-Type;
proxy_pass_header Content-Length;
}
}
|
后端容器中的nginx#
这里给出一部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
location / {
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://backend; #
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;
}
|
新的客户端请求处理流程#
