当前位置: 首页 > news >正文

服务容器化和部署到阿里云ECS

服务容器化和部署到阿里云ECS
M系列Mac + Docker + 阿里云ECS:一个RAG项目的完整容器化部署踩坑记录

写在前面:我本地做了一个基于RAG架构的智能文档平台,我想把这个系统部署到公网,算是自己的一个成品展示。同时也想自己走一遍容器部署的过程,在之前的公司,都是有很完善的基础设施,基本上就是调几个命令就能部署成功了。但是那始终不是我自己做的,道听途说的能力不是我真正的能力,我要把这些变成的自己的能力。现在确实有ai agent能做这一切,我还是想把这个能力真正地掌握住。

确实踩了很多坑,之前都没意识到会有这些问题,遂记录下来,以后可以追溯。

概况

我一共有三个服务:

前端react-pwa(react框架)

后端koa-node(koa框架)+MongoDB

后端python-for-ai(FastAPI)+MongoDB+ChromaDB

首先每个服务的根目录需要新增Dockerfile,Dockerfile是用来描述怎么把这个服务构建成镜像。前端项目除了Dockerfile之外,还要增加nginx.conf,用nginx作为服务器承载静态文件,进行展示。

其次,因为有三个服务,使用docker compose来定义和运行多容器服务。Docker-compose放在所有服务的上一级目录的根目录。

Dockerfile的编写

  1. 前端项目

前端分两步,第一步是构建阶段,主要是安装依赖和构建应用。第二步是部署和运行,复制nginx.conf到nginx服务里,并且启动。

Nginx.conf有几个需要注意的点。

  1. docker用的nginx.conf,跟完整nginx的配置是不一样的。nginx的完整配置分为三部分:全局块(逐条配置,无大括号),events块(用大括号包起来的代码块),http块(用大括号包起来的代码块)。http里还包含server的代码块配置。server就是跟具体服务相关的虚拟主机配置。

Docker的nginx.conf只包含server的部分,在dockerfile里面复制配置的时候

# 将自定义的nginx配置文件复制到nginx的配置目录,覆盖默认配置

COPY nginx.conf /etc/nginx/conf.d/default.conf

/etc/nginx/conf.d/default.conf 这个不是主配置文件,是被include进来的。

主配置文件夹在/etc/nginx/nginx.conf 这个路径。

所以在dockerfile里,专注于当前服务的server配置就好了。

2)设置body的长度,不然大一点的文件就没法上传,会返回413。所以

server {

listen 80;

client_max_body_size 50m; # 这个设置body的长度(大小)

...

}

3)增加让nginx接受的文件类型(放在server里)

types {

application/javascript js mjs;

text/css css;

text/html html;

image/svg+xml svg;

application/json json;

font/woff2 woff2;

}

4)转发请求到后端服务,服务名配置和/

location /koapi/ {

proxy_pass http://backend:3001/;

proxy_set_header Host $host;

proxy_set_header X-Real-IP $remote_addr;

}

这块的含义是,把/koapi/开头的请求转发到backend:3001/上。注意这个后端服务地址的/一定要有,有了的话,/koapi/sth 就是backend:3001/sth,没有的话就是backend:3001/sth。总结:有 / → 替换路径,没 / → 拼接路径。

还有一点,这个服务名backend,需要在docker-compose.yml文件里指定好

backend:

container_name: backend

5)index.html不缓存

location / {

root /usr/share/nginx/html;

try_files $uri $uri/ /index.html;

add_header Cache-Control "no-cache, no-store, must-revalidate";

}

主要是这句add_header Cache-Control "no-cache, no-store, must-revalidate";

6)暴露端口要在dockerfile里表明

# 开放80端口访问

EXPOSE 80

  1. node项目

node项目就简单很多了,下载依赖,启动服务就可以了。

  1. python项目

首先也是安装系统依赖,安装poerty,通过poetry去安装项目依赖。最重要的一点,要设置环境变量,禁用poetry创建虚拟环境。在本地环境,python是需要创建虚拟环境跟其他服务进行隔离,但是在容器里面只有这一个服务,所以不需要进行隔离。最后也是启动服务,由于不需要虚拟环境,所以直接用uvicorn启动。

# 设置环境变量,禁用 Poetry 创建虚拟环境

ENV POETRY_VIRTUALENVS_CREATE=false \

POETRY_VIRTUALENVS_IN_PROJECT=false

Docker-compose的编写

三个项目都要写对应的配置,由于用到了MongoDB,所以数据库也要进行容器化。ChromaDB就不用了,这是直接嵌入python服务里的。

有几个注意的点:

  1. MongoDB需要设置环境,因为我本地设置访问MongoDB是通过账户密码访问的,所以数据库初始化的时候就要设置admin账户,并且设置数据表的名称。一定要设置数据卷volumes,用来持久化数据到宿主机上。
  2. Node服务里用到的环境变量,需要用到的变量,要在environment指定值,这样容器启动的时候,才能带进去。同理python服务和react服务也一样。

Docker-compose的配置文件是用yaml写的,后缀为.yml。yaml是一种标记语言,区分大小写,使用缩进表示层级关机。跟jenkinsfile的语法不一样,jenkins的配置文件用的是groovy语法编写的。

这个yml文件配置的指令参考https://www.runoob.com/docker/docker-compose.html

主要有services。这个包裹下的就是一个个的服务信息。

ai-service: # 服务名

build: ./python-for-ai

container_name: ai-service

restart: always

# ports是暴露给公网的端口,去掉就不会暴露了

# ports:

# - "8000:8000"

env_file:

- ./python-for-ai/.env

volumes:

- chroma_data:/app/chroma

- uploads_data:/app/public/uploads

depends_on:

- mongodb

networks:

- app-net

比如这个服务的配置就是写在service下面的。

有个要注意的点,我上传后的文件是存在node服务的目录里的,所以要加上

volumes:

- uploads_data:/app/public/uploads

同时,这个目录也要供python读取,所以在在python的配置里面,也要加上这一段。这样才能两个服务都读到这个目录。

注意,本地一般是先打镜像再启动容器,这个时候就需要build描述镜像构建目录。如果是服务器上,已经有镜像,只需要启动容器,那就换成image镜像路径。还有depends_on,因为我这几个服务是有先后关系的,所以要使用这个字段来描述服务的先后启动关系。

镜像的生成和推送

配置文件全部准备好之后,就要打镜像了。

  1. 构建镜像

docker compose build

这是生成docker-compose里面的所有指定服务的镜像。

  1. 启动容器

docker compose up

这是启动docker-compose里面所有镜像的容器。

docker compose up -build

构建并启动容器。将build和up合成一条命令。

  1. 停掉容器

docker compose down

注意点:

服务器上的docker-compose跟本地的不太一样,服务器上只写image就可以了。因为我购买的ECS服务器性能比较低,所以在本地构建后镜像,再放到服务器上容器化。

阿里云ECS的使用

ECS篇

首先需要在ECS上进行docker的安装。

怎么安装,阿里云的文档有描述。

然后把docker-compose.yml上传到服务器上。

这里有点要注意,连接ECS的服务器,上传文件用的是SFTP的协议。早年我用ECS还是FTP,现在全面升级到SFTP了。除了主机号和实例密码外,还需要配置SSH的公钥到ECS上,才能正常连接。配置了之后,安全组需要放开22端口才能完成SSH的连接。

Docker安装成功,docker-compose.yml上传好了,容器也正常启动了之后,要在安全组里把80端口放开,不然没法访问到部署的服务。

镜像篇

本地生成好镜像之后,在阿里云申请镜像ACR服务,选择个人版实例。就能得到一个免费的镜像仓库。在本地把镜像上传到镜像仓库。

推送镜像分两步,第一步是给镜像打tag,第二步是推送镜像到远程仓库。

重点注意,ECS的系统是linux,是x86(AMD64),但是我本地电脑macmini M4是ARM架构的,打出的镜像版本也是arm架构的,不匹配x86,所以需要指定平台为linux/amd64来编译x86架构的镜像,否则在部署到服务器上运行时会因为架构不兼容而无法运行。

因此,如果直接打镜像是这样子。直接用docker build [单个镜像的名字] 就可以了,但是build出来的镜像是基于当前平台的。

这里是先用docker compose多个服务打镜像,打完之后打tag

```

DATE=$(date +%Y%m%d%H%M)

docker compose build

docker tag ragdocument-platform-pure-backend crpi-m58blkbdpmba35vy.cn-guangzhou.personal.cr.aliyuncs.com/yupire/rag:backend-$DATE

```

但是现在要基于x86打镜像。注意是用buildx来支持跨平台构建。加上--platform linux/amd64就可以在ARM上构建出x86的镜像。加上—push就是构建后了立马推送。使用三个我自己搭建的服务。

```

docker buildx build --platform linux/amd64 -t crpi-m58blkbdpmba35vy.cn-guangzhou.personal.cr.aliyuncs.com/yupire/rag:backend-$DATE ./koa-node --push

```

对于MongoDB,直接拉amd64的镜像即可。

```

docker pull --platform linux/amd64 mongo:7

docker tag mongo:7 crpi-m58blkbdpmba35vy.cn-guangzhou.personal.cr.aliyuncs.com/yupire/rag:mongo-$DATE

docker push crpi-m58blkbdpmba35vy.cn-guangzhou.personal.cr.aliyuncs.com/yupire/rag:mongo-$DATE

```

http://www.jsqmd.com/news/725164/

相关文章:

  • 别再只用FFT了!用MATLAB的Hilbert变换和instfreq函数,5分钟搞定信号瞬时频率分析
  • 别再只会用默认窗了!深入浅出聊聊Matlab FIR滤波器中Kaiser窗的参数调优艺术
  • 终极KMS激活指南:5分钟完成Windows和Office永久免费激活
  • 5个实用技巧:用哔哩下载姬downkyi高效下载B站视频的完整指南
  • 我的创作纪念日|码龄 1 年,从踩坑到分享,一路深耕 ESXi 虚拟化
  • 国内外CRM软件功能全景图:客户、销售、数据三大模块一次说清 - 毛毛鱼的夏天
  • 你的模型真的在学吗?用TensorBoard和Weights Biases可视化PyTorch/TensorFlow训练过程(实战指南)
  • 别再手动算坐标了!用C++/Qt手搓一个WGS-84经纬度与ECEF直角坐标互转的轻量库
  • 3分钟掌握Layerdivider:将单张图片智能转换为PSD分层文件的终极指南
  • Inno Setup实战:为你的Unity游戏制作首个安装程序,从下载软件到生成安装包全流程
  • Hitboxer终极指南:掌握键盘SOCD清洁与高级按键映射技术
  • 2026年杭州家教渠道避坑指南(杭州家长珍藏版):六个选项里,总有一个符合杭州家长 - 教育资讯板
  • 告别命令行恐惧:用IDEA内置Git工具轻松上传项目到Gitee(图文详解)
  • Sinkhorn散度在机器人多模态学习中的应用与优化
  • 别再手动复制粘贴了!用C#和EPPlus 7.0把DataGridView数据一键导出Excel(附图片插入技巧)
  • API集成管理:告别数据孤岛,企业数字化转型的关键一步
  • 概率论在机器学习中的核心作用与应用
  • 别再死记硬背公式了!用Python+NumPy实战理解随机信号的均值与方差
  • 从零开始:如何用downkyi打造你的B站视频离线收藏库
  • 从 API 接口到数据清洗:Python `Union` 类型在 3 个真实业务场景中的实战避坑指南
  • 无线传感器网络安全:蚂蚁代理与NRRP协议实践
  • AEUX终极指南:如何将Figma和Sketch设计无缝导入After Effects
  • KKManager完整指南:如何轻松管理Illusion游戏模组和插件
  • 从BPSK到GMSK:一张图看懂移动通信中的调制技术演进与实战选择
  • Applera1n:iOS 15-16.6激活锁离线绕过技术深度解析
  • 告别手动点点点:用CANoe.DIVA 16快速生成UDS自动化诊断测试用例(附CDD配置避坑指南)
  • RL微调中FP16与BF16精度格式的选择与优化
  • 2026年销售管理软件选型指南:14款主流产品功能对比与适配方案 - 毛毛鱼的夏天
  • Switch破解终极指南:5分钟掌握TegraRcmGUI高效注入技巧
  • 告别网络卡顿和广告:OpenWrt软路由搭配AdGuard Home与MosDNS v5.3.1的完整配置与优化心得