最近帮助好几个人将应用进行容器化,并使用 GitHub Actions 进行持续部署,虽然非常简单,但是属于会者不难。没有做过的人在一开始并不知道如何着手,所以记录一下。
几个在线例子
换脸服务 (Python Flask)
https://face-swap-scnx.onrender.com/,这是一个 Python Flask 项目。
- Restful API 接口文档: https://face-swap-scnx.onrender.com/apidocs
- GraphQL API 接口文档: https://face-swap-scnx.onrender.com/graphql
源代码见: https://github.com/JeffTrain/face-swap
暂未开源的 Java Spring Boot 例子
https://brickpets-user-service-latest-3q8s.onrender.com,这是一个 Java Spring Boot 项目。
- Restful API 接口文档:
- GraphQL API 接口文档: https://brickpets-user-service-latest-3q8s.onrender.com/graphiql?path=/graphql
相关文章见:《通过 Bean 的方式扩展 Spring 应用,使其同时支持多个授权服务颁发的令牌。 - Jeff Tian的文章 - 知乎 》
微信公众号自动回复服务(nodejs)
详见《调用 AWS Bedrock 服务,为微信公众号消息提供自动回复功能。 - Jeff Tian的文章 - 知乎 》。这是一个 NodeJs 项目。
源代码见: https://github.com/Jeff-Tian/bedrock
另一个 Python Flask 项目例子
这是一个英语学习的项目,也是使用 Python Flask 开发。源代码见: https://github.com/lichanping/flaskStudy,本文将以这个项目为例详解相关的代码提交。
步骤详解
应用容器化
首先,需要将应用进行容器化,即写一个 Dockerfile 文件。以上面的 Python Flask 项目为例,虽然应用代码完全由别人开发,但我其实不需要关心应用逻辑,只需要针对其项目特点,写一个 Dockerfile 即可。完整的代码提交见: https://github.com/lichanping/flaskStudy/commit/6d8354ffbc678e6fea8c5fc052364e262f00d4ff,这里做一个分解:
Dockerfile
写了这样一个 Dockerfile:
dockerfile
syntax=docker/dockerfile:1
FROM python:3.10-slim-buster
RUN apt update && apt install -y cmake g++ make ffmpeg libsm6 libxext6 wget
WORKDIR /python-docker
COPY requirements.txt requirements.txt RUN pip3 install -r requirements.txt
COPY . .
ENV IN_DOCKER=true
CMD [ python3, -m , flask, --app, app, run, --host, 0.0.0.0]
如果是一个 nodejs 项目,以前面的 bedrock 项目为例,Dockerfile 是这样的:
dockerfile FROM node:18.3.0-alpine
ENV TIME_ZONE=Asia/Shanghai
RUN mkdir -p /usr/src/app && apk add --no-cache tzdata && echo ${TIME_ZONE} > /etc/timezone && ln -sf /usr/share/zoneinfo/${TIME_ZONE} /etc/localtime
WORKDIR /usr/src/app
RUN npm i --registry=https://registry.npm.taobao.org
COPY . /usr/src/app
RUN yarn
EXPOSE 8080
CMD yarn start
如果是 Java SpringBoot 项目,以前面提到的未开源的项目为例,其 Dockerfile 是这样的:
dockerfile FROM maven as build WORKDIR /code COPY . /code/ RUN mvn package
FROM openjdk:11.0.16-jdk-slim-buster EXPOSE 8080 ENV TZ=Asia/Shanghai WORKDIR /app COPY --from=build /code/target/*.jar . CMD java -jar *.jar
准备构建容器镜像、推送到仓库的脚本
不管是什么项目,这个脚本都是一样的,因为它只需要一个 Dockerfile。不妨为该脚本起个名字,叫 dockerize.sh
shell docker build -t $2/flask-study:$1 . docker images docker run --network host -e CI=true -d -p 127.0.0.1:5000:5000 --name flask-study $2/flask-study:$1 docker ps | grep -q flask-study docker ps -aqf name=flask-study$ docker push $2/flask-study:$1 docker logs $(docker ps -aqf name=flask-study$) curl localhost:5000 || docker logs $(docker ps -aqf name=flask-study$) docker kill flask-study || echo flask-study killed
可以看到要执行该脚本,需要传入一些参数,分别是容器镜像的标签、要推送到的容器仓库的用户名。
在 CICD 中调用 dockerize.sh
如果使用 GitHub Actions,那不妨建一个文件: .github/workflows/cicd.yml,然后,输入以下内容:
yaml name: cicd on: push: branches: [ master ] pull_request: branches: [ master, dockerize ]
jobs:
build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - run: echo ${{secrets.DOCKER_PASSWORD}} | docker login -u ${{secrets.DOCKER_USERNAME}} --password-stdin - run: git_hash=$(git rev-parse --short $GITHUB_SHA) - run: sh dockerize.sh ${{ github.sha }} ${{secrets.DOCKER_USERNAME}} - run: sh dockerize.sh latest ${{secrets.DOCKER_USERNAME}} - run: curl ${{secrets.RENDER_DEPLOY_WEBHOOK_URL}}
可以看到,在这个 CICD 流水线中,需要一些秘密值,分别是 Docker 仓库的用户名和密码,以及一个部署 Webhook 地址,这个我们后面再讲。
在 GitHub 中设置秘密值
将以上的秘密值设置在仓库里:
部署
以前写过很多文章,都是将应用部署到 k8s 环境的,尤其是强烈推荐了 Okteto。但是 Okteto 也没有免费计划了,所以现在推荐 render 这个平台,对第一个例子的部署,详见《在 Python Flask 网站中对接身份认证平台,以Keycloak举例 - Jeff Tian的文章 - 知乎 》。
在 Render 中创建一个 Web Service,将镜像地址填写上就可以了:
将部署 Webhook 回填到 GitHub Secrets
到 Render 的控制面板里,找到部署 Webhook:
回填至 GitHub Secret:
这样,每当你有代码提交,就可以自动持续部署到 Render 平台了。
是不是非常简单?