1.基本概念
Kubernetes 是一个开源的,用于管理云平台中多个主机上的容器化的应用, Kubernetes的目标是让部署容器化的应用简单并且高效(powerful) , Kubernetes提供了应用部署,规划,更新维护的一种机制。
官方基本词汇
https://kubernetes.io/zh-cn/docs/reference/glossary/?all=true#term-control-plane
Kubernetes文档:
Kubernetes是什么 _ Kubernetes(K8S)中文文档_Kubernetes中文社区
一个k8s集群会包括master节点和node节点,下面我们来看大致框架
先看master节点,如图:

api-server:(接口服务):
- 基于 REST 风格开放 k8s 接口的服雾
Controller Manager:(控制器):
包括:
- 节点控制器(Node Controller):负责在节点出现故障时进行通知和响应
- 任务控制器(Job Controller) :监测代表一次性任务的Job对象,然后创建Pod来运行这些任务直至完成
- 端点分片控制器(EndpointSlice controller) :填充端点分片(EndpointSlice)对象(以提供Service和Pod之间的链接)。
- 服务账号控制器(ServiceAccount controller) :为新的命名空间创建默认的服务账号 (ServiceAccount)
scheduler(调度器):
负责将 Pod 基于一定算法,将其调用到更合适的节点(服务器)上
etcd:
理解为k8s的数据库,键值类型存储的分布式数据库,提供了基于Raft算法实现自主的集群高可用。
再看node节点

- kubelet负责Pod的生命周期、存储、网络
- kube-proxy网络代理,负责Service的服务发现负载均衡(4层负载)
- container-runtime容器运行时环境:如docker containerd等.
- Pod里存放容器
资源与对象
Kubernetes中的所有内容都被抽象为”资源”,如Pod, ServiceNode等都是资源。”对象”就是”资源”的实例,是持久化的实体。
对比Java,资源可以当作是类,而k8s的对象就是类的实例
而对象的创建、删除、修改都是通过”Kubernetes API”,也就是”Api Server”组件提供的API接口,命令行工具“kubectl”,实际上也是调用 kubernetes api.
K8s中的资源类别有很多种, kubectl可以通过配置文件来创建这些”对象”,配置文件更像是描述对象”属性”的文件,配置文件格式可以是”JSON”或”YAML”,常用”YAML”。
对于k8s资源,会分为不同层次,如图;
比如,命名空间1无法访问命名空间2。

API概述
官网文档:https://kubernetes.io/zh-cn/docs/reference/using-api/
REST API 是 Kubernetes 系统的重要部分,组件之间的所有操作和通信均由 API Server 处理的 REST AP I调用,大多数情况下, API 定义和实现都符合标准的 HTTP REST 格式,可以通过 kubectl 命令管理工具或其他命令行工具来执行。
Alpha版本
- 包含 alpha 名称的版本(例如v1alpha1)。
- 功能可能会被禁用。
Beta版本
- 包含 beta 名称的版本(例如 v2beta3)。
- 细节可能会改变,但功能在后续版本不会被删除
Stable版本
- 该版本名称命名方式:vX 这里 X 是一个整数。
- Stable 版本的功能特性,将出现在后续发布的软件版本中。
废弃 api 说明 :
https://kubernetes.io/zh-cn/docs/reference/using-api/deprecation-guide/
2.搭建k8s集群
1.使用环境
- 操作系统:CentOS 7
- Docker: 20+
- k8s: 1.23.6
使用2台主机

安装kubernetes集群要求Centos版本要在7.5或之上
查看centos版本
cat /etc/redhat-release

这里是学习使用,所以关闭防火墙,2个主机都要执行
systemctl stop firewalld
systemctl disable firewalld
selinux是linux系统下的一个安全服务,关闭selinux,2个主机都要执行
永久关闭
sed -i "s/enforcing/disabled/" /etc/selinux/config
临时
setenforce 0

关闭swap(关闭后需要重启虚拟机),2个主机都要执行
永久关闭
sed -ri "s/.*swap.*/#&/" /etc/fstab
临时
swapoff -a

记得重启!
编辑三台服务器的/etc/hosts文件,2个主机都要执行
vim /etc/hosts
添加下面内容(改成自己的ip)
ip master ip node1 ip node2

kubernetes要求集群中的节点时间必须精确一直。2个主机都要执行
yum install ntpdate -y
ntpdate time.windows.com

将桥接的IPV4流量传递到iptables的链,2个主机都要执行
编辑/etc/sysctl.d/kubernetes.conf
vim /etc/sysctl.d/kubernetes.conf
加入
net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1

最后执行,2个主机都要执行
sysctl --system

2.安装docker
接着就是安装docker了,2个主机都要执行
参考
docker-ce镜像_docker-ce下载地址_docker-ce安装教程-阿里巴巴开源镜像站 (aliyun.com)
注意,过高版本docker不兼容高版本k8s,所以我们下载指定版本
yum install --setopt=obsoletes=0 docker-ce-18.06.3.ce-3.el7 -y
如果报了错误如下

执行以下命令切换镜像源:
wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
再次安装
yum install --setopt=obsoletes=0 docker-ce-18.06.3.ce-3.el7 -y
开启Docker服务
sudo service docker start
开机自启
systemctl enable docker
检查是否安装成功
docker version

可使用自己的账户中的链接加速。

3.安装 kubeadm,kubelet、kubectl
以下2个主机都要执行
配置kubernetes源为阿里的yum源,
cat > /etc/yum.repos.d/kubernetes.repo << EOF [kubernetes] name=Kubernetes baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=0 repo_gpgcheck=0 gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg EOF
安装 kubeadm,kubelet、kubectl
yum install -y kubelet-1.23.6 kubeadm-1.23.6 kubectl-1.23.6
输出以下就是成功

设置开机启动
systemctl enable kubelet
systemctl start kubelet

查看版本:
kubelet --version

以下2个主机都要执行
vim /etc/docker/daemon.json

"exec-opts": ["native.cgroupdriver=systemd"]
然后重启
systemctl daemon-reload
systemctl restart docker
在Master节点上,创建master_images.sh
vim master_images.sh
脚本如下
#!/bin/bash
images=(
kube-apiserver:v1.23.6
kube-controller-manager:v1.23.6
kube-scheduler:v1.23.6
kube-proxy:v1.23.6
pause:3.1
etcd:3.4.3-0
coredns:1.6.5
)
for imageName in ${images[@]};do
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName k8s.gcr.io/$imageName
docker rmi registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName
done
加入读写权限
chmod 700 ./master_images.sh
执行脚本
./master_images.sh


初始化master节点( 在 Master 节点下执行)
kubeadm init --apiserver-advertise-address=ip地址 --image-repository registry.aliyuncs.com/google_containers --kubernetes-version v1.23.6 --service-cidr=10.96.0.0/12 --pod-network-cidr=10.244.0.0/16
出现以下成功


( 在 Master 节点下执行)
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

如图master节点在初始化成功后,会输出对应节点加入指令

在node节点执行即可
kubeadm join 172.31.7.240:6443 --token cwt549.gjxv4ktfue5nkjkh \ --discovery-token-ca-cert-hash sha256:09ea1b169e2d7c8c0f119f5963f3cc91d8fb887d448596d4d722cc9c7a978f24
在master节点执行,就可以获取节点
kubectl get nodes

解决NotReady状态
在master节点:
cd /opt
mkdir k8s
cd k8s/
curl https://docs.projectcalico.org/v3.20/manifests/calico.yaml -O
编辑文件
ll
vim calico.yaml

修改如下参数

改为,实际就是改为初始化的 –pod-network-cidr=10.244.0.0/16的参数

- name: CALICO_IPV4POOL_CIDR value: "10.244.0.0/16"
找到需要下载的镜像
grep image calico.yaml
这样它会从docker官方下,为了加速执行以下,
sed -i 's#docker.io/##g' calico.yaml

kubectl apply -f calico.yaml

完毕后,需要等待,可用此命令查看
kubectl get po -n kube-system

最后就可以了
kubectl get nodes

测试是否成功
创建部署,使用nginx测试
kubectl create deployment nginx --image=nginx:1.14-alpine
暴露端口,访问测试
kubectl expose deploy nginx --port=80 --target-port=80 --type=NodePort
查看 pod 以及服务信息
kubectl get pod,svc

如图,访问30443端口
可以访问master

可以访问node1

这个时候k8s集群的node节点,还不能使用命令行工具
kubectl get nodes

将 master 节点中 /etc/kubernetes/admin.conf 拷贝到需要运行的服务器的 /etc/kubernetes 目录中,node1是主机名,没有配置映射填ip地址
scp /etc/kubernetes/admin.conf root@node1:/etc/kubernetes

在node节点node1上配置环境变量
echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
source ~/.bash_profile

k8s集群的node节点使用命令行工具
kubectl get nodes


3.深入Pods
官网:https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/pod-lifecycle/
先知道:
无状态应用:不会对本地环境产生任何依赖,例如不会存储数据到本地磁盘。
有状态应用:会对本地环境产生依赖,例如需要存储数据到本地磁盘。
一.基本概念:
官网描述
- Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。
- Pod(就像在鲸鱼荚或者豌豆荚中)是一组(一个或多个) 容器; 这些容器共享存储、网络、以及怎样运行这些容器的声明。 Pod 中的内容总是并置(colocated)的并且一同调度,在共享的上下文中运行。 Pod 所建模的是特定于应用的 “逻辑主机”,其中包含一个或多个应用容器, 这些容器相对紧密地耦合在一起。 在非云环境中,在相同的物理机或虚拟机上运行的应用类似于在同一逻辑主机上运行的云应用。
- 除了应用容器,Pod 还可以包含在 Pod 启动期间运行的 Init 容器。
如图:

- Pod 容器组代表了 Kubernetes 中一个独立的应用程序运行实例,该实例可能由单个容器或者几个紧耦合在一起的容器组成。
- pause就是共享网络和存储的
Pod 模板
- 工作负载资源的控制器通常使用Pod 模板(Pod Template)来替你创建 Pod 并管理它们。
- 工作负载的控制器会使用负载对象中的Pod Template来生成实际的 Pod。
- Pod Template是你用来运行应用时指定的负载资源的目标状态的一部分。
Pod控制器
资源的控制器能够处理副本的管理、上线,并在 Pod 失效时提供自愈能力。 例如,如果一个节点失败,控制器注意到该节点上的 Pod 已经停止工作, 就可以创建替换性的 Pod。调度器会将替身 Pod 调度到一个健康的节点执行。
ReplicationController
- 确保在任何时候都有特定数量的 Pod 副本处于运行状态。帮助我们动态更新 Pod 的副本数
ReplicaSet
- ReplicaSet 的目的是维护一组在任何时候都处于运行状态的 Pod 副本的稳定集合。
- 因此,它通常用来保证给定数量的、完全相同的 Pod 的可用性。
- 即也可帮助我们动态更新 Pod 的副本数,但是相比ReplicationController可以通过 selector 来选择对哪些 Pod生效
Deployment
- Deployment 为 Pod 和 ReplicaSet 提供声明式的更新能力。
- 描述好Deployment 中的目标状态,而 Deployment 控制器(Controller) 以受控速率更改实际状态, 使其变为期望状态。可以定义 Deployment 以创建新的 ReplicaSet,或删除现有 Deployment, 并通过新的 Deployment 收养其资源。
StatefulSet
- StatefulSet 是用来管理有状态应用的工作负载 API 对象。
- StatefulSet 用来管理某 Pod 集合的部署和扩缩, 并为这些 Pod 提供持久存储和持久标识符。使用 StatefulSet可以使用存储卷为工作负载提供持久存储,也就是更适合有状态的,
- 如果应用程序不需要任何稳定的标识符或有序的部署、删除或扩缩,或持久存储 ,则应该使用由一组无状态的副本控制器提供的工作负载来部署应用程序,比如 Deployment
- 其中,Headless Service解决有状态服务的 DNS 管理,而volumeClaimTemplate用于创建持久化卷的模板
DaemonSet
- DaemonSet 确保全部(或者某些)节点上运行一个 Pod 的副本。 当有节点加入集群时, 也会为他们新增一个 Pod 。 当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。
- DaemonSet保证在每个Node上都运行一个容器副本,常用来部署一些集群的日志、监控或者其他系统管理应用。
- 典型的应用包括:日志收集,比如 fluentd, logstash 等;系统监控,比如Prometheus Node Exporter, collectd,New Relic agent, Ganglia gmond 等;系统程序,比如 kube-proxy, kube-dns, glusterd, ceph等
获取pods信息
kubectl get pods

如果我们需要对其进行删除操作,pods是根据deploy关联的,需要先删除deploy
获取当前的deploy信息
kubectl get deploy

删除nginx的deploy
kubectl delete deploy nginx

列出所有 namespace 中的所有 service
kubectl get services

删除指定services
kubectl delete services nginx

此时nginx的pods就被删除了

当然也可以直接删除
kubectl delete po nginx-6867cbf567-2jh49
二、编写配置文件
创建一个目录,并进入,将在此目录中完成编写配置文件
mkdir /opt/k8s/pods
cd pods/

创建一个nginx的pods,先创建一个配置文件

1.配置文件常用参数
配置文件的常用参数如下:
K8S APl 的版本,可以用 kubectl api versions 命令查询
apiVersion
yam 文件定义的资源类型和角色
kind
元数据对象,下面是它的属性
metadata
元数据对象的名字,比如 pod 的名字
metadata.name
元数据对象的命名空间
metadata.namespace
详细定义对象
spec
定义 Spec 对象的容器列表
spec.containers[]
为列表中的某个容器定义名称
spec.containers[].name
为列表中的某个容器定义需要的镜像名称
spec.containers[].image
- – Always(默认):意思是每次都尝试重新拉取镜像
- – Never:表示仅适用本地镜像
spec.containers[].imagePullPolicy
指定容器启动命令,因为是数组可以指定多个,不指定则使用镜像打包时使用的启动命令。
spec.containers[].command[]
指定容器启动命令参数,因为是数组可以指定多个。
spec.containers[].args[]
指定容器的工作目录
spec.containers[].workingDir
指定容器内部的存储卷配置
spec.containers[].volumeMounts[]
指定可以被容器挂载的存储卷的名称
spec.containers[].volumeMounts[].name
指定可以被容器挂载的存储卷的路径
spec.containers[].volumeMounts[].mountPath
设置存储卷路径的读写模式,ture 或者 false,默认是读写模式
spec.containers[].volumeMounts[].readOnly
指定容器需要用到的端口列表
spec.containers[].ports[]
指定端口的名称
spec.containers[].ports[].name
指定容器需要监听的端口号
spec.containers[].ports[].containerPort
指定容器所在主机需要监听的端口号,默认跟上面 containerPort 相同,注意设置了 hostPort 同一台主机无法启动该容器的相同副本(因为主机的端口号不能相同,这样会冲突)
spec.containers[].ports[].hostPort
指定端口协议,支持 TCP 和 UDP,默认值为 TCP
spec.containers[].ports[].protocol
指定容器运行前需设置的环境变量列表
spec.containers[].env[]
指定环境变量名称
spec.containers[].env[].name
指定环境变量值
spec.containers[].env[].value
指定资源限制和资源请求的值(这里开始就是设置容器的资源上限)
spec.containers[].resources
指定设置容器运行时资源的运行上限
spec.containers[].resources.limits
指定 CPU 的限制,单位为 Core 数,将用于 docker run –cpu-shares 参数
spec.containers[].resources.limits.cpu
指定 mem 内存的限制,单位为 MIB、GiB
spec.containers[].resources.limits.memory
指定容器启动和调度时的限制设置
spec.containers[].resources.requests
CPU请求,单位为core数,容器启动时初始化可用数量
spec.containers[].resources.requests.cpu
内存请求,单位为MIB、GiB,容器启动的初始化可用数量
spec.containers[].resources.requests.memory
- – Always:pod 一旦终止运行,则无论容器是如何终止的,kubelet 服务都将重启它。
- – OnFailure:只有 pod 以非零退出码终止时,kubelet 才会重启该容器。如果容器正常结束(退出码为0),则 kubectl 将不会重启它。
spec.restartPolicy
定义 Node 的 label 过滤标签,以 key:value 格式指定
spec.nodeSelector
定义 pull 镜像时使用 secret 名称,以 name:secretkey 格式指定
spec.imagePullSecrets
定义是否使用主机网络模式,默认值为 false。设置 true 表示使用宿主机网络,不使用 docker 网桥,同时设置了 true将无法在同一台宿主机上启动第二个副本
spec.hostNetwork
2.编写配置文件
上面就是常用的参数
下面来编写nginx的Pods
vim nginx-demo.yaml
对应配置如下:
# api 文档版本
apiVersion: v1
# 资源对象类型,也可以配置为Deployment,StatefulSet
kind: Pod
# 用于描述Pod的元数据
metadata:
# Pod的名称
name: nginx-demo
# 定义Pod的标签
labels:
#自定义key:value,如:
type: app
# 命名空间
namespace: 'default'
# 期望Pod按照这里描述创建
spec:
# 对容器描述
containers:
# 容器名称
- name: nginx
# 指定容器的镜像
image: nginx:1.7.9
# 定义镜像拉取策略,IfNotPresent表示如果本地有镜像就使用本地镜像,没有就拉取在线镜像。
imagePullPolicy: IfNotPresent
# 指定容器启动命令
command:
# 如指定命令:nginx -g 'daemon off;'
- nginx
- -g
- 'daemon off;'
# 指定容器的工作目录
workingDir: /usr/share/nginx/html
# 指定容器需要用到的端口
ports:
# 端口名称
- name: http
# 指定容器内需要监听的端口号
containerPort: 80
# 指定端口协议
protocol: TCP
# 环境变量
env:
# key值
- name: JVM_OPTS
# value值
value: '-Xms128m -Xmx128m'
# 指定设置容器运行时资源的运行限制
resources:
# 最少需要多少资源
requests:
# 限制最少使用0.1个核心
cpu: 100m
# 限制最少使用128兆
memory: 128Mi
# 最多需要多少资源
limits:
# 限制最少使用0.1个核心
cpu: 200m
# 限制最少使用128兆
memory: 256Mi
# 定义 pod 的重启策略,OnFailure只有失败才重启
restartPolicy: OnFailure
写好了配置文件,则可以使用其创建
用法:
创建资源 ,-f 后跟文件
kubectl create -f ./my-manifest.yaml
如:
创建上面写的yaml文件的Pod
kubectl create -f nginx-demo.yaml

如上图,可以看到已经创建了,但还在ContainerCreating,稍等即可,也可以使用命令查看情况
kubectl describe po nginx-demo

如上图,刚好,已经启动了
kubectl get po

三、深入Pod探针
容器探针
probe 是由 kubelet 对容器执行的定期诊断。 要执行诊断,kubelet 既可以在容器内执行代码,也可以发出一个网络请求。是容器内应用的监测机制,根据不同的探针来判断容器应用当前的状态。
1.探测结果
每次探测都将获得以下三种结果之一:
- Success(成功)容器通过了诊断。
- Failure(失败)容器未通过诊断。
- Unknown(未知)诊断失败,因此不会采取任何行动。
2.类型
LivenessProbe
指示容器是否正在运行。如果存活态探测失败,则 kubelet 会杀死容器, 并且容器将根据其重启策略决定未来。如果容器不提供存活探针, 则默认状态为 Success。
用于探测容器中的应用是否运行,如果探测失败,kubelet 会根据配置的重启策略进行重启,若没有配置,默认就认为容器启动成功,不会执行重启策略。
ReadinessProbe
指示容器是否准备好为请求提供服务。如果就绪态探测失败, 端点控制器将从与 Pod 匹配的所有服务的端点列表中删除该 Pod 的 IP 地址。 初始延迟之前的就绪态的状态值默认为 Failure。 如果容器不提供就绪态探针,则默认状态为 Success。
用于探测容器内的程序是否健康,它的返回值如果返回 success,那么就认为该容器已经完全启动,并且该容器是可以接收外部流量的。比如要求程序启动后再进行初始化后才算真正启动,才能接收用户请求。
StartupProbe
- 指示容器中的应用是否已经启动。如果提供了启动探针,则所有其他探针都会被禁用,直到此探针成功为止。如果启动探测失败,kubelet 将杀死容器, 而容器依其重启策略进行重启。 如果容器没有提供启动探测,则默认状态为 Success。
- k8s 1.16 版本新增的探针,用于判断应用程序是否已经启动了。
- 当配置了 startupProbe 后,会先禁用其他探针,直到 startupProbe 成功后,其他探针才会继续。
作用:由于有时候不能准确预估应用一定是多长时间启动成功,因此配置另外两种方式不方便配置初始化时长来检测,而配置了 statupProbe 后,只有在应用启动成功了,才会执行另外两种探针,可以更加方便的结合使用另外两种探针使用。
3.探针使用
探测方式
简单看看,后面有实际运用。
ExecAction
在容器内部执行一个命令,如果返回值为 0,则任务容器时健康的。
livenessProbe: exec: command: - cat - /health
TCPSocketAction
通过 tcp 连接监测容器内端口是否开放,如果开放则证明该容器健康
livenessProbe: tcpSocket: port: 80
HTTPGetAction
生产环境用的较多的方式,发送 HTTP 请求到容器内的应用程序,如果接口返回的状态码在 200~400 之间,则认为容器健康。
livenessProbe: failureThreshold: 5 httpGet: path: /health port: 8080 scheme: HTTP httpHeaders: - name: xxx value: xxx
常用参数
# 初始化时间 initialDelaySeconds: 60 # 超时时间 timeoutSeconds: 2 # 监测间隔时间 periodSeconds: 5 # 检查 1 次成功就表示成功 successThreshold: 1 # 监测失败 2 次就表示失败 failureThreshold: 2
查看Pod的配置文件
先查看默认命名空间下的Pods
kubectl get po

先查看指定命名空间下的Pods,-n后接命名空间名字
kubectl get po -n kube-system

使用编辑配置文件命令,就可以查看,-n后接命名空间名字 ,最后接Pod名字
kubectl edit po -n kube-system calico-node-4zw9h
如查看这个

如下,可以看到配置了对应探针

删除之前使用配置文件创建的nginx-demo
kubectl delete po nginx-demo

使用StartupProbe探针
我们测试一下参数使用
在master主机
cd /opt/k8s/pods/
改一下配置文件
vim nginx-demo.yaml
加入如下:
先使用HTTP方式
生产环境用的较多的方式,发送 HTTP 请求到容器内的应用程序,如果接口返回的状态码在 200~400 之间,则认为容器健康。
startupProbe:
httpGet:
path: /api/path
port: 80
# 监测失败 2 次就表示失败
failureThreshold: 2
# 监测间隔时间
periodSeconds: 5
# 检查 1 次成功就表示成功
successThreshold: 1
# 超时时间
timeoutSeconds: 2层级关系在spec下的containers下

注意此时并没有这个路径供测试,所以一定失败
创建上面写的yaml文件的Pod
kubectl create -f nginx-demo.yaml
如图

查看运行描述信息
kubectl describe po nginx-demo
下面Startup就是启动探针startupProbe

再获取一次,可以看到重启了四次,还是无法启动起来。
kubectl get pods

删除
kubectl delete po nginx-demo

改一下配置文件
vim nginx-demo.yaml
就改一下路径,改为一定有的/index.html
httpGet: path: /index.html port: 80

再创建一次,直接就运行起来了
kubectl create -f nginx-demo.yaml

使用TCP方式
通过 tcp 连接监测容器内端口是否开放,如果开放则证明该容器健康
改一下配置文件
vim nginx-demo.yaml
改为
startupProbe:
tcpSocket:
port: 80
# 监测失败 2 次就表示失败
failureThreshold: 2
# 监测间隔时间
periodSeconds: 5
# 检查 1 次成功就表示成功
successThreshold: 1
# 超时时间
timeoutSeconds: 2
再执行一次
kubectl create -f nginx-demo.yaml

查看运行描述信息
kubectl describe po nginx-demo
可以看到换成了tcp

使用命令行方式
在容器内部执行一个命令,如果返回值为 0,则任务容器时健康的。
startupProbe:
exec:
command:
- sh
- -c
- "echo 'Hello Pod' > /inited"成功

查看
执行容器命令,一个pod可以包含多个容器,所以要指定容器,-c就是指定容器,–是固定写法
kubectl exec -it nginx-demo -c nginx -- cat /inited

使用LivenessProbe探针
改一下配置文件
vim nginx-demo.yaml

# 启用探针
livenessProbe:
httpGet:
path: /path
port: 80
# 监测失败 2 次就表示失败
failureThreshold: 2
# 监测间隔时间
periodSeconds: 5
# 检查 1 次成功就表示成功
successThreshold: 1
# 超时时间
timeoutSeconds: 2
因为没有/path,使用会失败
kubectl describe po nginx-demo

可以看到重启了3次后,就失败了

注意:如果再重启范围内,存在此路径,不用重新创建也可以成功。就不再演示。
使用ReadinessProbe探针
# 启用探针
readinessProbe:
httpGet:
path: /path
port: 80
# 监测失败 2 次就表示失败
failureThreshold: 2
# 监测间隔时间
periodSeconds: 5
# 检查 1 次成功就表示成功
successThreshold: 1
# 超时时间
timeoutSeconds: 2
创建
kubectl create -f nginx-demo.yaml
因为没有/path,使用会失败
kubectl describe po nginx-demo

所以READY数会一直是零

注意:如果再重启范围内,存在此路径,不用重新创建也可以成功。就不再演示。
四、Pod生命周期
下面来看叩工狼教育做的关于Pod生命周期的一幅图,较详细了

有两个回调暴露给容器:
PostStart
这个回调在容器被创建之后立即被执行。 但是,不能保证回调会在容器入口点(ENTRYPOINT)之前执行。 没有参数传递给处理程序。
PreStop
在容器因 API 请求或者管理事件(诸如存活态探针、启动探针失败、资源抢占、资源竞争等) 而被终止之前,此回调会被调用。 如果容器已经处于已终止或者已完成状态,则对 preStop 回调的调用将失败。 在用来停止容器的 TERM 信号被发出之前,回调必须执行结束。 Pod 的终止宽限周期在 PreStop 回调被执行之前即开始计数, 所以无论回调函数的执行结果如何,容器最终都会在 Pod 的终止宽限期内被终止。 没有参数会被传递给处理程序。
改一下配置文件
vim nginx-demo.yaml

# 配置生命周期
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo 'Hello Delete Pod' > /usr/share/nginx/html/prestop.html"]
preStop:
exec:
command: ["/bin/sh","-c","echo 'Hello Delete Pod' >> /usr/share/nginx/html/prestop.html"]
运行
kubectl create -f nginx-demo.yaml

可以开两个窗口查看,加-w参数实时监控
kubectl get pods -w

接下来看这个变化
改一下配置文件
vim nginx-demo.yaml

如图,让它睡眠50秒

明明睡眠50秒,为什么只等待了30秒
这是因为在配置文件中,默认存在一个参数terminationGracePeriodSeconds,默认为30.
作用是变为删除中的状态后,会给 pod 一个宽限期,让 pod 去执行一些清理或销毁操作。
作用与 pod 中的所有容器
我们可以在配置文件加入以下参数
terminationGracePeriodSeconds: 30
层级目录在spec下

我们可以改这个数字,默认为30.
所以如果preStop执行命令时间超过了30秒,应该多配置一个参数terminationGracePeriodSeconds,改更大一定
初始化容器
在真正的容器启动之前,先启动 InitContainer,在初始化容器中完成真实容器所需的初始化操作,完成后再启动真实的容器。且一定在 EntryPoint 之前执行。
postStart无法保证一定在 EntryPoint 之前执行,postStart 更适合去执行一些命令操作,而 InitController 实际就是一个容器,可以在其他基础容器环境下执行更复杂的初始化功能。
在 pod 创建的模板中配置 initContainers 参数:
这里我要他睡眠100s,好等下查看效果
initContainers: - image: nginx imagePullPolicy: IfNotPresent command: ["sh", "-c", "sleep 100;"] name: init-test
注意层级关系,在.spec下

注意层级关系,如果是deploment则在.spec.template.spec下

创建
kubectl create -f nginx-demo.yaml
可以看到一直在init

过100s后就执行成功

4.资源调度
寻找资源
通过Label和Selector
Selector会搜索出符合要求有对应Label的资源
标签(Labels)
标签(Labels) 是附加到 Kubernetes 对象(比如 Pod)上的键值对。
1.配置文件
如之前配置的标签

2.命令
selector 按照 label 单值查找节点
kubectl get po -A -l 标签key=标签value
查看所有节点的 labels
kubectl get po --show-labels


设置标签
kubectl label po <资源名称> 标签key=标签value
如
kubectl label po nginx-demo test=test

修改标签
kubectl label po <资源名称> 标签key=标签value --overwrite
如:
kubectl label po nginx-demo test=123 --overwrite

直接编辑配置
kubectl edit po nginx-demo

选择器(Selector)
Selector会搜索出符合要求有对应Label的资源
1.配置文件
各对象的配置 spec.selector 或其他可以写 selector 的属性中编写
2.命令
匹配单个值,查找 app=hello 的 pod
kubectl get po -A -l app=hello
匹配多个值
kubectl get po -A -l 'k8s-app in (metrics-server, kubernetes-dashboard)'
查找 version!=1 and app=nginx 的 pod 信息
kubectl get po -l version!=1,app=nginx

不等值 + 语句
kubectl get po -A -l version!=1,'app in (busybox, nginx)'
Deployment
- Deployment 为 Pod 和 ReplicaSet 提供声明式的更新能力。
- 描述好Deployment 中的目标状态,而 Deployment 控制器(Controller) 以受控速率更改实际状态, 使其变为期望状态。可以定义 Deployment 以创建新的 ReplicaSet,或删除现有 Deployment, 并通过新的 Deployment 收养其资源。
先创建一个目录
mkdir /opt/k8s/deployment
cd /opt/k8s/deployment
创建一个 deployment
kubectl create deploy nginx-deploy --image=nginx:1.7.9

查看部署信息
kubectl get deployments

查看 rs,也就是ReplicaSet
kubectl get rs
或
kubectl get replicaset

仔细查看命名差别,可以理解为deployment下管理replicaset,而replicaset下管理Pods

更新 Deployment
注意:只有修改了 deployment 配置文件中的 template 中的属性后,才会触发更新操作
查看deploment
kubectl get deploy --show-labels

编辑
kubectl edit deploy nginx-deploy
修改一下副本数

可以看到确实变成3个

再修改一下nginx的版本
kubectl edit deploy nginx-deploy

通过 kubectl get deployments 获取部署信息,UP-TO-DATE 表示已经有多少副本达到了配置中要求的数目
可以看到deploy是一个一个更新的,但是其能访问到的一直是3个

查看部署描述,最后展示发生的事件列表也可以看到滚动更新过程
kubectl describe deploy <deployment_name>
kubectl describe deploy nginx-deploy
可以看到它使用了两个不同的replicaset

新创建一个nginx-deploy-754898b577,然后每停掉原来的nginx-deploy-78d8bf4fd7中的一个Pod,就先复制一个对应的Pod到nginx-deploy-754898b577中,然后使用,以达到类似热更新的效果。

如下图:

可以看到有两个RS,不过临时创建的不再有Pod了
kubectl get rs --show-labels

最后Pod都转接到nginx-deploy-754898b577下
kubectl get po --show-labels

还可以使用命令更改
修改 nginx 版本号,在最后加入–record 会在 annotation 中记录当前命令创建或升级了资源,后续可以查看做过哪些变动操作。
kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
查看滚动更新的过程
kubectl rollout status deploy <deployment_name>

回滚Deployment
如图,可以看到使用了两个不同的版本
kubectl get rs --show-labels

更新 deployment 时参数不小心写错,如 nginx:1.9.1 写成了 nginx:1.91
kubectl set image deployment/nginx-deploy nginx=nginx:1.91
监控滚动升级状态,由于镜像名称错误,下载镜像失败,因此更新过程会卡住
kubectl rollout status deployments nginx-deploy

结束监听后,获取 rs 信息,我们可以看到新增的 rs 副本数多了一个
kubectl get rs

关联到新的 rs 的 pod,状态是 ErrImagePull状态

找到需要回退的 revision 进行回退
获取 revison 的列表
kubectl rollout history deployment/nginx-deploy

查看对应版本详细信息
kubectl rollout history deployment/nginx-deploy --revision=3

回退到上一个版本
kubectl rollout undo deployment/nginx-deploy
回退到指定的 revision
kubectl rollout undo deployment/nginx-deploy --to-revision=3

kubectl describe deployment
可以看到和更新一样,同样都是类似热更新的

通过设置 .spec.revisonHistoryLimit 来指定 deployment 保留多少 revison,如果设置为 0,则不允许 deployment 回退了。
扩容缩容Deployment
方法1.通过 kube scale 命令可以进行自动扩容/缩容
kubectl scale --replicas=6 deploy nginx-deploy

方法2.配置文件编辑 replcas 也可以实现扩容/缩容
编辑
kubectl edit deploy nginx-deploy
修改一下副本数

可以看到确实变成3个

注意:扩容与缩容只是直接创建副本数,没有更新 pod template 因此不会创建新的 rs
暂停与恢复Deployment
如果频繁修改pod template ,可以暂停 deployment 的 rollout
就可以实现暂停,直到你下次恢复后才会继续进行滚动更新
kubectl rollout pause deployment <name>
恢复 rollout
kubectl rollout resume deploy <name>
Deployment配置文件
通过命令要deployment以yaml格式输出
kubectl get deployment nginx-deploy -o yaml

我们可以将输出的信息复制进yaml,当然最后的status不要加入。

创建并编辑
vim nginx-deploy.yaml
查看上面的写
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-deploy
name: nginx-deploy
namespace: default
spec:
# 期望副本数
replicas: 1
# 进行滚动更新后,保留的历史版本数
revisionHistoryLimit: 10
# Selector关联labels
selector:
matchLabels:
app: nginx-deploy
# 更新策略
strategy:
# 滚动更新配置
rollingUpdate:
# 进行滚动更新时,更新的个数最多可以超过期望副本数的个数/比例
maxSurge: 25%
# 进行滚动更新时,最大不可用比例更新比例,表示在所有副本数中,最多可以有多少个不更新成功
maxUnavailable: 25%
# 更新类型,采用滚动更新
type: RollingUpdate
# 创建Pod模板
template:
metadata:
labels:
app: nginx-deploy
spec:
containers:
- image: nginx:1.7.9
imagePullPolicy: IfNotPresent
name: nginx
restartPolicy: Always
terminationGracePeriodSeconds: 30
通过文件创建
kubectl create -f xxx.yaml --record
StatefulSet
定义
StatefulSet就是专门针对于有状态服务进行部署的一个控制器。
- StatefulSet 是用来管理有状态应用的工作负载 API 对象。
- StatefulSet 用来管理某 Pod 集合的部署和扩缩, 并为这些 Pod 提供持久存储和持久标识符。使用 StatefulSet可以使用存储卷为工作负载提供持久存储,也就是更适合有状态的,
- 如果应用程序不需要任何稳定的标识符或有序的部署、删除或扩缩,或持久存储 ,则应该使用由一组无状态的副本控制器提供的工作负载来部署应用程序,比如 Deployment
- Headless Service解决有状态服务的 DNS 管理,而volumeClaimTemplate用于创建持久化卷的模板
创建并进入文件夹
mkdir /opt/k8s/statefulSet
cd /opt/k8s/statefulSet
vim web.yaml
配置如下:
---
# 镶嵌的yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
# StatefulSet类型
kind: StatefulSet
metadata:
name: web
spec:
# 使用了哪个service来管理dns,就是上面镶嵌的yaml
serviceName: "nginx"
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
# 要暴露的端口
- containerPort: 80
name: web查看目前有什么StatefulSet
kubectl get sts
查看有什么service
kubectl get svc
以yaml创建
kubectl create -f web.yaml


查看此时的Pod值

运行一个 pod,基础镜像为 busybox 工具包,
kubectl run -i --tty --image busybox:1.28.4 dns-test --restart=Never --rm /bin/sh

可以看到都能ping通,证明了
nslookup 可以看到 dns 信息

exit退出

扩容缩容
方法1
kubectl scale statefulset web --replicas=5

方法2
patch方法打补丁
kubectl patch statefulset web -p '{"spec":{"replicas":3}}'
镜像更新
镜像更新,patch是打补丁,–type表明是json,-p指出要输出内容
kubectl patch sts web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"nginx:1.9.1"}]'
灰度发布
灰度发布(又名金丝雀发布)是指在黑与白之间,能够平滑过渡的一种发布方式。
就是让少部分人先使用,没有问题再逐渐扩大更新

StatefulSet 也可以采用滚动更新策略,同样是修改 pod template 属性后会触发更新,但是由于 pod 是有序的,在 StatefulSet 中更新时是基于 pod 的顺序倒序更新的
- 利用滚动更新中的 partition 属性,可以实现简易的灰度发布的效果
- 如果我们有 5 个 pod,如果当前 partition 设置为 3,那么此时滚动更新时,只会更新那些 序号 >= 3 的 pod
- 通过控制 partition 的值,来决定只更新其中一部分 pod,确认没有问题后再主键增大更新的 pod 数量,最终实现全部 pod 更新
kubectl edit sts web
如下图,默认使用的type是RollingUpdate滚动更新, 我们可以修改partition 属性

将当前 partition 修改为 3,就只会更新那些 序号 >= 3 的 pod,测试完毕没有问题后,再将partition 逐渐设置更大。
还有一种更新策略叫OnDelete
只有在 pod 被删除时会进行更新操作
编辑
kubectl edit sts web
改为OnDelete

再去修改

可以看到pod 被删除时,马上又重新创建了,此时版本就变为了nginx:1.7.9


删除操作
注意:因为StatefulSet的删除涉及到对关联的资源如何处理
删除 StatefulSet 和 Headless Service
级联删除:删除 statefulset 时会同时删除pods(默认)
kubectl delete statefulset web

非级联删除:删除 statefulset 时不会删除 pods,删除 sts 后,pods 就没人管了,此时再删除 pod 不会重建的
kubectl deelte sts web --cascade=false

当然,无论哪种方式都要删除 service
kubectl delete service nginx
如果存在pvc,也要对应删除
StatefulSet删除后PVC还会保留着,数据不再使用的话也需要删除
kubectl delete pvc www-web-0 www-web-1
DaemonSet
- DaemonSet 确保全部(或者某些)节点上运行一个 Pod 的副本。 当有节点加入集群时, 也会为他们新增一个 Pod 。 当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。
- DaemonSet保证在每个Node上都运行一个容器副本,常用来部署一些集群的日志、监控或者其他系统管理应用。
- 典型的应用包括:日志收集,比如 fluentd, logstash 等;系统监控,比如Prometheus Node Exporter, collectd,New Relic agent, Ganglia gmond 等;系统程序,比如 kube-proxy, kube-dns, glusterd, ceph等
如图:

配置文件
先创建个配置文件
mkdir /opt/k8s/daemonSet
cd /opt/k8s/daemonSet
vim fluentd.yaml
配置如下:
apiVersion: apps/v1
# 创建DaemonSet资源
kind: DaemonSet
metadata:
# 名字
name: fluentd
spec:
selector:
matchLabels:
app: logging
template:
metadata:
labels:
app: logging
id: fluentd
name: fluentd
spec:
containers:
- name: fluentd-es
image: agilestacks/fluentd-elasticsearch:v1.3.0
# 环境变量配置
env:
- name: FLUENTD_ARGS
value: -qq
# 加载数据卷,避免数据丢失
volumeMounts:
# 数据卷的名字
- name: containers
# 将数据卷挂载到容器内的哪个目录
mountPath: /var/lib/docker/containers
- name: varlog
mountPath: /varlog
# 定义数据卷
volumes:
# 数据卷类型,主机路径的模式,也就是与node共享目录
- hostPath:
# node中的共享目录
path: /var/lib/docker/containers
# 定义的数据卷的名称
name: containers
- hostPath:
path: /var/log
name: varlog创建
kubectl create -f fluentd.yaml
查看DaemonSet
kubectl get ds

再来
编辑一下
kubectl edit ds fluentd

在daemonset 配置中设置 nodeSelector
层级关系如下:
type:test是我们打的标签,只有存在这个标签的节点才能加入
spec: template: spec: nodeSelector: type: test

再去查看ds,就变成0了
kubectl get ds

我们给 Node 打上标签
kubectl label nodes node1 type=test
再去查看ds,就变成1了
kubectl get ds
如图,新加入符合的标签,可实时加入

更新
kubectl edit ds fluentd

默认使用RollingUpdate
不建议使用 RollingUpdate,建议使用 OnDelete 模式,这样避免频繁更新 ds
HorizontalPodAutoscaler
- HorizontalPodAutoscaler(简称 HPA ) 自动更新工作负载资源(例如 Deployment 或者 StatefulSet), 目的是自动扩缩工作负载以满足需求。
- 水平扩缩意味着对增加的负载的响应是部署更多的 Pod。 这与“垂直(Vertical)”扩缩不同,对于 Kubernetes, 垂直扩缩意味着将更多资源(例如:内存或 CPU)分配给已经为工作负载运行的 Pod。
- 如果负载减少,并且 Pod 的数量高于配置的最小值, HorizontalPodAutoscaler 会指示工作负载资源(Deployment、StatefulSet 或其他类似资源)缩减。
Pod 自动扩容:可以根据 CPU 使用率或自定义指标(metrics)自动对 Pod 进行扩/缩容。
- resources.requests.cpu
- resources.requests.memory

比如之前的nginx-deploy
执行,就是对nginx-deploy如果cp超过了20%,就最少部署2个,最大5个
kubectl autoscale deploy nginx-deploy --cpu-percent=20 --min=2 --max=5
此命令需要下载Metrics,下载可以参考我的博客:k8s-Metrics下载 – Dreams (tanjy.site)
kubectl top pods

开启了HPA,只要cpu达到要求,他就会扩容,cpu降下来后,就会缩容
获取 HPA 信息
kubectl get hpa

参考:
官网链接:Kubernetes
完整版Kubernetes(K8S)全套入门+微服务实战项目,带你一站式深入掌握K8S核心能力_哔哩哔哩_bilibili


