• 持续集成指南:GitHubAction 自动构建+部署AspNetCore项目


    前言

    之前研究了使用 GitHub Action 自动构建和发布 nuget 包:开发现代化的.NetCore控制台程序:(4)使用GithubAction自动构建以及发布nuget包

    现在更进一步,使用 GitHub Action 在其提供的 runner 里构建 docker 镜像,之后提交到阿里云镜像私有仓库,再在本地的 runner 将镜像 pull 下来运行。

    本文以 AIHub 项目为例。

    AIHub 是一个集成多种模型的AI平台,提供了大模型、计算机视觉、自然语言处理等多种功能,基于 AspNetCore + Blazor Server 技术开发。

    准备 Dockerfile

    首先准备好构建镜像的 Dockerfile

    一般来说使用 dotnet cli 创建项目的时候可以自动生成这个 Dockerfile

    没有的话可以参考我这个

    1. FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
    2. WORKDIR /app
    3. EXPOSE 80
    4. EXPOSE 443
    5. FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
    6. WORKDIR /src
    7. COPY ["AIHub.Blazor/AIHub.Blazor.csproj", "AIHub.Blazor/"]
    8. RUN dotnet restore "AIHub.Blazor/AIHub.Blazor.csproj"
    9. COPY . .
    10. WORKDIR "/src/AIHub.Blazor"
    11. RUN dotnet build "AIHub.Blazor.csproj" -c Release -o /app/build
    12. FROM build AS publish
    13. RUN dotnet publish "AIHub.Blazor.csproj" -c Release -o /app/publish /p:UseAppHost=false
    14. FROM base AS final
    15. WORKDIR /app
    16. COPY --from=publish /app/publish .
    17. ENTRYPOINT ["dotnet", "AIHub.Blazor.dll"]

    可以先在本地试一下 build 有没有问题

    docker build .

    一切正常可以进入下一步

    创建私有镜像仓库

    可以自行搭建,也可以使用云服务产品,我这里使用阿里云的「容器镜像服务 ACR」,个人版是免费的。

    创建一个镜像仓库,代码源选择「本地仓库」,可以通过命令行推送镜像到镜像仓库。

    PS: 我看里面还有 GitHub 仓库作为代码源,不过我还没测试。

    创建之后有个操作指南,这不是很重要,我们只需要关注用户名和密码就行。

    用于登录的用户名为阿里云账号全名,密码为开通服务时设置的密码。

    可以在访问凭证页面修改凭证密码。

    OK,这些信息保存好,接下来需要用到。

    本文使用的仓库地址是: registry.cn-hangzhou.aliyuncs.com/deali/aihub-test

    配置 GitHub Action Secret

    将阿里云仓库的地址、用户名、密码等信息配置到 Action Secret 中

    这里我设置的名字是

    • ALIYUN_DOCKER_REPO

    • ALIYUN_USERNAME

    • ALIYUN_PWD

    构建镜像

    编写 GitHub workflow 配置,细节不再赘述,不清楚的同学可以参考这篇文章: 开发现代化的.NetCore控制台程序:(4)使用GithubAction自动构建以及发布nuget包

    GitHub 提供的 workflow

    这是 GitHub 提供的,我没有使用这个方案,有兴趣的同学可以自行尝试一下。

    1. # 此工作流使用未经 GitHub 认证的操作。
    2. # 它们由第三方提供,并受
    3. # 单独的服务条款、隐私政策和支持
    4. # 文档。
    5. # GitHub 建议将操作固定到提交 SHA。
    6. # 若要获取较新版本,需要更新 SHA。
    7. # 还可以引用标记或分支,但该操作可能会更改而不发出警告。
    8. name: Publish Docker image
    9. on:
    10. release:
    11. types: [published]
    12. jobs:
    13. push_to_registry:
    14. name: Push Docker image to Docker Hub
    15. runs-on: ubuntu-latest
    16. steps:
    17. - name: Check out the repo
    18. uses: actions/checkout@v4
    19. - name: Log in to Docker Hub
    20. uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
    21. with:
    22. username: ${{ secrets.DOCKER_USERNAME }}
    23. password: ${{ secrets.DOCKER_PASSWORD }}
    24. - name: Extract metadata (tags, labels) for Docker
    25. id: meta
    26. uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
    27. with:
    28. images: my-docker-hub-namespace/my-docker-hub-repository
    29. - name: Build and push Docker image
    30. uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
    31. with:
    32. context: .
    33. file: ./Dockerfile
    34. push: true
    35. tags: ${{ steps.meta.outputs.tags }}
    36. labels: ${{ steps.meta.outputs.labels }}

    简单版 workflow

    这是我自己写的 workflow 比 GitHub 提供的例子简单一些

    1. name: Docker Image CI
    2. run-name: ${{ github.actor }} is building a image
    3. on: [push]
    4. jobs:
    5. build:
    6. runs-on: ubuntu-latest
    7. steps:
    8. - uses: actions/checkout@v3
    9. - name: Build the Docker image
    10. run: docker build . --file ./next-antd/AIHub.Blazor/Dockerfile --tag ${{ secrets.ALIYUN_DOCKER_REPO }}:${{ github.run_id }}
    11. - name: Login to aliyun docker repository
    12. run: docker login -u ${{ secrets.ALIYUN_USERNAME }} -p ${{ secrets.ALIYUN_PWD }} ${{ secrets.ALIYUN_DOCKER_REPO }}
    13. - name: Push image to aliyun docker repository
    14. run: docker push ${{ secrets.ALIYUN_DOCKER_REPO }}:${{ github.run_id }}

    这个 build 步骤,在 GitHub 托管的 runner 上构建 docker 镜像,并且推送到私有镜像仓库。

    镜像的 tag 版本,我使用了 run_id 这个环境变量,代表本次构建任务的唯一ID,例如 1658821493

    也可以使用 ${{ github.sha }} 代表这次的 commit sha ,但我觉得太长了就没有使用

    GITHUB_SHA: 触发工作流的提交 SHA。 此提交 SHA 的值取决于触发工作流程的事件。 有关详细信息,请参阅“触发工作流的事件”。 例如,ffac537e6cbbf934b08745a378932722df287a53

    PS:官方提供的例子使用的是 $(date +%s) 时间戳,但我还没探索出在环境变量里拼接字符串的方法。

    搭建本地 runner

    镜像构建完事了,还得在本地的服务器上跑。

    很简单,就是把镜像 pull 下来,然后 docker compose up 就行,现在我们把这一步也加入到 workflow 里。

    添加 runner

    访问这个页面: https://github.com/star-plan/aihub/settings/actions/runners

    点击 New self-hosted runner 按钮

    选择对应的系统和架构,然后根据里面的命令来就完事了。

    本文选择的是 Linux - x64 的方案

    GitHub 提供的命令是这样(这里只是给出例子,实际要以自己的项目配置页面为准)

    1. # Create a folder
    2. $ mkdir actions-runner && cd actions-runner# Download the latest runner package
    3. $ curl -o actions-runner-linux-x64-2.311.0.tar.gz -L https://github.com/actions/runner/releases/download/v2.311.0/actions-runner-linux-x64-2.311.0.tar.gz# Optional: Validate the hash

    其中下载这一步可能会遇到问题,因为某些莫名其妙的原因,GitHub 访问不了,这时候需要使用 proxychains 工具,请自行搜索 + 配置。

    PS:好家伙,这个 runner 居然有 180M

    接着运行命令 runner

    ./config.sh --url [REPO_URL] --token [TOKEN]

    • 提示输入 runner group 名称,默认即可

    • 提示需要输入 runner 名字,我输入了个 aihub

    • 接着还可以输入 label 啥的,根据需求来就行

    配置搞定之后就启动 runner

    ./run.sh

    安装服务

    用 ./run.sh 启动的 runner 并不稳定,退出登录之后就无了,就算使用 & 或者 Ctrl+Z 切换到后台执行,也不是那么稳定。

    GitHub runner 可以作为 Linux 服务运行,使用也很简单。

    先关掉正在运行的 runner

    1. ps aux | grep run.sh
    2. # 找到 pid 之后 kill 掉
    3. kill -9 pid

    安装服务

    sudo ./svc.sh install

    启动服务

    sudo ./svc.sh start

    更多操作请查看第四条参考资料。

    查看 runner 列表

    在 GitHub 页面上查看当前运行的 runner

    地址: https://github.com/star-plan/aihub/settings/actions/runners

    可以看到已经有一个叫 aihub 的 runner 了

    runner 网络代理

    这波我只能说 GitHub 太贴心了!他已经考虑到了不能上 GitHub 的情况,他真的,我哭死😭

    可以在环境变量里设置代理,也可以在 .env 文件里配置,这里我还是选 .env 吧。

    1. https_proxy=http://proxy.local:8080
    2. no_proxy=example.com,myserver.local:443


    更多关于搭建本地 runner 的文档,可以查看参考资料的第三条。

    使用本地 runner 部署服务

    老规矩,使用 docker-compose 来编排服务。

    先创建个目录,里面存放 docker-compose.yml 和一些持久化的文件。

    本例子的路径是: /home/apps/aihub

    1. version: '3.6'
    2. services:
    3. web:
    4. image: ${IMAGE}
    5. container_name: aihub-test
    6. restart: always
    7. environment:
    8. - ASPNETCORE_ENVIRONMENT=Production
    9. - ASPNETCORE_URLS=http://+:80
    10. volumes:
    11. - ./aihub.app.db:/app/aihub.app.db
    12. ports:
    13. - "12002:80"
    14. networks:
    15. - default
    16. - swag
    17. networks:
    18. swag:
    19. name: swag
    20. external: true
    21. default:
    22. name: aihub-test

    镜像部分我用了环境变量,因为每次构建的镜像tag都不一样,我要在 workflow 里将 tag 写入 .env 文件。当然也可以写固定 latest 。

    .env 文件是这样

    IMAGE=registry.cn-hangzhou.aliyuncs.com/deali/aihub-test:6861065827

    OK,总算是到了最后一步,继续编辑我们的 workflow ,增加一个 deployment 任务。

    1. name: Docker Image CI
    2. run-name: ${{ github.actor }} is building a image
    3. on: [push]
    4. jobs:
    5. build:
    6. runs-on: ubuntu-latest
    7. steps:
    8. - uses: actions/checkout@v3
    9. - name: Build the Docker image
    10. run: docker build . --file ./next-antd/AIHub.Blazor/Dockerfile --tag ${{ secrets.ALIYUN_DOCKER_REPO }}:${{ github.run_id }}
    11. - name: Login to aliyun docker repository
    12. run: docker login -u ${{ secrets.ALIYUN_USERNAME }} -p ${{ secrets.ALIYUN_PWD }} ${{ secrets.ALIYUN_DOCKER_REPO }}
    13. - name: Push image to aliyun docker repository
    14. run: docker push ${{ secrets.ALIYUN_DOCKER_REPO }}:${{ github.run_id }}
    15. deployment:
    16. runs-on: [self-hosted, linux, x64]
    17. needs: [build]
    18. steps:
    19. - name: export environment variant
    20. run: echo 'IMAGE=${{ secrets.ALIYUN_DOCKER_REPO }}:${{ github.run_id }}' > /home/apps/aihub/.env
    21. - name: docker compose deploy
    22. run: docker compose -f /home/apps/aihub/docker-compose.yml --project-directory /home/apps/aihub up -d

    注意:

    • jobs 默认是并行执行的,所以需要在 deployment 任务里加上 needs 配置,等 build 完了再部署

    • 使用 jobs..needs 标识运行此作业之前必须成功完成的所有作业。 它可以是一个字符串,也可以是字符串数组。 如果某个作业失败或跳过,则所有需要它的作业都会被跳过,除非这些作业使用让该作业继续的条件表达式。 如果运行包含一系列相互需要的作业,则故障或跳过将从故障点或跳过点开始,应用于依赖项链中的所有作业。 如果希望某个作业在其依赖的作业未成功时也能运行,请在 jobs..if 中使用 always() 条件表达式。

    • deployment 任务是在本地执行的,所以 runs-on 通过多个 label 选择了本地 runner

    • 执行 docker compose 命令的时候工作目录是在 GitHub Action 工具的 _work 目录里,所以需要指定 --project-directory 参数,或者通过 --env-file 指定 .env 文件位置

    查看执行结果

    在 GitHub Action 页面可以查看执行结果。

    搞定!

    参考资料

    文章转载自:程序设计实验室

    原文链接:https://www.cnblogs.com/deali/p/17833948.html

  • 相关阅读:
    SRM供应商管理系统有什么作用?
    在微信公众号怎么添加电子优惠券
    将Bean放入Spring容器中的方式有哪些?
    Haproxy
    windows安装nginx
    028-GUI事件处理,ActionListener事件,MouseListener事件
    Insight h2database SQL like 查询
    springboot如何忽略url大小写呢?
    基于STM32设计的智能水产养殖系统(华为云IOT)
    大厂常问到的14个Java面试题
  • 原文地址:https://blog.csdn.net/sdgfafg_25/article/details/134438379