基于k8s的CICD实现
master | node01 | jenkins+gitlab |
---|---|---|
2G | 2G | 4G |
192.168.1.20 | 192.168.1.21 | 192.168.1.22 |
docker服务,registry | docker服务 | docker服务、jenkns、gitlab |
模拟一个web服务
//环境准备好了之后,在master节点部署registry服务,将自定义镜像的v1版本上传到私有仓库中。当然其他的2台dockerhost也需要加入到registry服务中。
//提前准备好了私有镜像
[root@master ~]# docker pull registry:2
[root@master ~]# docker run -itd --name registry -p 5000:5000 --restart=always registry:2
95e38f1fd777cebf19a963c795946e91b8a76edd5e3544fd4f5dc0339f5960c4
三台节点都要修改
[root@master ~]# vim /usr/lib/systemd/system/docker.service
...
ExecStart=/usr/bin/dockerd --insecure-registry 192.168.1.20:5000
...
[root@master ~]# systemctl daemon-reload
[root@master ~]# systemctl restart docker
[root@master ~]# docker load < httpd_v1.tar
[root@master ~]# docker push 192.168.1.20:5000/httpd:v1
另外俩节点可以下载
//要求,创建一个Deployment资源,replicas:2,镜像使用自定义镜像V1版本,然后创建一个SVC(type: NodePort, nodePort: 30034)资源对象,和此Deployment资源关联。
创建deployment
[root@master ~]# mkdir /opt/autoweb
[root@master ~]# cd /opt/autoweb/
[root@master autoweb]# vim myapp.yaml
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: myapp
spec:
replicas: 2
template:
metadata:
labels:
app: httpd
spec:
containers:
- name: myapp
image: 192.168.1.20:5000/httpd:v1
[root@master autoweb]# kubectl apply -f myapp.yaml
创建svc
[root@master autoweb]# vim mysvc.yaml
kind: Service
apiVersion: v1
metadata:
name: mysvc
spec:
selector:
app: httpd
type: NodePort
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30039
[root@master autoweb]# kubectl apply -f mysvc.yaml
//验证各资源的部署情况
[root@master autoweb]# kubectl get deployments.
NAME READY UP-TO-DATE AVAILABLE AGE
myapp 2/2 2 2 3m43s
[root@master autoweb]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 11d
mysvc NodePort 10.97.18.79 <none> 80:30034/TCP 58s
[root@master autoweb]# kubectl describe svc mysvc
Name: mysvc
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{
"apiVersion":"v1","kind":"Service","metadata":{
"annotations":{
},"name":"mysvc","namespace":"default"},"spec":{
"ports":[{
"nodePort":30034,...
Selector: app=httpd
Type: NodePort
IP: 10.97.18.79
Port: <unset> 80/TCP
TargetPort: 80/TCP
NodePort: <unset> 30034/TCP
Endpoints: 10.244.1.2:80,10.244.2.2:80
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
[root@master autoweb]# curl 127.0.0.1:30034
111111
[root@node01 ~]# curl 127.0.0.1:30034
111111
[root@auto-web ~]# curl 127.0.0.1:30034
111111
部署JDK
/部署之前,先关闭防火墙、selinux
//部署jenkins,需要JDK(java环境),所以,这里先部署jdk.这里已经提前准备好了。
[root@auto-web autoweb]# ls
jdk-8u231-linux-x64.tar.gz
[root@auto-web autoweb]# ls
jdk1.8.0_231 jdk-8u231-linux-x64.tar.gz
[root@auto-web autoweb]# mv jdk1.8.0_231 /usr/java
[root@auto-web autoweb]# vim /etc/profile
...
大约76行,最后一行
unset -f pathmunge
export JAVA_HOME=/usr/java
export JRE_HOME=/usr/java/jre
export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
export CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar
...
[root@auto-web autoweb]# source /etc/profile
[root@auto-web autoweb]# java -version
java version "1.8.0_231"
Java(TM) SE Runtime Environment (build 1.8.0_231-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.231-b11, mixed mode)
部署jenkins
//这里我们使用rpm包安装的方式,部署jenkins,当然也有其他的部署方式,都可以。
[root@autoweb autoweb]# rpm -ivh jenkins-2.190.3-1.1.noarch_2.rpm
warning: jenkins-2.190.3-1.1.noarch_2.rpm: Header V4 DSA/SHA1 Signature, key ID d50582e6: NOKEY
Preparing... ################################# [100%]
Updating / installing...
1:jenkins-2.190.3-1.1 ################################# [100%]
//可以查看一下安装的相关目录
[root@autoweb autoweb]# rpm -ql jenkins
/etc/init.d/jenkins
/etc/logrotate.d/jenkins
/etc/sysconfig/jenkins
/usr/lib/jenkins
/usr/lib/jenkins/jenkins.war
/usr/sbin/rcjenkins
/var/cache/jenkins
/var/lib/jenkins
/var/log/jenkins
[root@autoweb autoweb]# rpm -qc jenkins
/etc/init.d/jenkins
/etc/logrotate.d/jenkins
/etc/sysconfig/jenkins
//添加jenkins启动依赖的JDK路径。
[root@auto-web autoweb]# vim /etc/init.d/jenkins
...
大概84行
/usr/bin/java
/usr/java/bin/java
"
...
//重新加载配置文件,启动jenkins,或者用: service jenkins start
[root@auto-web autoweb]# systemctl daemon-reload
[root@auto-web autoweb]# systemctl start jenkins
[root@auto-web autoweb]# systemctl status jenkins
● jenkins.service - LSB: Jenkins Automation Server
Loaded: loaded (/etc/rc.d/init.d/jenkins; bad; vendor preset: disabled)
Active: active (running) since Sun 2020-11-15 15:43:32 CST; 8s ago
Docs: man:systemd-sysv-generator(8)
Process: 40803 ExecStart=/etc/rc.d/init.d/jenkins start (code=exited, status=0/SUCCESS)
Tasks: 38
Memory: 349.7M
CGroup: /system.slice/jenkins.service
└─40831 /usr/java/bin/java -Dcom.sun.akuma.Daemon=d...
Nov 15 15:43:31 auto-web systemd[1]: Starting LSB: Jenkins Aut...
Nov 15 15:43:31 auto-web runuser[40811]: pam_unix(runuser:sess...
Nov 15 15:43:32 auto-web jenkins[40803]: Starting Jenkins [ O...
Nov 15 15:43:32 auto-web systemd[1]: Started LSB: Jenkins Auto...
Hint: Some lines were ellipsized, use -l to show in full.
//验证开启端口,然后去浏览器确认服务的运行
[root@auto-web autoweb]# ss -lnt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
...
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 50 :::8080 :::*
...
free -h 看内存
//查看对应的管理员密码
[root@auto-web autoweb]# cat /var/lib/jenkins/secrets/initialAdminPassword
636f384f72b14de7a31aa6cf314dae71
浏览器访问:http://192.168.1.22:8080
//可以设置一下jenkins的国内插件源,这里选择清华大学的。
[root@auto-web jenkins]# vim hudson.model.UpdateCenter.xml
<?xml version='1.1' encoding='UTF-8'?>
<sites>
<site>
<id>default</id>
<url>https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json</url>
</site>
</sites>
//jenkins启动完成之后,就本实验来说,除了支持中文的语言包之外,需要和gitlab联动,所以,需要支持Gitlab的三个包。
//这里插件已经准备好了,直接解压即可
[root@auto-web jenkins]# pwd
/var/lib/jenkins
[root@auto-web jenkins]# ls
plugins.tar.gz //提前准备好的插件包
[root@autoweb jenkins]# rm -rf plugins/ //可以把已有plugins删除
[root@auto-web jenkins]# mv plugins plugins.bak
[root@auto-web jenkins]# tar -zxf plugins.tar.gz
[root@auto-web jenkins]# ls
...
[root@auto-web jenkins]# ls plugins
...
//重启服务,浏览器验证
[root@auto-web jenkins]# service jenkins restart
Restarting jenkins (via systemctl): [ OK ]
//Jenkins部署到这,就可以暂时不用管它
部署gitlab
//rpm包已经准备好了,安装完依赖,直接导入,安装即可。
[root@auto-web autoweb]# yum -y install curl policycoreutils openssh-server openssh-clients postfix git
[root@auto-web autoweb]# systemctl start postfix
[root@auto-web autoweb]# systemctl enable postfix
[root@auto-web autoweb]# ls
gitlab-ce-11.9.8-ce.0.el6.x86_64.rpm
jdk-8u231-linux-x64.tar.gz
jenkins-2.179-1.1.noarch.rpm
[root@auto-web autoweb]# rpm -ivh gitlab-ce-11.9.8-ce.0.el6.x86_64.rpm
//安装完成之后,开启之前,需要将gitlab的默认端口进行更改,因为它的默认端口也是8080,和jenkins冲突了。
[root@auto-web autoweb]# vim /etc/gitlab/gitlab.rb
...
13 external_url 'http://192.168.1.22:90'
...
678 unicorn['listen'] = '127.0.0.1'
679 unicorn['port'] = 8088
//更改完成之后,启动gitlab服务,然后用浏览器验证服务
[root@auto-web autoweb]# gitlab-ctl reconfigure
root@auto-web autoweb]# ss -lnt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 511 *:90 *:*
浏览器访问:http://192.168.1.22:90
配置jenkins和gitlab平台的联动
部署这两个服务的联动,需要经过ssh验证。
首先我们需要在gitlab上绑定jenkins服务器的ssh公钥,因为是在同一台服务器上,所以就自己给自己绑定,这里我们使用的是root用户的公私钥,切记生产环境是不允许随便用root的
[root@auto-web ~]# ssh-keygen -t rsa
[root@auto-web ~]# cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC36u5+BYWoDTKnxMquq1YgvyBAMobCwq8N7uNdCbQ2r4dvmnZXJiFfUdlVeCEzE3ntmkq8YomSXpy44pmSCqzwxmEU9+zgxFoDCww7QF8QtXBUBqW/hJcF5ycb8S5qngiWii2Ebuvh7wDcaKcntgr0ay9eFcWgUEjdgkT/XctN72cgLNqFIVTr3GAyrhWrCwK4h4MTfSF3rOygQB3mFlUUbZbd5GpiCT1vZ9ZBGHyjfL1ZM6v/0dhek4NFueXsGUKsefOxAH4JJ60Gjbh1sZq+qT7gN4QzbQLQPOOzuG/1NBOmY1RtrOg/11fQuJNP53o+fd1ZmU969bVLPq4RIUq7 root@auto-web
//添加完成之后,在gitlab中,创建一个项目。
//可以使用git命令,在本地将项目clone下来验证查看
[root@auto-web ~]# git clone [email protected]:root/test.git
Cloning into 'test'...
The authenticity of host '192.168.1.22 (192.168.1.22)' can't be established.
ECDSA key fingerprint is SHA256:J+7vWuPOGQlIoF1XkiWMBk+74lVWEAnfU1+YOJLzRVk.
ECDSA key fingerprint is MD5:2c:b8:cf:c5:1e:37:19:4d:7c:99:5b:8b:30:9c:8f:26.
Are you sure you want to continue connecting (yes/no)? yw^Hes
Please type 'yes' or 'no': yes
Warning: Permanently added '192.168.1.22' (ECDSA) to the list of known hosts.
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (3/3), done.
[root@auto-web ~]# ls
anaconda-ks.cfg autoweb images test
[root@auto-web ~]# cat test/index.html
print "Hello k8s!"
//此时,服务验证没有问题之后,在jenkins上操作
//此时如果直接添加会报错。添加完成后提示本地连接不了,因为gitlab默认设置不允许向自己发送web hook
往下要修改gitlab & jenkins的设置。
//开启jenkins的匿名访问功能,否则会报403
//现在再重新添加和jenkins的联动
//测试和jenkins的连通性
//报200正常。
//当我们执行测试,其实就是手动触发了一下我们部署的shell脚本,这时我们的shell脚本是不正确的,但这次测试可以帮组我们看到脚本运行结果。
//可以根据输出结果优化脚本。
//这里我们最后需要做的一个ssh是关于jenkins,注意,这里是从autoweb向master节点做免密登录。
[root@auto-web ~]# ssh-copy-id [email protected]
//这里jenkins运行脚本是使用的是没有任何权限的jenkins用户,修改用户为:root,重启jenkins
[root@auto-web ~]# vim /etc/sysconfig/jenkins
...
29 JENKINS_USER="root"
...
最终脚本
#!/bin/bash
backupcode="/data/backcode/$JOB_NAME/$BUILD_NUMBER"
mkdir -p $backupcode
chmod 644 "$JENKINS_HOME"/workspace/"$JOB_NAME"/*
rsync -acP "$JENKINS_HOME"/workspace/"$JOB_NAME"/* $backupcode
echo From 192.168.1.20:5000/httpd:v1 >"$JENKINS_HOME"/workspace/Dockerfile
echo COPY ./"$JOB_NAME"/* /usr/local/apache2/htdocs/ >> "$JENKINS_HOME"/workspace/Dockerfile
docker rmi 192.168.1.20:5000/httpd:v1
docker build -t 192.168.1.20:5000/httpd:v1 /"$JENKINS_HOME"/workspace/.
docker push 192.168.1.20:5000/httpd:v1
ssh [email protected] kubectl delete deployment myapp
ssh [email protected] kubectl apply -f /opt/autoweb/myapp.yaml
ssh [email protected] kubectl apply -f /opt/autoweb/mysvc.yaml
//根据镜像的默认下载策略判断,刚开始部署的Deployment资源,它使用的镜像未签为v1,所以他的默认下载策略为: IfNotPresent,所以,要想使镜像实时更新,需要将myapp.yaml这个文件内的镜像下载策略改为:Always。
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: myapp
spec:
replicas: 2
template:
metadata:
labels:
app: httpd
spec:
containers:
- name: myapp
image: 192.168.1.20:5000/httpd:v1
imagePullPolicy: Always
最终测试
现在浏览器访问http://192.168.1.20:30039/
他会自动构建
在查看
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试(123.com)</title>
</head>
<body>
<h1>xxx测试</h1>
<p>123456789</p >
</body>
</html>