7.5 CI/CD综合实训

实验目标

本实验将带你从零开始创建一个简单的 Flask 项目,并综合应用 Gitea、Drone、Harbor 实现完整的 CI/CD 流程:

  • 自动构建:代码推送后自动构建 Docker 镜像
  • 自动部署:自动将应用部署到目标服务器
  • 自动通知:通过邮件通知部署结果

通过本次实验,你将复习上节课学习的自动构建知识,并掌握自动部署和邮件通知的配置方法。

前置知识
在开始本实验前,请确保你已经完成了上节课的学习,了解了 Harbor 镜像仓库的基本使用方法。如果还没有学习,请先查看 7.4 自动化构建(镜像仓库Harbor)

在这个任务中,我们将从零开始创建一个简单的 Flask Web 应用项目。

打开 Gitea 网页,创建一个新项目,项目名称为 helloflask

使用 Sublime Merge 将刚创建的项目克隆到本地。

在项目目录中创建 app.py 文件,这是我们的 Flask 应用主文件:

python

from flask import Flask
import os

app = Flask(__name__)

@app.route("/")
def hello():
    return '''
    <html>
        <head>
            <title>Hello Flask</title>
        </head>
        <body style="text-align: center; padding-top: 100px;">
            <h1 style="color: #2196F3;">Flask inside Docker!</h1>
            <p>这是一个运行在 Docker 容器中的 Flask 应用</p>
        </body>
    </html>
    '''

if __name__ == "__main__":
    port = int(os.environ.get("PORT", 5000))
    app.run(debug=True, host='0.0.0.0', port=port)
代码说明
  • @app.route("/"):定义网站根路径的访问处理函数
  • host='0.0.0.0':允许外部访问,这在 Docker 容器中是必需的
  • port=port:使用环境变量指定的端口,默认为 5000

创建 requirements.txt 文件,用于声明项目依赖的 Python 包:

txt

flask>=3.0.0
技巧
requirements.txt 是 Python 项目的标准依赖声明文件,Docker 构建时会根据这个文件安装所需的包。

在项目根目录创建 Dockerfile 文件,用于定义如何构建 Docker 镜像:

dockerfile

FROM python:3.9-alpine

# 临时解决网络连通性问题
ENV HTTP_PROXY=http://192.168.192.199:10809
ENV HTTPS_PROXY=http://192.168.192.199:10809
ENV ALL_PROXY=http://192.168.192.199:10809

WORKDIR /app

COPY . .
RUN pip install -r requirements.txt

CMD ["python", "app.py"]
Dockerfile 指令说明
  • FROM:指定基础镜像,这里使用 Python 3.9 的精简版
  • WORKDIR:设置工作目录为 /app,如果目录不存在会自动创建
  • COPY . .:复制项目所有文件
  • RUN:安装 Python 依赖包,使用中科大镜像源加速下载
  • CMD:指定容器启动时执行的命令

在配置自动构建之前,我们先测试一下 Dockerfile 是否能正常工作:

bash

docker build -t helloflask:test .
技巧
命令最后的 . 表示当前目录是 Docker 的构建上下文(工作目录),Docker 会从这个目录中查找 Dockerfile 和需要复制的文件。

如果构建成功,你会看到类似下面的输出:

构建成功

可以运行容器测试一下:

bash

docker run --rm -p 5000:5000 helloflask:test

然后在浏览器中访问 http://你的服务器IP:5000,看看是否能正常显示页面。

现在我们已经有了一个可以正常工作的 Flask 项目,接下来配置 Drone 实现自动构建和推送到 Harbor。

在项目根目录创建 .drone.yml 文件(注意文件名以 . 开头,是隐藏文件):

yml

kind: pipeline
type: docker
name: helloflask-cicd   # 任务名称

steps: 
# 步骤1:构建并推送镜像到 Harbor
- name: 构建并推送到Harbor
  image: plugins/docker 
  settings:
    insecure: true
    # 配置国内加速镜像
    mirror: https://docker.seahi.me
    # 镜像信息
    dockerfile: Dockerfile
    repo: 你的Harbor地址:9000/library/helloflask
    tags: latest
    # 注册中心信息,从“秘密”中读取信息
    registry: 你的Harbor地址:9000
    username: 
	  from_secret: harbor_username
    password: 
      from_secret: harbor_password
修改配置
将配置文件中的 你的Harbor地址 替换为实际的 Harbor 服务器 IP 地址!

由于我们在 .drone.yml 中使用了 from_secret 来引用 Harbor 的用户名和密码,需要在 Drone 网页中添加这些秘密。

打开 Drone 网页,进入你的 helloflask 仓库,点击 Settings(设置),然后找到 Secrets(秘密)部分:

添加密钥

添加以下两个秘密:

  • 名称harbor_usernameadmin
  • 名称harbor_passwordHarbor12345
安全提醒
秘密的名称必须与 .drone.yml 文件中 from_secret 后面的值完全一致,包括大小写。如果名称不匹配,构建时将无法获取到正确的认证信息,导致构建失败。

现在所有配置都完成了,我们可以使用 Sublime Merge 将代码提交到 Git 仓库,触发自动构建。

代码推送后,Drone 会自动检测到代码变化并触发构建。打开 Drone 网页,你可以看到正在执行的构建任务:

构建中

点击构建任务可以查看详细的构建日志:

构建成功

构建成功
当看到绿色的对勾和"success"字样时,说明构建已经成功完成!

构建成功后,打开 Harbor 网页,进入 library 项目,查看是否有新推送的 helloflask 镜像:

镜像列表

第一阶段完成

恭喜!你已经成功配置了自动构建流程。现在每当你向 Git 仓库推送代码时,Drone 都会自动构建 Docker 镜像并推送到 Harbor 仓库。

但这只是 CI/CD 的第一步,接下来我们要实现自动部署功能。

有了自动构建的镜像,下一步就是自动部署到服务器上运行。这样就实现了完整的 CI/CD 流程。

编辑 .drone.yml 文件,在 steps 数组中添加部署步骤:

yml

# 步骤2:部署到目标服务器
- name: 部署应用
  pull: if-not-exists
  image: appleboy/drone-ssh
  settings:
    host: 你的目标服务器IP
    port: 22
    username: root
    password: # 从秘密中读取
      from_secret: ssh_password
    script:
      - echo "========== 开始部署 =========="
      - echo "1. 停止并删除旧容器"
      - docker stop helloflask || true
      - docker rm helloflask || true
      - echo "2. 删除旧镜像"
      - docker rmi 你的Harbor地址:9000/library/helloflask:latest || true
      - echo "3. 从 Harbor 拉取最新镜像"
      - docker pull 你的Harbor地址:9000/library/helloflask:latest
      - echo "4. 启动新容器"
      - docker run --name helloflask -p 5000:5000 -d 你的Harbor地址:9000/library/helloflask:latest
      - echo "========== 部署成功 =========="
修改配置

请将配置文件中的以下内容替换为实际值:

  • 你的Harbor地址:Harbor 服务器的 IP 地址
  • 你的目标服务器IP:应用要部署到的服务器 IP 地址(可以和 Harbor 是同一台)
部署步骤说明

这个部署步骤使用 appleboy/drone-ssh 插件,它会通过 SSH 连接到目标服务器并执行一系列命令:

  1. 停止并删除旧容器:使用 || true 确保即使容器不存在也不会报错
  2. 删除旧镜像:清理旧版本的镜像,节省磁盘空间
  3. 拉取最新镜像:从 Harbor 拉取刚刚构建好的最新镜像
  4. 启动新容器:使用新镜像启动容器,对外暴露 5000 端口

这个过程实现了"零停机部署"的简化版本,在生产环境中可能需要更复杂的滚动更新策略。

由于部署步骤需要通过 SSH 连接到目标服务器,我们需要在 Drone 中添加 SSH 密码。

回到 Drone 网页的 Secrets(密钥)设置页面,添加:

  • 名称ssh_password:目标服务器的 root 密码(admin@123)

秘密

使用 Sublime Merge 将修改后的 .drone.yml 文件提交到仓库:

推送后,Drone 会自动触发构建和部署流程。打开 Drone 网页观察执行过程:

构建过程

部署成功
当所有步骤都显示绿色对勾时,说明构建和部署都成功了!

在浏览器中打开 http://目标服务器IP:5000,你应该能看到 Flask 应用的页面:

网页内容

最后一步,我们添加邮件通知功能,让系统在部署完成后自动发送通知邮件,这样即使不盯着 Drone 网页,也能知道部署结果。

编辑 .drone.yml 文件,添加邮件通知步骤:

yml

# 步骤3:发送邮件通知
- name: 邮件通知
  pull: if-not-exists
  image: drillster/drone-email
  settings:
    recipients_only: true
    host: smtp.larksuite.com
    port: 465
    subject: "【HelloFlask项目】部署完成通知"
    username: # 邮箱用户名
      from_secret: email_username
    password: # 邮箱密码
      from_secret: email_password
    from: # 发件人
      from_secret: email_username
    recipients: # 收件人
      from_secret: email_recipients
邮件通知配置说明
  • image: drillster/drone-email:使用 Drone 的邮件插件
  • recipients_only: true:只发送给指定的收件人,不发送给 Git 提交者
  • host/port:SMTP 服务器地址和端口,这里使用飞书邮箱的 SMTP 服务
  • subject:邮件主题
  • from_secret:从密钥中读取邮箱配置信息

回到 Drone 网页的 Secrets 设置页面,添加以下四个密钥:

  • 名称email_username:教师提供
  • 名称email_password:老师提供
  • 名称email_recipients:收件人邮箱(填自己的邮箱)

使用 Sublime Merge 将修改后的配置文件提交到仓库。

等待 Drone 执行完整个流程后,检查你的收件箱,应该能收到部署通知邮件:

CI/CD 完整流程完成

恭喜你!到此为止,你已经完成了一个完整的 CI/CD 流程配置:

  1. 代码管理:使用 Gitea 管理代码
  2. 自动构建:代码推送后 Drone 自动构建 Docker 镜像
  3. 镜像存储:构建的镜像自动推送到 Harbor
  4. 自动部署:自动将应用部署到目标服务器
  5. 状态通知:通过邮件通知部署结果

这就是现代软件开发中的持续集成/持续部署(CI/CD)流程!

相关内容