赞
踩
笔记列表:
简单来说,kubernetes就是容器管家
容器是打包和运行应用程序的好方式。在生产环境中,你需要管理运行应用程序的容器,并确保不会停机。 例如,如果一个容器发生故障,则需要启动另一个容器。如果系统处理此行为,会不会更容易?
这就是 Kubernetes 来解决这些问题的方法! Kubernetes 为你提供了一个可弹性运行分布式系统的框架。linux之上的一个服务编排框架;
Kubernetes 会满足你的扩展要求、故障转移、部署模式等。 例如,Kubernetes 可以轻松管理系统的 Canary 部署。
Kubernetes 为你提供:
Kubernetes 是一个可移植的、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。 Kubernetes 拥有一个庞大且快速增长的生态系统。Kubernetes 的服务、支持和工具广泛可用。
名称 Kubernetes 源于希腊语,意为“舵手”或“飞行员”。Google 在 2014 年开源了 Kubernetes 项目。 Kubernetes 建立在 Google 在大规模运行生产工作负载方面拥有十几年的经验 的基础上,结合了社区中最好的想法和实践。
Kubernetes 不是传统的、包罗万象的 PaaS(平台即服务)系统。
Kubernetes 在容器级别,而不是在硬件级别运行
它提供了 PaaS 产品共有的一些普遍适用的功能, 例如部署、扩展、负载均衡、日志记录和监视。
但是,Kubernetes 不是单体系统,默认解决方案都是可选和可插拔的。 Kubernetes 提供了构建开发人员平台的基础,但是在重要的地方保留了用户的选择和灵活性。
不限制支持的应用程序类型。 Kubernetes 旨在支持极其多种多样的工作负载,包括无状态、有状态和数据处理工作负载。 如果应用程序可以在容器中运行,那么它应该可以在 Kubernetes 上很好地运行。
不部署源代码,也不构建你的应用程序。 持续集成(CI)、交付和部署(CI/CD)工作流取决于组织的文化和偏好以及技术要求。
不提供应用程序级别的服务作为内置服务,例如中间件(例如,消息中间件)、 数据处理框架(例如,Spark)、数据库(例如,mysql)、缓存、集群存储系统 (例如,Ceph)。这样的组件可以在 Kubernetes 上运行,并且/或者可以由运行在 Kubernetes 上的应用程序通过可移植机制(例如, 开放服务代理)来访问。
不要求日志记录、监视或警报解决方案。 它提供了一些集成作为概念证明,并提供了收集和导出指标的机制。
不提供或不要求配置语言/系统(例如 jsonnet),它提供了声明性 API, 该声明性 API 可以由任意形式的声明性规范所构成。RESTful;写yaml文件
不提供也不采用任何全面的机器配置、维护、管理或自我修复系统。
此外,Kubernetes 不仅仅是一个编排系统,实际上它消除了编排的需要。 编排的技术定义是执行已定义的工作流程:首先执行 A,然后执行 B,再执行 C。 相比之下,Kubernetes 包含一组独立的、可组合的控制过程, 这些过程连续地将当前状态驱动到所提供的所需状态。 如何从 A 到 C 的方式无关紧要,也不需要集中控制,这使得系统更易于使用 且功能更强大、系统更健壮、更为弹性和可扩展。
我们的k8s集群是主管理从
的方式,将会存在一个或者多个master节点,然后管理多个node节点
解释图1:
解释图2:
master和node节点简介:
master节点(Control Plane【控制面板】):master节点控制整个集群
master节点上有一些核心组件:
node节点(worker工作节点):
如何部署一个应用?
程序员:调用CLI告诉master,我们现在要部署一个tomcat应用
想让k8s部署一个tomcat?
0、开机默认所有节点的kubelet、master节点的scheduler(调度器)、controller-manager(控制管理器)一直监听master的api-server发来的事件变化(for ::)
1、程序员使用命令行工具: kubectl ; kubectl create deploy tomcat --image=tomcat8(告诉master让集群使用tomcat8镜像,部署一个tomcat应用)
2、kubectl命令行内容发给api-server,api-server保存此次创建信息到etcd
3、etcd给api-server上报事件,说刚才有人给我里面保存一个信息。(部署Tomcat[deploy])
4、controller-manager监听到api-server的事件,是 (部署Tomcat[deploy])
5、controller-manager 处理这个 (部署Tomcat[deploy])的事件。controller-manager会生成Pod的部署信息【pod信息】
6、controller-manager 把Pod的信息交给api-server,再保存到etcd
7、etcd上报事件【pod信息】给api-server。
8、scheduler专门监听 【pod信息】 ,拿到 【pod信息】的内容,计算,看哪个节点合适部署这个Pod【pod调度过后的信息(node: node-02)】,
9、scheduler把 【pod调度过后的信息(node: node-02)】交给api-server保存给etcd
10、etcd上报事件【pod调度过后的信息(node: node-02)】,给api-server
11、其他节点的kubelet专门监听 【pod调度过后的信息(node: node-02)】 事件,集群所有节点kubelet从api-server就拿到了 【pod调度过后的信息(node: node-02)】 事件
12、每个节点的kubelet判断是否属于自己的事情;node-02的kubelet发现是他的事情
13、node-02的kubelet启动这个pod。汇报给master当前启动好的所有信息
2台虚拟机即可,一台做master节点,另外一台做worker节点不会安装的可以看这个:在VMvare中安装CentOS,建议安装centos7
安装之后需要配置静态ip和语言,记得先切换root用户(CentOS如何切换超级用户/root用户),然后根据以下文章配置即可:
修改虚拟机名称(注意:每个虚拟机单独执行,不能是localhost,每个虚拟机的主机名称必须不同,比如可以是k8s-01、k8s-02……):
# 例如:hostnamectl set-hostname k8s-01
hostnamectl set-hostname 主机名称
修改其他配置,直接复制执行即可(注意:在所有虚拟机上都执行相同指令即可)
######################################################################### #关闭防火墙: 如果是云服务器,需要设置安全组策略放行端口 # https://kubernetes.io/zh/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#check-required-ports systemctl stop firewalld systemctl disable firewalld # 查看修改结果 hostnamectl status # 设置 hostname 解析 echo "127.0.0.1 $(hostname)" >> /etc/hosts #关闭 selinux: sed -i 's/enforcing/disabled/' /etc/selinux/config setenforce 0 #关闭 swap: swapoff -a sed -ri 's/.*swap.*/#&/' /etc/fstab #允许 iptables 检查桥接流量 #https://kubernetes.io/zh/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#%E5%85%81%E8%AE%B8-iptables-%E6%A3%80%E6%9F%A5%E6%A1%A5%E6%8E%A5%E6%B5%81%E9%87%8F ## 开启br_netfilter ## sudo modprobe br_netfilter ## 确认下 ## lsmod | grep br_netfilter ## 修改配置 #####这里用这个,不要用课堂上的配置。。。。。。。。。 #将桥接的 IPv4 流量传递到 iptables 的链: # 修改 /etc/sysctl.conf # 如果有配置,则修改 sed -i "s#^net.ipv4.ip_forward.*#net.ipv4.ip_forward=1#g" /etc/sysctl.conf sed -i "s#^net.bridge.bridge-nf-call-ip6tables.*#net.bridge.bridge-nf-call-ip6tables=1#g" /etc/sysctl.conf sed -i "s#^net.bridge.bridge-nf-call-iptables.*#net.bridge.bridge-nf-call-iptables=1#g" /etc/sysctl.conf sed -i "s#^net.ipv6.conf.all.disable_ipv6.*#net.ipv6.conf.all.disable_ipv6=1#g" /etc/sysctl.conf sed -i "s#^net.ipv6.conf.default.disable_ipv6.*#net.ipv6.conf.default.disable_ipv6=1#g" /etc/sysctl.conf sed -i "s#^net.ipv6.conf.lo.disable_ipv6.*#net.ipv6.conf.lo.disable_ipv6=1#g" /etc/sysctl.conf sed -i "s#^net.ipv6.conf.all.forwarding.*#net.ipv6.conf.all.forwarding=1#g" /etc/sysctl.conf # 可能没有,追加 echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf echo "net.bridge.bridge-nf-call-ip6tables = 1" >> /etc/sysctl.conf echo "net.bridge.bridge-nf-call-iptables = 1" >> /etc/sysctl.conf echo "net.ipv6.conf.all.disable_ipv6 = 1" >> /etc/sysctl.conf echo "net.ipv6.conf.default.disable_ipv6 = 1" >> /etc/sysctl.conf echo "net.ipv6.conf.lo.disable_ipv6 = 1" >> /etc/sysctl.conf echo "net.ipv6.conf.all.forwarding = 1" >> /etc/sysctl.conf # 执行命令以应用 sysctl -p
sudo yum remove docker* sudo yum install -y yum-utils #配置docker yum 源 sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo #安装docker 19.03.9 yum install -y docker-ce-3:19.03.9-3.el7.x86_64 docker-ce-cli-3:19.03.9-3.el7.x86_64 containerd.io # 首先启动docker,然后让docker随虚拟机一起启动 systemctl start docker systemctl enable docker #配置加速,使用网易镜像加速器 sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["http://hub-mirror.c.163.com"] } EOF sudo systemctl daemon-reload sudo systemctl restart docker
# 配置K8S的yum源 cat <<EOF > /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=0 repo_gpgcheck=0 gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg EOF # 卸载旧版本 yum remove -y kubelet kubeadm kubectl # 查看可以安装的版本 yum list kubelet --showduplicates | sort -r # 安装kubelet、kubeadm、kubectl 指定版本 yum install -y kubelet-1.21.0 kubeadm-1.21.0 kubectl-1.21.0 # 开机启动kubelet systemctl enable kubelet && systemctl start kubelet
直接使用docker load -i 镜像tar包名称
即可导入,镜像在下面
链接:https://pan.baidu.com/s/17LEprW3CeEAQYC4Dn_Klxg?pwd=s5bt
提取码:s5bt
说明:
这些镜像是atguigu雷丰阳老师传到阿里云上的,我直接放到百度网盘中,大家可以直接导入即可
因为我们所用的k8s版本是1.21.0,根据https://projectcalico.docs.tigera.io/archive/v3.21/getting-started/kubernetes/requirements可以看到对应的calico版本是v3.21,截图在下面
直接使用docker load -i 镜像tar包名称
即可导入,镜像在下面
链接:https://pan.baidu.com/s/122EoickH6jsSMJ8ECJ3P5g?pwd=vv8n
提取码:vv8n
执行ip a
就可以找到了,如下:
service地址区间、pod地址区间和master节点的ip只要不重复就可以了,由于我的是192.168.139.128
,所以我选择的两个地址区间如下:
service地址区间:10.98.0.0/16
(注意:16代表前面XX.XX是固定的)
pod地址区间:10.99.0.0/16
(注意:16代表前面XX.XX是固定的)
注意:将master主节点id
、service地址区间
、pod地址区间
改成你自己主节点的,查找方法在上面
kubeadm init \
--apiserver-advertise-address=master主节点id \
--image-repository registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images \
--kubernetes-version v1.21.0 \
--service-cidr=service地址区间 \
--pod-network-cidr=pod地址区间
比如我的就是
kubeadm init \
--apiserver-advertise-address=192.168.139.128 \
--image-repository registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images \
--kubernetes-version v1.21.0 \
--service-cidr=10.98.0.0/16 \
--pod-network-cidr=10.99.0.0/16
说明:
指令中的registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images
对应k8s相关镜像的前缀,这些镜像来自于atguigu雷丰阳老师的阿里云镜像仓库,我直接把它放到百度网盘中了,大家可以直接下载导入即可
下面是我的初始化结果:
Your Kubernetes control-plane has initialized successfully! To start using your cluster, you need to run the following as a regular user: mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config Alternatively, if you are the root user, you can run: export KUBECONFIG=/etc/kubernetes/admin.conf You should now deploy a pod network to the cluster. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: https://kubernetes.io/docs/concepts/cluster-administration/addons/ Then you can join any number of worker nodes by running the following on each as root: kubeadm join 192.168.139.129:6443 --token gjkehd.e68y3u6csud6mz8y \ --discovery-token-ca-cert-hash sha256:0425228dfd80644425f3a1cbd5cb4a8a610f7e45b2d3d3b2f7f6ccddf60a98d7
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
export KUBECONFIG=/etc/kubernetes/admin.conf
链接:https://pan.baidu.com/s/1EWJNtWQuekb0LYXernjWew?pwd=70ku
提取码:70ku
说明:
虽然我已经给大家提供了calico.yaml
文件,但是还想和大家说一下该文件的来源,首先在2.5、导入calico镜像中可以知道,我们本次使用的calico版本是v3.21
,那么可以在linux上使用wget https://docs.projectcalico.org/v3.21/manifests/calico.yaml --no-check-certificate
指令下载(注意链接中的版本号是v3.21),其中--no-check-certificate
代表非安全方式下载,必须这样操作,不然无法下载
另外对于calico.yaml
来说,我们将所有image的值前面的docker.io/去掉了,毕竟我们已经将calico镜像导入了,就不用去docker.io下载镜像了
下一个需要修改的位置就是3.4.4、修改calico.yaml
里面的值了,这个直接跟着下面修改即可
根据ifconfig
找到我们所用ip前面的内容,比如我的是ens33
,如下:
根据你ip前面的结果来修改文件中interface
的值,如下:
其实下面这些指令都是我自己添加的,原来的calico.yaml
中是没有的,添加的原因是执行calico.yaml
报错了,然后根据这篇calico/node is not ready来添加的,添加之后在执行yaml
文件,然后calico
的所有容器都运行正常了
- name: IP_AUTODETECTION_METHOD
value: "interface=ens33"
kubectl apply -f calico.yaml
找到3.4、根据初始化结果来执行操作的master主节点中的最后结果,记得用你自己的初始化结果哈,然后在所有worker节点执行即可
如果命令中的token失效,可以在主节点虚拟机中通过kubeadm token create --print-join-command
得到最新的指令,然后在所有worker节点的虚拟机中执行即可
默认是iptables
模式,但是这种模式在大集群中会占用很多空间,所以建议使用ipvs
模式
首先执行kubectl edit cm kube-proxy -n kube-system
,然后输入/mode
,将mode的值设置成ipvs
,保存退出即可,如下:
kubectl get pod -A|grep kube-proxy
例如pod如下:
kubectl delete pod pod1名称 pod2名称…… -n kube-system
根据上面的命令,可以找到kube-proxy的pod名称,比如我上面的就是kube-proxy-cxh25
、kube-proxy-ws4nn
,那么删除命令就是:kubectl delete pod kube-proxy-cxh25 kube-proxy-ws4nn -n kube-system
,由于k8s拥有自愈能力,所以proxy删除之后就会重新拉起一个pod
使用kubectl get pod -A
命令即可,我们只看NAMESPACE
下面的kube-system
,只要看到所有STATUS
都是Running
,并且READY
都是1/1
就可以了,如果pod一直不满足要求,那就可以使用kubectl describe pod pod名称 -n kube-system
查看一下pod执行进度,如果把握不准,可以使用reboot
命令对所有虚拟机执行重启操作,最终结果是下面这样就可以了
链接:https://pan.baidu.com/s/1rNnCUa7B7GaX2SFjiPgZTQ?pwd=z2zp
提取码:z2zp
说明:
该yaml来自于https://github.com/kubernetes/dashboard中的该位置:
直接通过wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yaml
下载该yaml即可
由于我们通过浏览器直接访问kubernetes dashboard
,所以还需要在yaml
文件中添加type:NodePort
,如下:
然后直接执行kubectl apply -f recommended.yaml
即可
kubectl apply -f recommended.yaml
链接:https://pan.baidu.com/s/14upSiYdrZaw5EVFWRDNswg?pwd=co3g
提取码:co3g
说明:
该yaml来自于https://github.com/kubernetes/dashboard中的该位置:
进入Access Control链接之后,找到下列位置即可,复制到dashboard-admin.yaml
文件中即可
# 删除原有用户,避免启动报错
kubectl delete -f dashboard-admin.yaml
# 添加新用户
kubectl apply -f dashboard-admin.yaml
使用kubectl get all -A
命令即可,找到:
直接在浏览器上根据你的虚拟机ip和上述端口访问即可(注意:协议是https
),如下:
我们需要获取token,指令如下:
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')
复制红框框中的内容输入到文本框中,然后点击登录按钮即可,如下:
然后k8s-dashboard首页如下:
先执行:
kubectl completion bash | sudo tee /etc/bash_completion.d/kubectl > /dev/null
在执行:
source /usr/share/bash-completion/bash_completion
我们在执行kubectl
命令的时候可以用tab
键进行自动补全
说明: 大家可以通过https://kubernetes.io/zh-cn/docs/tasks/tools/included/optional-kubectl-configs-bash-linux/了解更多信息
// 安装nfs-utils工具包 yum install -y nfs-utils // 安装rpcbind,用于rpc通信 yum install -y rpcbind // 创建nfs文件夹 mkdir -p /nfs/data // 确定访问ip,其中*代表所有ip,当然也可以设置cidr,比如我的master节点ip是192.168.139.128,那么下面的*就可以换成192.168.0.0/16,这样可以限制访问nfs目录的ip echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports // 开机启动nfs相关服务 systemctl enable rpcbind systemctl enable nfs-server systemctl start rpcbind systemctl start nfs-server // 检查配置是否生效 exportfs -r exportfs
// 安装nfs-utils工具包 yum install -y nfs-utils // 检查 nfs 服务器端是否有设置共享目录,如果输出结果如下就是正常的:Export list for 192.168.139.128: /nfs/data * showmount -e master节点所在服务器ip // 创建nd共享master节点的/nfs/data目录 mkdir /nd // 将node节点nfs目录和master节点nfs目录同步(说明:假设node节点的nfs目录是/nd,而master节点的nfs目录是/nfs/data) mount -t nfs master节点所在服务器ip:/nfs/data /nd // 测试nfs目录共享效果 比如在node节点的/nd中执行echo "111" > a.txt,然后就可以去master节点的/nfs/data目录中看下是否存在a.txt文件 // 开启自动挂载nfs目录(注意:先启动master节点虚拟机,然后在启动node节点虚拟机,如果node节点虚拟机先启动,除非重新启动,不然只能通过mount -t nfs master节点所在服务器ip:/nfs/data /nd指令进行手动挂载) 执行 vim /etc/fstab 命令打开fstab文件,然后将 master节点所在服务器ip:/nfs/data /nd nfs defaults 0 0 添加到文件中,最终结果如下图,其中ip、nfs共享目录、 当前节点的nfs目录都是我自己的,大家可以看着配置成自己的即可
开发人员只用说明自己的需求,也就是pvc,在pvc里面指定对应的存储类,我们的需求到时候自然会被满足
运维人员会把供应商(比如nfs)创建好,另外会设置好存储类的类型,开发人员只用根据要求去选择合适的存储类即可
具体过程如下:
下面两个链接看下就行,主要从说明看起
操作文件所在路径:https://github.com/kubernetes-retired/external-storage/tree/master/nfs-client
目前使用deploy
安装方式,具体路径是:https://github.com/kubernetes-retired/external-storage/tree/master/nfs-client/deploy
说明: 上面三个yaml
可以整合到一个yaml
之中,然后用---
进行分隔,然后一次性执行即可,我这里提供一下合并之后的yaml,大家按照下面的说明自己改下,然后执行即可
链接:https://pan.baidu.com/s/1mtMjSDNqipi-oBTPDNjbNg?pwd=tgcj
提取码:tgcj
注意: 如果里面的镜像失效了,大家可以通过以下方式下载,然后通过kubectl load -i XXX.tar
方式导入即可
链接:https://pan.baidu.com/s/1FZy7bRUlFcGko4_OzLbAqA?pwd=041z
提取码:041z
地址:https://github.com/kubernetes-retired/external-storage/blob/master/nfs-client/deploy/class.yaml
我使用的内容可能和上面不一样,建议大家使用我下面的yaml,可以直接使用kubectl apply -f 下面的yaml文件
执行即可
## 创建了一个存储类
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage # 存储类名称
annotations:
storageclass.kubernetes.io/is-default-class: "true" # 是否是默认分类,也就是pvc不选择存储分类的时候就用这个,一般只用设置一个默认的即可
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
#provisioner指定一个供应商的名字。
#必须匹配 k8s-deployment 的 env PROVISIONER_NAME的值
parameters:
archiveOnDelete: "true" ## 删除pv的时候,pv的内容是否要备份,这个也是可选参数
#### 这里可以调整供应商能力。
我使用的内容可能和上面不一样,建议大家使用我下面的yaml,不能直接复制粘贴使用
,注意把yaml里面XXX代表的nfs主机ip和nfs共享目录修改成自己的,修改完成之后可以直接使用kubectl apply -f 下面的yaml文件
执行即可
另外里面使用的镜像是尚硅谷雷丰阳老师的阿里云仓库镜像,如果哪一天他的镜像不在了,大家可以使用docker load -i 镜像tar包名称
导入下面的镜像即可
链接:https://pan.baidu.com/s/1VT9pbmCIsh4tHdcLx5ryvA?pwd=o17g
提取码:o17g
apiVersion: apps/v1 kind: Deployment metadata: name: nfs-client-provisioner labels: app: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: default spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: nfs-client-provisioner template: metadata: labels: app: nfs-client-provisioner spec: serviceAccountName: nfs-client-provisioner containers: - name: nfs-client-provisioner image: registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/nfs-subdir-external-provisioner:v4.0.2 # 使用尚硅谷雷丰阳的镜像 # resources: # limits: # cpu: 10m # requests: # cpu: 10m volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: k8s-sigs.io/nfs-subdir-external-provisioner - name: NFS_SERVER value: XXX ## 指定自己nfs服务器地址,也就是装nfs服务器的主机ip,比如我的就是192.168.139.128 - name: NFS_PATH value: XXX ## 指定自己nfs服务器共享的目录,比如我的就是/nfs/data volumes: - name: nfs-client-root nfs: server: XXX ## 指定自己nfs服务器地址,也就是装nfs服务器的主机ip,比如我的就是192.168.139.128 path: XXX ## 指定自己nfs服务器共享的目录,比如我的就是/nfs/data
地址:https://github.com/kubernetes-retired/external-storage/blob/master/nfs-client/deploy/rbac.yaml
我使用的内容可能和上面不一样,建议大家使用我下面的yaml,直接使用kubectl apply -f 下面的yaml文件
执行即可
apiVersion: v1 kind: ServiceAccount metadata: name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: default --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nfs-client-provisioner-runner rules: - apiGroups: [""] resources: ["nodes"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["persistentvolumes"] verbs: ["get", "list", "watch", "create", "delete"] - apiGroups: [""] resources: ["persistentvolumeclaims"] verbs: ["get", "list", "watch", "update"] - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["events"] verbs: ["create", "update", "patch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: run-nfs-client-provisioner subjects: - kind: ServiceAccount name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: default roleRef: kind: ClusterRole name: nfs-client-provisioner-runner apiGroup: rbac.authorization.k8s.io --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: default rules: - apiGroups: [""] resources: ["endpoints"] verbs: ["get", "list", "watch", "create", "update", "patch"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: default subjects: - kind: ServiceAccount name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: default roleRef: kind: Role name: leader-locking-nfs-client-provisioner apiGroup: rbac.authorization.k8s.io
将下面yaml文件通过kubectl apply -f yaml文件
命令执行,然后通过kubectl get pvc
、kubectl get pv
看到对应的pvc和pv信息,并且能在nfs共享目录下面看到对应的文件夹,那就说明没有问题
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-pvc-2
namespace: default
labels:
app: nginx-pvc-2
spec:
storageClassName: managed-nfs-storage ## 存储类的名字,按照你自己的填写,如果设置了默认存储类,可以把不设置该值
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100m
链接:https://pan.baidu.com/s/1qF4zrQm8FYUqMZxMYU0aAg?pwd=ju13
提取码:ju13
tar -zxvf helm-v3.5.4-linux-amd64.tar.gz
mv linux-amd64/helm /usr/local/bin/helm
helm
helm repo add bitnami https://charts.bitnami.com/bitnami
仓库说明:默认仓库是hub,常用的第三方仓库是bitnami
,这些仓库都隶属于https://artifacthub.io/平台
不需要总结
kubectl create deploy XXX
方式启动的pod,即使这个pod挂了,k8s也会自动重新拉起一个pod,当然在yaml中通过Deployment方式部署的pod也拥有自愈功能kubectl run XXX
方式启动的pod,如果pod挂了,无法重新拉取一个podPod (容器组) 是一个k8s中一个抽象的概念,用于存放一组 container(可包含一个或多个 container 容器,即图上正方体),以及这些 container (容器)的一些共享资源。这些资源包括:
Pod(容器组)是 k8s 集群上的最基本的单元。当我们在 k8s 上创建 Deployment 时,会在集群上创建包含容器的 Pod (而不是直接创建容器)。每个Pod都与运行它的 worker 节点(Node)绑定,并保持在那里直到终止或被删除。如果节点(Node)发生故障,则会在群集中的其他可用节点(Node)上运行相同的 Pod(从同样的镜像创建 Container,使用同样的配置,IP 地址不同,Pod 名字不同)。
TIP
重要:
- Pod 是一组容器(可包含一个或多个应用程序容器),以及共享存储(卷 Volumes)、IP 地址和有关如何运行容器的信息。
- 如果多个容器紧密耦合并且需要共享磁盘等资源,则他们应该被部署在同一个Pod(容器组)中。
default
名称空间中的所有poddefault
名称空间中的所有pod的详细信息,包括部署的节点名称等default
名称空间中的所有deploydefault
名称空间中的所有deploy的详细信息,包括容器信息、镜像信息、可选标签等default
名称空间中的所有资源default
名称空间中的所有资源的详细信息default
名称空间中的上述资源的信息,例如:kubectl get pod,deploy
/bin/bash
也不是固定不变的,有的是/bin/sh
,所以注意点kubectl exec -it multi-container-pod -c alpine-container -- /bin/sh
;其中/bin/bash
也不是固定不变的,有的是/bin/sh
,所以注意点kubectl delete pod my-ali
用于删除pod,当然也可以写成kubectl delete pod/my-ali
;如果需要删除多个,中间用空格隔开即可,例如:kubectl delete pod/my-ali1 pod/my-ali2
kubectl delete pod/gitlab-55b5687489-j5mqv --force --grace-period=0 -n gitlab
kubectl get pod my-ali -oyaml
、kubectl delete pod/my-ali
这些写法都可以,其中资源名称可以用全名,也可以用缩写yaml
文件的时候,我们经常会遇到不太懂某个属性值的写法,那我们就可以这样来解释一下属性值的具体写法,比如kubectl explain pod.metadata.labels
就是解释下labels
属性的写法-w
的用法,其实作用就是-w
会将变化往下追加,所以建议还是使用watch -n 秒数 命令
来监控kubectl get pod -l version=v1
用来查找标签中version
是v1
的pod
资源yaml
文件内容,例如:kubectl run my-nginx --image=nginx --dry-run=client -oyaml
yaml
文件,例如:kubectl get pod my-nginx-pod-test -oyaml
yaml
文件,例如:kubectl edit pod my-nginx-pod-test
,编写完成之后输入:wq
就可以保存了我们先来创建一个部署,脚本如下:
// 第一个nginx是部署名称,第二个nginx是镜像名称
kubectl create deploy nginx --image=nginx
然后查看一些部署情况,如下:
kubectl get deploy
现在部署中只有一个pod
,然后我们将部署中的pod
进行扩容,脚本是:
// 副本数是5,副本数变大就是扩容,反之就是缩容,deploy是deployments的缩写,可以通过kubectl api-resources命令查看,然后nginx是上面的部署名称
kubectl scale --replicas=5 deploy/nginx
接着上一次的扩容例子继续讲解,上次创建的部署名称是nginx
,扩容之后存在多个pod,本次我们将这次部署暴露出去,然后统一负载均衡的访问多个pod,脚本如下:
// nginx是部署名称,81是service的端口名称,80代表pod的端口名称(pod中是nginx,所以访问端口是80),这样我们访问service的81端口就相当于访问pod的80端口,ClusterIP代表一种方式,这种方式只能在虚拟机内部访问,无法在浏览器上访问
kubectl expose deploy nginx --port=81 --target-port=80 --type=ClusterIP
我们可以通过kubectl get all
查看ClusterIP的情况,如下:
我们可以通过curl ip:port
来访问service中的pod,比如本次就是curl 10.100.152.152:81
我们可以通过kubectl exec -it pod名称 -- /bin/bash
命令进入容器内部,之后把/usr/share/nginx/html
中的index.html
删除,之后把一些特定数字(比如:111、222)写入index.html中,然后我们多次访问service就能看到负载均衡的效果,如下:
上面提到,ClusterIP类型的service服务无法在浏览器上访问,而NodePort类型的service服务可以在浏览器上访问,所以我们把上述暴露服务命令更改为如下内容:
kubectl expose deploy nginx --port=81 --target-port=80 --type=NodePort
注意: 已经暴露为ClusterIP形式的service需要先删除,然后在使用上面的命令重新暴露即可,然后通过kubectl get all
查看NodePort方式的service访问方式,其中81也会把端口暴露到外面,例如:
然后我们在浏览器上访问即可,其中ip是虚拟机ip,而端口是上图中的31957
,截图如下:
如果用图形表示,类似于:
我们想要给node添加一些角色,但是需要对node打标签,所以我们先看下节点标签的样子,首先输入kubectl get node
,可以看到ROLES
下面的值对应绿框框中的内容,所以只有标签键,根本没有标签值,如下所示:
那我们给k8s-02
节点添加worker
角色,其实是一个打标签的过程,命令如下:
// node是资源类型,k8s-02是资源名称,node-role.kubernets.io/worker是标签键,=代表添加
kubectl label node k8s-02 node-role.kubernetes.io/worker=
如果我们想删除k8s-02
节点中的worker
角色,命令如下:
// node是资源类型,k8s-02是资源名称,node-role.kubernets.io/worker是标签键,-代表减去
kubectl label node k8s-02 node-role.kubernetes.io/worker-
在上面给node
打标签的时候已经大致说过了,脚本如下:
// pod是资源类型,nginx-6799fc88d8-kwx5z是资源名称,name是标签键,而gm是标签值
kubectl label pod nginx-6799fc88d8-kwx5z name=gm
如果我们想把值gm
切换成gm1
,脚本如下:
kubectl label pod nginx-6799fc88d8-kwx5z name=gm1 --overwrite
如果我们想把这个pod删除了,那么脚本如下:
// pod是资源类型,nginx-6799fc88d8-kwx5z是资源名称,name是标签键,而-就代表删除指令
kubectl label pod nginx-6799fc88d8-kwx5z name-
滚动升级也就是让用户无感知的情况下,也就是不影响用户使用的情况下达到应用升级的目的,依然用上面的情况举例子,我们暴露了一个service服务,该服务对应一个deploy部署,而该部署中存在多个pod,假设此时我们升级image镜像版本,那就用到了k8s的滚动升级策略
依然用上面暴露的nginx服务为例,我们来说明滚动升级的具体流程和现象
镜像滚动升级命令如下:
// deploy是资源类型,第一个nginx是deployment部署名称,第二个nginx代表nginx:latest,也就是原有镜像信息,而nginx:1.9.1代表最新的nginx镜像信息,最后的--record=true代表记录本次变动的命令
// 作用:将nginx部署中的nginx镜像版本从latest更改为1.9.1
kubectl set image deploy nginx nginx=nginx:1.9.1 --record=true
如果我们同步使用kubectl get pod
命令监控pod变化,可以发现k8s会先启动一个pod,当这个pod真正运行之后,在杀掉原来的pod,从而达到不停机维护的目的
如果大家不知道部署中的镜像使用的是什么版本,我们可以对pod执行如下脚本:
// nginx-6799fc88d8-7525w是nginx的pod名称,-o yaml代表获取pod对应的yaml文件,然后通过grep image命令查看pod中所用的镜像信息
kubectl get pod nginx-6799fc88d8-7525w -o yaml | grep image
首先我们先来查看一下有哪些可以恢复的历史版本,命令如下:
// deploy是资源类型,nginx是deploy部署名称
kubectl rollout history deploy nginx
结果如下:
此时我们想回到revision=1的情况,脚本如下:
// deploy是资源类型,nginx是deploy部署名称,--to-revision=1代表回到版本为1的状态
kubectl rollout undo deploy nginx --to-revision=1
使用命令来对文件进行操作实在太麻烦了,另外运维在部署的时候也不好使用,所以最好使用文件来描述一下操作
我们来举一个例子,把下面内容复制到一个yaml文件中,比如nginx.yaml,内容如下:
apiVersion: apps/v1 #与k8s集群版本有关,使用 kubectl api-versions 即可查看当前集群支持的版本 kind: Deployment #该配置的类型,我们使用的是 Deployment metadata: #译名为元数据,即 Deployment 的一些基本属性和信息 name: nginx-deployment #Deployment 的名称 labels: #标签,可以灵活定位一个或多个资源,其中key和value均可自定义,可以定义多组,目前不需要理解 app: nginx #为该Deployment设置key为app,value为nginx的标签 spec: #这是关于该Deployment的描述,可以理解为你期待该Deployment在k8s中如何使用 replicas: 1 #使用该Deployment创建一个应用程序实例 selector: #标签选择器,与上面的标签共同作用,目前不需要理解 matchLabels: #选择包含标签app:nginx的资源 app: nginx template: #这是选择或创建的Pod的模板 metadata: #Pod的元数据 labels: #Pod的标签,上面的selector即选择包含标签app:nginx的Pod app: nginx spec: #期望Pod实现的功能(即在pod中部署) containers: #生成container,与docker中的container是同一种 - name: nginx #container的名称 image: nginx:1.7.9 #使用镜像nginx:1.7.9创建container,该container默认80端口可访问
假设文件名称是nginx.yaml
,我们执行如下脚本来创建一次部署,如下:
kubectl apply -f nginx.yaml
此时就会为我们创建一次部署
如果我们想修改nginx.yaml
文件中的内容,比如副本数量、镜像版本等,那我们可以直接修改该配置文件即可,例如我们把镜像改成最新的镜像,那么nginx:1.7.9
就变成了nginx
,修改完成之后,依然执行kubectl apply -f nginx.yaml
即可完成更新操作
如果我们想删除之前的部署,我们只用对yaml文件进行删除操作,那么相关部署、pod都会被删除,对应脚本如下:
kubectl delete -f nginx.yaml
上面已经总结了,这里不再总结
k8s中的每一种资源都有期望状态(也叫做目标状态)和当前状态,当前状态可能不等于期望状态,但是它会不断的超期望状态去靠近,直到达到期望状态
对于k8s中的任意一种资源都存在期望状态和目标状态,我们以上面进行的部署为例说明,先通过kubectl get all
查看部署情况,然后找到我们之前的部署信息,然后执行如下脚本,用来查看部署对应的yaml文件:
kubectl get deployment.apps/nginx-deployment -oyaml
yaml
文件具体内容如下:
apiVersion: apps/v1 kind: Deployment metadata: annotations: deployment.kubernetes.io/revision: "1" kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"labels":{"app":"nginx"},"name":"nginx-deployment","namespace":"default"},"spec":{"replicas":3,"selector":{"matchLabels":{"app":"nginx"}},"template":{"metadata":{"labels":{"app":"nginx"}},"spec":{"containers":[{"image":"nginx","name":"nginx"}]}}}} creationTimestamp: "2023-02-01T11:58:50Z" generation: 1 labels: app: nginx name: nginx-deployment namespace: default resourceVersion: "126322" uid: d7014776-7200-4451-a585-bf18334f1264 spec: progressDeadlineSeconds: 600 replicas: 3 revisionHistoryLimit: 10 selector: matchLabels: app: nginx strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: creationTimestamp: null labels: app: nginx spec: containers: - image: nginx imagePullPolicy: Always name: nginx resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 status: availableReplicas: 3 conditions: - lastTransitionTime: "2023-02-01T11:59:00Z" lastUpdateTime: "2023-02-01T11:59:00Z" message: Deployment has minimum availability. reason: MinimumReplicasAvailable status: "True" type: Available - lastTransitionTime: "2023-02-01T11:58:50Z" lastUpdateTime: "2023-02-01T11:59:00Z" message: ReplicaSet "nginx-deployment-6799fc88d8" has successfully progressed. reason: NewReplicaSetAvailable status: "True" type: Progressing observedGeneration: 1 readyReplicas: 3 replicas: 3 updatedReplicas: 3
可以看到里面有一个spec:
,它下面指示的是期望状态,而status:
下面指示的是当前状态,其中当前状态是一直在变化的,如果我们杀死pod,那我们在执行上述命令查看yaml文件,那就可以看到status:
内容发生变化了
status:
信息是自动生成的,而我们在编写yaml
文件的时候只需要指定spec:
内容就可以了
比如我想编写一个deploy
部署的yaml
,那就可以找到一个deploy
,然后查看对应的yaml
,命令如下:
kubectl get deployment.apps/nginx-deployment -oyaml
获取该yaml
之后模仿着写就是了
直接上命令,如下:
kubectl run my-nginx --image=nginx --dry-run=client -oyaml
我们运行一个nginx
的pod
,使用--dry-run=client
来表示干跑一遍,但是不会真正部署pod
,然后我们在获取到它的yaml
文件
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: my-nginx
name: my-nginx
spec:
containers:
- image: nginx
name: my-nginx
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
比如生成一个最简单的nginx
的pod
,该yaml
文件的名称是nginx.yaml
# typeMeta开始…… apiVersion: v1 # 对应 kubectl api-resources 命令中返回的APIVERSION kind: Pod # 对应 kubectl api-resources 命令中返回的KIND # typeMeta结束…… # ObjectMeta开始…… metadata: name: my-nginx-pod # 资源名称 namespace: default # ObjectMeta结束…… # 期望状态开始…… spec: containers: # 指定启动的容器信息 - image: nginx # 指定镜像 name: my-nginx-container # 容器名称 # 期望状态结束……
那么执行的脚本是:
kubectl apply -f my-nginx.yaml
还以98.1.3、自己手动编写yaml文件
为例,我们通过kubectl apply -f my-nginx.yaml
生成了一个pod,然后我们把nginx.yaml
中的镜像版本从latest
改成了1.9.1
,此时我们执行如下脚本来对比现在正在运行的pod和yaml文件中的pod之间的不同之处,如下:
kubectl diff -f my-nginx.yaml
执行结果如下图:
如果我们在执行kubectl apply -f my-nginx.yaml
,将会执行更新操作,然后让当前状态status达到现在的期望状态spec
还以上面的nginx.yaml
为例,删除的时候只需要执行如下脚本即可:
kubectl delete -f my-nginx.yaml
不同名称空间下的资源不同共享,但是网络可以互通
我们公司的k8s集群使用了基于环境隔离
和基于团队隔离
的方式
创建: kubectl create ns dev
,说明:创建dev名称空间
查看: kubectl get ns
,说明:查看所有名称空间
删除: kubectl delete ns dev
,说明:删除dev名称空间
首先把名称空间的yaml
文件放在yaml
文件中,如下:
apiVersion: v1
kind: Namespace
metadata:
name: dev
创建: kubectl apply -f ns.yaml
,说明:创建dev名称空间
查看: kubectl get ns
,说明:查看所有名称空间
删除: kubectl delete -f ns.yaml
,说明:删除dev名称空间
前提准备:
先编写之前,我们需要知道该类型的yaml文件大致怎么写的,那可以通过命令获取yaml的方式或者查看现有同类资源yaml的方式,上面已经说过了这两种方式,这里在说明一下
通过命令获取yaml:kubectl run my-nginx --image=nginx --dry-run=client -oyaml
,这是生成镜像为nginx的pod的yaml文件
查看现有同类资源yaml:kubectl get deployment.apps/nginx-deployment -oyaml
,这是获取pod中镜像为nginx的yaml文件
中途准备:
在编写yaml
文件的时候,我们会遇到某个属性的键或者值不会写了,这样我们就可以借助于kubectl explain命令来解释一下属性,我们下面的脚本就是解释pod的yaml文件中metadata下面labels的写法,这种写法是链式写法
kubectl explain pod.metadata.labels
对于上面脚本中用法的解释,下图是一个pod
的yaml
的截图,metadata
是其中一个属性,而labels
是metadata
中的一个子属性,如下图:
最终执行:
一般使用kubectl apply
就可以了,不仅可以用来新增,还可以用来更新已有的资源,而kubectl create
只可用用来新增,但是不能用了更新,因此建议使用kubectl apply
kubectl apply -f XXX.yaml
错误修复:
如果我们yaml
文件写的存在问题,那我们在执行kubectl apply
的时候就会出现错误提示,基本会明显的告诉我们yaml
文件哪里写错了
在yaml
文件中输入k8s
就可以看到很多可以选项,如下图:
我们在选中一些单词的的时候,点击Ctrl+D
,然后就可以依次选择一样的单词
我们依然来举一个例子,输入kubectl explain pod.spec.containers.resources
回车可以看到如下内容:
如果我们想了解更多resource
的信息,可以访问上图红色框中的链接,但是这是英文文档的链接,我们可以把链接中的https://kubernetes.io/
替换成https://kubernetes.io/zh-cn/
,那样就可以查看中文文档了,例如:https://kubernetes.io/zh-cn/docs/concepts/configuration/manage-resources-containers/
/etc/kubernetes
、/etc/kubernetes/manifests
,以pod方式安装核心组件/etc/sysconfig/kubelet
/var/lib/kubelet/config.yaml
上面已经说过了,这里不再赘述
首先先看一下镜像拉取策略在yaml中文件中的使用位置,如下:
我们再来看一下有哪几种镜像拉取策略,如下:
说明: 镜像拉取策略还是很有用的,我们公司有一个k8s演示集群,它部署在单独的服务器上,而harbor镜像仓库在其他服务器上,在我们公司内部,k8s集群和harbor仓库网络是通的,所以能拉取镜像,但是在演示项目的时候需要把服务器拉到客户单位,那就需要改变yaml文件中的镜像拉取策略,那就不能使用默认的Always了,否则镜像拉取就会报错
创建镜像拉取密钥的具体语法:
kubectl create secret -n 命名空间 docker-registry 密钥名称(用在yaml文件中) \
--docker-server=镜像仓库地址 \
--docker-username=用户名 \
--docker-password=密码
注意:-n 命令空间
是可选的,默认是default命名空间
我们使用上面的语法举一个例子,如下:
// 默认使用default命名空间,也可以使用-n指定名称空间
// my-aliyun是镜像密钥名称,可以在yaml文件中使用
// registry.cn-hangzhou.aliyuncs.com是镜像服务器地址
kubectl create secret docker-registry my-aliyun \
--docker-server=registry.cn-hangzhou.aliyuncs.com \
--docker-username=阿里云镜像仓库用户名 \
--docker-password=阿里云镜像仓库密码
如果大家想得到对应的yaml
文件,可以在上述命令之后添加--dry-run=client -oyaml
获得yaml
文件
直接上yaml文件,我的目的是从阿里云私有镜像仓库中拉取一个镜像,然后部署成pod
,大家主要看imagePullSecrets
下面name
属性的写法,我写的是my-aliyun
,我把下面的yaml文件用kubectl apply -f java-devops-demo.yaml
执行了,然后用kubectl describe pod my-java-devops-demo
命令查看了具体信息,发现镜像拉取都是正常的,截图如下:
yaml文件如下:
apiVersion: v1
kind: Pod
metadata:
name: "my-java-devops-demo"
namespace: default
labels:
app: "my-java-devops-demo"
spec:
imagePullSecrets:
- name: my-aliyun
containers:
- name: my-java-devops-demo
image: "registry.cn-hangzhou.aliyuncs.com/mingkuaidexuanmi61/java-devops-demo:v2.0"
总结: 是否使用镜像拉取密钥
是根据待拉取镜像的镜像仓库地址来的,能对上就用,对不上就去中央仓库拉取
直接上yaml
文件,在下面的yaml
文件中可以看到containers
下面有两个镜像,但是spec
下面的imagePullSecrets
只配置了一个,那两个镜像的拉取方式是不一样的,首先第一个镜像的镜像仓库地址是registry.cn-hangzhou.aliyuncs.com
,而imagePullSecrets
下的my-aliyun
中配置的也是阿里云镜像仓库的地址,所以拉取第一个镜像的时候肯定会用到这个镜像拉取密钥的;而第二个镜像仓库没有写明地址,那就是中央仓库地址,所以肯定不会用到上面阿里云镜像仓库的密钥的,毕竟地址对不上嘛
apiVersion: v1
kind: Pod
metadata:
name: "my-java-devops-demo-test"
namespace: default
labels:
app: "my-java-devops-demo-test"
spec:
imagePullSecrets:
- name: my-aliyun
containers:
- name: my-java-devops-demo-test
image: "registry.cn-hangzhou.aliyuncs.com/mingkuaidexuanmi61/java-devops-demo:v2.0"
- name: my-nginx-test
image: nginx:latest
直接上yaml
,该yaml
文件的作用是创建一个包含mysql
容器的pod
,我们首先应该关注env
的写法,其中name
后面就是环境变量名称,而value
后面就是环境变量真实值,比如下面的123456
是密码,但是密码是字符串而不是数字,所以值需要用字符串包裹起来
其次我们来聊一下env
的值从哪里获取,它肯定不是凭空来的,一般来自于dockerhub
,比如本次mysql
容器的值就来自于https://hub.docker.com/_/mysql
如果大家想了解env环境变量的详细信息,可以访问 为容器设置环境变量 页面
apiVersion: v1 kind: Pod metadata: name: "my-mysql" namespace: default labels: app: "my-mysql" spec: containers: - name: my-mysql image: mysql:5.7 env: - name: MYSQL_ROOT_PASSWORD value: "123456" - name: MYSQL_DATABASE value: "atguigu"
上面已经说明了env
环境变量怎么定义,下面我们说下环境变量怎么用,一般都是使用$(环境变量名称)
这种形式来使用环境变量,示例如下图:
直接上yaml
,我们在env
中定义了环境变量msg
,然后在command中通过$(msg)
使用了环境变量的值,在执行yaml
之后可以通过kubectl logs my-command-test
可以查看日志信息
apiVersion: v1 kind: Pod metadata: name: "my-command-test" namespace: default labels: app: "my-command-test" spec: containers: - name: my-command-test image: nginx env: - name: msg value: "hello command" command: - /bin/sh - -c - "echo $(msg);sleep 3600"
我们来说一下command
的写法,我们可以写成数组的形式,比如:command: ["/bin/sh", "-c", "echo $(msg);sleep 3600"]
,或者写成上面的写法都是可以的
另外说下镜像中命令和yaml
文件中command
命令的使用优先级,我们直接看第3列,如果yaml
文件中写了command
命令,那么镜像中的命令就完全不起效了,所以有谨慎使用;另外第4列是yaml
文件中args
属性的用法,第5列是命令执行列
说明: 只要我们会写docker run
命令,那就能写出来yaml
文件中containers
中的内容
说明: 我们都知道pod
中是容器,容器是存在生命周期的,在容器创建成功之后以及删除之前都是可以通知我们的
直接上yaml
文件,postStart
中的配置代表在nginx
容器创建完成之后就会发送http请求到某位置,我发送的位置是本机另外一个nginx的pod,方便用来测试嘛,可以用kubectl apply -f my-life-test.yaml
测试;preStop
中的配置代表在nginx
容器删除之前就会发送http请求,我依然使用的是本机另外一个nginx的pod,可以用kubectl delete -f my-life-test.yaml
测试,测试结果在下面的截图中
yaml文件如下:
apiVersion: v1 kind: Pod metadata: name: "my-life-test" namespace: default labels: app: "my-life-test" spec: containers: - name: my-life-test image: nginx lifecycle: postStart: httpGet: host: "10.101.179.43" path: "/postStart" port: 80 scheme: HTTP preStop: httpGet: host: "10.101.179.43" path: "/preStop" port: 80 scheme: HTTP
上面介绍的是httpGet
方式,还有其他通知方式,截图如下:
下面就是这几种探针的详细解释和具体写法,如下:
以后写yaml
文件主要注意两点:
先来说下面yaml
文件的作用,首先一个pod
中的两个容器分别是nginx-container
和alpine-container
,大家可以看到两个容器的volumeMounts
中用的都是common-vol
,对于nginx
容器的/usr/share/nginx/html
目录,和alpine
容器的/app
目录都是一致的,如果我们去更改共享目录中的index.html
文件内容,那么访问nginx
得到的内容就会发生改变,所以以下yaml
的作用是通过alpine
容器往index.html
中写入日期,然后访问nginx
容器的时候就会看到这个变化的日期,这也体现了Pod
中多容器协同
apiVersion: v1 kind: Pod metadata: name: "multi-container-pod" namespace: default labels: app: "multi-container-pod" spec: containers: - name: nginx-container image: "nginx" volumeMounts: - name: common-vol mountPath: /usr/share/nginx/html - name: alpine-container image: "alpine" command: ["/bin/sh", "-c", "while true; do sleep 1; date > /app/index.html; done;"] volumeMounts: - name: common-vol mountPath: /app volumes: - name: common-vol emptyDir: {} # docker匿名挂载
所有的初始化容器都必须有终结的时间点,可以短暂运行,但是不能一直运行,比如默认的nginx容器是绝对不能接受的,毕竟它是一直在运行的
所有的正式容器都需要能启动起来,并且长期运行,一旦无法启动或者停止运行,那么Pod
的状态将会是NotReady
状态,这样的话Pod
将无法为外界提供服务;如果Pod
中容器一旦启动失败或者停止运行,那么Pod
将会自动重启这些容器
主要讲述了一个临时容器用于Pod排错的事情,原因是pod的容器中多个命令其实都是不可使用的,甚至ping、curl……等命令都是无法使用的,那我们可以借助于临时容器共享工作容器中的所有资源(网络、存储…),然后在临时容器中操作就相当于在操作Pod中的工作容器一样;
但是目前临时容器还是试用版本,不能正式使用
暂时是实验版本,老师也没有演示具体使用,先不学了
在每一个节点中都存在/etc/kubernetes/manifests
位置,只要我们把Pod
的yaml
文件放在该目录下面,kubelet
就会自动拉起该pod
,如果我们手动把该pod
删除,然后kubelet
便会再次拉起该pod
,不需要用户手动干预,这就是静态pod
说明: kubelet会去检测这些探针
以下就是使用的yaml
文件,首先我们执行kubectl apply -f XXX.yaml
之后,然后通过kubectl get pod -owide
查看pod分配在哪个节点上,想要容器启动成功,那就需要去该节点上新建/app/abc
文件,并且想要存活探针、就绪探针都是成功的,那就需要新建/html/abc.html
文件
apiVersion: v1 kind: Pod metadata: labels: app: nginx-probe-test name: nginx-probe-test spec: containers: - name: nginx image: nginx # 启动探针 startupProbe: exec: command: ["/bin/sh", "-c", "cat /app/abc"] # 对于exec来说,只要执行不成功(命令执行之后可以通过echo $?返回值来确定成功与否,如果是0那就是成功,否则那就是失败),那就是启动探针没成功,失败之后很长时间不会在重启了 # 以下几个参数在存活探针和就绪探针中都有,不过我们只在此处详细解释 initialDelaySeconds: 5 # 在容器启动之后,并且存活探针初始化之前的延时秒数 periodSeconds: 5 # 每隔几秒运行一次,最小值是1 timeoutSeconds: # 探测超时秒数,最小值是1 successThreshold: 1 # 成功阈值,在失败之后,连续几次成功才算成功,默认值是10,最小值是1 failureThreshold: 5 # 失败阈值,连续几次成功才算成功,默认值是3,最小值是1 # 存活探针 livenessProbe: exec: command: ["/bin/sh", "-c", "cat /usr/share/nginx/html/abc.html"] # 就绪探针 readinessProbe: httpGet: # 访问本容器的话,不要写host,不然会导致接口无法调通 path: /abc.html port: 80 scheme: HTTP volumeMounts: - name: nginx-vol mountPath: /app - name: nginx-html mountPath: /usr/share/nginx/html volumes: - name: nginx-vol hostPath: path: /app - name: nginx-html hostPath: path: /html
老师没有录这一节
当我们执行kubectl apply -f XXX.yaml
命令之后,api-server就收到了部署请求,然后就把信息存储到etcd
里面,然后controller-manager
从etcd
中得到了部署请求信息,然后就调用Deployment控制器
进行监控,并且把处理过后的部署信息存储到etcd
中,然后api-server
就让某一节点的kubelet
去执行部署操作,当然Deployment控制器
的作用是保证部署最终能够达到期望目标,并且始终保证部署维持在期望目标
下面就是对应的nginx-deployment-test.yaml
文件,作用就是部署了一个deployment
,其中对应3个pod
,我们这样部署之后将会产生deployment
、replicaset
、pod
,其中deployment
控制replicaset
,而replicaset
控制pod
的数量,如下图:
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment-test namespace: default # deployment所属名称空间 labels: app: nginx-deployment-test # deployment的标签,在这里面没啥用 spec: selector: matchLabels: app: nginx-pod-test # 必须和下面pod的labels对应,我们deployment绑定pod就是根据该标签来的 replicas: 3 # pod副本数量,默认值是1,由副本集ReplicaSet控制器实现 template: # 下面就是编写pod内容的位置 metadata: labels: app: nginx-pod-test spec: containers: - name: nginx-pod-test image: nginx
其实在前面我们提到过滚动更新,只是当时使用的是纯命令行,但是现在使用的是yaml
文件,不过原理都是类似的,举一个场景吧,还以上面的yaml
文件为例,我们上面使用的是最新的nginx
版本,现在我们想更换nginx
版本,比如更换成nginx:1.9.1
,那么我们就可以把上述yaml
文件中的nginx
版本更改之后,在执行kubectl apply -f nginx-deployment-test.yaml
即可,此时我们在查看kubectl get all | grep nginx-deployment-test
,发现现在多了一个副本集记录,如下图:
如果我们同时观察pod的变更情况,可以看到pod是先启动新的,等新的pod完全启动之后,才会杀死老的pod,反之如果pod不能成功启动,那就无法删除老的pod,保证服务即使在更新失败的情况下依然可以提供良好的服务
现在我们来模拟由于镜像基本错误导致更新失败的情况,现在我们把镜像版本改成nginx:111
,那肯定不能正常更新的,我们来看下最新的pod和所有部署信息的情况,如下:
pod情况:
所有部署信息情况:
现在可以看到所有部署信息的截图中又多了一个副本集replicaset,并且数量是1 1 0,也就是kubectl当前希望新pod有1个,并且现在就有了1个,但是准备好的是0个,毕竟镜像版本是错误的,没法拉下来嘛
这是一种修改镜像的版本方式,当然也可以是通过kubectl edit deployment.apps/nginx-deployment-test
命令进入正在运行的deployment
对应的yaml
文件中,然后修改对应镜像版本,之后:wq
保存就可以进行更新了。另外每一个副本集都对应我们的一种状态,如果我们在将接镜像版本变更回到了之前副本集的版本,那就不会在新创建副本集了,而是会沿用之前的副本集
我们还可以通过通过这种形式来进行镜像的滚动升级,如下:
// deploy是资源类型,第一个nginx是deployment部署名称,第二个nginx代表nginx:latest,也就是原有镜像信息,而nginx:1.9.1代表最新的nginx镜像信息,最后的--record=true代表记录本次变动的命令
// 作用:将nginx部署中的nginx镜像版本从latest更改为1.9.1
kubectl set image deploy nginx nginx=nginx:1.9.1 --record=true
在镜像滚动升级出现了问题或者镜像滚动升级的办法不对的时候如何进行回滚呢,这个不要慌,我们现在来说几种办法
yaml
文件之后,执行kubecl apply -f XXX.yaml
,例如:kubectl apply -f nginx-deployment-test.yaml
yaml
,执行kubectl edit 资源类型 资源名称
,然后:wq
保存退出即可,例如:kubectl edit deployment.apps/nginx-deployment-test
kubectl set image 资源类型 资源名称 原镜像信息=新镜像信息 --record=true
直接更改镜像版本,例如:kubectl set image deploy nginx nginx=nginx:1.9.1 --record=true
kubectl rollout history 资源类型 资源名称
查看资源历史版本,例如:kubectl rollout history deployment.apps/nginx-deployment-test
,然后在通过kubectl rollout undo 资源类型 资源名称 --to-revision=版本号
命令回滚到以往版本,例如:kubectl rollout undo deploy nginx-deployment-test --to-revision=1
默认情况下可以保留15
个历史资源版本,不过可以通过revisionHistoryLimit
参数去设置,如下:
我们公司中设置最多10个历史版本
这个时间默认是600s,如果600s之后还没有部署成功,那就是出现问题了,kubelet也会报告问题,这个值不建议设置的太小
也就是下面的paused
属性,默认值是false
,如果我们这样设置,然后在启动之后只会创建一个deployment
部署,并且状态是0/3
,不会产生ReplicaSet
副本集,更不会产生Pod
,如果需要产生ReplicaSet
副本集和Pod
,那就需要恢复启动状态了,脚本是kubectl rollout resume 资源类型 资源名称
,例如:kubectl rollout resume deployment.apps/nginx-deployment-test
如果大家想要现在正在运行的deployment
部署暂停,脚本是kubectl rollout pause 资源类型 资源名称
,例如:kubectl rollout pause deployment.apps/nginx-deployment-test
,但是我没有看出来有啥变化
就是下面的minReadySeconds
,默认值是0
,也就是pod
一准备就绪即视为可用,而添加该参数之后,就代表该pod
准备就绪之后经过该秒数之后才被认为是准备就绪,只有准备就绪的pod
后期才会把流量分到它上面
默认存在两种更新策略,分别是Recreate
和RollingUpdate
,默认使用RollingUpdate
可以达到滚动更新的效果,现在一个一个来聊
Recreate举例:
说明:这种策略会将老的pod全部一次性杀死,然后在把所有新pod启起来
RollingUpdate举例:
说明:滚动更新是默认策略,一般情况下我们不需要去调整该比例
镜像导入:
直接使用docker load -i 镜像tar包名称
即可导入,镜像在下面
链接:https://pan.baidu.com/s/1Ploa1i1VVcZUC-rpc4ZAew?pwd=wmla
提取码:wmla
metrics-server.yaml:
使用kubectl apply -f metrics-server.yaml
命令执行以下yaml即可
apiVersion: v1 kind: ServiceAccount metadata: labels: k8s-app: metrics-server name: metrics-server namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: k8s-app: metrics-server rbac.authorization.k8s.io/aggregate-to-admin: "true" rbac.authorization.k8s.io/aggregate-to-edit: "true" rbac.authorization.k8s.io/aggregate-to-view: "true" name: system:aggregated-metrics-reader rules: - apiGroups: - metrics.k8s.io resources: - pods - nodes verbs: - get - list - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: k8s-app: metrics-server name: system:metrics-server rules: - apiGroups: - "" resources: - pods - nodes - nodes/stats - namespaces - configmaps verbs: - get - list - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: k8s-app: metrics-server name: metrics-server-auth-reader namespace: kube-system roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: extension-apiserver-authentication-reader subjects: - kind: ServiceAccount name: metrics-server namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: labels: k8s-app: metrics-server name: metrics-server:system:auth-delegator roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: system:auth-delegator subjects: - kind: ServiceAccount name: metrics-server namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: labels: k8s-app: metrics-server name: system:metrics-server roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: system:metrics-server subjects: - kind: ServiceAccount name: metrics-server namespace: kube-system --- apiVersion: v1 kind: Service metadata: labels: k8s-app: metrics-server name: metrics-server namespace: kube-system spec: ports: - name: https port: 443 protocol: TCP targetPort: https selector: k8s-app: metrics-server --- apiVersion: apps/v1 kind: Deployment metadata: labels: k8s-app: metrics-server name: metrics-server namespace: kube-system spec: selector: matchLabels: k8s-app: metrics-server strategy: rollingUpdate: maxUnavailable: 0 template: metadata: labels: k8s-app: metrics-server spec: containers: - args: - --cert-dir=/tmp - --kubelet-insecure-tls # 避免安全认证,少去很多麻烦,来自https://github.com/kubernetes-sigs/metrics-server#configuration - --secure-port=4443 - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname - --kubelet-use-node-status-port image: metrics-server:v0.4.3 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 3 httpGet: path: /livez port: https scheme: HTTPS periodSeconds: 10 name: metrics-server ports: - containerPort: 4443 name: https protocol: TCP readinessProbe: failureThreshold: 3 httpGet: path: /readyz port: https scheme: HTTPS periodSeconds: 10 securityContext: readOnlyRootFilesystem: true runAsNonRoot: true runAsUser: 1000 volumeMounts: - mountPath: /tmp name: tmp-dir nodeSelector: kubernetes.io/os: linux priorityClassName: system-cluster-critical serviceAccountName: metrics-server volumes: - emptyDir: {} name: tmp-dir --- apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: labels: k8s-app: metrics-server name: v1beta1.metrics.k8s.io spec: group: metrics.k8s.io groupPriorityMinimum: 100 insecureSkipTLSVerify: true service: name: metrics-server namespace: kube-system version: v1beta1 versionPriority: 100
我们上面大多数讲的都是滚动更新,但是没有提到动态更新的事情,其实动态更新就是在Pod不够用(CPU占用过高)的时候就去新启动一些Pod,如果Pod够用了,那就在把多余的Pod删除掉,这都是自动完成的过程,这叫做自动动态扩缩容
https://kubernetes.io/zh-cn/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough
安装 Metrics Server
,我们在上面已经完成了
来源:
yaml:
执行的命令是kubectl apply -f php-apache.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: php-apache spec: selector: matchLabels: run: php-apache replicas: 1 template: metadata: labels: run: php-apache spec: containers: - name: php-apache image: registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/php-hpa:latest ports: - containerPort: 80 resources: limits: cpu: 500m requests: cpu: 200m --- apiVersion: v1 kind: Service metadata: name: php-apache labels: run: php-apache spec: ports: - port: 80 selector: run: php-apache
来源:
yaml:
执行的命令是kubectl apply -f hpa.yaml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: php-apache # 自动扩缩容资源自己的标签名,暂时没啥用
spec:
maxReplicas: 10 # 扩容最大副本数
minReplicas: 1 # 缩容最小副本数
scaleTargetRef:
apiVersion: apps/v1 # 资源版本
kind: Deployment # 资源类型
name: php-apache # 资源名称
targetCPUUtilizationPercentage: 50 # Pod的CPU占用率超过这个比率就去扩容Pod
来源:
观察命令:
watch -n 1 kubectl get hpa:查看占用CPU总比率
watch -n 1 kubectl get pod:查看pod扩容情况
测试命令:
kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"
命令执行之后稍微等待一段时间,就可以通过watch -n 1 kubectl get hpa
命令看到CPU占用率明显升高,然后通过watch -n 1 kubectl get pod
命令看到pod
的数量变化
如果我们此时在上述测试命令后面使用Ctrl+C
按钮截止了,那CPU占用肯定减少了,不过pod
的数量减少效果需要等好一会才能看出来
前提:
直接使用docker load -i 镜像tar包名称
即可导入,镜像在下面
链接:https://pan.baidu.com/s/1CBOrbuTBBJSa15xl7lMlsQ?pwd=kqgx
提取码:kqgx
说明:
只需要把下面3个yaml
文件都使用kubectl apply -f XXX.yaml
命令执行,然后直接在浏览器上访问http://虚拟机ip:31666/
就能看到不同的效果,因为老版本输出111111111
,而新版本输出nginx默认页面,这样达到了service的流量可以分配到新老版本Pod的目的
yaml文件:
k8s-canary-service.yaml:
apiVersion: v1
kind: Service
metadata:
name: canary-service-test # 目前没啥用
namespace: default
spec:
selector:
app: canary-nginx-test # 新老版本都有这个标签,所以可以把service可以把流量分配给新老版本的pod
type: NodePort ### 可以直接在浏览器上访问
ports:
- name: canary-service-test
port: 80 ### service端口,对应tarPort
targetPort: 80 ### Pod的访问端口
protocol: TCP
nodePort: 31666 ### 浏览器访问的端口,对应port,所以在浏览器上访问的时候,可以通过nodePort(浏览器)》por(service)》targetPort(Pod)
k8s-canary-deploy1.yaml(老版本):
apiVersion: apps/v1 kind: Deployment metadata: name: canary-deployment-test-v1 namespace: default labels: app: canary-deployment-test-v1 # 目前没啥用 spec: selector: matchLabels: # 使用这两个标签可以控制下面的pod app: canary-nginx-test version: v1 replicas: 1 template: metadata: labels: app: canary-nginx-test # 和老版本相同 version: v1 # 和老版本不同 spec: containers: - name: nginx-test image: nginx-test:env-msg
k8s-canary-deploy2.yaml(新版本):
apiVersion: apps/v1 kind: Deployment metadata: name: canary-deployment-test-v2 namespace: default labels: app: canary-deployment-test-v2 # 目前没啥用 spec: selector: matchLabels: # 使用这两个标签可以控制下面的pod app: canary-nginx-test version: v2 replicas: 1 template: metadata: labels: app: canary-nginx-test # 和老版本相同 version: v2 # 和老版本不同 spec: containers: - name: nginx image: nginx
无论是查看pod
、deployment
、service
、node
,其实里面的信息都是类似的,一般都会说明资源的基本信息、当前状态、相关事件,当资源出现问题的时候还会告诉你问题是什么,所以在辅助我们排查的时候很有帮助,这里就简单举个Pod
为nginx
的例子吧,分析截图如下:
Name: my-nginx-pod-test # Pod名称 Namespace: default # 名称空间 Priority: 0 # 优先级 Node: k8s-02/192.168.139.134 # 节点信息,ip也是节点的ip Start Time: Sun, 05 Feb 2023 00:16:11 +0800 Labels: image-version=1.9.1 # Pod标签,用作筛选 type=pod Annotations: cni.projectcalico.org/containerID: bb64363d1f1b5008b8ea9ed5631fdd3ccb8f4afd646ba359867af3174d034af6 cni.projectcalico.org/podIP: 10.101.179.7/32 cni.projectcalico.org/podIPs: 10.101.179.7/32 # 注解信息,作用比较大 Status: Running # 当前状态 IP: 10.101.179.7 # Pod的ip IPs: IP: 10.101.179.7 # Pod的ip Containers: my-nginx-container-test: Container ID: docker://5ce48ea1f133654241bb106bb20cf1e69ff4342e23394dca00dbc2f7b6c85d8d Image: nginx:1.9.1 # 镜像版本 Image ID: docker-pullable://nginx@sha256:2f68b99bc0d6d25d0c56876b924ec20418544ff28e1fb89a4c27679a40da811b Port: <none> Host Port: <none> State: Running Started: Sun, 12 Feb 2023 19:15:44 +0800 Last State: Terminated Reason: Completed Exit Code: 0 Started: Sun, 12 Feb 2023 11:32:15 +0800 Finished: Sun, 12 Feb 2023 16:28:50 +0800 Ready: True Restart Count: 12 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-k85ld (ro) Conditions: Type Status Initialized True # 初始化完成 Ready True # 准备完成 ContainersReady True # 容器准备完成 PodScheduled True Volumes: kube-api-access-k85ld: Type: Projected (a volume that contains injected data from multiple sources) TokenExpirationSeconds: 3607 ConfigMapName: kube-root-ca.crt ConfigMapOptional: <nil> DownwardAPI: true QoS Class: BestEffort Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s node.kubernetes.io/unreachable:NoExecute op=Exists for 300s Events: <none>
用来选择Pod,可以设置一个或者多个标签键和值,例如:
apiVersion: apps/v1 #与k8s集群版本有关,使用 kubectl api-versions 即可查看当前集群支持的版本 kind: Deployment #该配置的类型,我们使用的是 Deployment metadata: #译名为元数据,即 Deployment 的一些基本属性和信息 name: nginx-deployment #Deployment 的名称 labels: #标签,可以灵活定位一个或多个资源,其中key和value均可自定义,可以定义多组,目前不需要理解 app: nginx #为该Deployment设置key为app,value为nginx的标签 spec: #这是关于该Deployment的描述,可以理解为你期待该Deployment在k8s中如何使用 replicas: 1 #使用该Deployment创建一个应用程序实例 selector: #标签选择器,与上面的标签共同作用,目前不需要理解 matchLabels: #选择包含标签app:nginx的资源 app: nginx template: #这是选择或创建的Pod的模板 metadata: #Pod的元数据 labels: #Pod的标签,上面的selector即选择包含标签app:nginx的Pod app: nginx spec: #期望Pod实现的功能(即在pod中部署) containers: #生成container,与docker中的container是同一种 - name: nginx #container的名称 image: nginx:1.7.9 #使用镜像nginx:1.7.9创建container,该container默认80端口可访问
注意: 该属性不能和matchLabels一起使用,避免造成冲突
使用说明:
可以设置3个子属性,分别是key(必须)、operator(必须)、values(非必须)
举例:
可以为集群中所有节点(不包含master,因为master节点含有污点)都部署一个Pod。并且集群中新加入的节点中也会自动部署一个Pod,将节点从该集群中移除之后,由于DamonSet部署的Pod也会自动移除。删除创建DamonSet资源之后,所有相关Pod都将被删除
用法基本一致,只是DamonSet不能指定副本数量,毕竟它可以为集群中的所有节点(不包含master,因为master节点含有污点)都部署一个Pod(有且仅有一个),所以既不能指定,也不用指定
效果:每一个节点(不包含master,因为master节点含有污点)中都有且仅有一个pod
apiVersion: apps/v1 kind: DaemonSet metadata: name: daemonset-test namespace: default labels: app: daemonset-test spec: selector: matchLabels: app: daemonset-test template: metadata: labels: app: daemonset-test spec: containers: - name: daemonset-test image: nginx
service下面对应StatefulSet,StatefulSet下面连接Pod,如果StatefulSet的serviceName对应service的name,并且service的ClusterIP是None(即ClusterIP不对应内容,那service就成为了无头服务),这样我们可以通过Pod名称.service名称.名称空间名称
的方式来访问pod,当然也可以省略名称空间,默认是default
嘛,如果直接访问service
名称来负责均衡访问Pod
也是可以的
通过DNSS解析
访问Pod
的3
步全部都在下面(测试发现第2步不是必须的),我们可以进入另外一个容器内部,然后通过curl statefulset-test-0.statefulset-service-test
方式访问部署的pod,当然也可以通过curl statefulset-service-test
方式来负责均衡访问Pod
apiVersion: apps/v1 kind: StatefulSet metadata: name: statefulset-test namespace: default spec: selector: matchLabels: app: statefulset-test # 和下面spec.template.metadata.labels一一对应 serviceName: "statefulset-service-test" # 3、设置serviceName是和service中metadata.name的值一致(通过DNS解析访问Pod第3步) replicas: 3 template: metadata: labels: app: statefulset-test # 和上面spec.selector.matchLabels一一对应 spec: containers: - name: nginx image: nginx --- apiVersion: v1 kind: Service metadata: name: statefulset-service-test namespace: default spec: selector: app: statefulset-test # 和上面deployment中的Pod的标签对应 type: ClusterIP # 1、设置type是ClusterIP(通过DNSS解析访问Pod第1步) clusterIP: None # 2、设置ClusterIP是None(通过DNSS解析访问Pod第2步) ports: - name: http protocol: TCP port: 80 targetPort: 80
主要介绍一下分区升级,和滚动升级不一样,它可以按照要求去升级部分Pod,它将更新Pod索引大于等于相应区块的Pod
比如下面红框中的内容,Pod原有下标大于等于分区号2的才会在执行kubectl apply -f XXX.yaml之后被更新,其他Pod不会更新
对于Pod原有下标的解释,比如我们部署了一个名称叫做statefulset-test的有状态服务,里面有3个Pod副本,那下标如下所示:
直接把yaml
文件列出来吧,大多数属性的使用都在里面说明了
属性详细解释版yaml:
apiVersion: batch/v1 kind: Job metadata: name: job-test namespace: default labels: app: job-test spec: activeDeadlineSeconds: 600 # 存活到期时间,一旦到期之后Job中的所有Pod都会被强制终止,单位:s backoffLimit: 4 # 标记Job失败之前的重试次数,默认值是6 parallelism: 2 # 并行运行的pod数量,默认按照次序运行,也就是第1个运行结束,才运行第2个 completions: 4 # 4次都成功才算成功,默认是1 ttlSecondsAfterFinished: 5 # Job完成之后删除该Job的倒计时时间,单位:s template: metadata: name: job-test labels: app: job-test spec: restartPolicy: Never # 重启策略:不重启 containers: - name: job-test image: busybox command: ['/bin/sh', '-c', 'ping -c 4 www.baidu.com'] # 镜像+执行指令必须能够结束,因为任务必须结束
简化版yaml:
apiVersion: batch/v1 kind: Job metadata: name: job-test namespace: default labels: app: job-test spec: template: metadata: name: job-test labels: app: job-test spec: restartPolicy: Never # 重启策略:不重启 containers: - name: job-test image: busybox command: ['/bin/sh', '-c', 'ping -c 4 www.baidu.com'] # 镜像+执行指令必须能够结束,因为任务必须结束
注意点:
注意事项:
必须谨慎操作,如果产生Pod过多,将导致新pod中的容器出现ContainersNotReady containers with unready status
情况,这时候就必须删除定时任务,否则很多Pod无法正常运行
属性详细解释版yaml:
apiVersion: batch/v1 kind: CronJob metadata: name: cronjob-test namespace: default spec: schedule: "*/1 * * * *" # cron表达式,五个级别按照顺序依次是分、时、日、月、周,这个代表每一分钟执行一次 # 并发策略 # Allow:允许,也是默认级别(说明:允许并发执行,即任务1没执行完成,但是根据cron表达式需要执行任务2,那么任务2也可以执行,多个任务并发执行) # Forbid:禁止(说明:如果任务1没执行完成,但是根据cron表达式需要执行任务2,那就不执行任务2了,继续执行任务1) # Replace:替换(说明:如果任务1没执行完成,但是根据cron表达式需要执行任务2,那就停止任务1,并且开始执行任务2) concurrencyPolicy: "Allow" successfulJobsHistoryLimit: 3 # 执行成功记录次数,默认值是3 failedJobsHistoryLimit: 3 # 执行失败记录次数,默认值是1,后期可以分析失败的原因 startingDeadlineSeconds: 600 # TODO 启动截止秒数,没看太懂,后续在补充吧 suspend: false # 暂停定时任务,默认是false;对已经执行了的任务,不会生效。作用是我需要排查问题的时候,不想让定时任务执行,那就先把定时任务暂停下 jobTemplate: # 下面都是job的内容,这里不再详细解释,详细属性解释请看上一节 spec: template: spec: containers: - name: cronjob-test image: busybox args: ['/bin/sh', '-c', 'date; echo Hello from the Kubernetes cluster'] restartPolicy: OnFailure
简化版yaml:
apiVersion: batch/v1 kind: CronJob metadata: name: cronjob-test namespace: default spec: schedule: "*/1 * * * *" # cron表达式,五个级别按照顺序依次是分、时、日、月、周,这个代表每一分钟执行一次 jobTemplate: # 下面都是job的内容,这里不再详细解释,详细属性解释请看上一节 spec: template: spec: containers: - name: cronjob-test image: busybox args: ['/bin/sh', '-c', 'date; echo Hello from the Kubernetes cluster'] restartPolicy: OnFailure
默认是级联删除的,也就是设置–cascade的值,如果为true的时候就是级联删除,反之就不是级联删除
我们举个不级联删除的例子,如下:
# 删除副本集,但不删除级联的Pod
kubectl delete replicaset my-repset --cascade=false
Kubernetes garbage collector(垃圾回收器)的作用是删除那些曾经有 owner,后来又不再有 owner 的对象。比如我们上面不级联删除之后的Pod就是这种对象,该特性在v1.12版本还是实现阶段,默认关闭,需要手动开启,一般用不到
k8s网络架构图如下:
拓展: 可以在pod中通过service名称去访问service
分析:
普通ClusterIP这种类型拥有IP,并且只能在集群内部访问,不能在浏览器上访问。默认是随机IP,不过可以指定访问IP。另外再说一下它的IP来源,来自于我们搭建K8s时的--pod-network-cidr=pod地址区间
随机IP举例(默认):
指定IP举例:
IP来源,来自于我们搭建K8s时的--pod-network-cidr=pod地址区间
无头ClusterIP这种类型不会分配到IP,只能在资源内部(比如Pod)通过service名称这种形式访问,当然之前说的针对无头服务可以通过pod名称.service名称.名称空间
方式在资源内部访问pod
NodePort这种方式可以在浏览器上访问,并且可以指定浏览器上的访问端口
随机端口举例(默认):
指定端口举例:
我们把nodePort暴露出去,那集群中所有节点中的kube-proxy都会监听该端口,只要我们向任何一个节点发送请求,都会回到同样的返回值,在所有节点中都可以查看端口监听情况,如下:
从下图中可以看出,我们service其实访问的是EndPoint,然后EndPoint访问Pod,所以EndPoint相当于中间人
假设我们多台Mysql部署在其他Ip的多台机器上,然后我们想统一访问这些Mysql,那我们可以只用访问service就可以了,然后service访问endpoint,endpoint指代到那些mysql
可以看到在定义service的时候并没有使用标签方式去选择Pod,下面EndPoints中的addresses中定义的就是Mysql的地址,然后注意service
和endpoint
中ports的name属性值要一致
service名称.名称空间
方式来访问的,详细来说就是针对同一个名称空间这种情况,在k8s内部直接使用service名称
进行访问。针对不同名称空间这种情况,在k8s内部使用service名称.名称空间
进行访问。无头服务
,也就是service的type是ClusterIP
,并且clusterIP
的值是None
,这就是无头服务;service名称
进行访问。针对不同名称空间这种情况,在k8s内部使用service名称.名称空间
进行访问。直接上yaml文件,然后注意type类型,以及externalName的值只能是外网域名,不能是IP,作用就是当我们k8s服务想访问外网域名的时候可以直接访问service名称.名称空间
就可以了,和外网域名调用的相关问题都是由该service进行处理
apiVersion: v1
kind: Service
metadata:
name: externalname-test
namespace: default
spec:
type: ExternalName # 注意类型
externalName: "atguigu.com" # 只能是域名,注意存在的跨域、伪装请求头问题
selector(类型:String):当type是ClusterIP、NodePort、LoadBalancer的时候,用来设置Pod的标签,作用是让我们在访问service的时候就可以负载均衡访问到对应标签的Pod
publishNotReadyAddress(类型:布尔值):是否发布未就绪的Pod,也就是流量到达service的时候,是否把流量打到未就绪的Pod,默认是false
ports(类型:列表):当type是ClusterIP、NodePort、LoadBalancer的时候,用来设置port(service端口)、targetPort(Pod端口,也是容器端口)、nodePort(浏览器用)的一一对应关系列表
ipFamilyPolicy(类型:String):下面截图是默认值,还有和IPV6相关的双栈协议等,如果真的使用,可以用kubectl explain svc.spec.XXX
解释
externalTrafficPolicy:默认值是Cluster,其中Cluster有负载均衡效果,而Local负载均衡效果不佳
externalName:在上面讲解ExternalName的时候说了,用来指定外网域名
clusterIP:指定一个节点中访问service的IP地址,指定之后clusterIPs也会有一个值,并且正是该值
clusterIPs:指定一组节点中访问service的IP地址,那我们访问该组中的任何一个IP都会访问到该service
sessionAffinity:默认值是None,如果是ClusterIP,name还可以配置sessionAffinityConfig中的超时时间,也就是在多长时间内session亲和策略依然有效,也就是会达到尽可能把相同机器的访问流量达到同一个节点上
之前我们说过无头服务,那种条件还是比较苛刻的,针对非无头服务,那我们如何在k8s资源内部通过类型域名的方式访问pod和service呢?
ping service名称
即可ping service名称.名称空间名称
即可ping pod-host-name.service名称
即可ping pod的hostname.service名称.名称空间名称
即可针对Pod来说举例,对应yaml如下,我们注意pod
中spec.hostname
和spec.subdomain
的写法,其中spec.hostname
可以随意写,而spec.subdomain
必须和service
中metadata.name
一致,测试pod的访问的时候就可以进入一个可以执行ping命令的资源,然后测试pod(busybox1)的命令是:ping busybox1.service-name
apiVersion: v1 kind: Service metadata: name: service-name namespace: default spec: selector: app: busybox type: ClusterIP ports: - name: test # 实际上不需要指定端口号 port: 1234 targetPort: 1234 --- apiVersion: v1 kind: Pod metadata: name: "busybox1" namespace: default labels: app: "busybox" spec: hostname: "busybox1" # 注意点1:随便起一个名称 subdomain: "service-name" # 注意点2:必须和上面service名称相同 containers: - name: "busybox1" image: "busybox" command: - sleep - "3600" --- apiVersion: v1 kind: Pod metadata: name: "busybox2" namespace: default labels: app: "busybox" spec: hostname: "busybox2" # 随便起一个名称 subdomain: "service-name" # 必须和上面service名称相同 containers: - name: "busybox2" image: "busybox" command: - sleep - "3600"
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。