title: 39.k8s安装配置 CreateTime: 2019-07-11 00:00:39 UpdateTime: 2024-03-23 11:57:17 CategoryName: CloudNative --- ## 1. 参考资料 https://www.cnblogs.com/RainingNight/p/using-kubeadm-to-create-a-cluster-1-13.html https://mp.weixin.qq.com/s/JCHyqkXYjToAjazeUwNXnQ https://jimmysong.io/ http://dockone.io/article/8115 https://www.huweihuang.com/kubernetes-notes/ https://my.oschina.net/zili/blog/1031428 https://www.kubernetes.org.cn/4956.html http://docs.kubernetes.org.cn/317.html https://www.kubernetes.org.cn/4664.html https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/ https://blog.csdn.net/mailjoin/article/details/79686934 https://my.oschina.net/u/1791060/blog/830023 https://blog.qikqiak.com/post/pod-workflow/ https://www.huweihuang.com/article/kubernetes/core-principle/kubernetes-core-principle-api-server/ https://www.huweihuang.com/article/kubernetes/core-principle/kubernetes-core-principle-controller-manager/ https://www.huweihuang.com/article/kubernetes/core-principle/kubernetes-core-principle-kubelet/ https://blog.csdn.net/ywq935/article/details/82716366 https://www.cnblogs.com/RainingNight/p/deploying-k8s-dashboard-ui.html https://kubernetes.io/docs/setup/independent/high-availability/ ## 2. k8s组件说明 ### 2.1.整体架构图 ![](/public/39/image1.jpeg) kubernetes的架构分为Master和Node两部分,由API Server.Controller Manager.Scheduler.Kubelet.etcd五种组件构成,它们之间协同工作从而完成整个集群的管理. 简单介绍下Kubernetes中组件和资源对象的基本概念: 1. Pod:Kubernetes中运行应用或服务的最小单元,其设计理念是支持多个容器在一个Pod中共享网络地址和文件系统 2. Service:访问Pod的代理抽象服务,主要用于集群内部的服务发现和负载均衡 3. Replication Controller(建议使用Deployment):用于伸缩Pod副本数量的组件 4. API Server组件:资源操作唯一入口,对以上1.2.3资源对象进行增.删.改.查的 API服务器 5. Scheduler组件:集群中资源对象的调度控制器,调度CPU内存资源,创建迁移pod 6. Controller Manager组件:内部管理控制中心,主要维护service和pod的映射关系 7. etcd组件:分布式键值对(k,v)存储服务,存储整个集群的状态信息 8. Kubelet组件:节点上的pod管家,负责维护Pod容器的生命周期 9. Label:用于Service及Replication Controller 与Pod关联的标签 ![](/public/39/image2.jpeg) ### 2.2.kube-master[控制节点] ![](/public/39/image3.png) 1. Kubecfg将特定的请求,比如创建Pod,发送给Kubernetes Client. 2. Kubernetes Client将请求发送给API server. 3. API Server根据请求的类型,比如创建Pod时storage类型是pods,然后依此选择何种REST Storage API对请求作出处理. 4. REST Storage API对的请求作相应的处理. 5. 将处理的结果存入高可用键值存储系统Etcd中. 6. 在API Server响应Kubecfg的请求后,Scheduler会根据Kubernetes Client获取集群中运行Pod及Minion/Node信息. 7. 依据从Kubernetes Client获取的信息,Scheduler将未分发的Pod分发到可用的Minion/Node节点上. #### 2.2.1.API Server[资源操作入口] 提供了资源对象的唯一操作入口,其他所有组件都必须通过它提供的API来操作资源数据,只有API Server与存储通信,其他模块通过API Server访问集群状态. 第一,是为了保证集群状态访问的安全. 第二,是为了隔离集群状态访问的方式和后端存储实现的方式:API Server是状态访问的方式,不会因为后端存储技术etcd的改变而改变. 作为kubernetes系统的入口,封装了核心对象的增删改查操作,以RESTFul接口方式提供给外部客户和内部组件调用.对相关的资源数据"全量查询"+"变化监听",实时完成相关的业务功能. 更多API Server信息请参考:[Kubernetes核心原理(一)之API Server](http://www.huweihuang.com/article/kubernetes/core-principle/kubernetes-core-principle-api-server/) #### 2.2.2.Controller Manager[内部管理控制中心] 实现集群故障检测和恢复的自动化工作,负责执行各种控制器,主要有: endpoint-controller:定期关联service和pod(关联信息由endpoint对象维护),保证service到pod的映射总是最新的. replication-controller:定期关联replicationController和pod,保证replicationController定义的复制数量与实际运行pod的数量总是一致的. 更多Controller Manager信息请参考:[Kubernetes核心原理(二)之Controller Manager](http://www.huweihuang.com/article/kubernetes/core-principle/kubernetes-core-principle-controller-manager/) #### 2.2.3.Scheduler[集群分发调度器] 1. Scheduler收集和分析当前Kubernetes集群中所有Minion/Node节点的资源(内存.CPU)负载情况,然后依此分发新建的Pod到Kubernetes集群中可用的节点. 2. 实时监测Kubernetes集群中未分发和已分发的所有运行的Pod. 3. Scheduler也监测Minion/Node节点信息,由于会频繁查找Minion/Node节点,Scheduler会缓存一份最新的信息在本地. 4. 最后,Scheduler在分发Pod到指定的Minion/Node节点后,会把Pod相关的信息Binding写回API Server. > 更多Scheduler信息请参考:[Kubernetes核心原理(三)之Scheduler](http://www.huweihuang.com/article/kubernetes/core-principle/kubernetes-core-principle-scheduler/) #### 2.2.4.kubectl[集群管理命令行工具集] 通过客户端的kubectl命令集操作,API Server响应对应的命令结果,从而达到对kubernetes集群的管理. 参考文章:https://yq.aliyun.com/articles/47308 ### 2.3.kube-node[工作节点] Kubelet结构图 ![](/public/39/image4.png) #### 2.3.1.Kubelet[节点上的Pod管家] ![](/public/39/image5.png) 负责Node节点上pod的创建.修改.监控.删除等全生命周期的管理 定时上报本Node的状态信息给API Server. kubelet是Master API Server和Minion/Node之间的桥梁,接收Master API Server分配给它的commands和work,通过kube-apiserver间接与Etcd集群交互,读取配置信息. 具体的工作如下: 1) 设置容器的环境变量.给容器绑定Volume.给容器绑定Port.根据指定的Pod运行一个单一容器.给指定的Pod创建network 容器. 1) 同步Pod的状态.同步Pod的状态.从cAdvisor获取coner info. pod info. root info. machine info. 3) 在容器中运行命令.杀死容器.删除Pod的所有容器. 更多Kubelet信息请参考:[Kubernetes核心原理(四)之Kubelet](http://www.huweihuang.com/article/kubernetes/core-principle/kubernetes-core-principle-kubelet/) #### 2.3.2.Proxy[负载均衡.路由转发] Proxy是为了解决外部网络能够访问跨机器集群中容器提供的应用服务而设计的,运行在每个Minion/Node上.Proxy提供TCP/UDP sockets的proxy,每创建一种Service,Proxy主要从etcd获取Services和Endpoints的配置信息(也可以从file获取),然后根据配置信息在Minion/Node上启动一个Proxy的进程并监听相应的服务端口,当外部请求发生时,Proxy会根据Load Balancer将请求分发到后端正确的容器处理. Proxy不但解决了同一主宿机相同服务端口冲突的问题,还提供了Service转发服务端口对外提供服务的能力,Proxy后端使用了随机.轮循负载均衡算法. ## 3. 环境设置(三台都要设置) kubeadm是管理集群生命周期的重要工具,从创建到配置再到升级,处理现有硬件上的生产集群的引导,并以最佳实践方式配置核心kubernetes组件,以便为新节点提供安全而简单的连接流程并支持轻松升级.kubernetes1.13 中kubeadm正式GA. ###cat /etc/hosts ### ![](/public/39/image6.jpeg) ```shell ###关闭防火墙### systemctl stop firewalld systemctl disable firewalld ###禁用SELINUX### vi /etc/selinux/config SELINUX=disabled ###修改网络参数配置### #vi /etc/sysctl.conf 最后 sysctl -p 生效 net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward=1 ###切换账户sysctl会失效!!!!!!!!!!!!!!!!!### modprobe br_netfilter sysctl -p ``` [参照27.Docker的安装和使用,安装Docker](/public/post/27-docker-config/) ###不要把docker的data-root(/var/lib/docker) 放到 cephfs网络存储 ```shell ###禁用swap### ###k8s 1.8开始要求必须禁用Swap,如果不关闭,默认配置下kubelet将无法启动.### vi /etc/fstab ###删除swap交换分区### #/swap.img none swap sw 0 0 ###然后运行### sudo swapoff -a ###修改hosts,设置主机名和apiServer需要用到的域名#### vi /etc/hosts ``` 安装kubeadm kubelet kubectl 增加k8s仓库 vi /etc/yum.repos.d/kubernetes.repo ``` [kubernetes] name=kubernetes baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/ enabled=1 gpgcheck=0 repo_gpgcheck=1 gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg ``` ```shell ###安装kubelet kubeadm kubectl### yum clean all yum install -y kubelet kubeadm kubectl kubernetes-cni runc systemctl daemon-reload ###大坑,坑了我一天!!!### ###kubectl没有启动成功,报错先不管,后面的kubeadm init会拉起 systemctl enable kubelet ``` ###IPVS代替IPTABLES### 日志查看目前使用的模式: ```kubectl -nkube-system logs kube-proxy-gfhbz``` 确保 ipvs 需要的内核模块,需要下面几个模块: ip_vs. ip_vs_rr. ip_vs_wrr. ip_vs_sh. nf_conntrack ```shell #加载模块 modprobe -- ip_vs modprobe -- ip_vs_rr modprobe -- ip_vs_wrr modprobe -- ip_vs_sh modprobe -- nf_conntrack #检查是否安装了ipvs mod lsmod | grep ip_vs ###修改ConfigMap的kube-system/kube-proxy中的config.conf### kubectl edit cm kube-proxy -n kube-system #修改ipvs:下的 mode="ipvs" ###重启kube-proxy### kubectl -nkube-system delete pod kube-proxy-gfhbz ``` 然后再查看kube-proxy日志,看看目前使用的模式 ## 4. Master上使用kubeadm安装k8s k8s的控制面板组件运行在Master节点上,包括etcd和APIServer(kubectl便是通过APIServer与k8s通信). 在执行初始化之前,有一下3点需要注意: 1.选择一个网络插件,并检查它是否需要在初始化Master时指定一些参数,比如可能需要根据选择的插件来设置```--pod-network-cidr```参数,calico默认是192.168.0.0/16,也可以修改calico.yml. 2.kubeadm使用eth0的默认网络接口(通常是内网IP)做为Master节点的advertise address,如果想使用不同的网络接口,可以使用```--APIServer-advertise-address=```参数来设置.如果适应IPv6,则必须使用IPv6d的地址,如:--APIServer-advertise-address=fd00::101. 3.使用kubeadm config images pull来预先拉取初始化需要用到的镜像,用来检查是否能连接到Kubenetes的Registries. Kubenetes默认Registries地址是k8s.gcr.io,国内不能访问,在1.13版本增加了一个```--image-repository```参数,默认值是k8s.gcr.io,指定为国内镜像地址:registry.aliyuncs.com/google_containers 其次,还需要指定--kubernetes-version参数,因为它的默认值是stable-1,会导致从https://dl.k8s.io/release/stable-1.txt下载最新的版本号,可以将其指定为固定版本(最新版:v1.29.2)来跳过网络请求. 4.```--service-cidr```:指定Service网络的范围,即负载均衡VIP使用的IP地址段. ###使用calico网络 ```--pod-network-cidr=192.168.0.0/16```,建议使用集群中用到的kubeadm-config.yaml文件进行创建### ```shell kubeadm init --image-repository registry.aliyuncs.com/google_containers --kubernetes-version v1.29.2 --pod-network-cidr=192.168.0.0/16 --service-cidr=10.96.0.0/12 ``` 输出中有以下关键内容: [kubelet-start]生成kubelet的配置文件,/var/lib/kubelet/config.yaml [certificates]生成相关的各种证书,/etc/kubernetes/pki [kubeconfig]生成相关的kubeconfig文件,/etc/kubernetes [control-plane]Using manifest folder,/etc/kubernetes/manifests [kube-controller-manager] 配置文件 /etc/pki/,/etc/ssl/certs etcd的数据文件保存到了:/var/lib/etcd [bootstraptoken]生成token记录下来,后边使用kubeadm join往集群中添加节点时会用到 下面的命令是配置普通用户(非root)如何使用kubectl访问集群: ```shell mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config ``` 最后是worker节点加入集群的命令: ```shell kubeadm join 10.0.67.15:6443 --token upwdcc.j90bhmkkwdklpm2f --discovery-token-ca-cert-hash sha256:7e79e6d0a6cda ``` ###初始化root环境变量,如果发现无法访问APIServer(8080端口),就设置一下#### export KUBECONFIG=/etc/kubernetes/admin.conf ###使环境变量生效### source /root/.bash_profile ###安装 Calico 网络插件### Calico是一个纯三层的虚拟网络方案,为每个容器分配一个IP,每个host都是 router,把不同host的容器连接起来.与VxLAN不同的是,Calico不对数据包做额外封装,不需要NAT和端口映射,扩展性和性能都很好. Calico默认使用的的网段是192.168.0.0/16,kubeadm在init的时候,通过```--pod-network-cidr=192.168.0.0/16```指定,也可以修改calico.yml来指定不同的网段. ###最新的calico版本### wget https://docs.projectcalico.org/manifests/calico.yaml ###可以修改文件中的 192.168.0.0/16,和kubeadm init中的 ```--pod-network-cidr=192.168.0.0/16``` 保持一致### ```kubectl apply -f calico.yaml``` 稍等片刻,再使用```kubectl get pods --all-namespaces```命令来查看网络插件的安装情况: ![](/public/39/image7.jpeg) 默认情况下,由于安全原因,集群并不会将pods部署在Master节点上,一般也建议这样做,如果服务器较少做集群时,可以开启.在开发环境下,可能只有一个Master节点,命令来解除这个限制: ```shell kubectl taint nodes --all node-role.kubernetes.io/master- ###输出### node/master untainted ###赶走容器,常用于升级docker和k8s组件,服务暂时不可用#### kubectl taint node node1 node-role.kubernetes.io/master=:NoExecute ``` ###kubeadm安装的apiServer的crt证书,默认是1年的有效期### https://www.cnblogs.com/hahp/p/8440743.html https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-certs/ ```shell ###自动产生新的crt证书,三台都要执行### https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-alpha/ ###kubeadm alpha certs renew all --config kubeadm-config.yaml kubeadm alpha certs renew all ###查看证书的有效期### kubeadm alpha certs check-expiration ###openssl查看证书有效期### openssl x509 -noout -text -in /etc/kubernetes/pki/apiserver.crt ###/etc/kubernetes/pki下的CA证数不会更新,CA有效期10年,需要手动更新### openssl x509 -noout -text -in /etc/kubernetes/pki/ca.crt ``` ## 5. 加入工作节点 在node节点上安装 kubelet kubeadm kubectl ```shell yum clean all yum install -y kubelet kubeadm kubectl systemctl enable kubelet ``` 要为群集添加工作节点,需要在每台node工作节点执行以下操作: ```shell kubeadm join : --token --discovery-token-ca-cert-hash sha256: kubeadm join 10.0.67.15:6443 --token upwdcc.j90bhmkkwdklpm2f --discovery-token-ca-cert-hash sha256:7e79e6d0a6cda249479baf03103ebfa71398b69084537327f1a02a1a12d94481 ##如果忘记了Master节点的加入token,可以使用如下命令来查看: kubeadm token list ##默认token有效期是24小时,如果token已经过期,以下命令重新生成:## kubeadm token create ###生成--discovery-token-ca-cert-hash的值:### openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //' ###在master上查看状态### kubectl get nodes ``` ![](/public/39/image8.jpeg) ## 6. 验证 ### 6.1.deployment发布Nginx 验证kube-APIServer,kube-controller-manager,kube-scheduler,pod network是否正常: 部署一个 Nginx Deployment,参考文档: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/ ```kubectl create -f https://k8s.io/examples/controllers/nginx-deployment.yaml``` #### 验证Nginx Pod是否正确运行,分配192.168.开头的集群内IP #### ```kubectl get pods -l app=nginx -o wide``` ![](/public/39/image10.jpeg) ### ~~6.2.kube-proxy代理服务~~ ###以NodePort方式对外提供服务### ###https://kubernetes.io/docs/concepts/services-networking/connect-applications-service/ ```kubectl expose deployment nginx-deployment --port=80 --type=NodePort``` 也可以使用yaml的方式发布service ![](/public/39/image11.jpeg) ###查看集群外可访问的Port### ```kubectl get services nginx-deployment``` ![](/public/39/image13.jpeg) ###可以通过任意 NodeIP:Port 在集群外部访问这个服务### curl http://10.0.67.19:30906 curl http://10.0.67.21:30906 ###也可以通过集群的虚拟IP访问,端口就是80了### curl http://10.102.206.73:80 ### 6.3.dns和pod network ###运行Busybox并进入交互模式### ```kubectl run -it curl --image=radial/busyboxplus:curl``` ###进入pod### ```#kubectl exec -it nginx-deployment-549647f4db-l4jdm -- /bin/bash``` ###nslookup nginx-deployment是否可以解析集群内的IP,验证DNS是否正常### ![](/public/39/image14.jpeg) ###通过服务名进行访问,验证kube-proxy是否正常### wget http://nginx-deployment/ ![](/public/39/image15.jpeg) ###分别访问Pod的内网IP,验证跨Node的网络通信是否正常### ![](/public/39/image10.jpeg) wget http://192.168.1.2 wget http://192.168.1.3 wget http://192.168.2.2 ![](/public/39/image16.jpeg) ### 6.4.删除service,deploment,pod ```shell ###查看### kubectl get service|deployment|pod ###查看describe### kubectl describe service|deployment|pod ###查看正在运行的yaml文件#### kubectl get service|deployment|pod nginx-deployment -o yaml >test.yaml ###修改deployment的副本数量### kubectl scale deployment nginx-deployment --replicas=1 ###强制删除pod### kubectl delete pod podname --grace-period=0 --force ###删除service### kubectl delete service nginx-service ###删除deployment会把关联的pod也删除,每个deployment的名称是唯一的,生成的pod名称都是以deployment的名称为前缀,也就是一个pod的deployment是唯一的,就是同一个镜像(template)实例化的时候就确定了deployment归属### kubectl delete deployment nginx-deployment ``` ### 6.5.deployment滚动升级 参考:http://docs.kubernetes.org.cn/317.html ```shell ##创建一个nginx## kubectl create -f https://k8s.io/examples/controllers/nginx-deployment.yaml --record ``` 将kubectl --record可以在annotation中记录当前命令创建或者升级了该资源.这在未来会很有用,例如查看在每个 Deployment revision 中执行了哪些命令. ```shell ###更新nginx的镜像升级到1.15.7### kubectl set image deployment/nginx-deployment nginx=nginx:1.15.7 ###也可以编辑deployment的文件属性版本,保存之后自动发布### kubectl edit deployment/nginx-deployment ###查看版本发布状态进度### kubectl rollout status deployment/nginx-deployment ``` ![](/public/39/image17.jpeg) ###升级错误,自动终止### ```kubectl set image deployment/nginx-deployment nginx=nginx:abc``` ![](/public/39/image18.jpeg) 版本号错误,会卡着无法升级,Deployment controller会自动停止坏的 rollout,并停止扩容新的 ReplicaSet.查看状态 #kubectl get rs #kubectl get pods 可以设置deployment的minReadySeconds指定热升级的准备时间.apply ![](/public/39/image19.jpeg) ```shell ###检查 Deployment 升级的历史记录### kubectl rollout history deployment/nginx-deployment 创建Deployment时使用--recored参数可以记录命令,可以查看每次vevision 的变化. kubectl rollout history deployment/nginx-deployment --revision=2 ###回退到上一个版本### kubectl rollout undo deployment/nginx-deployment ###回退到指定的版本### kubectl rollout undo deployment/nginx-deployment --to-revision=2 ``` ### 6.6.横向弹性扩容 https://www.kubernetes.org.cn/4664.html https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/ Horizontal Pod Autoscaler可以根据CPU使用率或应用自定义metrics自动扩展Pod数量(支持replication controller.deployment和replica set). 控制管理器每隔30s(可以通过----horizontal-pod-autoscaler-sync-period修改)查询metrics的资源使用情况,heapster已经废弃,推荐使用metrics-server自定义metrics. ```shell ###创建nginx-deployment的hpa,CPU超过50%就创建pod实例,最少1个,最多10个### kubectl autoscale deployment nginx-deployment --cpu-percent=50 --min=1 --max=10 ###查看hpa### kubectl get hpa ###查看nginx-deployment hpa的详细信息### kubectl describe hpa nginx-deployment ###删除hpa### kubectl delete hpa nginx-deployment ``` ### 6.7.Tomcat的完整例子 [下载tomcat yaml文件](/public/39/tomcat.yaml) ## 7. 资源限制 参考资料: https://blog.csdn.net/liyingke112/article/details/77198045 http://cizixs.com/2018/06/25/kubernetes-resource-management/ [下载LimitRange.yaml](/public/39/LimitRange.yaml) 默认只是对default生效,需要指定具体的namespace ## 8. 卸载集群 想要撤销kubeadm执行的操作,首先要[排除节点],并确保该节点为空,然后再将其关闭. 在Master节点上运行: kubectl drain --delete-local-data --force --ignore-daemonsets kubectl delete node 然后在需要移除的节点上,重置kubeadm的安装状态: ```shell kubeadm reset rm -rf /etc/kubernetes rm -rf /var/lib/etcd rm -rf $HOME/.kube systemctl disable kubelet #ifconfig cni0 down #ip link delete cni0 #rm -rf /var/lib/cni/ ###如果要重新配置集群,使用新的参数重新运行kubeadm init或者kubeadm join即可. ###cordon 设定node不可使用 ###drain 设定node进入维护模式 ###uncordon 设定node可以使用 kubectl cordon node1 kubectl drain node1 kubectl uncordon node1 ###赶走容器,常用于升级docker和k8s组件,服务暂时不可用#### kubectl taint node node1 node-role.kubernetes.io/master=:NoExecute ``` 卸载之后,etcd集群异常,无法再次正常加入集群,这是一个bug,官方正在修复,手动从etcd集群中删除节点,然后kubectl删除node,手动从configmap kubeadm-config中删除ip https://github.com/kubernetes/kubeadm/issues/1300 https://github.com/kubernetes/kubernetes/pull/74112 https://github.com/kubernetes/kubeadm/issues/1312 ###删除后重新加入node节点##### 1. 删除kubeadmin中记录的apiEndpoints节点 ```kubectl edit cm kubeadm-config -nkube-system``` 删除掉残留的历史记录 ![](/public/39/image22.jpeg) 2. 进入到etcd容器,查看member list信息,删除掉残留的节点信息 ```shell kubectl exec -it .... export ETCDCTL_API=3 etcdctl --endpoints=https://[127.0.0.1]:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key member list ``` 3. 然后再kubeadm join ...... ## 9. 升级集群 ### 查看目前集群版本 ```kubectl get nodes``` ![](/public/39/image23.jpeg) ###把需要的镜像下载到本地,验证仓库是否有最新版本#### ```kubeadm config images pull --config kubeadm-config.yaml``` ###先升级kubeadm,三台都升级### ```yum install kubeadm``` ###k8s写死了版本验证的dl.k8s.io这个地址,被墙了,所以要先更新kubeadm### ### 升级计划步骤 ```kubeadm upgrade plan``` ![](/public/39/image24.jpeg) 可以升级到v1.29.2版本 ~~###升级k8s服务,在master服务器上升级,立即执行,会假死20分钟左右###~~ ### 升级 ```shell kubeadm upgrade apply v1.29.2 ###其他master升级### kubeadm upgrade node kubeadm upgrade apply v1.29.2 ###升级calico网络插件,需要先检查文档是否兼容,确定是否需要手动升级!!!### wget https://docs.projectcalico.org/manifests/calico.yaml ###升级kubelet kubectl,三台都升级### yum install -y kubelet kubectl ###重启三台服务器上的kubelet### systemctl daemon-reload systemctl restart kubelet ###再次检查集群### kubeadm upgrade plan ``` ###升级问题总结#### https://blog.csdn.net/qq_21816375/article/details/82803201 通过命令journalctl -u kubelet -f查看kubelet的日志 通过命令journalctl -xefu kubelet查看kubelet的日志 ## 10. 配置cephfs 参考:https://blog.csdn.net/ywq935/article/details/82716366 ### 10.1.创建cephfs环境 [参照文档:35.Ceph安装配置](/public/post/35-ceph-config/) ### 10.2.创建secret 在创建pv前,由于ceph是开启了cephx认证的,首先需要创建secret资源,k8s的secret资源采用的是base64加密,在ceph monitor上提取key: ```ceph auth get-key client.admin |base64``` QVFCL3E1ZGIvWFdxS1JBQTUyV0ZCUkxldnRjQzNidTFHZXlVYnc9PQ== ceph-secret.yaml ```yaml apiVersion: v1 kind: Secret metadata: name: ceph-secret data: ###通过ceph auth get-key client.admin |base64 获取 ### key: QVFDR2tSaGNVSXdpTHhBQWVVZXRtd1VncVR0ZFVQMlA5MXFLbmc9PQ== ``` #kubectl apply -f ceph-secret.yaml ### 10.3.创建pv #vi cephfs-pv.yaml ```yaml apiVersion: v1 kind: PersistentVolume metadata: name: cephfs-pv labels: pv: cephfs-pv spec: capacity: storage: 5Gi accessModes: - ReadWriteMany cephfs: monitors: - node1:6789 - node2:6789 - node3:6789 ###可以配置cephfs的子目录,绑定不同的用户,用于权限隔离#### path: / ###ceph的账号### user: admin secretRef: ###和ceph-secret.yaml中的metadata.name保持一致### name: ceph-secret readOnly: false ###回收策略:Retain手动回收,Recycle需要擦出后才能再使用,Delete相关联的存储资产被删除#### persistentVolumeReclaimPolicy: Recycle ``` ```kubectl create -f cephfs-pv.yaml``` ###查看pv### ```kubectl get pv``` ### 10.4.创建pvc ```vi cephfs-pvc.yaml``` ```yaml kind: PersistentVolumeClaim apiVersion: v1 metadata: name: cephfs-pvc spec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi selector: matchLabels: ###和cephfs-pv.yaml中的labels对应### pv: cephfs-pv ``` ```kubectl create -f cephfs-pvc.yaml``` ###查看 pvc### ```kubectl get pvc``` ![](/public/39/image28.jpeg) pv和pvc都已经自动变为Bound状态,pvc在创建的时候就会主动去寻找符合requets条件的pv资源,如果寻找到了,便会自动进行绑定,无需做标签匹配. 注意: 1. 当pv的容量大于pvc的需求时,pvc可以成功自动绑定pv; 2. 当pv的容量小于pvc的需求时,pvc无法绑定该pv; 3. pv和pvc是一对一的唯一绑定关系. 4. pvc只能归属到一个namespace,不能跨namespace. 5. pv/pvc的创建顺序是:pv -> pvc -> pod 6. pv/pvc的销毁顺序是:pod -> pvc -> pv,顺序一定不要错 7. pv确认成功之后再创建pvc,确认pvc成功之后再创建pod关联 例如: 2G的pv可以被1G的pvc绑定,并且绑定成功后,pvc的实际空间也是2G而不是1G; 1G的pv无法被2G的pvc绑定 ### 10.5.pod绑定pvc ##先删除原来的deployment-nginx### ```kubectl delete deployment nginx-deployment``` ###创建deployment-nginx### ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx ###使用的镜像### image: nginx:1.15.4 ports: ###容器的端口### - containerPort: 80 volumeMounts: ###挂载点### - mountPath: /usr/share/nginx/html ###对应下面卷 cephfs-pvc-pod 的名称### name: cephfs-pvc-pod ###指定子目录,会在cephfs里创建子文件夹#### subPath: cephfs-pvc-pod volumes: ###卷名称,对应上面的挂载名称### - name: cephfs-pvc-pod persistentVolumeClaim: ###对应cephfs-pvc.yaml的metadata.name### claimName: cephfs-pvc ``` ```kubectl create -f deployment-nginx.yaml``` ## 11.配置CephRBD http://docs.kubernetes.org.cn/803.html#Ceph_RBD https://github.com/kubernetes/kubernetes/issues/38923 https://blog.csdn.net/aixiaoyang168/article/details/79120095 kube-controller-manager中没有安装ceph相关的包,导致Ceph RBD StorageClass无法使用!!!坑太大,跳不过去,先暂停. key通过```ceph auth get-key client.rbdredis|base64``` 获取 ###创建redis-ceph-secret.yaml### ```yaml apiVersion: v1 kind: Secret metadata: name: admin-ceph-secret namespace: kube-system type: "kubernetes.io/rbd" data: ###通过ceph auth get-key client.admin |base64 获取 ### key: QVFDR2tSaGNVSXdpTHhBQWVVZXRtd1VncVR0ZFVQMlA5MXFLbmc9PQ== --- apiVersion: v1 kind: Secret metadata: name: redis-ceph-secret namespace: kube-system type: "kubernetes.io/rbd" data: ###通过ceph auth get-key client.rbdredis |base64 获取 ### key: QVFBVklVaGNzUFloQWhBQWJqdUhvR2lCVk12OE41Ym9TTlFkbFE9PQ== ``` ###创建StorageClass-- redis-storageclass.yaml### ```yaml kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: redis-ceph-storageclass provisioner: kubernetes.io/rbd reclaimPolicy: Retain parameters: monitors: node1:6789,node2:6789,node3:6789 adminId: admin adminSecretName: admin-ceph-secret adminSecretNamespace: kube-system pool: cephrbdpool userId: rbdredis userSecretName: redis-ceph-secret userSecretNamespace: kube-system fsType: ext4 imageFormat: "2" imageFeatures: layering ``` ###创建PVC-- redis-storageclass-pvc.yaml ### ```yaml kind: PersistentVolumeClaim apiVersion: v1 metadata: name: redis-ceph-pvc spec: accessModes: - ReadWriteOnce ###对应StorageClass### storageClassName: redis-ceph-storageclass resources: requests: storage: 1Gi ``` ## 12. 配置管理面板 参考资料:https://www.cnblogs.com/RainingNight/p/deploying-k8s-dashboard-ui.html Kubernetes Dashboard是一个管理Kubernetes集群的全功能Web界面,旨在以UI的方式完全替代命令行工具(kubectl等). [下载kubernetes-dashboard.yaml](/public/39/kubernetes-dashboard.yaml) ```kubectl apply -f kubernetes-dashboard.yaml``` ###查看pod### ```kubectl get pods --all-namespaces``` ![](/public/39/image34.jpeg) ###删除### #kubectl -n kube-system delete service kubernetes-dashboard #kubectl -n kube-system delete deployment kubernetes-dashboard ###因为SSL证书的问题,需要使用火狐浏览器才能跳过证书错误### 火狐浏览器打开https://10.0.67.15:31024,端口31024是yaml中配置的. ![](/public/39/image35.jpeg) 如上图,跳转到了登录页面,需要先创建个用户: ###创建用户:admin-user.yaml### ```yaml apiVersion: v1 kind: ServiceAccount metadata: name: admin-user namespace: kube-system ``` ```kubectl create -f admin-user.yaml``` ###绑定角色:admin-user-role-binding.yaml### ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: admin-user roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: admin-user namespace: kube-system ``` 默认情况下,kubeadm创建集群时已经创建了admin角色,直接绑定即可: ```kubectl create -f admin-user-role-binding.yaml``` ###获取admin-user的登陆token,用于登陆dashboard### ```kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-user | awk '{print $1}')``` ###把产生的token,复制到浏览器里,访问dashboard### ![](/public/39/image38.jpeg) ###浏览器的效果如下图### ![](/public/39/image39.png) ## 13. Kubeadm配置多Master ### 13.1.参考文档: https://kubernetes.io/docs/setup/independent/high-availability/ https://github.com/HikoQiu/kubeadm-install-k8s http://blog.51cto.com/nosmoking/2062887 https://www.qikqiak.com/post/how-to-use-ipvs-in-kubernetes/ https://blog.csdn.net/fanren224/article/details/86548398 ### 13.2.架构图 因为只有三台服务器,Master同时还是work节点. ![](/public/39/image40.jpeg) ### 13.3.基础环境准备 ###安装docker### ###关闭selinux和swap分区,配置iptables### ###修改yum源### ###三台服务器上安装kubelet.kubeadm.kubectl,并确保kubelet开机启动### ###修改三台服务的 /etc/hosts 文件,加上apiServer的解析域名### ###使用hosts代替了HA的解析功能,比较简单,也可用三台服务器使用nginx实现### ![](/public/39/image41.jpeg) ### 13.4.初始化kubeadm配置文件 ###如果需要使用ipvs,需要提前在服务器安装好ipvs模块### https://www.qikqiak.com/post/how-to-use-ipvs-in-kubernetes/ ###kubeadm init 的配置文件,拷贝到三台服务器### **kubeadm-config.yaml** ```yaml apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration ###指定k8s的版本### kubernetesVersion: v1.29.2 ### 指定阿里云镜像仓库### imageRepository: registry.aliyuncs.com/google_containers #imageRepository: registry.aliyuncs.com/k8sxio #imageRepository: registry.cn-shenzhen.aliyuncs.com/kubernetes_aliyun ##imageRepository: gcr.azk8s.cn/google_containers ### apiServerCertSANs 填所有的masterip,lbip其它可能需要通过它访问apiserver的地址,域名或主机名等 ### ### 如阿里fip,证书中会允许这些ip ### ### 这里填一个自定义的域名 ### ### 用于访问APIServer的LB,一般通过nginx或者haproxy做集群解析.可以在每台服务器做hosts映射到127.0.0.1 然后每台服务器上都安装nginx,做upstream,用于健康检查. ### ### 这里我为了方便,修改三台服务器上的 /etc/hosts ,把有三个master的IP都解析到 domian 的域名,hosts好像做了健康检查,代替了DNS的功能 ### apiServer: ###添加域名的SSL证书### certSANs: - "api.k8s.jiagou.com" ###apiServer的集群访问地址### controlPlaneEndpoint: "api.k8s.jiagou.com:6443" ### calico 网络插件的子网 ### networking: podSubnet: "192.168.0.0/16" dnsDomain: cluster.local serviceSubnet: "10.96.0.0/12" ``` ###查看依赖的镜像### ```kubeadm config images list --config kubeadm-config.yaml``` ![](/public/39/image43.jpeg) ###把需要的镜像下载到本地,验证仓库是否有最新版本#### ```kubeadm config images pull --config kubeadm-config.yaml``` ### 13.5.安装Master node1 我们目标是要搭建一个高可用的 master集群,node2 node3需要依赖node1初始化产生的证书文件,所以需要先在node1初始化. ```kubeadm init --config kubeadm-config.yaml``` 记下加入的命令,例如: ```kubeadm join api.k8s.jiagou.com:6443 --token 39tdfod --discovery-token-ca-cert-hash sha256:4270dsf6f7``` ###查看集群状态### #kubectl cluster-info ![](/public/39/image44.jpeg) ###安装网络插件### ###最新的calico版本### wget https://docs.projectcalico.org/manifests/calico.yaml ###可以修改文件中的 192.168.0.0/16,和kubeadm init中的 --pod-network-cidr=192.168.0.0/16 保持一致### ```kubectl apply -f calico.yaml``` ###master同时也做work节点### ```shell kubectl taint nodes --all node-role.kubernetes.io/master- kubectl taint nodes --all node-role.kubernetes.io/control-plane- ``` ##node/master untainted ###同步证书文件#### **sync.master.ca.sh** ```shell #!/bin/sh vhost="node2 node3" usr=root who=`whoami` if [[ "$who" != "$usr" ]];then echo "请使用 root 用户执行或者 sudo ./sync.master.ca.sh" exit 1 fi echo $who # 需要从 node1 拷贝的 ca 文件 caFiles=( /etc/kubernetes/pki/ca.crt /etc/kubernetes/pki/ca.key /etc/kubernetes/pki/sa.key /etc/kubernetes/pki/sa.pub /etc/kubernetes/pki/front-proxy-ca.crt /etc/kubernetes/pki/front-proxy-ca.key /etc/kubernetes/pki/etcd/ca.crt /etc/kubernetes/pki/etcd/ca.key /etc/kubernetes/admin.conf ) pkiDir=/etc/kubernetes/pki/etcd for h in $vhost do ssh ${usr}@$h "mkdir -p $pkiDir" echo "Dirs for ca scp created, start to scp..." # scp 文件到目标机 scp /etc/kubernetes/pki/ca.crt /etc/kubernetes/pki/ca.key /etc/kubernetes/pki/sa.key /etc/kubernetes/pki/sa.pub /etc/kubernetes/pki/front-proxy-ca.crt /etc/kubernetes/pki/front-proxy-ca.key ${usr}@$h:/etc/kubernetes/pki/ scp /etc/kubernetes/pki/etcd/ca.crt /etc/kubernetes/pki/etcd/ca.key ${usr}@$h:/etc/kubernetes/pki/etcd/ scp /etc/kubernetes/admin.conf ${usr}@$h:/etc/kubernetes/ echo "Ca files transfered for $h ... ok" done ``` ###到node2和node3上查看/etc/kubernetes/ 目录### ![](/public/39/image46.jpeg) ### 13.6.安装Master node2,node3 在master的join命令里加入 --experimental-control-plane 参数,这个就是master集群的加入,不是普通node节点的加入. ~~需要先把 api.k8s.jiagou.com 只解析到node1,集群完成再改成解析到3台.因为hosts默认会解析到本机的ip,造成无法加入集群.~~ 例如: ```kubeadm join api.k8s.jiagou.com:6443 --token 39tdfod --discovery-token-ca-cert-hash sha256:4270dsf6f7 --experimental-control-plane``` ###master同时也做work节点### ```shell kubectl taint nodes --all node-role.kubernetes.io/master- kubectl taint nodes --all node-role.kubernetes.io/control-plane- ``` ###node3的操作和node2的一致### ### ~~13.7.部署高可用CoreDNS.K8S默认做了高可用~~ ```kubectl get pods -n kube-system -o wide``` ![](/public/39/image47.jpeg) ###从列表中,可以看到CoreDNS的两个Pod都在node1上,存在单点问题### ###部署多实例的coredns集群,创建 coredns deployment 配置 coredns.yaml ### 参考: https://github.com/coredns/deployment/tree/master/kubernetes 使用deploy.sh -s (或者-r -i,自己根据描述确定)生成需要的coredns.yaml [下载coredns.zip](/public/39/coredns.zip) ```./deploy.sh -s > coredns.yaml``` ###执行生成的 coredns.yaml#### ```kubectl apply -f coredns.yaml``` ###删除原来单点的 CoreDNS### ```kubectl delete --namespace=kube-system deployment kube-dns``` ###再次检查状态### ![](/public/39/image49.jpeg) ###检查 端点/入口/节点### ```kubectl get endpoints``` ### 13.8.资源限制 https://ieevee.com/tech/2018/05/15/k8s-limits.html [下载LimitRange.yaml](/public/39/LimitRange.yaml) 默认只是对default命名空间生效,需要指定具体的namespace 简单来说,request影响的是k8s的调度,也就是说k8s会保证container所request的资源,在调度时会考虑node是否满足request的条件.而limit则是实际运行时k8s的限制,防止container无限制的占用node的资源.显然的,由于调度时更多的考虑了request而不是limit,那么必然会出现某个node上container的limit总和超过该node资源的情况,此时,k8s针对cpu和memory会由不同的处理. 对于cpu,k8s认为cpu是可压缩的,在应用达到limit时,k8s会减少该容器的调度时间,并不会杀死应用. 对于memory,k8s认为memory是无法压缩的,此时k8s会杀死占用资源超过其request的应用(1.9版本之后的版本).首当其冲的是没有指定request的container,然后是使用资源超过其request更多的container.同等情况下优先级更低的container更容易被杀死. http://docs.kubernetes.org.cn/723.html#Node_Allocatable Kubernetes节点上的 allocatable 被定义为pod可用计算资源量.调度器不会超额申请 allocatable.目前支持CPU,memory和storage这几个参数.给系统预留一些资源,不然容易死机. 需要谨慎设置Node Allocatable参数,kubelet或者服务器可能无法正常启动!!! ```shell #修改 vi /usr/lib/systemd/system/kubelet.service [Service] ExecStartPre=/usr/bin/mkdir -p /sys/fs/cgroup/cpuset/system.slice/kubelet.service ExecStartPre=/usr/bin/mkdir -p /sys/fs/cgroup/hugetlb/system.slice/kubelet.service #修改 vi /var/lib/kubelet/config.yaml enforceNodeAllocatable: -pods -system-reserved #修改 vi /var/lib/kubelet/kubeadm-flags.env ###给系统预留的资源### --system-reserved-cgroup=/system.slice --system-reserved=cpu=4,memory=8G ``` ## 14.备份还原集群数据 https://blog.csdn.net/ygqygq2/article/details/82753840 主要是备份/etc/kubernetes目录和etcd数据 把etcd备份放到/etc/kubernetes/pki/etcd/backup/下,然后压缩备份. ###执行shell, -- 后面的shell不会当成参数,不然会作为 kubect的参数## kubectl exec -it -n -- 复杂的shell可以用"" 作为参数 /bin/bash --ec "复杂shell指令" 脚本如下: ```shell #!/usr/bin/env bash etcdPodName=etcd-mzywx-k8s-node3 backupdirpath=/cephfs/k8s/backup ###创建目录### mkdir -p $backupdirpath mkdir -p /etc/kubernetes/pki/etcd/backup ###进入容器备份etcd集群数据### kubectl exec -it $etcdPodName -nkube-system -- /bin/sh -ec "ETCDCTL_API=3 etcdctl --endpoints=https://[127.0.0.1]:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key snapshot save /etc/kubernetes/pki/etcd/backup/etcd-snapshot.db" ###压缩备份/etc/kubernetes### tar czf $backupdirpath/kubernetes_$(date +%Y-%m-%d_%H-%M-%S).tar.gz /etc/kubernetes ###删除30天内的文件 find $backupdirpath/* -mtime +30 -exec rm -rf {} \; ```` 还原主要是证书和etcd数据 注意:数据恢复操作,会停止全部应用状态和访问!!! 分别停掉三台Master机器的kube-apiserver. mv /etc/kubernetes/manifests /etc/kubernetes/manifests.bak docker ps|grep k8s_ # 查看etcd,api是否up,等待全部停止 mv /var/lib/etcd /var/lib/etcd.bak 使用同一份snapshot备份文件依次还原集群三台etcd. ## 15. 常用配置 配置deployment的更新策略为挨个升级,保证业务不中断,在副本不太多的时候比较适合. 可以给deployment增加默认的注解,如果注解更新,deployment会热启动.可以用于关联的configMap更新热重启. 默认配置 app 和version这两个label,用于兼容istio. ![](/public/39/image53.jpeg) ~~DaemonSet也可以配置更新策略,属性是updateStrategy,没有maxSurge参数,可以配置minReadySeconds,没有用,还是无法保证热升级,不用设置了~~ https://kubernetes.io/docs/tasks/manage-daemon/update-daemon-set/ ![](/public/39/image54.jpeg) ####还需要解决驱逐的时候,pod默认是中断的,可以使用grace-period 参数#### the job spec is invalid ... the field is immutable 这个异常是因为有些字段是不允许更新的,需要delete之后重新创建. [下载常用配置](/public/39/yaml.zip)