工作负载是运行在 Kubernetes 上的一个应用程序。
一个应用很复杂,可能由单个组件或者多个组件共同完成。无论怎样我们可以用一组Pod来表示一个应用,也就是一个工作负载
Pod又是一组容器(Containers)
所以关系又像是这样
工作负载(Workloads)控制一组Pod
Pod控制一组容器(Containers)
比如Deploy(工作负载) 3个副本的nginx(3个Pod),每个nginx里面是真正的nginx容器(container)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NiDWiolN-1657518906954)(images/Kubernetes/1619667328103.png)]
工作负载
能让Pod能拥有
自恢复能力。
会写Pod。研究不同的工作负载怎么控制Pod的行为
https://kubernetes.io/zh/docs/concepts/workloads/pods/
SideCar(为应用赋能)
**[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-stQ35xr3-1657518906955)(images/Kubernetes/1619667914671.png)]
编写yaml测试:多容器协同
vi pod-multicontainer.yaml
apiVersion: v1
kind: Pod
metadata:
name: "multi-container-pod"
namespace: default
labels:
app: "multi-container-pod"
spec:
volumes: ### 以后见到的所有名字 都应该是一个合法的域名方式
- name: nginx-vol
emptyDir: {} ### docker匿名挂载,外部创建一个位置 /abc
containers: ## kubectl exec -it podName -c nginx-container(容器名)-- /bin/sh
- name: nginx-container
image: "nginx"
volumeMounts: #声明卷挂载 -v
- name: nginx-vol
mountPath: /usr/share/nginx/html
- name: content-container
image: "alpine"
command: ["/bin/sh","-c","while true;do sleep 1; date > /app/index.html;done;"]
volumeMounts:
- name: nginx-vol
mountPath: /app
可以编写deploy等各种工作负载的yaml文件,最终创建出pod,也可以直接创建
Pod的模板如下
# 这里是 Pod 模版
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: hello
image: busybox
command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
restartPolicy: OnFailure
# 以上为 Pod 模版
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KVzZnYeX-1657518906955)(images/Kubernetes/1619669494854.png)]
NotReady
,Pod就不
对外提供服务了编写yaml测试生命周期
vi pod-lifecycle.yaml
- 应用容器生命周期钩子
- 初始化容器(也可以有钩子)
- 初始化容器
必须有终结的那个时刻
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6jbCvjHC-1657518906955)(images/Kubernetes-上/image-20211110222406101.png)]
apiVersion: v1
kind: Pod
metadata:
name: "pod-life-02"
namespace: default
labels:
app: "pod-life-02"
spec:
volumes:
- name: content-vol
emptyDir: {}
initContainers: ## Pod在启动containers之前,先要【运行完】initContainers的所有容器,所以这些容器必须有终结,不能一直运行
- name: init-c-01
image: alpine ### 必须有终结的那个时刻,一般不要用一直启动的镜像
command: ["/bin/sh","-c","echo 12222222 > /app/index.html;sleep 30;"]
volumeMounts:
- name: content-vol
mountPath: /app
# - name: init-c-02
# image: alpine ### 必须有终结的那个时刻,一般不要用一直启动的镜像
# command: ["/bin/sh","-c","echo 12222222 > /app/index.html;sleep 30;"]
# volumeMounts:
# - name: content-vol
# mountPath: /app
containers:
### docker run alpine 没有在后台一直启动的程序
- name: pod-life-01
image: "nginx" #默认的启动命令是启动nginx。nginx启动在后台一直有了
volumeMounts:
- name: content-vol
mountPath: /usr/share/nginx/html
- name: pod-life-02
image: "alpine" #pod里面的containers都必须能启动起来,Pod会不断的重启这个容器
command: ["/bin/sh","-c","sleep 30"]
临时容器
:线上排错。
https://kubernetes.io/zh/docs/concepts/workloads/pods/ephemeral-containers/
有些容器基础镜像(好多东西都没有,比如wget、vim)。线上没法排错。使用临时容器进入这个Pod。临时容器共享了Pod的所有。临时容器有Debug的一些命令,排错完成以后,只要exit退出容器,临时容器自动删除
Java:dump, jre 50mb。jdk 150mb
jre 50mb。:jdk作为临时容器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cWUE1Hlk-1657518906955)(images/Kubernetes-上/image-20211110224937656.png)]
https://kubernetes.io/zh/docs/tasks/debug-application-cluster/debug-running-pod/#ephemeral-container
临时容器需要开启特性门控 --feature-gates=“EphemeralContainers=true”
在所有组件,api-server、kubelet、scheduler、controller-manager都得配置
1.21.0: 生产环境推荐后缀是 .5
的版本
使用临时容器的步骤:
1、声明一个临时容器。准备好json文件
{
"apiVersion": "v1",
"kind": "EphemeralContainers",
"metadata": {
"name": "my-nginx666" //指定Pod的名字
},
"ephemeralContainers": [{
"command": [
"sh"
],
"image": "busybox", //jre的需要jdk来调试
"imagePullPolicy": "IfNotPresent",
"name": "debugger",
"stdin": true,
"tty": true,
"terminationMessagePolicy": "File"
}]
}
2、使用临时容器,应用一下即可
kubectl replace --raw /api/v1/namespaces/default/pods/my-nginx666【pod名】/ephemeralcontainers -f ec.json
在 /etc/kubernetes/manifests 位置放的所有Pod.yaml文件,机器启动kubelet自己就把他启动起来。
静态Pod一直守护在他的这个机器上
静态 Pod(Static Pod) 直接由特定节点上的 kubelet
守护进程管理, 不需要API 服务器看到它们。 尽管大多数 Pod 都是通过控制面(例如,Deployment) 来管理的,对于静态 Pod 而言,kubelet
直接监控每个 Pod,并在其失效时重启之。
静态 Pod 通常绑定到某个节点上的 kubelet。 其主要用途是运行自托管的控制面。 在自托管场景中,使用 kubelet
来管理各个独立的 控制面组件。
kubelet
自动尝试为每个静态 Pod 在 Kubernetes API 服务器上创建一个 镜像 Pod。 这意味着在节点上运行的 Pod 在 API 服务器上是可见的,但不可以通过 API 服务器来控制。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KpszlPT6-1657518906955)(images/Kubernetes-上/image-20211110153915251.png)]
https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes
kubectl explain pod.spec.containers.readinessProbe
每个容器三种探针(Probe)
启动探针(后来才加的) 一次性成功探针。 只要启动成功了
存活探针
如果检测失败就会重新启动这个容器
就绪探针
谁
利用这些探针探测
kubelet会主动按照配置给Pod里面的所有容器发送相应的探测请求
Probe配置项
initialDelaySeconds
:容器启动后要等待多少秒后存活和就绪探测器才被初始化,默认是 0 秒,最小值是 0。这是针对以前没有periodSeconds
:执行探测的时间间隔(单位是秒)。默认是 10 秒。最小值是 1。successThreshold
:探测器在失败后,被视为成功的最小连续成功数。默认值是 1。
failureThreshold
:当探测失败时,Kubernetes 的重试次数。 存活探测情况下的放弃就意味着重新启动容器。 就绪探测情况下的放弃 Pod 会被打上未就绪的标签。默认值是 3。最小值是 1。timeoutSeconds
:探测的超时后等待多少秒。默认值是 1 秒。最小值是 1。https://kubernetes.io/zh/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes
# 可以写下列字段
exec、httpGet、tcpSocket 【哪种方式探测】
failureThreshold # 失败阈值 连续几次失败才算真失败
initialDelaySeconds # 指定多少秒之后才执行探测
periodSeconds # 每隔几秒来运行这个
successThreshold # 成功阈值 连续几次成功才算成功
terminationGracePeriodSeconds
timeoutSeconds > # 探测超时时间 单位 秒 到了超时时间 还没返回结果说明失败
# 启动探针 vi start-probe.yaml
apiVersion: v1
kind: Pod
metadata:
name: "nginx-start-probe-test"
namespace: default
labels:
app: "nginx-start-probe-test"
spec:
volumes:
- name: nginx-vol
hostPath:
path: /app
containers:
- name: nginx
image: "nginx"
startupProbe:
exec:
command: ["/bin/sh","-c","cat /app/abc"] # 返回不是0,就是失败
initialDelaySeconds: 20 # 指定多少秒之后才执行探测
periodSeconds: 5 # 每隔几秒来运行这个
timeoutSeconds: 5 # 探测超时时间 单位 秒 到了超时时间 还没返回结果说明失败
successThreshold: 1 # 成功阈值 连续几次成功才算成功
failureThreshold: 3 # 失败阈值 连续几次失败才算真失败
volumeMounts:
- name: nginx-vol
mountPath: /app
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xzAqH2T8-1657518906956)(images/Kubernetes-上/image-20211111205147489.png)]
一直没有就绪
# 到运行pod的机器上 创建这个文件 touch /app/abc # 创建完后等待下一次探测就成功了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DCiRz7qS-1657518906956)(images/Kubernetes-上/image-20211111205836369.png)]
# 存活探针 vi liveness-probe.yaml
apiVersion: v1
kind: Pod
metadata:
name: "nginx-start-probe02"
namespace: default
labels:
app: "nginx-start-probe02"
spec:
volumes:
- name: nginx-vol
hostPath:
path: /app
- name: nginx-html
hostPath:
path: /html
containers:
- name: nginx
image: "nginx"
startupProbe:
exec:
command: ["/bin/sh","-c","cat /app/abc"] # 返回不是0,就是失败
initialDelaySeconds: 20 # 指定多少秒之后才执行探测
periodSeconds: 5 # 每隔几秒来运行这个
timeoutSeconds: 5 # 探测超时时间 单位 秒 到了超时时间 还没返回结果说明失败
successThreshold: 1 # 成功阈值 连续几次成功才算成功
failureThreshold: 3 # 失败阈值 连续几次失败才算真失败
volumeMounts:
- name: nginx-vol
mountPath: /app
- name: nginx-html
mountPath: /usr/share/nginx/html
livenessProbe: # nginx容器有没有 /abc.html,就绪探针
# httpGet:
# host: 127.0.0.1
# path: /abc.html
# port: 80
# scheme: HTTP
# periodSeconds: 5 ## 每隔几秒来运行这个
# successThreshold: 1 ## 成功阈值,连续几次成才算成功
# failureThreshold: 5 ## 失败阈值,连续几次失败才算真失败
exec:
command: ["/bin/sh","-c","cat /usr/share/nginx/html/abc.html"] ## 返回不是0,那就是探测失败
# initialDelaySeconds: 20 ## 指定的这个秒以后才执行探测
periodSeconds: 5 ## 每隔几秒来运行这个
timeoutSeconds: 5 ##探测超时,到了超时时间探测还没返回结果说明失败
successThreshold: 1 ## 成功阈值,连续几次成才算成功
failureThreshold: 3 ## 失败阈值,连续几次失败才算真失败
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ponjd8Gu-1657518906956)(images/Kubernetes-上/image-20211111211444928.png)]
到运行pod的机器上 创建这个文件
touch /html/abc.html
创建完后等待下一次探测就成功了
# 存活探针 vi pod-liveness.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 18; rm -rf /tmp/healthy; sleep 600
# 创建一个文件;睡30s;文件又删除,睡600秒
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5 #容器启动RUNNING 5秒以后再来探测
periodSeconds: 5 #每隔5秒探测一次
# vi pod-probe.yaml
apiVersion: v1
kind: Pod
metadata:
name: "nginx-start-probe02"
namespace: default
labels:
app: "nginx-start-probe02"
spec:
volumes:
- name: nginx-vol
hostPath:
path: /app
- name: nginx-html
hostPath:
path: /html
containers:
- name: nginx
image: "nginx"
ports:
- containerPort: 80
startupProbe:
exec:
command: ["/bin/sh","-c","cat /app/abc"] ## 返回不是0,那就是探测失败
# initialDelaySeconds: 20 ## 指定的这个秒以后才执行探测
periodSeconds: 5 ## 每隔几秒来运行这个
timeoutSeconds: 5 ##探测超时,到了超时时间探测还没返回结果说明失败
successThreshold: 1 ## 成功阈值,连续几次成才算成功
failureThreshold: 3 ## 失败阈值,连续几次失败才算真失败
volumeMounts:
- name: nginx-vol
mountPath: /app
- name: nginx-html
mountPath: /usr/share/nginx/html
livenessProbe: ## nginx容器有没有 /abc.html,就绪探针
# httpGet:
# host: 127.0.0.1
# path: /abc.html
# port: 80
# scheme: HTTP
# periodSeconds: 5 ## 每隔几秒来运行这个
# successThreshold: 1 ## 成功阈值,连续几次成才算成功
# failureThreshold: 5 ## 失败阈值,连续几次失败才算真失败
exec:
command: ["/bin/sh","-c","cat /usr/share/nginx/html/abc.html"] ## 返回不是0,那就是探测失败
# initialDelaySeconds: 20 ## 指定的这个秒以后才执行探测
periodSeconds: 5 ## 每隔几秒来运行这个
timeoutSeconds: 5 ##探测超时,到了超时时间探测还没返回结果说明失败
successThreshold: 1 ## 成功阈值,连续几次成才算成功
failureThreshold: 3 ## 失败阈值,连续几次失败才算真失败
readinessProbe: ##就绪检测,都是http
httpGet:
# host: 127.0.0.1 ###不行 因为就绪探针没成功 所以容器起不来 就访问不了 如果自己另外起一个容器可以 host本机 可以不写
path: /abc.html ## 给容器发请求
port: 80
scheme: HTTP ## 返回不是0,那就是探测失败
initialDelaySeconds: 2 ## 指定的这个秒以后才执行探测
periodSeconds: 5 ## 每隔几秒来运行这个
timeoutSeconds: 5 ##探测超时,到了超时时间探测还没返回结果说明失败
successThreshold: 3 ## 成功阈值,连续几次成才算成功
failureThreshold: 5 ## 失败阈值,连续几次失败才算真失败
# livenessProbe:
# exec: ["/bin/sh","-c","sleep 30;abc "] ## 返回不是0,那就是探测失败
# initialDelaySeconds: 20 ## 指定的这个秒以后才执行探测
# periodSeconds: 5 ## 每隔几秒来运行这个
# timeoutSeconds: 5 ##探测超时,到了超时时间探测还没返回结果说明失败
# successThreshold: 5 ## 成功阈值,连续几次成才算成功
# failureThreshold: 5 ## 失败阈值,连续几次失败才算真失败
微服务。 /health
K8S检查当前应用的状态;connection refuse;
SpringBoot 优雅停机:gracefulShowdown: true
pod.spec.terminationGracePeriodSeconds = 30s 优雅停机;给一个缓冲时间
健康检查 + 优雅停机 = 0宕机
start完成以后,liveness和readness并存。 liveness失败导致重启。readness失败导致不给Service负载均衡网络中加,不接受流量。 kubectl exec -it 就进不去。Kubectl describe 看看咋了。
https://kubernetes.io/zh/docs/concepts/workloads/controllers/deployment/
# Deployment:
# 滚动更新: 10 2 - 8 4 , 2 4 0 - 10
# RS1 RS2 两个版本同时存在
minReadySeconds: 10 这个Pod10s以后才认为是read状态,影响多久后杀死旧Pod
paused : false 当前是否停止状态,暂停更新
progressDeadlineSeconds: 600 处理的最终期限,Deployment如果超过了这个指定的处理描述就会给集群汇报错误
The maximum time in seconds for a deployment to make progress before it is
considered to be failed. The deployment controller will continue to process
failed deployments and a condition with a ProgressDeadlineExceeded reason
will be surfaced in the deployment status. Note that progress will not be
estimated during the time a deployment is paused. Defaults to 600s.
replicas : Pod 期望的数量(副本数量),是 ReplicaSet 控制器实现的
revisionHistoryLimit : 旧副本集保留的数量,可回滚的数量,默认是10
selector : 指定我们Deployment要控制的所有的Pod的共通标签
strategy : 指定新Pod替换旧Pod的策略
rollingUpdate : 指定滚动更新策略
maxSurge 【最大增量】 : 2 一次最多新建几个Pod。 百分比和数字都可以
MaxUnavailable:为0 的时候, maxSurge不能为0
maxUnavailable【最大不可用量】: 4 最大不可用的Pod数量
type : Recreate/RollingUpdate(默认)
template : 编写Pod
# Deployment:
# 滚动更新: 10 2 - 8 4 , 2 4 0 - 10
# RS1 RS2 两个版本同时存在
minReadySeconds: 10 这个Pod10s以后才认为是read状态,影响多久后杀死旧Pod
paused : false 当前是否停止状态,暂停更新
progressDeadlineSeconds: 600 处理的最终期限,Deployment如果超过了这个指定的处理描述就会给集群汇报错误
The maximum time in seconds for a deployment to make progress before it is
considered to be failed. The deployment controller will continue to process
failed deployments and a condition with a ProgressDeadlineExceeded reason
will be surfaced in the deployment status. Note that progress will not be
estimated during the time a deployment is paused. Defaults to 600s.
replicas : Pod 期望的数量(副本数量),是 ReplicaSet 控制器实现的
revisionHistoryLimit : 旧副本集保留的数量,可回滚的数量,默认是10
selector : 指定我们Deployment要控制的所有的Pod的共通标签
strategy : 指定新Pod替换旧Pod的策略
rollingUpdate : 指定滚动更新策略
maxSurge 【最大增量】 : 2 一次最多新建几个Pod。 百分比和数字都可以
MaxUnavailable:为0 的时候, maxSurge不能为0
maxUnavailable【最大不可用量】: 4 最大不可用的Pod数量
type : Recreate/RollingUpdate(默认)
template : 编写Pod
.metadata.name
指定deploy名字replicas
指定副本数量selector
指定匹配的Pod模板。template
声明一个Pod模板编写一个Deployment的yaml
赋予Pod
自愈
和故障转移
能力。
在检查集群中的 Deployment 时,所显示的字段有:
NAME
列出了集群中 Deployment 的名称。READY
显示应用程序的可用的 副本 数。显示的模式是“就绪个数/期望个数”。UP-TO-DATE
显示为了达到期望状态已经更新的副本数。AVAILABLE
显示应用可供用户使用的副本数。AGE
显示应用程序运行的时间。ReplicaSet 输出中包含以下字段:
NAME
列出名字空间中 ReplicaSet 的名称;DESIRED
显示应用的期望副本个数,即在创建 Deployment 时所定义的值。 此为期望状态;CURRENT
显示当前运行状态中的副本个数;READY
显示应用中有多少副本可以为用户提供服务;AGE
显示应用已经运行的时间长度。[Deployment名称]-[随机字符串]
。 其中的随机字符串是使用 pod-template-hash 作为种子随机生成的。一个Deploy产生三个
- Deployment资源
- replicaset资源
- Pod资源
Deployment控制RS,RS控制Pod的副本数
ReplicaSet: 只提供了副本数量的控制功能
Deployment: 每部署一个新版本就会创建一个新的副本集,利用他记录状态,回滚也是直接让指定的rs生效
— rs1: 4 abc
— rs2: 4 def
— rsN: 4 eee
nginx=111 nginx:v1=2222 nginx:v2=3333
仅当 Deployment Pod 模板(即 .spec.template
)发生改变时,例如模板的标签或容器镜像被更新, 才会触发 Deployment 上线。 其他更新(如对 Deployment 执行扩缩容的操作)不会触发上线动作。
上线动作 原理: 创建新的rs,准备就绪后,替换旧的rs(此时不会删除,因为revisionHistoryLimit
指定了保留几个版本)
常用的kubectl 命令
################更新#################################
#kubectl set image deployment资源名 容器名=镜像名
# --record 记录变更
kubectl set image deployment.apps/nginx-deployment php-redis=tomcat:8 --record
## yaml提取可更新的关键所有字段计算的hash。
#或者直接修改定义也行
kubectl edit deployment.v1.apps/nginx-deployment
#查看状态
kubectl rollout status deployment.v1.apps/nginx-deployment
################查看历史并回滚####################################
#查看更新历史-看看我们设置的历史总记录数是否生效了
kubectl rollout history deployment.v1.apps/nginx-deployment
#回滚
kubectl rollout undo deployment.v1.apps/nginx-deployment --to-revision=2
###############累计更新##############
#暂停记录版本
kubectl rollout pause deployment.v1.apps/nginx-deployment
#多次更新操作。
##比如更新了资源限制
kubectl set resources deployment.v1.apps/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
##比如更新了镜像版本
kubectl set image deployment.apps/nginx-deployment php-redis=tomcat:8
##在继续操作多次
##看看历史版本有没有记录变化
kubectl rollout history deployment.v1.apps/nginx-deployment
#让多次累计生效
kubectl rollout resume deployment.v1.apps/nginx-deployment
apiVersion: apps/v1 ###
kind: Deployment ##
metadata:
name: mydeploy-03 ### 遵循域名命名编写规范
namespace: default
labels:
dep: test-02
### 期望状态
spec:
paused: false ## 就是 kubectl rollout pause/resume 功能
progressDeadlineSeconds: 600 ##
revisionHistoryLimit: 15 ### 保留最近的15个版本。 /etcd
selector: ### 选择器,会被RS控制
matchLabels: ### 匹配标签
pod-name: aaaa ### 和模板template里面的pod的标签必须一样
####
template:
metadata: ### pod的metadata
labels:
pod-name: aaaa
spec:
containers:
- name: nginx-01
image: nginx
maxSurge(最大增量):除当前数量外还要添加多少个实例。
maxUnavailable(最大不可用量):滚动更新过程中的不可用实例数。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2PMHIDrM-1657518906956)(images/Kubernetes/5bddc931-ramped.gif)]
apiVersion: apps/v1 ###
kind: Deployment ##
metadata:
name: mydeploy-05 ### 遵循域名编写规范
namespace: default
labels:
dep: test-04
### 期望状态
spec:
strategy:
# type: Recreate ### 把以前全部杀死,直接新建
type: RollingUpdate
rollingUpdate:
maxUnavailable: 2
maxSurge: 20%
replicas: 10
selector: ### 选择器
matchLabels: ### 匹配标签
pod-name: aaa55566 ### 和模板template里面的pod的标签必须一样
####
template:
metadata: ### pod的metadata
labels:
pod-name: aaa55566
spec:
containers:
- name: nginx-01
image: nginx
概念:https://kubernetes.io/zh/docs/tasks/run-application/horizontal-pod-autoscale/#scaling-policies
实战:https://kubernetes.io/zh/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IagWQ6aa-1657518906956)(images/Kubernetes/horizontal-pod-autoscaler.svg)]
https://github.com/kubernetes-sigs/metrics-server
安装步骤
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
- --secure-port=4443
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --kubelet-use-node-status-port
image: registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/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
kubectl apply 即可、
全部runnning 用
配置hpa测试
FROM php:5-apache
COPY index.php /var/www/html/index.php
RUN chmod a+rx index.php
$x = 0.0001;
for ($i = 0; $i <= 1000000; $i++) {
$x += sqrt($x);
}
echo "OK!";
?>
### 测试镜像 registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/php-hpa:latest
##应用的yaml已经做好
apiVersion: v1
kind: Service
metadata:
name: php-apache
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
run: php-apache
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
run: php-apache
name: php-apache
spec:
replicas: 1
selector:
matchLabels:
run: php-apache
template:
metadata:
creationTimestamp: null
labels:
run: php-apache
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/php-hpa:latest
name: php-apache
ports:
- containerPort: 80
resources:
requests:
cpu: 200m
##hpa配置 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 # cpu使用率 % 低于缩容
#3、进行压力测试
kubectl run -i --tty load-generator --image=busybox /bin/sh
#回车然后敲下面的命令
kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"
蓝绿部署
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-evp5Ifji-1657518906956)(images/Kubernetes/a6324354-canary.gif)]
金丝雀部署
矿场。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bAqmJYwQ-1657518906957)(images/Kubernetes/a6324354-canary-1619679814751.gif)]
#### 使用这个镜像测试registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/nginx-test#### 这个镜像docker run 的时候 -e msg=aaaa,访问这个nginx页面就是看到aaaa
步骤原理
准备一个Service,负载均衡Pod
apiVersion: v1
kind: Service
metadata:
name: canary-test
namespace: default
spec:
selector:
app: canary-nginx
type: NodePort ### 浏览器可以直接访问
ports:
- name: canary-test
port: 80 ###
targetPort: 80 ### Pod的访问端口
protocol: TCP
nodePort: 31666 ### 机器上开的端口,浏览器访问
准备版本v1的deploy,准备版本v2的deploy
滚动发布的缺点
?(同时存在两个版本都能接受流量)
没法控制流量 ; 6 4, 8 2 ,3 7
滚动发布短时间就直接结束,不能直接控制新老版本的存活时间。
用两个镜像:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LxJItZ4J-1657518906957)(images/Kubernetes-上/image-20211115223655084.png)]
apiVersion: apps/v1
kind: Deployment
metadata:
name: canary-dep-v1
namespace: default
labels:
app: canary-dep-v1
spec:
selector:
matchLabels:
app: canary-nginx
v: v111
replicas: 2
template:
metadata:
labels:
app: canary-nginx
v: v111
spec:
# initContainers:
# Init containers are exactly like regular containers, except:
# - Init containers always run to completion.
# - Each init container must complete successfully before the next one starts.
containers:
- name: nginx
image: registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/nginx-test:env-msg
apiVersion: apps/v1
kind: Deployment
metadata:
name: canary-dep-v2
namespace: default
labels:
app: canary-dep-v2
spec:
selector:
matchLabels:
app: canary-nginx
v: v222
replicas: 1
template:
metadata:
labels:
app: canary-nginx
v: v222
spec:
# initContainers:
# Init containers are exactly like regular containers, except:
# - Init containers always run to completion.
# - Each init container must complete successfully before the next one starts.
containers:
- name: nginx
image: nginx
https://kubernetes.io/zh/docs/concepts/workloads/controllers/deployment/#deployment-status
kubectl describe 描述一个资源(Pod、Service、Node、Deployment)来进行排错
Condittions以及Events需要注意
https://kubernetes.io/zh/docs/concepts/workloads/controllers/replicaset/
RC: ReplicasController:副本控制器
RS:ReplicasSet:副本集;Deployment【滚动更新特性】默认控制的是他
RC是老版,RS是新版(可以有复杂的选择器【表达式】)。
kubectl explain rs.spec.selector
## RS支持复杂选择器
matchExpressions:
- key: pod-name
value: [aaaa,bbb]
# In, NotIn, Exists and DoesNotExist
# In: value: [aaaa,bbb]必须存在,表示key指定的标签的值是这个集合内的
# NotIn value: [aaaa,bbb]必须存在,表示key指定的标签的值不是这个集合内的
# Exists # 只要有key指定的标签即可,不用管值是多少
# DoesNotExist # 只要Pod上没有key指定的标签,不用管值是多少
operator: DoesNotExist
虽然ReplicasSet强大,但是我们也不直接写RS;都是直接写Deployment的,Deployment会自动产生RS。
Deployment每次的滚动更新都会产生新的RS。
https://kubernetes.io/zh/docs/concepts/workloads/controllers/daemonset/
k8s集群的每个机器(每一个节点)都运行一个程序(默认master除外,master节点默认不会把Pod调度过去)
无需指定副本数量;因为默认给每个机器都部署一个(master除外)
DaemonSet 控制器确保所有(或一部分)的节点都运行了一个指定的 Pod 副本。
DaemonSet 的典型使用场景有:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: logging
labels:
app: logging
spec:
selector:
matchLabels:
name: logging
template:
metadata:
labels:
name: logging
spec:
containers:
- name: logging
image: nginx
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
tolerations: #设置容忍master的污点
- key: node-role.kubernetes.io/master
effect: NoSchedule
#查看效果
kubectl get pod -l name=logging -o wide
https://kubernetes.io/zh/docs/concepts/workloads/controllers/statefulset/
Deployment部署的应用我们一般称为无状态应用
StatefulSet部署的应用我们一般称为有状态应用
无状态应用:网络可能会变,存储可能会变,顺序可能会变。场景就是业务代码(Deployment)
有状态应用:网络不变,存储不变,顺序不变。场景就是中间件(MySQL、Redis、MQ)
有状态副本集;Deployment等属于无状态的应用部署(stateless)
StatefulSet 使用场景;对于有如下要求的应用程序,StatefulSet 非常适用:
限制
storage class
来提供,或者由管理员预先提供。OrderedReady
) 时使用 滚动更新,可能进入需要人工干预 才能修复的损坏状态。如果一个应用程序不需要稳定的网络标识,或者不需要按顺序部署、删除、增加副本,就应该考虑使用 Deployment 这类无状态(stateless)的控制器
apiVersion: apps/v1
kind: StatefulSet ### 有状态副本集
metadata:
name: stateful-nginx
namespace: default
spec:
selector:
matchLabels:
app: ss-nginx # has to match .spec.template.metadata.labels
serviceName: "nginx" ## 服务名,指定加到那个service里面
replicas: 3 # 三个副本
template: ## Pod模板
metadata:
labels:
app: ss-nginx # has to match .spec.selector.matchLabels
spec:
containers:
- name: nginx
image: nginx
---
## 加网络
apiVersion: v1
kind: Service
metadata:
name: nginx ## 和上面的serviceName
namespace: default
spec:
selector:
app: ss-nginx
clusterIP: None ## 不要分配ClusterIP,headless service,整个集群的Pod能直接访问
# 浏览器目前不能访问,mysql、mq。继续使用ingress网络定义所有的访问逻辑
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 80
apiVersion: v1
kind: Service #定义一个负载均衡网络
metadata:
name: stateful-tomcat
labels:
app: stateful-tomcat
spec:
ports:
- port: 8123
name: web
targetPort: 8080
clusterIP: None #NodePort:任意机器+NodePort都能访问,ClusterIP:集群内能用这个ip、service域名能访问,clusterIP: None;不要分配集群ip。headless;无头服务。稳定的域名
selector:
app: stateful-tomcat
---
apiVersion: apps/v1
kind: StatefulSet #控制器。
metadata:
name: stateful-tomcat
spec:
selector:
matchLabels:
app: stateful-tomcat # has to match .spec.template.metadata.labels
serviceName: "stateful-tomcat" #这里一定注意,必须提前有个service名字叫这个的
replicas: 3 # by default is 1
template:
metadata:
labels:
app: stateful-tomcat # has to match .spec.selector.matchLabels
spec:
terminationGracePeriodSeconds: 10
containers:
- name: tomcat
image: tomcat:7
ports:
- containerPort: 8080
name: web
#观察效果。
删除一个,重启后名字,ip等都是一样的。保证了状态
#细节
kubectl explain StatefulSet.spec
podManagementPolicy:
OrderedReady(按序)、Parallel(并发)
serviceName -required-
设置服务名,就可以用域名访问pod了。
pod-specific-string.serviceName.default.svc.cluster.local
#测试
kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh
ping stateful-tomcat-0.stateful-tomcat
#我们在这里没有加存储卷。如果有的话 kubectl get pvc -l app=stateful-tomcat 我们就能看到即使Pod删了再拉起,卷还是同样的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OVBotHO6-1657518906957)(images/Kubernetes-上/image-20211120173421096.png)]
DNS解析。整个状态kubelet(DNS内容同步到Pod)和kube-proxy(整个集群网络负责)会同步
curl nginx-svc: 负载均衡到sts部署的Pod上
curl mysql-0.nginx-svc: 直接访问指定Pod
podManagementPolicy : 控制Pod创建、升级以及扩缩容逻辑
podManagementPolicy controls how pods are created during initial scale up,
when replacing pods on nodes, or when scaling down. The default policy is
OrderedReady
, where pods are created in increasing order (pod-0, then
pod-1, etc) and the controller will wait until each pod is ready before
continuing. When scaling down, the pods are removed in the opposite order.
The alternative policy is Parallel
which will create pods in parallel to
match the desired scale without waiting, and on scale down will delete all
pods at once.
默认是 OrderedReady
: 有序启动
修改为 Parallel
: 同时创建启动,一般不用
updateStrategy
updateStrategy indicates the StatefulSetUpdateStrategy that will be employed to update Pods in the StatefulSet when a revision is made to Template.
实验:
先部署一个sts
apiVersion: apps/v1
kind: StatefulSet ### 有状态副本集
metadata:
name: stateful-nginx
namespace: default
spec:
selector:
matchLabels:
app: ss-nginx # has to match .spec.template.metadata.labels
serviceName: "nginx" ## 服务名,指定加到那个service里面
replicas: 3 # 三个副本
template: ## Pod模板
metadata:
labels:
app: ss-nginx # has to match .spec.selector.matchLabels
spec:
containers:
- name: nginx
image: nginx
在进行分区升级
apiVersion: apps/v1
kind: StatefulSet ### 有状态副本集
metadata:
name: stateful-nginx
namespace: default
spec:
podManagementPolicy: OrderedReady ## 所有pod一起创建,OrderedReady:有序创建
updateStrategy: ## 升级策略
rollingUpdate:
partition: 1 ## 更新大于等于这个索引的pod
selector:
matchLabels:
app: ss-nginx # has to match .spec.template.metadata.labels
serviceName: "nginx" ## 服务名,指定加到那个service里面
replicas: 3 # 三个副本
template: ## Pod模板
metadata:
labels:
app: ss-nginx # has to match .spec.selector.matchLabels
spec:
containers:
- name: nginx
image: nginx:1.20.1 ## 默认第三个(最后一个)开始有序升级
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql-cluster
namespace: default
spec:
serviceName: mysql # 一定指定StatefulSet的serviceName
selector:
matchLabels:
app: mysql
replicas: 2 # by default is 1 。默认也是负载均衡
### 自己连进这两个mysql。才能主从同步
template:
metadata:
labels:
app: mysql # has to match .spec.selector.matchLabels
spec:
terminationGracePeriodSeconds: 10
containers:
- name: mysql
image: mysql:8.0.25
securityContext: ## 指定安全上下文
runAsUser: 1000
runAsGroup: 1000
ports:
- containerPort: 3306
name: mysql-port
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456"
- name: MYSQL_DATABASE
value: "db_test"
volumeMounts:
- name: mysql-cnf
mountPath: /etc/mysql/conf.d
- name: mysql-data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: mysql-cnf
spec:
storageClassName: "managed-nfs-storage"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
- metadata:
name: mysql-data
spec:
storageClassName: "managed-nfs-storage"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
name: mysql
namespace: default
spec:
selector:
app: mysql
type: NodePort
# type: ClusterIP
# clusterIP: None ## 没有集群ip,只能通过内部的dns访问 mysql-cluster-0.mysql.default
ports:
- name: mysql-port
port: 3306 ## service端口
targetPort: 3306 ## pod端口
protocol: TCP
# ---
# apiVersion: v1
# kind: PersistentVolumeClaim
# metadata:
# name: hahah
# namespace: default
# labels:
# app: hahah
# spec:
# storageClassName: "managed-nfs-storage"
# accessModes:
# - ReadWriteOnce
# resources:
# requests:
# storage: 1Gi
Kubernetes中的 Job 对象将创建一个或多个 Pod,并确保指定数量的 Pod 可以成功执行到进程正常结束:
# 错误写法 image不要用阻塞式的
apiVersion: batch/v1
kind: Job
metadata:
name: job-test
spec:
completions: 4 ## 前一次必须结束才会下一次
template:
spec:
containers:
- name: pi
image: nginx ## job类型的pod,不要用阻塞式的。如nginx。Deployment才应该是阻塞式的
restartPolicy: Never #Job情况下,不支持Always
apiVersion: batch/v1
kind: Job
metadata:
name: job-test-02
spec:
completions: 5 ## 前一次必须结束才会下一次
parallelism: 3
template:
spec:
containers:
- name: pi
image: busybox ## job类型的pod,不要用阻塞式的。如nginx。Deployment才应该是阻塞式的
command: ["/bin/sh","-c","ping -c 10 baidu.com"]
restartPolicy: Never #Job情况下,不支持Always
# backoffLimit: 4 #任务4次都没成,认为失败
activeDeadlineSeconds: 600 ## 整个Job的存活时间,超出就自动杀死
ttlSecondsAfterFinished: 10 ### 运行完成后自己删除
#默认这个任务需要成功执行一次。
#查看job情况
kubectl get job
#修改下面参数设置再试试
#千万不要用阻塞容器。nginx。job由于Pod一直running状态。下一个永远得不到执行,而且超时了,当前running的Pod还会删掉
kubectl api-resources
#参数说明
kubectl explain job.spec
activeDeadlineSeconds:10 总共维持10s
#该字段限定了 Job 对象在集群中的存活时长,一旦达到 .spec.activeDeadlineSeconds 指定的时长,该 Job 创建的所有的 Pod 都将被终止。但是Job不会删除,Job需要手动删除,或者使用ttl进行清理
backoffLimit:
#设定 Job 最大的重试次数。该字段的默认值为 6;一旦重试次数达到了 backoffLimit 中的值,Job 将被标记为失败,且尤其创建的所有 Pod 将被终止;
completions: #Job结束需要成功运行的Pods。默认为1
manualSelector:
parallelism: #并行运行的Pod个数,默认为1
ttlSecondsAfterFinished:
ttlSecondsAfterFinished: 0 #在job执行完时马上删除
ttlSecondsAfterFinished: 100 #在job执行完后,等待100s再删除
#除了 CronJob 之外,TTL 机制是另外一种自动清理已结束Job(Completed 或 Finished)的方式:
#TTL 机制由 TTL 控制器 提供,ttlSecondsAfterFinished 字段可激活该特性
#当 TTL 控制器清理 Job 时,TTL 控制器将删除 Job 对象,以及由该 Job 创建的所有 Pod 对象。
# job超时以后 已经完成的不删,正在运行的Pod就删除
#单个Pod时,Pod成功运行,Job就结束了
#如果Job中定义了多个容器,则Job的状态将根据所有容器的执行状态来变化。
#Job任务不建议去运行nginx,tomcat,mysql等阻塞式的,否则这些任务永远完不了。
##如果Job定义的容器中存在http server、mysql等长期的容器和一些批处理容器,则Job状态不会发生变化(因为长期运行的容器不会主动结束)。此时可以通过Pod的.status.containerStatuses获取指定容器的运行状态。
manualSelector:
https://kubernetes.io/zh/docs/concepts/workloads/controllers/cron-jobs/
CronJob 按照预定的时间计划(schedule)创建 Job(注意:启动的是Job不是Deploy,rs)。一个 CronJob 对象类似于 crontab (cron table) 文件中的一行记录。该对象根据 Cron 格式定义的时间计划,周期性地创建 Job 对象。
Schedule
所有 CronJob 的
schedule
中所定义的时间,都是基于 master 所在时区来进行计算的。
一个 CronJob 在时间计划中的每次执行时刻,都创建 大约 一个 Job 对象。这里用到了 大约 ,是因为在少数情况下会创建两个 Job 对象,或者不创建 Job 对象。尽管 K8S 尽最大的可能性避免这种情况的出现,但是并不能完全杜绝此现象的发生。因此,Job 程序必须是 幂等的。
当以下两个条件都满足时,Job 将至少运行一次:
startingDeadlineSeconds
被设置为一个较大的值,或者不设置该值(默认值将被采纳)concurrencyPolicy
被设置为 Allow
# kubectl explain cronjob.spec
concurrencyPolicy:并发策略
"Allow" (允许,default):
"Forbid"(禁止): forbids;前个任务没执行完,要并发下一个的话,下一个会被跳过
"Replace"(替换): 新任务,替换当前运行的任务
failedJobsHistoryLimit:记录失败数的上限,Defaults to 1.
successfulJobsHistoryLimit: 记录成功任务的上限。 Defaults to 3.
#指定了 CronJob 应该保留多少个 completed 和 failed 的 Job 记录。将其设置为 0,则 CronJob 不会保留已经结束的 Job 的记录。
jobTemplate: job怎么定义(与前面我们说的job一样定义法)
schedule: cron 表达式;
startingDeadlineSeconds: 表示如果Job因为某种原因无法按调度准时启动,在spec.startingDeadlineSeconds时间段之内,CronJob仍然试图重新启动Job,如果在.spec.startingDeadlineSeconds时间之内没有启动成功,则不再试图重新启动。如果spec.startingDeadlineSeconds的值没有设置,则没有按时启动的任务不会被尝试重新启动。
suspend 暂停定时任务,对已经执行了的任务,不会生效; Defaults to false.
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *" #分、时、日、月、周
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
args:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
https://kubernetes.io/zh/docs/concepts/workloads/controllers/ttlafterfinished/
这是alpha版本
这个特性现在在v1.12版本是alpha阶段,而且默认关闭的,需要手动开启。
- --feature-gates=TTLAfterFinished=true
命令,然后重启对应的pod即可。例如修改后的kube-scheduler.yaml的spec部分如下,kube-apiserver.yaml和kube-controller-manager.yaml也在spec部分加入- --feature-gates=TTLAfterFinished=true即可。
Kubernetes garbage collector(垃圾回收器)的作用是删除那些曾经有 owner,后来又不再有 owner 的对象。描述
垃圾收集器如何删除从属对象
当删除某个对象时,可以指定该对象的从属对象是否同时被自动删除,这种操作叫做级联删除(cascading deletion)。级联删除有两种模式:后台(background)和前台(foreground)
如果删除对象时不删除自动删除其从属对象,此时,从属对象被认为是孤儿(或孤立的 orphaned)
通过参数 --cascade
,kubectl delete 命令也可以选择不同的级联删除策略:
#删除rs,但不删除级联Podkubectl delete replicaset my-repset --cascade=false
更多详细内容