1.1 k8s中pod版本更新策略
deployment控制器支持两种更新策略:默认为滚动更新
1.滚动更新(rolling update)
滚动更新是默认的更新策略,滚动更新是基于新版本镜像创建新版本pod,然后删除一部分旧版本pod,然后再创建新版本Pod,再删除一部分旧版本pod,直到旧版本pod删除完成,滚动更新优势是在升级过程中不会导致服务不可用,缺点是升级过程中会导致两个版本在短时间内会并存。
具体升级过程是在执行更新操作后k8s会再创建一个新版本的ReplicaSet控制器,在删除旧版本的ReplicaSet控制器下的Pod的同时会在新版本的ReplicaSet控制器下创建新的pod,直到旧版本的pod全部被删除完后再把旧版本的ReplicaSet控制器也回收掉。
在执行滚动更新的同时,为了保证服务的可用性,当前控制器内不可用的pod(pod需要拉取镜像执行创建和执行探针探测期间是不可用的)不能超出一定范围,国为需要至少保留一定数量的pod以保证服务可以被客户端正常访问,可以通过以下参数指定:#kubectl explain deployment.spec.strategy
deployment.spec.strategy.rollingUpdate.maxSurge #指定在升级期间Pod总数可以超出定义好的期望的pod数的个数或者百分比,默认为25%;如果设置为10%,假如当前是100个pod,那么升级时最多将创建110个pod,即额外有10%的pod临时会超出当前(replicas)指定的副本数限制。
deployment.spec.strategy.rollingUpdate.maxUnavailable #指定在升级期间最大不可用的pod数,可以是整数或者当前pod的百分比,默认是25%,假如当前是100个pod,那么升级时最多可用25个(25%)pod不可用,即还要75个(75%)pod是可用的。
2.重建更新(recreate)
先删除现有的pod,然后基于新版本的镜像重建,优势是同时只有一个版本在线,不会产生多版本同时在线问题,缺点是Pod删除后到Pod重建成功中间的时间会导致服务无法访问,因此较少使用。
1.2 灰度更新流程
暂停更新与恢复更新 #https://kubernetes.io/zh/docs/concepts/workloads/controllers/deployment/#canary-deployment
灰度升级(即在更新过程中暂停一下)
-
更新set image,暂停rollout pause,灰度节点验证,继续更新rollout resume,更新完成;
-
更新set image,暂停rollout pause,遇到问题,回滚rollout undo;
1.3 命令行更新与回滚
升级到镜像的指定版本
# kubectl apply -f nginx.yaml --record=true #v1版本,--record=true为记录执行的kubectl #镜像更新命令格式为 #kubectl set image deployment/{deployment-name} {containers-name}={image} -n {namespace} #V2 # kubectl set image deployment/magedu-nginx-deployment magedu-nginx-container=harbor.magedu.net/magedu/nginx:1.16.1:v2 -n magedu --record #V3 # kubectl set image deployment/magedu-nginx-deployment magedu-nginx-container=harbor.magedu.net/magedu/nginx:1.16.1:v3 -n magedu --record
查看历史版本信息
查看历史版本信息 # kubectl rollout history deployment/magedu-nginx-deployment -n magedu deployment.extensions/magedu-nginx-deployment
回滚到上一个版本
kubectl rollout undo deployment magedu-nginx-deployment -n magedu
回滚到指定版本
查看当前版本号 # kubectl rollout history deployment/magedu-nginx-deployment -n magedu deployment.extensions/magedu-nginx-deployment # kubectl rollout undo deployment magedu-nginx-deployment -n magedu --to-revision=3 deployment.apps/magedu-nginx-deployment rolled back 查看回滚后版本号展示 # kubectl rollout history deployment/magedu-nginx-deployment -n magedu deployment.extensions/magedu-nginx-deployment
金丝雀/灰度
1.指定新镜像版本 # kubectl set image deployment magedu-tomcat-app1-deployment magedu-tomcat-app1-container=tomcat:8.5.56 -n magedu 2.暂停更新(即灰度一部分pod) # kubectl rollout pause deployment magedu-tomcat-app1-deployment -n magedu 3.恢复更新(即继续更新) # kubectl rollout resume deployment magedu-tomcat-app1-deployment -n magedu
2.k8s结合Jenkins与gitlab实现代码升级与回滚(持续集成与部署)
测试环境准备
一台Gitlab-server-172.31.5.101,4C4G;
一台Jenkins-server-172.31.5.102,4C4G;
2.1 部署Jenkins
安装包下载https://www.jenkins.io/download/
清华源下载https://mirrors.tuna.tsinghua.edu.cn/jenkins/debian-stable/jenkins_2.303.2_all.deb
root@jenkins-server:~# apt update root@jenkins-server:~# apt install openjdk-11-jdk root@jenkins-server:~# java -version root@jenkins-server:~# dpkg -c jenkins_2.303.2_all.deb #查看安装包使用的路径; root@jenkins-server:~# dpkg -i jenkins_2.303.2_all.deb #可能会提示需要安装依赖包daemon; root@jenkins-server:~# apt install daemon #会自动安装jenkins和启动jenkins; root@jenkins-server:~# systemctl stop jenkins #停止jenkins,修改配置文件设置启动用户,这里使用root身份; JAVA_ARGS="-Djava.awt.headless=true -Dhudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=true" #勾子,通过gitlab远程触发jenkins开始构建,根据需要开启CSRF; JENKINS_USER=root JENKINS_GROUP=root root@jenkins-server:~# systemctl restart jenkins
查看登录jenkins web页面使用的secrets;
root@jenkins-server:~# cat /var/lib/jenkins/secrets/initialAdminPassword
浏览器登录http://172.31.5.102:8080安装插件,需要这台虚机可以联网,或者从其它已经安装插件机器中将插件目录下的文件拷贝过来;
安装插件完成后,设置jenkins管理员账号和密码,比如jenkinsadmin账户;
安装插件后,很多插件还没有加载,需要重启jenkins服务加载插件;
root@jenkins-server:~# systemctl restart jenkins
使用浏览器登录jenkins web页面创建简单的任务验证jenkins是否可以正常运行;
1> web页面右侧,新建任务,输入任务名称; 2> 选择构建一个自由风格的软件项目;(SCM,Source Code Management代码管理仓库,比如gitlab或svn) 3> “源码管理”,先选择“无”; 4> “构建”选择“执行shell”; 测试shell命令:echo "$USER" 保存,应用 5> 选择这个任务,选择“立即构建”,查看执行结果;
6> 在build history中查看执行结果,选择“控制台输出”
2.2 部署gitlab
根据系统版本下载相应的gitlab安装包,这里使用的ubuntu focal系统,使用gitlab-ce_14.2.5安装包;
https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/ubuntu/pool/focal/main/g/gitlab-ce/gitlab-ce_14.2.5-ce.0_amd64.deb
root@gitlab-server:~# dpkg -i gitlab-ce_14.2.5-ce.0_amd64.deb *. *. *** *** ***** ***** .****** ******* ******** ******** ,,,,,,,,,***********,,,,,,,,, ,,,,,,,,,,,*********,,,,,,,,,,, .,,,,,,,,,,,*******,,,,,,,,,,,, ,,,,,,,,,*****,,,,,,,,,. ,,,,,,,****,,,,,, .,,,***,,,, ,*,. _______ __ __ __ / ____(_) /_/ / ____ _/ /_ / / __/ / __/ / / __ `/ __ \ / /_/ / / /_/ /___/ /_/ / /_/ / \____/_/\__/_____/\__,_/_.___/ Thank you for installing GitLab! GitLab was unable to detect a valid hostname for your instance. Please configure a URL for your GitLab instance by setting `external_url` configuration in /etc/gitlab/gitlab.rb file. Then, you can start your GitLab instance by running the following command: sudo gitlab-ctl reconfigure For a comprehensive list of configuration options please see the Omnibus GitLab readme https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md Help us improve the installation experience, let us know how we did with a 1 minute survey: https://gitlab.fra1.qualtrics.com/jfe/form/SV_6kVqZANThUQ1bZb?installation=omnibus&release=14-2
root@gitlab-server:~# vi /etc/gitlab/gitlab.rb external_url 'http://172.31.5.101' root@gitlab-server:~# gitlab-ctl reconfigure root@gitlab-server:~# cat /etc/gitlab/initial_root_password
通过网页登录gitlab设置自己使用的密码;
设置web网页语言,可以设置为中文;
在左上角“菜单”--“管理员”,新建群组magedu;
新建用户usr1,创建用户后设置用户密码;
创建项目app1,添加index.html测试文件;
在client端安装git,拉取自建gitlab项目和更新代码验证;
# apt install git # cd /opt # git clone http://172.31.5.101/magedu/app1.git # cd /opt/app1 # echo "666" >> index.html # git add . # git commit -m "v2" # git push
2.3 实现代码部署与回滚
2.3.1 准备脚本
#!/bin/bash #Author: ZhangShiJie #Date: 2018-10-24 #Version: v1 #记录脚本开始执行时间 starttime=`date +'%Y-%m-%d %H:%M:%S'` #变量 SHELL_DIR="/root/scripts" SHELL_NAME="$0" K8S_CONTROLLER1="172.31.7.101" K8S_CONTROLLER2="172.31.7.102" DATE=`date +%Y-%m-%d_%H_%M_%S` METHOD=$1 Branch=$2 if test -z $Branch;then Branch=develop fi function Code_Clone(){ Git_URL="git@172.31.5.101:magedu/app1.git" DIR_NAME=`echo ${Git_URL} |awk -F "/" '{print $2}' | awk -F "." '{print $1}'` DATA_DIR="/data/gitdata/magedu" Git_Dir="${DATA_DIR}/${DIR_NAME}" cd ${DATA_DIR} && echo "即将清空上一版本代码并获取当前分支最新代码" && sleep 1 && rm -rf ${DIR_NAME} echo "即将开始从分支${Branch} 获取代码" && sleep 1 git clone -b ${Branch} ${Git_URL} echo "分支${Branch} 克隆完成,即将进行代码编译!" && sleep 1 #cd ${Git_Dir} && mvn clean package #echo "代码编译完成,即将开始将IP地址等信息替换为测试环境" ##################################################### sleep 1 cd ${Git_Dir} tar czf ${DIR_NAME}.tar.gz ./* } #将打包好的压缩文件拷贝到k8s 控制端服务器 function Copy_File(){ echo "压缩文件打包完成,即将拷贝到k8s 控制端服务器${K8S_CONTROLLER1}" && sleep 1 scp ${Git_Dir}/${DIR_NAME}.tar.gz root@${K8S_CONTROLLER1}:/opt/k8s-data/dockerfile/web/magedu/tomcat-app1 echo "压缩文件拷贝完成,服务器${K8S_CONTROLLER1}即将开始制作Docker 镜像!" && sleep 1 } #到控制端执行脚本制作并上传镜像 function Make_Image(){ echo "开始制作Docker镜像并上传到Harbor服务器" && sleep 1 ssh root@${K8S_CONTROLLER1} "cd /opt/k8s-data/dockerfile/web/magedu/tomcat-app1 && bash build-command.sh ${DATE}" echo "Docker镜像制作完成并已经上传到harbor服务器" && sleep 1 } #到控制端更新k8s yaml文件中的镜像版本号,从而保持yaml文件中的镜像版本号和k8s中版本号一致 function Update_k8s_yaml(){ echo "即将更新k8s yaml文件中镜像版本" && sleep 1 ssh root@${K8S_CONTROLLER1} "cd /opt/k8s-data/yaml/magedu/tomcat-app1 && sed -i 's/image: harbor.magedu.*/image: harbor.magedu.net\/magedu\/tomcat-app1:${DATE}/g' tomcat-app1.yaml" echo "k8s yaml文件镜像版本更新完成,即将开始更新容器中镜像版本" && sleep 1 } #到控制端更新k8s中容器的版本号,有两种更新办法,一是指定镜像版本更新,二是apply执行修改过的yaml文件 function Update_k8s_container(){ #第一种方法 ssh root@${K8S_CONTROLLER1} "kubectl set image deployment/magedu-tomcat-app1-deployment magedu-tomcat-app1-container=harbor.magedu.net/magedu/tomcat-app1:${DATE} -n magedu" #第二种方法,推荐使用第一种 #ssh root@${K8S_CONTROLLER1} "cd /opt/k8s-data/yaml/magedu/tomcat-app1 && kubectl apply -f tomcat-app1.yaml --record" echo "k8s 镜像更新完成" && sleep 1 echo "当前业务镜像版本: harbor.magedu.net/magedu/tomcat-app1:${DATE}" #计算脚本累计执行时间,如果不需要的话可以去掉下面四行 endtime=`date +'%Y-%m-%d %H:%M:%S'` start_seconds=$(date --date="$starttime" +%s); end_seconds=$(date --date="$endtime" +%s); echo "本次业务镜像更新总计耗时:"$((end_seconds-start_seconds))"s" } #基于k8s 内置版本管理回滚到上一个版本 function rollback_last_version(){ echo "即将回滚之上一个版本" ssh root@${K8S_CONTROLLER1} "kubectl rollout undo deployment/magedu-tomcat-app1-deployment -n magedu" sleep 1 echo "已执行回滚至上一个版本" } #使用帮助 usage(){ echo "部署使用方法为 ${SHELL_DIR}/${SHELL_NAME} deploy " echo "回滚到上一版本使用方法为 ${SHELL_DIR}/${SHELL_NAME} rollback_last_version" } #主函数 main(){ case ${METHOD} in deploy) Code_Clone; Copy_File; Make_Image; Update_k8s_yaml; Update_k8s_container; ;; rollback_last_version) rollback_last_version; ;; *) usage; esac; } main $1 $2
2.3.2 配置jenkins通过ssh密钥登录gitlab
在jenkins生成ssh密钥;
root@jenkins-server:~# ssh-keygen root@jenkins-server:~# cat /root/.ssh/id_rsa.pub ssh pub公钥文本1
将pub公钥文本配置在gitlab的“用户设置”--“SSH密钥”中;
在client中验证git clone不需要输入密码;
2.3.3 在jenkins web页面配置脚本路径和选项参数
2.3.4 验证脚本
注释脚本中配置行,逐项测试;
2.3.5 更新应用代码和发布
从客户端更新index.html代码,并git push上传;
在gitlab查查看代码更新是否成功;
使用jenkins发布更新到k8s pod;
使用jenkins测试回滚;
测试环境:
ELK:
Elasticsearch+kafka+kibana,es1.s209.local,172.31.2.101
Elasticsearch+kafka,es2.s209.local,172.31.2.102
Elasticsearch+kafka,es3.s209.local,172.31.2.103
logstash,logstash1.s209.local,172.31.2.104
MQ:
zookeeper+kafka,mq1.s209.local,172.31.4.101
zookeeper+kafka,mq2.s209.local,172.31.4.102
zookeeper+kafka,mq3.s209.local,172.31.4.103
Zookeeper(服务注册与发现)
Pod日志(filebeat)--> Kafka(Topic话题) --> Logstash(收集、解析和转换日志) --> Es索引存储--> Kibana展示
3.1.部署zookeeper集群
3.2.部署kafka
ff
3.3.部署ES集群及浏览器安装elasticsearch head插件
ff
3.4.pod中启动filebeat实现日志收集并输出到kafka
ff
3.5.部署logstash将kakfa数据输出至elasticsearch集群
fff