pod
之前我们创建过pod,就是nginx,但是是基于原由的创建,我们可以基于配置文件来创建pod。
配置文件
apiVersion: v1 # api 文档版本
kind: Pod # 资源对象类型,也可以配置为像Deployment、StatefulSet这一类的对象
metadata: # Pod 相关的元数据,用于描述 Pod 的数据
name: nginx-demo # Pod 的名称
labels: # 定义 Pod 的标签
type: app # 自定义 label 标签,名字为 type,值为 app
test: 1.0.0 # 自定义 label 标签,描述 Pod 版本号
namespace: 'default' # 命名空间的配置
spec: # 期望 Pod 按照这里面的描述进行创建
containers: # 对于 Pod 中的容器描述
- name: nginx # 容器的名称
image: nginx:1.7.9 # 指定容器的镜像
imagePullPolicy: IfNotPresent # 镜像拉取策略,指定如果本地有就用本地的,如果没有就拉取远程的
command: # 指定容器启动时执行的命令
- nginx
- -g
- 'daemon off;' # nginx -g 'daemon off;'
workingDir: /usr/share/nginx/html # 定义容器启动后的工作目录
ports:
- name: http # 端口名称
containerPort: 80 # 描述容器内要暴露什么端口
protocol: TCP # 描述该端口是基于哪种协议通信的
- env: # 环境变量
name: JVM_OPTS # 环境变量名称
value: '-Xms128m -Xmx128m' # 环境变量的值
reousrces:
requests: # 最少需要多少资源
cpu: 100m # 限制 cpu 最少使用 0.1 个核心
memory: 128Mi # 限制内存最少使用 128兆
limits: # 最多可以用多少资源
cpu: 200m # 限制 cpu 最多使用 0.2 个核心
memory: 256Mi # 限制 最多使用 256兆
restartPolicy: OnFailure # 重启策略,只有失败的情况才会重启
执行yaml
-rw-r--r-- 1 root root 694 Jan 27 15:17 nginx-demo.yaml
[root@k8s-master pods]# kubectl create -f nginx-demo.yaml
pod/nginx-demo created
[root@k8s-master pods]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-demo 1/1 Running 0
探针
容器内应用的监测机制,根据不同的探针来判断容器应用当前的状态,比如pod中那个容器宕机了,是根据什么机制、策略来重启容器呢?
类型
目前探针有三种类型:StartupProbe、LivenessProbe、ReadlinessProbe。
StartupProbe
k8s 1.16 版本新增的探针,用于判断应用程序是否已经启动了。
当配置了 startupProbe 后,会先禁用其他探针,直到 startupProbe 成功后,其他探针才会继续。
作用:由于有时候不能准确预估应用一定是多长时间启动成功,因此配置另外两种方式不方便配置初始化时长来检测,而配置了 statupProbe 后,只有在应用启动成功了,才会执行另外两种探针,可以更加方便的结合使用另外两种探针使用。
startupProbe: httpGet: path: /api/startup port: 80
LivenessProbe
用于探测容器中的应用是否运行,如果探测失败,kubelet 会根据配置的重启策略进行重启,若没有配置,默认就认为容器启动成功,不会执行重启策略。
livenessProbe: failureThreshold: 5 httpGet: path: /health port: 8080 scheme: HTTP initialDelaySeconds: 60 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 5
ReadlinessProbe
用于探测容器内的程序是否健康,它的返回值如果返回 success,那么就认为该容器已经完全启动,并且该容器是可以接收外部流量的。
readinessProbe: failureThreshold: 3 # 错误次数 httpGet: path: /ready port: 8181 scheme: HTTP periodSeconds: 10 # 间隔时间 successThreshold: 1 timeoutSeconds: 1
生命周期
我们看如下示意图:
- 容器环境初始化好之后,才会正式的进入到生命周期之内,初始化包括下载镜像、exec等等。
- 第一个到达初始化阶段,是由专门的初始化容器来做的操作,可能有0个或者多个初始化容器。
- 初始化容器的时候,会有两个钩子函数,postStart和preStop两个函数,这两个函数的中间就是pod的生命周期,从创建到停止。
- 启动完成后,Pod内的主容器启动。
- 开始启动探针,最后就绪探针和存活探针启动。
以下是配置的命令:
lifecycle:
postStart: # 容创建完成后执行的动作,不能保证该操作一定在容器的 command 之前执行,一般不使用
exec: # 可以是 exec / httpGet / tcpSocket
command:
- sh
- -c
- 'mkdir /data'
preStop: # 在容器停止前执行的动作
httpGet: # 发送一个 http 请求
path: /
port: 80
exec: # 执行一个命令
command:
- sh
- -c
- sleep 9
pod退出流程:
endpoint删除pod的ip地址 --> pod变成Terminating状态 --> 执行preStop命令
资源调度
目前修改pod,或者针对扩缩容是没办法在pod运行时修改,需要删除pod,然后修改配置文件再启动pod。接下来一系列的介绍,会逐步的使用热修改资源文件的方式。
Label 和 Selector
在 Kubernetes 中,标签(Labels)和选择器(Selectors)是关键概念,用于标识和组织资源。它们在实现应用程序部署、服务发现、资源管理等方面发挥着重要的作用。
label
标签是键值对,可以附加到 Kubernetes 对象(如 Pod、Service、Deployment 等)上,在各类资源的 metadata.labels 中进行配置。它们是用于对对象进行分类和标识的元数据。标签通常用于描述对象的特征、用途、环境等信息。
例如,你可以为一个 Pod 添加标签,表示它属于生产环境:
metadata:
labels:
environment: production
通过kubectl的操作如下:
临时创建 label
kubectl label po <资源名称> app=hello
修改已经存在的标签
kubectl label po <资源名称> app=hello2 --overwrite
查看 label
# selector 按照 label 单值查找节点 kubectl get po -A -l app=hello # 查看所有节点的 labels kubectl get po --show-labels
选择器(Selectors)
选择器是一种通过标签来筛选和选择 Kubernetes 对象的机制。通过标签选择器,你可以从集群中选择带有特定标签的对象。
例如,你可以使用标签选择器选择所有环境是生产环境的 Pod:
selector:
matchLabels:
environment: production
通过kubectl的操作如下:
# 匹配单个值,查找 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
在 Kubernetes 中,Deployment 是一种控制器(Controller)类型,用于定义和管理 Pod 的部署。Deployment 提供了一种声明式的方式来描述应用程序的期望状态,以及在实际状态和期望状态之间的调解和处理。以下是 Deployment 的一些主要作用:
- 声明式部署: Deployment 允许你通过声明式的 YAML 文件来描述应用程序的期望状态。
- 自动化滚动升级: Deployment 具有滚动升级的能力,可以在不中断服务的情况下更新应用程序。
- 故障恢复: 如果某个节点上的 Pod 失效或被删除,Deployment 会自动创建新的 Pod 以替代它,确保应用程序的副本数符合定义。
- 伸缩调整: 你可以通过修改 Deployment 的副本数来实现应用程序的伸缩调整,根据流量负载和资源需求动态地调整 Pod 的数量。
- 版本回滚: 如果滚动升级后发现问题,你可以使用 Deployment 实现版本回滚,返回到之前的稳定版本。
- 标签选择器管理: Deployment 使用标签选择器来管理和关联 Pod,确保它们属于同一个应用程序。这为服务发现和关联性提供了方便。
创建
[root@k8s-master ~]# kubectl create deploy nginx-deploy --image=nginx:1.7.9
deployment.apps/nginx-deploy created
[root@k8s-master ~]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 1/1 1 1 2s
[root@k8s-master ~]# kubectl get replicaset
NAME DESIRED CURRENT READY AGE
nginx-deploy-5c6485bbd4 1 1 1 75s
[root@k8s-master ~]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-deploy-5c6485bbd4-wvghb 1/1 Running 0 81s
[root@k8s-master ~]# kubectl get po,rs,deploy --show-labels
NAME READY STATUS RESTARTS AGE LABELS
pod/nginx-deploy-5c6485bbd4-wvghb 1/1 Running 0 28m app=nginx-deploy,pod-template-hash=5c6485bbd4
NAME DESIRED CURRENT READY AGE LABELS
replicaset.apps/nginx-deploy-5c6485bbd4 1 1 1 28m app=nginx-deploy,pod-template-hash=5c6485bbd4
NAME READY UP-TO-DATE AVAILABLE AGE LABELS
deployment.apps/nginx-deploy 1/1 1 1 28m app=nginx-deploy
这里可以看出一点端倪,我们的deploy和replicaset以及pod的关系。 而且这三者都是通过label来进行关联的
这个只是通过命令行创建一个deploy,一般情况下我们都是通过配置文件来创建,但是可以先通过kubectl来创建出一个yaml的模版,然后通过 kubectl get deploy nginx-deploy -o yaml
来查看yaml,再复制下来修修改改即可。 比如下面就是修修改改之后得到的:
apiVersion: apps/v1 # deployment api 版本
kind: Deployment # 资源类型
metadata: # 原信息
labels: # 标签
app: nginx-deploy
name: nginx-deploy
namespace: default
spec:
replicas: 1 # 期望副本数
revisionHistoryLimit: 10 # 滚动更新后保留的历史版本数
selector: # 选择器,用于找到匹配的RS
matchLabels: # 按照标签匹配
app: nginx-deploy
strategy: # 更新策略
rollingUpdate: # 滚动更新配置
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate # 更新类型,采用滚动更新
template: # pod模版,该deploy下的pod模版
metadata: # pod元信息
labels: # pod标签
app: nginx-deploy
spec: # pod期望信息
containers:
- image: nginx:1.7.9
imagePullPolicy: IfNotPresent
name: nginx
restartPolicy: Always # pod重启策略
terminationGracePeriodSeconds: 30 # 删除操作最长宽限多少时间,也就是经过多少秒后删除
接下来聊聊几个作用。
作用
所有的操作,都是修改deploy的配置信息 如 kubectl edit deploy nginx-deploy
动态扩容
刚下面就一个副本,也就是只有一个nginx,下面变为三个副本。
spec:
progressDeadlineSeconds: 600
replicas: 3
即可
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deploy-5c6485bbd4-8v5zw 1/1 Running 0 33s
nginx-deploy-5c6485bbd4-gqqjk 1/1 Running 0 33s
nginx-deploy-5c6485bbd4-wvghb 1/1 Running 0 34m
滚动更新
比如把nginx的版本修改一下后,下面也是滚动更新过程:
[root@k8s-master ~]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-deploy-5c6485bbd4-8v5zw 0/1 Terminating 0 5m33s
nginx-deploy-5c6485bbd4-gqqjk 0/1 Terminating 0 5m33s
nginx-deploy-5c6485bbd4-wvghb 0/1 Terminating 0 39m
nginx-deploy-6568ff7c5d-4zqf7 1/1 Running 0 9s
nginx-deploy-6568ff7c5d-n92vs 1/1 Running 0 38s
nginx-deploy-6568ff7c5d-wlj4w 1/1 Running 0 11s
[root@k8s-master ~]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-deploy-6568ff7c5d-4zqf7 1/1 Running 0 14s
nginx-deploy-6568ff7c5d-n92vs 1/1 Running 0 43s
nginx-deploy-6568ff7c5d-wlj4w 1/1 Running 0 16s
当然,也可以通过命令行工具直接更新:
[root@k8s-master ~]# kubectl set image deployment/nginx-deploy nginx=nginx:1.7.9
deployment.apps/nginx-deploy image updated
[root@k8s-master ~]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-deploy-5c6485bbd4-72kmq 0/1 ContainerCreating 0 1s
nginx-deploy-5c6485bbd4-l9bbv 1/1 Running 0 3s
nginx-deploy-5c6485bbd4-s9jgj 1/1 Running 0 4s
nginx-deploy-6568ff7c5d-n92vs 1/1 Running 0 5m35s
nginx-deploy-6568ff7c5d-wlj4w 0/1 Terminating 0 5m8s
[root@k8s-master ~]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-deploy-5c6485bbd4-72kmq 1/1 Running 0 4s
nginx-deploy-5c6485bbd4-l9bbv 1/1 Running 0 6s
nginx-deploy-5c6485bbd4-s9jgj 1/1 Running 0 7s
nginx-deploy-6568ff7c5d-n92vs 0/1 Terminating 0 5m38s
[root@k8s-master ~]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-deploy-5c6485bbd4-72kmq 1/1 Running 0 6s
nginx-deploy-5c6485bbd4-l9bbv 1/1 Running 0 8s
nginx-deploy-5c6485bbd4-s9jgj 1/1 Running 0 9s
它会一个关掉一个启动的,不是全部停止。
回滚
先查看历史版本:
kubectl rollout history deployment/nginx-deploy
[root@k8s-master ~]# kubectl rollout history deployment/nginx-deploy
deployment.apps/nginx-deploy
REVISION CHANGE-CAUSE
2 <none>
3 <none>
[root@k8s-master ~]# kubectl rollout history deployment/nginx-deploy
deployment.apps/nginx-deploy
REVISION CHANGE-CAUSE
2 <none>
3 <none>
[root@k8s-master ~]# kubectl rollout history deployment/nginx-deploy --revision=2
deployment.apps/nginx-deploy with revision #2
Pod Template:
Labels: app=nginx-deploy
pod-template-hash=6568ff7c5d
Containers:
nginx:
Image: nginx:1.9.1
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
然后 比如说要回退到版本为2.
kubectl rollout undo deployment/nginx-deploy --to-revision=2
[root@k8s-master ~]# kubectl rollout undo deployment/nginx-deploy --to-revision=2
deployment.apps/nginx-deploy rolled back
[root@k8s-master ~]# kubectl rollout status deployment/nginx-deploy
deployment "nginx-deploy" successfully rolled out
注意的是:可以通过设置 .spec.revisonHistoryLimit 来指定 deployment 保留多少 revison,如果设置为 0,则不允许 deployment 回退了。
扩缩容
在流量高峰的时候需要扩容,低谷的时候需要缩减,其实刚刚我们已经实现了,就是修改replicas的值。
但是,这么常用的场景,每次修改yaml文件的话,是有点麻烦,所以可以通过kubectl的命令来修改。
kubectl scale --replicas=6 deploy nginx-deploy
[root@k8s-master ~]# kubectl scale --replicas=6 deploy nginx-deploy
deployment.apps/nginx-deploy scaled
[root@k8s-master ~]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 6/6 6 6 115m
[root@k8s-master ~]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-deploy-6568ff7c5d-6584j 1/1 Running 0 6m36s
nginx-deploy-6568ff7c5d-k4fzb 1/1 Running 0 13s
nginx-deploy-6568ff7c5d-pqlv5 1/1 Running 0 13s
nginx-deploy-6568ff7c5d-prh9q 1/1 Running 0 6m39s
nginx-deploy-6568ff7c5d-wg7z8 1/1 Running 0 6m40s
nginx-deploy-6568ff7c5d-zn5cs 1/1 Running 0 13s
缩容,也是修改减少值。
暂停和恢复
由于每次对 pod template 中的信息发生修改后,都会触发更新 deployment 操作,那么此时如果频繁修改信息,就会产生多次更新,而实际上只需要执行最后一次更新即可,当出现此类情况时我们就可以暂停 deployment 的 rollout
通过kubectl rollout pause deployment <name>
就可以实现暂停,直到你下次恢复后才会继续进行滚动更新
StatefulSet
有状态的服务。刚刚都是针对无状态的服务进行扩缩容、删减、修改等等,但是针对有状态的服务可不能这么干了。
创建
我们使用模版来创建
---
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
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
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
[root@k8s-master statefulset]# kubectl create -f web.yaml
service/nginx created
statefulset.apps/web created
[root@k8s-master statefulset]# kubectl get sts
NAME READY AGE
web 2/2 5s
[root@k8s-master statefulset]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d18h
nginx ClusterIP None <none> 80/TCP 13s
[root@k8s-master statefulset]# kubectl get po
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 29s
web-1 1/1 Running 0 28s
扩缩容
扩缩容也是一行命令,kubectl scale sts web --replicas=5
来调整,但是它是有顺序操作的,并非和deploy一样是随机的。
# 扩容到5
[root@k8s-master statefulset]# kubectl scale sts web --replicas=5
statefulset.apps/web scaled
[root@k8s-master statefulset]# kubectl get po
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 6m36s
web-1 1/1 Running 0 6m35s
web-2 1/1 Running 0 2s
web-3 0/1 ContainerCreating 0 1s
[root@k8s-master statefulset]# kubectl get po
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 6m39s
web-1 1/1 Running 0 6m38s
web-2 1/1 Running 0 5s
web-3 1/1 Running 0 4s
web-4 1/1 Running 0 2s
# 缩容2
[root@k8s-master statefulset]# kubectl scale sts web --replicas=2
statefulset.apps/web scaled
[root@k8s-master statefulset]# kubectl get po
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 7m58s
web-1 1/1 Running 0 7m57s
以上例子可以说明,扩容是2/3/4,缩容的话也是一样的从后开始删减,保证顺序性。
镜像更新、灰度
目前还不支持直接更新 image,需要 patch 来间接实现
kubectl patch sts web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"nginx:1.9.1"}]'
这其中可以进行灰度发布: 利用滚动更新中的 partition 属性,可以实现简易的灰度发布的效果
例如我们有 5 个 pod,如果当前 partition 设置为 3,那么此时滚动更新时,只会更新那些 序号 >= 3 的 pod
利用该机制,我们可以通过控制 partition 的值,来决定只更新其中一部分 pod,确认没有问题后再主键增大更新的 pod 数量,最终实现全部 pod 更新
删除
# 删除 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
# StatefulSet删除后PVC还会保留着,数据不再使用的话也需要删除
$ kubectl delete pvc www-web-0 www-web-1
DaemonSet
在 Kubernetes 中,DaemonSet 是一种控制器(Controller)类型,用于确保集群中的每个节点都运行一个副本(Pod)的特定 Pod。DaemonSet 通常用于在集群的每个节点上运行一些基础设施性质的服务,如日志收集、监控、网络代理等。
DaemonSet 是一种非常有用的资源控制器,用于在 Kubernetes 集群中管理分布在每个节点上的特定服务或任务的 Pod。
配置
apiVersion: apps/v1
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:
- hostPath:
path: /var/lib/docker/containers
name: containers
- hostPath:
path: /var/log
name: varlog