1.背景

我之前写了篇CICD项目实践的文章,但是那会是比较简单的探索和实操,也并没有涉及到k8s和docker容器,距离真正的CICD生产模式还是有点差距的,所以这次花了几天时间来操作和反复测试,终于梳理总结出这篇文章。本文主要介绍了在Centos7.9下基于.Net 8.0、GitLab、Jenkins、k8s、docker搭建CI/CD,实现自动发布.Net 8.0 WebAPI到k8s集群,并支持代码更新后的自动发布。
 

2.知识储备

2.1 CI/CD概念

CI/CD就是持续集成,持续交互。简单理解就是项目自动化,解放手工操作。将项目自动编译,自动发布,自动执行。这里的项目,我们定义为.NET Web API 8.0;

​2.2 CI/CD架构

下面是1个完整的CI/CD架构图:

2.3 CI/CD环境准备

2.3.1 机器准备

准备3台虚拟机如下,版本centos 7.9

IP

机器名称

配置
192.168.126.194lmaster硬盘40GB,内存2GB
192.168.126.195lnode1硬盘80GB,内存4GB
192.168.126.196

lnode2

硬盘40GB,内存8GB

2.3.2 源代码准备

新增 .NET Web API 8.0项目:K8s_CICD

新增K8s_CICDController,代码如下

using Microsoft.AspNetCore.Mvc;

namespace K8s_CICD.Controllers
{
    [ApiController]
    [Route("[controller]/[action]")]
    public class K8s_CICDController : ControllerBase
    {
        private readonly ILogger<WeatherForecastController> _logger;

        public K8s_CICDController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }


        [HttpGet(Name = "GetK8sCICD")]
        public string GetK8sCICD()
        {
            return $"K8s CI/CD部署成功:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}";
        }


    }
}

2.3.3 k8s集群搭建

这个过程可以参考这篇文章,我是用它来搭建k8s集群。此处就不再重复介绍了。

2.3.4 Jenkins安装

在k8s从节点-lnode1机器上安装Jenkins。按照下面命令去执行

wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo;
rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io-2023.key

# 安装 java
yum install -y fontconfig java-11-openjdk

# 检查 java 版本
java -version


# 使用 wget 下载 Jenkins 软件包的存储库配置文件,并将其保存到 /etc/yum.repos.d/jenkins.repo 文件中
# 证书过期,不检查证书:sudo wget --no-check-certificate -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo

sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo

# 使用 rpm 导入 Jenkins 软件包的 GPG 密钥,以确保安装的软件包是经过验证的,并且没有被篡改过
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key

# 安装 EPEL 的发行包,通过安装 EPEL 发行包,您可以访问一些常用的第三方软件包
yum install epel-release

# 使用 yum 安装 Jenkins 软件包
yum install -y jenkins

#给jenkins加docker 组
sudo usermod -aG docker jenkins


systemctl enable jenkins
systemctl start jenkins

下面打开地址http://192.168.126.195:8080/,访问下Jenkins

在k8s从结点lnode1,输入下列命令,查看密码

#查看初始密码
 cat /var/lib/jenkins/secrets/initialAdminPassword

按照下面操作:安装推荐的插件

等待几分钟后,就安装完毕了,如下图:

按照下图创建用户

用户:admin
密码:12345678

2.3.5 Jenkins访问K8s

这一步是专门用来设置k8s从节点也能执行kubectl命令,并且安装在k8s从节点上的Jenkins能使用shell命令去执行kubectl。

1.配置从节点机器lnode1 执行kubectl

在k8s主节点lmaster机器上,输入下面的命令,并根据提示输入账号和密码

scp /etc/kubernetes/admin.conf root@lnode1:/etc/kubernetes/

scp /etc/kubernetes/admin.conf root@lnode2:/etc/kubernetes/

在k8s从节点lnode1机器上,输入下面的命令

echo "export KUBECONFIG=/etc/kubernetes/admin.conf"  >> ~/.bash_profile

# 永久生效,执行kubeadm reset后再次init也无需再次执行这条命令
source ~/.bash_profile 

# 执行永久生效命令之后需要source一下使其生效
echo $KUBECONFIG 

在k8s从节点lnode1机器上,输入下面的命令来验证下效果

kubectl get nodes

从上图可以看到,本次操作成功,从结点lnode1可以执行kubectl命令。

2.配置Jenkins在shell脚本中可以 执行kubectl

在k8s从节点lnode1机器上,输入下面的命令

#从结点 执行
mkdir /var/lib/jenkins/.kube

在k8s主节点lmaster机器上,输入下面的命令,并根据提示输入账号和密码

#主节点执行
scp /root/.kube/config root@lnode1:/var/lib/jenkins/.kube

在k8s从节点lnode1机器上,输入下面的命令

sudo chown jenkins  /var/lib/jenkins/.kube/config

2.3.5 Net 8.0框架安装

在k8s从节点lnode1机器上安装.Net8.0框架。

安装过程可以参考这篇文章

2.3.6 GitLab安装

在k8s从节点lnode2机器上安装GitLab。

输入下面的命令

mkdir -p /usr/local/gitlab
cd /usr/local/gitlab
wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-14.9.1-ce.0.el7.x86_64.rpm

rpm -ivh gitlab-ce-14.9.1-ce.0.el7.x86_64.rpm

执行下面命令,修改 GitLab对外提供服务的ip端口: 

vim /etc/gitlab/gitlab.rb

修改external_url 为如下:

external_url   'http://192.168.126.196:8848' 

注意:192.168.126.196为K8s从节点lnode2的ip,这个要根据实际ip去修改;端口8848是自定义,随意取。

然后,执行下面命令,重启下Jenkins

gitlab-ctl reconfigure

gitlab-ctl start

在等待10+分钟后,执行完毕如下所示:

打开地址:http://192.168.126.196:8848 ,访问GitLab如下所示:

在k8s从结点lnode2使用下面命令,查看原始密码

cat /etc/gitlab/initial_root_password

所以,用下面账号密码来登录Gitlab

账号:root
密码:xbM27BZDL2+6rx4dgykL55xaf1QgkiaQXDpENFpC0k8=

接下来,修改下Gitlab用户root密码为 12345678,方便后面操作


那么Gitlab用户信息如下:

用户:root

密码 :12345678

2.4 CI/CD架构实战

2.4.1 创建GitLab项目

访问GitLab地址:http://192.168.126.196:8848 ,并按照下列新增项目K8s_CICD

并按照下图操作,拿到该项目的地址,后面会用到

该项目的地址如下:

SSH:  git@192.168.126.196:root/k8s_cicd.git
HTTP:  http://192.168.126.196:8848/root/k8s_cicd.git

2.4.2 源代码上传

将2.3.2创建的项目的源代码,上传到k8s从节点lnode2的目录/opt

在K8s从节点lnode2输入下面的命令,去提交刚刚拷贝过来的项目

git config  --global user.name "Administrator"
git config  --global user.email "admin@example.com"

#在已经存在的目录去初始化仓库
cd K8s_CICD

git init

git remote add origin http://192.168.126.196:8848/root/k8s_cicd.git

git add .

git commit -m "Initial commit"

git push -u origin master


打开GitLab后,发现项目上传成功

注意:我们上传的是master分支,一般是当做主分支使用的。这里我们可以将master按照下图操作设置为默认分支。

2.4.3 创建Jenkins Job

这个过程主要是介绍在k8s从结点lnode1.执行命令,拿到公钥,并部署到Jenkins凭证

ssh-keygen  -t rsa

执行下面命令,拿到公钥A:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC97Ha1zHcD4bOe/gh11BRc61bOGUAW/gZjTUTuB9z0eUz+DGXBBj9Moa8AorOqR5u1CIu7YDjFHCPr2wXM9cLNs6pmg5YB4/lNZS56wAKEJqPjb0sKe8bU7KyQ1rmfcKZ1KHyK8Z1BJJ2z+gXsKOM0YaPwcLwVmhS3uFsoEsmn9kKBdbk94m+/EO9qrEJOY3Ea20Q6e/9VyAD7ua/XYf0PA7YHwEw/oI69Dk7Eo5mpfFycID9Qu8oJdSD+PyWioC3io3a8YDoPQgtsjJlc9BFerTnE+LxRipcqIQOxz1hfgSFwC9WPdkeGVh6lCgZvP2KBbFE2W4wmN6V1z+8E8SP9 root@lnode1
#公钥,部署在gitlab:SSH Key
 cat /root/.ssh/id_rsa.pub

执行下面命令,拿到私钥B:

-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAvex2tcx3A+Gznv4IddQUXOtWzhlAFv4GY01E7gfc9HlM/gxl
wQY/TKGvAKKzqkebtQiLu2A4xRwj69sFzPXCzbOqZoOWAeP5TWUuesAChCaj429L
CnvG1OyskNa5n3CmdSh8ivGdQSSds/oF7CjjNGGj8HC8FZoUt7hbKBLJp/ZCgXW5
PeJvvxDvaqxCTmNxGttEOnv/VcgA+7mv12H9DwO2B8BMP6COvQ5OxKOZqXxcnCA/
ULvKCXUg/j8loqAt4qN2vGA6D0ILbIyZXPQRXq05xPi8UYqXKiEDsc9YX4EhcAvV
j3ZHhlYepQoGbz9igWxRNluMJjeldc/vBPEj/QIDAQABAoIBAE7eNkGyga3T+TJK
DZtYkYgwlmCJrcqefGqaOMib7U58XNOWtF6eyIR7E+AwsGlCyU85GEWcZJa949Da
qCL/34BqXpWpiQ6J7AoOvWlt+N2F6kLVAZV95wieq96NvJGQRx+Zy3YrdYEKwo5t
gi4aoJctANYlCoXx8S6F2RzgCGu9qWetwiBvphAxPRBDGwdRlNmDfEeGZDqC65o1
7sHSF2CuypSsQwqvakVLv9MA4Snrh8A/w3jUtrMJPcjSfmf1Nr/zkucZaJJc8JU+
3eHu7+NfHb+3IJTkNYYeM5SrTLm1LdMxdtu4pcFo07z2nbSCkDJFlNamBhlr7SVJ
beGfhSECgYEA6GIY90Q3Pdi/DLBcEJcs/8bsJcwI7JNoSzdfSgy5dJ1nPhags3r0
C8fZWAFwcI+Nqdu+5+IqgoT20BPKPki6VBGd1DHoa+UoKatVXdLAZqE8PIRKHihP
pPxpXiFK8/U0BNP6BZHVQ7a9ZttKL6iqFXzhQztD6mCrrM2Fpf6aE3kCgYEA0Tmy
/8F+qNQbG9b+CM/Xvr48EQ4hFn6d7I8gK9Sj3/b3dxwYGjZxL0eW6dl/CE1tSSCJ
8WSmtkN3YC6fnejmdKNGWBmuIaP8mYUYFhDgowOpUvn0iLuSAmbf0zdCX4h84fv+
wRbHA1I9MMcHDMSuOL0cmf7dmuj7KT/wBw5Sj6UCgYEAwSfY7J6s9CFXG+rze27N
HoVwADLKMCqOhAawk9JjzISRLlCMnuLSO4CQLdB0b3tDGy7mTcP15aszo9zvPDoj
doF2GMyrDhPaAFjDiksFVckrUnn7SXnkSZTs2CsALCtiY6j2pu6Cv9gDMp2P2nFt
fpLggouedhCIYggq0MEBvLECgYEApc+WXj4YhO/jtAKEPLOLBW156QJLkqoxueIL
2vCgFsSAhfLL3yo6NQAFR7rIg+norEWPTLE5tcRt/Nm2QczrppAnFXb0m1B8xaXG
2uXxQP+L12ikNSCBrEmfJKLshQ2D+wxcbuYAPk+Uku2IVsQgVnL5Ecn8EeKF+cDk
FpNxNskCgYEAmOswsCSYA+RbXTnmIeJv5fJtETtnKAZmwpof6TZfLo9PywI17gEl
cJRQHwnA9wcRcF9TZx4JppBUut2vq1xgmWjQeYZHgW9kj2lyRpY0wU6WJxSrji8g
nZYwCDSb8MDuNwgt63T8Lnlzls1hi9Jg7PQLMt3MaaqSKQOb63T98vs=
-----END RSA PRIVATE KEY-----
 cat /root/.ssh/id_rsa

访问Jenkins地址:http://192.168.126.195:8080/ 

按照下面操作去Jenkins新增凭证

按照下面操作去GitLab新增SSH Keys

按照如下操作创建Job:K8sCICD

将下列命令,如下图填入,并点击 保存:

#!/bin/sh -l
echo '开始发布.net 8.0项目'
cd K8s_CICD
dotnet restore
dotnet build
dotnet publish --framework net8.0 --runtime linux-x64   --no-dependencies

2.4.4 执行Jenkins Job

从上图发现 执行Job失败了,我们打开下执行的详情。

这里,我是怎么做的了?

我删除该Jenkins Job,重启机器lnode1和lnode2,重新配置了GitLab的SSH Keys 和Jenkins的凭证。按照步骤2.4.3重新来一遍,问题解决。

到这里,Jenkins 就能自动编译,并发布.Net 8.0项目。

2.4.5 手动部署K8s Deployment

2.4.4步骤拿到了.Net 8.0项目的发布文件,对于项目的部署,我们需要先手动部署到k8s集群.这样后续Jenkins直接更新Deployment镜像,就能实现升级发布的效果。

在k8s从节点机器lnode1,按照下面命令去操作

cd /var/lib/jenkins/workspace/K8sCICD/K8s_CICD/bin/Release/net8.0/linux-x64/

输入下列命令,创建Dockerfile

vim   Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0.0
WORKDIR /publish
EXPOSE 80
EXPOSE 443
coPY publish/ /publish
ENV ASPNETCORE_URLS http://+:80
ENTRYPOINT ["dotnet","K8s_CICD.dll"]

接下来按照如下操作,去生成docker镜像,并将镜像推送到阿里云个人镜像仓库;

阿里云镜像仓库怎么使用,比较简单,可以自行百度 。

cd /var/lib/jenkins/workspace/K8sCICD/K8s_CICD/bin/Release/net8.0/linux-x64/
docker build -f Dockerfile -t k8scicd:v1 .
docker login --username=xxxxx registry.cn-hangzhou.aliyuncs.com  --password=*****
docker tag k8scicd:v1 registry.cn-hangzhou.aliyuncs.com/zzz/k8scicd:v1
docker push registry.cn-hangzhou.aliyuncs.com/zzz/k8scicd:v1

登录阿里云个人镜像仓库,查看刚刚推送的dokcer镜像

接下来,按照下面命令,去构建k8s Deployment

cd /root
kubectl create deployment k8scicd --image=registry.cn-hangzhou.aliyuncs.com/zzz/k8scicd:v1 --port=80 --replicas=1 -n default --dry-run=client -o yaml > k8scicd-deployment.yaml
kubectl create -f  k8scicd-deployment.yaml --record     
kubectl expose deployment k8scicd --port=80 --type=NodePort
kubectl get pod,svc

通过上图可以看到,我们部署.NET 8.0 Web API项目的服务已经构建成功,这个项目对外的地址是:

        http://192.168.126.194:32052/K8s_CICD/GetK8sCICD

        http://192.168.126.195:32052/K8s_CICD/GetK8sCICD

        http://192.168.126.196:32052/K8s_CICD/GetK8sCICD


 

2.4.6 编辑Jenkins Job

.NET 8.0 Web API项目已经部署成功。我们需要修改Jenkins Job让它支持项目发布后,自动生成docker镜像,推送镜像到阿里云,变更K8s集群的k8scicd的镜像版本为刚刚推送的镜像,这样版本就实现了升级更新。

按照下图去修改Build Steps--Excute Shell,并保存


#!/bin/sh -l
echo '开始发布.net 8.0项目'
cd K8s_CICD
dotnet restore
dotnet build
dotnet publish --framework net8.0 --runtime linux-x64   --no-dependencies
echo '发布.net 8.0项目-成功'
echo '开始拷贝.net 8.0项目到k8s机器,打包docker镜像'
cd /var/lib/jenkins/workspace/K8sCICD/K8s_CICD/bin/Release/net8.0/linux-x64/
docker build -f Dockerfile -t k8scicd:v$BUILD_ID .
echo '拷贝.net 8.0项目到k8s机器-成功,打包docker镜像-成功'
echo "开始登录阿⾥云镜像仓库,推送镜像"
docker login --username=xxxxx  registry.cn-hangzhou.aliyuncs.com  --password=*****
docker tag k8scicd:v$BUILD_ID registry.cn-hangzhou.aliyuncs.com/zzz/k8scicd:v$BUILD_ID
docker push registry.cn-hangzhou.aliyuncs.com/zzz/k8scicd:v$BUILD_ID
echo "登录阿⾥云镜像仓库-成功,推送镜像-成功"
echo "开始修改k8s机器的镜像"
kubectl  set image deployment/k8scicd  k8scicd=registry.cn-hangzhou.aliyuncs.com/zzz/k8scicd:v$BUILD_ID

echo "修改k8s机器的镜像-成功"

重新执行下 Jenkins  Job:K8sCICD 试试。

查看.NET 8.0 WEB API是不是正常访问?

检查k8s 镜像记录

 kubectl rollout history deployment k8scicd

 kubectl rollout history deployment k8scicd --revision=2

从上面可以看到 镜像更新也是对的,是刚刚最新的镜像。

2.4.7 更新源代码

目标:代码修改后,提交到分支,需要触发CI/CD。

思路:通过 webhook触发jenkins构建:自动拉取代码,编译,发布,运行项目。

在Jenkins 安装插件:Generic Webhook Trigger、GitLab

上面2个插件安装成功后,就能在Installed plugins看到。

接下来,正式配置GitLab提交分支后 触发Jenkins执行Job

在Jenkins按照如下配置,拿到web hook地址:http://192.168.126.195:8080/project/K8sCICD

秘钥:073fbf97008038bef38ac7cc9d8b23d2

在GitLab按照如下去配置,实现本地网络通讯

打开具体项目去配置webhook链接。按下图操作

按照下面的操作,输入web hook地址:http://192.168.126.195:8080/project/K8sCICD

密钥:073fbf97008038bef38ac7cc9d8b23d2

最后点击  Add webhook

在k8s从节点lnode2,按照如下去修改代码,提交到master分支

cd /opt/K8s_CICD/K8s_CICD/Controllers/

通过命令修改  K8s_CICDController.cs

vim K8s_CICDController.cs

这里,修改下返回的 提示信息,加了个版本v3,方便在页面上看到差异,就能知道代码有修改,发布了新版本。

按照下面的命令,提交代码到分支。

git add .

git commit -m "v3 modify"

git push -u origin master

这个时候,看下Jenkins,发现Job已经被触发执行了

查看.NET 8.0 Web API是不是正常访问?页面是不是修改后的效果?

从上图可以看出,修改代码后的发布是成功的,页面是最新版本。

3.结束

本文是对CI/CD比较深入的一次探索,基本复刻了生产环境的流程模式。即便是使用商业产品腾讯Coding,它底层的原理也是类似的。在日常工作中,其实不需要程序员去搭建,运维工程师就搞定了。但对于我,为了多接触点K8s的落地应用,我实操了下,基本掌握了基于K8s的CICD,K8s对于我也没那么陌生了。

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐