基于K8S的CICD系统实现

基于K8S的CICD系统实现

前情提要

本系统仅仅是搭建好了需要的组件,尚未完成测试,还不确定哪里需要完善,可自行测试,后续会完善

在此声明,这个项目需要有32G+以上的运行内存,不然继续不了,只做出了雏形,奈何硬件问题,运行不下去了

系统拓扑图

K8S集群

主机名 ip1(NAT) 系统 磁盘 内存
master1 192.168.48.101 OpenEuler-22.04-LTS 100G 4G
master2 192.168.48.102 OpenEuler-22.04-LTS 100G 4G
master3 192.168.48.103 OpenEuler-22.04-LTS 100G 4G
node01 192.168.48.104 OpenEuler-22.04-LTS 100G 8G
高可用ip 192.168.48.200

harbor集群

角色 主机名 ip 系统 资源最低要求
Harbor1
nginx
Keepalived1
harbor1 192.168.48.106 OpenEuler-22.04-LTS CPU:4核
内存:1G
硬盘:40G
Harbor2
nginx
Keepalived2
harbor2 192.168.48.107 OpenEuler-22.04-LTS CPU:4核
内存:1G
硬盘:40G
postgresql
Redis
NFS共享
zujian 192.168.48.108 OpenEuler-22.04-LTS CPU:4核
内存:1G
硬盘:40G
高可用ip 192.168.48.100

部署K8S高可用集群

OpenEuler-部署K8S高可用集群(内部etcd) - 严千屹博客 (qianyios.top)

部署ceph集群

注意:原文章是部署在master1,node01,node02,由于硬件原因,现在需要部署在三台master,所以原文章开头加硬盘,你也只需要加在三台master上,请自己注意在2.1-2位置修改集群名称和硬盘名称。包括要下载的镜像,就在三台master下载就行了,接着你就可以继续做了

基于K8S1.28.2实验rook部署ceph - 严千屹博客 (qianyios.top)

以下进行cephfs存储做存储声明即Storageclass,方便后续jenkins和gitlab调用

创建cephfs文件系统

操作节点[master1]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
cd
cd rook/deploy/examples
cat >rook-cephfs.yaml << "EOF"
apiVersion: ceph.rook.io/v1
kind: CephFilesystem
metadata:
name: rook-cephfs #修改名字
namespace: rook-ceph
spec:
metadataPool:
replicated:
size: 3
requireSafeReplicaSize: true # 参数指示是否要求副本数量必须是偶数
parameters:
compression_mode:
none
dataPools:
- name: replicated
failureDomain: host
replicated:
size: 3
requireSafeReplicaSize: false
parameters:
compression_mode:
none
preserveFilesystemOnDelete: true #当删除CephFilesystem资源时,是否保留Ceph集群中的实际文件系统。若设为true则保留,方便后续恢复使用。
metadataServer:
activeCount: 3
activeStandby: true
placement:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- rook-ceph-mds
topologyKey: topology.kubernetes.io/zone
priorityClassName: system-cluster-critical
livenessProbe:
disabled: false
startupProbe:
disabled: false
EOF
kubectl apply -f rook-cephfs.yaml
kubectl get pod -n rook-ceph | grep rook-cephfs

可能要一分钟才会创建好

为什么我能直接在k8s直接运行ceph指令,而不进入pod,自行去第二步开通看部署ceph集群的

image-20240501205306444

快捷链接:在K8S中直接调用出ceph命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@master1 examples]# ceph fs status
rook-cephfs - 0 clients
===========
RANK STATE MDS ACTIVITY DNS INOS DIRS CAPS
0 active rook-cephfs-f Reqs: 0 /s 10 13 12 0
1 active rook-cephfs-c Reqs: 0 /s 0 0 0 0
2 active rook-cephfs-d Reqs: 0 /s 10 12 11 0
0-s standby-replay rook-cephfs-a Evts: 0 /s 0 0 0 0
2-s standby-replay rook-cephfs-b Evts: 0 /s 0 0 0 0
1-s standby-replay rook-cephfs-e Evts: 0 /s 0 0 0 0
POOL TYPE USED AVAIL
rook-cephfs-metadata metadata 0 94.9G
rook-cephfs-replicated data 0 94.9G
MDS version: ceph version 17.2.6 (d7ff0d10654d2280e08f1ab989c7cdf3064446a5) quincy (stable)
[root@master1 examples]# ceph fs ls
name: rook-cephfs, metadata pool: rook-cephfs-metadata, data pools: [rook-cephfs-replicated ]
[root@master1 examples]#

rook-cephfs-replicated是下面存储声明需要用到的 pool

创建Storageclass

是k8s调用ceph的声明,通过这个Storageclass才能去调用ceph

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cd 
cd rook/deploy/examples
cat > rook-cephfs-sc.yaml <<"EOF"
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: rook-cephfs-sc
provisioner: rook-ceph.cephfs.csi.ceph.com
parameters:
clusterID: rook-ceph #ceph集群命名空间
fsName: rook-cephfs #cephfs,刚刚创建的文件系统
pool: rook-cephfs-replicated #刚刚创建的fs所包含的pool

csi.storage.k8s.io/provisioner-secret-name: rook-csi-cephfs-provisioner
csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
csi.storage.k8s.io/controller-expand-secret-name: rook-csi-cephfs-provisioner
csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
csi.storage.k8s.io/node-stage-secret-name: rook-csi-cephfs-node
csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
reclaimPolicy: Delete
allowVolumeExpansion: true
EOF
kubectl apply -f rook-cephfs-sc.yaml
kubectl get sc

image-20240914162514951

部署harbor进群

Harbor共享存储高可用 - 严千屹博客 (qianyios.top)

配置仓库地址

部署好后,需要将K8s各个节点,和harbor各个节点都要进行配置仓库地址

操作节点:[所有节点]

1
vim /etc/docker/daemon.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 客户端默认使用的是https协议,所以需要对docker做以下修改,在文件末尾添加insecure-registries
[root@qianyios ~]# vim /etc/docker/daemon.json
{
................
"registry-mirrors": [],#无关紧要,不用看,
"insecure-registries": [ "192.168.48.100" ],#重要加这行,别忘了如果他不是最后一行一定要在末尾加逗号
................
}

# 修改后,重启docker使其生效
systemctl daemon-reload
systemctl restart docker

# 利用docker info查看是否添加上
[root@qianyios ~]# docker info
Containers: 10
Running: 1
Paused: 0
Stopped: 9
Images: 37
...
Experimental: false
Insecure Registries:
192.168.48.100 ###要确保有这个才行
127.0.0.0/8
Registry Mirrors:

image-20240505170836267

测试免密登入

接下来测试免密登入,第一次登入要密码,第二次登入就不用了,第二次之后就是免密登入

1
docker login 192.168.48.100

image-20240505172454889

免密登入成功!

部署jenkins

注意:以下仅实现部署了jenkins,尚未完成测试,后续有时间再进行测试,如果你有时间可以进行测试,还不确定哪里没有完善的地方

操作节点:[masetr1]

创建rabc验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cd 
cd jenkins
cat > jenkins-rabc.yaml << "EOF"
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins-admin
namespace: jenkins
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: jenkins-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: jenkins-admin
namespace: jenkins
EOF

kubectl apply -f jenkins-rabc.yaml

创建jenkins用户的secret

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cd 
cd jenkins
cat >jenkins-admin-secret.yaml << "EOF"
apiVersion: v1
kind: Secret
metadata:
name: jenkins-admin-secret
namespace: jenkins
annotations:
kubernetes.io/service-account.name: jenkins-admin
type: kubernetes.io/service-account-token
EOF
kubectl apply -f jenkins-admin-secret.yaml
kubectl get secret -n jenkins

[root@master1 jenkins]# kubectl get secret -n jenkins
NAME TYPE DATA AGE
jenkins-admin-secret kubernetes.io/service-account-token 3 15s

创建pvc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#创建命名空间
cd
kubectl create namespace jenkins
mkdir jenkins
cd jenkins
cat > pvc.yaml << EOF
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: jenkins-pvc
namespace: jenkins
spec:
storageClassName: rook-cephfs-sc #这个是第4步部署完ceph集群创建的Storageclass
resources:
requests:
storage: 3Gi
accessModes:
- ReadWriteMany
EOF
kubectl apply -f pvc.yaml
kubectl get pvc -n jenkins

image-20240914162447149

部署jenkins

自行在harbor仓库创建好cicd仓库

image-20240505231349308

构建jenkins镜像

1
docker pull jenkins/jenkins

可能会出现拉取缓慢现象,也可以用以下方法进行构建

基于阿里云容器服务构建私人docker镜像 - 严千屹博客 (qianyios.top)

构建之后就要进行拉取下载打标签,以下是我自己构建的,你可以用这个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#下载镜像
docker pull registry.cn-hangzhou.aliyuncs.com/qianyios/jenkins:latest

#打标签
docker tag registry.cn-hangzhou.aliyuncs.com/qianyios/jenkins:latest 192.168.48.100/cicd/jenkins:latest

#查看镜像
[root@master1 jenkins]# docker images | grep jenk
192.168.48.100/cicd/jenkins latest 786c9e8a0cb8 6 days ago 472MB
registry.cn-hangzhou.aliyuncs.com/qianyios/jenkins latest 786c9e8a0cb8 6 days ago 472MB
[root@master1 jenkins]#


#推送镜像到harbor仓库
docker push 192.168.48.100/cicd/jenkins:latest

image-20240505231712011

1
2
3
4
#给所有master节点打上master标签
kubectl label node master1 k8s-type=master
kubectl label node master2 k8s-type=master
kubectl label node master3 k8s-type=master
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
cd 
cd jenkins
cat >jenkins-deploy.yaml << "EOF"
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins
namespace: jenkins
spec:
replicas: 1
selector:
matchLabels:
app: jenkins-server
template:
metadata:
labels:
app: jenkins-server
spec:
securityContext:
fsGroup: 995
runAsUser: 1000
serviceAccountName: jenkins-admin
nodeSelector:
k8s-type: master
containers:
- name: jenkins
image: 192.168.48.100/cicd/jenkins:latest
imagePullPolicy: IfNotPresent
resources:
limits:
memory: "2Gi"
cpu: "1000m"
requests:
memory: "500Mi"
cpu: "500m"
ports:
- name: httpport
containerPort: 8080
- name: jnlpport
containerPort: 50000
livenessProbe:
httpGet:
path: "/login"
port: 8080
initialDelaySeconds: 90
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 5
readinessProbe:
httpGet:
path: "/login"
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
volumeMounts:
- name: jenkins-data
mountPath: /var/jenkins_home
- name: kubectl
mountPath: /usr/bin/kubectl
- name: kube-config
mountPath: /root/.kube
- name: docker
mountPath: /usr/bin/docker
- name: docker-sock
mountPath: /var/run/docker.sock
volumes:
- name: jenkins-data
persistentVolumeClaim:
claimName: jenkins-pvc
- name: kubectl
hostPath:
path: /usr/bin/kubectl
- name: kube-config
hostPath:
path: /root/.kube
- name: docker
hostPath:
path: /usr/bin/docker
- name: docker-sock
hostPath:
path: /var/run/docker.sock
EOF
kubectl apply -f jenkins-deploy.yaml
kubectl get pods -n jenkins

创建svc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
cd 
cd jenkins
cat >jenkins-svc.yaml << "EOF"
apiVersion: v1
kind: Service
metadata:
name: jenkins-service
namespace: jenkins
annotations:
prometheus.io/scrape: 'true'
prometheus.io/path: /
prometheus.io/port: '8080'
spec:
selector:
app: jenkins-server
type: NodePort
ports:
- port: 8080
targetPort: 8080
nodePort: 32000
name: httpport
- name: jnlpport
port: 50000
targetPort: 50000
EOF
kubectl apply -f jenkins-svc.yaml
kubectl get svc -n jenkins

访问页面

1
http://192.168.48.200:32000/

image-20240505235348080

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
kubectl get pods -n jenkins
#查看你的pod名字替换下面的名字即可(jenkins-799dc7cd88-d2n4k)

#进入容器
kubectl exec -it -n jenkins jenkins-799dc7cd88-d2n4k bash

#修改Update Center源
sed -i 's#https://updates.jenkins.io/update-center.json#http://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json#g' /var/jenkins_home/hudson.model.UpdateCenter.xml

#替换插件源地址:
sed -i 's#https://updates.jenkins.io/download#http://mirrors.aliyun.com/jenkins#g' /var/jenkins_home/updates/default.json
#替换谷歌地址:
sed -i 's#http://www.google.com#http://www.baidu.com#g' /var/jenkins_home/updates/default.json


#查看网页密码
jenkins@jenkins-546cf958bd-kq5f2:~$ cat /var/jenkins_home/secrets/initialAdminPassword

ebfc1b12835f43c8a8c2677728e4aa55

image-20240506000643463

先点无,这里先不安装,后面再安装

image-20240928203306616

使用admin账户继续

image-20240506001948294

默认下一步

image-20240506002019436

自行去设置修改admin密码

image-20240506002313407

配置k8s等插件和实现功能

安装插件

1
安装插件:Git / Git Parameter/Pipeline/Config File Provider/Gitlab/Generic Webhook Trigger/Blue Ocean/Localization: Chinese /Kubernetes

在首页点击系统管理然后点击插件管理—–安装Kubernetes插件

image-20240506002747172

安装之后需要等待他重启

image-20240506003015735

image-20240506003148720

配置K8s代理节点

配置jenkins连接kubernetes

点击系统管理-cloud

image-20240928213206053

点击Clouds-添加New cloud

image-20240928213240693

点击create

image-20240928213328017

查看Kubernetes 服务证书 key

[root@master1 jenkins]# cat /etc/kubernetes/pki/ca.crt
-----BEGIN CERTIFICATE-----
MIIDBTCCAe2gAwIBAgIIcJ+z+Wx0m20wDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE
AxMKa3ViZXJuZXRlczAeFw0yNDA5MjgxMTI5NDJaFw0zNDA5MjYxMTM0NDJaMBUx
EzARBgNVBAMTCmt1YmVybmV0ZXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQDYeRyEbAJRMqWyAmQf0LfK9wecWoQSyKYX+gHDUvZMaQK/nkAfrEme5Wot
J8lcODlNAj0OImRRKkCzfBwlZl5WMYH3Roonn8z9j4hkUAX/EgTwMun1q0G/D1yV
zxcRSUxxiFDKlRCVsPxIsuHIUvTrAHkU0qpz1S4cITisF9o9hCvqZZZ/5fCudn7I
sLlDhxzL1TAI5R2hqZKFdondpoGxYF5oc2wuk+0g/3GJZeaGEO/9p5ySX/glamil
e5npU/EvLsG4er2UQqB7dc9wfxOT2p0Qlj7UjHcqgY8E6ufhd7GqYVKNDXSmKXiP
BZI5ba6/kZJj0nsSz3GnVdhFxUD1AgMBAAGjWTBXMA4GA1UdDwEB/wQEAwICpDAP
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBT5qTcFwRrY/VSJtfAZK85ZCp2ViTAV
BgNVHREEDjAMggprdWJlcm5ldGVzMA0GCSqGSIb3DQEBCwUAA4IBAQDX+1q8NXKb
HWnfR75MORrQJ898B9M1FBoHfLRdsmmCJVrSQXbBbKn1zVoJL6YLdjDOx2NfWa8o
f1Y7KSme9Z6B4j57tGFQ/4LST4Cwk4PPh1v6nrwVesW6xE6ClHVZ0N1S4ggZi8ll
Wcv3ZCgdGrjSQm15xsRr4oN7XGY/B1kAZWU4defpcxhtIMtLQ7/m74hfYo/P5L/b
Wu1knzRSs1/Cna2GFkWx3BYfbG78ZPBIh17mN4vFAt/x8ZOZCJ+bb0Ey6upYnhjP
H2jiNrHcyJVnnDO4N6kMII9sh2n+gYvK45u+/Vw8nPElf72LkHFHOyQc8QD9opXF
LC9bmhoJuU9v
-----END CERTIFICATE-----

image-20240928213425808

获取凭证

不是低版本,请跳到下一步!!!!

低版本获取凭证方法,低版本会自动生成一个secret

[root@master1 ~]# SECRET_NAME=$(kubectl get serviceaccount jenkins-admin  -o=jsonpath='{.secrets[0].name}' -n jenkins)
[root@master1 ~]# kubectl get secrets $SECRET_NAME  -o=jsonpath='{.data.token}' -n jenkins | base64 -d

k8s1.28获取凭证方法,需要手动创建secret

使用kubectl create token获取的token会过期

这里手动创建secret,并查看相关token值

编写jenkins-admin用户secret清单,并创建

cd /root/jenkins
cat >jenkins-admin-secret.yaml<< "EOF"
apiVersion: v1
kind: Secret
metadata:
  name: jenkins-admin-secret
  namespace: jenkins
  annotations:
    kubernetes.io/service-account.name: jenkins-admin
type: kubernetes.io/service-account-token
EOF
 kubectl apply -f jenkins-admin-secret.yaml

查看secret

kubectl get secret -n jenkins

image-20240928213605321

获取token

[root@master1 jenkins]# kubectl get secrets jenkins-admin-secret  -o=jsonpath='{.data.token}' -n jenkins | base64 -d
eyJhbGciOiJSUzI1NiIsImtpZCI6ImpaNkJTN3d0M0pFblBCSVBaaGFoNzdUTVNLMHZiTERxY09Ibmg4WEtFNTQifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJqZW5raW5zIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImplbmtpbnMtYWRtaW4tc2VjcmV0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImplbmtpbnMtYWRtaW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI3MTg2Mzg1Mi1jNDkwLTQyMDEtYTA2OS1lM2ZhOTcyNTgwODYiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6amVua2luczpqZW5raW5zLWFkbWluIn0.sfofmctQos9fcEAf0hZEfEKN2WiG7GklOW6NMEdXbiJHkg5SNe8-MuJK4c4JtubyIA9IFhHo6PfQoFl8-2smuFaojjSKZKn2esJJ5enT_WNsbIdXmu4tg8a2571EikotiGKLpGHuLEZOLdTyswTsQW-FSQH7K16VmfUSzHCkKjV5eXNK3gpRj9p3voGWlBRQ3Jqfm6NWSKp_1_XZqFyi_KM8DOaMHhffN24ejwC2lvIzKNcZp80yY2rW4BkCI0dLN2GqUNlzB9QXYUslLtsigObukCdjY8EefCc34Rh68kq2UQVpXb9eTkyK50J9HEFJtLiuameD3Yx8gNE9xWJ4Vw

image-20240928213838987

配置kubernetes相关信息

  • Name: 这个自定义, 默认的是kubernetes

  • Kubernetes URL: https://kubernetes.default- 这个一般是从你的 service account 自动配置的

  • Kubernetes 服务证书 key: 如果您有 Kubernetes 集群 CA 证书,您可以添加它以实现安全连接。您可以从 pod 位置获取证书/var/run/secrets/kubernetes.io/serviceaccount/ca.crt。如果您没有证书,您可以启用“ disable https certificate check”(禁用HTTPS证书检查)选项

  • Kubernetes Namespace: 一般是 default 除非你要在一个特殊的命名空间 ,否则不要动他.因为我的jenkins部署在了jenkin命名空间,就用了jenkins

  • Credentials(凭据): 为了让 Jenkins 与 Kubernetes 集群通信,我们需要一个服务帐户令牌,该令牌具有在设置的命名空间中部署 pod 的权限

  • Jenkins URL: http://<your_jenkins_hostname>:port

  • Jenkins tunnel: <your_jenkins_hostname>:50000 - 这就是用来和 Jenkins 启动的 agent 进行交互的端口

修改名称和kubernetes地址及服务证书key

此Kubernetes由于Jenkins 服务器在同一个 Kubernetes 集群中运行,这里直接通过service进行通讯

此服务证书key就是前几步获取的key

添加凭证

点击添加->jenkins

image-20240928214022992

选择Domain为全局凭据

类型选择为secret txt

范围选择为全局

secret就是刚才获取的凭据

描述 就是凭据的名称

image-20240928214459767

点击添加

选择凭据为刚才添加的,点击测试链接,验证 Kubernetes 集群的连接性

image-20240928214608024

配置 Jenkins URL 详细信息

对于在k8s集群内部运行的 Jenkins master,您可以使用 Kubernetes 集群的 Service 端点作为 Jenkins URL,因为代理 pod 可以通过内部服务 DNS 连接到集群

url语法:http://.:8080

jenkins-service.jenkins:8080

注意:Jenkins 通道(Jenkins tunnel)链接不需要加http://,否则无法正常通讯

image-20240928214829511

创建成功

image-20240928214845932

创建Jenkins代理镜像

拉取jenkins代理镜像并上传到harbor仓库

docker pull jenkins/inbound-agent
#如果下不到可以用我的
docker pull registry.cn-hangzhou.aliyuncs.com/qianyios/inbound-agent:latest
docker tag registry.cn-hangzhou.aliyuncs.com/qianyios/inbound-agent:latest 192.168.48.100/library/inbound-agent:latest
docker push 192.168.48.100/library/inbound-agent:latest
docker images | grep inbound

部署gitlab

注意:以下仅实现部署了gitlab,尚未完成测试,后续有时间再进行测试,如果你有时间可以进行测试,还不确定哪里没有完善的地方

创建gitlab的secret

1
2
3
4
#长度为8个字符
[root@master1 ~]# echo -n 'qianyios' | base64
cWlhbnlpb3M=
#qianyios将会成为gitlab页面的登入密码
1
2
3
4
mkdir /root/gitlab
cd /root/gitlab
#创建namespace
kubectl create namespace gitlab
1
2
3
4
5
6
7
8
9
10
11
12
cat >gitlab-secret-pwd.yaml << "EOF"
apiVersion: v1
data:
password: cWlhbnlpb3M= #换成刚刚前面生成的密码
kind: Secret
metadata:
creationTimestamp: null
name: gitlab-pwd
namespace: gitlab
EOF
kubectl apply -f gitlab-secret-pwd.yaml
kubectl get secret -n gitlab

image-20240928215102453

创建pvc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
cat > gitlab-pvc.yaml <<"EOF"
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: gitlab-pvc-logs
namespace: gitlab
spec:
storageClassName: rook-cephfs-sc
resources:
requests:
storage: 5Gi
accessModes:
- ReadWriteOnce
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: gitlab-pvc-config
namespace: gitlab
spec:
storageClassName: rook-cephfs-sc
resources:
requests:
storage: 1Gi
accessModes:
- ReadWriteOnce
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: gitlab-pvc-data
namespace: gitlab
spec:
storageClassName: rook-cephfs-sc
resources:
requests:
storage: 10Gi
accessModes:
- ReadWriteOnce
EOF

kubectl apply -f gitlab-pvc.yaml
kubectl get pvc -n gitlab

image-20240510195549565

部署gitlab

1
2
3
4
5
6
7
8
9
10
11
#下载gitlab-ce镜像,镜像很大要1个G多
docker pull gitlab/gitlab-ce
# 如果下不了用我构建的镜像
docker pull registry.cn-hangzhou.aliyuncs.com/qianyios/gitlab:latest


#镜像打标签#这个里我用了自己构建的镜像,你要是用这个gitlab/gitlab-ce自行替换
docker tag registry.cn-hangzhou.aliyuncs.com/qianyios/gitlab:latest 192.168.48.100/cicd/gitlab:latest

#推送镜像
docker push 192.168.48.100/cicd/gitlab:latest
1
2
node节点打上k8s-type=node标签
kubectl label nodes node01 k8s-type=node
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
cat > gitlab-deploy.yaml << "EOF"
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: gitlab
name: gitlab
namespace: gitlab
spec:
replicas: 1
selector:
matchLabels:
app: gitlab
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: gitlab
spec:
nodeSelector:
k8s-type: node
containers:
- image: 192.168.48.100/cicd/gitlab:latest #更换镜像
imagePullPolicy: IfNotPresent
name: gitlab-ce
env:
- name: GITLAB_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: gitlab-pwd
key: password
- name: GITLAB_ROOT_MAIL
value: xiaoohu2002@126.com
ports:
- name: gitlab80
containerPort: 80
- name: gitlab22
containerPort: 22
- name: gitlab443
containerPort: 443
volumeMounts:
- name: gitlab-logs
mountPath: /var/log/gitlab
- name: gitlab-config
mountPath: /etc/gitlab
- name: gitlab-data
mountPath: /var/opt/gitlab
volumes:
- name: gitlab-logs
persistentVolumeClaim:
claimName: gitlab-pvc-logs
- name: gitlab-config
persistentVolumeClaim:
claimName: gitlab-pvc-config
- name: gitlab-data
persistentVolumeClaim:
claimName: gitlab-pvc-data
status: {}

EOF
kubectl apply -f gitlab-deploy.yaml
kubectl get pod -n gitlab

创建svc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
cat > gitlab-svc.yaml << "EOF"
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: gitlab
name: gitlab
namespace: gitlab
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
nodePort: 30880
- name: 443-443
port: 443
protocol: TCP
targetPort: 443
- name: 22-22
port: 22
protocol: TCP
targetPort: 22
selector:
app: gitlab
type: NodePort
status:
loadBalancer: {}

EOF
kubectl apply -f gitlab-svc.yaml
kubectl get svc -n gitlab

访问页面

1
http://192.168.48.200:30880/

image-20240510211753542

页面测试

设置中文

sp20240920_184829_245

创建项目

image-20240920185232410

image-20240920185329957

项目推送

操作节点:[master1]

1
2
3
4
yum install -y git
mkdir /root/cicd/
cd /root/cicd/
mkdir chatgpt && cd chatgpt/

上传Chatgpt镜像站源码

项目地址:ChatGPTNextWeb

1
2
cd chatgpt/
wget https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web/archive/refs/heads/main.zip
1
[root@master1 chatgpt]# ls main.zip

解压源代码压缩包

1
2
3
unzip /root/cicd/chatgpt/main.zip
mv ChatGPT-Next-Web-main/* ./
rm -rf ChatGPT-Next-Web-main main.zip

Git全局设置

1
2
git config --global user.name "Administrator"
git config --global user.email "XiaooHu2002@163.com"

添加版本库

1
2
cd /root/cicd/chatgpt/
git init

添加远程仓库

要注意是哪个主分支哦!这里的是main

image-20240920192141173

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
git remote add origin http://192.168.48.200:30880/root/chatgpt.git
#跟踪所有改动过的文件
git add .
#提交所有更新过的文件
git commit -m "first commit"
#将代码推送到远程仓库(主分支main)
#如果主分支是main则直接执行下一步
#首先我本地的主分支是master,我需要切换,可以通过git branch查看
git branch -m master main
#推送main分支
git push -u origin main

#会提示你让你输入gitlab的账号密码
Username for 'http://192.168.48.200:30880': root
Password for 'http://root@192.168.48.200:30880':
#密码是qianyios

image-20240928221810920

image-20240928221824375

Jenkins对接gitlab

创建gitlab Secret令牌

进入gitlab创建Secret令牌

image-20240928232433171

image-20240928232523788

创建成功Secret令牌,并复制令牌

此令牌需要保存好,后面jenkins还需要用到

glpat-vLZgV6Z1nbC_96yyZdyp

image-20240928232604113

Jenkins创建流水线

点击新建任务,输入名称并选择为流水线,并点击确定

image-20240928232711976

在general中找到Generic Webhook Trigger 并勾选且复制webhook链接

http://JENKINS_URL/generic-webhook-trigger/invoke

image-20240928232844592

添加gitlab凭据

image-20240928233042430

image-20240928233233174

image-20240928233322636

配置Webhook

配置允许Webhook和服务对本地网络的请求

进入管理员-设置-网络

image-20240928233445339

勾选允许来自 webhooks 和集成对本地网络的请求并保存更改即可

image-20240928233549420

接下来配置webhooks

进入到项目中

image-20240928233715393

填写相关信息

网址:就是刚才jenkins创建项目的时候复制的链接,这里只是对其进行修改了,因为jenkins和gitlab都是部署在同一个k8s集群中我这里将域名修改成了service的地址

原地址:http://JENKINS_URL/generic-webhook-trigger/invoke

修改后的地址:http://jenkins-service.jenkins:8080/generic-webhook-trigger/invoke

Secret 令牌:就是刚创建的个人令牌

推送事件:指定只有推送到某个仓库时才触发,留空则全部分支

先看更改地址,这一步不需要操作什么,看清楚,替换了啥JENKINS_URL➡️jenkins-service.jenkins:8080

image-20240928234842712

部署webhook

image-20240928235008407

image-20240928234156662

然后添加webhook即可,然后测试推送事件

image-20240928235306092

配置jenkins流水线

添加harbor用户

image-20240928235427264

image-20240928235449242

输入相关信息并点击create创建

类型选择Username with password

范围选择全局

用户名为Harbor仓库用户名

密码为Harbor仓库用户密码

描述为此凭据的名称

image-20240928235632916

image-20240928235646179

创建好后,接下来配置流水线

先获取项目仓库地址

image-20240929000356404

但是我们要对其中的地址改一下,改成

http://gitlab.gitlab/root/chatgpt.git

回到jenkins任务

点击Dashboard->ChatGPT->设置->并点击流水线

image-20240928235754557

image-20240929002051798

点击添加凭据

Domain 选择全局凭据

类型选择Username with password

范围选择全局

用户名即是gitlab账号

密码即是gitlab账号密码

描述为此凭据的名称

image-20240929002313733

往下滑

image-20240929002527605

保存即可

harbor新建项目

输入相关信息并点击确定

用于存放业务镜像

访问级别设置成公开

存储容量为-1即代表不限制存储容量

image-20240929002628378

项目镜像准备

1
2
3
4
5
docker pull node:18-alpine
#如果下载不了可以用我的
docker pull registry.cn-hangzhou.aliyuncs.com/qianyios/node:18-alpine
docker tag registry.cn-hangzhou.aliyuncs.com/qianyios/node:18-alpine 192.168.48.100/library/node:18-alpine
docker push 192.168.48.100/library/node:18-alpine

编写业务部署清单

1
2
3
4
5
6
[root@master1 ~]# echo -n "https://xiaoai.plus" | base64
aHR0cHM6Ly94aWFvYWkucGx1cw==

[root@master1 ~]# echo -n "sk-K19c1kSqZZ92sXp13d042aD4E2B74a60B749E717Ed69449e" | base64

c2stSzE5YzFrU3FaWjkyc1hwMTNkMDQyYUQ0RTJCNzRhNjBCNzQ5RTcxN0VkNjk0NDll

key是ChatGPTkey,这里已经对其base64加密

baseurl是代理地址,这里已经对其base64加密

1
2
3
4
cd /root/cicd/chatgpt
kubectl create deploy chatgpt --image=chatgpt-next-web --dry-run=client -oyaml
kubectl create svc nodeport chatgpt --tcp=3000:3000 --dry-run=client -oyaml >> deploy.yaml
vim deploy.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
apiVersion: v1
data:
key: c2stSzE5YzFrU3FaWjkyc1hwMTNkMDQyYUQ0RTJCNzRhNjBCNzQ5RTcxN0VkNjk0NDll
baseurl: aHR0cHM6Ly94aWFvYWkucGx1cw==
kind: Secret
metadata:
creationTimestamp: null
name: chat-config

---
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: chatgpt
name: chatgpt
spec:
replicas: 1
selector:
matchLabels:
app: chatgpt
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: chatgpt
spec:
containers:
- image: chatgpt-next-web
name: chatgpt
ports:
- containerPort: 3000
imagePullPolicy: IfNotPresent
env:
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: chat-config
key: key
- name: BASE_URL
valueFrom:
secretKeyRef:
name: chat-config
key: baseurl
---
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: chatgpt
name: chatgpt
spec:
ports:
- name: 3000-3000
port: 3000
protocol: TCP
targetPort: 3000
selector:
app: chatgpt
type: NodePort
status:
loadBalancer: {}

编写镜像构建文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
cd /root/cicd/chatgpt
cat > Dockerfile <<"EOF"
# 使用 BuildKit
ARG BUILDKIT=1

# 基础镜像
FROM 192.168.48.100/library/node:18-alpine AS base

# 设置国内镜像源
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
RUN apk add --no-cache libc6-compat proxychains-ng

WORKDIR /app

# 依赖阶段
FROM base AS deps
COPY package.json yarn.lock ./

# 确保使用淘宝镜像源
RUN yarn config set registry "https://registry.npm.taobao.org/"

# 检查网络连通性
RUN wget -qO- https://registry.npm.taobao.org || echo "Failed to reach the npm mirror"

# 安装依赖并提高日志级别
RUN yarn install --frozen-lockfile --verbose

# 构建阶段
FROM base AS builder
RUN apk update && apk add --no-cache git
ENV OPENAI_API_KEY=""
ENV BASE_URL=""

WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN yarn build

# 运行阶段
FROM base AS runner
ENV PROXY_URL=""
ENV OPENAI_API_KEY=""
ENV BASE_URL=""

COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/.next/server ./.next/server

EXPOSE 3000

CMD if [ -n "$PROXY_URL" ]; then \
export HOSTNAME="127.0.0.1"; \
protocol=$(echo $PROXY_URL | cut -d: -f1); \
host=$(echo $PROXY_URL | cut -d/ -f3 | cut -d: -f1); \
port=$(echo $PROXY_URL | cut -d: -f3); \
conf=/etc/proxychains.conf; \
echo "strict_chain" > $conf; \
echo "proxy_dns" >> $conf; \
echo "remote_dns_subnet 224" >> $conf; \
echo "tcp_read_time_out 15000" >> $conf; \
echo "tcp_connect_time_out 8000" >> $conf; \
echo "localnet 127.0.0.0/255.0.0.0" >> $conf; \
echo "localnet ::1/128" >> $conf; \
echo "[ProxyList]" >> $conf; \
echo "$protocol $host $port" >> $conf; \
cat /etc/proxychains.conf; \
proxychains -f $conf node server.js; \
else \
node server.js; \
fi
EOF

编写流水线脚本

withCredentials 块来引用一个名为 my-credentials 的凭据,该凭据的类型是用户名密码。usernameVariablepasswordVariable 参数分别指定了在代码块中使用凭据时的变量名。

withCredentials 块内部,你可以执行需要使用凭据的操作,比如在 Shell 脚本中使用用户名和密码进行身份验证。

请注意,credentialsId 参数需要指定你在 Jenkins 中创建的凭据的 ID。确保凭据 ID 正确,并且具有访问该凭据的权限。

使用 withCredentials 块可以确保凭据的安全性,因为凭据的值不会明文显示在日志中,而是以变量的形式传递给代码块中的操作。这样可以避免凭据泄露的风险。

以下内容,自行修改,对照,每一行都去看

Harbor-passwd是jenkins创建的harbor的用户凭据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
cd /root/cicd/chatgpt
cat > Jenkinsfile<<"EOF"
pipeline{
agent {
kubernetes {
inheritFrom "jenkins-slave"
yaml '''
apiVersion: v1
kind: Pod
metadata:
name: jenkins-slave
spec:
securityContext:
fsGroup: 0
runAsUser: 0
nodeSelector:
k8s-type: master
containers:
- name: jnlp
image: "192.168.48.100/library/inbound-agent:latest"
imagePullPolicy: IfNotPresent
volumeMounts:
- name: kubectl
mountPath: /usr/bin/kubectl
- name: kube-config
mountPath: /root/.kube
- name: docker
mountPath: /usr/bin/docker
- name: docker-sock
mountPath: /var/run/docker.sock
volumes:
- name: kubectl
hostPath:
path: /usr/bin/kubectl
- name: kube-config
hostPath:
path: /root/.kube
- name: docker
hostPath:
path: /usr/bin/docker
- name: docker-sock
hostPath:
path: /var/run/docker.sock
'''
}
}
environment {
NPM_REGISTRY = "https://registry.npm.taobao.org/"
YARN_REGISTRY = "https://registry.npm.taobao.org/"
}
stages{
stage('git clone') {
steps {
sh 'git version'
}
}
stage('image-build'){
steps{
withCredentials([usernamePassword(credentialsId: 'Harbor-passwd', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
sh 'docker build -t 192.168.48.100/chatgpt/chatgpt:v1-$BUILD_NUMBER -f Dockerfile .'
sh 'docker login 192.168.48.100 -u=$USERNAME -p=$PASSWORD'
sh 'docker push 192.168.48.100/chatgpt/chatgpt:v1-$BUILD_NUMBER'
}
}
}
stage('cloud-deploy'){
steps{
sh 'sed -i "s#chatgpt-next-web#192.168.48.100/chatgpt/chatgpt:v1-$BUILD_NUMBER#g" deploy.yaml'
sh 'cat deploy.yaml'
sh 'kubectl get pod -A'
sh 'kubectl get secret,deploy,svc -A'
sh 'kubectl apply -f deploy.yaml'
sh 'kubectl get -f deploy.yaml'
}
}
}
}
EOF

通过git上传代码

1
2
3
4
5
6
cd /root/cicd/chatgpt
git add .
git commit -m "add Jenkinsfile Dockerfile and deploy.yaml"
git push -u origin main
Username for 'http://192.168.48.200:30880': root
Password for 'http://root@192.168.48.200:30880':

image-20240929010336567

测试

通过刚刚的上传deploy.yaml,流水线已经开始执行

进入jenkins页面可以看到jenkins建的项目正在执行,并且可以看到右下角有一个jenkins代理,说明新建了一个jenkins代理执行

特别声明
千屹博客旗下的所有文章,是通过本人课堂学习和课外自学所精心整理的知识巨著
难免会有出错的地方
如果细心的你发现了小失误,可以在下方评论区告诉我,或者私信我!
非常感谢大家的热烈支持!

基于K8S的CICD系统实现
https://blog.qianyios.top/posts/40462/
作者
严千屹
发布于
2024年5月10日
更新于
2024年9月29日
许可协议