k8s

一、简介

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:

  1. ”安装nginx服务的请求“发送至master节点的API Server组件
  2. API Server调用Scheduler组件做出决定(选择哪个node节点)。它会从etcd中读取node节点信息,根据一定的算法进行选择,并将结果告诉API Server
  3. API Server调用ControllerManager组件去安排这个决定(调度node节点安装nginx)
  4. ControllerManager将安排发送给KubeletKubelet接受到指令后,会通知Docker,由Docker启动一个nginx的pod(pod是k8s的最小操作单元,容器必须跑在pod中)
  5. 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的功能

image-20211207095642065

学习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集群的命令行工具,通过它对集群本身进行管理

1
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:暴露端口
1
2
3
4
5
6
#查看所有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中所有的内容都抽象为资源,可以通过下面的命令进行查看:

1
kubectl api-resources
资源分类 资源名称 缩写 资源作用
集群级别资源 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.命令式对象配置

命令式对象管理使用命令 + 各种参数

命令式对象配置使用命令 + 配置文件,配置文件写的就是各种参数

  1. 创建一个nginx-pod.yaml文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 创建namespace  dev
    apiVersion: v1
    kind: Namespace
    metadata:
    name: dev

    # ---分割文件,这是yaml的语法
    ---

    # 创建pod 名为nginxpod,命名空间为上一步创建的dev
    apiVersion: v1
    kind: Pod
    metadata:
    name: nginxpod
    namespace: dev
    spec:
    # 和docker差不多,指定容器名和镜像源
    containers:
    - name: nginx-containers
    image: nginx:latest
  2. 执行create命令,创建资源

    1
    2
    3
    [root@master ~]# kubectl create -f nginxpod.yaml
    namespace/dev created
    pod/nginxpod created
  3. 执行get命令,查看资源

    1
    2
    3
    4
    5
    6
    7
    #查看namespace
    [root@master ~]# kubectl get ns dev
    #查看pod
    [root@master ~]# kubectl get pod -n dev

    #一起查看,通过nginxpod.yaml
    [root@master ~]# kubectl get -f nginxpod.yaml
  4. 执行delete命令,删除资源

    1
    2
    3
    [root@master ~]# kubectl delete -f nginxpod.yaml
    namespace "dev" deleted
    pod "nginxpod" deleted

4.声明式对象配置

只有一个命令apply

1
2
3
4
5
6
7
8
9
# 首先执行一次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使用量、内存使用量等等,来实现租户可用资源的管理

命令方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 查看
# 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

1
2
3
4
apiVersion: v1
kind: Namespace
metadata:
name: dev

创建和删除命令

1
2
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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中

image-20211207143321015

Pod可以认为是容器的封装,Pod中可包含一个或多个容器,容器可分为两类

  • 用户程序定义的容器
  • Pause容器。这是每个Pod都会有的一个根容器,作用:
    • 以它为依据,评估整个Pod的健康状态
    • 可以在根容器设置ip地址,其他容器共享此ip,实现Pod内部网络通讯

查看Pod

1
2
# -n kube-system 查看命名空间为kube-system的pod 
kubectl get pod -n kube-system

创建并运行

1
2
3
4
5
6
7
8
# 命令格式: 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,注意要加上命名空间

1
2
3
4
5
6
7
# 查看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

1
[root@master ~]# kubectl delete pod nginx -n dev

通过配置文件操作

nginx-pod.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Pod
metadata:
# 这个name指的是pod
name: nginx
namespace: dev
spec:
containers:
- image: nginx:latest
name: pod
ports:
- name: nginx-port
containerPort: 80
protocol: TCP

创建和删除命令:

1
2
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 属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [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。创建了两个容器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 创建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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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中的容器初始化完毕之后运行一个命令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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秒向文件中写入当前时间

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # 创建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的功能。

    1. 如果command和args均没有写,那么用Dockerfile的配置。
    2. 如果command写了,但args没有写,那么Dockerfile默认的配置会被忽略,执行输入的command
    3. 如果command没写,但args写了,那么Dockerfile中配置的ENTRYPOINT的命令会被执行,使用当前args的参数
    4. 如果command和args都写了,那么Dockerfile的配置被忽略,执行command并追加上args参数

    环境变量

    env,用于在pod容器中设计环境变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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:
    # 定义一个名为DEMO_GREETING值为"Hello from the environment"的环境变量
    - name: DEMO_GREETING
    value: "Hello from the environment"

    运行后使用kubectl exec -it envar-demo -- /bin/bash进入容器中,使用printenv查看环境变量

    端口设置

    ports支持的子选项

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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选项实现资源分配,它有两个子选项规定容器的上下限:

    • requets:下限。设置容器需要的最小资源,不够不启动容器

    • limits:上限。限制运行时容器的最大占用资源,超过就重启容器

    pod-resources.yaml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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终止过程

    image-20211213150831069

    在整个生命周期中,Pod会出现5种状态相位),分别如下:

    • 挂起(Pending):apiserver已经创建了pod资源对象,但它尚未被调度完成或者仍处于下载镜像的过程中
    • 运行中(Running):pod已经被调度至某节点,并且所有容器都已经被kubelet创建完成
    • 成功(Succeeded):pod中的所有容器都已经成功终止并且不会被重启
    • 失败(Failed):所有容器都已经终止,但至少有一个容器终止失败,即容器返回了非0值的退出状态
    • 未知(Unknown):apiserver无法正常获取到pod对象的状态信息,通常由网络通信失败所导致

    创建和终止

    pod的创建过程

    1. 用户通过kubectl提交要创建的pod信息给apiServer
    2. apiServer生成pod对象信息并存入etcd,然后确认信息
    3. apiServer开始反应etcd中pod对象的变化,其他组件使用watch机制来跟踪检查apiService上的变动
    4. scheduler发现有新的pod要创建,为pod分配主机并将结果更新给apiServer
    5. node节点的kubectl发现有pod调度过来,尝试用docker启动容器,并将结果返回给apiServer
    6. apiServer将接收到的pod状态信息存入etcd中

    pod的终止过程

    1. 用户通过kubectl提交要删除的pod信息给apiServer
    2. 在删除前需要停止容器,在宽限期内(默认30s),pod被视为dead
    3. 将pod标记为terminating状态
    4. kubectl监控到pod处于terminating状态,同时启动pod关闭过程
    5. 端点控制器监控到pod对象的关闭行为时将其从所有匹配到此端点的service资源的端点列表中移除
    6. 如果pod定义了preStop钩子处理器,则在其标记为terminating后会以同步的方式启动执行
    7. pod容器进程收到停止信号
    8. 宽限期结束后,若pod还存在运行的进程,那么pod对象会收到立即终止的信号
    9. kubectl请求apiServer将此pod资源的宽限期设置为0从而完成删除

    初始化容器

    初始化容器不是一个动作,而是在pod主容器启动之前要运行的容器,主要是做一些主容器的前置工作(比如环境),具有两大特征:

    1. 初始化容器必须运行完成直至结束,若某初始化容器运行失败,那么k8s需要重启它直到成功完成
    2. 初始化容器必须按照定义的顺序执行,当前一个成功后,后面的一个才能运行(初始化容器有多个)

    初始化容器有很多的应用场景,比如:

    • 提供主容器镜像中不具备的工具程序或自定义代码
    • 初始化容器要先于应用容器串行启动并运行成功,可用于延后应用容器的启动(类似DockerCompose中的depends_on依赖关系)

    pod-initcontainer.yaml

    initContainers属性和containers是同级的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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 :容器终止之前执行,执行完成之后容器将成功终止,在其完成之前会阻塞删除容器的操作

    钩子处理器提供了三种方式定义动作:

    1. Exec命令:在容器内执行一次命令

      1
      2
      3
      4
      5
      6
      lifecycle:
      postStart:
      exec:
      command:
      - cat
      - /tmp/healthy
    2. TCPSocket:在当前容器尝试访问指定的socket

      1
      2
      3
      4
      lifecycle:
      postStart:
      tcpSocket:
      port: 8080
    3. HTTPGet:在当前容器中向某url发起http请求

      1
      2
      3
      4
      5
      6
      7
      8
      lifecycle:
      postStart:
      httpGet:
      path: / #URI地址
      port: 80 #端口号
      host: 192.168.70.28 #主机地址
      scheme: HTTP #支持的协议,http或者https
      #拼起来就是http://192.168.70.28:80

    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: # 在容器启动的时候执行一个命令,修改掉nginx的默认首页内容
    command: ["/bin/sh", "-c", "echo postStart... > /usr/share/nginx/html/index.html"]
    preStop:
    exec: # 在容器停止之前停止nginx服务
    command: ["/usr/sbin/nginx","-s","quit"]
    1
    2
    3
    4
    5
    6
    7
    [root@k8s-master hook-test]# kubectl create -f pod-hook-exec.yaml 
    pod/pod-hook-exec created
    [root@k8s-master hook-test]# kubectl get pod -n njm -o wide
    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]# curl 172.29.16.32:80
    postStart...

    容器探测

    容器探测用于检测容器中的应用实例是否正常工作,是保障业务可用性的一种传统机制。如果经过探测,实例的状态不符合预期,那么kubernetes就会把该问题实例” 摘除 “,不承担业务流量。kubernetes提供了两种探针来实现容器探测,分别是:

    • liveness probes:存活性探针,用于检测应用实例当前是否处于正常运行状态,如果不是,k8s会重启容器
    • readiness probes:就绪性探针,用于检测应用实例当前是否可以接收请求,如果不能,k8s不会转发流量(ready 变y为i加ness)

    livenessProbe 决定是否重启容器

    readinessProbe 决定是否将请求转发给容器

    探针方式:

    • Exec命令:在容器内执行一次命令,如果命令执行的退出码为0,则认为程序正常,否则不正常

      1
      2
      3
      4
      5
      livenessProbe:
      exec:
      command:
      - cat
      - /tmp/healthy
    • TCPSocket:将会尝试访问一个用户容器的端口,如果能够建立这条连接,则认为程序正常,否则不正常

      1
      2
      3
      livenessProbe:
      tcpSocket:
      port: 8080
    • HTTPGet:调用容器内Web应用的URL,如果返回的状态码在200和399之间,则认为程序正常,否则不正常

      1
      2
      3
      4
      5
      6
      livenessProbe:
      httpGet:
      path: / #URI地址
      port: 80 #端口号
      host: 127.0.0.1 #主机地址
      scheme: HTTP #支持的协议,http或者https

    liveness probes(存活性探针)例子

    1. Exec命令 pod-liveness-exec.yaml

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      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"] # 执行一个查看文件的命令(这个文并不存在)
      1
      2
      3
      4
      5
      6
      7
      8
      #创建
      [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

      查看详情,提示探测失败,容器将被重启

      image-20211214163426890

    2. TCPSocket pod-liveness-tcpsocket.yaml

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      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 # 尝试访问8080端口

      同样的创建、查看

      nginx的端口为80,所以会失败

      image-20211214164003174

    3. 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: # 其实就是访问http://127.0.0.1:80/hello
      scheme: HTTP #支持的协议,http或者https
      port: 80 #端口号
      path: /hello #URI地址

      出现404错误,将会重启

      image-20211214164926386

    重启策略

    探测中如果容器出了问题会重启,而重启是由重启策略决定的,有三种:

    1. Always(默认):容器失效时,自动重启该容器
    2. OnFailure: 容器终止运行且退出码不为0时重启
    3. 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 # 设置的是pod的重启策略,所以和containers同一级别,设置重启策略为Never

    探测失败后停止容器

    image-20211214170101271

    image-20211214170137699

    4.调度

    Pod在哪个node节点上运行,是由scheduler组件决定的,这个过程不受人工控制。如果我们想控制某些Pod到达某些节点上,就需要改变调度规则,k8s提供了4种调度方式

    1. 自动调度:顾名思义,自动
    2. 定向调度:NodeName、NodeSelector
    3. 亲和性调度:NodeAffinity、PodAffinity、PodAntiAffinity
    4. 污点(容忍)调度:Taints、Toleration

    定向调度

    通过在pod上声明nodeName或nodeSelector,以此将Pod调度到期望的node节点上

    NodeName

    NodeName强制将Pod调度到指定的Name的Node节点上(即使NodeName不存在),跳过了scheduler

    创建一个pod-nodename.yaml文件

    nodeName是pod的属性,和containers同级

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    apiVersion: v1
    kind: Pod
    metadata:
    name: pod-nodename
    namespace: njm
    spec:
    containers:
    - name: nginx
    image: nginx:1.17.1
    nodeName: node1 # 指定调度到node1节点上
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #创建
    [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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    apiVersion: v1
    kind: Pod
    metadata:
    name: pod-nodeselector
    namespace: njm
    spec:
    containers:
    - name: nginx
    image: nginx:1.17.1
    nodeSelector:
    nodeenv: pro # 指定调度到具有nodeenv=pro标签的节点上

    创建并运行,提示node selector匹配失败的提示

    image-20211215135344439

    亲和性调度

    它在NodeSelector的基础之上的进行了扩展,可以通过配置的形式,实现优先选择满足条件的Node进行调度,如果没有,也可以调度到不满足条件的节点上,使调度更加灵活

    Affinity主要分为三类:

    1. nodeAffinity(node亲和性): 以node为目标,解决pod可以调度到哪些node的问题
    2. podAffinity(pod亲和性) : 以pod为目标,解决pod可以和哪些已存在的pod部署在同一个拓扑域中的问题
    3. 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
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    关系符的使用说明:
    - 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: #设置node亲和性
    preferredDuringSchedulingIgnoredDuringExecution: # 软限制
    - weight: 1
    preference:
    matchExpressions: # 匹配nodeenv的值在["xxx","yyy"]中的标签(当前环境没有)
    - 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: #设置pod亲和性
    requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
    - labelSelector:
    matchExpressions: # 匹配podenv的值在["xxx","yyy"]中的标签
    - 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: #设置pod亲和性
    requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
    - labelSelector:
    matchExpressions: # 匹配podenv的值在["pro"]中的标签
    - 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 节点名 污点

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 设置污点
    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上去,这时候应该怎么做呢?这就要使用到容忍

    image-20211215173159089

    污点就是拒绝,容忍就是忽略,Node通过污点拒绝pod调度上去,Pod通过容忍忽略拒绝

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    apiVersion: v1
    kind: Pod
    metadata:
    name: pod-toleration
    namespace: njm
    spec:
    containers:
    - name: nginx
    image: nginx:1.17.1
    tolerations: # 添加容忍
    - key: "tag" # 要容忍的污点的key
    operator: "Equal" # 操作符
    value: "taint" # 容忍的污点的value
    effect: "NoExecute" # 添加容忍的规则,这里必须和标记的污点规则相同

    容忍的详细配置:

    1
    2
    3
    4
    5
    6
    7
    8
    [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: # rs名称
    namespace: # 所属命名空间
    labels: #标签
    controller: rs
    spec: # 详情描述

    replicas: 3 # 副本数量
    selector: # 选择器,通过它指定该控制器管理哪些pod
    matchLabels: # Labels匹配规则
    app: nginx-pod # 即管理标签为app:nginx-pod的pod
    matchExpressions: # Expressions匹配规则
    - {key: app, operator: In, values: [nginx-pod]}

    template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
    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


    扩缩容

    1
    2
    3
    4
    5
    6
    7
    8
    # 编辑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

    镜像更新

    1
    2
    3
    4
    5
    6
    7
    # 编辑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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # 使用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管理ReplicaSetReplicaSet管理Pod,所以DeploymentReplicaSet功能更加强大

    image-20211216143827793

    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 # 暂停部署,默认是false
    progressDeadlineSeconds: 600 # 部署超时时间(s),默认是600
    strategy: # 策略
    type: RollingUpdate # 滚动更新策略
    rollingUpdate: # 滚动更新
    maxSurge: 30% # 最大额外可以存在的副本数,可以为百分比,也可以为整数
    maxUnavailable: 30% # 最大不可用状态的 Pod 的最大值,可以为百分比,也可以为整数
    selector: # 选择器,通过它指定该控制器管理哪些pod
    matchLabels: # Labels匹配规则
    app: nginx-pod
    matchExpressions: # Expressions匹配规则
    - {key: app, operator: In, values: [nginx-pod]}

    template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
    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差不多

    1
    2
    3
    4
    5
    6
    7
    # 第一种 变更副本数量为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指定策略类型

    1
    2
    3
    4
    5
    6
    7
    strategy: 指定新的Pod替换旧的Pod的策略, 支持两个属性:
    type: 指定策略类型,支持两种策略
    Recreate: 重建更新
    RollingUpdate: 滚动更新中
    rollingUpdate: 当type为RollingUpdate时生效,用于为RollingUpdate设置参数,支持两个属性:
    maxUnavailable: 用来指定在升级过程中不可用Pod的最大数量,默认为25%。
    maxSurge: 用来指定在升级过程中可以超过期望的Pod的最大数量,默认为25%。

    重建更新

    1
    2
    3
    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

    滚动更新

    1
    2
    3
    4
    5
    6
    spec:
    strategy: # 策略
    type: RollingUpdate # 滚动更新策略
    rollingUpdate:
    maxSurge: 25%
    maxUnavailable: 25%

    其他都一样

    版本回退

    在滚动更新中原来的rs依旧存在,只是pod数量变为了0,而后又新产生了一个rs,pod数量为3
    这就是deployment能够进行版本回退的原因

    1
    2
    3
    4
    [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回滚到指定版本)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 查看当前升级版本的状态
    [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>

    版本回退

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 这里直接使用--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类型的控制器创建。

    image-20211217164517412

    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: # rs名称
    namespace: # 所属命名空间
    labels: #标签
    controller: daemonset

    spec: # 详情描述
    revisionHistoryLimit: 3 # 保留历史版本
    updateStrategy: # 更新策略
    type: RollingUpdate # 滚动更新策略
    rollingUpdate: # 滚动更新
    maxUnavailable: 1 # 最大不可用状态的 Pod 的最大值,可以为百分比,也可以为整数
    selector: # 选择器,通过它指定该控制器管理哪些pod
    matchLabels: # Labels匹配规则
    app: nginx-pod
    matchExpressions: # Expressions匹配规则
    - {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: # rs名称
    namespace: # 所属命名空间
    labels: #标签
    controller: job

    spec: # 详情描述
    completions: 1 # 指定job需要成功运行Pods的次数。默认值: 1
    parallelism: 1 # 指定job在任一时刻应该并发运行Pods的数量。默认值: 1
    activeDeadlineSeconds: 30 # 指定job可运行的时间期限,超过时间还未结束,系统将会尝试进行终止
    backoffLimit: 6 # 指定job失败后进行重试的次数。默认是6
    manualSelector: true # 是否可以使用selector选择器选择pod,默认是false
    selector: # 选择器,通过它指定该控制器管理哪些pod
    matchLabels:
    app: counter-pod
    matchExpressions:
    - {key: app, operator: In, values: [counter-pod]}

    template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
    metadata:
    labels:
    app: counter-pod
    spec:
    restartPolicy: Never # 重启策略只能设置为Never或者OnFailure
    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"]
    1
    2
    3
    4
    5
    6
    7
    8
    #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服务

    image-20211209103014124

    ​ Service在很多情况下只是一个概念,真正起作用的其实是kube-proxy服务进程,每个Node节点上都运行着一个kube-proxy服务进程。当创建Service的时候会通过api-server向etcd写入创建的service的信息,而kube-proxy会基于监听的机制发现这种Service的变动,然后它会将最新的Service信息转换成对应的访问规则

    image-20211217134945154

    两种不同的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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # 修改类型为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.配置方式

    1. 首先创建一个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

    1
    2
    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
    1. 创建service

    nodePort:(主机)节点的端口,省略的话随机分配

    port:service的端口

    targetPort:目标pod的端口

    type:service的类型

    selector:标签选择器,上一步deploy标签为run: httpd,这里对应

    sessionAffinity:session亲和性,支持ClientIP、None。比如三个pod位于A、B、C三个地区,对于来自A地区的请求要交给A地区的pod

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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 # service的ip 可省略
    type: NodePort
    sessionAffinity: #session亲和性

    查看

    PORT(S)80:58721 80 是 service的端口(即port),58721 则是主机(或者节点)上监听的端口。每个节点都会监听此端口并将请求转发给 Service

    1
    2
    3
    [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 的对应关系

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    [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>
    1. 访问
    1
    2
    3
    4
    5
    6
    7
    # 通过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查看规则

    1
    2
    3
    [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

    这两条规则的含义是:

    1. 如果 Cluster 内的 Pod(源地址来自 10.253.0.0/16)要访问 httpd-service,则允许
    2. 其他源地址访问 httpd-service,跳转到规则KUBE-SVC-6DSZY5JO37TTEYHN

    查看KUBE-SVC-6DSZY5JO37TTEYHN规则

    image-20211223143306492

    这三条规则的含义是:

    1. 1/3 的概率跳转到规则 KUBE-SEP-YZI6E5F46FBZHQJD
    2. 1/3 的概率(剩下 2/3 的一半)跳转到规则 KUBE-SEP-YZI6E5F46FBZHQJD
    3. 1/3 的概率跳转到规则 KUBE-SEP-YXWZPGCWM5AYTRC5

    查看第一条KUBE-SEP-YZI6E5F46FBZHQJD规则,最后会被转发到172.29.16.3的pod80端口上

    image-20211223143614670

    查看这三条规则,iptables 将访问 Service 的流量转发到后端 Pod,而且使用类似轮询的负载均衡策略

    image-20211223143717405


    本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

     TOC