通过jenkins交付微服务到kubernetes

网友投稿 243 2022-10-29

通过jenkins交付微服务到kubernetes

随着Kubernetes的遍地开花,Kubernetes的优势可以说是深入人心,很多企业也是利用Kubernetes,来实现更高效的交付和更好地提高我们的资源使用率,推动标准化,适应云原生。

随着Kubernetes和云原生加速企业产品落地,现在总结以下几点

另外就是交付spring cloud到k8s之前说一下微服务的概念

什么是微服务?

早在2011年的5月份在威尼斯的一个架构研讨会上微服务的概念就被人提起了,当时的参会者对它的描述只是一种通用的软件并没给出明确的定义是什么,之后随着技术的不断发展,在2014年詹姆斯里维斯以及它的伙伴马丁福勒在它的微博中发表了一篇有关于微服务特点的文章,对微服务进行了全面的阐述,之后微服务就走进了我们的视野cloud微服务体系的组成

服务发现 (Eureka,Cousul,zookeeper)也就是注册中心最为微服务必不可少的中央管理者,服务发现的主要职责就是将其它的微服务模块进行登记与管理,这就相当于生活中来了一家公司,去工商局进行登记一样的道理,在服务发现中它主包含了三个子模块,分别是eureka,cousul,zookeeper,这些spring cloud底层都支持的注册中心,一般常用的是eureka和consul,那么微服务构建好了之后,那么微服务与微服务直接怎么进行服务直接的通信,或者微服务遇到了故障无法达到请求的话(hystrix/ribbon/openfeign)另外就是路由与过滤主要是针对对外接口的暴露的,这里主要涉及zuul,spring cloud gateway,这两个组件主要为外部的调用者比如其他的系统和我们的微服务进行通信的时候,由外到内是怎么彼此进行访问的,那么这些就是由这两个组件进行完成的配置中心就是存放我们应用程序配置的地方,可能我们有上百个应用程序,那么每个应用程序都是一个微服务,那么就会产生一个很严重的问题,就是这些配置文件放在什么地方比如每个服务下都放一个xml,或者yml,维护起来是非常不方便的,因为改一个参数,就要对所有的应用进行调整,为了解决这个问题配置中心就出现了,相当于又提供了一个微服务把我们应用中所有的配置文件,都放在了配置中心中,那么其他应用都是通过配置中心来获取到这些配置文件的而不是我们要这个这个配置文件放到每个程序中,这样的好处就是可以将我们的配置文件进行集中的管理,只需要改一个地方所有地方都能生效

spring cloud微服务组成

消息总线,spring cloud stream或者spring cloud bus就跟我们的消息mq差不多就是我们发布一个信息,到我们队列里面由其他的微服务或者其他的应用进行获取提供了系统与系统之间或者微服务与微服务之间的消息传递过程,这个中间增加了一个额外的东西叫做消息总线,具体的消息总线可以是mq或者是redis,不同的厂商实现了不同的实现安全控制是针对我们安全的管理,在我们传统网站开发的时候,应用的访问控制有授权的可以使用这个功能,没有授权的就无法进行访问,安全控制在spring cloud中也是存在的提供了AUTH2.0方案的支持,链路监控就是对我们消息传递的过程要进行统筹和监控,比如系统中有10个微服务,而这10个微服务是彼此依赖的,第一个微服务它是底层最基础的用户管理而第二个微服务是基于用户管理开发一个权限管理,在往上是应用管理,应用系统的扩展,每一个微服务之间彼此之间进行依赖在顶层我们进行调用的时候会安装微服务的调用顺序一级一级消息往下传递,这样做有一个问题来了,如果中间有个环节出现了问题,没有响应服务我们在使用的角度当前我们的请求失败了,但是具体的环节不知道是在那一块出现问题,那么链路监控就是让我们快递定位消息传递过程哪个阶段进行出错,有助于我们问题的排查spring cloud cli命令行工具,来实现我们开发来实现的一些功能,spring cloud cluster是对我们集群管理的一个辅助工具

现在去交付微服务到k8s中举个demo仅供参考

一、发布流程设计 二、准备基础环境 三、在Kubernetes中部署jenkins 四、jenkins pipeline及参数化构建 五、jenkins在k8s中动态创建代理 六、自定义构建jenkins-slave镜像 七、基于kubernetes构建jenkins ci系统 八、pipeline集成helm发布spring cloud微服务

使用jenkins自动话发布的流程是这么样的?显然这种方式发布多个微服务很不高效,所以就需要ci/cd,这么一说,那么有jenkins了,怎么将这种方式自动化起来,减少人工的干预。上面那张图,首先是这样的,开发将代码推送到git仓库中,通过commit提交上去,然后再到jenkins了,它负责的任务就是checkout代码的拉取,code compile代码的编译,docker build &push ,镜像的构建与推送到harbor仓库中,然后deploy,将应用部署到k8s中,这里呢由于可能是很多的微服务,那么我们就需要模版的代替,去发布微服务,这里我们就会需要用到它原生的helm微服务发布工具来到k8s当中去deploy,发布到测试环境中去,然后通过slb提供一个统一的出口,发布出去,中间产生的镜像也都会存放到harbor仓库中,当QA测试没有问题,这个镜像也就可以去发布生产环境中。

为什么需要jenkins slave架构另外这里还提到了一个jenkins,slave的一个架构,主要的是可以动态的可以完成这些任务,动态的去调度一个机器和一个pod来完成这几步的任务,因为当任务很多时,也就是都在jenkins master去做,显然任务多了负载就高了,所以就需要引入这个slave去解决这个问题。

二、准备基础环境,所需的组件来完成我们流程的发布

1、k8s——(ingress controller、coredns、pv自动供给) 2、harbor,并启用chart存储功能,将我们的helm打成chart并存放到harbor中 3、helm-v3 工具,主要来实现模版化,动态的将应用渲染安装与卸载,更好的去管理微服务 4、gitlab代码仓库,docker-compose实现 5、mysql,微服务数据库 6、在k8s中部署eureka(注册中心)

1、检查k8s基础组件的环境是否安装:1、默认我的这个基础的组件都是安装好的,ingress 和coredns

[root@k8s-master1 ~]# kubectl get pod -A NAMESPACE NAME READY STATUS RESTARTS AGE ingress-nginx nginx-ingress-controller-2vs56 1/1 Running 0 5h3m ingress-nginx nginx-ingress-controller-586gw 1/1 Running 0 167m ingress-nginx nginx-ingress-controller-pxztr 1/1 Running 0 5h3m ingress-nginx nginx-ingress-controller-qp266 1/1 Running 0 5h6m kube-system coredns-59fb8d54d6-vjn62 1/1 Running 0 5h7m kube-system kube-flannel-ds-amd64-2hnkf 1/1 Running 0 5h7m kube-system kube-flannel-ds-amd64-2smpl 1/1 Running 0 5h7m kube-system kube-flannel-ds-amd64-jbrv4 1/1 Running 0 167m kube-system kube-flannel-ds-amd64-jsxdf 1/1 Running 0 5h7m kubernetes-dashboard dashboard-metrics-scraper-566cddb686-mddlb 1/1 Running 0 5h7m kubernetes-dashboard kubernetes-dashboard-c4bc5bd44-wpgc7 1/1 Running 0 5h7m

1.2、k8s pv的自动供给,这里当然也可以使用Ceph持久化存储,由于我的测试环境配置不够,先拿NFS对有状态的应用实现自动的PV供给。先准备一台NFS服务器为K8S提供存储支持

[root@k8s-node3 ~]# yum -y install nfs-utils 创建共享的目录 [root@k8s-node3 ~]# mkdir /ifi/kubernetes -p [root@k8s-node3 ~]# cat /etc/exports /ifi/kubernetes 10.4.7.0/24(rw,no_root_squash) [root@k8s-node3 kubernetes]# systemctl start nfs [root@k8s-node3 ~]# systemctl enable nfs 并且要在每个Node上安装nfs-utils包,用于mount挂载时用。 [root@k8s-master1 ~]# mount -t nfs 10.4.7.22:/ifi/kubernetes /mnt 由于K8S不支持NFS动态供给,还需要先安装nfs-client-provisioner插件 修改nfs的服务端地址和挂载的目录,这是我nfs-client的地址,如果借鉴的需要将id_rsa.pub给我 git clone git@gitee.com:zhaocheng172/nfs-client.git [root@k8s-master1 nfs-client]# kubectl get pod NAME READY STATUS RESTARTS AGE busybox 1/1 Running 0 35m nfs-client-provisioner-86dff449dd-68ngn 1/1 Running 0 106s

2、镜像仓库Harbor2.1安装docker与docker-compose

# wget -O /etc/yum.repos.d/docker-ce.repo # yum install docker-ce -y # systemctl start docker # systemctl enable docker

docker-compose的下载地址:https://docs.docker.com/compose/install/ curl -L -s`-`uname -m` -o /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose

2.2 解压离线包部署下载地址:tar zxvf harbor-offline-installer-v1.10.1.tgz # cd harbor # vi harbor.yml hostname: harbor.zhaocheng.com # ./prepare # ./install.sh --with-chartmuseum # docker-compose ps

# cat /etc/docker/daemon.json { "registry-mirrors": ["https://38vve9ja.mirror.aliyuncs.com"], "insecure-registries": ["harbor.zhaocheng.com"] } # systemctl restart docker

3、helm-v3 工具3.1安装helm工具

[root@k8s-master1 helm]# wget https://get.helm.sh/helm-v3.0.0-linux-amd64.tar.gz [root@k8s-master1 helm]# tar xf helm-v3.0.0-linux-amd64.tar.gz [root@k8s-master1 helm]# mv linux-amd64/helm /usr/bin/ [root@k8s-master1 helm]# helm --help

3.2 安装push插件

# git clone https://gitee.com/zhaocheng172/helm-push.git # tar zxvf helm-push_0.7.1_linux_amd64.tar.gz # mkdir -p /root/.local/share/helm/plugins/helm-push # chmod +x bin/* # mv bin plugin.yaml /root/.local/share/helm/plugins/helm-push 3.3 添加repo # helm repo add --username admin --password Harbor12345 myrepo 推送与安装Charthelm安装好有默认的模版,那么我们先使用它的进行生成一个chart包,用于我们测试推送到我们的Harbor仓库中,这个Chart是当我们部署完之后,官方默认自带的模版,小的demo,install之后是一个Nginx的应用

[root@k8s-master ~]# mkdir chart-test [root@k8s-master ~]# cd chart-test/ [root@k8s-master chart-test]# helm create test [root@k8s-master chart-test]# helm install test01 test NAME: test01 LAST DEPLOYED: Sat Mar 14 17:10:20 2020 NAMESPACE: default STATUS: deployed REVISION: 1 NOTES: 1. Get the application URL by running these commands: export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=test,app.kubernetes.io/instance=test01" -o jsonpath="{.items[0].metadata.name}") echo "Visit to use your application" kubectl --namespace default port-forward $POD_NAME 8080:80

这里是直接使用他们自己写的模版创建的pod查看这个pod已经正常运行,而这个test01是我们自己起的名字,这个部署的时候一般是我们的微服务的名称要是去加个--dry-run的话就是预先执行,一般看看这个模版有没有都执行成功,有没有问题

[root@k8s-master chart-test]# helm install test02 --dry-run test/ [root@k8s-master chart-test]# kubectl get pod NAME READY STATUS RESTARTS AGE nfs-client-provisioner-564dddddd6-dgv26 1/1 Running 8 26h test01-f7f8c5759-zv8kf 1/1 Running 0 31s 没什么问题的话我们就需要将这个chart达成一个包,以便下次的时候再用 [root@k8s-master chart-test]# helm package test/ Successfully packaged chart and saved it to: /root/chart-test/test-0.1.0.tgz [root@k8s-master chart-test]# ls test test-0.1.0.tgz 推送到我们的镜像harbor仓库中 [root@k8s-master chart-test]# helm push test-0.1.0.tgz --username=admin --password=Harbor12345 http://192.168.30.27/chartrepo/library Pushing test-0.1.0.tgz to http://192.168.30.27/chartrepo/library... Done.

[root@k8s-master ~]# helm install test02 test-0.1.0.tgz NAME: test02 LAST DEPLOYED: Sat Mar 14 17:49:00 2020 NAMESPACE: default STATUS: deployed REVISION: 1

4、部署gitlab,这里分别我整理了两个方法来部署gitlab,第一个是英文版页面,第二个是中文版页面4.1#安装gitlab,建议2c2g+

yum -y install policycoreutils openssh-server openssh-clients postfix #修改postfix sed -i 's/inet_interfaces = localhost/inet_interfaces = all/g' /etc/postfix/main.cf sed -i 's/inet_protocols = all/inet_protocols = ipv4/g' /etc/postfix/main.cf sudo systemctl enable postfix sudo systemctl start postfix curl -sS | sudo bash sudo EXTERNAL_URL="yum install -y gitlab-ce gitlab配置文件路径 /etc/gitlab/gitlab.rb external_url 'http://10.4.7.200:9999' # 端口可以变动 gitlab-ctl reconfigure ,这个初始化配置比较久 # gitlab启动初始化操作 # gitlab-ctl restart 重启

4.2、使用docker-compose部署中文版Gitlab1)首先在一台新的服务器上安装docker-ce,并使用docker加速器,使用中科大的加速器/阿里云加速器2)部署安装docker-compose3)安装gitlab,编辑docker-compose文件

[root@localhost ~]# mkdir gitlab [root@localhost ~]# cd gitlab/ [root@localhost gitlab]# vim docker-compose.yml yml地址:git@gitee.com:zhaocheng172/gitlab-docker-compose.yml.git 4)创建相关目录,config存储gitlab配置信息,data 存储数据库,logs存储日志 [root@localhost gitlab]# mkdir -p /opt/gitlab/{config,data,logs} [root@localhost gitlab]# ls -l /opt/gitlab/ total 0 drwxr-xr-x. 2 root root 6 Mar 14 19:44 config drwxr-xr-x. 2 root root 6 Mar 14 19:44 data drwxr-xr-x. 2 root root 6 Mar 14 19:44 logs 5)拉取gitlan中文版镜像,这个提前可以拉取下来,不然执行docker-compose需要等待 [root@localhost gitlab]# docker pull zhaocheng172/gitlab-ce-zh:latest 6)启动gitlab容器 在启动前,先要修改宿主机的22端口,因为宿主机占用了22端口,所以启动容器会失败,因为映射不过来,修改如下: vim /etc/ssh/sshd_config 默认在第17行修改:Port 2222 修改后,重启sshd:systemctl restart sshd [root@localhost gitlab]# netstat -anpt | grep 22 tcp 0 0 0.0.0.0:2222 0.0.0.0: LISTEN 31889/sshd tcp6 0 0 :::2222 ::: LISTEN 31889/sshd 7)正式启动 [root@localhost gitlab]# docker-compose up -d Creating network "gitlab_default" with the default driver Creating gitlab ... done [root@localhost gitlab]# docker-compose ps Name Command State Ports --------------------------------------------------------------------------------------------------------------- gitlab /assets/wrapper Up (health: starting) 0.0.0.0:22->22/tcp, 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp 8)设置gitlab开机启动 [root@localhost gitlab]# chmod +x /etc/rc.local [root@localhost gitlab]# ls -l /etc/rc.local lrwxrwxrwx. 1 root root 13 Mar 14 12:57 /etc/rc.local -> rc.d/rc.local [root@localhost gitlab]# echo "cd /root/gitlab && docker-compose up -d" >> /etc/rc.local 9)gitlab管理页面 输入配置的ip或者域名 这里我是使用的域名登陆 另外就是如果这台服务开启了selinux的话,要是重启机器的话会导致ssh连接不上,解决方法要不就是关闭selinux,要不就是开启支持的端口,默认docker-compose部署gitlab官方推荐的是修改22端口,所以要修改一些配置 或者要不就是直接 #sed -i 's/enforcing/disabled/' /etc/selinux/config # 永久 # 安装修改工具 yum -y install policycoreutils-python # 查看selinux中的ssh的端口,输出为 22 semanage port -l | grep ssh # 新增端口 semanage port -a -t ssh_port_t -p tcp 2222 由于我是拿测试机做的所以我需要将这个写入我windows的C:\Windows\System32\drivers\etc\hosts 192.168.30.27 harbor.zhaocheng.com 192.168.30.28 gitlab.zhaocheng.com docker-compose重启命令,这个是需要在docker-compose.yml下才能重启 docker-compose restart 用户:root,首次登陆需要手动设置密码

现在我们先克隆一下我们这个ms的仓库到本地来设置git全局设置,这里我们需要我们的用户也就是我们gitlab去登录这个平台的账号,提交代码的时候我们需要达到master分支,其他的开发去使用这个gitlab的时候我们需要给他去创建一个用户,也就是在gitlab去创建的,以便它们提交代码到仓库中[root@k8s-master1]# mkdir ms[root@k8s-master1]# cd ms[root@k8s-master1 ms]# git config --global user.name "zhaocheng"[root@k8s-master1 ms]# git config --global user.email "zhaocheng"

看到只有一个仓库。里面是空的,这个地方需要输入我们gitlab的账号与密码,这样的话才能有访问控制,让你去拉这个代码

[root@k8s-master ms]# git clone http://192.168.30.28/root/ms.git Cloning into 'ms'... Username for 'root Password for ' warning: You appear to have cloned an empty repository.

当我们git clone之后这里有遗留下的空目录,因为这是刚才我们去测试去拉的代码,如有代码的话就拉取下来了

[root@k8s-master ms]# ls ms

现在将开发写的代码解压之后,将里面的服务都拷贝到刚才我们拉取代码遗留的空仓库中

[root@k8s-master ms]# ls ms simple-microservice-master simple-microservice-master.zip [root@k8s-master ms]# cp simple-microservice-master/* -rf ms [root@k8s-master ms]# cd ms [root@k8s-master ms]# ls basic-common eureka-service k8s lombok.config pom.xml product-service stock-service db gateway-service LICENSE order-service portal-service README.md

提交缓存区[root@k8s-master1 ms]# git add .

使用commit打个tag格式git commit -a -m "提交添加的注释信息"或者写成先添代码

[root@k8s-master1 ms]# git commit -m "all"

推送到gitlab中

[root@k8s-master ms]# git push origin master Username for 'root Password for ' Counting objects: 515, done. Delta compression using up to 2 threads. Compressing objects: 100% (411/411), done. Writing objects: 100% (515/515), 15.62 MiB | 17.78 MiB/s, done. Total 515 (delta 60), reused 0 (delta 0) remote: Resolving deltas: 100% (60/60), done. To http://192.168.30.28/root/ms.git * [new branch] master -> master

现在已经将代码推送到gitlab中

另外就是分支说明master主分支,有且只有一个release线上分支,一般为线上版本,线上版本发布后,会将release分支合并到masterdevelop 开发分支,通常给测试部署环境或者打包的分支,每个人在自己的分支上开发完成后,向develop分支合并feature 通常为一个功能分支或者个人分支,一般有很多个,通常合并完成后会删除

5、mysql 微服务数据库导入数据库到Mysql

[root@k8s-master1 ~]# cd simple-microservice-dev3 [root@k8s-master1 simple-microservice-dev3]# ls basic-common gateway-service lombok.config portal-service stock-service db k8s order-service product-service eureka-service LICENSE pom.xml README.md [root@k8s-master1 simple-microservice-dev3]# cd db/ [root@k8s-master1 db]# ls order.sql product.sql stock.sql [root@k8s-master1 db]# scp * root@192.168.30.24:~

这里呢之前遇到一个问题当部署gitlab之后如果是使用的docker去部署的gitlab默认的22端口改成2222端口之后当用其他服务器进行scp或者ssh登录的时候就会显示拒接

[root@k8s-master db]# scp order.sql root@192.168.30.28:/root/ Permission denied (publickey). lost connection

这里我安装了一个mariadb的实例进行测试

[root@harbor-mysql-gitlab ~]# yum install mariadb mariadb-server mariadb-devel [root@harbor-mysql-gitlab ~]# systemctl start mariadb [root@harbor-mysql-gitlab ~]# netstat -anpt |grep 3306 tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 6226/mysqld

修改mariadb的密码,默认没有密码

[root@harbor-mysql ~]# mysql -u root -p MariaDB [(none)]> set password for root@localhost = password('666666'); MariaDB [(none)]> flush privileges;

创建数据库

MariaDB [(none)]> create database tb_order; MariaDB [(none)]> create database tb_product; MariaDB [(none)]> create database tb_stock; 进入order数据库,把我们根目录下的sql语句导入我们的数据库中 MariaDB [(none)]> use tb_order; MariaDB [tb_order]> source /root/order.sql; 进入product数据库,把我们根目录下的sql语句导入我们的数据库中 MariaDB [tb_order]> use tb_product ; MariaDB [tb_product]> source /root/product.sql 进入stock数据库,把我们根目录下的sql语句导入我们的数据库中 MariaDB [tb_product]> use tb_stock ; Database changed MariaDB [tb_stock]> source /root/stock.sql; MariaDB [tb_stock]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | tb_order | | tb_product | | tb_stock | | test | +--------------------+ 7 rows in set (0.00 sec)

6、将eureaka集群部署到k8s中

[root@k8s-master ~]# yum install java-1.8.0-openjdk maven -y 软件包 1:java-1.8.0-openjdk-1.8.0.222.b10-0.el7_6.x86_64 已安装 将eureka-service进行maven编译可以执行的jar包 [root@k8s-master simple-microservice-dev1]# mvn clean package -D maven.test.skip=true

会在target下面生成jar包

[root@k8s-master eureka-service]# ls Dockerfile pom.xml src target

将这个eureka制作成一个镜像,然后编排yaml文件好让这个容器运行起来

[root@k8s-master1 eureka-service]# cat Dockerfile FROM java:8-jdk-alpine RUN apk add -U tzdata && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime COPY ./target/eureka-service.jar ./ EXPOSE 8888 CMD java -jar -Deureka.instance.hostname=${MY_POD_NAME}.eureka.ms /eureka-service.jar

构建并上传到我们的harbor仓库中,[root@k8s-master eureka-service]# docker build -t eureka .

这里需要我们去我们的Harbor创建一个项目仓库的名称,这里是创建的microservice,并达成推送我们镜像的tag名称,这样推送的时候会直接找我们镜像仓库的地址[root@k8s-master eureka-service]# docker tag eureka 192.168.30.27/microservice/eureka:latest上传到我们的harbor上

这里需要登录一下我们的harbor仓库,才能上传

[root@k8s-master ~]# docker login 192.168.30.27 Username: admin Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded [root@k8s-master eureka-service]# docker push 192.168.30.27/microservice/eureka:latest

创建k8s登录harbor信息认证,这里并提前创建好命名空间ms,这样k8s才能到harbor仓库拉取镜像有这个secret先创建一个ms的命名空间

[root@k8s-master eureka-service]# kubectl create ns ms namespace/ms created [root@k8s-master eureka-service]# kubectl get ns NAME STATUS AGE default Active 68m ingress-nginx Active 55m kube-node-lease Active 68m kube-public Active 68m kube-system Active 68m ms Active 4s [root@k8s-master k8s]# kubectl create secret docker-registry registry-pull-secret --docker-server=192.168.30.27 --docker-username=admin --docker-password=Harbor12345 --docker-email=admin@zhaocheng.com -n ms

查看状态

[root@k8s-master ~]# kubectl get pod,svc,ing -n ms NAME READY STATUS RESTARTS AGE![](https://s4./images/blog/202003/28/0c07c95b7ce22d59b778082427c7d2bd.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=) pod/eureka-0 1/1 Running 1 16h pod/eureka-1 1/1 Running 0 16h pod/eureka-2 1/1 Running 1 16h

创建一个service-account绑定到rbac里面,rbac主要就是设置一些权限让jenkins访问到k8s,service-connout主要是让pod访问到apiserver,它去apiserver调度创建pod这是我jenkins的地址,如果借鉴的需要将id_rsa.pub给我

git clone git@gitee.com:zhaocheng172/jenkins-k8s.git [root@k8s-master1 jenkins]# ls deployment.yml ingress.yml rbac.yml service-account.yml service.yml

deployment参数详解:主要来部署jenkins的容器的配置

serviceAccountName: jenkins 使用service-account创建的名字 image: jenkins/jenkins:lts 使用官方长期维护lts镜像 - containerPort: 8080 jenkins ui的访问的端口 - containerPort: 50000 slave访问master访问jenkins所使用的端口 volumeMounts: - name: jenkins-home mountPath: /var/jenkins_home 说到jenkins持久化数据,在jenkins中需要持久化的目录就是它的工作目录,也就是它所产生有状态的数据都放在这个/var/jenkins_home下 volumes: - name: jenkins-home persistentVolumeClaim: claimName: jenkins-home 而持久化的这个目录也都会落到这个pvc这个卷 name: jenkins-home spec: storageClassName: "managed-nfs-storage" accessModes: ["ReadWriteOnce"] 而pvc这里就是我们创建使用的storageclass自动供给来提供的pv,申请5G,设置都可读写

查看创建的storage class

[root@k8s-master1 jenkins]# kubectl get sc NAME PROVISIONER AGE managed-nfs-storage fuseim.pri/ifs 22h

service参数:这里主要就是使用nodeport去开放一个端口,另外一般生产环境都使用ingress,ingress需要关联service,还要使用nginx做反向代理,将这个域名通过slb发布出去[root@k8s-master1 jenkins]# kubectl apply -f .

四、jenkins pipeline及参数化构建jenkins pipeline是一套插件,支持在jenkins中实现集成和持续交付管道;pipeline通过特定语法对简单到复杂的传输管道进行建模;

[root@k8s-master jenkins]# kubectl logs jenkins-7d5fbd857d-tmwbm 6e22df63432f474f863dc07c9d291967

[root@k8s-node3 ~]# ll /ifi/kubernetes/default-jenkins-home-pvc-0d67f7f5-2b31-4dc8-aee2-5e7b9e0e7e19/jobs/test/ 总用量 8 drwxr-xr-x 3 1000 1000 50 1月 13 11:36 builds -rw-r--r-- 1 1000 1000 1021 1月 13 11:36 config.xml -rw-r--r-- 1 1000 1000 2 1月 13 11:36 nextBuildNumber

测试一个hello的pipeline的语法格式

pipeline { agent any stages { stage('Build') { steps { echo "hello" } } stage('test') { steps { echo "hello" } } stage('deploy') { steps { echo "hello" } } } }

有了这些方式,就可以将这些不同点通过里面的agent和shell脚本来处理了,写pipeline参数化构建就是满足更多的一个需求,能适配更多的项目,能让人工干预的做一些复杂的任务

五、jenkins在k8s中动态创建代理如何在k8s中动态的创建slave代理?当完成这些任务之后考虑的问题,这些任务都是在jenkins机器去完成的,那么这个也肯定是在pod中去运行的,因为我们的是将jenkins部署在pod中的,也就是这当前的这个节点去完成的拉取代码,编译,构建镜像,发布,那么可能会遇到一个问题,那么项目很多,每天做持续集成很高,十几次甚至上百次,面对这样的一个需求量,当前的这个pod是很难支撑的,就好比刚才的job,有十几个人去运行,来运行不同的服务,本来是可以几分钟完成的事情,最后导致10多分钟才执行完成,这样的话就很耽误项目进度了,所以就需要使用jenkins的master-slave架构了,而master只负责调度分配,slave来完成这些job任务,而slave是由物理机或者虚拟机存在的,和master保持通信,只要有任务就下发到slave节点,这样就解决了单jenkins的性能问题了

[root@k8s-node3 updates]# sed -i 's/default.json && \ sed -i 's/default.json

在jenkins页面上restart,重启jenkins生效

六、自定义构建jenkins-slave镜像jenkins slave制作这个镜像看需要什么?1、需要什么开发语言?因为slave去完成的需要代码的编译,如果是java的语言,那么就需要maven的环境,如果是go就需要去用go去编译,所以开发语言不一样,slave所做的事环境也不一样2、额外环境,比如docker,需要打镜像对微服务,以及推送到镜像仓库都需要docker的环境,还会使用helm,helm是直接将服务部署到k8s中。

比如就拿java项目为例,一般微服务也都是使用java去写的代码的编译,一般使用比较多的就是maven,这个maven还依赖jdk,打包镜像需要docker,我们需要使用helm去做持续部署,所以这也就是这个镜像里面需要封装的依赖

另外还有一点,这个镜像怎么去做为一个slave去存在呢,传统的在页面添加一个就可以了,当连接的时候,会连接到slave节点帮你启动一个agent,也就是下发一个jar包,这个agent就可以直接和master去交互了,那么将这个jar包kill掉,这个slave也就是不可用状态了,所以它们直接的一个交互就是由自己实现的一个程序去完成的,每个slave上面会有一个agent,master与agent去交互,agent去完成这个job任务,那么这个镜像里面也得需要包含这个agent这个jar包,传统的方式会自动的帮你去安装了,但是镜像的还得自己去加上,加上之后才能去连接jenkins,master才能去下发任务

[root@k8s-master1 jenkins-slave]# ls Dockerfile helm jenkins-slave kubectl settings.xml slave.jar

这个jenkins-slave是一个脚本主要来启动这个slave.jar,那么这个还需要一个docker环境,本身这个pod就是以docker container启动的,那么这个pod也就可以做数据卷挂载了,因为这个pod是在每个node上去启动的,每个node上都有docker,那么直接就可以把每个node上的docker挂载到容器中就可以了,所以这就用到了一个docker in docker,这个容器里面又有了一个docker的环境,所以我们需要写数据卷将它挂载进来,还有kubectl这个命名,一般主要来查看pod的一些状态,而且使用这个命令来完成k8s的各种各样的操作,但是需要它这个命令,只需要它连接k8s的认证信息,因为k8s有它的鉴权现在将这个镜像打包成镜像推送到镜像仓库中

[root@k8s-master1 jenkins-slave]# cat Dockerfile FROM centos:7 RUN yum install -y java-1.8.0-openjdk maven curl git libtool-ltdl-devel && \ yum clean all && \ rm -rf /var/cache/yum/* && \ mkdir -p /usr/share/jenkins COPY slave.jar /usr/share/jenkins/slave.jar COPY jenkins-slave /usr/bin/jenkins-slave COPY settings.xml /etc/maven/settings.xml RUN chmod +x /usr/bin/jenkins-slave COPY helm kubectl /usr/bin/ ENTRYPOINT ["jenkins-slave"]

构建镜像的时候可以直接写harbor的地址加镜像的名称,这样直接可以push,不然构建完还得打个tag

[root@k8s-master jenkins-slave]# docker build . -t 192.168.30.27/library/jenkins-slave:jdk-1.8 [root@k8s-master jenkins-slave]# docker push 192.168.30.27/library/jenkins-slave

现在就可以去测试能不能动态的去创建jenkins-slave,需要将pipeline这个脚本能去调用刚才我们配置的k8s的插件jenkins官方地址给出了相关的pipeline调用k8s的插件的用法github地址:ci系统现在去动态的在pipeline去引用并创建一个slave的镜像,使用pipeline在k8s去运行这个pod,然后将这个pod发布我们的任务,刚才我们是先安装的插件,以对jenkins可以实现slave的代理,可以正常去交互,又制作了我们的slave的镜像,将java所需的配置也都封装在这个slave里面这样的话,我们就可以采用这个slave来完成下发的任务了,而master只作为一个管理节点给他们下发任务到slave上这就是我们的pipeline,现在目前是可以使用我们这个slave这个镜像来发布任务

安装pipeline插件

pipeline { agent { kubernetes { label 'jenkins-slave' yaml """ apiVersion: v1 kind: Pod metadata: name: jenkins-slave spec: containers: - name: jnlp image: "192.168.30.27/library/jenkins-slave:jdk-1.8" """ } } stages { stage('Build') { steps { echo "hello" } } stage('test') { steps { echo "hello" } } stage('deploy') { steps { echo "hello" } } } }

#!/usr/bin/env groovy // 所需插件: Git Parameter/Git/Pipeline/Config File Provider/kubernetes/Extended Choice Parameter // 公共 def registry = "192.168.30.27" // 项目 def project = "microservice" def git_url = "http://192.168.30.28/root/ms.git" def gateway_domain_name = "gateway.zhaocheng.com" def portal_domain_name = "portal.zhaochengr.com" // 认证 def image_pull_secret = "registry-pull-secret" def harbor_registry_auth = "e5402e52-7dd0-4daf-8d21-c4aa6e47736b" def git_auth = "a65680b4-0bf7-418f-a77e-f20778f9e737" // ConfigFileProvider ID def k8s_auth = "7ee65e53-a559-4c52-8b88-c968a637051e" pipeline { agent { kubernetes { label "jenkins-slave" yaml """ kind: Pod metadata: name: jenkins-slave spec: containers: - name: jnlp image: "${registry}/library/jenkins-slave-jdk:1.8" imagePullPolicy: Always volumeMounts: - name: docker-cmd mountPath: /usr/bin/docker - name: docker-sock mountPath: /var/run/docker.sock - name: maven-cache mountPath: /root/.m2 volumes: - name: docker-cmd hostPath: path: /usr/bin/docker - name: docker-sock hostPath: path: /var/run/docker.sock - name: maven-cache hostPath: path: /tmp/m2 """ } } parameters { gitParameter branch: '', branchFilter: '.*', defaultValue: '', description: '选择发布的分支', name: 'Branch', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'PT_BRANCH' extendedChoice defaultValue: 'none', description: '选择发布的微服务', \ multiSelectDelimiter: ',', name: 'Service', type: 'PT_CHECKBOX', \ value: 'gateway-service:9999,portal-service:8080,product-service:8010,order-service:8020,stock-service:8030' choice (choices: ['ms', 'demo'], description: '部署模板', name: 'Template') choice (choices: ['1', '3', '5', '7'], description: '副本数', name: 'ReplicaCount') choice (choices: ['ms'], description: '命名空间', name: 'Namespace') } stages { stage('拉取代码'){ steps { checkout([$class: 'GitSCM', branches: [[name: "${params.Branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]] ]) } } stage('代码编译') { // 编译指定服务 steps { sh """ mvn clean package -Dmaven.test.skip=true """ } } stage('构建镜像') { steps { withCredentials([usernamePassword(credentialsId: "${harbor_registry_auth}", passwordVariable: 'password', usernameVariable: 'username')]) { sh """ docker login -u ${username} -p '${password}' ${registry} for service in \$(echo ${Service} |sed 's/,/ /g'); do service_name=\${service%:*} image_name=${registry}/${project}/\${service_name}:${BUILD_NUMBER} cd \${service_name} if ls |grep biz &>/dev/null; then cd \${service_name}-biz fi docker build -t \${image_name} . docker push \${image_name} cd ${WORKSPACE} done """ configFileProvider([configFile(fileId: "${k8s_auth}", targetLocation: "admin.kubeconfig")]){ sh """ # 添加镜像拉取认证 kubectl create secret docker-registry ${image_pull_secret} --docker-username=${username} --docker-password=${password} --docker-server=${registry} -n ${Namespace} --kubeconfig admin.kubeconfig |true # 添加私有chart仓库 helm repo add --username ${username} --password ${password} myrepo http://${registry}/chartrepo/${project} """ } } } } stage('Helm部署到K8S') { steps { sh """ common_args="-n ${Namespace} --kubeconfig admin.kubeconfig" for service in \$(echo ${Service} |sed 's/,/ /g'); do service_name=\${service%:*} service_port=\${service#*:} image=${registry}/${project}/\${service_name} tag=${BUILD_NUMBER} helm_args="\${service_name} --set image.repository=\${image} --set image.tag=\${tag} --set replicaCount=${replicaCount} --set imagePullSecrets[0].name=${image_pull_secret} --set service.targetPort=\${service_port} myrepo/${Template}" # 判断是否为新部署 if helm history \${service_name} \${common_args} &>/dev/null;then action=upgrade else action=install fi # 针对服务启用ingress if [ \${service_name} == "gateway-service" ]; then helm \${action} \${helm_args} \ --set ingress.enabled=true \ --set ingress.host=${gateway_domain_name} \ \${common_args} elif [ \${service_name} == "portal-service" ]; then helm \${action} \${helm_args} \ --set ingress.enabled=true \ --set ingress.host=${portal_domain_name} \ \${common_args} else helm \${action} \${helm_args} \${common_args} fi done # 查看Pod状态 sleep 10 kubectl get pods \${common_args} """ } } } }

pipeline解析1、首先去安装这几个插件Git Parameter 可以实现动态的从git中获取所有分支Git 拉取代码Pipeline 刚才安装的pipeline,来实现这个pipeline流水线的发布任务Config File Provider 主要可以将kubeconfig配置文件存放在jenkins里,让这个pipeline引用这个配置文件,比如构建的slave镜像里面有kubectl,那么连接k8s肯定需要授权,直接拷贝这个命令肯定不好使,而且像helm -v3版本也是通过kubeconfig来连接k8s-api来部署的任务,这两个命令都是通过kubeconfig去读取的k8s,所以我们需要将这两个命令给他们权限来连接k8s,所以需要准备一个kubeconfig文件,能让这个两个工具可以读到,但是这两个命令都是在slave的pod中,所以我们需要使用这个插件将kubeconfig文件由jenkins来保存,然后再通过jenkins特定的语法让它拿到,让它保存到slave中,形成一个动态的文件,动态的加进去,然后helm,kubectl通过这个文件就能直接连接k8s集群了,这样的好处主要是安全,也可以直接将这个kubeconfig文件打到镜像中,也可以,但是这样也不是很安全,别人一旦拿到这个kubeconfig文件久相当于把kubectl的权限给别人了,可以访问k8s集群了,这样就不安全了,所以我们还是按插件的方式去安装这个,动态的放在jenkins中还是比较好的kubernetes 动态的去创建代理,好让k8s连接到jenkins,可以动态的去伸缩slave节点Extended Choice Parameter 进行对选择框插件进行扩展,可以多选,扩展参数构建,而且部署微服务还需要多选,比如同时发布两个微服务,三个微服务,不可能每发布一个要点一下,这样肯定是不现实的。2、参数含义// 公共def registry = "192.168.30.27" 比如镜像仓库的地址// 项目def project = "microservice" 项目的名称def git_url = " 微服务的gitlab的项目的git地址def gateway_domain_name = "gateway.zhaocheng.com" 微服务里面有几个对外提供服务,指定域名def portal_domain_name = "portal.zhaocheng.com" 微服务里面有几个对外提供服务,指定域名,因为不是所有的微服务都是提供域名的,所以要为需要配置的提供一个域名// 认证def image_pull_secret = "registry-pull-secret" 当helm去部署应用的时候,我们需要拉取去在拉取仓库的镜像与k8s进行认证,那么这个就是在k8s中去创建好的,也就是创建k8s登录harbor信息的一个认证,一般会在yaml中定义imagePullSecrets,镜像拉取的认证可以通过kubectl create secret docker-registry registry-pull-secret --docker-server=192.168.30.27 --docker-username=admin --docker-password=Harbor12345 --docker-email=admin@ooo.com -n ms 命令去创建def harbor_registry_auth = "e5402e52-7dd0-4daf-8d21-c4aa6e47736b" 也就是拉取镜像时需要docker login登录一下才可以拉,一般私有的需要指定这个密钥def git_auth = "a65680b4-0bf7-418f-a77e-f20778f9e737" 这个是拉取git的时候需要指定的认证需要保存一下// ConfigFileProvider IDdef k8s_auth = "7ee65e53-a559-4c52-8b88-c968a637051e" 这就是k8s的认证,这个也就是保存在kubeconfig中这些都是定义的公共的变量,这些变量主要是让脚本适用于一个通用性,将一些变动的值传入进去这样主要可以让项目动态的去适配了

3、动态的在k8s中去创建slave-podpipeline {agent {kubernetes {label "jenkins-slave" 指定标签yaml """kind: Podmetadata:name: jenkins-slave 指定pod的名字spec:containers:

name: jnlp 默认使用jnlpimage: "${registry}/library/jenkins-slave-jdk:1.8" 使用我们封装好的slave的镜像imagePullPolicy: Always 镜像拉取策略,始终拉取镜像仓库的镜像volumeMounts: 挂载的数据卷,我们在构建jenkins-slave镜像的时候,docker需要数据卷挂载 name: docker-cmd 也就是docker in dockermountPath: /usr/bin/docker name: docker-sockmountPath: /var/run/docker.sock name: maven-cache 主要是将容器中maven拉取依赖包的缓存挂载到宿主机的/tmp/m2下,一旦宿主机都具备这个缓存的话,mountPath: /root/.m2 那么以后构建都会先读取缓存,或者也就是可以将这些包放到共享存储里面pvc中去读取,可以在这个yamlvolumes: 中去定义也都可以 name: docker-cmdhostPath:path: /usr/bin/docker 将宿主机上的/var/bin/docker和/var/run/docker.sock 挂载到容器中的目录mountpath:对应目录中 name: docker-sock 这样容器就可以使用docker命令了,hostPath:path: /var/run/docker.sock name: maven-cachehostPath:path: /tmp/m2"""} } 4、参数化构建parameters {gitParameter branch: '', branchFilter: '.', defaultValue: '', description: '选择发布的分支', name: 'Branch', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '', type: 'PT_BRANCH' ###动态的去获取参数extendedChoice defaultValue: 'none', description: '选择发布的微服务', \ ###加了扩展,可以多选发布多个微服务微服务找出我们需要哪些需要人工交互的就是使用的这套微服务都适用于这套chart模版1、微服务名称,以及针对一些服务需要带上域名,另外比如去配置的微服务的名字都是不一样的,这个名字是保证是唯一的,需要使用include,,一般写在_helpers。tpl下,因为我们部署的时候已经拿到微服务的名称了,所以helm起的名字也是微服务的名字,然后再加上公用的标签就区分出来了,另外就是微服务的端口也是不一样的2、端口,每个微服务的端口也都不一3、命名空间 使用helm -n 就可以部署到指定的命名空间了4、副本数 这个本来在helm中是3个副本,我们可以通过传参的形式变成5或者2都可以5、资源的限制,本身这个k8s中的限制是无法满足一个java应用的限制的,一般1.8jdk版本是不兼容的,新的版本是兼容的,所以手动的去指定它的对内存的大小,这个一般在dockerfile启用jar包的时候带入6、chart模版的选择 可能一个项目满足不了一个项目,那么可能就得需要两个模版来实现multiSelectDelimiter: ',', name: 'Service', type: 'PT_CHECKBOX', \value: 'gateway-service:9999,portal-service:8080,product-service:8010,order-service:8020,stock-service:8030'choice (choices: ['ms', 'demo'], description: '部署模板', name: 'Template')choice (choices: ['1', '3', '5', '7'], description: '副本数', name: 'ReplicaCount')choice (choices: ['ms'], description: '命名空间', name: 'Namespace')}

然后需要将这个chart模版添加到repo里

[root@k8s-master1 ~]# helm repo add --username admin --password Harbor12345 myrepo http://192.168.30.27/chartrepo/library "myrepo" has been added to your repositories [root@k8s-master1 ~]# helm repo list NAME URL myrepo ~]# helm push ms-0.1.0.tgz --username=admin --password=Harbor12345 http://192.168.30.27/chartrepo/library Pushing ms-0.1.0.tgz to http://192.168.30.27/chartrepo/library... Done.

最后进行测试发布在pipeline的配置指定发布的服务进行发布查看pod的状态

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:K8S使用deployment 管理Pod以及滚动更新(6)
下一篇:汽车音频接口的使用方法
相关文章

 发表评论

暂时没有评论,来抢沙发吧~