一、简介 1. 介绍 Kubernetes是一个基于 Docker 的容器集群管理系统,其目的是让用户透过 Kubernetes 集群来进行云端容器集群的管理
它的本质是一组服务器 (集群),可以在集群的每个节点运行特点的程序,来对节点中的容器进行管理。目的是为了实现资源管理的自动化
功能:
自我修复 :一旦某个容器奔溃,能够迅速启动新的容器
弹性伸缩 :根据需要自动对集群中正在运行的容器调整数量
服务发现 :服务可以通过自动发现的形式找到它所依赖的服务
负载均衡 :如果(1000个)请求启动了多个(5个nginx)容器,能够自动实现请求的负载均衡
版本回退 :如果新发布的应用有问题,可以立即回退到原来的版本
存储编排 :根据容器自身的需求自动创建存储卷
2. 组件 一个k8s集群由**控制节点(master)、 工作节点(node)**构成,每个节点上都会安装不同的组件
master:管理层,负责集群的决策
API Server :集群管理操作的入口,不管是kubectl还是HTTP调用来操作Kubernetes集群各种资源,都是通过它的接口进行操作
Scheduler :负责集群资源调度,根据调度策略将Pod调度到相应的node节点上
ControllerManager :资源对象的控制自动化中心。即监控Node,当故障时转移资源对象,自动修复集群到期望状态。比如程序部署安排、故障检测、自动扩展等
Etcd :负责存储集群中各种资源对象的信息。k8s启动后,master和node都会将自身的信息存储到etcd数据库中
node:工作层,负责为容器提供运行环境
Kubelet : 负责Pod内容器的创建、启停。并与Master密切协作实现集群管理(注册自己,汇报Node状态)
监听Scheduler组件的任务分配
挂载pod所需Volume
下载pod所需Secrets
通过与docker daemon的交互运行docker容器
监控、报告pod和node状态到ControllerManager组件
KubeProxy :负责提供集群内部的服务发现和负载均衡,负责将后端pod访问规则具体为节点上的iptables/ipvs规则
Docker :负责镜像管理以及pod和容器的真正运行
部署Nginx:
”安装nginx服务的请求“发送至master节点的API Server 组件
API Server 调用Scheduler 组件做出决定(选择哪个node节点)。它会从etcd 中读取node节点信息,根据一定的算法进行选择,并将结果告诉API Server
API Server 调用ControllerManager 组件去安排这个决定(调度node节点安装nginx)
ControllerManager 将安排发送给Kubelet ,Kubelet 接受到指令后,会通知Docker ,由Docker 启动一个nginx的pod(pod是k8s的最小操作单元,容器必须跑在pod中)
nginx服务运行来了,如果需要访问,就需要通过KubeProxy 来对pod产生访问的代理,这样外界用户可以访问集群中的nginx访问了
客户(用户)想要增加一个新功能,会联系项目经理(API Server),项目经理通过分析(Scheduler)得知谁来做这个功能,然后通知(ControllerManager)这个小组长(Kubelet),小组长再将工作告诉某个人(Docker)
3. 概念 Master :集群控制节点,每个集群至少有一个master节点负责集群的管控
Node :工作负载节点,由master节点分配容器到node工作节点上,node节点上的docker容器负责运行
Pod :k8s的最小控制单元,容器运行在pod中,一个pod包含多个容器。通过控制pod进而控制容器
Controller :pod控制器,通过它来实现对pod的管理,比如启动、停止
Service :pod对外提供服务的统一入口,可以维护同一类的pod
Label :标签,用于对pod进行分类
Namespace :命名空间,用来隔离pod的运行环境
二、资源管理 在kubernetes中,所有的内容都抽象为资源,用户需要通过操作资源来管理kubernetes
部署服务:在k8s集群中运行一个个的容器,并将指定的程序跑在容器中
k8s的最小管理单元是pod,所以容器要放在pod 中,k8s并不直接管理pod ,还是通过**pod控制器(Controller)**来管理pod
pod提供服务之后,就要访问服务了,这就是Service 的功能
学习kubernetes的核心,就是学习如何对集群上的Pod、Pod控制器、Service、存储 等资源进行操作
1.资源管理方式
命令式对象管理:使用命令去操作kubernetes资源
kubectl run nginx-pod --image=nginx:1.17.1 --port=80
命令式对象配置:使用命令 + 配置文件去操作kubernetes资源
kubectl create/patch -f nginx-pod.yml
声明式对象配置:通过apply
(创建和更新的结合)命令和配置文件去操作kubernetes资源
kubectl apply -f nginx-pod.yml
2.命令式对象管理 kubectl是kubernetes集群的命令行工具,通过它对集群本身进行管理
kubectl [command] [type] [name] [flags]
command
:指定要对资源执行的操作,比如create、get、delete
type
:指定资源类型,比如deployment、pod、service
name
:指定资源名称,大小写敏感
flags
:指定额外的可选参数
-o
:格式化显示。-o=yaml,yaml格式显示结果;-o=wide,详细信息
-n/--namespace
:查看指定的命名空间,后跟 namespace
--images
:指定镜像
--port
:暴露端口
# 查看所有pod kubectl get pod# 查看某个pod kubectl get pod pod_name# 查看某个pod,yml输出 kubectl get pod pod_name -o=yml
command操作
命令分类
命令
翻译
命令作用
基本命令
create
创建
创建一个资源
edit
编辑
编辑一个资源
get
获取
获取一个资源
patch
更新
更新一个资源
delete
删除
删除一个资源
explain
解释
展示资源文档
运行和调试
run
运行
在集群中运行一个指定的镜像
expose
暴露
暴露资源为Service
describe
描述
显示资源内部信息
logs
日志输出容器在 pod 中的日志
输出容器在 pod 中的日志
attach
缠绕进入运行中的容器
进入运行中的容器
exec
执行容器中的一个命令
执行容器中的一个命令
cp
复制
在Pod内外复制文件
rollout
首次展示
管理资源的发布
scale
规模
扩(缩)容Pod的数量
autoscale
自动调整
自动调整Pod的数量
高级命令
apply
create/patch
通过文件对资源进行配置
label
标签
更新资源上的标签
其他命令
cluster-info
集群信息
显示集群信息
version
版本
显示当前Server和Client的版本
type资源 kubernetes中所有的内容都抽象为资源,可以通过下面的命令进行查看:
资源分类
资源名称
缩写
资源作用
集群级别资源
nodes
no
集群组成部分
namespaces
ns
隔离Pod
pod资源
pods
po
装载容器
pod资源控制器
replicationcontrollers
rc
控制pod资源
replicasets
rs
控制pod资源
deployments
deploy
控制pod资源
daemonsets
ds
控制pod资源
jobs
控制pod资源
cronjobs
cj
控制pod资源
horizontalpodautoscalers
hpa
控制pod资源
statefulsets
sts
控制pod资源
服务发现资源
services
svc
统一pod对外接口
ingress
ing
统一pod对外接口
存储资源
volumeattachments
存储
persistentvolumes
pv
存储
persistentvolumeclaims
pvc
存储
配置资源
configmaps
cm
配置
secrets
配置
下面以一个namespace / pod的创建和删除简单演示下命令的使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 # 创建一个namespace,名为dev [root@master ~]# kubectl create namespace dev namespace/dev created# 获取namespace [root@master ~]# kubectl get ns NAME STATUS AGE default Active 21h dev Active 21s kube-node-lease Active 21h kube-public Active 21h kube-system Active 21h# 在此namespace下创建并运行一个nginx的Pod [root@master ~]# kubectl run pod --image=nginx:latest -n dev# 查看namespace下的pod,不加-n dev默认查询-n default [root@master ~]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE pod 1/1 Running 0 21s# 删除指定的pod [root@master ~]# kubectl delete pod pod-864f9875b9-pcw7x pod "pod" deleted# 删除指定的namespace [root@master ~]# kubectl delete ns dev namespace "dev" deleted
3.命令式对象配置 命令式对象管理 使用命令 + 各种参数
命令式对象配置 使用命令 + 配置文件,配置文件写的就是各种参数
创建一个nginx-pod.yaml文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 apiVersion: v1 kind: Namespace metadata: name: dev --- apiVersion: v1 kind: Pod metadata: name: nginxpod namespace: dev spec: containers: - name: nginx-containers image: nginx:latest
执行create命令,创建资源
[root@master ~]# kubectl create -f nginxpod.yaml namespace/dev created pod/nginxpod created
执行get命令,查看资源
# 查看namespace [root@master ~]# kubectl get ns dev# 查看pod [root@master ~]# kubectl get pod -n dev# 一起查看,通过nginxpod.yaml [root@master ~]# kubectl get -f nginxpod.yaml
执行delete命令,删除资源
[root@master ~]# kubectl delete -f nginxpod.yaml namespace "dev" deleted pod "nginxpod" deleted
4.声明式对象配置 只有一个命令apply
# 首先执行一次kubectl apply -f yaml文件,发现创建了资源 [root@master ~]# kubectl apply -f nginxpod.yaml namespace/dev created pod/nginxpod created# 再次执行一次kubectl apply -f yaml文件,发现说资源没有变动 [root@master ~]# kubectl apply -f nginxpod.yaml namespace/dev unchanged pod/nginxpod unchanged
声明式对象配置就是使用apply
描述一个资源最终的状态(在yaml中定义状态) 使用apply
操作资源: 如果资源不存在,就创建,相当于kubectl create
如果资源已存在,就更新,相当于kubectl patch
三、Namespace 默认情况下,Pod是可以相互访问的,如果不想让两个Pod之间互相访问,就可以将两个Pod划分到不同的namespace下。k8s通过将集群内部的资源分配到不同的namespace中,形成逻辑上的组,方便不同的组的资源进行隔离使用和管理
可以通过kubernetes的授权机制,将不同的namespace交给不同租户进行管理,这样就实现了多租户的资源隔离。此时还能结合kubernetes的资源配额机制,限定不同租户能占用的资源,例如CPU使用量、内存使用量等等,来实现租户可用资源的管理
命令方式
# 查看 # Active 命名空间正在使用中 Terminating 正在删除命名空间 [root@master]# kubectl get namespace NAME STATUS AGE default Active 45h # 所有未指定Namespace的对象都会被分配在default命名空间 kube-node-lease Active 45h # 集群节点之间的心跳维护,v1.13开始引入 kube-public Active 45h # 此命名空间下的资源可以被所有人访问(包括未认证用户) kube-system Active 45h # 所有由Kubernetes系统创建的资源都处于这个命名空间# 创建 [root@master]# kubectl create ns njm namespace/njm created# 删除 [root@master]# kubectl delete ns njm namespace "njm" deleted
配置方式
ns-dev.yaml
apiVersion: v1 kind: Namespace metadata: name: dev
创建和删除命令
kubectl create -f ns-dev.yaml kubectl delete -f ns-dev.yaml
四、Label 在资源上添加标识,用来对它们进行区分和选择。在后续的pod控制器和Service都是通过label来管理pod
namespace可以实现环境隔离,比如隔离dev环境和test环境。而dev环境下又有前端和后端项目,前后端项目之间需要通信,所以不能用namespace,就需要使用Label
namespace隔离了pod, 所以通过label分组,但不隔离
特点:
一个Label会以key/value键值对的形式附加到各种对象上,如Node、Pod、Service等
一个资源对象可以定义任意数量的Label ,同一个Label也可以被添加到任意数量的资源对象上去
Label通常在资源对象定义时确定,也可以在对象创建后动态添加或者删除
标签定义完毕之后,还要考虑到标签的选择,这就要使用到Label Selector
Label用于给某个资源对象定义标识
Label Selector用于查询指定标签的资源对象
基于等式的Label Selector:name=slave
基于集合的Label Selector:name in (master,slave)
命令方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # 打标签 kubectl label 资源类型 资源名 标签 [root@master ~]# kubectl label pod nginx-pod -n dev version=1.0 pod/nginx-pod labeled# 查看标签--show-labels [root@master ~]# kubectl get pod nginx-pod -n dev --show-labels NAME READY STATUS RESTARTS AGE LABELS nginx-pod 1/1 Running 0 10m version=1.0# 修改标签--overwrite [root@master ~]# kubectl label pod nginx-pod version=2.0 -n dev --overwrite pod/nginx-pod labeled# 筛选pod,根据标签 [root@master ~]# kubectl get pod -n dev -l version=2.0 --show-labels# 删除标签 标签名- [root@master ~]# kubectl label pod nginx-pod -n dev version-
配置方式
pod-nginx.yaml
apiVersion: v1 kind: Pod metadata: name: nginx namespace: dev labels: version: "3.0" env: "test" spec: containers: - image: nginx:latest name: pod ports: - name: nginx-port containerPort: 80 protocol: TCP
执行命令:kubectl apply -f pod-nginx.yaml
五、Pod 1.入门 Pod是kubernetes集群进行管理的最小单元,程序要运行必须部署在容器中,而容器必须存在于Pod中
Pod可以认为是容器的封装,Pod中可包含一个或多个容器,容器可分为两类
用户程序定义的容器
Pause容器。这是每个Pod都会有的一个根容器 ,作用:
以它为依据,评估整个Pod的健康状态
可以在根容器设置ip地址,其他容器共享此ip,实现Pod内部网络通讯
查看Pod
# -n kube-system 查看命名空间为kube-system的pod kubectl get pod -n kube-system
创建并运行
# 命令格式: kubectl run (pod名称) [参数] # --image 指定Pod的镜像 # --port 指定端口 # --namespace 指定namespace # 运行一个名称为nginx的pod [root@master ~]# kubectl run nginx --image=nginx:latest --port=80 --namespace dev pod/nginx created
查看Pod ,注意要加上命名空间
# 查看Pod基本信息 [root@master ~]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE nginx 1/1 Running 0 43s# 查看Pod的详细信息 [root@master ~]# kubectl describe pod nginx -n dev
删除Pod
[root@master ~]# kubectl delete pod nginx -n dev
通过配置文件操作
nginx-pod.yaml
apiVersion: v1 kind: Pod metadata: name: nginx namespace: dev spec: containers: - image: nginx:latest name: pod ports: - name: nginx-port containerPort: 80 protocol: TCP
创建和删除命令:
kubectl create -f nginx-pod.yaml kubectl delete -f nginx-pod.yaml
2.配置 可以使用explain查看某种类型的可配置项
kebectl explain 资源类型
查看一级属性
kebectl explain 资源类型.属性
查看属性的子属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 [root@k8s-master01 ~]# kubectl explain pod KIND: Pod VERSION: v1 FIELDS: #一级属性 apiVersion <string> kind <string> metadata <Object> spec <Object> status <Object> [root@k8s-master01 ~]# kubectl explain pod.metadata KIND: Pod VERSION: v1 RESOURCE: metadata <Object> FIELDS: # pod的metadate属性 annotations <map[string]string> clusterName <string> creationTimestamp <string> deletionGracePeriodSeconds <integer> deletionTimestamp <string> finalizers <[]string> generateName <string> generation <integer> labels <map[string]string> managedFields <[]Object> name <string> namespace <string> ownerReferences <[]Object> resourceVersion <string> selfLink <string> uid <string>
一级属性:
apiVersion :版本,由k8s内部定义,版本号必须可以用 kubectl api-versions
查询到
kind :资源类型,由k8s内部定义,版本号必须可以用 kubectl api-resources
查询到
metadata :元数据,主要是资源标识和说明,常用的有name、namespace、labels等
spec :描述 ,这是配置中最重要的一部分,里面是对各种资源配置的详细描述
status :状态信息,不需要定义,由k8s自动生成
spec的常见子属性:
containers <[]Object>:容器列表,定义容器的详细信息
nodeName <[]Object>:根据nodeName将pod调度至指定的Node节点上
nodeSelector <map[]>:根据NodeSelector(标签)将pod调度到包含这些label的Node节点上
hostNetwork :是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
volumes <[]Object> 存储卷,用于定义Pod上面挂在的存储信息
restartPolicy 重启策略,表示Pod在遇到故障的时候的处理策略
基本配置
2.配置中介绍的都是containers 的子属性
pod.spec.containers
属性
[root@k8s-master01 ~]# kubectl explain pod.spec.containers KIND: Pod VERSION: v1 RESOURCE: containers <[]Object> # 数组,代表可以有多个容器 FIELDS: name <string> # 容器名称 image <string> # 容器需要的镜像地址 imagePullPolicy <string> # 镜像拉取策略 command <[]string> # 容器的启动命令列表,如不指定,使用打包时使用的启动命令 args <[]string> # 容器的启动命令需要的参数列表 env <[]Object> # 容器环境变量的配置 ports <[]Object> # 容器需要暴露的端口号列表 resources <Object> # 资源限制和资源请求的设置
创建pod-base.yaml文件
创建pod,名为pod-base,命名空间为dev,标签user:niujiaming。创建了两个容器
apiVersion: v1 kind: Pod metadata: name: pod-base namespace: dev labels: user: niujiaming spec: containers: - name: nginx01 image: nginx:1.17.1 - name: nginx02 image: nginx
# 创建Pod [root@k8s-master01 pod]# kubectl apply -f pod-base.yaml pod/pod-base created# 查看Pod状况 [root@k8s-master01 pod]# kubectl get pod -n dev# 可以通过describe查看内部的详情 [root@k8s-master01 pod]# kubectl describe pod pod-base -n dev
镜像拉取策略 创建pod-imagepullpolicy.yaml文件
imagePullPolicy,用于设置镜像拉取策略
Always:一直远程下载
IfNotPresent:本地有就本地 本地没远程下载
Never:一直使用本地
如果镜像tag为具体版本号,拉取策略为IfNotPresent
如果没有镜像tag(默认latest),拉取策略为Always
apiVersion: v1 kind: Pod metadata: name: pod-imagepullpolicy namespace: dev spec: containers: - name: nginx image: nginx:1.17.1 imagePullPolicy: Never - name: nginx02 image: nginx
启动命令 用于在pod中的容器初始化完毕之后运行一个命令
apiVersion: v1 kind: Pod metadata: name: pod-command namespace: dev spec: containers: - name: busybox image: busybox:1.30 command: ["/bin/sh","-c","touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt; sleep 3; done;"]
“/bin/sh”,”-c”, 使用sh执行命令
touch /tmp/hello.txt; 创建一个/tmp/hello.txt 文件
while true;do /bin/echo $(date +%T) >> /tmp/hello.txt; sleep 3; done; 每隔3秒向文件中写入当前时间
# 创建Pod [root@k8s-master01 pod]# kubectl create -f pod-command.yaml# 进入pod中的busybox容器,查看文件内容 # kubectl exec pod名称 -n 命名空间 -it -c 容器名称 /bin/sh 在容器内部执行的命令 # 使用这个命令就可以进入某个容器的内部,然后进行相关操作了 # 比如,可以查看txt文件的内容 [root@k8s-master01 pod]# kubectl exec pod-command -n dev -it -c busybox /bin/sh / # tail -f /tmp/hello.txt 14:44:19 14:44:22 14:44:25
args
command已经可以完成启动命令和传递参数的功能,为什么这里还要提供一个args选项,用于传递参数呢?这其实跟docker有点关系,kubernetes中的command、args两项其实是实现覆盖Dockerfile中ENTRYPOINT的功能。
如果command和args均没有写,那么用Dockerfile的配置。
如果command写了,但args没有写,那么Dockerfile默认的配置会被忽略,执行输入的command
如果command没写,但args写了,那么Dockerfile中配置的ENTRYPOINT的命令会被执行,使用当前args的参数
如果command和args都写了,那么Dockerfile的配置被忽略,执行command并追加上args参数
环境变量 env,用于在pod容器中设计环境变量
apiVersion: v1 kind: Pod metadata: name: envar-demo labels: purpose: demonstrate-envars spec: containers: - name: envar-demo-container image: gcr.io/google-samples/node-hello:1.0 env: - name: DEMO_GREETING value: "Hello from the environment"
运行后使用kubectl exec -it envar-demo -- /bin/bash
进入容器中,使用printenv
查看环境变量
端口设置 ports支持的子选项
[root@k8s-master ~]# kubectl explain pod.spec.containers.ports KIND: Pod VERSION: v1 RESOURCE: ports <[]Object> FIELDS: containerPort<integer> #容器端口。必填,容器要监听的端口 hostIP <string> #主机IP。要将外部端口绑定到主机IP,一般省略 hostPort <integer> #主机端口。容器要在主机上公开的端口,一般省略 name <string> #端口名字 protocol <string> #端口协议,默认TCP
pod-ports.yaml
apiVersion: v1 kind: Pod metadata: name: pod-ports namespace: dev spec: containers: - name: nginx image: nginx:1.17.10 ports: - name: nginx-port containerPort: 80 protocol: TCP
资源配额 程序运行要占用资源,如果不对某个容器的资源做限制,那么它就可能吃掉大量资源,导致其他容器无法运行。k8s通过resources 选项实现资源分配,它有两个子选项规定容器的上下限:
pod-resources.yaml
apiVersion: v1 kind: Pod metadata: name: pod-resources namespace: dev spec: containers: - name: nginx image: nginx:1.17.1 resources: # 资源配额 limits: # 限制资源(上限) cpu: "2" # CPU限制,单位是core数 memory: "10Gi" #内存大小,可以使用Gi、Mi、G、M等形式 requests: # 请求资源(下限) cpu: "1" memory: "10Mi"
3.生命周期 pod对象从创建到终止 的这段时间范围称为pod的生命周期,包括:
pod创建过程
运行初始化容器(init container)过程
运行主容器(main container 用户容器)过程
容器启动后钩子(post start)、容器终止前钩子(pre stop)
容器的存活性探测(liveness probe)、就绪性探测(readiness probe)
pod终止过程
在整个生命周期中,Pod会出现5种状态 (相位 ),分别如下:
挂起(Pending):apiserver已经创建了pod资源对象,但它尚未被调度完成或者仍处于下载镜像的过程中
运行中(Running):pod已经被调度至某节点,并且所有容器都已经被kubelet创建完成
成功(Succeeded):pod中的所有容器都已经成功终止并且不会被重启
失败(Failed):所有容器都已经终止,但至少有一个容器终止失败,即容器返回了非0值的退出状态
未知(Unknown):apiserver无法正常获取到pod对象的状态信息,通常由网络通信失败所导致
创建和终止 pod的创建过程
用户通过kubectl
提交要创建的pod信息给apiServer
apiServer
生成pod对象信息并存入etcd,然后确认信息
apiServer
开始反应etcd中pod对象的变化,其他组件使用watch机制来跟踪检查apiService
上的变动
scheduler
发现有新的pod要创建,为pod分配主机并将结果更新给apiServer
node节点的kubectl
发现有pod调度过来,尝试用docker启动容器,并将结果返回给apiServer
apiServer
将接收到的pod状态信息存入etcd中
pod的终止过程
用户通过kubectl
提交要删除的pod信息给apiServer
在删除前需要停止容器,在宽限期内(默认30s),pod被视为dead
将pod标记为terminating状态
kubectl
监控到pod处于terminating状态,同时启动pod关闭过程
端点控制器监控到pod对象的关闭行为时将其从所有匹配到此端点的service资源的端点列表中移除
如果pod定义了preStop钩子处理器,则在其标记为terminating后会以同步的方式启动执行
pod容器进程收到停止信号
宽限期结束后,若pod还存在运行的进程,那么pod对象会收到立即终止的信号
kubectl
请求apiServer
将此pod资源的宽限期设置为0从而完成删除
初始化容器 初始化容器不是一个动作,而是在pod主容器启动之前要运行的容器,主要是做一些主容器的前置工作(比如环境),具有两大特征:
初始化容器必须运行完成直至结束,若某初始化容器运行失败,那么k8s需要重启它直到成功完成
初始化容器必须按照定义的顺序执行,当前一个成功后,后面的一个才能运行(初始化容器有多个)
初始化容器有很多的应用场景,比如:
提供主容器镜像中不具备的工具程序或自定义代码
初始化容器要先于应用容器串行启动并运行成功,可用于延后应用容器的启动(类似DockerCompose中的depends_on依赖关系)
pod-initcontainer.yaml
initContainers属性和containers是同级的
apiVersion: v1 kind: Pod metadata: name: pod-initcontainer namespace: dev spec: containers: - name: main-container image: nginx:1.17.1 ports: - name: nginx-port containerPort: 80 initContainers: - name: xxxx image: xxxx
钩子函数 钩子函数能够感知自身生命周期中的事件,并在相应的时刻到来时运行用户指定的程序代码。
类似初始化容器,不过初始化容器的单位是容器,容器启动成功则继续,而这个是函数
kubernetes在主容器的启动之后 和停止之前 提供了两个钩子函数:
post start:容器创建之后 执行,如果失败了会重启容器
pre stop :容器终止之前 执行,执行完成之后容器将成功终止,在其完成之前会阻塞删除容器的操作
钩子处理器提供了三种方式定义动作:
Exec命令:在容器内执行一次命令
lifecycle: postStart: exec: command: - cat - /tmp/healthy
TCPSocket:在当前容器尝试访问指定的socket
lifecycle: postStart: tcpSocket: port: 8080
HTTPGet:在当前容器中向某url发起http请求
lifecycle: postStart: httpGet: path: / port: 80 host: 192.168 .70 .28 scheme: HTTP
exec 例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 apiVersion: v1 kind: Pod metadata: name: pod-hook-exec namespace: dev spec: containers: - name: main-container image: nginx:1.17.1 ports: - name: nginx-port containerPort: 80 lifecycle: postStart: exec: command: ["/bin/sh" , "-c" , "echo postStart... > /usr/share/nginx/html/index.html" ] preStop: exec: command: ["/usr/sbin/nginx" ,"-s" ,"quit" ]
[root@k8s-master hook-test] pod/pod-hook-exec created [root@k8s-master hook-test] NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-hook-exec 1/1 Running 0 15s 172.29.16.32 192.168.70.28 <none> <none> [root@k8s-master hook-test] postStart...
容器探测 容器探测用于检测容器中的应用实例是否正常工作,是保障业务可用性的一种传统机制。如果经过探测,实例的状态不符合预期,那么kubernetes就会把该问题实例” 摘除 “,不承担业务流量。kubernetes提供了两种探针来实现容器探测,分别是:
liveness probes:存活性探针,用于检测应用实例当前是否处于正常运行状态 ,如果不是,k8s会重启容器
readiness probes:就绪性探针,用于检测应用实例当前是否可以接收请求 ,如果不能,k8s不会转发流量(ready 变y为i加ness)
livenessProbe 决定是否重启容器
readinessProbe 决定是否将请求转发给容器
探针方式:
Exec命令:在容器内执行一次命令,如果命令执行的退出码为0,则认为程序正常,否则不正常
livenessProbe: exec: command: - cat - /tmp/healthy
TCPSocket:将会尝试访问一个用户容器的端口,如果能够建立这条连接,则认为程序正常,否则不正常
livenessProbe: tcpSocket: port: 8080
HTTPGet:调用容器内Web应用的URL,如果返回的状态码在200和399之间,则认为程序正常,否则不正常
livenessProbe: httpGet: path: / port: 80 host: 127.0 .0 .1 scheme: HTTP
liveness probes(存活性探针)例子
Exec命令 pod-liveness-exec.yaml
apiVersion: v1 kind: Pod metadata: name: pod-liveness-exec namespace: njm spec: containers: - name: nginx image: nginx ports: - name: nginx-port containerPort: 80 livenessProbe: exec: command: ["/bin/cat" ,"/tmp/hello.txt" ]
# 创建 [root@k8s-master probes-test]# kubectl create -f pod-liveness-test.yaml pod/pod-liveness-exec created# 查看,RESTARTS重启了一次 [root@k8s-master probes-test]# kubectl get pod -n njm NAME READY STATUS RESTARTS AGE pod-liveness-exec 1/1 Running 1 63s
查看详情,提示探测失败,容器将被重启
TCPSocket pod-liveness-tcpsocket.yaml
apiVersion: v1 kind: Pod metadata: name: pod-liveness-tcpsocket namespace: njm spec: containers: - name: nginx image: nginx ports: - name: nginx-port containerPort: 80 livenessProbe: tcpSocket: port: 8080
同样的创建、查看
nginx的端口为80,所以会失败
HTTPGet pod-liveness-httpget.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 apiVersion: v1 kind: Pod metadata: name: pod-liveness-httpget namespace: njm spec: containers: - name: nginx image: nginx:1.17.1 ports: - name: nginx-port containerPort: 80 livenessProbe: httpGet: scheme: HTTP port: 80 path: /hello
出现404错误,将会重启
重启策略 探测中如果容器出了问题会重启,而重启是由重启策略决定的,有三种:
Always(默认):容器失效时,自动重启该容器
OnFailure: 容器终止运行且退出码不为0时重启
Never: 不论状态为何,都不重启该容器
重启策略适用于pod对象中的所有容器,首次需要重启的容器,将在其需要时立即进行重启,随后再次需要重启的操作将由kubelet延迟一段时间后进行,且反复的重启操作的延迟时长以此为10s、20s、40s、80s、160s和300s(最大)
pod-restartpolicy.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 apiVersion: v1 kind: Pod metadata: name: pod-restartpolicy namespace: njm spec: containers: - name: nginx image: nginx:1.17.1 ports: - name: nginx-port containerPort: 80 livenessProbe: httpGet: scheme: HTTP port: 80 path: /hello restartPolicy: Never
探测失败后停止容器
4.调度 Pod在哪个node节点上运行,是由scheduler组件决定的,这个过程不受人工控制。如果我们想控制某些Pod到达某些节点上,就需要改变调度规则,k8s提供了4种调度方式
自动调度:顾名思义,自动
定向调度:NodeName、NodeSelector
亲和性调度:NodeAffinity、PodAffinity、PodAntiAffinity
污点(容忍)调度:Taints、Toleration
定向调度 通过在pod上声明nodeName或nodeSelector,以此将Pod调度到期望的node节点上
NodeName NodeName强制将Pod调度到指定的Name的Node节点上(即使NodeName不存在),跳过了scheduler
创建一个pod-nodename.yaml文件
nodeName是pod的属性,和containers同级
apiVersion: v1 kind: Pod metadata: name: pod-nodename namespace: njm spec: containers: - name: nginx image: nginx:1.17.1 nodeName: node1
# 创建 [root@k8s-master dispatch-test]# kubectl create -f pod-nodename.yaml pod/pod-nodename created# 查看,由于不存在node3节点,所以pod无法正常运行 [root@k8s-master dispatch-test]# kubectl get pod -n njm -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-nodename 0/1 Pending 0 45s <none> node1 <none> <none>
NodeSelector NodeSelector用于将pod调度到添加了指定标签的node节点上。它是通过kubernetes的label-selector机制实现的,也就是说,在pod创建之前,会由scheduler使用MatchNodeSelector调度策略进行label匹配,找出目标node,然后将pod调度到目标节点,该匹配规则是强制约束
需要先给node节点添加标签
创建一个pod-nodeselector.yaml
apiVersion: v1 kind: Pod metadata: name: pod-nodeselector namespace: njm spec: containers: - name: nginx image: nginx:1.17.1 nodeSelector: nodeenv: pro
创建并运行,提示node selector匹配失败的提示
亲和性调度 它在NodeSelector的基础之上的进行了扩展,可以通过配置的形式,实现优先选择满足条件的Node进行调度,如果没有,也可以调度到不满足条件的节点 上,使调度更加灵活
Affinity 主要分为三类:
nodeAffinity (node亲和性): 以node为目标,解决pod可以调度到哪些node 的问题
podAffinity (pod亲和性) : 以pod为目标,解决pod可以和哪些已存在的pod部署在同一个 拓扑域中的问题
podAntiAffinity (pod反亲和性) : 以pod为目标,解决pod不能和哪些已存在pod部署在同一个 拓扑域中的问题
关于亲和性(反亲和性)使用场景的说明:
亲和性 :如果两个应用频繁交互,那就有必要利用亲和性让两个应用的尽可能的靠近,这样可以减少因网络通信而带来的性能损耗
反亲和性 :当应用的采用多副本部署时,有必要采用反亲和性让各个应用实例打散分布在各个node上,这样可以提高服务的高可用
NodeAffinity NodeAffinity主要实现以Node为参照,实现让新创建的Pod在指定的Node中
NodeAffinity
的可配置项:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 pod.spec.affinity.nodeAffinity requiredDuringSchedulingIgnoredDuringExecution #Node节点必须满足指定的所有规则才可以,相当于硬限制 nodeSelectorTerms #节点选择列表 matchFields #按节点字段列出的节点选择器要求列表 matchExpressions #按节点标签列出的节点选择器要求列表(推荐) key #键 values #值 operat or #关系符 支持Exists, DoesNotExist, In, NotIn, Gt, Lt preferredDuringSchedulingIgnoredDuringExecution #优先调度到满足指定的规则的Node,相当于软限制 (倾向) preference #一个节点选择器项,与相应的权重相关联 matchFields #按节点字段列出的节点选择器要求列表 matchExpressions #按节点标签列出的节点选择器要求列表(推荐) key #键 values #值 operator #关系符 支持In, NotIn, Exists, DoesNotExist, Gt, Lt weight #倾向权重,在范围1-100
关系符的使用说明: - matchExpressions: - key: nodeenv # 匹配存在标签的key为nodeenv的节点 operator: Exists - key: nodeenv # 匹配标签的key为nodeenv,且value是"xxx"或"yyy"的节点 operator: In values: ["xxx","yyy"] - key: nodeenv # 匹配标签的key为nodeenv,且value大于"xxx"的节点 operator: Gt values: "xxx"
演示preferredDuringSchedulingIgnoredDuringExecution
创建pod-nodeaffinity-preferred.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 apiVersion: v1 kind: Pod metadata: name: pod-nodeaffinity-preferred namespace: njm spec: containers: - name: nginx image: nginx:1.17.1 affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: nodeenv operator: In values: ["xxx" ,"yyy" ]
NodeAffinity规则设置的注意事项:
1. 如果同时定义了nodeSelector和nodeAffinity,那么必须两个条件都得到满足,Pod才能运行在指定的Node上
2. 如果nodeAffinity指定了多个nodeSelectorTerms,那么只需要其中一个能够匹配成功即可
3. 如果一个nodeSelectorTerms中有多个matchExpressions ,则一个节点必须满足所有的才能匹配成功
4. 如果一个pod所在的Node在Pod运行期间其标签发生了改变,不再符合该Pod的节点亲和性需求,则系统将忽略此变化
PodAffinity PodAffinity主要实现以运行的Pod为参照,实现让新创建的Pod跟参照pod在一个区域的功能
PodAffinity
的可配置项:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 pod.spec.affinity.podAffinity requiredDuringSchedulingIgnoredDuringExecution #硬限制 namespaces #指定参照pod的namespace topologyKey #指定调度作用域 labelSelector #标签选择器 matchExpressions #按节点标签列出的节点选择器要求列表(推荐) key #键 values #值 operator #关系符 支持In, NotIn, Exists, DoesNotExist. matchLabels #指多个matchExpressions映射的内容 preferredDuringSchedulingIgnoredDuringExecution #软限制 podAffinityTerm #选项 namespaces topologyKey labelSelector matchExpressions key #键 values #值 operator matchLabels weight #倾向权重,在范围1-100
topologyKey用于指定调度时作用域,例如: 如果指定为kubernetes.io/hostname,那就是以Node节点为区分范围 如果指定为beta.kubernetes.io/os,则以Node节点的操作系统类型来区分
演示requiredDuringSchedulingIgnoredDuringExecution
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 apiVersion: v1 kind: Pod metadata: name: pod-podaffinity-required namespace: njm spec: containers: - name: nginx image: nginx:1.17.1 affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: podenv operator: In values: ["xxx" ,"yyy" ] topologyKey: kubernetes.io/hostname
上面配置表达的意思是:新Pod必须要与拥有标签nodeenv=xxx或者nodeenv=yyy的pod在同一Node上
PodAntiAffinity PodAntiAffinity主要实现以运行的Pod为参照,让新创建的Pod跟参照pod不在一个区域中
配置方式和选项跟PodAffinty是一样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 apiVersion: v1 kind: Pod metadata: name: pod-podantiaffinity-required namespace: njm spec: containers: - name: nginx image: nginx:1.17.1 affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: podenv operator: In values: ["pro" ] topologyKey: kubernetes.io/hostname
污点和容忍 污点(Taints) 前面的调度方式都是站在Pod的角度上,通过Pod,决定Pod要调度到哪一个Node 上,我们也可以站在Node的角度上,通过在Node上添加污点 属性,来决定Node是否允许Pod调度过来
Node被设置上污点之后就和Pod之间存在了一种相斥的关系,进而拒绝Pod调度进来,甚至可以将已经存在的Pod驱逐出去
污点的格式为:key=value:effect
, key和value是污点的标签,effect描述污点的作用,有三个选项:
PreferNoSchedule(委婉拒绝,除非没办法) :将尽量避免 把Pod调度到具有该污点的Node上,除非没有其他节点可调度
NoSchedule(拒绝新的pod) :将不会 把Pod调度到具有该污点的Node上,但不会影响当前Node上已存在的Pod
NoExecute(拒绝新的pod和在这的pod) :将不会 把Pod调度到具有该污点的Node上,同时也会将Node上已存在的Pod驱离
使用kubectl设置和去除污点的命令示例如下:
kubectl taint nodes 节点名 污点
# 设置污点 kubectl taint nodes node1 key=value:effect# 去除某个污点 kubectl taint nodes node1 key:effect-# 去除所有污点 kubectl taint nodes node1 key-# 为node1设置污点(PreferNoSchedule) [root@k8s-master01 ~]# kubectl taint nodes node1 tag=taint:PreferNoSchedule
容忍(Toleration) 上面介绍了污点的作用,我们可以在node上添加污点用于拒绝pod调度上来,但是如果就是想将一个pod调度到一个有污点的node上去,这时候应该怎么做呢?这就要使用到容忍
污点就是拒绝,容忍就是忽略,Node通过污点拒绝pod调度上去,Pod通过容忍忽略拒绝
apiVersion: v1 kind: Pod metadata: name: pod-toleration namespace: njm spec: containers: - name: nginx image: nginx:1.17.1 tolerations: - key: "tag" operator: "Equal" value: "taint" effect: "NoExecute"
容忍的详细配置:
[root@k8s-master01 ~]# kubectl explain pod.spec.tolerations ...... FIELDS: key # 对应着要容忍的污点的键,空意味着匹配所有的键 value # 对应着要容忍的污点的值 operator # key-value的运算符,支持Equal和Exists(默认) effect # 对应污点的effect,空意味着匹配所有影响 tolerationSeconds # 容忍时间, 当effect为NoExecute时生效,表示pod在Node上的停留时间
六、Pod控制器 按照pod的创建方式可以分为两类:
自主式pod:直接创建出来的pod ,这种pod删除后就没有了,也不会重建
控制器创建的pod:通过控制器创建的pod ,这种pod删除了之后还会自动重建
Pod控制器是管理pod的中间层,通过pod控制器,可以规定需要多少个什么样的pod,如果pod在运行出现故障,pod控制器会基于指定策略重启pod
pod控制器有很多种,每种都有自己的适合场景:
ReplicationController:已经被废弃,由ReplicaSet替代
ReplicaSet:保证副本数量一直维持在期望值,并支持pod数量扩缩容,镜像版本升级
Deployment :通过控制ReplicaSet来控制Pod,并支持滚动升级、回退版本
Horizontal Pod Autoscaler:可以根据集群负载自动水平调整Pod的数量,实现削峰填谷
DaemonSet:在集群中的指定Node上运行且仅运行一个副本,一般用于守护进程类的任务
Job:它创建出来的pod只要完成任务就立即退出,用于执行一次性任务
Cronjob:它创建的Pod和周期性的执行,用于执行周期性任务
StatefulSet:管理有状态应用
1.ReplicaSet(rs) 简称RS,主要保证一定数量的pod能够正常运行 ,它会持续监听这些pod的运行状态,一旦pod发生故障就会重启或重建,同时还支持对pod数量的扩缩容和版本镜像的升级
yaml文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 apiVersion: apps/v1 kind: ReplicaSet metadata: name: namespace: labels: controller: rs spec: replicas: 3 selector: matchLabels: app: nginx-pod matchExpressions: - {key: app , operator: In , values: [nginx-pod ]} template: metadata: labels: app: nginx-pod spec: containers: - name: nginx image: nginx:1.17.1 ports: - containerPort: 80
spec
下面几个选项:
replicas:指定副本数量,其实就是当前rs创建出来的pod的数量,默认为1
selector:选择器,它的作用是建立pod控制器和pod之间的关联关系,采用的Label Selector机制
在pod模板上定义label,在控制器上定义选择器,就可以表明当前控制器能管理哪些pod了
template:模板,就是当前控制器创建pod所使用的模板板,里面其实就是pod的定义
创建ReplicaSet
创建replicaset.yaml文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 apiVersion: apps/v1 kind: ReplicaSet metadata: name: pc-replicaset namespace: njm spec: replicas: 3 selector: matchLabels: app: nginx-pod template: metadata: labels: app: nginx-pod spec: containers: - name: nginx image: nginx:1.17.1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # 创建rs [root@k8s-master]# kubectl create -f replicaset.yaml replicaset.apps/pc-replicaset created# 查看rs # desire:期望副本数量 # current:当前副本数量 # ready:已经准备好提供服务的副本数量 [root@k8s-mastert]# kubectl get rs -n njm -o wide NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR pc-replicaset 3 3 3 2m8s nginx nginx:1.17.1 app=nginx-pod# 查看pod # 这里发现控制器创建出来的pod的名称是在控制器名称后面拼接了-xxxxx随机码 [root@k8s-master]# kubectl get pod -n njm NAME READY STATUS RESTARTS AGE pc-replicaset-84rcb 1/1 Running 0 3m35s pc-replicaset-k6rxm 1/1 Running 0 3m35s pc-replicaset-kmn5m 1/1 Running 0 3m35s
扩缩容
# 编辑rs的副本数量,修改spec:replicas: 6即可 [root@k8s-master01 ~]# kubectl edit rs pc-replicaset -n njm replicaset.apps/pc-replicaset edited# 当然也可以直接使用命令实现 # 使用scale命令实现扩缩容, 后面--replicas=n直接指定目标数量即可 [root@k8s-master01 ~]# kubectl scale rs pc-replicaset --replicas=2 -n njm replicaset.apps/pc-replicaset scaled
镜像更新
# 编辑rs的容器镜像 - image: nginx:1.17.2 [root@k8s-master01 ~]# kubectl edit rs pc-replicaset -n njm replicaset.apps/pc-replicaset edited# 使用命令kubectl set image rs rs名称 容器=镜像版本 -n namespace [root@k8s-master01 ~]# kubectl set image rs pc-replicaset nginx=nginx:1.17.2 -n njm replicaset.apps/pc-replicaset image updated
删除ReplicaSet
# 使用kubectl delete命令会删除此RS以及它管理的Pod # 在kubernetes删除RS前,会将RS的replicasclear调整为0,等待所有的Pod被删除后,在执行RS对象的删除 [root@k8s-master01 ~]# kubectl delete rs pc-replicaset -n dev replicaset.apps "pc-replicaset" deleted# 也可以使用yaml直接删除 [root@k8s-master01 ~]# kubectl delete -f pc-replicaset.yaml replicaset.apps "pc-replicaset" deleted# 如果只删除RS对象(保留Pod),可以使用添加--cascade=false (级联删除=false ) [root@k8s-master01 ~]# kubectl delete rs pc-replicaset -n dev --cascade=false replicaset.apps "pc-replicaset" deleted [root@k8s-master01 ~]# kubectl get pods -n dev NAME READY STATUS RESTARTS AGE pc-replicaset-cl82j 1/1 Running 0 75s pc-replicaset-dslhb 1/1 Running 0 75s
2.Deployment(deploy) Deployment 并不直接管理pod,而是通过管理ReplicaSet 来间接管理Pod,即:Deployment 管理ReplicaSet ,ReplicaSet 管理Pod ,所以Deployment 比ReplicaSet 功能更加强大
Deployment主要功能:
支持ReplicaSet的所有功能
支持发布的停止、继续
支持滚动升级和回滚版本
yaml文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 apiVersion: apps/v1 kind: Deployment metadata: name: namespace: labels: controller: deploy spec: replicas: 3 revisionHistoryLimit: 3 paused: false progressDeadlineSeconds: 600 strategy: type: RollingUpdate rollingUpdate: maxSurge: 30 % maxUnavailable: 30 % selector: matchLabels: app: nginx-pod matchExpressions: - {key: app , operator: In , values: [nginx-pod ]} template: metadata: labels: app: nginx-pod spec: containers: - name: nginx image: nginx:1.17.1 ports: - containerPort: 80
创建deployment 创建pc-deployment.yaml文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 apiVersion: apps/v1 kind: Deployment metadata: name: pc-deployment namespace: njm spec: replicas: 3 selector: matchLabels: app: nginx-pod template: metadata: labels: app: nginx-pod spec: containers: - name: nginx image: nginx:1.17.1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # 创建deployment [root@k8s-master]# kubectl create -f pc-deployment.yaml deployment.apps/pc-deployment created# 查看deployment # UP-TO-DATE 最新版本的pod的数量 # AVAILABLE 当前可用的pod的数量 [root@k8s-master]# kubectl get deploy -n njm NAME READY UP-TO-DATE AVAILABLE AGE pc-deployment 3/3 3 3 101s# 查看pod [root@k8s-master]# kubectl get pod -n njm NAME READY STATUS RESTARTS AGE pc-deployment-5d9c9b97bb-fs2cp 1/1 Running 0 3m pc-deployment-5d9c9b97bb-kch8l 1/1 Running 0 3m pc-deployment-5d9c9b97bb-rjns8 1/1 Running 0 3m
扩缩容 和rs差不多
# 第一种 变更副本数量为5个 [root@k8s-master01 ~]# kubectl scale deploy pc-deployment --replicas=5 -n njm deployment.apps/pc-deployment scaled# 第二种 编辑deployment的副本数量,修改spec:replicas: 4 [root@k8s-master01 ~]# kubectl edit deploy pc-deployment -n dev deployment.apps/pc-deployment edited
镜像更新 deployment支持两种更新策略:
重建更新:一次性删掉所有旧版本pod,立即重建同等数量的新版本pod
滚动更新(默认):先删一部分旧版本pod,再重建一部分新版本pod,以此类推
可以通过strategy
指定策略类型
strategy: 指定新的Pod替换旧的Pod的策略, 支持两个属性: type: 指定策略类型,支持两种策略 Recreate: 重建更新 RollingUpdate: 滚动更新中 rollingUpdate: 当type为RollingUpdate时生效,用于为RollingUpdate设置参数,支持两个属性: maxUnavailable: 用来指定在升级过程中不可用Pod的最大数量,默认为25%。 maxSurge: 用来指定在升级过程中可以超过期望的Pod的最大数量,默认为25%。
重建更新
spec: strategy: type: Recreate
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 # 变更镜像 [root@k8s-master]# kubectl set image deployment pc-deployment nginx=nginx -n njm deployment.apps/pc-deployment image updated# 查看 正在停止 [root@k8s-master]# kubectl get pod -n njm NAME READY STATUS RESTARTS AGE pc-deployment-7cbfc8fc88-2cpnp 1/1 Terminating 0 63s pc-deployment-7cbfc8fc88-gx4lq 1/1 Terminating 0 63s pc-deployment-7cbfc8fc88-v2b9t 1/1 Terminating 0 63s# 查看 正在创建 [root@k8s-master]# kubectl get pod -n njm NAME READY STATUS RESTARTS AGE pc-deployment-7cbfc8fc88-2cpnp 0/1 ContainerCreating 0 2s pc-deployment-7cbfc8fc88-gx4lq 0/1 ContainerCreating 0 2s pc-deployment-7cbfc8fc88-v2b9t 0/1 ContainerCreating 0 2s # 查看 正在运行 [root@k8s-master]# kubectl get pod -n njm NAME READY STATUS RESTARTS AGE pc-deployment-7cbfc8fc88-2cpnp 1/1 Running 0 63s pc-deployment-7cbfc8fc88-gx4lq 1/1 Running 0 63s pc-deployment-7cbfc8fc88-v2b9t 1/1 Running 0 63s
滚动更新
spec: strategy: type: RollingUpdate rollingUpdate: maxSurge: 25 % maxUnavailable: 25 %
其他都一样
版本回退 在滚动更新中原来的rs依旧存在 ,只是pod数量变为了0,而后又新产生了一个rs,pod数量为3 这就是deployment能够进行版本回退的原因
[root@k8s-master]# kubectl get rs -n njm NAME DESIRED CURRENT READY AGE pc-deployment-5d9c9b97bb 0 0 0 85s pc-deployment-7cbfc8fc88 3 3 3 14s
deployment支持版本升级过程中的暂停、继续功能以及版本回退等诸多功能
kubectl rollout: 版本升级相关功能,支持下面的选项:
status 显示当前升级状态
history 显示 升级历史记录
pause 暂停版本升级过程
resume 继续已经暂停的版本升级过程
restart 重启版本升级过程
undo 回滚到上一级版本(可以使用–to-revision回滚到指定版本)
# 查看当前升级版本的状态 [root@k8s-master]# kubectl rollout status deploy pc-deployment -n njm deployment "pc-deployment" successfully rolled out# 查看升级历史记录,有两个版本.CHANGE-CAUSE是因为在启动时没有加--record=true ,所以没有记录 [root@k8s-master]# kubectl rollout history deploy pc-deployment -n njm deployment.apps/pc-deployment REVISION CHANGE-CAUSE 1 <none> 2 <none>
版本回退
# 这里直接使用--to-revision=1回滚到了1版本, 如果省略这个选项,默认回退到上个版本 [root@k8s-master ]# kubectl rollout undo deployment pc-deployment --to-revision=1 -n njm deployment.apps/pc-deployment rolled back# 查看rs 发现第一个rs中变成了有3个pod运行 [root@k8s-master ]# kubectl get rs -n njm NAME DESIRED CURRENT READY AGE pc-deployment-5d9c9b97bb 3 3 3 12m pc-deployment-7cbfc8fc88 0 0 0 10m
其实deployment之所以可是实现版本的回滚,就是通过记录下历史rs来实现的,一旦想回滚到哪个版本,只需要将当前版本pod数量降为0,然后将回滚版本的pod提升为目标数量就可以了
3.DaemonSet(DS) DaemonSet控制器可以保证在集群中的每一台(或指定)节点上都运行一个副本。一般适用于日志收集、节点监控等场景。
也就是说,如果一个Pod提供的功能是节点级别的(每个节点都需要且只需要一个),那么这类Pod就适合使用DaemonSet类型的控制器创建。
DaemonSet控制器的特点:
每当向集群中添加一个节点时,指定的 Pod 副本也将添加到该节点上
当节点从集群中移除时,Pod 也就被垃圾回收了
yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 apiVersion: apps/v1 kind: DaemonSet metadata: name: namespace: labels: controller: daemonset spec: revisionHistoryLimit: 3 updateStrategy: type: RollingUpdate rollingUpdate: maxUnavailable: 1 selector: matchLabels: app: nginx-pod matchExpressions: - {key: app , operator: In , values: [nginx-pod ]} template: metadata: labels: app: nginx-pod spec: containers: - name: nginx image: nginx:1.17.1 ports: - containerPort: 80
4.Job 主要用于负责**批量处理(一次要处理指定数量任务)短暂的 一次性(每个任务仅运行一次就结束)**任务
当Job创建的pod执行成功结束时,Job将记录成功结束的pod数量
当成功结束的pod达到指定的数量时,Job将完成执行
yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 apiVersion: batch/v1 kind: Job metadata: name: namespace: labels: controller: job spec: completions: 1 parallelism: 1 activeDeadlineSeconds: 30 backoffLimit: 6 manualSelector: true selector: matchLabels: app: counter-pod matchExpressions: - {key: app , operator: In , values: [counter-pod ]} template: metadata: labels: app: counter-pod spec: restartPolicy: Never containers: - name: counter image: busybox:1.30 command: ["bin/sh" ,"-c" ,"for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 2;done" ]
restartPolicy重启策略: 如果指定为OnFailure,则job会在pod出现故障时重启容器,而不是创建pod,failed次数不变 如果指定为Never,则job会在pod出现故障时创建新的pod,并且故障pod不会消失,也不会重启,failed次数加1
创建job
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 apiVersion: batch/v1 kind: Job metadata: name: pc-job namespace: njm spec: manualSelector: true selector: matchLabels: app: counter-pod template: metadata: labels: app: counter-pod spec: restartPolicy: Never containers: - name: counter image: busybox:1.30 command: ["bin/sh" ,"-c" ,"for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 3;done" ]
# pod在运行完毕任务后,就会变成Completed状态 [root@k8s-master ]# kubectl get pod -n njm NAME READY STATUS RESTARTS AGE pc-job-hh9fs 1/1 Running 0 7s [root@k8s-master ]# kubectl get pod -n njm NAME READY STATUS RESTARTS AGE pc-job-hh9fs 0/1 Completed 0 35s
七、Service
每个Pod都会分配一个单独的Pod IP,但是该IP会随着Pod的重建而变化,且该IP为集群内部的虚拟IP,外部无法访问。因此kubernets设计了Service来解决这个问题
Service 会对提供同一个服务的多个pod进行聚合,并提供一个统一的入口地址。通过访问Service的入口地址就能访问到后面的pod服务
Service在很多情况下只是一个概念,真正起作用的其实是kube-proxy服务进程,每个Node节点上都运行着一个kube-proxy服务进程。当创建Service的时候会通过api-server向etcd写入创建的service的信息,而kube-proxy会基于监听的机制发现这种Service的变动,然后它会将最新的Service信息转换成对应的访问规则
两种不同的service类型
ClusterIP :Service 通过 Cluster 内部的 IP 对外提供服务,只有 Cluster 内的节点和 Pod 可访问,这是默认的 Service 类型
NodePort :Service 通过 Cluster 节点的静态端口对外提供服务。Cluster 外部可以通过 <NodeIP>:<NodePort>
访问 Service
1.命令方式 操作一:创建集群内部可访问的Service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # Service通过deployment找到要管理的pod # --name Service的名字 # --type Serive的类型,ClusterIP指集群内部可访问 # --port Service的端口 # --target-port 目标的端口 # -n 命名空间 [root@master ~]# kubectl expose deploy nginx --name=svc-nginx1 --type=ClusterIP --port=80 --target-port=80 -n dev service/svc-nginx1 exposed# 查看service,svc是service的缩写 # 这里产生了一个CLUSTER-IP,这就是service的IP,在Service的生命周期中,这个地址是不会变动的 [root@master ~]# kubectl get svc svc-nginx1 -n dev -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR svc-nginx1 ClusterIP 10.109.179.231 <none> 80/TCP 3m51s run=nginx# 访问,service会随机寻找一个 [root@master ~]# curl 10.109.179.231:80
操作二:创建集群外部可访问的Service
# 修改类型为NodePort [root@master ~]# kubectl expose deploy nginx --name=svc-nginx2 --type=NodePort --port=80 --target-port=80 -n dev# 查看 # 此时查看,会发现出现了NodePort类型的Service,而且有一对Port(80:31928) [root@master ~]# kubectl get svc svc-nginx2 -n dev -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR svc-nginx2 NodePort 10.100.94.0 <none> 80:31928/TCP 9s run=nginx# 接下来就可以通过集群外的主机访问 节点IP:31928访问服务了 # 电脑主机上通过浏览器访问下面的地址(master主机的地址)会跳转到service 10.100.94.0:80 http://192.168.90.100:31928/# 删除service [root@master ~]# kubectl delete svc svc-nginx-2 -n dev service "svc-nginx-1" deleted
2.配置方式
首先创建一个deployment管理pod
创建了三个httpd的pod,端口为80
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 kind: Deployment metadata: name: httpd namespace: njm spec: replicas: 3 selector: matchLabels: run: httpd template: metadata: labels: run: httpd spec: containers: - image: httpd name: httpd ports: - containerPort: 80
查看,三个pod的ip分别为.3、.4、.5
[root@k8s-master service-test]# kubectl get pod -n njm -o wide NAME READY STATUS RESTARTS AGE IP NODE httpd-5dcdfd6b9f-mgzgp 1/1 Running 0 36m 172.29.16.3 192.168.70.28 httpd-5dcdfd6b9f-ntr5x 1/1 Running 0 36m 172.29.16.4 192.168.70.28 httpd-5dcdfd6b9f-spf6n 1/1 Running 0 36m 172.29.16.5 192.168.70.28
创建service
nodePort
:(主机)节点的端口,省略的话随机分配
port
:service的端口
targetPort
:目标pod的端口
type
:service的类型
selector
:标签选择器,上一步deploy
标签为run: httpd
,这里对应
sessionAffinity
:session亲和性,支持ClientIP、None。比如三个pod位于A、B、C三个地区,对于来自A地区的请求要交给A地区的pod
apiVersion: v1 kind: Service metadata: name: httpd-service namespace: njm spec: selector: run: httpd ports: - port: 80 protocol: TCP targetPort: 80 clusterIP: 10. xx.xx.xx type: NodePort sessionAffinity:
查看
PORT(S)
为 80:58721
,80
是 service的端口(即port),58721
则是主机(或者节点)上监听的端口。每个节点都会监听此端口并将请求转发给 Service
[root@k8s-master service-test]# kubectl get svc -n njm NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE httpd-service NodePort 10.253.12.26 <none> 80:58721/TCP 23m
查看 httpd-svc 与 Pod 的对应关系
[root@k8s-master service-test]# kubectl describe service httpd-service -n njm Name: httpd-service Namespace: njm Labels: <none> Annotations: <none> Selector: run=httpd Type: NodePort IP: 10.253.12.26 Port: <unset> 80/TCP TargetPort: 80/TCP NodePort: <unset> 58721/TCP Endpoints: 172.29.16.3:80,172.29.16.4:80,172.29.16.5:80 Session Affinity: None External Traffic Policy: Cluster Events: <none>
访问
# 通过service的ip访问 [root@k8s-master ~]# curl 10.253.12.26:80 <html><body><h1>It works!</h1></body></html># 通过主机的ip访问 [root@k8s-master ~]# curl 192.168.70.28:58721 <html><body><h1>It works!</h1></body></html>
3.工作原理 使用iptables-save | grep serviceIP
查看规则
[root@k8s-master ~]# iptables-save | grep 10.253.12.26 -A KUBE-SERVICES ! -s 10.253.0.0/16 -d 10.253.12.26/32 -p tcp -m comment --comment "njm/httpd-service cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ -A KUBE-SERVICES -d 10.253.12.26/32 -p tcp -m comment --comment "njm/httpd-service cluster IP" -m tcp --dport 80 -j KUBE-SVC-6DSZY5JO37TTEYHN
这两条规则的含义是:
如果 Cluster 内的 Pod(源地址来自 10.253.0.0/16)要访问 httpd-service
,则允许
其他源地址访问 httpd-service
,跳转到规则KUBE-SVC-6DSZY5JO37TTEYHN
查看KUBE-SVC-6DSZY5JO37TTEYHN
规则
这三条规则的含义是:
1/3 的概率跳转到规则 KUBE-SEP-YZI6E5F46FBZHQJD
1/3 的概率(剩下 2/3 的一半)跳转到规则 KUBE-SEP-YZI6E5F46FBZHQJD
1/3 的概率跳转到规则 KUBE-SEP-YXWZPGCWM5AYTRC5
查看第一条KUBE-SEP-YZI6E5F46FBZHQJD
规则,最后会被转发到172.29.16.3
的pod80
端口上
查看这三条规则,iptables 将访问 Service 的流量转发到后端 Pod,而且使用类似轮询的负载均衡策略