2

环境说明

PS:本文档实验过程中并没有对权限做出严格约束,比如直接在jenkins存放管理员的kubeconfig文件、直接在jenkins用集群管理员角色对接k8s集群等操作,均有很大风险,需要根据实际情况约束相应用户的权限。

规划设计:

角色地址域名
master192.168.10.100
node192.168.10.101
gitlab192.168.10.110
jenkins192.168.10.111jenkins.snow.com
harbor192.168.10.112harbor.snow.com

实验之前集群已经搭建完毕,搭建教程可参考构建高可用k8s集群,jenkins与gitlab分别使用安装包的方式安装在两台虚拟机上。harbor以容器的方式单独部署在一台虚拟机。

策略设计

k8s集群内的pro名称空间模拟生产环境,dev名称空间模拟开发环境,开发环境下的代码只要推送到代码仓库会触发jenkins自动发布到dev名称空间的对应POD,pro名称空间的POD只有管理员手动按选定的tag构建出来的版本才可以发布到k8s环境。

添加kubelet认证,让jenkins可以有操作k8s集群的权限

在Harbor仓库分别添加两个新的项目,项目名分别为pro和dev,用来存放生产和测试的镜像。为了实验方便将项目都配置为了公开模式,如果想要配置为私密模式则需要添加仓库的认证信息,具体参考文章:[docker配置https加密对接k8s]
image.png
将master节点的.kube文件和kubectl命令发送到jenkins所在的节点

root@master01:~# which kubectl
/opt/kube/bin/kubectl
root@master01:~# scp /opt/kube/bin/kubectl 192.168.10.111:/usr/local/bin/kubectl
root@192.168.10.111's password: 
kubectl                                                                                                                                              100%   45MB  29.0MB/s   00:01    
root@master01:~# scp -r .kube 192.168.10.111:/root/.kube
root@192.168.10.111's password: 
config                                                                                                                                               100% 6241     1.9MB/s   00:00    
9f754ca1a0545e7b871b81c83a185054                                                                                                                     100% 2460     1.6MB/s   00:00    
c4f8f2c14858bcf309490b8356533dde                                                                                                                     100%  642   219.8KB/s   00:00   

在jenkins验证是否有操作k8s集群的权限

root@jenkins:~# kubectl get no
NAME             STATUS   ROLES    AGE     VERSION
192.168.10.100   Ready    master   5d22h   v1.22.2
192.168.10.101   Ready    node     5d22h   v1.22.2

如果执行get node的时候报错网络超时需要检查.kube/config文件中的server字段是否指定的是apiserver的地址及apiserver的6443端口是否监听在127.0.0.1地址。在jenkins添加访问k8s集群的凭证登录jenkins后选择Dashboard->系统管理->凭据->系统->全局凭据,点击右上角创建一个新的凭据。

image.png

类型选择X.509 Client Certficate,Client Key字段内容填写.kube/config文件中的client-key-data字段数据base64解码后的值。Client Certificate字段填写.kube/config文件中的client-certificate-data字段数据base64解码后的值,Server CA Certificate字段填写.kube/config文件中的certificate-authority-data字段数据base64解码后的值。

image.png

添加gitlab认证,让jenkins可以有拉取代码的权限

继续按照上一步的操作新添加一个凭证

image.png

创建新仓库,分别创建main与dev分支并推送到gitlab。

在gitlab新建一个空白项目

image.png

在master节点使用git命令创建分支并将代码推送到gitlab

root@master01:~/dev/httpserver# git init 
Initialized empty Git repository in /root/dev/httpserver/.git/
root@master01:~/dev/httpserver# git remote add origin http://192.168.10.110/root/helloserver.git
root@master01:~/dev/httpserver# git checkout -b main
Switched to a new branch 'main'

准备提前写好的Dockerfile文件与测试代码。PS:这里的dockerfile写的很烂,只是能用。

root@master01:~/dev/httpserver# ls
Dockerfile  go.mod  main.go
root@master01:~/dev/httpserver# cat Dockerfile 
FROM golang:latest
ADD . /
WORKDIR /
RUN go build -o main.exe
EXPOSE 80
ENTRYPOINT ["./main.exe"]
root@master01:~/dev/httpserver# cat main.go 
package main

import (
    "net/http"
)
func main() {
    http.HandleFunc("/", func(resp http.ResponseWriter, req *http.Request) {
        resp.Write([]byte("Version=1.0"))
    })
    http.ListenAndServe(":80", nil)
}

将main分支的代码推送到仓库

root@master01:~/dev/httpserver# git add .
root@master01:~/dev/httpserver# git status
On branch main

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
    new file:   Dockerfile
    new file:   go.mod
    new file:   main.go

root@master01:~/dev/httpserver# git commit -m "v1.0"
[main (root-commit) 3b5d105] v1.0
 3 files changed, 21 insertions(+)
 create mode 100644 Dockerfile
 create mode 100644 go.mod
 create mode 100644 main.go
root@master01:~/dev/httpserver# git tag v1.0
root@master01:~/dev/httpserver# git push --tags
Username for 'http://192.168.10.110': root
Password for 'http://root@192.168.10.110': 
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 2 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 584 bytes | 584.00 KiB/s, done.
Total 5 (delta 0), reused 0 (delta 0)
To http://192.168.10.110/root/helloserver.git
 * [new tag]         v1.0 -> v1.0
#将主分支的代码推送到仓库,在操作的时候有点失误,最后强制合并的。
root@master01:~/dev/httpserver# git pull --allow-unrelated-histories origin main
Username for 'http://192.168.10.110': root
Password for 'http://root@192.168.10.110': 
From http://192.168.10.110/root/helloserver
 * branch            main       -> FETCH_HEAD
hint: Waiting for your editor to close the file... 
  GNU nano 4.8                           /root/dev/httpserver/.git/MERGE_MSG                                     
Merge branch 'main' of http://192.168.10.110/root/helloserver into main
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
Merge made by the 'recursive' strategy.
 README.md | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)
 create mode 100644 README.md
root@master01:~/dev/httpserver# 
root@master01:~/dev/httpserver# git push -u origin main
Username for 'http://192.168.10.110': root
Password for 'http://root@192.168.10.110': 
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 2 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 402 bytes | 402.00 KiB/s, done.
Total 2 (delta 0), reused 0 (delta 0)
To http://192.168.10.110/root/helloserver.git
   924f2d2..eeb98b1  main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.

在Gitlab查看推送到主分支的代码

image.png

创建开发分支,并将开发分支推送到Gitlab

root@master01:~/dev/httpserver# git checkout -b dev
Switched to a new branch 'dev'
root@master01:~/dev/httpserver# git add .
root@master01:~/dev/httpserver# git commit -m "v1.0"
On branch dev
nothing to commit, working tree clean
root@master01:~/dev/httpserver# git tag v1.0
fatal: tag 'v1.0' already exists
root@master01:~/dev/httpserver# git push -u origin dev
Username for 'http://192.168.10.110': root
Password for 'http://root@192.168.10.110': 
Total 0 (delta 0), reused 0 (delta 0)
remote: 
remote: To create a merge request for dev, visit:
remote:   http://gitlab.example.com/root/helloserver/-/merge_requests/new?merge_request%5Bsource_branch%5D=dev
remote: 
To http://192.168.10.110/root/helloserver.git
 * [new branch]      dev -> dev
Branch 'dev' set up to track remote branch 'dev' from 'origin'.

推送完成后发现已经多了一个名字为dev的分支

image.png

设置生产环境需要指定tag版本发布。

在jenkins创建一个自由风格的任务

image.png

配置参数化构建信息

image.png

在源码管理位置配置gitlab仓库信息,注意需要选择之前创建的认证信息,不然会报权限不足。

image.png

在构建环境位置选择Setup Kubernetes CLI (kubectl),并配置集群相关信息,此处的certificate配置的数据为.kube/config文件中certificate-authority-data字段的值经过base64解码后的值。凭据选择之前创建的有操作k8s集群权限的凭据。

image.png

配置更新镜像需要执行的shell命令。已经在每台主机配置了将harbor.snow.com解析为镜像仓库地址的条目,所以此处直接写了域名。

image.png

配置完成后单击保存,点击参数化构建可以看到之前推送到Gitlab仓库的代码的tag,根据tag去拉取代码。

image.png

在k8s提前使用yaml文件创建出业务deployment控制器,将生产相关代码创建在pro名称空间。对其进行版本更新的操作就是对yaml文件中image字段的更新。

root@master01:~/pod# kubectl create ns pro
namespace/pro created
root@master01:~/pod# cat httpserver.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpserver
spec:
  replicas: 3
  selector:
    matchLabels:
      run: httpserver
  template:
    metadata:
      labels:
        run: httpserver
    spec:
      containers:
        - name: httpserver
          image: nginx
          imagePullPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  name: httpserver-service
spec:
  type: NodePort
  selector:
    run: httpserver
  ports:
    - port: 80
      targetPort: 80

root@master01:~/pod# kubectl apply -f . -n pro
deployment.apps/httpserver created
service/httpserver-service created

配置完成后在jenkins点击参数化构建,选择v1.0版本进行构建。

image.png

构建过程可以在控制台输出位置看到

image.png

现在去k8s访问业务代码的地址查看其版本。

image.png

现在使用git命令将v2.0版本推送到代码仓库,2.0版本只是在main.go文件中将版本号更改为2.0.以下是手动改完版本后的操作。

root@master01:~/dev/httpserver# git status
On branch main
Your branch is up to date with 'origin/main'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   main.go

no changes added to commit (use "git add" and/or "git commit -a")
root@master01:~/dev/httpserver# git add .
root@master01:~/dev/httpserver# git commit -m "v2.0"
[main 3c7199e] v2.0
 1 file changed, 1 insertion(+), 1 deletion(-)
root@master01:~/dev/httpserver# git tag v2.0
root@master01:~/dev/httpserver# git push --tags
Username for 'http://192.168.10.110': root
Password for 'http://root@192.168.10.110': 
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 2 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 277 bytes | 277.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0)
To http://192.168.10.110/root/helloserver.git
 * [new tag]         v2.0 -> v2.0

操作完成去gitlab查看发现2.0版本已经成功推送上来了。

image.png

现在去jenkins选择参数化构建,构建的时候tag选2.0版本。

image.png

构建完成后发现版本已经成为最新v2.0版本。

image.png

设置dev分支可以自动发布

在k8s集群创建出dev名称空间,并创建出对应的业务service的deployment,所用到的yaml与上面在pro名称空间创建资源时使用的统一个,这里就没有重复截图。

image.png

去jenkins创建一个新的自由风格的任务

image.png

在源码管理位置配置代码仓库相关信息,注意要拉取的分支改为开发分支。

image.png

选择构建触发器中的Build when a change is pushed to GitLab选项,这个选项是需要安装Gitlab Hook Plugin和Build Authorization Token Root Plugin插件才可以看到。

配置k8s的连接信息

image.png

此处在构建时使用了$BUILD_NUMBER变量作为镜像的tag,确保每次构建k8s都能拉取到最新的镜像。

image.png

创建完成后先手动点击构建,看是否能正常构建成功

image.png

在k8s平台测试手动构建成功

image.png

此时在jenkins点击配置,在构建触发器取出此链接,需要配置到Gitlab平台。

image.png

同样在该选项卡下点击高级配置可以看到如下选项,点击生成一个新的token

image.png

之后单击保存。

单击页面左上角选择最下面的管理员

image.png

在设置选项卡找到网络。

image.png

在出站请求位置勾选 允许来自 web hooks 和服务对本地网络的请求,否则无法添加本地需要调用的webhook地址。更改完成后保存。

image.png

进入项目配置信息,选择设置,单击WebHook。

image.png

在此处配置刚刚取出的地址和token

image.png

配置完成后在此页面最下方会看到创建的webhook

image.png

创建完成后可以去测试推送事件触发构建,发现在jenkins已经成功触发构建

image.png

image.png

此时用git向dev分支提交代码,手动将main.go的版本号修改为2.0。修改文件过程不再演示。

root@master01:~/dev/httpserver# git add .
root@master01:~/dev/httpserver# git commit -m "v2.0"
[dev 9df58bd] v2.0
 1 file changed, 1 insertion(+), 1 deletion(-)
root@master01:~/dev/httpserver# git push -u origin dev
Username for 'http://192.168.10.110': root
Password for 'http://root@192.168.10.110': 
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 2 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 277 bytes | 277.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0)
remote: 
remote: To create a merge request for dev, visit:
remote:   http://gitlab.example.com/root/helloserver/-/merge_requests/new?merge_request%5Bsource_branch%5D=dev
remote: 
To http://192.168.10.110/root/helloserver.git
   eeb98b1..9df58bd  dev -> dev
Branch 'dev' set up to track remote branch 'dev' from 'origin'.

此时去jenkins平台查看发现已经触发构建。

image.png

现在去k8s平台去验证dev名称空间的POD是否已经自动更新。

root@master01:~/dev/httpserver# kubectl get svc -n dev
NAME                 TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
httpserver-service   NodePort   10.100.53.6   <none>        80:30222/TCP   36m
root@master01:~/dev/httpserver# curl 10.100.53.6
Version=2.0root@master01:~/dev/httpserver# 

ps:以上内容在本人实现环境中已试验成功,如发现有问题或表述不清的地方欢迎指正。


李朝阳
52 声望14 粉丝

人生到处知何似,应似飞鸿踏雪泥