隨着Kubernetes的遍地開花,Kubernetes的優點能夠說是深刻人心,不少企業也是利用Kubernetes,來實現更高效的交付和更好地提升咱們的資源使用率,推進標準化,適應雲原生。html
隨着Kubernetes和雲原生加速企業產品落地,如今總結如下幾點java
1)更快的應用開發與交付 2)自然適合微服務,是微服務和Devops的橋樑 3)可移植性,支持公有云,私有云,裸機,虛擬機 4)標準化的應用開發與發佈:聲明式API和Operator 5)自動化運維:彈性伸縮(HPA),故障自愈,負載均衡,配置管理等
另外就是交付spring cloud到k8s以前說一下微服務的概念node
早在2011年的5月份在威尼斯的一個架構研討會上微服務的概念就被人提起了,當時的參會者對它的描述只是一種通用的軟件並沒給出明確的定義是什麼,以後隨着技術的不斷髮展,在2014年詹姆斯里維斯以及它的夥伴馬丁福勒在它的微博中發表了一篇有關於微服務特色的文章,對微服務進行了全面的闡述,以後微服務就走進了咱們的視野
https://martinfowler.com/articles/microservices.html
這是關於網站的描述
在這個文章中並給出微服務一個明確的定義,微服務實際上是一種軟件的架構風格,是一種將單體架構
拆分爲小的服務進行去開發,每一個服務都運行在本身的進程中,採用的是輕量級的restful或者http進行通訊,而且都是獨立開發獨立部署和測試的,可使用多種語言進行開發python
對於微服務有一個關鍵點叫化整爲零,把一個大的應用卻成一個小的不一樣的應用
好比嘀嘀打車,早期在一個互聯網應用上基本上都是單體架構,不是分佈式的
單體狀況下把不少程序都寫一個程序中,而後一臺服務器對全部服務進行運行,可是隨着併發的提升,這種單體架構顯然承受不了了,這樣的話就須要咱們對咱們軟件的指責進行慢慢的劃分,將其剝離出來,造成一個一個的微服務,也就是多個微服務的模塊造成一個完整的應用,這些都是獨立部署獨立運行的,一個微服務也會運行在一個虛擬機裏面。mysql
服務發現 (Eureka,Cousul,zookeeper)
也就是註冊中心最爲微服務必不可少的中央管理者,服務發現的主要職責就是將其它的微服務模塊進行登記與管理,這就至關於生活中來了一家公司,去工商局進行登記同樣的道理,在服務發現中它主包含了三個子模塊,分別是eureka,cousul,zookeeper,這些spring cloud底層都支持的註冊中心,通常經常使用的是eureka和consul,那麼微服務構建好了以後,那麼微服務與微服務直接怎麼進行服務直接的通訊,或者微服務遇到了故障沒法達到請求的話(hystrix/ribbon/openfeign)
另外就是路由與過濾主要是針對對外接口的暴露的,這裏主要涉及zuul,spring cloud gateway,這兩個組件主要爲外部的調用者好比其餘的系統和咱們的微服務進行通訊的時候,由外到內是怎麼彼此進行訪問的,那麼這些就是由這兩個組件進行完成的
配置中心就是存放咱們應用程序配置的地方,可能咱們有上百個應用程序,那麼每一個應用程序都是一個微服務,那麼就會產生一個很嚴重的問題,就是這些配置文件放在什麼地方好比每一個服務下都放一個xml,或者yml,維護起來是很是不方便的,由於改一個參數,就要對全部的應用進行調整,爲了解決這個問題配置中心就出現了,至關於又提供了一個微服務把咱們應用中全部的配置文件,都放在了配置中心中,那麼其餘應用都是經過配置中心來獲取到這些配置文件的而不是咱們要這個這個配置文件放到每一個程序中,這樣的好處就是能夠將咱們的配置文件進行集中的管理,只須要改一個地方全部地方都能生效linux
消息總線,spring cloud stream或者spring cloud bus就跟咱們的消息mq差很少就是咱們發佈一個信息,到咱們隊列裏面由其餘的微服務或者其餘的應用進行獲取提供了系統與系統之間或者微服務與微服務之間的消息傳遞過程,這個中間增長了一個額外的東西叫作消息總線,具體的消息總線能夠是mq或者是redis,不一樣的廠商實現了不一樣的實現
安全控制是針對咱們安全的管理,在咱們傳統網站開發的時候,應用的訪問控制有受權的可使用這個功能,沒有受權的就沒法進行訪問,安全控制在spring cloud中也是存在的提供了AUTH2.0方案的支持,鏈路監控就是對咱們消息傳遞的過程要進行統籌和監控,好比系統中有10個微服務,而這10個微服務是彼此依賴的,第一個微服務它是底層最基礎的用戶管理而第二個微服務是基於用戶管理開發一個權限管理,在往上是應用管理,應用系統的擴展,每個微服務之間彼此之間進行依賴在頂層咱們進行調用的時候會安裝微服務的調用順序一級一級消息往下傳遞,這樣作有一個問題來了,若是中間有個環節出現了問題,沒有響應服務咱們在使用的角度當前咱們的請求失敗了,可是具體的環節不知道是在那一塊出現問題,那麼鏈路監控就是讓咱們快遞定位消息傳遞過程哪一個階段進行出錯,有助於咱們問題的排查
spring cloud cli命令行工具,來實現咱們開發來實現的一些功能,spring cloud cluster是對咱們集羣管理的一個輔助工具nginx
如今去交付微服務到k8s中舉個demo僅供參考git
1、發佈流程設計 2、準備基礎環境 3、在Kubernetes中部署jenkins 4、jenkins pipeline及參數化構建 5、jenkins在k8s中動態建立代理 6、自定義構建jenkins-slave鏡像 7、基於kubernetes構建jenkins ci系統 8、pipeline集成helm發佈spring cloud微服務
1、傳統的發佈流程是怎麼樣的?
如今的這個發佈流程設計仍是要和本身的項目中去考量,佈置一個大致的拓撲圖,那麼好比沒有這樣的場景jenkins去發佈微服務,它是一個怎麼樣的流程,做爲運維來說首先要去拉代碼,開發已經將這個項目開發好了,並推送到git倉庫中或者部署的私有的gitlab代碼倉庫中,第一步作的就是將這個代碼拉下來,拉完代碼,通常代碼都是java應用,會設計到一個編譯,編譯出來一個可部署的包,通常微服務是jar包,或者直接啓動的應用程序,而後就開始去封裝這個服務了,通常就是將這個jar包或者應用程序,經過dockerfile去達成一個可部署的鏡像,這個鏡像通常會本身製做jdk環境,或者就是jre環境,就是基礎鏡像可以運行這個鏡像的底包,最後一步就是部署到k8s中,這裏就會寫一些yaml文件了去把這個鏡像部署到k8s中,也就是容器的編排,另外還要考慮怎麼將這個應用暴露出去,讓用戶訪問到。github
使用jenkins自動話發佈的流程是這麼樣的?
顯然這種方式發佈多個微服務很不高效,因此就須要ci/cd,這麼一說,那麼有jenkins了,怎麼將這種方式自動化起來,減小人工的干預。
上面那張圖,首先是這樣的,開發將代碼推送到git倉庫中,經過commit提交上去,而後再到jenkins了,它負責的任務就是checkout代碼的拉取,code compile代碼的編譯,docker build &push ,鏡像的構建與推送到harbor倉庫中,而後deploy,將應用部署到k8s中,這裏呢因爲多是不少的微服務,那麼咱們就須要模版的代替,去發佈微服務,這裏咱們就會須要用到它原生的helm微服務發佈工具來到k8s當中去deploy,發佈到測試環境中去,而後經過slb提供一個統一的出口,發佈出去,中間產生的鏡像也都會存放到harbor倉庫中,當QA測試沒有問題,這個鏡像也就能夠去發佈生產環境中。redis
爲何須要jenkins slave架構
另外這裏還提到了一個jenkins,slave的一個架構,主要的是能夠動態的能夠完成這些任務,動態的去調度一個機器和一個pod來完成這幾步的任務,由於當任務不少時,也就是都在jenkins master去作,顯然任務多了負載就高了,因此就須要引入這個slave去解決這個問題。
2、準備基礎環境,所需的組件來完成咱們流程的發佈
一、k8s——(ingress controller、coredns、pv自動供給) 二、harbor,並啓用chart存儲功能,將咱們的helm打成chart並存放到harbor中 三、helm-v3 工具,主要來實現模版化,動態的將應用渲染安裝與卸載,更好的去管理微服務 四、gitlab代碼倉庫,docker-compose實現 五、mysql,微服務數據庫 六、在k8s中部署eureka(註冊中心)
一、檢查k8s基礎組件的環境是否安裝:
一、默認個人這個基礎的組件都是安裝好的,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.二、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
二、鏡像倉庫Harbor
2.1安裝docker與docker-compose
# wget http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -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 https://github.com/docker/compose/releases/download/1.25.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose
2.2 解壓離線包部署
下載地址:https://github.com/goharbor/harbor
# 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
--with-chartmuseum 參數表示啓用Charts存儲功能。
進行訪問:
http://harbor.zhaocheng.com
這個已經啓動chart功能
2.3 配置Docker可信任
因爲habor未配置https,還須要在node節點上的docker配置可信任。
# cat /etc/docker/daemon.json { "registry-mirrors": ["https://38vve9ja.mirror.aliyuncs.com"], "insecure-registries": ["harbor.zhaocheng.com"] } # systemctl restart docker
三、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 http://192.168.30.27/chartrepo/library
3.4 推送與安裝Chart
helm安裝好有默認的模版,那麼咱們先使用它的進行生成一個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 http://127.0.0.1:8080 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.
tgz包安裝helm ,通常用於以前製做的包,好比咱們以前製做的模版,若是想使用了,那麼直接就能夠再使用
[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
四、部署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 https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash sudo EXTERNAL_URL="https://gitlab.example.com" 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.二、使用docker-compose部署中文版Gitlab
1)首先在一臺新的服務器上安裝docker-ce,並使用docker加速器,使用中科大的加速器/阿里雲加速器
2)部署安裝docker-compose
3)安裝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,首次登錄須要手動設置密碼
將代碼推送到gitlab中
建立ms的倉庫名稱
建立完須要咱們將咱們的本地的代碼上傳到gitlab中來
如今咱們先克隆一下咱們這個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 'http://192.168.30.28': root Password for 'http://root@192.168.30.28': 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 'http://192.168.30.28': root Password for 'http://root@192.168.30.28': 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中
另外就是若是其餘的開發人員須要將代碼提交到gitlab上的話,那麼咱們就須要給他去建立一個用戶,設置必定的權限,而後制定好密碼,告訴他,它使用本身的帳號去管理本身的項目代碼
另外就是在使用jenkins作持續集成的時候,若是傳統的通常會須要對gitlab作SSH祕鑰對的認證,也就是在jenkins生成祕鑰對,私鑰本身留着將公鑰放在右上角的gitlab帳號處,會看到settings的下面,將公鑰放到指定框內,也就是jenkins須要有權限去拉取gitlab上的代碼,如今已經支持在Jenkins中以key的形式存儲的slavepod中
另外就是分支說明
master主分支,有且只有一個
release線上分支,通常爲線上版本,線上版本發佈後,會將release分支合併到master
develop 開發分支,一般給測試部署環境或者打包的分支,每一個人在本身的分支上開發完成後,向develop分支合併
feature 一般爲一個功能分支或者我的分支,通常有不少個,一般合併完成後會刪除
五、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)
六、將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.51cto.com/images/blog/202003/28/0c07c95b7ce22d59b778082427c7d2bd.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,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
訪問eureka
3、在Kubernetes中部署jenkins
在k8s中去部署jenkins須要注意的是自己它須要一個存儲,就是它須要存儲這些插件和配置的job都是須要存儲的,而咱們部署到k8s中這個pod是不固定的,有可能在第一個節點也有可能在第二個節點,那就須要保證這個jenkins這個存儲功能換個節點也能實時讀取到,這就用到了k8s的pv和pvc了,就會使用到持久化存儲,這樣的話就會用到pv的自動供給,而後用jenkins持久化目錄到pv上,持久到遠程的存儲上
建立一個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 .
4、jenkins pipeline及參數化構建
jenkins pipeline是一套插件,支持在jenkins中實現集成和持續交付管道;
pipeline經過特定語法對簡單到複雜的傳輸管道進行建模;
去Manage jenkins去安裝插件,找到manage plugins ,點擊Available檢索pipeline,進行安裝,安裝後選擇install without restart
如今去建立一個流水線進行測試一下
部署完以後可使用log查看登陸的密碼
[root@k8s-master jenkins]# kubectl logs jenkins-7d5fbd857d-tmwbm 6e22df63432f474f863dc07c9d291967
通常最好進去的時候不安裝插件,第一默認使用的國外的源,下載插件的時候很慢,咱們須要作作一些優化
先建立一個test的pipeline的語法流水線,熟悉一下怎麼發佈任務
在這裏就能夠看到語法的格式,這裏分爲兩種,以pipeline開頭的也叫聲明式語法,主要遵循的Groovy的相同語法來實現的pipeline {}
這個也是比較主流的方式。
測試一個hello的語法,默認提供的pipeline,進行使用
直接build,這個就能構建
當咱們構建完成後,這裏會顯示一個執行的步驟顯示一個具體的內容,能夠看到jenkins的工做目錄,默認傳統部署jenkins的目錄爲/root/.jenkins下,而做爲在k8s部署jenkins須要考慮數據的持久化了,由於pod遇到不肯定的因素進行重啓以後,那麼這個pod的數據就會丟失,因此針對這個問題,咱們就須要將這個pod的工做目錄掛載到持久捲上,這樣的話,即便pod重啓飄移到其餘的節點也能讀取到相應的數據了。
能夠看到k8s的持久化目錄是在這個jobs目錄下,將咱們構建的內容和數據都放在這裏了。
[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" } } } }
控制檯輸出了三個任務,分別執行hello,大概就是這個樣子
目錄也持久化了,看到新增的jenkins的項目任務
[root@k8s-node3 ~]# ll /ifi/kubernetes/default-jenkins-home-pvc-0d67f7f5-2b31-4dc8-aee2-5e7b9e0e7e19/jobs/
總用量 0
drwxr-xr-x 3 1000 1000 61 1月 13 11:36 test
drwxr-xr-x 3 1000 1000 61 1月 13 14:04 test-demo
jenkins pipeline就像一個管道的建模同樣,在這個腳本里完成了整個生命週期各個階段,從development開發提交代碼commit id,到build構建,再到test測試,再到stage步驟作一些處理,deploy部署到dev或者qa環境中,最後到線上,其實在這個流程中它是有一個目的的,剛開始是在開發環境,最終是把它帶到線上環境,而中間一系列的流程都是經過管道的形式串起來,而這個管道這個模型是經過pipeline去書寫的,這個語法就是這個模型,須要把這個生命週期的所需的都套進這個模型中來,而後由jenkins pipeline去管理
第一用這個pipepine它有很大的特色
一、可視化頁面,每一個步驟均可以可視化展現,方便咱們去解決每一個步驟的相關問題
二、每一個步驟都寫腳本里面了,只須要維護這個腳本就行了,而這個腳本能夠寫的具備通用性,若是想寫多個項目時,好比發佈3組微服務,那麼第一個寫的pipeline,那麼也一樣適用於第二個和第三個微服務的模版。那麼這個須要考慮它們有哪些不一樣點?
不一樣點:
1)拉取git代碼的地址不同
2)分支名也不同,由於是不一樣的git地址,因此打的分支名也不同。
3)部署的機器也不同,有可能這幾個服務部署在node1,另外的服務部署在node2或者node3
4)打出的包名不同
因此要把這些不一樣點,作成一種人工交互的形式去發佈,這樣的話這個腳本才具備通用性,發佈服務才能使用這寫好的pipeline發佈更多的微服務,並且jenkins pipeline支持參數化構建。
這裏也就是pipeline一些的語法,好比選擇parameters參數化構建,選擇框式參數choice parameter,好比給它幾個值,而後讓它動態的去輸入,或者憑據參數credentials parameter,或者文件參數file parameter,或者密碼參數password parameter,或者運行參數 run parameter,或者字符串參數 string paramether ,或者多行字符串參數multi-line string parameter,或者布爾型參數boolean parameter
好比選擇choice parameter,選擇型參數
好比發佈的git地址不同,那麼就須要多個地址能夠去選擇,須要使用choice parameter選擇框型參數,這個能夠體如今構建的頁面,也能夠體如今configure配置的頁面,這樣配置也比較麻煩,因此直接在configure裏面直接添加對應的參數就能夠
先配置一個看一下效果
將生成的選擇型參數添加到指定的pipeline的語法中,save一下
再回到項目中能夠看到build名字從build now換成了build with parameters,也就是增長了幾行的的配置,能夠進行選擇的去拉去哪一個分支下的代碼了
也能夠在configure去配置,這兩個地方均可以添加,要是再添加一個直接add parameter,能夠選擇多種類型的參數幫助咱們去構建這個多樣式的需求
再好比分支這一塊,可能每次打的分支都不一樣,這個不是固定的,因此須要一個git的參數化構建,那麼這個就須要動態的去從選擇的git地址獲取到當前的全部的分支
還有一個分佈的機器不一樣,這個也可使用剛纔的choice parameter,將多個主機的ip也進去
將這個生產的語法,複製到pipeline語法中
choice choices: ['10.4.7.12', '10.4.7.21', '10.4.7.22'], description: '發佈哪臺node上', name: 'host'
構建一下,發現也可使用選擇型參數了,相似這個的人工交互就能夠選擇多個參數了,能夠寫一個通用的模版,就處理人工交互的邏輯
如今咱們能夠去人工選擇了,這裏面的值怎麼獲取到,咱們處理不一樣的項目,必須在這裏面去實現,好比選擇這個git以後,拉取這個代碼編譯構建,這些可能都是一些相同點,不一樣點發布的機器不同,因此要選擇用戶是拿到的哪一個git地址,發佈的哪一個機器,在腳本里去拿到,其實默認這個name就是一個變量,jenkins已經將這個賦予變量,而且pipeline能夠直接獲取這個變量名,就是剛纔定義的git,host這個名字,那麼咱們從剛纔設置的parameters裏去測試這個變量可不能夠拿到,拿到的話說明這個就很好去處理
構建一下,如今構建成功後已是構建成功了,也已經獲取到剛纔咱們的git這個參數下的值了
有了這些方式,就能夠將這些不一樣點經過裏面的agent和shell腳原本處理了,寫pipeline參數化構建就是知足更多的一個需求,能適配更多的項目,能讓人工干預的作一些複雜的任務
5、jenkins在k8s中動態建立代理
如何在k8s中動態的建立slave代理?
當完成這些任務以後考慮的問題,這些任務都是在jenkins機器去完成的,那麼這個也確定是在pod中去運行的,由於咱們的是將jenkins部署在pod中的,也就是這當前的這個節點去完成的拉取代碼,編譯,構建鏡像,發佈,那麼可能會遇到一個問題,那麼項目不少,天天作持續集成很高,十幾回甚至上百次,面對這樣的一個需求量,當前的這個pod是很難支撐的,就比如剛纔的job,有十幾我的去運行,來運行不一樣的服務,原本是能夠幾分鐘完成的事情,最後致使10多分鐘才執行完成,這樣的話就很耽誤項目進度了,因此就須要使用jenkins的master-slave架構了,而master只負責調度分配,slave來完成這些job任務,而slave是由物理機或者虛擬機存在的,和master保持通訊,只要有任務就下發到slave節點,這樣就解決了單jenkins的性能問題了
也就是提早建立好幾個jenkins-slave,在其餘節點讓它們待定着,當master有人點job構建了,這個jenkins會幫你把這個job具體作的事,轉發到slave去幹活,master也就啓到一個領導的角色,它自己就沒什麼壓力了,只負責調度了,那麼若是不用k8s的容器的這樣架構,就比如在一臺機器上裝了一個jenkins,而後找臺主機作slave,在manage node,添加new node,而後這個就會經過master下發任務讓slave去完成了。
那麼咱們的jenkins是從k8s去部署的,因此咱們的slave也是從k8s中去考慮,就能夠將這個slave當成一個pod去處理,master就拿這個pod去處理
這個的話也就是能夠預先起一些slave,也能夠動態的去建立slave,要是預先啓動slave的話,可能會消耗一些資源,這些資源也並非必需要消耗的,因此就要考慮動態的去考慮slave,也就是即開即用,不用就銷燬了,當這個量大的時候,這個就比較明顯了,因此在k8s中去建立代理能夠經過插件去作到的
直接去安裝一個kubernetes的插件
安裝插件的時候咱們須要在咱們的持久化目錄中去修改咱們的國外地址
[root@k8s-node3 updates]# sed -i 's/http:\/\/updates.jenkins-ci.org\/download/https:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins/g' default.json && \ sed -i 's/http:\/\/www.google.com/https:\/\/www.baidu.com/g' default.json
在jenkins頁面上restart,重啓jenkins生效
要想動態的去在k8s中建立slave pod,因此要鏈接k8s,定義鏈接k8s的地址是多少,建立slave pod鏈接jenkins的地址是多少
找到管理jenkins 這裏,找到系統配置configure system
當安裝好插件以後,會在最下面發現一個cloud
這裏鏈接k8s直接使用service的地址就能夠,由於咱們部署了coredns直接能夠就要解析到這個k8s,點擊鏈接測試能夠鏈接
若是jenkins是在外部去部署的,也就是單獨哪臺服務器去部署的,走的傳統部署,也就是要鏈接k8s對外的地址也就是https://10.4.7.11:6443這個端口,而且將它的CA添加進來添加一個憑據,這樣才能鏈接成功
而且還有將jenkins的地址也寫上,http://jenkins.default,或者寫成鏈接ip的地址也能夠
如今jenkins已經知道要鏈接哪一個k8s,那麼再去建立這個slave容器的pod,要建立pod必須就的須要鏡像,若是沒有鏡像,即便jenkins像k8s發起建立一個pod,k8s確定不知道去建立哪一個pod,必須有鏡像,這個鏡像也就是slave的鏡像,因此下一步咱們須要作的就是構建一個鏡像。
讓k8s使用這個鏡像拉取一個pod,而這個鏡像製做的話,看須要什麼環境的包。
6、自定義構建jenkins-slave鏡像
jenkins slave製做這個鏡像看須要什麼?
一、須要什麼開發語言?由於slave去完成的須要代碼的編譯,若是是java的語言,那麼就須要maven的環境,若是是go就須要去用go去編譯,因此開發語言不同,slave所作的事環境也不同
二、額外環境,好比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地址:https://plugins.jenkins.io/kubernetes
7、基於kubernetes構建jenkins 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" } } } }
如今能夠在jenkins中動態的去建立pod,只有有下發任務的時候纔去建立pod,而jenkins-master只負責任務調度,slave來作任務處理來節省資源,當任務完成以後,這個slave-pod也會自動的銷燬
[root@k8s-master1 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
jenkins-7d5fbd857d-6tgdj 1/1 Running 0 23m
jenkins-slave-gdtqz-p17b1 1/1 Running 0 40s
8、pipeline集成helm發佈spring cloud微服務
如今編寫這個pipeline腳原本實現自動化發佈微服務
#!/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解析
一、首先去安裝這幾個插件
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 進行對選擇框插件進行擴展,能夠多選,擴展參數構建,並且部署微服務還須要多選,好比同時發佈兩個微服務,三個微服務,不可能每發佈一個要點一下,這樣確定是不現實的。
二、參數含義
// 公共
def registry = "192.168.30.27" 好比鏡像倉庫的地址
// 項目
def project = "microservice" 項目的名稱
def git_url = "http://192.168.30.28/root/ms.git" 微服務的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 ID
def k8s_auth = "7ee65e53-a559-4c52-8b88-c968a637051e" 這就是k8s的認證,這個也就是保存在kubeconfig中
這些都是定義的公共的變量,這些變量主要是讓腳本適用於一個通用性,將一些變更的值傳入進去這樣主要可讓項目動態的去適配了
三、動態的在k8s中去建立slave-pod
pipeline {
agent {
kubernetes {
label "jenkins-slave" 指定標籤
yaml """
kind: Pod
metadata:
name: jenkins-slave 指定pod的名字
spec:
containers:
name: jnlp 默認使用jnlp
image: "${registry}/library/jenkins-slave-jdk:1.8" 使用咱們封裝好的slave的鏡像
imagePullPolicy: Always 鏡像拉取策略,始終拉取鏡像倉庫的鏡像
volumeMounts: 掛載的數據卷,咱們在構建jenkins-slave鏡像的時候,docker須要數據卷掛載
name: maven-cache 主要是將容器中maven拉取依賴包的緩存掛載到宿主機的/tmp/m2下,一旦宿主機都具有這個緩存的話,
mountPath: /root/.m2 那麼之後構建都會先讀取緩存,或者也就是能夠將這些包放到共享存儲裏面pvc中去讀取,能夠在這個yaml
volumes: 中去定義也均可以
四、參數化構建
parameters {
gitParameter branch: '', branchFilter: '.', defaultValue: '', description: '選擇發佈的分支', name: 'Branch', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '', type: 'PT_BRANCH' ###動態的去獲取參數
extendedChoice defaultValue: 'none', description: '選擇發佈的微服務', \ ###加了擴展,能夠多選發佈多個微服務
微服務找出咱們須要哪些須要人工交互的
就是使用的這套微服務都適用於這套chart模版
一、微服務名稱,以及針對一些服務須要帶上域名,另外好比去配置的微服務的名字都是不同的,這個名字是保證是惟一的,須要使用include,,通常寫在_helpers。tpl下,由於咱們部署的時候已經拿到微服務的名稱了,因此helm起的名字也是微服務的名字,而後再加上公用的標籤就區分出來了,另外就是微服務的端口也是不同的
二、端口,每一個微服務的端口也都不一
三、命名空間 使用helm -n 就能夠部署到指定的命名空間了
四、副本數 這個原本在helm中是3個副本,咱們能夠經過傳參的形式變成5或者2均可以
五、資源的限制,自己這個k8s中的限制是沒法知足一個java應用的限制的,通常1.8jdk版本是不兼容的,新的版本是兼容的,因此手動的去指定它的對內存的大小,這個通常在dockerfile啓用jar包的時候帶入
六、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 http://192.168.30.27/chartrepo/library
將helm製做完成後打包並push到倉庫中,而後當咱們部署的時候就去拉這個helm模版地址
[root@k8s-master1 ~]# 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.
五、jenkins-slave所執行的具體任務 stages { stage('拉取代碼'){ steps { checkout([$class: 'GitSCM', branches: [[name: "${params.Branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]] 它須要將這個參數傳給上面的git parameters,讓它可以動態的git地址中拉取全部的分支, ]) } } stage('代碼編譯') { // 編譯指定服務 steps { sh """ mvn clean package -Dmaven.test.skip=true """ } } stage('構建鏡像') { steps { withCredentials([usernamePassword(credentialsId: "${harbor_registry_auth}", passwordVariable: 'password', usernameVariable: 'username')]) { 這裏使用了一個憑據的認證將鏈接harbor認證信息保存到憑據裏面,爲了安全性,使用了憑據的引用,動態的將它保存到變量中,而後經過調用變量的形式去登陸這鏡像倉庫,這樣的話就不用在pipeline中去體現密碼了, sh """ docker login -u ${username} -p '${password}' ${registry} for service in \$(echo ${Service} |sed 's/,/ /g'); do service_name=\${service%:*} 由於咱們是部署的微服務,因此咱們須要不少的服務的構建,因此這裏加了一個for循環 它調用的$service正是參數化構建中的選擇的services,而後根據不一樣的服務推送到鏡像倉庫, 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 """ 以前說須要kubeconfig這個配置存到jenins中的slave的pod中,起個名字叫admin.kubeconfig configFileProvider([configFile(fileId: "${k8s_auth}", targetLocation: "admin.kubeconfig")]){ sh """ # 添加鏡像拉取認證 當使用拉取鏡像的認證信息的時候就能夠直接指定admin.kubeconfig了,它就能鏈接到這個集羣了 kubectl create secret docker-registry ${image_pull_secret} --docker-username=${username} --docker-password=${password} --docker-server=${registry} -n ${Namespace} --kubeconfig admin.kubeconfig |true # 添加私有chart倉庫到這個pod中 helm repo add --username ${username} --password ${password} myrepo http://${registry}/chartrepo/${project} """ } } } } ------------------------------------------------------------------------------------------------------------------------------------------ 六、deploy,使用helm部署到k8s中 stage('Helm部署到K8S') { steps { sh """定義公共的參數,使用helm,kubectl都要加namespace命名空間,鏈接k8s認證的kubeconfig文件 common_args="-n ${Namespace} --kubeconfig admin.kubeconfig" for service in \$(echo ${Service} |sed 's/,/ /g'); do for循環每一個微服務的端口都不同,因此在微服務這裏添加微服務的名字和它對應的端口,把選擇的服務和端口進行拆分 service_name=\${service%:*} service_port=\${service#*:} image=${registry}/${project}/\${service_name} tag=${BUILD_NUMBER} 。 jenkins構建的一個編號 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 那麼加一個判斷看看是否是部署了,爲假就install,爲真就upgrade action=upgrade 舊部署的使用upgrade更新 else action=install 新部署的使用install fi # 針對服務啓用ingress if [ \${service_name} == "gateway-service" ]; then helm \${action} \${helm_args} \ --set ingress.enabled=true \ 爲true就啓用ingress,由於chart確定默認的爲force,就是不啓用ingress --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最好先從一個地方複製一下,修改完再放進pipeline gitlab的項目地址def git_url = "http://192.168.30.28/root/ms.git" 修改harbor的憑據 選擇credentials
點擊jenkins
add 添加憑據
填寫harbor的用戶名和密碼,密碼Harbor12345
描述隨便寫,
再添加第二個
git的用戶名和密碼
而後更新一下,把密鑰放到指定的pipeline中
將這個id放到pipeline中
將生成的密鑰認證放到pipeline中
// 認證
def image_pull_secret = "registry-pull-secret"
def harbor_registry_auth = "7177c1f3-9e6b-435c-b4cc-187c742c4516"
def git_auth = "28484aa2-aeb4-479b-ad43-cf12c2a7d445"
而後將咱們須要的插件都安裝上
// 所需插件: Git Parameter/Git/Pipeline/Config File Provider/kubernetes/Extended Choice Parameter
如今去添加kubeconfig的文件
將這個ID放到咱們k8s-auth的pipeline中,這個配置文件是k8s鏈接kubeconfig的ID,若是是kubeadm部署的須要到[root@k8s-master ~]# cat /root/.kube/config 這個文件下將文件拷貝到jenkins中
apiVersion: v1
clusters:
最後進行測試發佈在pipeline的配置指定發佈的服務進行發佈查看pod的狀態