学习完资源清单后,记得要回去看看一个资源的创建过程。
K8S中所有内容都抽象为资源,资源实例化之后,叫作对象。
类型 |
资源 |
工作负载型(workload) |
Pod、ReplicaSet、Deployment、StatefulSet、DaemonSet、Job、CronJob(ReplicationController在v1.11版本被废弃了) |
服务发现及负载均衡型(ServiceDiscovery LoadBalance) |
Service、Ingress |
配置与存储型 |
Volume、CSI(容器存储接口,可以扩展第三方存储卷) |
特殊类型的存储卷 |
ConfigMap、Secret、DownwardAPI(外部环境中的信息输给容器) |
集群级型 |
NameSpace、Node、Role、ClusterRole、RoleBinding、ClusterRoleBinding |
元数据型 |
HPA、PodTemplate、LimitRange |
资源清单常用字段
在K8S中,一般使用yaml格式的文件来创建符合预期期望的Pod,这样的yaml文件一般称为资源清单。
必备属性:
名称 |
类型 |
说明 |
version |
String |
目前基本是v1版本,可以用kubectl api-versions命令查询 |
kind |
String |
yaml文件定义的资源类型和角色,比如Pod |
metadata |
Object |
元数据对象,固定值 |
metadata.name |
String |
元数据对象的名字,用户编写,如命名Pod的名字 |
spec |
Object |
详细定义,固定值 |
spec.containers[] |
List |
容器列表定义 |
主要对象(非必须,有默认值):
名称 |
类型 |
说明 |
metadata.namespace |
String |
元数据对象的命名空间,用户自定义,默认是default |
spec.containers[].name |
String |
容器的名字 |
spec.containers[].image |
String |
镜像名称 |
spec.containers[].imagePullPolicy |
String |
镜像拉取策略 Always每次都会尝试重新拉取,有时发现本地有镜像却出现拉取失败,因链接不上对应的网络 IfNotPresent本地有则用本地,没有则在线拉取 Nerver仅使用本地 |
spec.containers[].command[] |
List |
指定容器启动命令,因为是数组可以指定多个,不指定则使用镜像打包时使用的启动命令 |
spec.containers[].args[] |
List |
指定容器启动命令参数,因为是数组可以指定多个 |
spec.containers[].workingDir |
String |
容器工作目录 |
spec.containers[].volumeMounts[] |
List |
容器内部的存储卷配置 |
spec.containers[].volumeMounts[].name |
String |
可以被容器挂载的存储卷的名称 |
spec.containers[].volumeMounts[].mountPath |
String |
可以被容器挂载的存储卷的路径 |
spec.containers[].volumeMounts[].readOly |
String |
设置存储卷的读写模式,true或false,默认为读写模式 |
spec.containers[].ports[] |
List |
容器需要用到的端口列表 |
spec.containers[].port[].name |
String |
端口名称 |
spec.containers[].port[].containerPort |
String |
容器需要监听的端口 |
spec.containers[].port[].hostPort |
String |
容器所在主机需要监听的端口号,默认跟上面的containerPort相同。 注意:设置了hostPort同一台主机无法启动该容器的相同副本,因为主机的端口号不能相同,这样会冲突 |
spec.containers[].port[].protocol |
String |
端口协议,支持TCP和UDP,默认TCP |
spec.containers[].env[] |
List |
容器运行前需设置的环境变量列表 |
spec.containers[].env[].name |
String |
容器运行前需设置的环境变量名 |
spec.containers[].env[].value |
String |
容器运行前需设置的环境变量值 |
spec.containers[].resources |
Object |
指定资源限制和资源请求的值(设置容器资源上限) |
spec.containers[].resources.limits |
Object |
指定容器运行时的资源上限 |
spec.containers[].resources.limits.cpu |
String |
指定CPU限制,单位为core数,将用于docker run –cpu-shares参数 |
spec.containers[].resources.limits.memory |
String |
指定MEM内存的限制,单位是MIB、GIB |
spec.containers[].resources.requests |
Object |
指定容器启动和调度时的限制设置 |
spec.containers[].resources.requests.cpu |
String |
CPU请求,单位为core数,容器启动时初始化可用数量 |
spec.containers[].resources.requests.memory |
String |
内存请求,单位为MIN、GIB,容器启动时初始化可用数量 |
spec.restartPolicy |
String |
定义Pod重启策略 Always是指无论Pod是如何终止的,Kubelet都会重启此Pod,默认是这个值。 OnFailure只有Pod以非0退出码终止时,kubelet才回重启该容器,如果容器正常结束(退出码为0),kebelet将不会重启它 Never是指Pod终止后,kubelet会把退出码报告给Master,但不会重启该Pod |
spec.nodeSelector |
Object |
定义Node的Label过滤标签,以key:value格式指定 |
spec.imagePullSecrets |
Object |
Pull镜像时使用secret名称,以name:secretkey格式指定 |
spec.hostNetwork |
Boolean |
定义是否使用主机网络模式,默认值为false,设置true就标识使用宿主机网络,不使用docker网桥,同时设置了true将无法在同一台宿主机上启动第二个副本 |
第一个资源清单的制作:
vi test-pod.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #指定K8S Api版本 apiVersion: v1 #指定yaml文件定义的资源类型和角色 kind: Pod #元数据对象,固定值 metadata: #元数据对象的名称,kind指定的资源类型是Pod,这里指的是Pod的名称 name: testapp-pod #所属的名称空间 namespace: default #标签 labels: app: myapp version: v1 #固定对象 spec: #运行的容器列表 containers: #容器名 - name: app1 #运行的镜像 image: levi.harbor.com/library/nginx:1.9.1 - name: app2 image: levi.harbor.com/library/nginx:1.9.1 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
#一个pod中运行2个相同容器,会出现端口占用 kubectl apply -f test-pod.yaml
kubectl get pod
#查看pod的信息 kubectl describe pod myapp-pod(容器名)
#查看容器日志,不需要指定容器就不需要加-c kubectl log myapp-pod -c test
#把test给删除,留下app
kubectl delete pod myapp-pod
kubectp create -f test-pod.yaml |
容器的生命周期
Pod容器的生命周期:
Pod生命周期的整个过程都是存储在Etcd的。
详细过程简述:kubectl à kubelet à CRI à 容器环境初始化 à Pause(基础容器,负责网络和基础卷共享) à InitC(初始化容器,初始化完成后就死亡了,可能有多个,但是多个InitC是不能并行的) à Start(容器运行之前执行) à Readiness(就绪)à Liveness(生存检测) à Stop(容器结束之前执行)
每一个Pod都有一个特殊的被称为根容器的Pause容器。Pause容器又叫Infra容器,在检查node节点时,会发现每个node上都运行了很多Pause容器。
InitC容器
Pod能够具有多个容器,应用运行在容器里面,但是它也有可能有一个或多个先于应用容器启动的Init容器。
Init容器与普通容器非常像,但具有两点明显区别。一、Init容器总是运行到成功完成为止;二、每个Init容器都必须在下一个Init容器启动之前成功完成。
如果Pod的Init容器失败,K8S会不断的重启该Pod,知道Init容器成功为止,然而如果Pod对应的restartPolicy为Netver,它将不会重新启动。
Init容器具有与应用程序容器分离的单独镜像,所以它们启动相关代码时,具有一些优势:
它们可以包含并允许实用工具,但是出于安全考虑,是不建议在应用程序容器镜像中包含这些实用工具的。
它们可以包含使用工具和定制化代码来安装,但是不能出现在应用程序镜像中。例如,创建镜像没必要FROM另一个镜像,只需要安装过程中使用类似sed、awk、python或dig这样的工具。
应用程序镜像可以分离出创建和部署的角色,而没有必要联合它们构建一个单独的镜像。
Init容器使用Liunx NameSpace,所以相对应用程序容器来说具有不同的文件系统视图。因此,它们能够具有访问Secret的权限,而应用程序容器则不能。
它们必须在应用程序容器启动之前运行完成,而应用程序容器是并行运行的,所以Init容器能够提供一种简单的阻塞或延迟应用容器的启动的方法,知道满足了一组先决条件。
InitC实验:
在Pod启动过程中,Init容器会按照顺序在网络和数据卷初始化之后启动,即Pause启动后启动。每个容器必须在下一个容器之前成功退出。
如果由于运行时或失败退出,将导致容器启动失败,它会根据Pod的restartPolicy指定的策略进行重试,然而,如果Pod的restartPolicy设置为Always,Init容器失败时会使用RestartPolicy策略。
在所有Init容器没有成功之前,Pod将不会变成Ready状态。Init容器的端口将不会在Service中进行聚集。正在初始化中的Pod处于Pending桩体,但应该会将Initalizing状态设置为true。
如果Pod重启,所有Init容器必须重新执行。
对Init容器spec的修改被限制在容器image字段,修改其他字段都不会生效。更改Init容器的image字段,等价于重启该Pod。
Init容器具有应用容器的所有字段。除了readinessProbe,因为Init容器无法定义不同于完成(completion)的就绪(readiness)之外的其他状态。
在Pod中每个app和Init容器的名称必须唯一;与任何其他容器共享同一个名称。
vi ini-pod.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #指定K8S Api版本 apiVersion: v1 #指定yaml文件定义的资源类型和角色 kind: Pod #元数据对象,固定值 metadata: #元数据对象的名称,kind指定类型是Pod,这里指的就是Pod的名称 name: detect-pod1 #名称空间 namespace: default #标签 labels: app: myapp #详细定义对象,固定对象 spec: #运行的容器列表 containers: #运行的容器名 - name: myapp-container #镜像 image: busybox #指定容器启动命令,因为是数组可以指定多个,不指定则使用镜像打包时的启动命令 command: ['sh','-c','echo running! && sleep 3600'] #初始化容器,即容器会先启动一个或多个容器,如果有多个,这几个Init Container按照容器的定义顺序会先启动,只有Init Container执行完后,主容器才会启动 #注意:名称不可以相同,端口可以相同,因为其中一个容器执行完成后就退出了,下一个容器即便端口一样还是不会报错,可以运行的 initContainers: #容器名 - name: init1-myservice #镜像 image: busybox #指定容器启动命令 #启动时会去解析myservice这个主机名,K8S DNS会把svc、pod、service解析成为IP,一旦有了这个myservice命名的svc/pod/service,K8S内部就会解析为IP。 #这条命令的意思是如果找不到(flase),则会打印出一句话后休眠2秒。 command: ['sh','-c','until nslookup myservice;do echo waiting for myservice;sleep 2;done;'] #容器名 - name: init2-mydb #镜像 image: levi.harbor.com/library/nginx:1.9.1 #指定容器启动命令 #启动时会去解析mydb这个主机名,K8S会把svc、pod、service解析成为IP,一旦有了这个mydb命名的svc/pod/service,K8S内部就会解析成为IP。 #这条命令的意思是如果找不到(false),则会打印出一句话后休眠2秒。 command: ['sh','-c','until nslookup mydb;do echo waiting for mydb;sleep 2;done;'] 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 kubectl get pod kubectl delete pod --all kubectl delete deployment --all kubectl delete svc --all
kubectl create -f init-pod.yaml
#看Status kubectl get pod
#看详细信息 kubectl describe pod detect-pod1
#仔细关注日志 kubectl log detect-pod1 -c init1-myservice
#仔细看提示信息 kubectl log detect-pod1 -c init2-mydb
#回过来看 kubectl get pod
vi myservice.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #指定K8S Api版本 apiVersion: v1 #指定yaml文件定义的资源类型和角色 kind: Service #元数据对象 metadata: name: myservice #详细定义对象 spec: #定义端口(多个) ports: #端口的协议 - protocol: TCP #端口是80 port: 80 #暴露的svc的端口 targetPort: 9577 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 kubectl create -f myservice.yaml kubectl get svc #会发现Init变成1/2了 kubectl get pod
vi mydb.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #指定k8s api版本 apiVersion: v1 #指定yaml文件定义的资源类型和角色 kind: Service #元数据对象 metadata: #运行的资源类型的名称,指定的是SVC即SVC的名称 name: mydb #详细定义对象 spec: #定义端口(多个) ports: - protocol: TCP #端口 port: 80 #暴露的svc的端口 targetPort: 9578 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl create -f mydb.yaml
kubectl get pod -w
kubectl describe pod detect-pod1
latest标签的镜像版本会每次都跑去远程仓库检测下,所以能不用latest就不用,并且下载策略是Always。 |
探针
探针是kubelet对容器执行的定期诊断。要执行诊断,kubelet调用由容器实现的Handler。
有三种的类型处理程序:
ExecAction:在容器内执行指定命令,如果命令退出时返回码为0,则认为诊断成功。
TCPSocketAction:对指定端口上的容器的IP地址进行TCP检查。如果端口打开,则诊断被认为是成功的。
HTTPGetAction:对指定的端口和路径上的容器的IP地址执行HTTP Get请求。如果响应状态码大于等于200且小于400,则诊断被认为是成功的。
每次探测都会获得三种结果之一:
成功:容器通过诊断。
失败:容器未通过诊断。
未知:诊断失败,因此不会采取任何行动。
readinessProbe:指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与Pod匹配的所有Service的端点中删除该Pod的IP地址。初始延迟之前的就绪状态默认为Failure。如果容器不提供就绪探针,则默认状态为Success。
vi read.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #指定K8S API版本 apiVersion: v1 #指定资源类型 kind: Pod #元数据 metadata: #资源类型的运行名称 name: readiness-httpget-pod #名称空间 namespace: default #详细定义 spec: #运行的容器 containers: #容器名 - name: readiness-httpget-container #镜像 image: levi.harbor.com/library/nginx:1.9.1 #镜像拉取策略:Always每次都尝试重新拉取。Never仅使用本地镜像。IfNotPresent本地有就用,没有就拉取 imagePullPolicy: IfNotPresent #就绪状态检测 readinessProbe: #检测方案HTTP GET httpGet: #端口 port: 80 #路径 path: /index1.html #初始延迟时间,容器启动1秒后开始检测 initialDelaySeconds: 1 #重试检测周期 periodSeconds: 3 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl create -f read.yaml
#看READY栏 kubectl get pod
#可以看到是失败的 kubectl describe pod readiness-httpget-pod
#如果pod有多个容器则需要使用-c指定容器 kubectl exec readiness-httpget-pod -it -- /bin/sh kubectl exec readiness-httpget-pod -c 容器名 -it -- /bin/sh
cd /usr/share/nginx cd html/ ls echo "123" >> index1.html
#会发现READY栏成功了,有了这个文件就检测完成了。 kubectl get pod |
livenessProbe:指示容器是否正在运行。如果存活探测失效,则kubelet会杀死容器,并且容器将受到其重启策略的影响。如果容器不提供存活探针,则默认状态为Success。
vi live-exec.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #指定k8s 版本 apiVersion: v1 #指定资源类型 kind: Pod #元数据 metadata: #资源类型运行时的名称 name: liveness-exec-pod #名称空间 namespace: default #详细信息 spec: #容器 containers: #容器名称 - name: liveness-exec-container #镜像 image: busybox #镜像拉取策略,Always每次都尝试重新拉取镜像,Never仅使用本地镜像,IfNotPresent本地有则使用,没则拉 imagePullPolicy: IfNotPresent #容器启动时,执行的命令 command: ['/bin/sh','-c','touch /tmp/live; sleep 10;rm -rf /tmp/live;sleep 20;'] #存活检测策略 livenessProbe: #采用策略,执行命令 exec: command: ['test','-e','/tmp/live'] #启动1秒后开始检测 initialDelaySeconds: 1 #重复检测周期为3秒 periodSeconds: 3 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 kubectl create -f live-exec.yaml
kubectl get pod
kubectl describe pod liveness-exec-pod
#关注重启次数,在每次重启时,都重新加载文件,此时又发现该文件,10秒在重启,如此循环 kubectl get pod –w
vi live-httpget.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #指定k8s 版本 apiVersion: v1 #资源类型 kind: Pod #元数据 metadata: #资源运行名称 name: liveness-httpget-pod #名称空间 namespace: default #详细 spec: #容器 containers: #容器名称 - name: liveness-httpget-container #镜像 image: levi.harbor.com/library/nginx:1.9.1 #镜像拉取策略,Always每次都尝试去拉取,Nerver只在本地查找,IfNotPresent本地没有则拉取 imagePullPolicy: IfNotPresent #端口 ports: #协议 - name: http #容器端口 containerPort: 80 #存活检测 livenessProbe: #检测策略 httpGet: #端口 port: 80 #路径 path: /index.html #启动后1秒开始检测 initialDelaySeconds: 1 #重复检测周期 periodSeconds: 3 #超时时间 timeoutSeconds: 10 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl create -f live-httpget.yaml
kubectl describe pod livenessProbe-httpget-pod kubectl get pod -0 wide
kubectl exec livenessProbe-httpget-pod -c 容器名 -it -- /bin/sh rm -rf /usr/share/nginx/index.html
kubectl get pod –w
#端口可用8080 vi live-tcp.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #k8s api版本 apiVersion: v1 #资源类型 kind: Pod #元数据 metadata: #资源运行名称 name: liveness-tcp-pod #详细 spec: #容器 containers: #容器名 - name: liveness-tcp-container #镜像 image: levi.harbor.com/library/nginx:1.9.1 #存活检测 livenessProbe: #启动初始化后5秒开始检测 initialDelaySeconds: 5 #超时时间 timeoutSeconds: 1 #检测策略 tcpSocket: #端口 #port: 80 port: 8081 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl create -f live-tcp.yaml
kubectl get pod –w
#结合 vi live-two.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #指定K8S版本 apiVersion: v1 #资源类型 kind: Pod #元数据 metadata: #资源运行名称 name: liveness-two-pod #名称空间 namespace: default #详细 spec: #容器 containers: #容器名 - name: liveness-two-container #镜像 image: levi.harbor.com/library/nginx:1.9.1 #镜像拉取策略,Always每次都尝试拉取,Nerver只使用本地,IfNotPresent优先本地 imagePullPolicy: IfNotPresent #运行端口 ports: #端口协议 - name: http #容器端口 containerPort: 80 #1.就绪检测 readinessProbe: #检测策略 httpGet: #检测端口 port: 80 #路径 path: /index1.html #初始化后1秒执行 initialDelaySeconds: 1 #重复检测周期 periodSeconds: 3 #2.存活检测 livenessProbe: #检测策略 httpGet: #检测端口 port: http #路径 path: /index.html #初始化后1秒执行 initialDelaySeconds: 1 #重复检测周期 periodSeconds: 3 #检测过期时间 timeoutSeconds: 10 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl create -f live-two.yaml
kectl get pod
kubectl describe pod liveness-two-pod
#进入容器内 kubectl exec liveness-two-pod -it -- /bin/bash cd /usr/share/nginx/html echo '321' >> index1.html
#再次查看pod状态 kubectl get pods
#进入容器内 kubectl exec liveness-two-pod -it -- /bin/bash cd /usr/share/nginx/html rm -rf index.html
#再次查看pod状态 kubectl get pods -w |
Pod Hook(钩子)
Pod Hook是由K8S管理的kubelet发起的,当容器中的进程自动铅或者容器中的进程终止之前执行,这包含在容器的生命周期之中,可以同时为Pod中的所有容器都配置Hook。
Hook的类型有两种:一是exec,执行一段命令;二是Http,发送Http请求。
vi hook.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: v1 kind: Pod metadata: name: hook-pod spec: containers: - name: hook-container image: levi.harbor.com/library/nginx:1.9.1 lifecycle: postStart: exec: command: ["/bin/sh", "-c", "echo Start > /tmp/test.txt"] preStop: exec: command: ["/bin/sh", "-c", "echo Stop > /tmp/test.txt"] 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl create -f hook.yaml
kectl get pod
cat /tmp/test.txt
kubectl delete pod pod名 |
Pod状态说明
挂起(Pending):Pod已被K8S系统接受,但有一个或多个容器镜像尚未创建。等待时间包括调度Pod的时间和通过网络下载镜像的时间,这可能需要花点时间。
运行中(Running):该Pod已经被绑定到了一个节点,Pod中所有的容器都已被创建,至少有一个容器正在运行,或者正处于启动或重启状态。
成功(Successed):Pod中所有容器都被成功终止,并且不会重启。
失败(Failed):Pod中所有容器都已终止了,并且至少有一个容器是因为失败终止,也就是说,容器是以非0状态退出或者被系统终止。
未知(Unknown):因为某些原因无法取得Pod状态,通常是因为与Pod所在主机通信失败。
Kubernetes(K8S)常用命令
命令 |
描述 |
kubeadm reset |
重置,如节点重置后需要重新执行加入命令 |
Systemctl daemon-reload |
更改配置文件后重新加载 |
systemctl <start、restart、stop、status> docker |
重启docker |
systemctl <start、restart、stop、status> kubelet |
重启k8s |
|
|
kubectl get nodes |
获取节点相应的信息 |
kubectl cluster-info |
查看集群信息 |
kubectl -s http://localhost:8080 get componentstatuses |
查看各组件信息 |
kubectl get pods -o wide kubectl get pod <PodName> -o yaml |
查看pods所在的运行节点 |
kubectl get pods -o yaml |
查看pods定义的详细信息 |
kubectl exec <PodName> env |
查看运行的pod的环境变量 |
|
|
kubectl create -f 文件名.yml |
重新根据yaml文件生成新的,即创建资源 |
kubectl replace -f 文件名 [--force] |
重建资源 |
kubectl apply -f 文件名.yml |
根据配置文件里面列出来的内容,升级现有的 |
kubectl delete -f 文件名 kubectl delete pod pod名 kubectl delete rc rc名 kubectl delete service service名 kubectl delete pod --all |
删除资源 |
|
|
kubectl get services kubectl get services -n kube-system |
查看所有service |
kubectl get deployment kubectl get deployment -n kube-system |
查看所有deployment |
kubectl get pods --all-namespaces kubectl get pods -o wide --all-namespaces kubectl get pods -n kube-system | grep flannel |
查看pod及对应的名称空间 |
kubectl describe pod pod名 kubectl describe pods/pod名 #其他同理 kubectl describe svc nginx-deployment |
查看指定资源详细描述信息 |
kubectl scale rc nginx --replicas=5 kubectl scale deploment redis-slave --replicas=5 kubectl scale --replicas=2 -f redis-slave-deployment.yaml |
kubernetes动态伸缩 |
kubectl exec pod名 -it -- /bin/bash |
进入pod启动容器 |
资源控制器
Kubernetes(K8S)中内建了很多controller(控制器),这些相当于一个状态机,用来控制Pod的具体状态和行为。
控制器类型:
ReplicationController和ReplicaSet
Deployment
DaemonSet
StatefulSet
Job/CronJob
Horizontal Pod Autoscaling
ReplicationController和ReplicaSet
RC用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的Pod来替代;而如果异常多出来的容器也会自动回收;
在新版本K8S中建议使用RS来取代RC。RS和RC没有什么区别,RS支持集合式Selector。
Deployment
Deployemnt为Pod和RS提供了一个声明式定义(declarative)方法,用来替代以前的RC来方便管理应用,典型的应用场景包括:
定义Deployment来创建Pod和ReplicaSet
滚动升级和回滚应用
扩容和缩容
暂停和继续Deployment
RS、RC、Deployment
#RC、RS与Deployment的关系
#查看RS的模板信息 kubectl explain rs
vi rs.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #K8S api版本 apiVersion: extensions/v1beta1 #资源类型 kind: ReplicaSet #元数据 metadata: #资源运行名称 name: frontend #详细 spec: #副本数 replicas: 3 #选择器 selector: #匹配的标签 matchLabels: tier: frontend #模板,创建RS的Pod template: #模板信息 metadata: #标签 labels: tier: frontend #详细 spec: #容器 containers: #容器名称 - name: myapp #镜像 image: levi.harbor.com/library/nginx:1.9.1 #环境变量 env: #名称 - name: GET_HOSTS_FROM #值 value: dns #端口 ports: #容器端口 - containerPort: 80 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 kubectl create -f rs.yaml kubectl get pod kubectl delete pod --all
kubectl get rs
#会发现按照期望值又新建了,NAME不一样 kubectl get pod
#配置文件的标签 kubectl get pod --show-labels
#新增标签 kubectl label pod pod名称 标签K=V kubectl label pod frontend-44f46 testK=testV
#修改标签 kubectl label pod pod名称 标签K=V1 --overwrite=True kubectl label pod frontend-psjnh tier=V1 --overwrite=True
#Pod的确是给rs管理的,并且可以看到又创建了一个的Pod kubectl delete rs -all
kubectl get pod
kubectl get pod --show-labels |
vi nginx-deployment.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #K8S Api版本 apiVersion: extensions/v1beta1 #资源类型 kind: Deployment metadata: #运行时名称 name: nginx-deployment spec: #副本 replicas: 3 #模板,即创建Pod template: metadata: #标签 labels: app: nginx spec: #容器 containers: - name: nginx image: levi.harbor.com/library/nginx:1.9.1 ports: - containerPort: 80 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
#record参数可以记录命令,可以很方便的查看每次revision的变化 kubectl create -f nginx-deployment.yaml --record
#K8S的网络都是扁平化网络都可以通过暴露的端口访问
kubectl get deployment
#deployment创建rs出来 kubectl get rs
kubectl get pod
#每一台的位于位置和IP kubectl get pod -o wide
#扩容 kubectl scale deployment nginx-deployment --replicas 10
kubectl get pod
#滚动更新的话,会新建一个新的RS kubectl get rs
#更新镜像 kubectl set image deployment/nginx-deployment nginx=nginx:1.9.2
#镜像的更改会导致rs的创建 kubectl get rs -w
kubectl get pod
#回滚,默认回滚到上一个版本 kubectl rollout undo deployment/nginx-deployment
kubectl get rs -w
kubectl get pod
#Deployment更新策略说明:Deployment可以保证在升级时,只有一定数量的Pod是down的,默认的,它会确保至少有比期望的Pod数量少一个是up状态(最多一个不可用)。同时也可以确保只创建超过期望数量的一定数量的Pod,默认的它会确保最多比期望的Pod数量多一个的Pod是up的(最多一个surge)。未来的K8S版本中将会从阈值1-1变成25%-25%
kubectl describe deployments
#Rollover(多个rollout并行)说明:假如创建了一个有5个nginx:1.9.1的replica的Deployment,但是当还只有3个nginx:1.9.1的replica创建出来的时候,就开始更新含有5个nginx:1.9.1的replicaDeployment。在这个情况下,Deployment会立即杀掉已创建的3个nginx:1.9.1的Pod,并开始创建nginx:1.9.1的Pod。不会等到所有5个nginx:1.9.1的Pod都创建完成后才开始改变。
#查看更新状态 kubectl rollout status deployment/nginx-deployment
#更新历史 kubectl rollout history deployment/nginx-deployment
#指定回退到某个历史版本 kubectl rollout undo deployment/nginx-deployment --to-revision=2
#暂停deployment的更新 kubectl rollout pause deployment/nginx-deployment
kubectl get deployment
kubectl get pod
kubectl get rs
#查看是否回滚成功,如果为0则为成功 kubectl rollout status deployment/nginx-deployment
echo $?
#清理Policy:可以通过设置.spec.revisonHistoryLimit项来指定deployment最多保留多少revision历史记录,默认是会保留所有,如果设置为0,Deployment就不允许回退 |
DaemonSet
DaemonSet确保全部(或者一些)Node上运行一个Pod的副本。当有Node加入集群时,也会为他们新增一个Pod。当有Node从集群移除时,这些Pod也会被回收。删除DaemonSet将会删除它创建的所有Pod。
使用DaemonSet的一些典型用法:
运行集群存储daemon,例如在每个Node上运行glusterd、ceph
在每个Node上运行日志收集daemon,例如fluentd、logstash
在每个Node上运行监控daemon,例如Prometheus Node Exporter、collectd、Datadog代理、New Relic代理,或Ganglia gmond。
vi daemonset.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #版本 apiVersion: apps/v1 #资源类型 kind: DaemonSet metadata: #运行名称 name: deamonset-example #标签 labels: app: daemonset spec: #匹配选择器 selector: matchLabels: name: deamonset-example #运行的Pod template: metadata: #标签 labels: name: deamonset-example spec: #容器 containers: - name: deamonset-example image: levi.harbor.com/library/nginx:1.9.1 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl create -f daemonset.yaml
kubectl get pod
#可以发现所有的Node都不会在master运行,原因就跟污点有关,后续章节 kubectl get pod -o wide
kubectl delete daemonset --all |
Job
负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束。
#spec说明:spec.template格式同Pod; #单个Pod时,默认Pod成功运行后Job即结束; #spec.completions标志Job结束需要成功允许的Pod个数,默认为1; #spec.parallelism标志并允许的Pod的个数,默认为1; #spec.activeDeadlineSeconds标志失败Pod的重试最大时间,超过这个时间不会继续重试。
vi job.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #api版本 apiVersion: batch/v1 #资源 kind: Job metadata: #运行名称 name: pi-job spec: #运行的Pod信息 template: metadata: name: pi-pod spec: #容器 containers: - name: pi image: perl imagePullPolicy: IfNotPresent command: ["perl","-Mbignum=bpi","-wle","print bpi(2000)"] #重启策略,永不重启 restartPolicy: Never 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 kubectl create -f job.yaml
kubectl get pod
kubectl describe pod pod名
kubectl get job
kubectl get pod -o wide
kubectl log pod名
kubectl delete pod --all |
CronJob
管理基于时间的Job,即:在给定时间点只运行一次;周期性的在给定时间点运行;
典型使用场景:
在给定的时间点调度Job运行
创建周期性运行的Job,例如:数据库备份、发送邮件
使用前提:当前使用K8S集群的版本>=1.8(对CronJob)。对于先前版本的集群,版本<1.8启动APIServer时,通过传递选项—runtime-config=batch/v2alpha1=true可以开启batch/v2alpha1 API。
#spec说明:spec.template格式同Pod; #单个Pod时,默认Pod成功运行后Job即结束; #spec.completions标志Job结束需要成功允许的Pod个数,默认为1; #spec.parallelism标志并允许的Pod的个数,默认为1; #spec.activeDeadlineSeconds标志失败Pod的重试最大时间,超过这个时间不会继续重试。
#spec.schedule:调度,必要字段,指定任务运行周期,格式同Job #spec.jobTemplate:Job模板,必须字段,指定需要运行的任务,格式同Job #spec.startingDeadlineSeconds:启动Job的期限(秒级别),该字段是可选的。如果因为任何原因而错过了被调度的时间,那么错过执行时间的Job将被认为是失败的。如果没有指定则没有期限。 #spec.concurrencyPolicy:并发策略,该字段也是可选的,指定了如何处理被CronJob创建的Job的并发执行。只允许指定其中一种策略。Allow(默认)允许并发允许Job;Forbid禁止并发允许,如果前一个还没有完成,则直接跳过下一个;Replace取消当前正在运行的Job,用一个新的来替换。注意:当前策略只能应用于同一个CronJob创建的Job,如果存在多个CronJob,它们创建的Job之间总是允许并发允许。 #spec.suspend:挂起该字段也是可选,如果设置为true,后续所有执行都会被挂起,它对已经开始执行的Job不起作用,默认为false。 #spec.successfulJobsHistoryLimit和spec.failedJobsHistoryLimit:历史限制,是可选的字段。它们指定了可以保留多少完成和失败的Job。默认情况下它们分别设置为3和1。设置限制的值为0,相关类型的Job完成后将不会被保留。
vi cronjob.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #api版本 apiVersion: batch/v1beta1 #资源类型 kind: CronJob metadata: #运行名称 name: hello spec: #调度,格式同Cron schedule: "*/1 * * * *" #Job模板,指定需要运行的任务,格式同Job jobTemplate: spec: #运行的Pod template: spec: #容器 containers: - name: hello image: busybox #拉取策略 imagePullPolicy: IfNotPresent args: - /bin/sh - -c - date;echo Hello from the Kubernetes cluster #重启策略,Nerver从不重启,OnFailure失败重启 restartPolicy: OnFailure 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f cronjob.yaml
kubectl get job
kubectl get crondjob
kubectl get pod kubectl get cronjob
#等待不断创建新的Job kubectl get job -w
kubectl log pod名
#删除crondjob时,不会删除job,删除job要另外用kubectl delete job kubectl delete crondjob
#CrondJob本身的限制,创建Job操作应该是幂等的 |
StatefulSet
StatefulSet作为Controller为Pod提供唯一的标识。它可以保证部署和Scale的顺序。
StatefulSet是为了解决有状态服务的问题(对应Deployments和ReplicaSets是为无状态服务而设计),其应用场景包括:
稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现。
稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现。
有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次进行(即从0到N - 1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于init containers来实现。
有序收缩,有序删除(即从N - 1到0)
Horizontal Pod Autoscaling
应用的资源使用率通常都有高峰和低谷的时候,如何削峰填谷,提高集群的整体资源利用率,让Service中的Pod个数自动调整,即Pod水平自动缩放。