案例一: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. 操作
部署和更新
# 构建并启动服务
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)"
验证部署结果
检查容器运行状态:
docker compose -f docker-compose.prod.yml ps测试后端 API:
curl -X POST http://localhost:8000/api/standardize \ -H "Content-Type: application/json" \ -d '{"text": "北京市朝阳区某某街道123号"}'测试前端页面:
curl http://localhost:3000
未经测试的复现命令
# 在当前服务器保存镜像为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定义如何构建镜像(怎么做的过程定义)
镜像是一个快照是一系列的文件,这包含了程序能够运行的一切条件(系统、环境、磁盘卷等)
编排是容器如何运行和交互,如本项目中定义了前后端的接口,后端的热重启,环境变量等
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:专注于域名解析和外部请求路由
这里是本项目的目录结构
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 环境,并将构建好的静态文件放入其中。
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 环境,并将后端代码放入其中
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配置,通常,我们在/etc/nginx/conf.d/下以域名命名的xxx.conf,
[root@iZgw0ee0yux4vr71p4i7xgZ ~]# cd /etc/nginx/conf.d/
[root@iZgw0ee0yux4vr71p4i7xgZ conf.d]# ls
address-parser.conf amebob.cn.conf ap2.amebob.cn.conf
而单个站点的conf,我们仅配置server部分(下面有站点nginx的示例)
在服务器的Nginx配置中,我们会使用include /etc/nginx/conf.d/*.conf;来加载所有的站点Nginx配置。
注意:后面的server配置会覆盖前面的(如果发生冲突)
[root@iZgw0ee0yux4vr71p4i7xgZ conf.d]# cat /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /home;
index index.html;
# 记录访问日志(可选)
access_log /var/log/nginx/default_access.log;
error_log /var/log/nginx/default_error.log warn;
# 安全头
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
location / {
try_files $uri $uri/ /index.html;
}
# 防止爬虫索引
location /robots.txt {
return 200 "User-agent: *\nDisallow: /\n";
}
}
}
- 注意到本项目中使用了两类nginx配置,
容器内部 nginx:专注于静态文件服务和容器间通信
站点nginx:专注于域名解析和外部请求路由
站点nginx
当用户访问 http://ap2.amebob.cn 时,Nginx 会将请求转发到本地运行的前端 Docker 容器(端口 3000),同时保留用户的原始请求信息
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
这里给出一部分
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;
}
新的客户端请求处理流程

