LOADING

加载过慢请开启缓存 浏览器默认开启

基于阿里云云效Flow的Python Web服务构建与部署

基于阿里云云效Flow的Python Web服务构建与部署


基本要求

  • 理解并掌握Python虚拟环境的应用价值与管理操作
  • 掌握Docker命令与Dockerfile构建逻辑,能够基于Dockerfile创建容器镜像
  • 熟练掌握阿里云云服务器ECS、阿里云云效代码管理Codeup与流水线Flow,以及阿里云容器镜像服务ACR的相关配置与管理操作
  • 理解并掌握Python项目的多种部署方式,初步体验流水线的应用模式

实验过程

范例代码结构

环境搭建

本地开发环境
  • 在本地环境安装Git与Python3(略)
  • 在本地环境安装Python第三方库
准备云服务器ECS(略)
在ECS安装Docker引擎(略)
在ECS安装Python3
(ecs)$ sudo apt install python3
(ecs)$ sudo apt install python3-venv

![屏幕截图 2024-11-06 152716](https://cdn.jsdelivr.net/gh/Whimsically1/ImgServer/基于阿里云云效Flow的Python Web服务构建与部署/屏幕截图 2024-11-06 152716.png)

![屏幕截图 2024-11-06 152835](https://cdn.jsdelivr.net/gh/Whimsically1/ImgServer/基于阿里云云效Flow的Python Web服务构建与部署/屏幕截图 2024-11-06 152835.png)

基于阿里云容器镜像服务ACR配置镜像仓库

访问容器镜像服务-阿里云,点击“管理控制台”进入实例列表,创建使用个人实例。具体使用的镜像仓库将在后续配置Flow流水线时按需创建。

基于阿里云云效代码管理Codeup创建代码库
  • 在Codeup新建远程仓库

新建代码库exp_pyms_demo,注意勾选“创建.gitignore”,并选择Python模板。

新建后,Codeup默认创建Master分支并提供推荐.gitignore文件。

![屏幕截图 2024-11-06 154109](https://cdn.jsdelivr.net/gh/Whimsically1/ImgServer/基于阿里云云效Flow的Python Web服务构建与部署/屏幕截图 2024-11-06 154109.png)

  • 配置SSH访问Codeup远程仓库

根据如何配置SSH密钥及自定义SSH认证密钥的路径_云效(Apsara Devops)-阿里云帮助中心,分别在本地环境与ECS服务器创建SSH公私钥,并在Codeup对应页面添加公钥,保证本地环境与ECS服务器均可基于SSH访问Codeup远程仓库。

本地环境已有公钥可以直接使用。下面为ECS服务器添加公钥:

  • 在ECS安装Git
apt-get install git

git config --global user.name "<用户名>"
git config --global user.email "<邮箱>"

![屏幕截图 2024-11-06 172158](https://cdn.jsdelivr.net/gh/Whimsically1/ImgServer/基于阿里云云效Flow的Python Web服务构建与部署/屏幕截图 2024-11-06 172158.png)

获取系统Git版本(需大于1.9):

git --version

![屏幕截图 2024-11-06 172420](https://cdn.jsdelivr.net/gh/Whimsically1/ImgServer/基于阿里云云效Flow的Python Web服务构建与部署/屏幕截图 2024-11-06 172420.png)

  • 对于OpenSSH,ECS已经内置
  • 生成SSH密钥
ssh-keygen -t ed25519 -C "<注释内容>"

[!NOTE]

如果没有添加注释的需求,-C及以后的内容可以不写。

选择生成路径,一般我们选择默认即可。默认路径如下:

# 以 ED25519 算法为例
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/user/.ssh/id_ed25519):

这里直接敲回车就可以。密钥默认生成路径:/home/user/.ssh/id_ed25519,公钥与之对应为:/home/user/.ssh/id_ed25519.pub

设置密钥口令,口令默认为空。可以选择使用口令保护私钥文件。如果不想在每次使用 SSH 协议访问仓库时,都要输入用于保护私钥文件的口令,可以在创建密钥时,输入空口令。

Enter passphrase (empty for no passphrase):
Enter same passphrase again:

保持空白,连续敲击两次回车就可以了。

[!WARNING]

密钥用于鉴权,请谨慎保管。公钥文件以 .pub 扩展名结尾,可以公开给其他人,而没有 .pub 扩展名的私钥文件不要泄露给任何人!

  • 拷贝公钥
xclip -sel clip < ~/.ssh/id_ed25519.pub

[!NOTE]

屏幕截图 2024-11-07 090531

错误信息 “Error: Can’t open display: (null)” 表明 xclip 命令无法找到可用的 X11 显示环境。这通常发生在你通过 SSH 连接到服务器并且没有启用 X11 转发的情况下。由于你是以 root 用户身份连接的,而且 xclip 需要访问图形界面,所以它无法在没有 X11 转发的情况下工作。

可以直接查看/root/.ssh/id_ed25519.pub文件的内容。

cat /root/.ssh/id_ed25519.pub

执行这个命令后,文件的内容将被显示在终端中,可手动复制这些内容。

屏幕截图 2024-11-07 110826

  • 在Codeup上设置公钥

登录云效Codeup,在页面右上角选择个人设置->SSH公钥,添加生成的SSH公钥信息。

屏幕截图 2024-11-07 111956

基于阿里云云服务器ECS直接部署范例服务

获取范例服务包并解压
  • 将范例服务包上传ECS服务器

参考通过WinSCP上传本地文件到Linux系统的ECS或下载文件到本地-阿里云帮助中心,把范例文件上传到ECS。

下载并打开WinSCP,用root用户名登录,即可拖拽传输文件了:

屏幕截图 2024-11-07 143623

  • 解压后获得exp_pyws_demo目录,以此作为工作目录进入。
(ecs)$ tar -xzvf exp_pyms_demo.tar.gz

(ecs)$ cd exp_pyws_demo
(ecs)(exp_pyws_demo)$ ls -F

(ecs)(exp_pyws_demo)$

屏幕截图 2024-11-07 144731

在虚拟环境部署范例服务

创建Python虚拟环境venv并安装requirements.txt指定的相关依赖:

(ecs)(exp_pyws_demo)$ cat requirements.txt #查看所需依赖

(ecs)(exp_pyws_demo)$ python3 -m venv exp_venv #完成后生成目录exp_venv
(ecs)(exp_pyws_demo)$ source exp_venv/bin/activate #激活Python虚拟环境
(ecs)(exp_pyws_demo)(exp_venv)$ pip3 install -r requirements.txt #安装所需依赖

屏幕截图 2024-11-07 145632

启动Python Web服务:

(ecs)(exp_pyws_demo)(exp_venv)$ python3 server.py

屏幕截图 2024-11-07 150452

使用浏览器访问<ECS IP>:8000/,查看服务页面输出。

屏幕截图 2024-11-07 150609

查看无误后,键入Ctrl + C停止服务:

屏幕截图 2024-11-07 150743

随后退出虚拟环境venv,删除虚拟目录。

(ecs)(exp_pyws_demo)(exp_venv)$ deactivate
(ecs)(exp_pyws_demo)$ rm -r exp_venv

屏幕截图 2024-11-07 150915

以容器形式部署范例服务

exp_pyws_demo目录下创建Dockerfile文件,将Python Web服务范例代码打包进容器镜像。

# 基于Python最新基础镜像
FROM python:3.10-slim-buster
LABEL maintainer="<邮箱>"

# 工作目录
WORKDIR /app

# 安装Python库
COPY requirements.txt requirements.txt
RUN apt-get update && apt-get install -y \
    && pip3 install -r requirements.txt

# 清理apt软件包缓存
RUN rm -rf /var/lib/apt/lists/*

# 复制当前文件夹全部文件到镜像
COPY . .

# 暴露服务端口8000
EXPOSE 8000

# 容器启动时执行命令
CMD [ "python3", "server.py"]

屏幕截图 2024-11-07 151920

使用docker build命令构建镜像,完成后通过docker images可查询。

(ecs)(exp_pyws_demo)$ docker build -t exp_pyms_demo .

(ecs)(exp_pyws_demo)$ docker images

屏幕截图 2024-11-07 155515

基于镜像exp_pyms_demo启动容器:

(ecs)$ docker run -d --restart=always --name exp_pyms_demo -p 8000:8000 exp_pyms_demo

屏幕截图 2024-11-07 163540

浏览器访问http://<ECS IP>:8000/,查看服务页面输出。此外也可在ECS中使用curl命令访问ECS本地服务URL,观察输出已确认服务部署是否生效。

(ecs)$ curl http://127.0.0.1:8000

屏幕截图 2024-11-07 163619

测试确认部署无误,关闭容器,删除容器与镜像。

(ecs)$ docker stop exp_pyms_demo #停止容器
(ecs)$ docker rm exp_pyms_demo #删除容器
(ecs)$ docker rmi exp_pyms_demo #删除镜像

屏幕截图 2024-11-07 163717

基于阿里云云效Flow在虚拟环境部署范例服务

配置Git仓库,创建分支venv

将范例服务包下载到本地环境后,解压进入目录exp_pyws_demo,将该目录作为Git工作目录。此时查看目录,内容如下:

(local)$ ls -a -p

屏幕截图 2024-11-07 164345

完成本地仓库初始化之后关联远程仓库。

(local)$ git init

(local)$ git remote add origin git@codeup.aliyun.com:6705174d49e9309ce56b9e53/exp_pyms_demo.git

屏幕截图 2024-11-07 164655

屏幕截图 2024-11-07 164702

查看当前所在分支与工作目录文件状态。每次开工前,首先从远程仓库git pull

(local)$ git pull origin master

(local)$ ls -a -F 
# Codeup远程仓库创建时生成了.gitignore,此时通过git pull已经下载到本地

屏幕截图 2024-11-07 170641

通过git status观察工作目录文件状态,随后全部纳入跟踪且暂存,再提交。

(local)$ git status

(local)$ git add .
# 将本地目录全部文件纳入跟踪
(local)$ git commit -m "init"
# 进行本地初始化提交
(local)$ git push -u origin master
# 推送至远程仓库master分支
(local)$ git checkout -b venv
# 创建venv分支并切换
(local)$ git push --set-upstream origin venv
# 创建远程仓库,与本地仓库关联

屏幕截图 2024-11-07 170827

屏幕截图 2024-11-07 170835

配置云效Flow以支持ECS虚拟环境部署
  • 根据模板创建流水线

在云效流水线Flow系统新建流水线,选择云效预置模板“Python·测试、构建、部署到阿里云ECS/自有主机”,将测试、构建、部署三个阶段命名分别改为代码测试、制品构建、服务部署。

屏幕截图 2024-11-07 171351

  • 配置阶段“流水线源”

点击“添加流水线源”,在“代码源”页面中:

  1. “选择代码源”选择Codeup
  2. “代码仓库”选择exp_pyms_demo
  3. “默认分支”选择venv
  4. “触发事件”选择代码提交
  5. “工作目录”设为exp_pyms_demo

屏幕截图 2024-11-07 171939

  • 配置阶段“代码测试”

本阶段模板设置有“Python单元测试”与“Python代码扫描”两个任务。我们暂不考虑单元测试,删除“Python单元测试”任务。而“Python代码扫描”任务保持模板默认配置即可。

屏幕截图 2024-11-07 172216

  • 配置阶段“制品构建”

本阶段模板设置有一个任务“Python构建上传到仓库”,包含“Python构建”与“构建物上传”两步骤。我们无需对Python脚本进行特殊构建,只需使用默认设置将代码制品打包上传至阿里云提供的“云效公共存储空间”即可。

  • 配置阶段“服务部署”

本阶段模板有一个任务“主机部署”,其中:

  • “制品”选择上一步“构建物上传”步骤设定的制品名称Artifacts_${PIPELINE_ID}

  • “主机组”

首次使用时,需要点击“新建主机组”,弹出界面中选择“新建主机组”下方的“新建主机组-阿里云ECS标签”。

“服务连接”点击“添加服务连接”创建新的服务连接,进行部署授权。

如果没有服务连接,需要新建,并提供服务授权:

屏幕截图 2024-11-07 174023

“地域”选择自己名下的ECS服务器所在地域。

“ECS标签键”,“ECS标签值”依次选择即可。

[!NOTE]

需要先设置ECS服务器的标签:

屏幕截图 2024-11-07 180145

  • “部署配置”

“下载路径”保持默认。

“执行用户”保持默认。

“部署脚本”定义如下:

# 清理上一次部署时的运行环境
pkill python3
rm -rf ~/exp_pyms_demo
# 解压代码到指定运行目录
mkdir ~/exp_pyms_demo
tar -xvzf /home/admin/app/package.tgz -C ~/exp_pyms_demo
# 此处路径必须与“部署配置->下载路径”一致
cd ~/exp_pyms_demo

# 建立Python虚拟环境并安装依赖
python3 -m venv exp_venv
source exp_venv/bin/activate
pip3 install -r requirements.txt

# 运行Web服务
nohup python3 server.py > /dev/null 2>&1 &
# nohup:no hang up,程序输出重定向到nohup.out,终端退出不会影响运行
# > /dev/null:将server.py的日志输出重定向到/dev/null而非标注输出stdout
# 2>&1:2为stderr,>&为重定向,将标准错误出重定向到标准输出
# &:让程序在后台执行,不会被CTRL+C触发的SIGINT中断,终端退出不会影响运行

屏幕截图 2024-11-07 184104

运行流水线

点击“保存并运行”按钮,弹出对话框中点击“运行”按钮,流水线即被触发,逐一执行阶段任务直至最终完成服务部署。

屏幕截图 2024-11-07 184447

此时阿里云ECS已经基于容器启动了Python Web服务,通过curl命令可测试服务接口是否可访问。

(ecs)$ curl http://127.0.0.1:8000

屏幕截图 2024-11-07 184726

也可选择某台能访问ECS IP的终端设备,使用浏览器访问<ECS IP>:8000/,可查看服务页面输出。

修改设备文件,提交代码并触发流水线

在本地环境修改devices.csv,添加一条设备信息,保存退出。

(local)$ vim devices.csv
7097988787878778888,device4,client,PC,00003,10,2023-08-01 00:00:00,WiFi,00:00:00:00:00:15,156.123.2.13,alive

屏幕截图 2024-11-07 191657

直接提交并推送远程仓库并触发流水线执行。

(local)$ git commit -a -m "docs:Add a device info in devices.csv"

(local)$ git push origin venv

屏幕截图 2024-11-07 192018

可见流水线已经自动执行一次:

屏幕截图 2024-11-07 192105

流水线自动执行完毕后,使用浏览器重新访问该服务,可发现设备信息表多出一行,更新成功。

屏幕截图 2024-11-07 192205

完成测试后关闭范例服务
(ecs)$ ps aux|grep server.py

(ecs)$ kill 4981 #<PID>
(ecs)$ ps aux|grep server.py

屏幕截图 2024-11-07 192529

基于阿里云云效Flow以容器形式部署范例服务

配置Git仓库,创建分支docker

在本地环境从当前venv分支中创建检出docker分支。

(local)$ git checkout -b docker
# 基于分支venv检出分支docker

(local)$ git branch

屏幕截图 2024-11-07 192904

准备Dockerfile文件,用于在流水线中制作承载范例服务的Docker镜像。

# 基于Python最新基础镜像
FROM python:3.10-slim-buster
LABEL maintainer="<邮箱>"

# 工作目录
WORKDIR /app

# 安装Python库
COPY requirements.txt requirements.txt
RUN apt-get update && apt-get install -y \
    && pip3 install -r requirements.txt

# 清理apt软件包缓存
RUN rm -rf /var/lib/apt/lists/*

# 复制当前文件夹全部文件到镜像
COPY . .

# 暴露服务端口8000
EXPOSE 8000

# 容器启动时执行命令
CMD [ "python3", "server.py"]

屏幕截图 2024-11-07 211442

添加

(local)$ git add Dockerfile
(local)$ git commit -m "docs:Add Dockerfile"
(local)$ git push --set-upstream origin docker
# 推送远程仓库分支origin/docker,没有则新建
(local)$ la -F

屏幕截图 2024-11-07 195107

配置云效Flow以支持ECS容器镜像部署

基于之前配置的云效Flow流水线进行修改,以支持ECS容器镜像模式部署范例服务。

在云效控制台页面选中之前配置的流水线,点击“编辑”按钮,进入流水线配置页面。其中“代码测试”阶段保持不变,其他三个阶段均需修改。

  • 配置阶段“流水线源”

“默认分支”选择docker

屏幕截图 2024-11-07 195217

  • 配置阶段“镜像构建”

将原“制品构建”阶段更名为“镜像构建”,首先新建“并行任务”用于构建镜像,随后再删除原有任务“Python构建上传到仓库”(否则若该阶段无任务,自身也会被自动删除)。

新建“并行任务”时,在弹出页面中选择“镜像构建”,再选择“Python镜像构建”。

屏幕截图 2024-11-07 204252

随后配置任务“Python镜像构建”,在步骤“镜像构建并推送至ACR(个人版)”中:

  1. 点击“添加服务连接”,创建新的服务连接,“使用范围”设为私密。
  2. 选择“地域”。
  3. 在ACR控制台新建仓库exp_pyms_demo,并绑定到此处。
  4. “标签”:${DATETIME}
  5. “Dockerfile路径”:默认为Dockerfile,即从仓库目录直接查找。

屏幕截图 2024-11-07 203047

  • 配置阶段“服务部署”

首先新建“并行任务”用于容器部署,再删除任务“主机部署”。

新建“并行任务”时,在弹出页面中选择“部署”,再选择“Docker部署”。

在具体配置“Docker部署”任务之前,先点击页面顶部的“变量和缓存”,新建字符变量ACR_LOGIN_PWD,默认值为登录阿里云容器镜像服务ACR时所需密码,必须采用“私密模式”保存。该变量将用于后续任务配置中的“部署脚本”。

屏幕截图 2024-11-07 204647

回到“流程配置”页面,在“服务部署”阶段配置“Docker部署”任务:

“主机组”选择之前所建主机组。

“执行用户”保持默认。

“部署脚本”定义如下,使用时请更换阿里云账号username以及地域region

docker login --username=<username> --password=${ACR_LOGIN_PWD} crpi-exr3j7gox2plovb8.cn-heyuan.personal.cr.aliyuncs.com

docker rm -f exp_pyms_demo

docker pull ${CONTAINER_TAG}
docker run -d --restart=always --name exp_pyms_demo -p 8000:8000 ${CONTAINER_TAG}

点击“添加”新增变量,选择“上游任务 制品/镜像 下载地址”,新增变量“CONTAINER_TAG”,变量值选择镜像公网地址。

运行流水线

点击“保存并运行”按钮,弹出对话框点击“运行”按钮,流水线即被触发,逐一执行阶段任务直至最终完成服务部署。

由于始终报错,决定先将基础镜像拉取至ACR镜像仓库“:

(ecs)$ docker login --username=沙里院的雪 crpi-exr3j7gox2plovb8.cn-heyuan.personal.cr.aliyuncs.com
(ecs)$ docker pull python:3.10-slim-buster
(ecs)$ docker tag python:3.10-slim-buster crpi-exr3j7gox2plovb8.cn-heyuan.personal.cr.aliyuncs.com/whim111/exp_pyms_demo:1.0
(ecs)$ docker push crpi-exr3j7gox2plovb8.cn-heyuan.personal.cr.aliyuncs.com/whim111/exp_pyms_demo:1.0

同时Dockerfile的开头也要修改:

# 基于ACR中的Python基础镜像
FROM crpi-exr3j7gox2plovb8.cn-heyuan.personal.cr.aliyuncs.com/whim111/exp_pyms_demo:1.0

这次Python镜像构建成功。但是Docker部署有报错:

屏幕截图 2024-11-07 223052

端口未释放的问题,重启ECS就解决了。

屏幕截图 2024-11-07 224809

运行完成后,在阿里云ECS上执行docker imagesdocker ps命令查看到生成的镜像和容器。此时用浏览器重新访问该服务,可见之前一样的页面输出。

屏幕截图 2024-11-07 224906

屏幕截图 2024-11-07 224926

屏幕截图 2024-11-07 225006

修改代码文件,提交代码并触发流水线

在本地环境根据“代码测试”阶段“Python代码扫描”任务上次执行所提示的信息,修订server.py存在的格式问题后提交、推送。

屏幕截图 2024-11-07 212040

(local)$ git commit -a -m "style: Adjust format on server.py"
(local)$ git push origin docker

屏幕截图 2024-11-07 225256

本次推送将再次自动触发流水线,可发现修订后的代码文件正常通过了代码扫描。

屏幕截图 2024-11-07 230131