.NetCore基于Jenkins和Gogs的自动化部署方案
准备工作
Jenkins和gogs的安装配置可以看前两篇:Jenkins安装、配置与说明 和 gogs安装与说明(docker)
此外,因为还要安装.net core的SDK和Git工具:
安装.net core(本文使用的3.1) : linux 部署.net core 环境
安装Git:
- # Ubuntu
- sudo apt-get install git
- # CentOS
- sudo yum install -y git
- # 配置,暂时也可以不配置
- git config --global user.name "your name"
- git config --global user.email "your email"
一、创建项目及Git仓库
首先,我们需要一个.net core项目及git仓库,以.net core的WebApi为例,创建一个WebApi项目(我使用的.net core 3.1),项目名称是DemoWebApi,添加一个简单的控制器(后面会修改这个接口来进行演示):
- [ApiController]
- [Route("[controller]")]
- public class HomeController : ControllerBase
- {
- [HttpGet]
- public string Get()
- {
- return "Hello,当前时间:" + DateTime.Now;
- }
- }
在gogs上创建一个仓库,然后创建的WebApi项目推送到gogs中的这个仓库,最后仓库大致是这样子的:
二、创建本地构建的Jenkins的任务
接下来是任务构建,如果发现自己找不到对应的设置,可能是相应的插件未安装,比如,如果没有安装Git插件,下面的源码管理中可能就没有Git源码管理,建议插件安装是推荐使用Jenkins首次启动时的推荐插件安装。
然后在【源码管理】中配置git仓库所在位置:
【构建触发器】和【构建环境】可按需要自行配置,我这里暂时不配置:
在【构建】选项卡选择自己的构建方式,比如我使用的是Ubuntu,所以我选择的是【执行shell】,也就是说构建使用执行shell脚本的方式来执行:
接下来就是一个重点了:脚本如何执行?
一般的,我们不会使用命令行直接运行项目,也就是说我们不会直接使用 dotnet XXXX.dll 的形式运行项目,理由有二:
1、没有守护进程机制,项目挂了也就挂了,不会重启
2、如果项目构建运行时阻塞了Jenkins构建进程,构建过程会一直等待,直到完成或超时,当然,我们也可以直接使用命令行在后台运行项目而不阻塞构建进程,但等Jenkins构建结束后,会kill掉构建进程及其子进程,也就是说项目所在的子进程也会被kill掉,虽然我们可以配置让项目的这个子进程不被kill,但是下次构建可能就会出现端口冲突而导致构建失败。
所以,我们可以采用守护进程来实现,比如Supervisor,服务单元,我们也可以采用docker来实现,这里以服务单元和docker来举例,Supervisor的方式类似。
首先,我们添加一个目录用来存放项目文件,同时设置它的权限:
- # 创建一个目录,存放项目文件,目录可自定义,比如我这里是/opt/demo
- sudo mkdir /opt/demo
- # 修改权限,把这个目录所有者给jenkins用户
- sudo chown -R jenkins. /opt/demo
1、如果采用服务单元,我们需要先创建一个服务单元:
- # 打开一个service文件
- sudo vim /etc/systemd/system/DemoWebApi.service
输入以下内容(根据实际项目情况填写):
- [Unit]
- Description=DemoWebApi(dotnet)
- [Install]
- WantedBy=multi-user.target
- [Service]
- User=root
- WorkingDirectory=/opt/demo
- ExecStart=/opt/dotnet-sdk-3.1.302-linux-x64/dotnet DemoWebApi.dll --urls=http://0.0.0.0:5050
- ExecReload=/bin/kill -HUP $MAINPID
- KillMode=process
- Restart=always
- RestartSec=30s
其中主要三个地方注意:Description是描述,ExecStart是启动命令,WorkingDirectory是命令执行的工作目录,命令执行前会切换到这个目录
保存退出之后,启用服务单元
- # 启用
- sudo systemctl enable DemoWebApi.service
那么我们执行的shell脚本是这样子的(根据实际项目填写):
- #!/bin/bash
- # 这里执行的shell的脚本将使用git pull下来的代码根路径作为当前工作路径来执行脚本,这个路径也就是Jenkins所指的workspace路径,这里切换到.csproj文件所在目录
- cd DemoWebApi
- # 停止服务单元
- sudo systemctl stop DemoWebApi.service
- # 使用的是dotnet 3.1,-c Release表示以Release的形式发布项目,发布失败直接退出
- /opt/dotnet-sdk-3.1.302-linux-x64/dotnet publish -c Release || exit 1
- # 删除旧发布文件
- rm -rf /opt/demo/*
- # 移动新发布文件到项目文件存放目录
- mv bin/Release/netcoreapp3.1/publish/* /opt/demo/
- # 启动服务单元
- sudo systemctl start DemoWebApi.service
2、如果使用docker容器化,我们需要安装docker,参考:docker简单安装 ,还需要.net core 运行的镜像,参考:docker构建.net core运行的镜像
使用docker构建容器化,我们可以直接使用docker命令行,也可以使用docker-compose。
如果使用docker命令行,那么只需要直接在构建脚本中实现:
- #!/bin/bash
- # 这里执行的shell的脚本将使用git pull下来的代码根路径作为当前工作路径来执行脚本,这个路径也就是Jenkins所指的workspace路径,这里切换到.csproj文件所在目录
- cd DemoWebApi
- # 停止并删除容器
- sudo docker stop DemoWebApi && sudo docker rm DemoWebApi
- # 使用的是dotnet 3.1,-c Release表示以Release的形式发布项目,发布失败直接退出
- /opt/dotnet-sdk-3.1.302-linux-x64/dotnet publish -c Release || exit 1
- # 删除旧发布文件
- rm -rf /opt/demo/*
- # 移动新发布文件到项目存放目录
- mv bin/Release/netcoreapp3.1/publish/* /opt/demo/
- # 创建并启动容器,注意,这里项目在容器中启动端口是5000,使用-p在宿主机和容器做了一个端口映射
- sudo docker run -d --name DemoWebApi -p 5050:5000 -w /opt/demo -v /opt/demo:/opt/demo dotnetcore:v3.1 dotnet DemoWebApi.dll --urls=http://0.0.0.0:5000
如果采用docker-compose,需要创建一个docker-compose.yml文件,比如我在/opt/demo目录下创建一个docker-compose.yml:
- # 创建docker-compose.yml
- sudo vim /opt/demo/docker-compose.yml
- # 修改权限,把所有者给jenkins用户
- sudo chown -R jenkins. /opt/demo/docker-compose.yml
docker-compose.yml内容如下:
- version: '2'
- services:
- api:
- image: dotnetcore:v3.1
- container_name: DemoWebApi
- volumes:
- - /opt/demo:/opt/demo
- expose:
- - 5000
- restart: always
working_dir: /opt/demo- ports:
- - 5050:5000
- command: dotnet DemoWebApi.dll --urls=http://0.0.0.0:5000
构建的脚本就是:
- #!/bin/bash
- # 这里执行的shell的脚本将使用git pull下来的代码根路径作为当前工作路径来执行脚本,这个路径也就是Jenkins所指的workspace路径,这里切换到.csproj文件所在目录
- cd DemoWebApi
- # down,--project-directory是docker-compose项目生成目录,-f是指定docker-compose.yml
- sudo docker-compose --project-directory /opt/demo -f /opt/demo/docker-compose.yml down
- # 使用的是dotnet 3.1,-c Release表示以Release的形式发布项目,发布失败直接退出
- /opt/dotnet-sdk-3.1.302-linux-x64/dotnet publish -c Release || exit 1
- # 删除旧发布文件
- find /opt/demo/* | grep -v docker-compose.yml | xargs sudo rm -rf
- # 移动新发布文件到项目存放目录
- mv bin/Release/netcoreapp3.1/publish/* /opt/demo/
- # up,--project-directory是docker-compose项目生成目录,-f是指定docker-compose.yml
- sudo docker-compose --project-directory /opt/demo -f /opt/demo/docker-compose.yml up -d
按照自己的方式选择构建方式后,我们还可以选择构建完成之后的操作,比如构建完成后发送邮件等等,不过这里我这边暂不设置:
保存后回到控制面板,可以看到我们创建的任务:
任务创建好了,就可以开始构建了,点击我们创建的任务最右边的图标立即构建一次。
构建成功后,我们可以访问我们的项目,比如我这里是一个WebApi项目,而服务器地址是192.168.209.128,那么在浏览器上输入 http://192.168.209.128:5050/Home 即可访问
接下来,我们修改上面的接口代码:
- [ApiController]
- [Route("[controller]")]
- public class HomeController : ControllerBase
- {
- [HttpGet]
- public string Get()
- {
- return "Hello,这是修改后的当前时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
- }
- }
然后使用git更新上传代码到gogs,再次点击上面的构建按钮再构建一次,成功后再访问这个接口,得到结果:
可以发现,我们的代码已经在服务器更新并发布运行了,不需要我们手动干预,这样一来,大大方便了项目的部署。
此外我们还可以查看任务状态:
任务状态大概是这样的
如果构建失败,我们可以点击构建历史记录,进入查看构建详情:
注:如果构建失败,但是我们的脚本及构建方式都没问题,可以尝试清理工作空间后重试
三、跨服务器构建部署
上面虽然完成了一个项目的构建,但是存在一个问题,那就是我们项目的构建和运行是在同一台服务器上,但是现实中往往他们是分开的,构建过程可能在本地,而程序是在远程服务器上运行。
为实现构建与部署的分离,我们可以像上面一样,在shell脚本中操作,构建完成之后,将文件打包,然后发送到远程服务器,再执行远程服务器的命令或者脚本来部署项目,事实上,我们很少这么做,因为这个写脚本的过程繁琐且不易维护,这违背了Jenkins的宗旨,可喜的是,Jenkins以插件的形式,提供了上述构建与部署分离的一个实现。
首先,我们要安装插件:Publish Over SSH
点击【系统管理】=》【插件管理】=》【可选插件】,搜索Publish Over SSH
安装完成之后,执行下面的重启一下jenkins,如果是使用服务单元启动的jenkins,则执行下面的命令重启jenkins:
- # 重启
- sudo systemctl restart jenkins.service
重启之后,在【系统管理】=》【系统配置】中就会有SSH的相关设置:
说明:
- Passphrase:私钥的秘钥,在生成SSH Key的时候可以设置一个秘钥,就是Passphrase,如果不设置,此项可以置为空
- Path to key:私钥文件的路径,可以是绝对路径,也可以是基于
$JENKINS_HOME
的相对路径- Key:私钥,也就是私钥文件的内容,Key和Path to key应该至少设置一个,如果都设置,Key将优先使用
私钥生成参考:SSH公/私秘钥的生成及使用,这里我采用的是Path to Key,生成的私钥文件默认在用户主目录下的.ssh目录中,我将它copy一份到/var/lib/jenkins/目录下,所以上面我的私钥文件路径是 /var/lib/jenkins/id_rsa 。
点击【新增】添加一个服务器连接配置:
说明:
- Name:连接名称,随便取
- Hostname:SSH连接使用的地址,可以是Hostname,也可以是IP
- Username:SSH连接使用的用户,要求将上面配置的私钥对应的公钥信息追加到这个用户所在主目录下的.ssh目录下的authorized_keys文件中,为避免出现不必要的权限问题,建议使用root用户
- Remote Directory:远程服务器上的一个目录地址,必须是已存在的,SSH连接只会将会将文件发送保存到这个目录下,同时保证上面的Username用户对这个目录有操作权限
- 高级:像端口等其它设置在高级里面
Test Configuration:测试SSH Server配置是否正确,建议配置完成后测试一遍
到这里,SSH相关配置就完成了,下面就是构建的配置了,以服务单元的形式为例。
首先,我们在远程服务器上再做一个上面介绍的服务单元。
接着,我们的项目同样采用shell脚本的形式构建:
- #!/bin/bash
- # 这里执行的shell的脚本将使用git pull下来的代码根路径作为当前工作路径来执行脚本,这个路径也就是Jenkins所指的workspace路径,这里切换到.csproj文件所在目录
- cd DemoWebApi
- # 使用的是dotnet 3.1,-c Release表示以Release的形式发布项目,发布失败直接退出
- /opt/dotnet-sdk-3.1.302-linux-x64/dotnet publish -c Release || exit 1
- # 如果上次包文件存在,则删除
- if [ -f ./publish.tar.gz ];then
- rm -f ./publish.tar.gz
- fi
- # 将发布文件打包
- tar -zcf publish.tar.gz -C bin/Release/netcoreapp3.1 publish
在安装Publish Over SSH插件之后,在【构建后操作】处就有SSH相关的操作了:
选择【构建后操作】:Send build artifacts over SSH
其中Exec command的脚本内容如下:
- #!/bin/bash
- # 注意,命令执行的目录是用户根目录,所以建议切换目录或者使用绝对路径
- cd /opt/jenkins/DemoWebApi
- # 文件解压
- tar -zxf publish.tar.gz
- # 停止服务单元
- systemctl stop DemoWebApi.service
- # 删除旧发布文件
- rm -rf /opt/demo/*
- # 移动新发布文件到项目文件存放目录
- mv /opt/jenkins/DemoWebApi/publish/* /opt/demo/
- # 启动服务单元
- systemctl start DemoWebApi.service
- # 清空当前目录文件
- rm -rf ./*
说明:
- SSH Server:即上面我们创建的服务器连接配置
- Transfer:即往SSH Server发送文件或者执行命令的设置集合set,每个set设置如下:
- Source file:要往SSH Server发送的文件,多个文件之间默认使用逗号(,)分隔,注意,这是文件不是目录,如果有多个文件及目录,可以使用tar打包,发送过去后再解压,比如我这里打包publish.tar.gz
- Remote directory:SSH Server上存放这个文件的目录,如果不存在会自动创建,注意,这个目录是相对上面【系统管理】=》【系统配置】中配置的SSH Server的Remote directory目录的,比如我这边Source files会保存在/opt/jenkins/DemoWebApi/目录下
- Remove prefix:移除前缀,一般是Source files的目录部分,比如我这里如果不设置前缀,那么我上面的Source files将会放到/opt/jenkins/DemoWebApi/DemoWebApi/目录下,因为我的Source files前面还有一节路径DemoWebApi,如果我这里设置了前缀DemoWebApi,因此会将Source files放到/opt/jenkins/DemoWebApi目录下
- Exec command:发送SSH Server执行的命令,注意,命令执行的目录是用户主目录,不是Remote directory,所以建议命令使用到的路径采用绝对路径
这样基本上就设置完成了,但是,还有一点需要补充一下,在安装Publish Over SSH插件之后,在【构建后操作】处就有SSH相关的操作:
在构建环境中可以选择在构建之前或之后往SSH Server发送文件或者执行脚本的操作,不过这里构建后往SSH Server发送文件或者执行脚本的操作类似上面【构造后操作】,不过它先于上面【构造后操作】执行。
保存退出后重新构建一次,就会发现程序在远程服务器上运行了,上面整个构建流程大致如下:
- 1、点击立即构建开始构建
- 2、Jenkins从gogs获取代码更新
- 3、执行【构建环境】中的【Send files or execute commands over SSH before the build starts】操作(这里没使用到)
- 4、执行【构建】,即执行shell脚本,我这里是发布项目,并将发布文件打包成tar包
- 5、执行【构建环境】中的【Send files or execute commands over SSH after the build runs】操作(这里没使用到)
- 6、执行【构建后操作】,我使用的是【Send build artifacts over SSH】,先发送Source files,然后执行Command脚本,脚本内容就是解压,并将发布文件更新,再重新启动服务
- 7、构建完成
四、使用WebHook自动构建部署
上面都是我们手动去点击立即构建才开始一次构建,我们也可以在【构建触发器】中使用其它的方式去自动构建,比如使用定时构建:
不过这里要说的是使用WebHook来自动构建,也就是说当提交代码后,自动触发构建一次。这里使用的是gogs的WebHook,当然也可以是Gitee等其他平台。
首先,我们需要安装Generic Webhook Trigger插件:
安装之后,在【构建触发器】中就会有Generic Webhook Trigger选项
勾选后保存,然后在Token栏中输入认证(随便写):
另外,Generic Webhook Trigger还有很多其他的选项,像Parameter、过滤器等等,感兴趣的可以自己操作试一下,这里就不单独介绍了。
保存之后,我们打开gogs中项目的【仓库设置】=》【管理Web钩子】,添加钩子时选择【Gogs】
推送地址格式:http(s)://<你的Jenkins地址>/generic-webhook-trigger/invoke?token=<你的token>
添加完成之后保存。接着修改接口:
- [ApiController]
- [Route("[controller]")]
- public class HomeController : ControllerBase
- {
- [HttpGet]
- public string Get()
- {
- return "Hello,这是本次修改后将自动构建,当前时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
- }
- }
接着使用git将代码push之后,在查看Jenkins构建记录,会发现自动生成构建了一次,如果访问接口,显示:
这下子都不用自己去点击构建按钮了!!!
五、总结
虽然这里是根据Jenkins和Gogs对.net core进行自动化部署来解释说明,但是重点还是Jenkins,能理解活用就可以了,比如上面自动构建过程,gogs的钩子推送消息到Jenkins,而Jenkins又从gogs获取代码更新,那是不是说gogs和Jenkins要部署在同一网络下,让他们可以互通呢?其实不是的,我们可以让Jenkins可以直接访问gogs,但是gogs推送消息到Jenkins仅仅只是一个http请求,我们完全可以在它们之间做一层反向代理来实现。Jenkins还有很多功能,要在使用过程中慢慢了解了。
.NetCore基于Jenkins和Gogs的自动化部署方案的更多相关文章
- 基于Jenkins,docker实现自动化部署(持续交互)
前言 随着业务的增长,需求也开始增多,每个需求的大小,开发周期,发布时间都不一致.基于微服务的系统架构,功能的叠加,对应的服务的数量也在增加,大小功能的快速迭代,更加要求部署的快速化,智能化.因此 ...
- 基于Jenkins,docker实现自动化部署(持续交互)【转】
前言 随着业务的增长,需求也开始增多,每个需求的大小,开发周期,发布时间都不一致.基于微服务的系统架构,功能的叠加,对应的服务的数量也在增加,大小功能的快速迭代,更加要求部署的快速化,智能化.因此 ...
- node项目自动化部署--基于Jenkins,Docker,Github(3)自动化部署
GitHub仓库 由于现在的代码基本上都是多人合作开发,所以肯定会用到像 git 这样的版本控制工具 所以这里使用 GitHub 来做一个演示 首先我们需要在github上新建一个仓库 点击New来新 ...
- .NET持续集成与自动化部署之路第一篇——半天搭建你的Jenkins持续集成与自动化部署系统
.NET持续集成与自动化部署之路第一篇(半天搭建你的Jenkins持续集成与自动化部署系统) 前言 相信每一位程序员都经历过深夜加班上线的痛苦!而作为一个加班上线如家常便饭的码农,更是深感其痛 ...
- 基于云原生DevOps服务自动化部署前端项目学习总结
本文主要以部署前端Vue项目为例,讲述了如何基于云原生DevOps服务自动化部署前端项目~从开发完成到线上环境,我们只需提交代码即可~ 一.引言 作为一名开发人员,日常工作中我们除了需要负责代码的开发 ...
- jenkins+git+maven搭建自动化部署项目环境
简介 折腾了两个晚上,趁着今晚比较有空,把jenkins+git+maven搭建自动化部署项目环境搭建的过程记录一下,这里我把github作为git的远程仓库(https://github.co ...
- Jenkins+SVN+Maven+shell 自动化部署实践
JAVA环境中利用Jenkins+svn+maven进行自动化部署实践 一. 前言2 1.介绍jenkins2 1.本地项目打包2 2.通过secureCRT工具,手动传输到服务器2 3.然后 ...
- 基于 Node.js 的服务器自动化部署搭建实录
基于 Node.js 的服务器自动化部署搭建实录 在服务器上安装 Node.js 编写拉取仓库.重启服务器脚本 配置 Github 仓库的 Webhook 设置 配置 Node.js 脚本 其他问题 ...
- 自动化部署方案CICD
自动化部署方案 由于来来也的时间不久,可能对现有的部署情况不是很了解,以下是个人对POC自动化部署的设计方案. 自动化部署优点 降低成本,提高生产力,高可用,更可靠,性能优化 与gitlab持 ...
随机推荐
- android知识点duplicateParentState
android知识点duplicateParentState 今天要做一个效果,组件RelativeLayout上有两个TextView,这两个TextView具有不同的颜色值,现在要的效果是,当Re ...
- jenkins+Gitlab安装及初步使用
安装包下载地址:https://packages.gitlab.com/gitlab/gitlab gitlab-cerpm 包国内下载地址: https://mirrors.tuna.tsinghu ...
- layui 弹窗中 分页展示table
1. 需求:点击查看更多,展示该类别 所有数据,并分页 2. 参考文档: (1)https://www.jianshu.com/p/40da11ebae66 (2) https://blog.csdn ...
- 【编程思想】【设计模式】【行为模式Behavioral】观察者模式Observer
Python转载版 https://github.com/faif/python-patterns/blob/master/behavioral/observer.py #!/usr/bin/env ...
- Linux:expr、let、for、while、until、shift、if、case、break、continue、函数、select
1.expr计算整数变量值 格式 :expr arg 例子:计算(2+3)×4的值 1.分步计算,即先计算2+3,再对其和乘4 s=`expr 2 + 3` expr $s \* 4 2.一步完成计算 ...
- 阿里云esc 安装 mysql5.7.27
1. 下载: wget http://repo.mysql.com/mysql57-community-release-el7-10.noarch.rpm 2. 安装: (1) yum -y in ...
- String 、StringBuffer、StringBuilder的区别
String:字符串常量 StringBuffer:字符串变量:线程安全的 StringBuilder:字符串变量:线程非安全的 三者执行速度比较:StringBuilder > String ...
- [源码解析] PyTorch 分布式(15) --- 使用分布式 RPC 框架实现参数服务器
[源码解析] PyTorch 分布式(15) --- 使用分布式 RPC 框架实现参数服务器 目录 [源码解析] PyTorch 分布式(15) --- 使用分布式 RPC 框架实现参数服务器 0x0 ...
- centos部署代码仓库gitlab
目录 一.简介 二.程序部署 部署gitlab 汉化gitlab 三.设置管理员密码 网页方式 指令方式 一.简介 GitLab是一个利用 Ruby on Rails 开发的开源应用程序,实现一个自托 ...
- Python用pandas获取Excel数据
import pandas as pd df1 = pd.DataFrame(pd.read_excel(r'C:\python测试文件\我的三国啊.xlsx',sheet_name='Sheet1' ...