持续集成指南: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
没有的话可以参考我这个
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY ["AIHub.Blazor/AIHub.Blazor.csproj", "AIHub.Blazor/"]
RUN dotnet restore "AIHub.Blazor/AIHub.Blazor.csproj"
COPY . .
WORKDIR "/src/AIHub.Blazor"
RUN dotnet build "AIHub.Blazor.csproj" -c Release -o /app/buildFROM build AS publish
RUN dotnet publish "AIHub.Blazor.csproj" -c Release -o /app/publish /p:UseAppHost=falseFROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
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 提供的,我没有使用这个方案,有兴趣的同学可以自行尝试一下。
# 此工作流使用未经 GitHub 认证的操作。
# 它们由第三方提供,并受
# 单独的服务条款、隐私政策和支持
# 文档。# GitHub 建议将操作固定到提交 SHA。
# 若要获取较新版本,需要更新 SHA。
# 还可以引用标记或分支,但该操作可能会更改而不发出警告。name: Publish Docker imageon:release:types: [published]jobs:push_to_registry:name: Push Docker image to Docker Hubruns-on: ubuntu-lateststeps:- name: Check out the repouses: actions/checkout@v4- name: Log in to Docker Hubuses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20awith:username: ${{ secrets.DOCKER_USERNAME }}password: ${{ secrets.DOCKER_PASSWORD }}- name: Extract metadata (tags, labels) for Dockerid: metauses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7with:images: my-docker-hub-namespace/my-docker-hub-repository- name: Build and push Docker imageuses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671with:context: .file: ./Dockerfilepush: truetags: ${{ steps.meta.outputs.tags }}labels: ${{ steps.meta.outputs.labels }} 
 
简单版 workflow
这是我自己写的 workflow 比 GitHub 提供的例子简单一些
name: Docker Image CI
run-name: ${{ github.actor }} is building a imageon: [push]jobs:build:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v3- name: Build the Docker imagerun: docker build . --file ./next-antd/AIHub.Blazor/Dockerfile --tag ${{ secrets.ALIYUN_DOCKER_REPO }}:${{ github.run_id }}- name: Login to aliyun docker repositoryrun: docker login -u ${{ secrets.ALIYUN_USERNAME }} -p ${{ secrets.ALIYUN_PWD }} ${{ secrets.ALIYUN_DOCKER_REPO }}- name: Push image to aliyun docker repositoryrun: 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 提供的命令是这样(这里只是给出例子,实际要以自己的项目配置页面为准)
# Create a folder
$ mkdir actions-runner && cd actions-runner# Download the latest runner package
$ 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
ps aux | grep run.sh
# 找到 pid 之后 kill 掉
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 吧。
https_proxy=http://proxy.local:8080
no_proxy=example.com,myserver.local:443 
 
更多关于搭建本地 runner 的文档,可以查看参考资料的第三条。
使用本地 runner 部署服务
老规矩,使用 docker-compose 来编排服务。
先创建个目录,里面存放 docker-compose.yml 和一些持久化的文件。
本例子的路径是: /home/apps/aihub
version: '3.6'services:web:image: ${IMAGE}container_name: aihub-testrestart: alwaysenvironment:- ASPNETCORE_ENVIRONMENT=Production- ASPNETCORE_URLS=http://+:80volumes:- ./aihub.app.db:/app/aihub.app.dbports:- "12002:80"networks:- default- swagnetworks:swag:name: swagexternal: truedefault:name: aihub-test 
 
镜像部分我用了环境变量,因为每次构建的镜像tag都不一样,我要在 workflow 里将 tag 写入 .env 文件。当然也可以写固定 latest 。
.env 文件是这样
IMAGE=registry.cn-hangzhou.aliyuncs.com/deali/aihub-test:6861065827 
 
OK,总算是到了最后一步,继续编辑我们的 workflow ,增加一个 deployment 任务。
name: Docker Image CI
run-name: ${{ github.actor }} is building a imageon: [push]jobs:build:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v3- name: Build the Docker imagerun: docker build . --file ./next-antd/AIHub.Blazor/Dockerfile --tag ${{ secrets.ALIYUN_DOCKER_REPO }}:${{ github.run_id }}- name: Login to aliyun docker repositoryrun: docker login -u ${{ secrets.ALIYUN_USERNAME }} -p ${{ secrets.ALIYUN_PWD }} ${{ secrets.ALIYUN_DOCKER_REPO }}- name: Push image to aliyun docker repositoryrun: docker push ${{ secrets.ALIYUN_DOCKER_REPO }}:${{ github.run_id }}deployment:runs-on: [self-hosted, linux, x64]needs: [build]steps:- name: export environment variantrun: echo 'IMAGE=${{ secrets.ALIYUN_DOCKER_REPO }}:${{ github.run_id }}' > /home/apps/aihub/.env- name: docker compose deployrun: docker compose -f /home/apps/aihub/docker-compose.yml --project-directory /home/apps/aihub up -d 
 
注意:
-  
jobs 默认是并行执行的,所以需要在 deployment 任务里加上
needs配置,等 build 完了再部署 
-  
使用
jobs.<job_id>.needs标识运行此作业之前必须成功完成的所有作业。 它可以是一个字符串,也可以是字符串数组。 如果某个作业失败或跳过,则所有需要它的作业都会被跳过,除非这些作业使用让该作业继续的条件表达式。 如果运行包含一系列相互需要的作业,则故障或跳过将从故障点或跳过点开始,应用于依赖项链中的所有作业。 如果希望某个作业在其依赖的作业未成功时也能运行,请在jobs.<job_id>.if中使用always()条件表达式。 
-  
deployment任务是在本地执行的,所以runs-on通过多个 label 选择了本地 runner 
-  
执行
docker compose命令的时候工作目录是在 GitHub Action 工具的_work目录里,所以需要指定--project-directory参数,或者通过--env-file指定.env文件位置 
查看执行结果
在 GitHub Action 页面可以查看执行结果。

搞定!
参考资料
-  
变量 - GitHub 文档
 -  
发布 Docker 映像 - GitHub 文档
 -  
关于自托管运行程序 - GitHub 文档
 -  
将自托管的运行应用程序配置为服务 - GitHub 文档
 -  
将代理服务器与自托管运行程序结合使用 - GitHub 文档
 -  
在工作流程中使用作业 - GitHub 文档
 -  
Ways to set environment variables in Compose | Docker Docs
 
文章转载自:程序设计实验室
原文链接:https://www.cnblogs.com/deali/p/17833948.html
相关文章:
持续集成指南:GitHubAction 自动构建+部署AspNetCore项目
前言 之前研究了使用 GitHub Action 自动构建和发布 nuget 包:开发现代化的.NetCore控制台程序:(4)使用GithubAction自动构建以及发布nuget包 现在更进一步,使用 GitHub Action 在其提供的 runner 里构建 docker 镜像,之后提交到阿…...
Docker 笔记(三)--容器
Docker 笔记(三)–容器 记录Docker 安装操作记录,便于查询。 参考 链接: Docker 入门到实战教程(三)镜像和容器链接: docker run中的-itd参数正确使用链接: docker官方文档链接: 阿里云Debian 镜像链接: Debian 全球镜像站链接: Debian/Ub…...
gd32关于IO引脚配置的一些问题
一、gd32f103的PA15问题 1、 #define GPIO_SWJ_NONJTRST_REMAP ((uint32_t)0x00300100U) /*!< full SWJ(JTAG-DP SW-DP),but without NJTRST */ #define GPIO_SWJ_SWDPENABLE_REMAP ((uint32_t)0x00300200U) /*!< JTAG-DP disabled and SW-DP enab…...
QT小记:警告Use multi-arg instead
"Use multi-arg instead" 是一个提示,建议使用 QObject::tr() 函数的多参数版本来处理多个占位符,而不是使用单参数版本。 在 Qt 中,tr() 是用于进行文本翻译(国际化)的函数。它允许你在应用程序中使用多种…...
皮肤性病科专家谭巍主任提出HPV转阴后饮食七点建议
HPV转阴是每一位感染者都期盼的,因为转阴所以健康,只有转为阴性才意味着不具备传染性,从此也不必再害怕将病毒传染给家人的风险,也不必再担忧持续感染而引发的健康风险。总之,HPV转阴是预示感染者恢复健康与否的主要标…...
快速弄懂C++中的智能指针
智能指针是C中的一个对象,它的行为类似于指针,但它提供了自动的内存管理功能。当智能指针超出作用域时(比如说在函数中使用智能指针指向了一个对象,当该函数结束时会自动销毁该对象),它会自动删除其所指向的…...
C#调用C++ dll教程
文章目录 一、创建C dll项目二、C#程序员调用C dll三、C与C#数据类型对应基本数据类型对应表C指针类型与C#类型 在使用C#开发客户端时,有时需要调用C dll,本篇博客来介绍C#程序如何调用C dll。 一、创建C dll项目 首先使用VS2022创建C dll项目…...
计算机毕设 深度学习 大数据 股票预测系统 - python lstm
文章目录 0 前言1 课题意义1.1 股票预测主流方法 2 什么是LSTM2.1 循环神经网络2.1 LSTM诞生 2 如何用LSTM做股票预测2.1 算法构建流程2.2 部分代码 3 实现效果3.1 数据3.2 预测结果项目运行展示开发环境数据获取 最后 0 前言 🔥 这两年开始毕业设计和毕业答辩的要…...
97.qt qml-自定义Table之实现ctrl与shift多选
我们之前实现了:93.qt qml-自定义Table优化(新增:水平拖拽/缩放自适应/选择使能/自定义委托)-CSDN博客 实现选择使能的时候,我们只能一行行去点击选中,非常麻烦,所以本章我们实现ctrl多选与shift多选、 所以在Table控件新增两个属性: 1.实现介绍 ctrl多选实现原理:当我…...
运行软件报错mfc140.dll丢失?分享mfc140.dll丢失的解决方法
小伙伴们,你是否也有过这样的经历:每当碰到诸如" mfc140.dll 丢失 "之类的烦人错误时,你是不是会一头雾水,完全不知道从何下手去解决?不要担心,接下来咱就给你提供这样一篇实用教程,教…...
milvus数据库-连接
Milvus 支持 19530 和 9091 两个端口: 端口 19530 用于 gRPC 和 RESTful API。 这是您使用不同 Milvus SDK 或 HTTP 客户端连接到 Milvus 服务器时的默认端口。 端口 9091 用于 Kubernetes 内的指标收集、pprof 分析和运行状况探测。 它用作管理端口。 1.连接到数…...
ios + vue3 Teleport + inset 兼容性问题
目录 1,问题表现2,解决步骤1,teleport 的问题2,inset 的问题3,teleport 的问题之二 1,问题表现 使用 vue3 的 Teleport 实现的 dialog 弹窗,但是在 ios app 中嵌套的 h5 中无法打开。 直接在io…...
计蒜客T1654 数列分段(C语言实现)
【题目描述】对于给定的一个长度为n的正整数数列ai,现要将其分成连续的若干段,并且每段和不超过m(可以等于m),问最少能将其分成多少段使得满足要求。 【输入格式】第一行包含两个正整数n,m,表示…...
Linux进程——system函数、popen函数
system函数(执行shell 命令) 头文件 #include <stdlib.h> 函数定义 int system(const char * string); 函数说明 system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,…...
【智能家居】5、主流程设计以及外设框架编写与测试
目录 一、主流程设计 1、工厂模式结构体定义 (1)指令工厂 inputCmd.h (2)外设工厂 controlDevices.h 二、外设框架编写 1、创建外设工厂对象bathroomLight 2、编写相关函数框架 3、将浴室灯相关操作插入外设工厂链表等待被调…...
详解ssh远程登录服务
华子目录 简介概念功能 分类文字接口图形接口 文字接口ssh连接服务器浅浅介绍一下加密技术凯撒加密加密分类对称加密非对称加密非对称加密方法(也叫公钥加密) ssh两大类认证方式:连接加密技术简介密钥解析 ssh工作过程版本协商阶段密钥和算法…...
LangChain 3使用Agent访问Wikipedia和llm-math计算狗的平均年龄
接着前两节的Langchain,继续实现Langchain中的Agent LangChain 实现给动物取名字,LangChain 2模块化prompt template并用streamlit生成网站 实现给动物取名字 代码实现 # 从langchain库中导入模块 from langchain.llms import OpenAI # 从langchain.l…...
wpf devexpress绑定grid到总计和分组统计
此主题描述了如何在gridcontrol中的视图模型和显示定义总计和分组统计 在视图模型中指定统计 1、创建 SummaryItemType 枚举你想要在GridControl中显示的统计类型: public enum SummaryItemType { Max, Count, None } 2、创建一个grid统计描述类 public class S…...
嵌入式 Linux 移植与系统启动方法
1、Linux系统启动与U-Boot 所谓移植就是把程序代码从一种运行环境转移到另一种运行环境。对于内核移植来说,主要是从一种硬件平台转移到另一种硬件平台上运行。 体系结构级别的移植是指在不同体系结构平台上Linux内核的移植,例如,在ARM、MI…...
代码随想录算法训练营|五十六天
回文子串 647. 回文子串 - 力扣(LeetCode) dp含义:表示区间内[i,j]是否有回文子串,有true,没有false。 递推公式:当s[i]和s[j]不相等,false;相等时,情况一,…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...
C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...
