K8S 命令

在这里插入图片描述

Kubernetes集群客户端命令kubectl

kubectl命令帮助

集群中的管理操作几乎都可以使用kubectl命令完成

[root@k8s-master1 ~]# kubectl -h

kubectl命令说明

基础命令

命令描述
create通过文件名或标准输入创建资源
expose将一个资源公开为一个新的Service
run在集群中运行一个特定的镜像
set在对象上设置特定的功能
get显示一个或多个资源
explian文档参考资料
edit使用默认的编辑器编辑一个资源
delete通过文件名、标准输入、资源名称或标签选择器来删除资源

部署命令

命令描述
rollout管理资源的发布
rollout-update对给定的复制控制器滚动更新
scale扩容或缩容pod数量,Deployment、ReplicaSet、RC或Job
autoscale创建一个自动选择扩容或缩容并设置pod数量

集群管理命令

命令描述
certificate修改证书资源
cluster-info显示集群信息
top显示资源(CPU/Memory/Storage)使用。需要HeapSter运行
cordon标记节点不可调度
uncordon标记节点可调度
drain驱逐节点上的应用,准备下线维护
train修改节点taint标记

故障诊断和调试命令

命令描述
describe显示特定资源或资源组的详细信息
logs在一个pod中打印一个容器日志。如果pod只有一个容器,容器名称是可选的
attach附加到一个运行的容器
exec执行命令到容器
port-forward转发一个或多个本地端口到一个pod
proxy运行一个proxy到Kubernetes API server
cp拷贝文件或目录到容器中
auth检查授权

高级命令

命令描述
apply通过文件名或标准输入对资源应用配置
patch使用补丁修改、更新资源的字段
replace通过文件名或标准输入替换一个资源
convert不同的API版本之间转换配置文件

设置命令

命令描述
label更新资源上的标签
annotate更新资源上的注释
completion用于实现kubectl根据自动补全

其他命令

命令描述
api-version打印受支持的API版本
config修改kubeconfig文件(用于访问API,比如配置认证信息)
help所有命令帮助
plugin运行一个命令行插件
version打印客户端和服务版本信息

kubectl命令补全

yum install -y bash-completion
source /usr/share/bash-completion/bash_completion
source <(kubectl completion bash)
kubectl completion bash > ~/.kube/completion.bash.inc
source '/root/.kube/completion.bash.inc'  
source $HOME/.bash_profile

Kubernetes集群Node管理

一、查看集群信息

[root@k8s-master1 ~]# kubectl cluster-info
Kubernetes control plane is running at https://192.168.10.100:6443
CoreDNS is running at https://192.168.10.100:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

二、查看节点信息

2.1 查看集群节点信息

[root@k8s-master1 ~]# kubectl get nodes

在这里插入图片描述

2.2 查看集群节点详细信息

[root@k8s-master1 ~]# kubectl get nodes -o wide

在这里插入图片描述

2.3 查看节点描述详细信息

[root@k8s-master1 ~]# kubectl describe node k8s-master1

在这里插入图片描述
节点无法使用kubectl指令

[root@k8s-worker1 ~]#  which kubectl

在这里插入图片描述
找到kebectl的对应的文件位置

scp /usr/bin/kubectl  <节点名>:/usr/bin/kubectl

scp /usr/bin/kubectl  k8s-worker01:/usr/bin/kubectl

在这里插入图片描述

三、worker node节点管理集群

  • 如果是kubeasz安装,所有节点(包括master与node)都已经可以对集群进行管理

  • 如果是kubeadm安装,在node节点上管理时会报如下错误

[root@k8s-worker1 ~]# kubectl get nodes
The connection to the server localhost:8080 was refused - did you specify the right host or port?

只要把master上的管理文件/etc/kubernetes/admin.conf拷贝到node节点的$HOME/.kube/config就可以让node节点也可以实现kubectl命令管理

1, 在node节点的用户家目录创建.kube目录

[root@k8s-worker1 ~]# mkdir /root/.kube

2, 在master节点做如下操作

[root@k8s-worker1 ~]# scp /etc/kubernetes/admin.conf k8s-worker01:/root/.kube/config

3, 在worker node节点验证

[root@k8s-worker1 ~]# kubectl get nodes

在这里插入图片描述

四、节点标签(label)

  • k8s集群如果由大量节点组成,可将节点打上对应的标签,然后通过标签进行筛选及查看,更好的进行资源对象的相关选择与匹配

4.1 查看节点标签信息

[root@k8s-master1 ~]# kubectl get node --show-labels

在这里插入图片描述

4.2 设置节点标签信息

4.2.1 设置节点标签

为节点k8s-worker1打一个region=huanai 的标签

[root@k8s-master1 ~]# kubectl label node k8s-worker01 region=hangzhou
node/k8s-worker01 labeled

在这里插入图片描述

4.2.2 查看所有节点标签

[root@k8s-master1 ~]# kubectl get node --show-labels

在这里插入图片描述

4.2.3 查看所有节点带region的标签

[root@k8s-master1 ~]# kubectl get nodes -L region

在这里插入图片描述

4.3 多维度标签

4.3.1 设置多维度标签

也可以加其它的多维度标签,用于不同的需要区分的场景

如把k8s-worker02标签为华南区,A机房,测试环境,游戏业务

[root@k8s-master1 ~]# kubectl label node k8s-worker02 zone=A env=test bussiness=game

在这里插入图片描述

[root@k8s-master1 ~]# kubectl get nodes k8s-master3 --show-labels

在这里插入图片描述

4.3.2 显示节点的相应标签

[root@k8s-master1 ~]# kubectl get nodes -L region,zone

在这里插入图片描述

4.3.3 查找region=huanai的节点

[root@k8s-master1 ~]# kubectl get nodes -l region=hangzhou

在这里插入图片描述

4.3.4 标签的修改

[root@k8s-master1 ~]# kubectl label node k8s-worker02 bussiness=ad --overwrite=true
node/k8s-master3 labeled
加上--overwrite=true覆盖原标签的value进行修改操作

在这里插入图片描述

[root@k8s-master1 ~]# kubectl get nodes -L bussiness

在这里插入图片描述

4.3.5 标签的删除

使用key加一个减号的写法来取消标签

[root@k8s-master1 ~]# kubectl label node k8s-worker01 region-

在这里插入图片描述
在这里插入图片描述

4.3.6 标签选择器

标签选择器主要有2类:

  • 等值关系: =, !=
  • 集合关系: KEY in {VALUE1, VALUE2…}
[root@k8s-master1 ~]# kubectl label node k8s-master2 env=test1

[root@k8s-master1 ~]# kubectl label node k8s-master3 env=test2

在这里插入图片描述

[root@k8s-master1 ~]# kubectl get node -l "env in(test1,test2)"

在这里插入图片描述

Kubernetes集群声明式文件YAML

一、YAML介绍

YAML 的意思是:仍是一种标记语言,但为了强调这种语言以数据做为中心,而不是以标记语言为重点。是一个可读性高,用来表达数据序列的格式。

二、基本语法

1.低版本缩进时不允许使用Tab键,只允许使用空格
2.缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
3.# 标识注释,从这个字符一直到行尾,都会被解释器忽略

三、YAML 支持的数据结构

  • 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
  • 数组:一组按次序排列的值,又称为序列(sequence) / 列表 (list)
  • 纯量(scalars):单个的、不可再分的值
对象类型:对象的一组键值对,使用冒号结构表示
name: Steve
age: 18

Yaml 也允许另一种写法,将所有键值对写成一个行内对象

hash: { name: Steve, age: 18 }
数组类型:一组连词线开头的行,构成一个数组
animal
- Cat
- Dog

数组也可以采用行内表示法

animal: [Cat, Dog]
复合结构:对象和数组可以结合使用,形成复合结构
1 languages:
2 - Ruby 
3 - Perl 
4 - Python
5 websites:
6 YAML: yaml.org 
7 Ruby: ruby-lang.org 
8 Python: python.org 
9 Perl: use.perl.org  

纯量:纯量是最基本的、不可再分的值。以下数据类型都属于纯量
1 字符串  布尔值  整数 浮点数 Null 
2 时间  日期

数值直接以字面量的形式表示
number: 12.30

布尔值用true和false表示
isSet: true

null用 ~ 表示
parent: ~

时间采用 ISO8601 格式
iso8601: 2001-12-14t21:59:43.10-05:00

日期采用复合 iso8601 格式的年、月、日表示
date: 1976-07-31

YAML 允许使用两个感叹号,强制转换数据类型
e: !!str 123
f: !!str true
字符串

字符串默认不使用引号表示

str: 这是一行字符串

如果字符串之中包含空格或特殊字符,需要放在引号之中

str: '内容:  字符串'

单引号和双引号都可以使用,双引号不会对特殊字符转义

s1: '内容\n字符串'
s2: "内容\n字符串"

单引号之中如果还有单引号,必须连续使用两个单引号转义

str: 'labor''s day'

字符串可以写成多行,从第二行开始,必须有一个单空格缩进。换行符会被转为 空格

str: 这是一段
  多行
  字符串

多行字符串可以使用|保留换行符,也可以使用>折叠换行

this: |
Foo
Bar
that
Foo
Bar

四、Kubernetes集群中资源对象描述方法

在kubernetes中,一般使用ymal格式的文件来创建符合我们预期期望的pod,这样的yaml文件称为资源清单文件。

4.1 常用字段

参数名字段类型说明
versionString这里是指的是K8S API的版本,目前基本上是v1,可以用 kubectl api-versions命令查询
kindString这里指的是yam文件定义的资源类型和角色,比如:Pod
metadataObject元数据对象,固定值就写 metadata
metadata.nameString元数据对象的名字,这里由我们编写,比如命名Pod的名字
metadata.namespaceString元数据对象的命名空间,由我们自身定义
SpecObject详细定义对象,固定值就写Spec
spec. containers[]list这里是Spec对象的容器列表定义,是个列表
spec containers [].nameString这里定义容器的名字
spec.containers [].imageString这里定义要用到的镜像名称
spec.containers [].imagePullPolicyString定义镜像拉取策路,有 Always、 Never、Ifnotpresent三个值可选:(1) Always:意思是每次都尝试重新拉取镜像;(2) Never:表示仅使用本地镜像;(3) IfNotPresent:如果本地有镜像就使用本地镜像,没有就拉取在线镜像。上面三个值都没设置的话,默认是 Always。
spec containers [].command[]List指定容器启动命令,因为是数组可以指定多个。不指定则使用镜像打包时使用的启动命令。
spec.containers [].argsList指定容器启动命令参数,因为是数组可以指定多个.
spec.containers [].workDirString指定容器的工作目录
spec.containers[]. volumeMounts[]List指定容器内部的存储卷配置
spec.containers[]. volumeMounts[].nameString指定可以被容器挂载的存储卷的名称
spec.containers[]. volumeMounts[].mountPathString指定可以被容器挂载的存储卷的路径
spec.containers[]. volumeMounts[].readOnlyString设置存储卷路径的读写模式,ture或者 false,默认为读写模式
spec.containers [].ports[]String指容器需要用到的端口列表
spec.containers [].ports[].nameString指定端口名称
spec.containers [].ports[].containerPortString指定容器需要监听的端口号
spec.containers [].ports[].hostPortString指定容器所在主机需要监听的端口号,默认跟上面 containerPort相同,注意设置了 hostPort同一台主机无法启动该容器的相同副本(因为主机的端口号不能相同,这样会冲突)
spec.containers [].ports[].protocolString指定端口协议,支持TCP和UDP,默认值为TCP
spec.containers [].env[]List指定容器运行前需设的环境变量列表
spec.containers [].env[].nameString指定环境变量名称
spec.containers [].env[].valueString指定环境变量值
spec.containers[].resourcesObject指定资源 限制和资源请求的值(这里开始就是设置容器的资源上限)
spec.containers[].resources.limitsObject指定设置容器运行时资源的运行上限
spec.containers[].resources.limits.cpuString指定CPU限制,单位为core数,将用于docker run – cpu-shares参数
spec.containers[].resources.limits.memoryString指定MEM内存的限制,单位为MiB、GiB
spec.containers[].resources.requestsObject指定容器启动和调度时的限制设置
spec.containers[].resources.requests.cpuStringCPU请求,单位为core数,容器启动时初始化可用数量
spec.containers[].resources.requests.memoryString内存请求,单位为MiB、GiB,容器启动时初始化可用数量
sepc.restartPolicyString定义Pod的重启策略,可选值为Always、OnFailure,默认值为Always。1.Always:Pod一旦终止运行,则无论容器时如何终止的,kubelet服务都将重启它。2.OnFailure:只有Pod以非零退出码终止时,kubelet才会重启该容器。如果容器正常结束(退出码为0),则kubelet将不会重启它。3.Never:Pod终止后,kubelet将退出码报告给Master,不会重启该Pod。
spec.nodeSelectorObject定义Node的Label过滤标签,以key:value格式指定。
spec.imagePullSecretsObject定义pull镜像时使用secret名称,以name:secretkey格式指定。
spec.hostNetworkBoolean定义是否使用主机网络模式,默认值为false。设置true表示使用宿主机网络,不使用docker网桥,同时设置了true将无法在同一台宿主机上启动第二个副本。

4.2 举例说明

4.2.1 使用声明式文件YAML创建namespace
apiVersion: v1
kind: Namespace
metadata:
  name: test
4.2.2 使用声明式文件YAML创建pod
apiVersion: v1
kind: Pod
metadata:
  name: pod1   #元数据对象的名字
spec:
  containers:
  - name: k8sonline1 #容器的名字
    image: nginx:latest  # 镜像名称
    imagePullPolicy: IfNotPresent #镜像拉取策路

Kubernetes集群命名空间(Namespace)

一、命名空间(namespace)作用

  • Namespace是对一组资源和对象的抽象集合.
  • 常见的 pod, service, deployment 等都是属于某一个namespace的(默认是 default)
  • 不是所有资源都属于namespace,如nodes, persistent volume,namespace 等资源则不属于任何 namespace

二、查看namespace

[root@k8s-master1 ~]# kubectl get namespaces       # namespaces可以简写为namespace或ns
NAME              STATUS   AGE
default           Active   130m			# 所有未指定Namespace的对象都会被默认分配在default命名空间
kube-node-lease   Active   130m			
kube-public       Active   130m			# 此命名空间下的资源可以被所有人访问
kube-system       Active   130m			# 所有由Kubernetes系统创建的资源都处于这个命名空间

三、查看namespace里的资源

使用kubectl get all --namespace=命名空间名称可以查看此命名空间下的所有资源

[root@k8s-master1 ~]# kubectl get all -n kube-system
[root@k8s-master1 ~]# kubectl get all -n=kube-system
[root@k8s-master1 ~]# kubectl get all --namespace=kube-system
NAME                                             READY   STATUS    RESTARTS   AGE
pod/calico-kube-controllers-7fdc86d8ff-cskfq     1/1     Running   3          5d1h
pod/calico-node-9dpc9                            1/1     Running   2          5d1h
pod/calico-node-jdmxw                            1/1     Running   3          5d1h
pod/calico-node-krwps                            1/1     Running   2          5d1h
pod/calico-node-tttlr                            1/1     Running   2          5d1h
pod/coredns-65dbdb44db-mm7cr                     1/1     Running   2          5d1h
pod/dashboard-metrics-scraper-545bbb8767-q66bc   1/1     Running   2          5d1h
pod/kubernetes-dashboard-65665f84db-nll6k        1/1     Running   4          5d1h
pod/metrics-server-869ffc99cd-8f4jd              1/1     Running   3          5d1h

NAME                                TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)                  AGE
service/dashboard-metrics-scraper   ClusterIP   10.2.246.128   <none>        8000/TCP                 5d1h
service/kube-dns                    ClusterIP   10.2.0.2       <none>        53/UDP,53/TCP,9153/TCP   5d1h
service/kubernetes-dashboard        NodePort    10.2.213.30    <none>        443:21351/TCP            5d1h
service/metrics-server              ClusterIP   10.2.232.121   <none>        443/TCP                  5d1h

NAME                         DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                 AGE
daemonset.apps/calico-node   4         4         4       4            4           beta.kubernetes.io/os=linux   5d1h

NAME                                        READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/calico-kube-controllers     1/1     1            1           5d1h
deployment.apps/coredns                     1/1     1            1           5d1h
deployment.apps/dashboard-metrics-scraper   1/1     1            1           5d1h
deployment.apps/kubernetes-dashboard        1/1     1            1           5d1h
deployment.apps/metrics-server              1/1     1            1           5d1h

NAME                                                   DESIRED   CURRENT   READY   AGE
replicaset.apps/calico-kube-controllers-7fdc86d8ff     1         1         1       5d1h
replicaset.apps/coredns-65dbdb44db                     1         1         1       5d1h
replicaset.apps/dashboard-metrics-scraper-545bbb8767   1         1         1       5d1h
replicaset.apps/kubernetes-dashboard-65665f84db        1         1         1       5d1h
replicaset.apps/metrics-server-869ffc99cd              1         1         1       5d1h

使用kubectl get 资源类型 --namespace=命名空间名称可以查看此命名空间下的对应的资源

[root@k8s-master1 ~]# kubectl get pod -n kube-system
[root@k8s-master1 ~]# kubectl get pod -n=kube-system
[root@k8s-master1 ~]# kubectl get pod --namespace=kube-system
NAME                                         READY   STATUS    RESTARTS   AGE
calico-kube-controllers-7fdc86d8ff-cskfq     1/1     Running   3          5d1h
calico-node-9dpc9                            1/1     Running   2          5d1h
calico-node-jdmxw                            1/1     Running   3          5d1h
calico-node-krwps                            1/1     Running   2          5d1h
calico-node-tttlr                            1/1     Running   2          5d1h
coredns-65dbdb44db-mm7cr                     1/1     Running   2          5d1h
dashboard-metrics-scraper-545bbb8767-q66bc   1/1     Running   2          5d1h
kubernetes-dashboard-65665f84db-nll6k        1/1     Running   4          5d1h
metrics-server-869ffc99cd-8f4jd              1/1     Running   3          5d1h

四、创建namespace

4.1 命令创建

[root@k8s-master1 ~]# kubectl create namespace ns1
namespace/ns1 created

[root@k8s-master1 ~]# kubectl get ns
NAME              STATUS   AGE
default           Active   5d1h
kube-node-lease   Active   5d1h
kube-public       Active   5d1h
kube-system       Active   5d1h
ns1               Active   10s

4.2 YAML文件创建

  • k8s中几乎所有的资源都可以通这YAML编排来创建
  • 可以使用kubectl edit 资源类型 资源名编辑资源的YAML语法
[root@k8s-master1 ~]# kubectl edit namespace ns1
......
  • 也可使用kubectl get 资源类型 资源名 -o yaml来查看
[root@k8s-master1 ~]# kubectl get ns ns1 -o yaml
......
  • 还可通过kubectl explain 资源类型来查看语法文档
[root@k8s-master1 ~]# kubectl explain namespace				   # 查看namespace相关语法参数
[root@k8s-master1 ~]# kubectl explain namespace.metadata	   # 查看namespace下级metadata的相关语法参数
[root@k8s-master1 ~]# kubectl explain namespace.metadata.name  # 查看namespace下级metadata再下级name的相关语法参数

编写创建namespace的YAML文件

[root@k8s-master1 ~]# vim create_ns2.yml
apiVersion: v1							# api版本号
kind: Namespace							# 类型为namespace
metadata:								# 定义namespace的元数据属性
  name: ns2					    		# 定义name属性为ns2

使用kubctl apply -f应用YAML文件

[root@k8s-master1 ~]# kubectl apply -f create_ns2.yml
namespace/ns2 created
[root@k8s-master1 ~]# kubectl get ns
NAME              STATUS   AGE
default           Active   5d2h
kube-node-lease   Active   5d2h
kube-public       Active   5d2h
kube-system       Active   5d2h
ns1               Active   10m
ns2               Active   46s

五、删除namespace

注意:

  • 删除一个namespace会自动删除所有属于该namespace的资源(类似mysql中drop库会删除库里的所有表一样,请慎重操作)
  • default,kube-system,kube-public命名空间不可删除

5.1 命令删除

[root@k8s-master1 ~]# kubectl delete namespace ns1
namespace "ns1" deleted

5.2 YAML文件删除

[root@k8s-master1 ~]# kubectl delete -f create_ns2.yml
namespace "ns2" deleted
[root@k8s-master1 ~]# kubectl get ns
NAME              STATUS   AGE
default           Active   5d2h
kube-node-lease   Active   5d2h
kube-public       Active   5d2h
kube-system       Active   5d2h

Kubernetes核心概念

一、kubernetes核心概念

1.1 Pod

Pod是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。

Pod就像豌豆荚一样,其中包含着一组(一个或多个)容器; 这些容器共享存储、网络、以及怎样运行这些容器的声明。

在这里插入图片描述
Pod就像一台物理服务器一样,其中包含一个或多个应用容器, 这些容器中运行着用户应用程序。

举例说明Pod、Container、应用程序三者之间的关系:麻屋子,红帐子,里面住着白胖子。Pod就是麻屋子,Container就是红帐子,应用程序就是里面的白胖子。

在这里插入图片描述

1.2 Controller

在 Kubernetes 中,用于管理和运行Pod的对象

在 Kubernetes 中,控制器通过监控集群的公共状态,并致力于将当前状态转变为期望的状态

举例说明Controller(控制器)作用:房间里的温度自动调节器

当你设置了温度,告诉了温度自动调节器你的期望状态(Desired State)。 房间的实际温度是当前状态(Current State)。 通过对设备的开关控制,温度自动调节器让其当前状态接近期望状态。

一个控制器至少追踪一种类型的 Kubernetes 资源。这些对象有一个代表期望状态的 spec 字段。 该资源的控制器负责确保其当前状态接近期望状态。

不同的类型的控制器所实现的控制方式不一样,例如:

  • deployment
    • 部署无状态应用
    • 部署无状态应用: 认为pod 都一样,没有顺序要求, 不用考虑在哪个node 运行,随意进行扩展和伸缩
    • 管理Pod和 ReplicaSet
    • 部署、滚动升级等
    • 典型的像web服务、分布式服务等
  • StatefulSet
    • 部署有状态应用
    • 有状态应用,每个pod 都独立运行,保持pod 启动顺序和唯一性; 有唯一的网络标识符,持久存储; 有序,比如mysql 主从; 主机名称固定。 而且其扩容以及升级等操作也是按顺序进行的操作。
  • DaemonSet
    • 部署守护进程
    • DaemonSet保证在每个Node上都运行一个容器副本,常用来部署一些集群的日志、监控或者其他系统管理应用。 新加入的node 也同样运行在一个pod 里面。
  • job
    • 一次性任务
    • Job负责批量处理短暂的一次性任务 (short lived one-off tasks),即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束。
  • Cronjob
    • 周期性定时任务

1.3 Label

1.3.1 Label介绍

Label是附着到object上(例如Pod)的键值对。可以在创建object的时候指定,也可以在object创建后随时指定。Labels的值对系统本身并没有什么含义,只是对用户才有意义。

一个Label是一个key=value的键值对,其中key与value由用户自己指定。

Label可以附加到各种资源对象上,例如Node、Pod、Service、RC等,一个资源对象可以定义任意数量的Label,同一个Label也可以被添加到任意数量的资源对象上去,Label通常在资源对象定义时确定,也可以在对象创建后动态添加或者删除。

我们可以通过指定的资源对象捆绑一个或多个不同的Label来实现多维度的资源分组管理功能,以便于灵活、方便地进行资源分配、调度、配置、部署等管理工作。例如:部署不同版本的应用到不同的环境中;或者监控和分析应用(日志记录、监控、告警)等。

一些常用abel示例如下所示:

版本标签:“release” : “stable” , “release” : “canary”…

环境标签:“environment” : “dev” , “environment” : “production”

架构标签:“tier” : “frontend” , “tier” : “backend” , “tier” : “middleware”

分区标签:“partition” : “customerA” , “partition” : “customerB”…

质量管控标签:“track” : “daily” , “track” : “weekly”

Label相当于我们熟悉的“标签”,给某个资源对象定义一个Label,就相当于给它打了一个标签,随后可以通过Label Selector(标签选择器)查询和筛选拥有某些Label的资源对象,Kubernetes通过这种方式实现了类似SQL的简单又通用的对象查询机制。

1.3.2 Label语法及字符集

Label key的组成:

  • 不得超过63个字符
  • 可以使用前缀,使用/分隔,前缀必须是DNS子域,不得超过253个字符,系统中的自动化组件创建的label必须指定前缀,kubernetes.io/由kubernetes保留
  • 起始必须是字母(大小写都可以)或数字,中间可以有连字符、下划线和点

Label value的组成:

  • 不得超过63个字符
  • 起始必须是字母(大小写都可以)或数字,中间可以有连字符、下划线和点

1.4 Label Selector

通过label selector,客户端/用户可以指定一个object集合,通过label selector对object的集合进行操作。

Label selector有两种类型:

  • equality-based(基于等式) :可以使用===!=操作符,可以使用逗号分隔多个表达式
  • set-based(基于集合) :可以使用innotin!操作符,另外还可以没有操作符,直接写出某个label的key,表示过滤有某个key的object而不管该key的value是何值,!表示没有该label的object

举例说明Label Selector

Label Selector可以被类比为SQL语句中的where查询条件,例如,name=redis-slave这个label Selector作用于Pod时,可以被类比为select * from pod where pod’s name = 'redis-slave’这样的语句。

1.5 Service

将运行在一组 Pods上的应用程序公开为网络服务的抽象方法。

由于Pod是非永久性资源对象,如果你使用Controller运行你的应用程序,你可以动态创建和销毁Pod,这样就会导致无法准确访问到所想要访问的Pod

例如:如果一组 Pod(称为“后端”)为集群内的其他 Pod(称为“前端”)提供功能, 那么前端如何找出并跟踪要连接的 IP 地址,以便前端可以使用提供工作负载的后端部分?

是一组iptables或ipvs规划,通过把客户端的请求转发到服务端(Pod),如有多个Pod情况,亦可实现负载均衡的效果。

例如:一个图片处理后端,它运行了 3 个副本(Pod)。这些副本是可互换的 —— 前端不需要关心它们调用了哪个后端副本。 然而组成这一组后端程序的 Pod 实际上可能会发生变化, 前端客户端不应该也没必要知道,而且也不需要跟踪这一组后端的状态。

1.6 Endpoints

为Service管理后端Pod,当后端Pod被创建或销毁时,endpoints列表会更新Pod对应的IP地址,以便Service访问请求能够确保被响应。

1.7 DNS

为kubernetes集群内资源对象的访问提供名称解析,这样就可以实现通过DNS名称而非IP地址来访问服务。

  • 实现集群内Service名称解析
  • 实现集群内Pod内Container中应用访问互联网提供域名解析

二、Kubernetes核心概念之间的关系

2.1 Pod与Controller

pod 是通过Controller 实现应用的运维,比如伸缩,滚动升级等待。pod 和 controller 通过label 标签建立关系。
在这里插入图片描述

2.2 Pod与Service

service 是为了防止pod 失联,提供的服务发现,类似于微服务的注册中心。定义一组pod 的访问策略。可以为一组具有相同功能的容器应用提供一个统一的入口地址,并将请求负载分发到后端的各个容器应用上。

service 通过selector 来管控对应的pod。根据label 和 selector 建立关联,通过service 实现pod 的负载均衡。

在这里插入图片描述

2.3 Service与DNS

通过DNS实现对Service名称解析,以此达到访问后端Pod目的。

三、基于kubernetes集群容器化应用的微服务

3.1 服务部署方式介绍

  • 单体服务架构
    • 所有服务进程运行在同一台主机内
  • 分布式服务架构
    • 服务进程分布于不同的主机,其中一台主机出现故障,不影响其它主机上的服务运行
  • 微服务架构
    • 使用容器化技术把分布式服务架构运行起来,并实现对不同的服务进程的高可用及快速发布等。

3.2 微服务架构服务组件(kubernetes核心概念)之间关系举例说明

以在kubernetes集群中运行LNMT应用为例:

把kubernetes集群看做是一个IDC机房,把LNMT Web架构应用以微服务(kubernetes集群资源对象)的方式部署到kubernetes集群中。

在这里插入图片描述

Kubernetes集群核心概念 Pod

一、工作负载(workloads)

参考链接:https://kubernetes.io/zh/docs/concepts/workloads/

工作负载(workload)是在kubernetes集群中运行的应用程序。无论你的工作负载是单一服务还是多个一同工作的服务构成,在kubernetes中都可以使用pod来运行它。

在这里插入图片描述
workloads分为pod与controllers

  • pod通过控制器实现应用的运行,如何伸缩,升级等
  • controllers 在集群中管理pod
  • pod与控制器之间通过label-selector相关联,是唯一的关联方式

在这里插入图片描述
在pod的YAML里指定pod标签

定义标签
  labels: 
	app: nginx

在控制器的YAML里指定标签选择器匹配标签

通过标签选择器选择对应的pod
  selector:
    matchLabels:
      app: nginx

二、pod介绍

2.1 pod定义与分类

参考链接: https://kubernetes.io/zh/docs/concepts/workloads/pods/

2.1.1 Pod定义
  • Pod(豌豆荚) 是Kubernetes集群管理(创建、部署)与调度的最小计算单元,表示处于运行状态的一组容器。
  • Pod不是进程,而是容器运行的环境。
  • 一个Pod可以封装一个容器或多个容器(主容器或sidecar边车容器)
  • 一个pod内的多个容器之间共享部分命名空间,例如:Net Namespace,UTS Namespace,IPC Namespace及存储资源
  • 用户pod默认会被调度运行在node节点之上(不运行在master节点上,但也有例外情况)
  • pod内的IP不是固定的,集群外不能直接访问pod
2.1.2 Pod分类
  • 静态Pod 也称之为“无控制器管理的自主式pod”,直接由特定节点上的 kubelet 守护进程管理, 不需要API 服务器看到它们,尽管大多数 Pod 都是通过控制面(例如,Deployment) 来管理的,对于静态 Pod 而言,kubelet 直接监控每个 Pod,并在其失效时重启之。
  • 控制器管理的pod 控制器可以控制pod的副本数,扩容与裁剪,版本更新与回滚等

2.2 查看pod方法

pod是一种计算资源,可以通过kubectl get pod来查看

[root@k8s-master1 ~]# kubectl get pod		# pod或pods都可以,不指定namespace,默认是名为default的namespace
	
[root@k8s-master1 ~]# kubectl get pod -n kube-system

2.3 pod的YAML资源清单格式

先看一个yaml格式的pod定义文件解释

# yaml格式的pod定义文件完整内容:
apiVersion: v1       #必选,api版本号,例如v1
kind: Pod       	#必选,Pod
metadata:       	#必选,元数据
  name: string       #必选,Pod名称
  namespace: string    #Pod所属的命名空间,默认在default的namespace
  labels:     		 # 自定义标签
    name: string     #自定义标签名字
  annotations:        #自定义注释列表
    name: string
spec:         #必选,Pod中容器的详细定义(期望)
  containers:      #必选,Pod中容器列表
  - name: string     #必选,容器名称
    image: string    #必选,容器的镜像名称
    imagePullPolicy: [Always | Never | IfNotPresent] #获取镜像的策略 Alawys表示下载镜像 IfnotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像
    command: [string]    #容器的启动命令列表,如不指定,使用打包时使用的启动命令
    args: [string]     #容器的启动命令参数列表
    workingDir: string     #容器的工作目录
    volumeMounts:    #挂载到容器内部的存储卷配置
    - name: string     #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
      mountPath: string    #存储卷在容器内mount的绝对路径,应少于512字符
      readOnly: boolean    #是否为只读模式
    ports:       #需要暴露的端口库号列表
    - name: string     #端口号名称
      containerPort: int   #容器需要监听的端口号
      hostPort: int    #容器所在主机需要监听的端口号,默认与Container相同
      protocol: string     #端口协议,支持TCP和UDP,默认TCP
    env:       #容器运行前需设置的环境变量列表
    - name: string     #环境变量名称
      value: string    #环境变量的值
    resources:       #资源限制和请求的设置
      limits:      #资源限制的设置
        cpu: string    #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
        memory: string     #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
      requests:      #资源请求的设置
        cpu: string    #Cpu请求,容器启动的初始可用数量
        memory: string     #内存清求,容器启动的初始可用数量
    livenessProbe:     #对Pod内个容器健康检查的设置,当探测无响应几次后将自动重启该容器,检查方法有exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可
      exec:      #对Pod容器内检查方式设置为exec方式
        command: [string]  #exec方式需要制定的命令或脚本
      httpGet:       #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
        path: string
        port: number
        host: string
        scheme: string
        HttpHeaders:
        - name: string
          value: string
      tcpSocket:     #对Pod内个容器健康检查方式设置为tcpSocket方式
         port: number
       initialDelaySeconds: 0  #容器启动完成后首次探测的时间,单位为秒
       timeoutSeconds: 0   #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
       periodSeconds: 0    #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
       successThreshold: 0
       failureThreshold: 0
       securityContext:
         privileged:false
    restartPolicy: [Always | Never | OnFailure] # Pod的重启策略,Always表示一旦不管以何种方式终止运行,kubelet都将重启,OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该Pod
    nodeSelector: obeject  # 设置NodeSelector表示将该Pod调度到包含这个label的node上,以key:value的格式指定
    imagePullSecrets:    #Pull镜像时使用的secret名称,以key:secretkey格式指定
    - name: string
    hostNetwork: false     #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
    volumes:       #在该pod上定义共享存储卷列表
    - name: string     #共享存储卷名称 (volumes类型有很多种)
      emptyDir: {}     #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
      hostPath: string     #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
        path: string     #Pod所在宿主机的目录,将被用于同期中mount的目录
      secret:      #类型为secret的存储卷,挂载集群与定义的secret对象到容器内部
        scretname: string  
        items:     
        - key: string
          path: string
      configMap:     #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
        name: string
        items:
        - key: string
          path: string

YAML格式查找帮助方法回顾

[root@k8s-master1 ~]# kubectl explain namespace

[root@k8s-master1 ~]# kubectl explain pod
[root@k8s-master1 ~]# kubectl explain pod.spec
[root@k8s-master1 ~]# kubectl explain pod.spec.containers

三、pod创建与验证

3.1 命令创建pod(v1.18变化)

  • k8s之前版本中, kubectl run命令用于创建deployment控制器
  • 在v1.18版本中, kubectl run命令改为创建pod
3.1.1 创建一个名为pod-nginx的pod
[root@k8s-master1 ~]# kubectl run nginx-yuyang --image=nginx:1.15-alpine
pod/nginx-yuyang created
3.1.2 验证
[root@k8s-master1 ~]# kubectl get pods
[root@k8s-master1 ~]# kubectl get pod

在这里插入图片描述

3.2 YAML创建pod

3.2.1 准备yaml文件
[root@k8s-master1 ~]# vim pod1.yml
apiVersion: v1					# api版本
kind: Pod						# 资源类型为Pod
metadata:						
  name: yuyang-pod				# 自定义pod的名称
spec:
  containers:					# 定义pod里包含的容器
  - name: c1					# 自定义pod中的容器名
    image: polinux/stress		# 启动容器的镜像名   #对应的启动镜像
    command: ["stress"]			# 自定义启动容器时要执行的命令(类似dockerfile里的CMD)
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"] # 自定义启动容器执行命令的参数
    
# polinux/stress这个镜像用于压力测试,在启动容器时传命令与参数就是相当于分配容器运行时需要的压力

2, 通过yaml文件创建pod

[root@k8s-master1 ~]# kubectl apply -f pod1.yml
pod/pod-stress created
3.2.2 查看pod信息

查看pod信息

[root@k8s-master1 ~]# kubectl get pod
NAME          READY   STATUS    RESTARTS   AGE
pod-stress    1/1     Running   0          45s

查看pod详细信息

[root@k8s-master1 ~]# kubectl get pods -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS GATES
pod-stress   1/1     Running   0          71s   10.244.194.72   k8s-worker1   <none>           <none>

描述pod详细信息

[root@k8s-master1 ~]# kubectl describe pod pod-stress 
......
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  102s  default-scheduler  Successfully assigned default/pod-stress to k8s-worker1
  Normal  Pulling    102s  kubelet            Pulling image "polinux/stress"
  Normal  Pulled     83s   kubelet            Successfully pulled image "polinux/stress" in 18.944533343s
  Normal  Created    83s   kubelet            Created container c1
  Normal  Started    82s   kubelet            Started container c1

在这里插入图片描述

3.3 删除pod

3.3.1 单个pod删除

方法1:


[root@k8s-master1 ~]# kubectl delete pod yuyang-pod
pod "pod-stress" deleted

[root@k8s-master1 ~]# kubectl delete pod yuyang-pod -n default
[root@k8s-master1 ~]# kubectl delete pod yuyang-pod <-n namespace>

方法2:

[root@k8s-master1 ~]# kubectl delete -f pod1.yml
[root@k8s-master1 ~]# kubectl delete -f pod1.yaml -n default

3.3.2 多个pod删除
#遍历所有的pod
kubectl get pod | awk '{print $1}'

方法1: 后接多个pod名

[root@k8s-master1 ~]# kubectl delete pod pod名1 pod名2 pod名3 ......

方法2: 通过awk截取要删除的pod名称,然后管道给xargs

[root@k8s-master1 ~]# kubectl get pods |awk 'NR>1 {print $1}' |xargs kubectl  delete pod

方法3: 如果要删除的pod都在同一个非default的命名空间,则可直接删除命名空间

[root@k8s-master1 ~]# kubectl delete ns xxxx

3.4 镜像拉取策略

由imagePullPolicy参数控制

  • Always : 不管本地有没有镜像,都要从仓库中下载镜像
  • Never : 从来不从仓库下载镜像, 只用本地镜像,本地没有就算了
  • IfNotPresent: 如果本地存在就直接使用, 不存在才从仓库下载

默认的策略是:

  • 当镜像标签版本是latest,默认策略就是Always
  • 如果指定特定版本默认拉取策略就是IfNotPresent。

1, 将上面的pod删除再创建,使用下面命令查看信息

[root@k8s-master1 ~]# kubectl apply -f pod1.yml
[root@k8s-master1 ~]# kubectl delete -f pod1.yml
[root@k8s-master1 ~]# kubectl describe pod pod-stress
......
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  102s  default-scheduler  Successfully assigned default/pod-stress to k8s-worker1
  Normal  Pulling    102s  kubelet            Pulling image "polinux/stress"
  Normal  Pulled     83s   kubelet            Successfully pulled image "polinux/stress" in 18.944533343s
  Normal  Created    83s   kubelet            Created container c1
  Normal  Started    82s   kubelet            Started container c1

说明: 可以看到第二行信息还是pulling image下载镜像
在这里插入图片描述

2, 修改YAML

[root@k8s-master1 ~]# vim pod1.yml
apiVersion: v1
kind: Pod
metadata:
  name: pod-stress
  namespace: default
spec:
  containers:
  - name: c1
    image: polinux/stress
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
    imagePullPolicy: IfNotPresent					#  增加了这一句

3,再次删除再创建

[root@k8s-master1 ~]# kubectl describe pod pod-stress
......
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  17s   default-scheduler  Successfully assigned default/pod-stress to k8s-worker1
  Normal  Pulled     17s   kubelet            Container image "polinux/stress" already present on machine
  Normal  Created    17s   kubelet            Created container c1
  Normal  Started    17s   kubelet            Started container c1

说明: 第二行信息是说镜像已经存在,直接使用了

3.5 pod的标签

  • 为pod设置label,用于控制器通过label与pod关联
  • 语法与前面学的node标签几乎一致
3.5.1 通过命令管理Pod标签
  1. 查看pod的标签
[root@k8s-master1 ~]# kubectl get pods --show-labels
NAME          READY   STATUS    RESTARTS   AGE   LABELS
pod-stress     1/1    Running   0          7m25s   <none>
  1. 打标签,再查看
[root@k8s-master1 ~]# kubectl label pod pod-stress region=huanai zone=A env=test bussiness=game
pod/pod-stress labeled

[root@k8s-master1 ~]# kubectl get pods --show-labels
NAME          READY   STATUS    RESTARTS   AGE     LABELS
pod-stress    1/1     Running   0          8m54s   bussiness=game,env=test,region=huanai,zone=A
  1. 通过等值关系标签查询
[root@k8s-master1 ~]# kubectl get pods -l zone=A
NAME         READY   STATUS    RESTARTS   AGE
pod-stress   1/1     Running   0          9m22s
  1. 通过集合关系标签查询
[root@k8s-master1 ~]# kubectl get pods -l "zone in (A,B,C)"
NAME         READY   STATUS    RESTARTS   AGE
pod-stress   1/1     Running   0          9m55s
  1. 删除标签后再验证
[root@k8s-master1 ~]# kubectl label pod pod-stress region- zone- env- bussiness-
pod/pod-stress labeled

[root@k8s-master1 ~]# kubectl get pods --show-labels
NAME          READY   STATUS    RESTARTS   AGE   LABELS
pod-stress    1/1     Running   0          16m     <none>

小结:

  • pod的label与node的label操作方式几乎相同
  • node的label用于pod调度到指定label的node节点
  • pod的label用于controller关联控制的pod
3.5.2 通过YAML创建Pod时添加标签

1, 修改yaml

[root@k8s-master1 ~]# vim pod1.yml
apiVersion: v1
kind: Pod
metadata:
  name: pod-stress
  namespace: default
  labels:     # 直接在原来的yaml里加上多个标签
    env: dev
    app: nginx				
spec:
  containers:
  - name: c1
    image: polinux/stress
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
    imagePullPolicy: IfNotPresent

2, 直接apply应用

[root@k8s-master1 ~]# kubectl apply -f pod1.yaml
pod/pod-stress1 configured			  # 这里是configured,表示修改了

3, 验证

[root@k8s-master1 ~]# kubectl get pods --show-labels
NAME          READY   STATUS             RESTARTS   AGE     LABELS
pod-stress   1/1     Running            0          3m5s    app=nginx,env=dev		# 标签有了

3.6 pod资源限制

准备2个不同限制方式的创建pod的yaml文件

[root@k8s-master1 ~]# vim pod2.yml
apiVersion: v1
kind: Namespace
metadata:
  name: namespace1
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-stress2
  namespace: namespace1
spec:
  containers:
  - name: c1
    image: polinux/stress
    imagePullPolicy: IfNotPresent
    resources:     #pod资源限制
      limits:
        memory: "200Mi"    #限制最高200m
      requests:
        memory: "100Mi"    #请求100m
    command: ["stress"]				    # 启动容器时执行的命令
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]  # 产生1个进程分配150M内存1秒后释放
[root@k8s-master1 ~]# vim pod3.yml
apiVersion: v1
kind: Namespace
metadata:
  name: namespace1
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-stress3
  namespace: namespace1
spec:
  containers:
  - name: c1
    image: polinux/stress
    imagePullPolicy: IfNotPresent
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "150Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1"]

[root@k8s-master1 ~]# kubectl apply -f pod2.yml
namespace/namespace1 created
pod/pod-stress2 created

[root@k8s-master1 ~]# kubectl apply -f pod3.yml
namespace/namespace1 unchanged
pod/pod-stress3 created
[root@k8s-master1 ~]# kubectl get namespace  |grep namespace1
namespace1        Active   1m28s

[root@k8s-master1 ~]# kubectl get pod -n namespace1
NAME          READY   STATUS      RESTARTS   AGE
pod-stress2   1/1     Running     0          2m2s
pod-stress3   0/1     OOMKilled   4          115s


查看会发现pod-stress3这个pod状态变为OOMKilled,因为它是内存不足所以显示Container被杀死

说明: 一旦pod中的容器挂了,容器会有重启策略, 如下:

  • Always:表示容器挂了总是重启,这是默认策略

  • OnFailures:表容器状态为错误时才重启,也就是容器正常终止时才重启

  • Never:表示容器挂了不予重启

  • 对于Always这种策略,容器只要挂了,就会立即重启,这样是很耗费资源的。所以Always重启策略是这么做的:第一次容器挂了立即重启,如果再挂了就要延时10s重启,第三次挂了就等20s重启… 依次类推

测试完后删除

[root@k8s-master1 ~]# kubectl delete ns namespace1

3.7 pod包含多个容器

1, 准备yml文件

[root@k8s-master1 ~]# vim pod4.yml
apiVersion: v1
kind: Pod
metadata:
  name: pod-stress4
spec:
  containers:
  - name: c1
    image: polinux/stress
    imagePullPolicy: IfNotPresent
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
    
  - name: c2
    image: polinux/stress
    imagePullPolicy: IfNotPresent
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]

在这里插入图片描述

2, 应用yml文件创建pod

[root@k8s-master1 ~]# kubectl apply -f pod4.yml
pod/pod-stress4 created

3, 查看pod在哪个节点

[root@k8s-master1 ~]# kubectl get pods  -o wide
NAME          READY   STATUS    RESTARTS   AGE     IP               NODE          NOMINATED NODE   READINESS GATES
pod-stress4   2/2     Running   0          70s     10.244.159.136   k8s-master1   <none>           <none>
可以看到有2个容器,运行在k8s-master1节点

4,在k8s-master1上验证,确实产生了2个容器

[root@k8s-master1 ~]# docker ps -a |grep stress
d7827a963f9d        df58d15b053d              "stress --vm 1 --vm-…"   2 hours ago         Up 2 hours                                      k8s_c2_pod-stress4_default_a534bce1-3ffe-45f5-8128-34657e289b44_0
ae8e8f8d095b        df58d15b053d              "stress --vm 1 --vm-…"   2 hours ago         Up 2 hours                                      k8s_c1_pod-stress4_default_a534bce1-3ffe-45f5-8128-34657e289b44_0
e66461900426        easzlab/pause-amd64:3.2   "/pause"                 2 hours ago         Up 2 hours                                      k8s_POD_pod-stress4_default_a534bce1-3ffe-45f5-8128-34657e289b44_0

[root@k8s-master1 ~]# crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                   ATTEMPT             POD ID
08cd23ac9b416       df58d15b053d1       2 hours ago         Running             c2                     0                   2dd084491f019
65f0ecba8dec3       df58d15b053d1       2 hours ago         Running             c1                     0                   2dd084491f019

3.8 对pod里的容器进行操作

3.8.1 命令帮助
[root@k8s-master1 ~]# kubectl exec -h
3.8.2 不用交互直接执行命令

格式为: kubectl exec pod名 -c 容器名 -- 命令

kubectl exec (POD | TYPE/NAME) [-c CONTAINER] [flags] -- COMMAND [args...] [options]
[root@k8s-master1 ~]#  kubectl exec pod-stress4 -- date
[root@k8s-master1 ~]# kubectl exec pod-stress4 -c c1 -- date

在这里插入图片描述

注意:

  • -c 容器名为可选项,如果是1个pod中1个容器,则不用指定;
  • 如果是1个pod中多个容器,不指定默认为第1个。
# 在第二个容器中创建文件夹 111
[root@k8s-master1 ~]# kubectl exec pod-stress4 -c c2  -- touch /111     

[root@k8s-master1 ~]# kubectl exec pod-stress4 -c c2  -- ls /111
/111

不指定容器名,则默认为pod里的第1个容器

[root@k8s-master1 ~]# kubectl exec  pod-stress4  -- touch /222
Defaulting container name to c1.
Use 'kubectl describe pod/pod-stress4 -n default' to see all of the containers in this pod.
3.8.3 和容器交互操作

和docker exec几乎一样

#进入pod为pod-stress4的第一个容器
[root@k8s-master1 ~]# kubectl exec -it pod-stress4 -c c1 -- /bin/sh
[root@k8s-master1 ~]# kubectl exec -it pod-stress4 -c c1 -- /bin/bash
bash-5.0# touch /333
bash-5.0# ls
222    bin    etc    lib    mnt    proc   run    srv    tmp    var
333    dev    home   media  opt    root   sbin   sys    usr
bash-5.0# exit
exit	   

3.9 验证pod中多个容器网络共享

1, 编写YAML

[root@k8s-master1 ~]# vim pod-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx2
spec:
  containers:
  - name: c1
    image: nginx:1.15-alpine

  - name: c2
    image: nginx:1.15-alpine

2, 应用YAML

[root@k8s-master1 ~]# kubectl apply -f pod-nginx.yaml
pod/nginx2 created

3, 查看pod信息与状态

[root@k8s-master1 ~]# kubectl describe pod nginx2
......
......
Events:
  Type    Reason     Age              From               Message
  ----    ------     ----             ----               -------
  Normal  Scheduled  25s              default-scheduler  Successfully assigned default/nginx2 to k8s-worker1
  Normal  Pulling    24s              kubelet            Pulling image "nginx:1.15-alpine"
  Normal  Pulled     5s               kubelet            Successfully pulled image "nginx:1.15-alpine" in 18.928009025s
  Normal  Created    5s               kubelet            Created container c1
  Normal  Started    5s               kubelet            Started container c1
  Normal  Pulled     2s (x2 over 5s)  kubelet            Container image "nginx:1.15-alpine" already present on machine
  Normal  Created    2s (x2 over 5s)  kubelet            Created container c2
  Normal  Started    2s (x2 over 5s)  kubelet            Started container c2

[root@k8s-master1 ~]# kubectl get pods |grep nginx2
nginx2   1/2     CrashLoopBackOff   3          2m40s
有一个启不来,因为一个容器中两个pod是共用网络的,所以不能两个都占用80端口

有一个启不来,因为一个pod中两个容器是共用网络的,所以不能两个都占用80端口

通过查找k8s-worker1上面的容器,然后docker logs或crictl logs containerID查看,得到如下的报错,说明是端口被占用

[root@k8s-worker1 ~]# docker logs k8s_c2_nginx2_default_51fd8e81-1c4b-4557-9498-9b25ed8a4c99_4
2020/11/21 04:29:12 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address in use)
2020/11/21 04:29:12 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address in use)
2020/11/21 04:29:12 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address in use)
2020/11/21 04:29:12 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address in use)
2020/11/21 04:29:12 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address in use)
2020/11/21 04:29:12 [emerg] 1#1: still could not bind()
nginx: [emerg] still could not bind()

四、pod调度

4.1 pod调度流程

在这里插入图片描述

Step1
通过kubectl命令应用资源清单文件(yaml格式)向api server 发起一个create pod 请求

Step2
api server接收到pod创建请求后,生成一个包含创建信息资源清单文件

Step3
apiserver 将资源清单文件中信息写入etcd数据库

Step4
Scheduler启动后会一直watch API Server,获取 podSpec.NodeName为空的Pod,即判断pod.spec.Node == null? 若为null,表示这个Pod请求是新的,需要创建,因此先进行调度计算(共计2步:1、过滤不满足条件的,2、选择优先级高的),找到合适的node,然后将信息在etcd数据库中更新分配结果:pod.spec.Node = nodeA (设置一个具体的节点)

Step5
kubelet 通过watch etcd数据库(即不停地看etcd中的记录),发现有新的Node出现,如果这条记录中的Node与所在节点编号相同,即这个Pod由scheduler分配给自己,则调用node中的Container Runtime,进而创建container,并将创建后的结果返回到给api server用于更新etcd数据库中数据状态。

4.2 调度约束方法

我们为了实现容器主机资源平衡使用, 可以使用约束把pod调度到指定的node节点

  • nodeName 用于将pod调度到指定的node名称上
  • nodeSelector 用于将pod调度到匹配Label的node上

4.2.1 nodeName

1, 编写YAML文件

[root@k8s-master1 ~]# vim pod-nodename.yml
apiVersion: v1
kind: Pod
metadata:
  name: pod-nodename
spec:
  nodeName: k8s-worker01                    # 通过nodeName调度到k8s-worker01节点
  containers:
  - name: nginx
    image: nginx:1.15-alpine

2, 应用YAML文件创建pod

[root@k8s-master1 ~]# kubectl apply -f pod-nodename.yml
pod/pod-nodename created

3, 验证

[root@k8s-master1 ~]# kubectl describe pod pod-nodename |tail -6
Events:
  Type    Reason   Age    From     Message
  ----    ------   ----   ----     -------
  Normal  Pulled   2m47s  kubelet  Container image "nginx:1.15-alpine" already present on machine
  Normal  Created  2m47s  kubelet  Created container nginx
  Normal  Started  2m47s  kubelet  Started container nginx

倒数第3行没有使用scheduler,而是直接给运行了,说明nodeName约束生效

4.2.2 nodeSelector

1, 为k8s-worker1打标签

[root@k8s-master1 ~]# kubectl label nodes k8s-worker01 bussiness=game
node/k8s-worker1 labeled

2, 编写YAML文件

[root@k8s-master1 ~]# vim pod-nodeselector.yml
apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeselect
spec:
  nodeSelector:                         # nodeSelector节点选择器
    bussiness: game                     # 指定调度到标签为bussiness=game的节点
  containers:
  - name: nginx
    image: nginx:1.15-alpine

3, 应用YAML文件创建pod

[root@k8s-master1 ~]# kubectl apply -f pod-nodeselector.yml
pod/pod-nodeselect created

4, 验证

[root@k8s-master1 ~]# kubectl describe pod pod-nodeselect |tail -6
 Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  20s   default-scheduler  Successfully assigned default/pod-nodeselect to k8s-worker1
  Normal  Pulled     19s   kubelet            Container image "nginx:1.15-alpine" already present on machine
  Normal  Created    19s   kubelet            Created container nginx
  Normal  Started    19s   kubelet            Started container nginx

仍然经过了scheduler,但确实分配到了 k8s-worker01上

有兴趣可以再删除后再创建,重复几次验证

五、pod的生命周期

5.1 Pod生命周期

  • 有些pod(比如运行httpd服务),正常情况下会一直运行中,但如果手动删除它,此pod会终止
  • 也有些pod(比如执行计算任务),任务计算完后就会自动终止

上面两种场景中,pod从创建到终止的过程就是pod的生命周期。

在这里插入图片描述

5.1.1 容器启动
  1. pod中的容器在创建前,有初始化容器(init container)来进行初始化环境

  2. 初化完后,主容器(main container)开始启动

  3. 主容器启动后,有一个post start的操作(启动后的触发型操作,或者叫启动后钩子)

  4. post start后,就开始做健康检查

    • 第一个健康检查叫存活状态检查(liveness probe ),用来检查主容器存活状态的

    • 第二个健康检查叫准备就绪检查(readiness probe),用来检查主容器是否启动就绪

5.1.2 容器终止
  1. 可以在容器终止前设置pre stop操作(终止前的触发型操作,或者叫终止前钩子)
  2. 当出现特殊情况不能正常销毁pod时,大概等待30秒会强制终止
  3. 终止容器后还可能会重启容器(视容器重启策略而定)。
5.1.3 回顾容器重启策略
  • Always:表示容器挂了总是重启,这是默认策略

  • OnFailures:表示容器状态为错误时才重启,也就是容器正常终止时不重启

  • Never:表示容器挂了不予重启

  • 对于Always这种策略,容器只要挂了,就会立即重启,这样是很耗费资源的。所以Always重启策略是这么做的:第一次容器挂了立即重启,如果再挂了就要延时10s重启,第三次挂了就等20s重启… 依次类推

5.2 HealthCheck健康检查

当Pod启动时,容器可能会因为某种错误(服务未启动或端口不正确)而无法访问等。

5.2.1 Health Check方式

kubelet拥有两个检测器,它们分别对应不同的触发器(根据触发器的结构执行进一步的动作)

方式说明
Liveness Probe(存活状态探测)指示容器是否正在运行。如果存活态探测失败,则 kubelet 会杀死容器, 并且容器将根据其重启策略决定未来。如果容器不提供存活探针, 则默认状态为 Success
readiness Probe(就绪型探测)指示容器是否准备好为请求提供服务。如果就绪态探测失败, 端点控制器将从与 Pod 匹配的所有服务的端点列表中删除该 Pod 的 IP 地址。 初始延迟之前的就绪态的状态值默认为 Failure。 如果容器不提供就绪态探针,则默认状态为 Success。注:检查后不健康,将容器设置为Notready;如果使用service来访问,流量不会转发给此种状态的pod
startup Probe指示容器中的应用是否已经启动。如果提供了启动探针,则所有其他探针都会被 禁用,直到此探针成功为止。如果启动探测失败,kubelet 将杀死容器,而容器依其 重启策略进行重启。 如果容器没有提供启动探测,则默认状态为 Success
5.2.2 Probe探测方式
方式说明
Exec执行命令
HTTPGethttp请求某一个URL路径
TCPtcp连接某一个端口
gRPC使用 gRPC 执行一个远程过程调用。 目标应该实现 gRPC健康检查。 如果响应的状态是 “SERVING”,则认为诊断成功。 gRPC 探针是一个 alpha 特性,只有在你启用了 “GRPCContainerProbe” 特性门控时才能使用。
5.2.3 liveness-exec案例

1, 准备YAML文件

[root@k8s-master1 ~]# vim pod-liveness-exec.yml
apiVersion: v1
kind: Pod
metadata:
  name: liveness-exec
  namespace: default
spec:
  containers:
  - name: liveness
    image: busybox
    imagePullPolicy: IfNotPresent
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe:            			    #  Liveness Probe(存活状态探测) 
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5 				# pod启动延迟5秒后探测
      periodSeconds: 5 						# 每5秒探测1次

2, 应用YAML文件

[root@k8s-master1 ~]# kubectl apply -f pod-liveness-exec.yml

3, 通过下面的命令观察

[root@k8s-master1 ~]# kubectl describe pod liveness-exec
......
Events:
  Type     Reason     Age   From               Message
  ----     ------     ----  ----               -------
  Normal   Scheduled  40s   default-scheduler  Successfully assigned default/liveness-exec to k8s-worker1
  Normal   Pulled     38s   kubelet    Container image "busybox" already present on machine
  Normal   Created    37s   kubelet     Created container liveness
  Normal   Started    37s   kubelet     Started container liveness
  Warning  Unhealthy  3s    kubelet     Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory

看到40s前被调度以k8s-worker1节点,3s前健康检查出问题

4, 过几分钟再观察

[root@k8s-master1 ~]# kubectl describe pod liveness-exec
......
Events:
  Type     Reason     Age                  From               Message
  ----     ------     ----                 ----               -------
  Normal   Scheduled  3m42s                default-scheduler  Successfully assigned default/liveness-exec to k8s-worker1
  Normal   Pulled     70s (x3 over 3m40s)  kubelet     Container image "busybox" already present on machine
  Normal   Created    70s (x3 over 3m39s)  kubelet     Created container liveness
  Normal   Started    69s (x3 over 3m39s)  kubelet     Started container liveness
  Warning  Unhealthy  26s (x9 over 3m5s)   kubelet     Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
  Normal   Killing    26s (x3 over 2m55s)  kubelet     Container liveness failed liveness probe, will be restarted
[root@k8s-master1 ~]# kubectl get pod
NAME            READY   STATUS    RESTARTS   AGE
liveness-exec   1/1     Running   3          4m12s

看到重启3次,慢慢地重启间隔时间会越来越长
拓展: 容器重启策略验证
apiVersion: v1
kind: Pod
metadata:
  name: liveness-exec
  namespace: default
spec:
  restartPolicy: Never					# 把容器重启策略由默认的always改为Never
  containers:
  - name: liveness
    image: busybox
    imagePullPolicy: IfNotPresent
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5                         
      periodSeconds: 5                                 

请自行验证

验证结果为:

  • 容器健康检查出现问题后,不再重启,也不会继续sleep 600秒,而是直接关闭了
5.2.4 liveness-httpget案例

1, 编写YMAL文件

[root@k8s-master1 ~]# vim pod-liveness-httpget.yml
apiVersion: v1
kind: Pod
metadata:
  name: liveness-httpget
  namespace: default
spec:
  containers:
  - name: liveness
    image: nginx:1.15-alpine
    imagePullPolicy: IfNotPresent
    ports:							    # 指定容器端口,这一段不写也行,端口由镜像决定 
    - name: http						# 自定义名称,不需要与下面的port: http对应
      containerPort: 80					# 类似dockerfile里的expose 80
    livenessProbe:
      httpGet:                          # 使用httpGet方式
        port: http                      # http协议,也可以直接写80端口
        path: /index.html               # 探测家目录下的index.html
      initialDelaySeconds: 3            # 延迟3秒开始探测
      periodSeconds: 5                  # 每隔5s钟探测一次

2, 应用YAML文件

[root@k8s-master1 ~]# kubectl apply -f pod-liveness-httpget.yml

3, 验证查看

[root@k8s-master1 ~]# kubectl get pods
NAME               READY   STATUS             RESTARTS   AGE
liveness-httpget   1/1     Running            0          9s

4, 交互删除nginx里的主页文件

[root@k8s-master1 ~]# kubectl exec -it liveness-httpget -- rm -rf /usr/share/nginx/html/index.html

5, 验证查看会发现

[root@k8s-master1 ~]# kubectl get pod
NAME               READY   STATUS    RESTARTS   AGE
liveness-httpget   1/1     Running   1          11m

只restart一次
5.2.5 liveness-tcp案例

1, 编写YAML文件

检测端口

[root@k8s-master1 ~]# vim pod-liveness-tcp.yml
apiVersion: v1
kind: Pod
metadata:
  name: liveness-tcp
  namespace: default
spec:
  containers:
  - name: liveness
    image: nginx:1.15-alpine
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
    livenessProbe:
      tcpSocket:                        # 使用tcp连接方式
        port: 80                        # 连接80端口进行探测
      initialDelaySeconds: 3
      periodSeconds: 5

2, 应用YAML文件创建pod

[root@k8s-master1 ~]# kubectl apply -f pod-liveness-tcp.yml
pod/liveness-tcp created

3, 查看验证

[root@k8s-master1 ~]# kubectl get pod
NAME               READY   STATUS             RESTARTS   AGE
liveness-tcp       1/1     Running            0          14s

4, 交互关闭nginx

[root@k8s-master1 ~]# kubectl exec -it liveness-tcp -- /usr/sbin/nginx -s stop

5, 再次验证查看

[root@k8s-master1 ~]# kubectl get pod
NAME               READY   STATUS    RESTARTS   AGE
liveness-tcp       1/1     Running   1          5m13s

也只重启1次,重启后重新初始化了
5.2.6 readiness案例

1, 编写YAML文件

[root@k8s-master1 ~]# vim pod-readiness-httpget.yml
apiVersion: v1
kind: Pod
metadata:
  name: readiness-httpget
  namespace: default
spec:
  containers:
  - name: readiness
    image: nginx:1.15-alpine
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
    readinessProbe:                     # 健康检查方式  这里由liveness换成了readiness(就绪型探测)
      httpGet:       					# HTTPGet探测方式
        port: http
        path: /index.html
      initialDelaySeconds: 3
      periodSeconds: 5

2, 应用YAML文件

[root@k8s-master1 ~]# kubectl apply -f pod-readiness-httpget.yml
pod/readiness-httpget created

3, 验证查看

[root@k8s-master1 ~]# kubectl get pod
NAME                READY   STATUS             RESTARTS   AGE
readiness-httpget   1/1     Running            0          10s

4, 交互删除nginx主页

[root@k8s-master1 ~]# kubectl exec -it readiness-httpget -- rm -rf /usr/share/nginx/html/index.html

5, 再次验证

[root@k8s-master1 ~]# kubectl get pod
NAME                READY   STATUS    RESTARTS   AGE
readiness-httpget   0/1     Running   0          2m49s

READY状态为0/1

6, 交互创建nginx主页文件再验证

[root@k8s-master1 ~]# kubectl exec -it readiness-httpget -- touch /usr/share/nginx/html/index.html
[root@k8s-master1 ~]# kubectl get pod
NAME                READY   STATUS             RESTARTS   AGE
readiness-httpget   1/1     Running            0          3m10s

READY状态又为1/1了
5.2.7 readiness+liveness综合案例

实际使用中推荐 readiness+liveness结合使用
1, 编写YAML文件

[root@k8s-master1 ~]# vim pod-readiness-liveiness.yml
apiVersion: v1
kind: Pod
metadata:
  name: readiness-liveness-httpget
  namespace: default
spec:
  containers:
  - name: readiness-liveness
    image: nginx:1.15-alpine
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
    livenessProbe:
      httpGet:    # 探测对应的文件是否存在
        port: http
        path: /index.html
      initialDelaySeconds: 1    #容器启动后1s开始探测
      periodSeconds: 3              #每隔3s探测一次
    readinessProbe:
      httpGet:      # 探测对应的文件是否存在
        port: http
        path: /index.html
      initialDelaySeconds: 5
      periodSeconds: 5

2, 应用YAML文件

[root@k8s-master1 ~]# kubectl apply -f pod-readiness-liveiness.yml
pod/readiness-liveness-httpget created

3, 验证

[root@k8s-master1 ~]# kubectl exec -it readiness-httpget -- rm -rf /usr/share/nginx/html/index.html

[root@k8s-master1 ~]# kubectl get pod |grep readiness-liveness-httpget
NAME                         READY   STATUS             RESTARTS   AGE
readiness-liveness-httpget   0/1     Running            0          6s

5.3 post-start

1, 编写YAML文件

[root@k8s-master1 ~]# vim pod-poststart.yml

apiVersion: v1
kind: Pod
metadata:
  name: poststart
  namespace: default
spec:
  containers:
  - name: poststart
    image: nginx:1.15-alpine
    imagePullPolicy: IfNotPresent
    lifecycle:                                       # 生命周期事件
      postStart:    # 创建haha这个目录
        exec:
          command: ["mkdir","-p","/usr/share/nginx/html/haha"]

2, 应用YMAL文件

[root@k8s-master1 ~]# kubectl apply -f pod-poststart.yml

3, 验证

[root@k8s-master1 ~]# kubectl get pods
NAME                         READY   STATUS             RESTARTS   AGE
poststart                    1/1     Running            0          25s
[root@k8s-master1 ~]# kubectl exec -it poststart -- ls /usr/share/nginx/html -l
total 8
-rw-r--r-- 1 root root 494 Apr 16 13:08 50x.html
drwxr-xr-x 2 root root   6 Aug  5 05:33 haha			有创建此目录
-rw-r--r-- 1 root root 612 Apr 16 13:08 index.html

5.4 pre-stop

容器终止前执行的命令

1, 编写YAML文件

[root@k8s-master1 ~]# vim prestop.yml
apiVersion: v1
kind: Pod
metadata:
  name: prestop
  namespace: default
spec:
  containers:
  - name: prestop
    image: nginx:1.15-alpine
    imagePullPolicy: IfNotPresent
    lifecycle:                                       # 生命周期事件
      preStop:                                       # preStop
        exec:
          command: ["/bin/sh","-c","sleep 60000000"]     # 容器终止前sleep 60000000秒

2, 应用YAML文件创建pod

[root@k8s-master1 ~]# kubectl apply -f prestop.yml
pod/prestop created

3, 删除pod验证

[root@k8s-master1 ~]# kubectl delete -f prestop.yml
pod "prestop" deleted		会在这一步等待一定的时间(大概30s-60s左右)才能删除,说明验证成功

结论: 当出现特殊情况不能正常销毁pod时,大概等待30秒会强制终止

5.5 pod故障排除

状态描述
Pending(悬决)Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。
Running(运行中)pod已经绑定到一个节点,并且已经创建了所有容器。至少有一个容器正在运行中,或正在启动或重新启动。
completed(完成)Pod中的所有容器都已成功终止,不会重新启动。
Failed(失败)Pod的所有容器均已终止,且至少有一个容器已在故障中终止。也就是说,容器要么以非零状态退出,要么被系统终止。
Unknown(未知)由于某种原因apiserver无法获得Pod的状态,通常是由于Master与Pod所在主机kubelet通信时出错。
CrashLoopBackOff多见于CMD语句错误或者找不到container入口语句导致了快速退出,可以用kubectl logs 查看日志进行排错
  • kubectl describe pod pod名
  • kubectl logs pod [-c CONTAINER]
  • kubectl exec pod [-c CONTAINER] --COMMAND [args…]

kubernetes持久化存储卷

一、存储卷介绍

容器数据的持久化

作用:

pod有生命周期,生命周期结束后pod里的数据会消失(如配置文件,业务数据等)。

解决: 我们需要将数据与pod分离,将数据放在专门的存储卷上

pod在k8s集群的节点中是可以调度的, 如果pod挂了被调度到另一个节点,那么数据和pod的联系会中断。

解决: 所以我们需要与集群节点分离的存储系统才能实现数据持久化

简单来说: volume提供了在容器上挂载外部存储的能力

二、存储卷的分类

kubernetes支持的存储卷类型非常丰富,使用下面的命令查看:

# kubectl explain pod.spec.volumes

或者参考: https://kubernetes.io/docs/concepts/storage/

kubernetes支持的存储卷列表如下:

我们将上面的存储卷列表进行简单的分类:

  • 本地存储卷
    • emptyDir pod删除,数据也会被清除, 用于数据的临时存储
    • hostPath 宿主机目录映射(本地存储卷)
  • 网络存储卷
    • NAS类 nfs等
    • SAN类 iscsi,FC等
    • 分布式存储 glusterfs,cephfs,rbd,cinder等
    • 云存储 aws,azurefile等

三、存储卷的选择

市面上的存储产品种类繁多, 但按应用角度主要分为三类:

  • 文件存储 如:nfs,glusterfs,cephfs等
    • 优点: 数据共享(多pod挂载可以同读同写)
    • 缺点: 性能较差
  • 块存储 如: iscsi,rbd等
    • 优点: 性能相对于文件存储好
    • 缺点: 不能实现数据共享(部分)
  • 对象存储 如: ceph对象存储
    • 优点: 性能好, 数据共享
    • 缺点: 使用方式特殊,支持较少

面对kubernetes支持的形形色色的存储卷,如何选择成了难题。在选择存储时,我们要抓住核心需求:

  • 数据是否需要持久性
  • 数据可靠性 如存储集群节点是否有单点故障,数据是否有副本等
  • 性能
  • 扩展性 如是否能方便扩容,应对数据增长的需求
  • 运维难度 存储的运维难度是比较高的,尽量选择稳定的开源方案或商业产品
  • 成本

总之, 存储的选择是需要考虑很多因素的, 熟悉各类存储产品, 了解它们的优缺点,结合自身需求才能选择合适自己的。

四、本地存储卷之emptyDir

  • 应用场景

    实现pod内容器之间数据共享

  • 特点

随着pod被删除,该卷也会被删除

1.创建yaml文件

[root@k8s-master1 ~]# vim volume-emptydir.yml
apiVersion: v1
kind: Pod
metadata:
  name: volume-emptydir
spec:
  containers:
  - name: write
    image: centos
    imagePullPolicy: IfNotPresent
    command: ["bash","-c","echo haha > /data/1.txt ; sleep 6000"]
    volumeMounts:
    - name: data
      mountPath: /data

  - name: read
    image: centos
    imagePullPolicy: IfNotPresent
    command: ["bash","-c","cat /data/1.txt; sleep 6000"]
    volumeMounts:
    - name: data
      mountPath: /data
      
  volumes:
  - name: data
    emptyDir: {}

2.基于yaml文件创建pod

[root@k8s-master1 ~]# kubectl apply -f volume-emptydir.yml
pod/volume-emptydir created

3.查看pod启动情况

[root@k8s-master1 ~]# kubectl get pods |grep volume-emptydir
NAME                               READY   STATUS    RESTARTS   AGE
volume-emptydir                    2/2     Running   0          15s

4.查看pod描述信息

[root@k8s-master1 ~]# kubectl describe pod volume-emptydir | tail -10
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  50s   default-scheduler  Successfully assigned default/volume-emptydir to k8s-worker1
  Normal  Pulling    50s   kubelet            Pulling image "centos:centos7"
  Normal  Pulled     28s   kubelet            Successfully pulled image "centos:centos7" in 21.544912361s
  Normal  Created    28s   kubelet            Created container write
  Normal  Started    28s   kubelet            Started container write
  Normal  Pulled     28s   kubelet            Container image "centos:centos7" already present on machine
  Normal  Created    28s   kubelet            Created container read
  Normal  Started    28s   kubelet            Started container read

5.验证

[root@k8s-master1 ~]# kubectl logs volume-emptydir -c write

[root@k8s-master1 ~]# kubectl logs volume-emptydir -c read
haha

[root@k8s-master1 ~]# kubectl exec -it volume-emptydir  -c read -- cat /data/1.txt

[root@k8s-master1 ~]# kubectl exec -it volume-emptydir  -c read -- /bin/bash

[root@k8s-master1 ~]# kubectl exec -it volume-emptydir  -c read -- /bin/sh

五、本地存储卷之hostPath

  • 应用场景

    pod内与集群节点目录映射(pod中容器想访问节点上数据,例如监控,只有监控访问到节点主机文件才能知道集群节点主机状态)

  • 缺点

    如果集群节点挂掉,控制器在另一个集群节点拉起容器,数据就会变成另一台集群节点主机的了(无法实现数据共享)

1.创建yaml文件

[root@k8s-master1 ~]# vim volume-hostpath.yml
apiVersion: v1
kind: Pod
metadata:
  name: volume-hostpath
spec:
  containers:
  - name: busybox
    image: busybox
    imagePullPolicy: IfNotPresent
    command: ["/bin/sh","-c","echo haha > /data/1.txt ; sleep 600"]
    volumeMounts:
    - name: data
      mountPath: /data
      
  volumes:
  - name: data
    hostPath:
      path: /opt
      type: Directory

2.基于yaml文件创建pod

[root@k8s-master1 ~]# kubectl apply  -f volume-hostpath.yml
pod/volume-hostpath created

3.查看pod状态

[root@k8s-master1 ~]# kubectl get pods -o wide |grep volume-hostpath
volume-hostpath     1/1   Running   0    29s     10.224.69.245   k8s-worker02   <none>     <none>
可以看到pod是在k8s-worker02节点上

在这里插入图片描述

4.验证pod所在机器上的挂载文件

[root@k8s-worker02 ~]# cat /opt/1.txt
haha

在这里插入图片描述

六、网络存储卷之nfs

1.搭建nfs服务器

[root@nfsserver ~]# mkdir -p /data/nfs
[root@nfsserver ~]# vim /etc/exports
/data/nfs       *(rw,no_root_squash,sync)
[root@nfsserver ~]# systemctl restart nfs-server
[root@nfsserver ~]# systemctl enable nfs-server

2.所有node节点安装nfs客户端相关软件包

[root@k8s-worker1 ~]# yum install nfs-utils -y

[root@k8s-worker2 ~]# yum install nfs-utils -y

3.验证nfs可用性

[root@node1 ~]# showmount -e 192.168.10.129
Export list for 192.168.10.129:
/data/nfs *

[root@node2 ~]# showmount -e 192.168.10.129
Export list for 192.168.10.129:
/data/nfs *

4.master节点上创建yaml文件

[root@k8s-master1 ~]# vim volume-nfs.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: volume-nfs
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.15-alpine
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - name: documentroot
          mountPath: /usr/share/nginx/html
        ports:
        - containerPort: 80
      volumes:
      - name: documentroot
        nfs:
          server: 192.168.10.129     #要挂载在哪个服务器ip地址上 
          path: /data/nfs

5.应用yaml创建

[root@k8s-master1 ~]#  kubectl apply -f volume-nfs.yml
deployment.apps/nginx-deployment created

6.在nfs服务器共享目录中创建验证文件

[root@nfsserver ~]# echo "volume-nfs" > /data/nfs/index.html

7.验证pod

[root@k8s-master1 ~]# kubectl get pod |grep volume-nfs
volume-nfs-649d848b57-qg4bz   1/1     Running   0          10s
volume-nfs-649d848b57-wrnpn   1/1     Running   0          10s


[root@k8s-master1 ~]# kubectl exec -it volume-nfs-649d848b57-qg4bz -- /bin/sh
/ # ls /usr/share/nginx/html/
index.html
/ # cat /usr/share/nginx/html/index.html
volume-nfs										# 文件内容与nfs服务器上创建的一致
/ # exit


[root@k8s-master1 ~]# kubectl exec -it volume-nfs-649d848b57-wrnpn -- /bin/sh
/ # ls /usr/share/nginx/html/
index.html
/ # cat /usr/share/nginx/html/index.html
volume-nfs										# 文件内容与nfs服务器上创建的一致
/ # exit

七、PV(持久存储卷)与PVC(持久存储卷声明)

7.1 认识pv与pvc

kubernetes存储卷的分类太丰富了,每种类型都要写相应的接口与参数才行,这就让维护与管理难度加大。

persistenvolume(PV) 是配置好的一段存储(可以是任意类型的存储卷)

  • 也就是说将网络存储共享出来,配置定义成PV。

PersistentVolumeClaim(PVC)是用户pod使用PV的申请请求。

  • 用户不需要关心具体的volume实现细节,只需要关心使用需求。

7.2 pv与pvc之间的关系

  • pv提供存储资源(生产者)

  • pvc使用存储资源(消费者)

  • 使用pvc绑定pv
    在这里插入图片描述

7.3 实现nfs类型pv与pvc

1.编写创建pv的YAML文件

[root@k8s-master1 ~]# vim pv-nfs.yml
apiVersion: v1
kind: PersistentVolume						# 类型为PersistentVolume(pv)
metadata:		
  name: pv-nfs								# 名称
spec:
  capacity:
    storage: 1Gi							# 大小
  accessModes:
    - ReadWriteMany							# 访问模式
  nfs:
    path: /data/nfs							# nfs共享目录
    server: 192.168.10.129					# nfs服务器IP

访问模式有3种 参考: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes

  • ReadWriteOnce 单节点读写挂载
  • ReadOnlyMany 多节点只读挂载
  • ReadWriteMany 多节点读写挂载

cephfs存储卷3种类型都支持, 我们要实现多个nginx跨节点之间的数据共享,所以选择ReadWriteMany模式。

2.创建pv并验证

[root@k8s-master1 ~]# kubectl apply -f pv-nfs.yml
persistentvolume/pv-nfs created
[root@k8s-master1 ~]# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv-nfs   1Gi        RWX            Retain           Available                                   81s

说明:

  • RWX为ReadWriteMany的简写
  • Retain是回收策略
    • Retain表示需要不使用了需要手动回收
    • 参考: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#reclaim-policy

3.编写创建pvc的YAML文件

[root@k8s-master1 ~]# vim pvc-nfs.yml
apiVersion: v1
kind: PersistentVolumeClaim				# 类型为PersistentVolumeClaim(pvc)
metadata:
  name: pvc-nfs							# pvc的名称
spec:
  accessModes:
    - ReadWriteMany						# 访问模式
  resources:
    requests:
      storage: 1Gi						# 大小要与pv的大小保持一致

4.创建pvc并验证

[root@k8s-master1 ~]# kubectl apply -f pvc-nfs.yml
persistentvolumeclaim/pvc-nfs created
[root@k8s-master1 ~]# kubectl get pvc
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc-nfs   Bound    pv-nfs   1Gi        RWX                           38s

注意: STATUS必须为Bound状态(Bound状态表示pvc与pv绑定OK)

5.编写deployment的YMAL

[root@k8s-master1 ~]# vim deploy-nginx-nfs.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx-nfs
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.15-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        volumeMounts:                    # 卷的挂载
        - name: www
          mountPath: /usr/share/nginx/html    #挂载到这个位置上
      volumes:                                    #谁被挂载过来
      - name: www  #卷的名称
        persistentVolumeClaim:
          claimName: pvc-nfs    #对应的pvc

6.应用YAML创建deploment

[root@k8s-master1 ~]# kubectl apply -f deploy-nginx-nfs.yml
deployment.apps/deploy-nginx-nfs created

7.验证pod

[root@k8s-master1 ~]# kubectl get pod |grep deploy-nginx-nfs
deploy-nginx-nfs-6f9bc4546c-gbzcl   1/1     Running   0          1m46s
deploy-nginx-nfs-6f9bc4546c-hp4cv   1/1     Running   0          1m46s

8.验证pod内卷的数据

[root@k8s-master1 ~]# kubectl exec -it deploy-nginx-nfs-6f9bc4546c-gbzcl -- /bin/sh
/ # ls /usr/share/nginx/html/
index.html
/ # cat /usr/share/nginx/html/index.html
volume-nfs
/ # exit


[root@k8s-master1 ~]# kubectl exec -it deploy-nginx-nfs-6f9bc4546c-hp4cv -- /bin/sh
/ # ls /usr/share/nginx/html/
index.html
/ # cat /usr/share/nginx/html/index.html
volume-nfs
/ # exit

7.4 subpath使用

subpath是指可以把相同目录中不同子目录挂载到容器中不同的目录中使用的方法。以下通过案例演示:

编辑文件
# vim 01_create_pod.yaml

编辑后查看,保持内容一致即可
# cat 01_create_pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod1
spec:
  containers:
  - name: c1
    image: busybox
    command: ["/bin/sleep","100000"]
    volumeMounts:
      - name: data
        mountPath: /opt/data1
        subPath: data1
      - name: data
        mountPath: /opt/data2
        subPath: data2
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: pvc-nfs
执行文件,创建pod
# kubectl apply -f 01_create_pod.yaml
pod/pod1 created
编辑文件
# vim 02_create_pvc.yaml

查看编辑后文件,保持内容一致即可
# cat 02_create_pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim                             # 类型为PersistentVolumeClaim(pvc)
metadata:
  name: pvc-nfs                                                 # pvc的名称
spec:
  accessModes:
    - ReadWriteMany                                             # 访问模式
  resources:
    requests:
      storage: 1Gi                                              # 大小要与pv的大小保持一致
执行文件,创建pvc
# kubectl apply  -f 02_create_pvc.yaml
persistentvolumeclaim/pvc-nfs created
编辑文件
# vim 03_create_pv_nfs.yaml

查看编辑后文件,保持内容一致,注意修改nfs服务器及其共享的目录
# cat 03_create_pv_nfs.yaml
apiVersion: v1
kind: PersistentVolume               # 类型为PersistentVolume(pv)
metadata:
  name: pv-nfs                                  # 名称
spec:
  capacity:
    storage: 1Gi                            # 大小
  accessModes:
    - ReadWriteMany                     # 访问模式
  nfs:
    path: /sdb                        # nfs共享目录
    server: 192.168.10.214
执行文件,创建pv
# kubectl apply -f 03_create_pv_nfs.yaml
persistentvolume/pv-nfs created
在nfs服务器查看pod中目录是否自动添加到nfs服务器/sdb目录中
[root@nfsserver ~]# ls /sdb
data1  data2

八、存储的动态供给

8.1 什么是动态供给

每次使用存储要先创建pv, 再创建pvc,真累! 所以我们可以实现使用存储的动态供给特性。

  • 静态存储需要用户申请PVC时保证容量和读写类型与预置PV的容量及读写类型完全匹配, 而动态存储则无需如此.
  • 管理员无需预先创建大量的PV作为存储资源

Kubernetes从1.4版起引入了一个新的资源对象StorageClass,可用于将存储资源定义为具有显著特性的类(Class)而不是具体

的PV。用户通过PVC直接向意向的类别发出申请,匹配由管理员事先创建的PV,或者由其按需为用户动态创建PV,这样就免去

了需要先创建PV的过程。

8.2 使用NFS文件系统创建存储动态供给

PV对存储系统的支持可通过其插件来实现,目前,Kubernetes支持如下类型的插件。

官方地址:https://kubernetes.io/docs/concepts/storage/storage-classes/

官方插件是不支持NFS动态供给的,但是我们可以用第三方的插件来实现

第三方插件地址: https://github.com/kubernetes-retired/external-storage

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
1.下载并创建storageclass

[root@k8s-master1 ~]# wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/class.yaml

[root@k8s-master1 ~]# mv class.yaml storageclass-nfs.yml
[root@k8s-master1 ~]# cat storageclass-nfs.yml
apiVersion: storage.k8s.io/v1
kind: StorageClass				# 类型
metadata:
  name: nfs-client		# 名称,要使用就需要调用此名称
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner 	# 动态供给插件
parameters:
  archiveOnDelete: "false"		# 删除数据时是否存档,false表示不存档,true表示存档
[root@k8s-master1 ~]# kubectl apply -f storageclass-nfs.yml
storageclass.storage.k8s.io/managed-nfs-storage created
[root@k8s-master1 ~]# kubectl get storageclass
NAME         PROVISIONER                                   RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
nfs-client   k8s-sigs.io/nfs-subdir-external-provisioner   Delete          Immediate           false                  10s

# RECLAIMPOLICY pv回收策略,pod或pvc被删除后,pv是否删除还是保留。
# VOLUMEBINDINGMODE Immediate 模式下PVC与PV立即绑定,主要是不等待相关Pod调度完成,不关心其运行节点,直接完成绑定。相反的 WaitForFirstConsumer模式下需要等待Pod调度完成后进行PV绑定。
# ALLOWVOLUMEEXPANSION pvc扩容

2.下载并创建rbac

因为storage自动创建pv需要经过kube-apiserver,所以需要授权。

[root@k8s-master1 ~]# wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/rbac.yaml

[root@k8s-master1 ~]# mv rbac.yaml storageclass-nfs-rbac.yaml
[root@k8s-master1 ~]# cat storageclass-nfs-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io

[root@k8s-master1 ~]# kubectl apply -f rbac.yaml
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created

3.创建动态供给的deployment

需要一个deployment来专门实现pv与pvc的自动创建

[root@k8s-master1 ~]# vim deploy-nfs-client-provisioner.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccount: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: k8s-sigs.io/nfs-subdir-external-provisioner
            - name: NFS_SERVER
              value: 192.168.10.129
            - name: NFS_PATH
              value: /data/nfs
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.10.129
            path: /data/nfs
[root@k8s-master1 ~]# kubectl apply -f deploy-nfs-client-provisioner.yml
deployment.apps/nfs-client-provisioner created
[root@k8s-master1 ~]# kubectl get pods |grep nfs-client-provisioner
nfs-client-provisioner-5b5ddcd6c8-b6zbq   1/1     Running   0          34s
测试存储动态供给是否可用

# vim nginx-sc.yaml

---
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx
  serviceName: "nginx"
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      imagePullSecrets:
      - name: huoban-harbor
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "nfs-client"
      resources:
        requests:
          storage: 1Gi
[root@k8s-master1 nfs]# kubectl get pods
NAME                                     READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-9c988bc46-pr55n   1/1     Running   0          95s
web-0                                    1/1     Running   0          95s
web-1                                    1/1     Running   0          61s
[root@nfsserver ~]# ls /data/nfs/
default-www-web-0-pvc-c4f7aeb0-6ee9-447f-a893-821774b8d11f  default-www-web-1-pvc-8b8a4d3d-f75f-43af-8387-b7073d07ec01 

扩展:

批量下载文件:
# for file in class.yaml deployment.yaml rbac.yaml  ; do wget https://raw.githubusercontent.com/kubernetes-incubator/external-storage/master/nfs-client/deploy/$file ; done

Kubernetes配置与密钥管理 ConfigMap&Secret

一、ConfigMap

1.1 什么是configmap

  • kubernetes集群可以使用ConfigMap来实现对容器中应用的配置管理
  • 可以把ConfigMap看作是一个挂载到pod中的存储卷

1.2 创建ConfigMap的4种方式

1.2.1 在命令行指定参数创建

通过直接在命令行中指定configmap参数创建,即--from-literal=key=value; --from参数可加多个

[root@k8s-master1 ~]# kubectl create configmap cm1 --from-literal=host=127.0.0.1 --from-literal=port=3306
configmap/cm1 created
[root@k8s-master1 ~]# kubectl get cm
NAME   DATA   AGE
cm1    2      12s
[root@k8s-master1 ~]#  kubectl describe cm cm1
[root@k8s-master1 ~]#  kubectl describe configmap cm1
Name:         cm1
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
host:
----
127.0.0.1
port:
----
3306
Events:  <none>
1.2.2 在命令行通过多个文件创建

通过指定文件创建,即将一个配置文件创建为一个ConfigMap,--from-file=文件路径; --from参数可加多个

[root@k8s-master1 ~]#  echo -n 127.0.0.1 > host
[root@k8s-master1 ~]#  echo -n 3306 > port				

[root@k8s-master1 ~]#  kubectl create configmap cm2 --from-file=./host --from-file=./port
configmap/cm2 created

[root@k8s-master1 ~]#  kubectl get cm
NAME   DATA   AGE
cm1    2      3m45s
cm2    2      94s
[root@k8s-master1 ~]#  kubectl describe cm cm2
[root@k8s-master1 ~]#  kubectl describe configmap cm2
Name:         cm2
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
host:
----
127.0.0.1
port:
----
3306
Events:  <none>
1.2.3 在命令行通过文件提供多个键值对创建

通过一个文件内多个键值对,--from-env-file=文件路径; --from参数可加多个

[root@k8s-master1 ~]#  vim env.txt
host=127.0.0.1
port=3306

[root@k8s-master1 ~]#  kubectl create configmap cm3 --from-env-file=env.txt
configmap/cm3 created
[root@k8s-master1 ~]#  kubectl get cm
NAME   DATA   AGE
cm1    2      4m37s
cm2    2      2m26s
cm3    2      12s
[root@k8s-master1 ~]#  kubectl describe cm cm3
[root@k8s-master1 ~]#  kubectl describe configmap cm3
Name:         cm3
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
host:
----
127.0.0.1
port:
----
3306
Events:  <none>
1.2.4 通过YAML资源清单文件创建

通过kubectl create/apply -f YMAL文件 创建 ; --from参数可加多个

[root@k8s-master1 ~]#  vim cm4.yml
apiVersion: v1
kind: ConfigMap
metadata:
  name: cm4
data:
  host: 127.0.0.1
  port: "3306"
  
[root@k8s-master1 ~]#  kubectl apply -f cm4.yml
configmap/cm4 created
[root@k8s-master1 ~]#  kubectl get cm
NAME   DATA   AGE
cm1    2      6m18s
cm2    2      4m7s
cm3    2      113s
cm4    2      11s
[root@k8s-master1 ~]#  kubectl describe cm cm4
Name:         cm4
Namespace:    default
Labels:       <none>
Annotations:
Data
====
host:
----
127.0.0.1
port:
----
3306
Events:  <none>

1.3 ConfigMap的2种使用方式

1.3.1 通过环境变量的方式传递给pod
[root@k8s-master1 ~]#  vim pod-cm1.yml
apiVersion: v1
kind: Pod
metadata:
  name: pod-cm1
spec:
  containers:
  - name: busybox
    image: busybox
    args: [ "/bin/sh", "-c", "sleep 10000" ]    #参数
    envFrom:							# env方式   
    - configMapRef:					# 引用哪个configmap
        name: cm1						# configmap名称
[root@k8s-master1 ~]#  kubectl apply -f pod-cm1.yml
pod/pod-cm1 created
[root@k8s-master1 ~]#  kubectl get pods
NAME               READY   STATUS    RESTARTS   AGE
pod-cm1            1/1     Running   0          9s
[root@k8s-master1 ~]#  kubectl exec pod-cm1 -- env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=pod-cm1
host=127.0.0.1								 # 创建的configmap传进去的env
port=3306									 # 创建的configmap传进去的env
DEPLOY_NGINX_PORT_80_TCP=tcp://10.2.205.160:80
DEPLOY_NGINX_PORT_80_TCP_ADDR=10.2.205.160
KUBERNETES_PORT=tcp://10.2.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.2.0.1:443
MY_SERVICE_SERVICE_HOST=10.2.52.46
MY_SERVICE_PORT_80_TCP_ADDR=10.2.52.46
KUBERNETES_SERVICE_HOST=10.2.0.1
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_ADDR=10.2.0.1
MY_SERVICE_SERVICE_PORT=80
MY_SERVICE_PORT=tcp://10.2.52.46:80
MY_SERVICE_PORT_80_TCP=tcp://10.2.52.46:80
DEPLOY_NGINX_SERVICE_HOST=10.2.205.160
DEPLOY_NGINX_SERVICE_PORT=80
KUBERNETES_PORT_443_TCP_PORT=443
MY_SERVICE_PORT_80_TCP_PORT=80
DEPLOY_NGINX_PORT=tcp://10.2.205.160:80
DEPLOY_NGINX_PORT_80_TCP_PROTO=tcp
DEPLOY_NGINX_PORT_80_TCP_PORT=80
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
MY_SERVICE_PORT_80_TCP_PROTO=tcp
HOME=/root
1.3.2 通过volume的方式挂载到pod内
[root@k8s-master1 ~]#  vim pod-cm2.yml
apiVersion: v1
kind: Pod
metadata:
  name: pod-cm2
spec:
  containers:
  - name: busybox
    image: busybox
    args: [ "/bin/sh", "-c", "sleep 10000" ]
    volumeMounts:                               # 用volume挂载方式
    - name: vol-cm                              # 对应下面的volume名
      mountPath: "/etc/mysql"                   # 挂载到容器内部的路径
      readOnly: true                            # 只读

  volumes:
  - name: vol-cm                                # 卷名称
    configMap:
      name: cm2                                 # configmap的名称
[root@k8s-master1 ~]#  kubectl apply -f pod-cm2.yml
pod/pod-cm2 created
[root@k8s-master1 ~]#  kubectl get pod
NAME      READY   STATUS    RESTARTS   AGE
pod-cm1   1/1     Running   0          3m51s
pod-cm2   1/1     Running   0          49s
[root@k8s-master1 ~]#  kubectl exec pod-cm2 -- ls /etc/mysql
host
port
[root@k8s-master1 ~]#  kubectl exec pod-cm2 -- cat /etc/mysql/host
127.0.0.1

[root@k8s-master1 ~]#  kubectl exec pod-cm2 -- cat /etc/mysql/port
3306

1.4 ConfigMap的热更新

1.4.1 ConfigMap热更新方式

如果修改了value, 那么容器内部会不会更新?

  • 通过环境变量的方式传递给pod。这种方式不会热更新
  • 通过volume的方式挂载到pod内。这种方式会热更新,大概需要半分钟左右。
1.4.2 ConfigMap热更新验证
1.4.2.1 通过环境变量方式

此种方式不会热更新

1.编辑修改对应的configmap

[root@k8s-master1 ~]# kubectl edit cm cm1
apiVersion: v1
data:
  host: 127.0.0.1
  port: "3307"								3306修改成3307
kind: ConfigMap
metadata:
  creationTimestamp: "2020-11-07T12:07:04Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        .: {}
        f:host: {}
        f:port: {}
    manager: kubectl
    operation: Update
    time: "2020-11-07T12:07:04Z"
  name: cm1
  namespace: default
  resourceVersion: "169386"
  selfLink: /api/v1/namespaces/default/configmaps/cm1
  uid: f06cd44d-2ef9-48f2-9ccc-995f9d9ea2ad
  1. 验证对应的pod里的变化,发现很久都不会改变(环境变量方式)
[root@k8s-master1 ~]#  kubectl exec pod-cm1 -- env |grep port
port=3306									仍然为3306
1.4.2.2 通过volume方式
  1. 编辑修改对应的configmap
[root@k8s-master1 ~]#  kubectl edit cm cm2
apiVersion: v1
data:
  host: 127.0.0.1
  port: "3308"							 		 修改成3308
kind: ConfigMap
metadata:
  creationTimestamp: "2020-11-07T12:09:15Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        .: {}
        f:host: {}
        f:port: {}
    manager: kubectl
    operation: Update
    time: "2020-11-07T12:09:15Z"
  name: cm2
  namespace: default
  resourceVersion: "169707"
  selfLink: /api/v1/namespaces/default/configmaps/cm2

2.验证对应的pod里的变化,一段时间后会改变(卷挂载方式)

[root@k8s-master1 ~]#  kubectl exec pod-cm2 -- cat /etc/mysql/port
3308										     大概半分钟后更新

二、Secret

2.1 什么是secret

  • Secret与ConfigMap类似,主要的区别是ConfigMap存储的是明文,而Secret存储的是密文。

  • ConfigMap可以用配置文件管理,而Secret可用于密码、密钥、token等敏感数据的配置管理。

2.2 secret类型

Secret有4种类型:

  • Opaque: base64编码格式的Secret,用来存储密码、密钥、信息、证书等,类型标识符为generic
  • Service Account: 用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的/var/run/secrets/kubernetes.io/serviceaccount目录中
  • kubernetes.io/dockerconfigjson: 用来存储私有docker registry的认证信息,类型标识为docker-registry。
  • kubernetes.io/tls: 用于为SSL通信模式存储证书和私钥文件,命令式创建类型标识为tls。
[root@k8s-master1 ~]#  kubectl create secret -h
Create a secret using specified subcommand.

Available Commands:
  docker-registry Create a secret for use with a Docker registry
  generic         Create a secret from a local file, directory or literal value
  tls             Create a TLS secret

Usage:
  kubectl create secret [flags] [options]

Use "kubectl <command> --help" for more information about a given command.
Use "kubectl options" for a list of global command-line options (applies to all commands).

在这里插入图片描述

2.3 Secret应用案例

创建mysql管理员密码Secret案例,使用Opaque类型来创建mysql密码Secret

2.3.1 将明文密码进行base64编码

Opaque类型密码需要进行base64编码

[root@k8s-master1 ~]#  echo -n 123 |base64
MTIz
假设密码为123,得到的编码为MTIz
2.3.2 编写创建secret的YAML文件
[root@k8s-master1 ~]#  vim secret-mysql.yml
apiVersion: v1
kind: Secret
metadata:
  name: secret-mysql
data:
  password: MTIz
2.3.3 创建secret并确认
[root@k8s-master1 ~]#  kubectl apply -f secret-mysql.yml
secret/secret-mysql created
[root@k8s-master1 ~]#  kubectl get secret |grep secret-mysql
secret-mysql          Opaque                                1      40s

2.4 Secret的2种使用方式

2.4.1 通过环境变量的方式传递给pod

  1. 编写pod的YAML文件使用Secret
[root@k8s-master1 ~]#  vim pod-mysql-secret.yml
apiVersion: v1
kind: Pod
metadata:
  name: pod-mysql-secret1
spec:
  containers:
  - name: mysql
    image: mysql:5.7
    env:
      - name: MYSQL_ROOT_PASSWORD
        valueFrom:
          secretKeyRef:   #挂载 secret
            name: secret-mysql				    # 挂载对应的secret名
            key: password

2.创建pod

[root@k8s-master1 ~]#  kubectl apply -f pod-mysql-secret.yml
pod/pod-mysql-secret1 created

3.验证pod

[root@k8s-master1 ~]#  kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
pod-mysql-secret1                   1/1     Running   0          1m46s

4.验证传入pod的变量效果

[root@k8s-master1 ~]#  kubectl exec -it pod-mysql-secret1 -- /bin/bash
root@pod-mysql-secret1:/# env |grep MYSQL_ROOT_PASSWORD
MYSQL_ROOT_PASSWORD=123

root@pod-mysql-secret1:/# mysql -p123
2.4.2 通过volume的方式挂载到pod内

1.编写pod的YAML文件使用Secret

[root@k8s-master1 ~]#  vim pod-mysql-secret2.yml

apiVersion: v1
kind: Pod
metadata:
  name: pod-mysql-secret2
spec:
  containers:
  - name: busybox
    image: busybox
    args:
    - /bin/sh
    - -c
    - sleep 100000
    volumeMounts:
    - name: vol-secret                  # 定义挂载的卷,对应下面定义的卷名
      mountPath: "/opt/passwd"    # 挂载目录(支持热更新),也可以使用subPath挂载文件(但不支持热更新)
      readOnly: true                    # 只读
  volumes:
  - name: vol-secret                    # 定义卷名
    secret:                             # 使用secret
      secretName: secret-mysql              # 挂载对应的secret名

2.创建pod

[root@k8s-master1 ~]#  kubectl apply -f pod-mysql-secret2.yml
pod/pod-mysql-secret2 created

3.验证pod

[root@k8s-master1 ~]#  kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
pod-mysql-secret2                   1/1     Running   0          15m

4.验证

[root@k8s-master1 ~]#  kubectl exec  pod-mysql-secret2 -- cat /opt/passwd/password
123												 在容器内都被解码了

5.热更新测试

[root@k8s-master1 ~]#  echo -n haha123 |base64
aGFoYTEyMw==

[root@k8s-master1 ~]#  kubectl edit secret secret-mysql
apiVersion: v1
data:
  password: aGFoYTEyMw==					    密码改成haha123的base64编码
kind: Secret
metadata:
[root@k8s-master1 ~]#  kubectl exec  pod-mysql-secret2 -- cat /opt/passwd/password
haha123										   过一会儿,确认密码确实更新了

kubernetes核心概念 Controller

一、pod控制器controller

1.1 Controller作用及分类

controller用于控制pod

参考: https://kubernetes.io/zh/docs/concepts/workloads/controllers/

在这里插入图片描述
控制器主要分为:

  • Deployments 部署无状态应用,控制pod升级,回退
  • ReplicaSet 副本集,控制pod扩容,裁减
  • ReplicationController(相当于ReplicaSet的老版本,现在建议使用Deployments加ReplicaSet替代RC)
  • StatefulSets 部署有状态应用,结合Service、存储等实现对有状态应用部署
  • DaemonSet 守护进程集,运行在所有集群节点(包括master), 比如使用filebeat,node_exporter
  • Jobs 一次性
  • Cronjob 周期性

1.2 Deployment

1.2.1 Replicaset控制器的功能
  • 支持新的基于集合的selector(以前的rc里没有这种功能)
  • 通过改变Pod副本数量实现Pod的扩容和缩容
1.2.2 Deployment控制器的功能
  • Deployment集成了上线部署、滚动升级、创建副本、回滚等功能
  • Deployment里包含并使用了ReplicaSet
1.2.3 Deployment用于部署无状态应用

无状态应用的特点:

  • 所有pod无差别
  • 所有pod中容器运行同一个image
  • 所有pod可以运行在集群中任意node上
  • 所有pod无启动顺序先后之分
  • 随意pod数量扩容或缩容
  • 例如简单运行一个静态web程序
1.2.4 创建deployment类型应用

1, 准备YAML文件

[root@k8s-master1 ~]# vim deployment-nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx			# deployment名
spec:				
  replicas: 1					# 副本集,deployment里使用了replicaset
  selector:
    matchLabels:
      app: nginx				# 匹配的pod标签,表示deployment和rs控制器控制带有此标签的pod
  template:					    # 代表pod的配置模板
    metadata:
      labels:
        app: nginx				# pod的标签
    spec:
      containers:				# 以下为pod里的容器定义
      - name: nginx
        image: nginx:1.15-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80   #容器暴露的端口

2, 应用YAML文件创建deployment

[root@k8s-master1 ~]# kubectl apply -f deployment-nginx.yml
deployment.apps/deploy-nginx created

3, 查看验证

[root@k8s-master1 ~]# kubectl get deployment				# deployment可简写成depoly
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
deploy-nginx   1/1     1            1           19s
[root@k8s-master1 ~]# kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
deploy-nginx-6c9764bb69-pbc2h   1/1     Running   0          75s
[root@k8s-master1 ~]# kubectl get replicasets				# replicasets可简写成rs
NAME                      DESIRED   CURRENT   READY   AGE
deploy-nginx-6c9764bb69   1         1         1       2m6s
1.2.5 访问deployment

1,查看pod的IP地址

[root@k8s-master1 ~]# kubectl get pods -o wide
NAME                            READY   STATUS    RESTARTS   AGE   IP               NODE          NOMINATED NODE   READINESS GATES
deploy-nginx-6d9d558bb6-88nr8   1/1     Running   0          39s   10.244.159.155   k8s-master1   <none>           <none>

pod在k8s-master1节点,pod的IP为10.244.159.155

2, 查看所有集群节点的网卡

[root@k8s-master1 ~]# ifconfig tunl0 |head -2
tunl0: flags=193<UP,RUNNING,NOARP>  mtu 1480
        inet 10.244.159.128  netmask 255.255.255.255
[root@k8s-master2 ~]# ifconfig tunl0 |head -2
tunl0: flags=193<UP,RUNNING,NOARP>  mtu 1480
        inet 10.244.224.0  netmask 255.255.255.255
[root@k8s-master3 ~]# ifconfig tunl0 |head -2
tunl0: flags=193<UP,RUNNING,NOARP>  mtu 1480
        inet 10.244.135.192  netmask 255.255.255.255
[root@k8s-worker1 ~]# ifconfig tunl0 |head -2
tunl0: flags=193<UP,RUNNING,NOARP>  mtu 1480
        inet 10.244.194.64  netmask 255.255.255.255
  • 可以看到所有集群节点的IP都为10.244.0.0/16这个大网段内的子网

3, 在任意集群节点上都可以访问此deploy里pod

# curl 10.244.159.155

结果是任意集群节点都可以访问这个POD,但集群外部是不能访问的
1.2.6 删除deployment中的pod

1, 删除pod(注意: 是删除deployment中的pod

[root@k8s-master1 ~]# kubectl delete pod deploy-nginx-6c9764bb69-pbc2h
pod "deploy-nginx-6c9764bb69-pbc2h" deleted

2, 再次查看,发现又重新启动了一个pod(节点由k8s-master1转为k8s-worker1 了,IP地址也变化了)

[root@k8s-master1 ~]# kubectl get pods  -o wide
NAME                            READY   STATUS    RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS GATES
deploy-nginx-6d9d558bb6-f2t6r   1/1     Running   0          28s   10.244.194.94   k8s-worker1   <none>           <none>

也就是说**pod的IP不是固定的,比如把整个集群关闭再启动,pod也会自动启动,但是IP地址也会变化**

既然IP地址不是固定的,所以需要一个固定的访问endpoint给用户,那么这种方式就是service.

1.2.7 pod版本升级

查看帮助

[root@k8s-master1 ~]# kubectl set image -h

1, 升级前验证nginx版本

[root@k8s-master1 ~]# kubectl describe pods deploy-nginx-6d9d558bb6-f2t6r | grep Image:
    Image:          nginx:1.15-alpine
    
[root@k8s-master1 ~]# kubectl exec deploy-nginx-6d9d558bb6-f2t6r -- nginx -v
nginx version: nginx/1.15.12

2, 升级为1.16版

[root@k8s-master1 ~]# kubectl set image deployment deploy-nginx nginx=nginx:1.16-alpine --record
deployment.apps/deploy-nginx image updated

说明:

  • deployment deploy-nginx代表名为deploy-nginx的deployment

  • nginx=nginx:1.16-alpine前面的nginx为容器名

  • –record 表示会记录

容器名怎么查看?

  • kubectl describe pod pod名查看

  • kubectl edit deployment deployment名来查看容器名

  • kubectl get deployment deployment名 -o yaml来查看容器名

3, 验证

如果升级的pod数量较多,则需要一定时间,可通过下面命令查看是否已经成功

[root@k8s-master1 ~]# kubectl rollout status deployment deploy-nginx	
deployment "deploy-nginx" successfully rolled out

验证 pod

[root@k8s-master1 ~]# kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
deploy-nginx-5f4749c8c8-nskp9   1/1     Running   0          104s     更新后,后面的id变了

验证版本

[root@k8s-master1 ~]# kubectl describe pod deploy-nginx-5f4749c8c8-nskp9 |grep Image:
    Image:          nginx:1.16-alpine							升级为1.16了
    
[root@k8s-master1 ~]# kubectl exec deploy-nginx-5f4749c8c8-nskp9 -- nginx -v
nginx version: nginx/1.16.1										升级为1.16了

练习: 再将nginx1升级为1.17版

[root@k8s-master1 ~]# kubectl set image deployment deploy-nginx nginx=nginx:1.17-alpine --record
deployment.apps/deploy-nginx image updated
1.2.8 pod版本回退

1, 查看版本历史信息

[root@k8s-master1 ~]# kubectl rollout history deployment deploy-nginx
deployment.apps/deploy-nginx
REVISION  CHANGE-CAUSE
1         <none>												原1.15版
2         kubectl set image deployment deploy-nginx nginx=nginx:1.16-alpine --record=true
3         kubectl set image deployment deploy-nginx nginx=nginx:1.17-alpine --record=true

2, 定义要回退的版本(还需要执行才是真的回退版本)

[root@k8s-master1 ~]# kubectl rollout history deployment deploy-nginx --revision=1
deployment.apps/deploy-nginx with revision #1
Pod Template:
  Labels:       app=nginx
        pod-template-hash=6c9764bb69
  Containers:
   nginx:
    Image:      nginx:1.15-alpine				可以看到这是要回退的1.15版本
    Port:       80/TCP
    Host Port:  0/TCP
    Environment:        <none>
    Mounts:     <none>
  Volumes:      <none>

3, 执行回退

[root@k8s-master1 ~]# kubectl rollout undo deployment deploy-nginx --to-revision=1
deployment.apps/deploy-nginx rolled back

4, 验证

[root@k8s-master1 ~]# kubectl rollout history deployment deploy-nginx
deployment.apps/deploy-nginx
REVISION  CHANGE-CAUSE
         kubectl set image deployment deploy-nginx nginx=nginx:1.16-alpine --record=true
         kubectl set image deployment deploy-nginx nginx=nginx:1.17-alpine --record=true
         <none>						回到了1.15版,但revision的ID变了
[root@k8s-master1 ~]# kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
deploy-nginx-6c9764bb69-zgwpj   1/1     Running   0          54s
[root@k8s-master1 ~]# kubectl describe pod deploy-nginx-6c9764bb69-zgwpj |grep Image:
    Image:          nginx:1.15-alpine				回到了1.15版

[root@k8s-master1 ~]# kubectl exec deploy-nginx-6c9764bb69-zgwpj -- nginx -v
nginx version: nginx/1.15.12						回到了1.15版
1.2.9 副本扩容

查看帮助

[root@k8s-master1 ~]# kubectl scale -h

1, 扩容为2个副本

[root@k8s-master1 ~]# kubectl scale deployment deploy-nginx --replicas=2
deployment.apps/deploy-nginx scaled

2, 查看

[root@k8s-master1 ~]# kubectl get pods -o wide
NAME                            READY   STATUS    RESTARTS   AGE   IP               NODE          NOMINATED NODE   READINESS GATES
deploy-nginx-6d9d558bb6-4c64l   1/1     Running   0          27s   10.244.159.157   k8s-master1   <none>           <none>
deploy-nginx-6d9d558bb6-hkq2b   1/1     Running   0          71s   10.244.194.95    k8s-worker1   <none>           <none>

在两个node节点上各1个pod

3, 继续扩容(我们这里只有2个node,但是可以大于node节点数据)

[root@master ~]# kubectl scale deployment deploy-nginx --replicas=4
deployment.extensions/nginx1 scaled
[root@k8s-master1 ~]# kubectl get pods -o wide
NAME                            READY   STATUS    RESTARTS   AGE     IP               NODE          NOMINATED NODE   READINESS GATES
deploy-nginx-6d9d558bb6-4c64l   1/1     Running   0          87s     10.244.159.157   k8s-master1   <none>           <none>
deploy-nginx-6d9d558bb6-586dr   1/1     Running   0          31s     10.244.135.197   k8s-master3   <none>           <none>
deploy-nginx-6d9d558bb6-hkq2b   1/1     Running   0          2m11s   10.244.194.95    k8s-worker1   <none>           <none>
deploy-nginx-6d9d558bb6-kvgsc   1/1     Running   0          31s     10.244.224.13    k8s-master2   <none>           <none>
1.2.10 副本裁减

1, 指定副本数为1进行裁减

[root@k8s-master1 ~]# kubectl scale deployment deploy-nginx --replicas=1
deployment.apps/deploy-nginx scaled

2, 查看验证

[root@k8s-master1 ~]# kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
deploy-nginx-6d9d558bb6-hkq2b   1/1     Running   0          2m56s
1.2.11 多副本滚动更新

1, 先扩容多点副本

[root@k8s-master1 ~]# kubectl scale deployment deploy-nginx --replicas=16
deployment.apps/deploy-nginx scaled

2, 验证

[root@master ~]# kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
nginx1-7d9b8757cf-2hd48   1/1     Running   0          61s
nginx1-7d9b8757cf-5m72n   1/1     Running   0          61s
nginx1-7d9b8757cf-5w2xr   1/1     Running   0          61s
nginx1-7d9b8757cf-5wmdh   1/1     Running   0          61s
nginx1-7d9b8757cf-6szjj   1/1     Running   0          61s
nginx1-7d9b8757cf-9dgsw   1/1     Running   0          61s
nginx1-7d9b8757cf-dc7qj   1/1     Running   0          61s
nginx1-7d9b8757cf-l52pr   1/1     Running   0          61s
nginx1-7d9b8757cf-m7rt4   1/1     Running   0          26m
nginx1-7d9b8757cf-mdkj2   1/1     Running   0          61s
nginx1-7d9b8757cf-s79kp   1/1     Running   0          61s
nginx1-7d9b8757cf-shhvk   1/1     Running   0          61s
nginx1-7d9b8757cf-sv8gb   1/1     Running   0          61s
nginx1-7d9b8757cf-xbhf4   1/1     Running   0          61s
nginx1-7d9b8757cf-zgdgd   1/1     Running   0          61s
nginx1-7d9b8757cf-zzljl   1/1     Running   0          61s
nginx2-559567f789-8hstz   1/1     Running   1          114m

3, 滚动更新

[root@k8s-master1 ~]# kubectl set image deployment deploy-nginx nginx=nginx:1.17-alpine --record
deployment.apps/deploy-nginx image updated

4, 验证

[root@k8s-master1 ~]# kubectl rollout status deployment deploy-nginx
......
Waiting for deployment "deploy-nginx" rollout to finish: 13 of 16 updated replicas are available...
Waiting for deployment "deploy-nginx" rollout to finish: 14 of 16 updated replicas are available...
Waiting for deployment "deploy-nginx" rollout to finish: 15 of 16 updated replicas are available...
deployment "deploy-nginx" successfully rolled out
1.2.12 删除deployment

如果使用 kubectl delete deployment deploy-nginx 命令删除deployment,那么里面的pod也会被自动删除

1.3 Replicaset

1, 编写YAML文件

[root@master ~]# vim rs-nginx.yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: rs-nginx
  namespace: default
spec:                    # replicaset的spec
  replicas: 2            # 副本数
  selector:              # 标签选择器,对应pod的标签
    matchLabels:
      app: nginx         # 匹配的label
  template:
    metadata:
      name: nginx		# pod名
      labels:           # 对应上面定义的标签选择器selector里面的内容
        app: nginx
    spec:               # pod的spec
      containers:
      - name: nginx
        image: nginx:1.15-alpine
        ports:
        - name: http
          containerPort: 80

2, 应用YAML文件

[root@k8s-master1 ~]# kubectl apply -f rs-nginx.yml
replicaset.apps/rs-nginx created

3, 验证

[root@k8s-master1 ~]# kubectl get rs
NAME       DESIRED   CURRENT   READY   AGE
rs-nginx   2         2         2       26s
[root@k8s-master1 ~]# kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
rs-nginx-7j9hz   1/1     Running   0          44s
rs-nginx-pncsk   1/1     Running   0          43s
[root@k8s-master1 ~]# kubectl get deployment
No resources found.

找不到deployment,说明创建rs并没有创建deployment

二、pod控制器Controller进阶

2.1 DaemonSet

2.1.1 DaemonSet介绍
  • DaemonSet能够让所有(或者特定)的节点运行同一个pod。
  • 当节点加入到K8S集群中,pod会被(DaemonSet)调度到该节点上运行,当节点从K8S集群中被移除,被DaemonSet调度的pod会被移除
  • 如果删除DaemonSet,所有跟这个DaemonSet相关的pods都会被删除。
  • 如果一个DaemonSet的Pod被杀死、停止、或者崩溃,那么DaemonSet将会重新创建一个新的副本在这台计算节点上。
  • DaemonSet一般应用于日志收集监控采集分布式存储守护进程

不能做扩缩容操作

2.1.2 DaemonSet应用案例

1, 编写YAML文件

[root@master ~]# vim daemonset-nginx.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: daemonset-nginx			
spec:
  selector:
    matchLabels:
      name: nginx-ds
  template:      #pod模版
    metadata:
      labels:
        name: nginx-ds
    spec:
      tolerations:						# tolerations代表容忍
      - key: node-role.kubernetes.io/master  # 能容忍的污点key
        effect: NoSchedule   # kubectl explain pod.spec.tolerations查看(能容忍的污点effect)
      containers:
      - name: nginx
        image: nginx:1.15-alpine
        imagePullPolicy: IfNotPresent
        resources:    # resources资源限制是为了防止master节点的资源被占太多(根据实际情况配置)
          limits:
            memory: 100Mi
          requests:
            memory: 100Mi 

2, apply应用YAML文件

[root@k8s-master1 ~]# kubectl apply -f daemonset-nginx.yml
daemonset.apps/daemonset-nginx created

3, 验证

[root@master ~]# kubectl get daemonset				# daemonset可简写为ds
[root@k8s-master1 ~]# kubectl get ds
NAME              DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
daemonset-nginx   4         4         4       4            4           <none>          114s
[root@k8s-master1 ~]# kubectl get pods -o wide
NAME                    READY   STATUS    RESTARTS   AGE   IP               NODE          NOMINATED NODE   READINESS GATES
daemonset-nginx-94z6d   1/1     Running   0          6s    10.244.194.104   k8s-worker1   <none>           <none>
daemonset-nginx-hs9mk   1/1     Running   0          6s    10.244.135.206   k8s-master3   <none>           <none>
daemonset-nginx-jrcf5   1/1     Running   0          6s    10.244.159.167   k8s-master1   <none>           <none>
daemonset-nginx-sslpl   1/1     Running   0          6s    10.244.224.22    k8s-master2   <none>           <none>


k8s集群中每个节点都会运行一个pod

2.2 Job

2.2.1 Job介绍
  • 对于ReplicaSet而言,它希望pod保持预期数目、持久运行下去,除非用户明确删除,否则这些对象一直存在,它们针对的是耐久性任务,如web服务等。
  • 对于非耐久性任务,比如压缩文件,任务完成后,pod需要结束运行,不需要pod继续保持在系统中,这个时候就要用到Job。
  • Job负责批量处理短暂的一次性任务 (short lived one-off tasks),即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束。
2.2.2 Job应用案例
2.2.2.1 计算圆周率2000位

1, 编写YAML文件

[root@master ~]# vim job1.yml
apiVersion: batch/v1
kind: Job
metadata:
  name: pi			# job名
spec:
  template:
    metadata:
      name: pi		# pod名
    spec:
      containers:
      - name: pi	   # 容器名
        image: perl	   # 此镜像有800多M,可提前导入到所有节点,也可能指定导入到某一节点然后指定调度到此节点
        imagePullPolicy: IfNotPresent
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never   # 执行完后不再重启

2, 应用YAML文件创建job

[root@master ~]# kubectl apply -f job1.yml
job.batch/pi created

3, 验证

[root@k8s-master1 ~]# kubectl get jobs
NAME   COMPLETIONS   DURATION   AGE
pi     1/1           11s        18s
[root@k8s-master1 ~]# kubectl get pods
NAME                         READY   STATUS             RESTARTS   AGE
pi-tjq9b                     0/1     Completed          0         27s

Completed状态,也不再是ready状态
[root@k8s-master1 ~]# kubectl logs pi-tjq9b
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275901

2.2.2.2 创建固定次数job

1, 编写YAML文件

[root@master ~]# vim job2.yml
apiVersion: batch/v1
kind: Job
metadata:
  name: busybox-job
spec:
  completions: 10                                               # 执行job的次数
  parallelism: 1                                                # 执行job的并发数
  template:
    metadata:
      name: busybox-job-pod
    spec:
      containers:
      - name: busybox
        image: busybox
        imagePullPolicy: IfNotPresent
        command: ["echo", "hello"]
      restartPolicy: Never

2, 应用YAML文件创建job

[root@k8s-master1 ~]# kubectl apply -f job2.yml
job.batch/busybox-job created

3, 验证

[root@k8s-master1 ~]# kubectl get job
NAME          COMPLETIONS   DURATION   AGE
busybox-job   2/10          9s         9s

[root@k8s-master1 ~]# kubectl get job
NAME          COMPLETIONS   DURATION   AGE
busybox-job   3/10          12s        12s

[root@k8s-master1 ~]# kubectl get job
NAME          COMPLETIONS   DURATION   AGE
busybox-job   4/10          15s        15s

[root@k8s-master1 ~]# kubectl get job
NAME          COMPLETIONS   DURATION   AGE
busybox-job   10/10         34s        48s

34秒左右结束
[root@master ~]# kubectl get pods
NAME                         READY   STATUS             RESTARTS   AGE
busybox-job-5zn6l            0/1     Completed          0          34s
busybox-job-cm9kw            0/1     Completed          0          29s
busybox-job-fmpgt            0/1     Completed          0          38s
busybox-job-gjjvh            0/1     Completed          0          45s
busybox-job-krxpd            0/1     Completed          0          25s
busybox-job-m2vcq            0/1     Completed          0          41s
busybox-job-ncg78            0/1     Completed          0          47s
busybox-job-tbzz8            0/1     Completed          0          51s
busybox-job-vb99r            0/1     Completed          0          21s
busybox-job-wnch7            0/1     Completed          0          32s
2.2.2.3 一次性备份MySQL数据库

通过Job控制器创建应用备份MySQL数据库

2.2.2.3.1 MySQL数据库准备
[root@nginx jobcontroller]# cat 00_mysql.yaml
apiVersion: v1
kind: Service
metadata:
  name: mysql-test
  namespace: default
spec:
  ports:
  - port: 3306
    name: mysql
  clusterIP: None
  selector:
    app: mysql-dump

---

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: db
  namespace: default
spec:
  selector:
    matchLabels:
      app: mysql-dump
  serviceName: "mysql-test"
  template:
    metadata:
      labels:
        app: mysql-dump
    spec:
      nodeName: k8s-master3
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "abc123"
        ports:
        - containerPort: 3306
        volumeMounts:
        - mountPath: "/var/lib/mysql"
          name: mysql-data
      volumes:
      - name: mysql-data
        hostPath:
          path: /opt/mysqldata
2.2.2.3.2 创建用于实现任务的资源清单文件
[root@nginx jobcontroller]# cat 03_job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: mysql-dump
spec:
  template:
    metadata:
      name: mysql-dump
    spec:
      nodeName: k8s-master2
      containers:
      - name: mysql-dump
        image: mysql:5.7
        command: ["/bin/sh","-c","mysqldump --host=mysql-test -uroot -pabc123 --databases mysql > /root/mysql2022.sql"]
        volumeMounts:
        - mountPath: "/root"
          name: mysql-data
      restartPolicy: Never
      volumes:
      - name: mysql-data
        hostPath:
          path: /opt/mysqldump

2.3 CronJob

2.3.1 CronJob介绍
  • 类似于Linux系统的crontab,在指定的时间周期运行相关的任务
  • 时间格式:分时日月周
2.3.2 CronJob应用案例
2.3.2.1 周期性输出字符

1, 编写YAML文件

[root@k8s-master1 ~]# vim cronjob.yml
apiVersion: batch/v1 
kind: CronJob
metadata:
  name: cronjob1
spec:
  schedule: "* * * * *"                 # 分时日月周
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox
            args:
            - /bin/sh
            - -c
            - date; echo hello kubernetes
            imagePullPolicy: IfNotPresent
          restartPolicy: OnFailure

2, 应用YAML文件创建cronjob

[root@k8s-master1 ~]# kubectl apply -f cronjob.yml
cronjob.batch/cronjob1 created

3, 查看验证

[root@k8s-master1 ~]# kubectl get cronjob
NAME       SCHEDULE    SUSPEND   ACTIVE   LAST SCHEDULE   AGE
cronjob1   * * * * *   False     0        <none>          21s
[root@k8s-master1 ~]# kubectl get cronjobs.batch
NAME       SCHEDULE    SUSPEND   ACTIVE   LAST SCHEDULE   AGE
cronjob1   * * * * *   False     0        8s              19m

[root@k8s-master1 ~]# kubectl get pods
NAME                         READY   STATUS             RESTARTS   AGE
cronjob-1564993080-qlbgv     0/1     Completed          0          2m10s
cronjob-1564993140-zbv7f     0/1     Completed          0          70s
cronjob-1564993200-gx5xz     0/1     Completed          0          10s

看AGE时间,每分钟整点执行一次
2.3.2.2 周期性备份MySQL数据库
2.3.2.2.1 MySQL数据库准备
[root@nginx jobcontroller]# cat 00_mysql.yaml
apiVersion: v1
kind: Service
metadata:
  name: mysql-test
  namespace: default
spec:
  ports:
  - port: 3306
    name: mysql
  clusterIP: None
  selector:
    app: mysql-dump

---

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: db
  namespace: default
spec:
  selector:
    matchLabels:
      app: mysql-dump
  serviceName: "mysql-test"
  template:
    metadata:
      labels:
        app: mysql-dump
    spec:
      nodeName: worker03
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "abc123"
        ports:
        - containerPort: 3306
        volumeMounts:
        - mountPath: "/var/lib/mysql"
          name: mysql-data
      volumes:
      - name: mysql-data
        hostPath:
          path: /opt/mysqldata
2.3.2.2.2 Cronjob控制器类型应用资源清单文件
[root@nginx jobcontroller]# cat 05_cronjob.yaml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: mysql-dump
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          nodeName: worker02
          containers:
          - name: c1
            image: mysql:5.7
            command: ["/bin/sh","-c","mysqldump --host=mysql-test -uroot -pabc123 --databases mysql > /root/mysql`date +%Y%m%d%H%M`.sql"]
            volumeMounts:
              - name: mysql-data
                mountPath: "/root"
          restartPolicy: Never
          volumes:
            - name: mysql-data
              hostPath:
                path: /opt/mysqldump

Kubernetes核心概念 Controller之StatefulSet控制器

一、StatefulSet控制器作用

  • StatefulSet 是用来管理有状态应用的控制器。

  • StatefulSet 用来管理某Pod集合的部署和扩缩, 并为这些 Pod 提供持久存储和持久标识符。

  • 参考: https://kubernetes.io/zh/docs/concepts/workloads/controllers/statefulset/

二、无状态应用与有状态应用

2.1 无状态应用

  • 如nginx
  • 请求本身包含了响应端为响应这一请求所需的全部信息。每一个请求都像首次执行一样,不会依赖之前的数据进行响应。
  • 不需要持久化的数据
  • 无状态应用的多个实例之间互不依赖,可以无序的部署、删除或伸缩

2.2 有状态应用

  • 如mysql
  • 前后请求有关联与依赖
  • 需要持久化的数据
  • 有状态应用的多个实例之间有依赖,不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的 ID。

三、StatefulSet的特点

  • 稳定的、唯一的网络标识符。 (通过headless服务实现)
  • 稳定的、持久的存储。 (通过PV,PVC,storageclass实现)
  • 有序的、优雅的部署和缩放。
  • 有序的、自动的滚动更新。

四、StatefulSet的YAML组成

需要三个组成部分:

  1. headless service: 实现稳定,唯一的网络标识
  2. statefulset类型资源: 写法和deployment几乎一致,就是类型不一样
  3. volumeClaimTemplate : 指定存储卷

五、创建StatefulSet应用

  • 参考: https://kubernetes.io/zh/docs/tutorials/stateful-application/basic-stateful-set/

5.1 编辑YAML资源清单文件

创建statelfulset应用来调用名为nfs-client的storageclass,以实现动态供给

[root@k8s-master1 ~]# vim nginx-storageclass-nfs.yml
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None								   # 无头服务
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web											# statefulset的名称
spec:
  serviceName: "nginx"
  replicas: 3										# 3个副本
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.15-alpine
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "nfs-client"		# 与前面定义的storageclass名称对应
      resources:
        requests:
          storage: 1Gi
[root@k8s-master1 ~]# kubectl apply -f nginx-storageclass-nfs.yml
service/nginx created
statefulset.apps/web created
[root@k8s-master1 ~]# kubectl get service
NAME             TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
nginx            ClusterIP      None             <none>        80/TCP           3m37s

[root@k8s-master1 ~]# kubectl get statefulset
NAME   READY   AGE
web    0/3     14s
[root@k8s-master1 ~]# kubectl get statefulset.apps
NAME   READY   AGE
web    0/3     21s
[root@k8s-master1 ~]# kubectl get sts
NAME   READY   AGE
web    0/3     35s

5.2 应用部署后验证

5.2.1 验证pod

产生了3个pod

[root@k8s-master1 ~]# kubectl get pods |grep web
web-0                                     1/1     Running   0          1m15s
web-1                                     1/1     Running   0          1m7s
web-2                                     1/1     Running   0          57s
5.2.2 验证pv

自动产生了3个pv

[root@k8s-master1 ~] # kubectl get pv
pvc-2436b20d-1be3-4c2e-87a9-5533e5c5e2c6  1Gi  RWO   Delete  Bound  default/www-web-0   nfs-client       3m
pvc-3114be74-5969-40eb-aeb3-87a3b9ae17bc  1Gi  RWO   Delete  Bound  default/www-web-1   nfs-client       2m
pvc-43afb71d-1d02-4699-b00c-71679fd75fc3  1Gi  RWO   Delete  ound   default/www-web-2   nfs-client       2m
5.2.3 验证pvc

自动产生了3个PVC

[root@k8s-master1 ~]# kubectl get pvc |grep web
www-web-0  Bound   pvc-2436b20d-1be3-4c2e-87a9-5533e5c5e2c6   1Gi   RWO  nfs-client  3m
www-web-1  Bound   pvc-3114be74-5969-40eb-aeb3-87a3b9ae17bc   1Gi   RWO  nfs-client  2m
www-web-2  Bound   pvc-43afb71d-1d02-4699-b00c-71679fd75fc3   1Gi   RWO  nfs-client  2m
5.2.4 验证nfs服务目录

在nfs服务器(这里为hostos)的共享目录中发现自动产生了3个子目录

[root@nfsserver ~]# ls /data/nfs/
default-www-web-0-pvc-2436b20d-1be3-4c2e-87a9-5533e5c5e2c6  
default-www-web-2-pvc-43afb71d-1d02-4699-b00c-71679fd75fc3
default-www-web-1-pvc-3114be74-5969-40eb-aeb3-87a3b9ae17bc  

3个子目录默认都为空目录

[root@nfsserver ~]# tree /data/nfs/
/data/nfs/
├── default-www-web-0-pvc-2436b20d-1be3-4c2e-87a9-5533e5c5e2c6
├── default-www-web-1-pvc-3114be74-5969-40eb-aeb3-87a3b9ae17bc
└── default-www-web-2-pvc-43afb71d-1d02-4699-b00c-71679fd75fc3
5.2.5 验证存储持久性

在3个pod中其中一个创建一个主页文件

[root@k8s-master1 ~]# kubectl exec -it web-0 -- /bin/sh
/ # echo "haha" >  /usr/share/nginx/html/index.html
/ # exit

在nfs服务器上发现文件被创建到了对应的目录中

[root@nfsserver ~]# tree /data/nfs/
/data/nfs/
├── default-www-web-0-pvc-2436b20d-1be3-4c2e-87a9-5533e5c5e2c6
│   └── index.html								# 此目录里多了index.html文件,对应刚才在web-0的pod中的创建
├── default-www-web-1-pvc-3114be74-5969-40eb-aeb3-87a3b9ae17bc
└── default-www-web-2-pvc-43afb71d-1d02-4699-b00c-71679fd75fc3


[root@nfsserver ~]# cat /data/nfs/default-www-web-0-pvc-2436b20d-1be3-4c2e-87a9-5533e5c5e2c6/index.html
haha											# 文件内的内容也与web-0的pod中创建的一致

删除web-0这个pod,再验证

[root@k8s-master1 ~]# kubectl delete pod web-0
pod "web-0" deleted


[root@k8s-master1 ~]# kubectl get pods |grep web			# 因为控制器的原因,会迅速再拉起web-0这个pod
web-0                                     1/1     Running   0          9s	  # 时间上看到是新拉起的pod
web-1                                     1/1     Running   0          37m
web-2                                     1/1     Running   0          37m

[root@k8s-master1 ~]# kubectl exec -it web-0 -- cat /usr/share/nginx/html/index.html
haha													# 新拉起的pod仍然是相同的存储数据

[root@nfsserver ~]# cat /data/nfs/default-www-web-0-pvc-2436b20d-1be3-4c2e-87a9-5533e5c5e2c6/index.html
haha													# nfs服务器上的数据还在

结论: 说明数据可持久化

5.2.6 访问验证
验证Coredns是否可用
# kubectl get svc -n kube-system
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   6d23h

# dig -t a www.baidu.com @10.96.0.10
# dig -t a nginx.default.svc.cluster.local. @10.96.0.10

....
;; ANSWER SECTION:
nginx.default.svc.cluster.local. 30 IN  A       10.224.194.75
nginx.default.svc.cluster.local. 30 IN  A       10.224.159.141
nginx.default.svc.cluster.local. 30 IN  A       10.224.126.6

# dig -t a web-0.nginx.default.svc.cluster.local. @10.96.0.10
在kubernetes集群内创建pod访问
# kubectl run -it busybox --image=radial/busyboxplus
/ # curl nginx.default.svc.cluster.local.
web-0
/ # curl web-0.nginx.default.svc.cluster.local.
web-0

六、已部署应用滚动更新(含金丝雀发布)

它将按照与 Pod 终止相同的顺序(从最大序号到最小序号)进行,每次更新一个 Pod。

StatefulSet可以使用partition参数来实现金丝雀更新,partition参数可以控制StatefulSet控制器更新的Pod。下面,我们就进行StatefulSet控制器的金丝雀更新实战。

kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}'
说明:
使用patch参数来指定了StatefulSet控制器的partition参数为2,表示当更新时,只有Pod的编号大于等于2的才更新。
# kubectl exec -it web-0 -- nginx -v
nginx version: nginx/1.15.12
kubectl set image sts/web nginx=nginx:latest
kubectl get pods -w
# kubectl exec -it web-2 -- nginx -v
nginx version: nginx/1.21.6
# kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name                                     Image
web-0                                    nginx:1.15-alpine
web-1                                    nginx:1.15-alpine
web-2                                    nginx:latest

如何实现全部更新呢?

kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'
kubectl set image sts/web nginx=nginx:latest
# kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image

七、已部署应用扩容与缩容

在StatefulSet扩容时,会创建一个新的Pod,该Pod与之前的所有Pod都是有顺序的,并且新Pod的序号最大。在缩容时,StatefulSet控制器删除的也是序号最大的Pod。

# kubectl scale sts web --replicas=4
# kubectl get pods -w

kubernetes核心概念 Service

一、 service作用

使用kubernetes集群运行工作负载时,由于Pod经常处于用后即焚状态,Pod经常被重新生成,因此Pod对应的IP地址也会经常变化,导致无法直接访问Pod提供的服务,Kubernetes中使用了Service来解决这一问题,即在Pod前面使用Service对Pod进行代理,无论Pod怎样变化 ,只要有Label,就可以让Service能够联系上Pod,把PodIP地址添加到Service对应的端点列表(Endpoints)实现对Pod IP跟踪,进而实现通过Service访问Pod目的。

  • 通过service为pod客户端提供访问pod方法,即可客户端访问pod入口
  • 通过标签动态感知pod IP地址变化等
  • 防止pod失联
  • 定义访问pod访问策略
  • 通过label-selector相关联
  • 通过Service实现Pod的负载均衡(TCP/UDP 4层)
  • 底层实现由kube-proxy通过userspace、iptables、ipvs三种代理模式

二、kube-proxy三种代理模式

  • kubernetes集群中有三层网络,一类是真实存在的,例如Node Network、Pod Network,提供真实IP地址;一类是虚拟的,例如Cluster Network或Service Network,提供虚拟IP地址,不会出现在接口上,仅会出现在Service当中

  • kube-proxy始终watch(监控)kube-apiserver上关于Service相关的资源变动状态,一旦获取相关信息kube-proxy都要把相关信息转化为当前节点之上的,能够实现Service资源调度到特定Pod之上的规则,进而实现访问Service就能够获取Pod所提供的服务

  • kube-proxy三种代理模式:UserSpace模式、iptables模式、ipvs模式

2.1 UserSpace模式

userspace 模式是 kube-proxy 使用的第一代模式,该模式在 kubernetes v1.0 版本开始支持使用。

userspace 模式的实现原理图示如下:
在这里插入图片描述
kube-proxy 会为每个 Service 随机监听一个端口(proxy port),并增加一条 iptables 规则。所以通过 ClusterIP:Port 访问 Service 的报文都 redirect 到 proxy port,kube-proxy 从它监听的 proxy port 收到报文以后,走 round robin(默认) 或是 session affinity(会话亲和力,即同一 client IP 都走同一链路给同一 pod 服务),分发给对应的 pod。

由于 userspace 模式会造成所有报文都走一遍用户态(也就是 Service 请求会先从用户空间进入内核 iptables,然后再回到用户空间,由 kube-proxy 完成后端 Endpoints 的选择和代理工作),需要在内核空间和用户空间转换,流量从用户空间进出内核会带来性能损耗,所以这种模式效率低、性能不高,不推荐使用。

在这里插入图片描述

2.2 iptables模式

iptables 模式是 kube-proxy 使用的第二代模式,该模式在 kubernetes v1.1 版本开始支持,从 v1.2 版本开始成为 kube-proxy 的默认模式。

iptables 模式的负载均衡模式是通过底层 netfilter/iptables 规则来实现的,通过 Informer 机制 Watch 接口实时跟踪 Service 和 Endpoint 的变更事件,并触发对 iptables 规则的同步更新。

iptables 模式的实现原理图示如下:
在这里插入图片描述
通过图示可以发现在 iptables 模式下,kube-proxy 只是作为 controller,而不是 server,真正服务的是内核的 netfilter,体现在用户态的是 iptables。所以整体的效率会比 userspace 模式高。

在这里插入图片描述

2.3 ipvs模式

ipvs 模式被 kube-proxy 采纳为第三代模式,模式在 kubernetes v1.8 版本开始引入,在 v1.9 版本中处于 beta 阶段,在 v1.11 版本中正式开始使用。

ipvs(IP Virtual Server) 实现了传输层负载均衡,也就是 4 层交换,作为 Linux 内核的一部分。ipvs运行在主机上,在真实服务器前充当负载均衡器。ipvs 可以将基于 TCP 和 UDP 的服务请求转发到真实服务器上,并使真实服务器上的服务在单个 IP 地址上显示为虚拟服务。

ipvs 模式的实现原理图示如下:
在这里插入图片描述

在这里插入图片描述
ipvs 和 iptables 都是基于 netfilter 的,那么 ipvs 模式有哪些更好的性能呢?

  • ipvs 为大型集群提供了更好的可拓展性和性能
  • ipvs 支持比 iptables 更复杂的负载均衡算法(包括:最小负载、最少连接、加权等)
  • ipvs 支持服务器健康检查和连接重试等功能
  • 可以动态修改 ipset 的集合,即使 iptables 的规则正在使用这个集合

ipvs 依赖于 iptables。ipvs 会使用 iptables 进行包过滤、airpin-masquerade tricks(地址伪装)、SNAT 等功能,但是使用的是 iptables 的扩展 ipset,并不是直接调用 iptables 来生成规则链。通过 ipset 来存储需要 DROP 或 masquerade 的流量的源或目标地址,用于确保 iptables 规则的数量是恒定的,这样我们就不需要关心有多少 Service 或是 Pod 了。

使用 ipset 相较于 iptables 有什么优点呢?iptables 是线性的数据结构,而 ipset 引入了带索引的数据结构,当规则很多的时候,ipset 依然可以很高效的查找和匹配。我们可以将 ipset 简单理解为一个 IP(段) 的集合,这个集合的内容可以是 IP 地址、IP 网段、端口等,iptables 可以直接添加规则对这个“可变的集合进行操作”,这样就可以大大减少 iptables 规则的数量,从而减少性能损耗。

举一个例子,如果我们要禁止成千上万个 IP 访问我们的服务器,如果使用 iptables 就需要一条一条的添加规则,这样会在 iptables 中生成大量的规则;如果用 ipset 就只需要将相关的 IP 地址(网段)加入到 ipset 集合中,然后只需要设置少量的 iptables 规则就可以实现这个目标。

下面的表格是 ipvs 模式下维护的 ipset 表集合:

设置名称成员用法
KUBE-CLUSTER-IP所有服务 IP + 端口在 masquerade-all=true 或 clusterCIDR 指定的情况下对 Service Cluster IP 地址进行伪装,解决数据包欺骗问题
KUBE-LOOP-BACK所有服务 IP + 端口 + IP解决数据包欺骗问题
KUBE-EXTERNAL-IP服务外部 IP + 端口将数据包伪装成 Service 的外部 IP 地址
KUBE-LOAD-BALANCER负载均衡器入口 IP + 端口将数据包伪装成 Load Balancer 类型的 Service
KUBE-LOAD-BALANCER-LOCAL负载均衡器入口 IP + 端口 以及externalTrafficPolicy=local接受数据包到 Load Balancer externalTrafficPolicy=local
KUBE-LOAD-BALANCER-FW负载均衡器入口 IP + 端口 以及loadBalancerSourceRanges使用指定的 loadBalancerSourceRanges 丢弃 Load Balancer 类型 Service 的数据包
KUBE-LOAD-BALANCER-SOURCE-CIDR负载均衡器入口 IP + 端口 + 源 CIDR接受 Load Balancer 类型 Service 的数据包,并指定 loadBalancerSourceRanges
KUBE-NODE-PORT-TCPNodePort 类型服务 TCP 端口将数据包伪装成 NodePort(TCP)
KUBE-NODE-PORT-LOCAL-TCPNodePort 类型服务 TCP 端口,带有externalTrafficPolicy=local接受数据包到 NodePort 服务,使用 externalTrafficPolicy=local
KUBE-NODE-PORT-UDPNodePort 类型服务 UDP 端口将数据包伪装成 NodePort(UDP)
KUBE-NODE-PORT-LOCAL-UDPNodePort 类型服务 UDP 端口,使用externalTrafficPolicy=local接受数据包到 NodePort 服务,使用 externalTrafficPolicy=local

2.4 iptables与ipvs对比

  • iptables

    • 工作在内核空间
    • 优点
      • 灵活,功能强大(可以在数据包不同阶段对包进行操作)
    • 缺点
      • 表中规则过多时,响应变慢,即规则遍历匹配和更新,呈线性时延
  • ipvs

    • 工作在内核空间
    • 优点
      • 转发效率高
      • 调度算法丰富:rr,wrr,lc,wlc,ip hash…
    • 缺点
      • 内核支持不全,低版本内核不能使用,需要升级到4.0或5.0以上。
  • 使用iptables与ipvs时机

    • 1.10版本之前使用iptables(1.1版本之前使用UserSpace进行转发)
    • 1.11版本之后同时支持iptables与ipvs,默认使用ipvs,如果ipvs模块没有加载时,会自动降级至iptables

三、 service类型

Service类型决定了访问Service的方法

3.1 service类型

  • ClusterIP

    • 默认,分配一个集群内部可以访问的虚拟IP
  • NodePort

    • 在每个Node上分配一个端口作为外部访问入口
    • nodePort端口范围为:30000-32767
  • LoadBalancer

    • 工作在特定的Cloud Provider上,例如Google Cloud,AWS,OpenStack
  • ExternalName

    • 表示把集群外部的服务引入到集群内部中来,即实现了集群内部pod和集群外部的服务进行通信

3.2 Service参数

  • port 访问service使用的端口

  • targetPort Pod中容器端口

  • nodePort 通过Node实现外网用户访问k8s集群内service (30000-32767)

四、 Service创建

Service的创建在工作中有两种方式,一是命令行创建,二是通过资源清单文件YAML文件创建。

4.1 ClusterIP类型

ClusterIP根据是否生成ClusterIP又可分为普通Service和Headless Service

Service两类:

  • 普通Service:

为Kubernetes的Service分配一个集群内部可访问的固定虚拟IP(Cluster IP), 实现集群内的访问。

  • Headless Service:

该服务不会分配Cluster IP, 也不通过kube-proxy做反向代理和负载均衡。而是通过DNS提供稳定的网络ID来访问,DNS会将headless service的后端直接解析为pod IP列表。

在这里插入图片描述

4.1.1 普通ClusterIP Service创建
4.1.1.1 命令行创建Service
  • 创建Deployment类型的应用
[root@master01 ~]# cat 01_create_deployment_app_nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-server1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
     metadata:
       labels:
         app: nginx
     spec:
       containers:
       - name: c1
         image: nginx:1.15-alpine
         imagePullPolicy: IfNotPresent
         ports:
         - containerPort: 80
  • 应用资源清单文件
[root@master01 ~]# kubectl apply -f 01_create_deployment_app_nginx.yaml
  • 验证Deployment类型的创建情况
[root@master01 ~]# kubectl get deployment.apps
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
nginx-server1   2/2     2            2           13s
  • 创建ClusterIP类型service与Deployment类型应用关联
命令创建service
[root@master01 ~]# kubectl expose deployment.apps nginx-server1 --type=ClusterIP --target-port=80 --port=80
输出
service/nginx-server1 exposed
说明
expose 创建service
deployment.apps 控制器类型
nginx-server1 应用名称,也是service名称
--type=ClusterIP 指定service类型
--target-port=80 指定Pod中容器端口
--port=80 指定service端口
4.1.1.2 通过资源清单文件创建Service
[root@master01 ~]# cat 02_create_deployment_app_nginx_with_service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-server1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
     metadata:
       labels:
         app: nginx
     spec:
       containers:
       - name: nginx-smart
         image: nginx:1.15-alpine
         imagePullPolicy: IfNotPresent
         ports:
         - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  type: ClusterIP
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  selector:
    app: nginx

[root@master01 ~]# kubectl  apply -f 02_create_deployment_app_nginx_with_service.yaml
  • 验证
查看service
[root@master01 ~]# kubectl get service
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP    4d15h
nginx-svc    ClusterIP   10.101.153.50   <none>        80/TCP    3s
查看endpoints
[root@master01 ~]# kubectl get endpoints
NAME         ENDPOINTS                            AGE
kubernetes   192.168.122.30:6443                  4d15h
nginx-svc    172.16.189.74:80,172.16.235.150:80   8s
查看Pod
[root@master01 ~]# kubectl get pods -l app=nginx
NAME                             READY   STATUS    RESTARTS   AGE
nginx-server1-77d4c485d8-gsrmq   1/1     Running   0          12s
nginx-server1-77d4c485d8-mmc52   1/1     Running   0          12s
4.1.1.3 访问
[root@master01 ~]# curl http://10.101.153.50:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
4.1.1.4 两个pod里做成不同的主页方便测试负载均衡
[root@master01 ~]# kubectl exec -it nginx-server1-77d4c485d8-gsrmq -- /bin/bash
root@deployment-nginx-6fcfb67547-nv7dn:/# cd /usr/share/nginx/html/
root@deployment-nginx-6fcfb67547-nv7dn:/usr/share/nginx/html# echo web1 > index.html
root@deployment-nginx-6fcfb67547-nv7dn:/usr/share/nginx/html# exit
exit
[root@master01 ~]# kubectl exec -it nginx-server1-77d4c485d8-mmc52 -- /bin/bash
root@deployment-nginx-6fcfb67547-rqrcw:/# cd /usr/share/nginx/html/
root@deployment-nginx-6fcfb67547-rqrcw:/usr/share/nginx/html# echo web2 > index.html
root@deployment-nginx-6fcfb67547-rqrcw:/usr/share/nginx/html# exit
exit
4.1.1.5 测试
[root@master01 ~]# curl 10.101.153.50[root@master01 ~]# while true;do curl 10.101.153.50;sleep 1; done
4.1.2 Headless Service
  • 普通的ClusterIP service是service name解析为cluster ip,然后cluster ip对应到后面的pod ip
  • Headless service是指service name 直接解析为后面的pod ip
4.1.2.1 编写用于创建Deployment控制器类型的资源清单文件
[root@master01 ~]# cat 03_create_deployment_app_nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-server1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
     metadata:
       labels:
         app: nginx
     spec:
       containers:
       - name: nginx-smart
         image: nginx:1.15-alpine
         imagePullPolicy: IfNotPresent
         ports:
         - containerPort: 80
4.1.2.2 通过资源清单文件创建headless Service
编写YAML文件
命令
[root@master ~]# vim 04_headless-service.yml
apiVersion: v1
kind: Service
metadata:
  name: headless-service
  namespace: default
spec:
  type: ClusterIP     # ClusterIP类型,也是默认类型
  clusterIP: None     # None就代表是无头service
  ports:                                # 指定service 端口及容器端口
  - port: 80                            # service ip中的端口
    protocol: TCP
    targetPort: 80                      # pod中的端口
  selector:                             # 指定后端pod标签
     app: nginx                    # 可通过kubectl get pod -l app=nginx查看哪些pod在使用此标签
 
4.1.2.3 应用资源清单文件创建headless Service
命令
[root@master ~]# kubectl apply -f 04_headless_service.yml
输出
service/headless-service created
4.1.2.4 查看已创建的headless Service
命令
[root@master ~]# kubectl get svc
输出
NAME               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
headless-service   ClusterIP   None             <none>        80/TCP           2m18s
kubernetes         ClusterIP   10.96.0.1        <none>        443/TCP          5d9h
可以看到headless-service没有CLUSTER-IP,用None表示
4.1.2.5 DNS

DNS服务监视Kubernetes API,为每一个Service创建DNS记录用于域名解析

headless service需要DNS来解决访问问题

DNS记录格式为: ..svc.cluster.local.

4.1.2.5.1 查看kube-dns服务的IP
命令
[root@master1 ~]# kubectl get svc -n kube-system


输出
NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                  AGE
kube-dns         ClusterIP   10.96.0.2      <none>        53/UDP,53/TCP,9153/TCP   5d9h
metrics-server   ClusterIP   10.105.219.44   <none>        443/TCP                  45h
查看到coreDNS的服务地址是10.96.0.2
4.1.2.5.2 在集群主机通过DNS服务地址查找无头服务的dns解析
命令
[root@master01 ~]# dig -t A headless-service.default.svc.cluster.local. @10.96.0.2


输出
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-16.P2.el7_8.2 <<>> -t A headless-service.default.svc.cluster.local. @10.96.0.2
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31371
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;headless-service.default.svc.cluster.local. IN A #被解析域名

;; ANSWER SECTION:
headless-service.default.svc.cluster.local. 30 IN A 10.224.235.147 #注意这里IP

;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.2)
;; WHEN: Sun May 17 10:58:50 CST 2020
;; MSG SIZE  rcvd: 129

4.1.2.5.3 验证pod的IP
命令
[root@master ~]# kubectl get pod -o wide
输出
NAME                                READY   STATUS             RESTARTS   AGE   IP               NODE      NOMINATED NODE   READINESS GATES
nginx-deployment-56bf6c9c8c-jmk7r   1/1     Running            0          35m   10.224.235.147   worker1   <none>           <none>


4.1.2.5.4 在集群中创建一个pod验证

创建一个镜像为busyboxplus:curl的pod,pod名称为bb2,用来解析域名

命令
[root@master01 ~]# kubectl run bbp --image=busyboxplus:curl -it[root@master01 ~]# kubectl run bbp --image=1.28 -it

输出
If you don't see a command prompt, try pressing enter.

解析域名
nslookup headless-service.default.svc.cluster.local.
访问命令
[ root@bbp:/ ]$ curl http://headless-service.default.svc.cluster.local.

输出
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[ root@bbp:/ ]$ exit
Session ended, resume using 'kubectl attach bbp -c bbp -i -t' command when the pod is running

4.2 NodePort类型

  • 创建资源清单文件
[root@master01 ~]# cat 05_create_nodeport_service_app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-app
  labels:
    app: nginx-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-app
  template:
    metadata:
      labels:
        app: nginx-app
    spec:
      containers:
      - name: c1
        image: nginx:1.15-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-app
spec:
  type: NodePort
  selector:
    app: nginx-app
  ports:
  - protocol: TCP
    nodePort: 30001
    port: 8060
    targetPort: 80
  • 应用资源清单文件
[root@master01 ~]# kubectl apply -f 05_create_nodeport_service_app.yaml
deployment.apps/nginx-app created
service/nginx-app created
  • 验证service创建
[root@master01 ~]# kubectl get deployment.apps
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
nginx-app    2/2     2            2           26s


[root@master01 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          2d22h
nginx-app    NodePort    10.104.157.20    <none>        8060:30001/TCP   36s

[root@master01 ~]# kubectl get endpoints
NAME         ENDPOINTS                       AGE
kubernetes   192.168.122.10:6443             2d22h
nginx-app    172.16.1.24:80,172.16.2.20:80   2m10s


[root@master01 ~]# ss -anput | grep ":30001"
tcp    LISTEN     0      128      :::30001                :::*                   users:(("kube-proxy",pid=5826,fd=9))

[root@worker01 ~]# ss -anput | grep ":30001"
tcp    LISTEN     0      128      :::30001                :::*                   users:(("kube-proxy",pid=4937,fd=11))

[root@worker02 ~]# ss -anput | grep ":30001"
tcp    LISTEN     0      128      :::30001                :::*                   users:(("kube-proxy",pid=5253,fd=11))

[root@master01 ~]# kubectl get pods
NAME                          READY   STATUS    RESTARTS   AGE
nginx-app-ffd5ccc78-cnwbx    1/1     Running   0          8m59s
nginx-app-ffd5ccc78-mz77g    1/1     Running   0          8m59s

[root@master01 ~]# kubectl exec -it nginx-app-ffd5ccc78-cnwbx -- bash
root@nginx-app-ffd5ccc78-cnwbx:/# echo "nginx-app-1" > /usr/share/nginx/html/index.html
root@nginx-app-ffd5ccc78-cnwbx:/# exit
exit
[root@master01 ~]# kubectl exec -it nginx-app-ffd5ccc78-mz77g -- bash
root@nginx-app-ffd5ccc78-mz77g:/# echo "nginx-app-2" > /usr/share/nginx/html/index.html
root@nginx-app-ffd5ccc78-mz77g:/# exit
exit
  • 在与kubernetes 节点同一网络主机中访问k8s集群内service
[root@bogon ~]# curl http://192.168.10.12:30001
nginx-app-2
[root@bogon ~]# curl http://192.168.10.13:30001
nginx-app-1
[root@bogon ~]# curl http://192.168.10.14:30001
nginx-app-1
[root@bogon ~]# curl http://192.168.10.15:30001
nginx-app-2

4.3 LoadBalancer

4.3.1 集群外访问过程
  • 用户
  • 域名
  • 云服务提供商提供LB服务
  • NodeIP:Port(service IP)
  • Pod IP:端口

在这里插入图片描述

4.3.2 自建Kubernetes的LoadBalancer类型服务方案-MetalLB

MetalLB可以为kubernetes集群中的Service提供网络负载均衡功能。

MetalLB两大功能为:

  • 地址分配,类似于DHCP
  • 外部通告,一旦MetalLB为服务分配了外部IP地址,它就需要使群集之外的网络意识到该IP在群集中“存在”。MetalLB使用标准路由协议来实现此目的:ARP,NDP或BGP。
4.3.2.1 参考资料

参考网址: https://metallb.universe.tf/installation/

4.3.2.2 应用资源清单文件
资源清单文件下载:
# kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/namespace.yaml
# kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/metallb.yaml
4.3.2.3 准备metallb配置文件
[root@nginx metallb]# cat metallb-conf.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 192.168.10.90-192.168.10.100
 
192.168.10.90-192.168.10.100是集群节点服务器IP同一段。

在master01节点应用资源清单文件
[root@master01 ~]# kubectl apply -f metallb-conf.yaml	
验证配置
# kubectl describe configmap config -n metallb-system
Name:         config
Namespace:    metallb-system
Labels:       <none>
Annotations:  <none>

Data
====
config:
----
address-pools:
- name: default
  protocol: layer2
  addresses:
  - 192.168.10.90-192.168.10.100

Events:  <none>
4.3.2.4发布Service类型为LoadBalancer的Deployment控制器类型应用
创建Deployment控制器类型应用nginx-metallb及service,service类型为LoadBalancer

[root@master01 ~]# vim 02_nginx-metabllb.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-metallb
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx-metallb1
        image: nginx:1.15-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-metallb
spec:
  ports:
  - port: 8090
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: LoadBalancer
  
[root@master01 ~]# kubectl apply -f nginx.yaml
4.3.2.5 验证
[root@master01 ~]# kubectl get ns
NAME                   STATUS   AGE
default                Active   16d
kube-node-lease        Active   16d
kube-public            Active   16d
kube-system            Active   16d
kubernetes-dashboard   Active   13d
metallb-system         Active   130m
test1                  Active   12d
[root@master01 ~]# kubectl get pods -n metallb-system
NAME                         READY   STATUS    RESTARTS   AGE
controller-64f8f944d-qdf8m   1/1     Running   0          110m
speaker-cwzq7                1/1     Running   0          110m
speaker-qk5fb                1/1     Running   0          110m
speaker-wsllb                1/1     Running   0          110m
speaker-x4bwt                1/1     Running   0          110m

[root@master01 ~]# kubectl get svc
NAME            TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)          AGE
kubernetes      ClusterIP      10.96.0.1       <none>           443/TCP          16d
nginx-metallb   LoadBalancer   10.105.239.69   192.168.10.90   8090:31372/TCP   106m

[root@master01 ~]# ping 192.168.10.90
PING 192.168.10.90 (192.168.10.90) 56(84) bytes of data.
64 bytes from 192.168.10.90: icmp_seq=1 ttl=64 time=3.45 ms
64 bytes from 192.168.10.90: icmp_seq=2 ttl=64 time=0.040 ms
4.3.2.6 访问
[root@master01 ~]# curl http://192.168.122.90:8090
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

在这里插入图片描述
注意:使用kubeadm部署kubernetes集群修改方法

如果在IPVS模式下使用kube-proxy,从Kubernetes v1.14.2开始,必须启用ARP模式。

可以通过在当前集群中编辑kube-proxy配置来实现:
# kubectl edit configmap -n kube-system kube-proxy

并设置:
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
  strictARP: true

4.4 ExternalName

4.4.1 ExternalName作用
  • 把集群外部的服务引入到集群内部中来,实现了集群内部pod和集群外部的服务进行通信
  • ExternalName 类型的服务适用于外部服务使用域名的方式,缺点是不能指定端口
  • 还有一点要注意: 集群内的Pod会继承Node上的DNS解析规则。所以只要Node可以访问的服务,Pod中也可以访问到, 这就实现了集群内服务访问集群外服务
4.4.2 将公网域名引入

1, 编写YAML文件

 [root@master01 ~]# vim externelname.yml
 
apiVersion: v1
kind: Service
metadata:
  name: my-externalname
  namespace: default
spec:
  type: ExternalName
  externalName: www.baidu.com                  # 对应的外部域名为www.baidu.com
 

2, 应用YAML文件

 [root@master01 ~]# kubectl apply -f externelname.yml
 service/my-externalname created

3, 查看service

 [root@master01 ~]# kubectl get svc |grep exter
 my-externalname    ExternalName   <none>         www.baidu.com   <none>         69s

4, 查看my-service的dns解析

 [root@master01 ~]# dig -t A my-externalname.default.svc.cluster.local. @10.96.0.2
 
 ; <<>> DiG 9.9.4-RedHat-9.9.4-72.el7 <<>> -t A my-externalname.default.svc.cluster.local. @10.2.0.2
 ;; global options: +cmd
 ;; Got answer:
 ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31378
 ;; flags: qr aa rd; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1
 ;; WARNING: recursion requested but not available
 
 ;; OPT PSEUDOSECTION:
 ; EDNS: version: 0, flags:; udp: 4096
 ;; QUESTION SECTION:
 ;my-externalname.default.svc.cluster.local. IN A
 
 ;; ANSWER SECTION:
 my-externalname.default.svc.cluster.local. 5 IN CNAME www.baidu.com.
 www.baidu.com.          5       IN      CNAME   www.a.shifen.com.
 www.a.shifen.com.       5       IN      A       14.215.177.38           解析的是百度的IP
 www.a.shifen.com.       5       IN      A       14.215.177.39           解析的是百度的IP
 
 ;; Query time: 32 msec
 ;; SERVER: 10.2.0.2#53(10.96.0.2)
 ;; WHEN: Thu Nov 05 11:23:41 CST 2020
 ;; MSG SIZE  rcvd: 245
 [root@master01 ~]# kubectl exec -it deploy-nginx-6c9764bb69-86gwj -- /bin/sh
 / # nslookup www.baidu.com
 ......
 Name:      www.baidu.com
 Address 1: 14.215.177.39
 Address 2: 14.215.177.38
 
 
 / # nslookup my-externalname.default.svc.cluster.local         
 ......
 Name:      my-externalname.default.svc.cluster.local
 Address 1: 14.215.177.38
 Address 2: 14.215.177.39

解析此my-externalname.default.svc.cluster.local域名和解析www.baidu.com是一样的结果

4.4.3 不同命名空间访问

1, 创建ns1命名空间和相关deploy, pod,service

 [root@master01 ~]# vim ns1-nginx.yml
apiVersion: v1                                                  
kind: Namespace                                                 
metadata:                                                             
  name: ns1                                                     # 创建ns1命名空间
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx                    
  namespace: ns1                                                # 属于ns1命名空间
spec:
  replicas: 1                                  
  selector:
    matchLabels:
      app: nginx                                
  template:                                        
    metadata:
      labels:
        app: nginx                             
    spec:
      containers:                              
      - name: nginx
        image: nginx:1.15-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: svc1                                # 服务名
  namespace: ns1                            # 属于ns1命名空间
spec:
  selector:
    app: nginx
  clusterIP: None                           # 无头service
  ports:
  - port: 80                         
    targetPort: 80                  
---
kind: Service
apiVersion: v1
metadata:
  name: external-svc1
  namespace: ns1                            #  属于ns1命名空间
spec:
  type: ExternalName
  externalName: svc2.ns2.svc.cluster.local   # 将ns2空间的svc2服务引入到ns1命名空间
   
   
 [root@master1 ~]# kubectl apply -f ns1-nginx.yml
 namespace/ns1 created
 deployment.apps/deploy-nginx created
 service/svc1 created
 

2, 创建ns2命名空间和相关deploy, pod,service

[root@master01 ~]# vim ns1-nginx.yml
apiVersion: v1                                                  
kind: Namespace                                                 
metadata:                                                             
  name: ns2                                                     # 创建ns2命名空间
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx                    
  namespace: ns2                                                # 属于ns2命名空间
spec:
  replicas: 1                                  
  selector:
    matchLabels:
      app: nginx                                
  template:                                        
    metadata:
      labels:
        app: nginx                             
    spec:
      containers:                              
      - name: nginx
        image: nginx:1.15-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: svc2                                # 服务名
  namespace: ns2                            # 属于ns2命名空间
spec:
  selector:
    app: nginx
  clusterIP: None                           # 无头service
  ports:
  - port: 80                         
    targetPort: 80                  
---
kind: Service
apiVersion: v1
metadata:
  name: external-svc1
  namespace: ns2                            #  属于ns2命名空间
spec:
  type: ExternalName
  externalName: svc1.ns1.svc.cluster.local   # 将ns1空间的svc1服务引入到ns2命名空间
 [root@master01 ~]# kubectl apply -f ns2-nginx.yml
 namespace/ns2 created
 deployment.apps/deploy-nginx created
 service/svc2 created
 service/external-svc2 created

3, 在ns1命名空间的pod里验证

 [root@master01 ~]# kubectl get pods -n ns1
 NAME                            READY   STATUS    RESTARTS   AGE
 deploy-nginx-6c9764bb69-g5xl8   1/1     Running   0          8m10s
 [root@master01 ~]# kubectl exec -it -n ns1 deploy-nginx-6c9764bb69-g5xl8 -- /bin/sh
 / # nslookup svc1
 ......
 Name:      svc1
 Address 1: 10.3.166.140 deploy-nginx-6c9764bb69-g5xl8       IP与ns1里的podIP一致(见下面的查询结果)
 
 / # nslookup svc2.ns2.svc.cluster.local
 .....
 Name:      svc2.ns2.svc.cluster.local
 Address 1: 10.3.104.17 10-3-104-17.svc2.ns2.svc.cluster.local   IP与ns2里的podIP一致(见下面的查询结果)
 
 / # exit
 
 [root@master01 ~]# kubectl get pods -o wide -n ns1
 NAME                            READY   STATUS    RESTARTS   AGE   IP             NODE             NOMINATED NODE   READINESS GATES
 deploy-nginx-6c9764bb69-g5xl8   1/1     Running   0          70m   10.3.166.140   192.168.122.13   <none>           <none>
 [root@master01 ~]# kubectl get pods -o wide -n ns2
 NAME                            READY   STATUS    RESTARTS   AGE   IP            NODE             NOMINATED NODE   READI            NESS GATES
 deploy-nginx-6c9764bb69-8psxl   1/1     Running   0          68m   10.3.104.17   192.168.122.14   <none>           <none>
 

反之,在ns2命名空间的pod里访问svc1.ns1.svc.cluster.local,解析的IP是ns1命名空间里的pod的IP(请自行验证)

4, 验证ns2中的pod的IP变化, ns1中的pod仍然可以使用svc2.ns2.svc.cluster.local访问

 [root@master01 ~]# kubectl get pod -n ns2
 NAME                            READY   STATUS    RESTARTS   AGE
 deploy-nginx-6c9764bb69-8psxl   1/1     Running   0          81m
 
 [root@master01 ~]# kubectl delete pod deploy-nginx-6c9764bb69-8psxl -n ns2
 pod "deploy-nginx-6c9764bb69-8psxl" deleted                   因为有replicas控制器,所以删除pod会自动拉一个起来
 
 [root@master01 ~]# kubectl get pod -o wide -n ns2
 NAME                            READY   STATUS    RESTARTS   AGE     IP             NODE             NOMINATED NODE   READINESS GATES
 deploy-nginx-6c9764bb69-8qbz2   1/1     Running   0          5m36s   10.3.166.141   192.168.122.13   <none>           <none>
 
 pod名称变了,IP也变成了10.3.166.141

回到ns1中的pod验证

 [root@master01 ~]# kubectl exec -it -n ns1 deploy-nginx-6c9764bb69-g5xl8 -- /bin/sh
 
 / # ping svc2.ns2.svc.cluster.local -c 2
 PING svc2.ns2.svc.cluster.local (10.3.166.141): 56 data bytes    解析的IP就是ns2中pod的新IP
 64 bytes from 10.3.166.141: seq=0 ttl=63 time=0.181 ms
 64 bytes from 10.3.166.141: seq=1 ttl=63 time=0.186 ms
 
 --- svc2.ns2.svc.cluster.local ping statistics ---
 2 packets transmitted, 2 packets received, 0% packet loss
 round-trip min/avg/max = 0.181/0.183/0.186 ms
 / # exit
 

五、sessionAffinity

会话粘贴

设置sessionAffinity为Clientip (类似nginx的ip_hash算法,lvs的sh算法)

[root@nginx ~]# cat 02_create_deployment_app_nginx_with_service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-server1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
     metadata:
       labels:
         app: nginx
     spec:
       containers:
       - name: c1
         image: nginx:1.15-alpine
         imagePullPolicy: IfNotPresent
         ports:
         - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  type: ClusterIP
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  selector:
    app: nginx
[root@master01 ~]# kubectl apply -f 02_create_deployment_app_nginx_with_service.yaml
deployment.apps/nginx-server1 created
service/nginx-svc created
[root@master01 ~]# kubectl get pods
NAME                             READY   STATUS    RESTARTS   AGE
nginx-server1-58845f75f4-9zlnw   1/1     Running   0          2m11s
nginx-server1-58845f75f4-ffqdt   1/1     Running   0          2m11s
[root@master01 ~]# kubectl exec -it nginx-server1-58845f75f4-9zlnw bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
root@nginx-server1-58845f75f4-9zlnw:/# echo web1 > /usr/share/nginx/html/index.html
root@nginx-server1-58845f75f4-9zlnw:/# exit
exit
[root@master01 ~]# kubectl exec -it nginx-server1-58845f75f4-ffqdt bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
root@nginx-server1-58845f75f4-ffqdt:/# echo web2 > /usr/share/nginx/html/index.html
root@nginx-server1-58845f75f4-ffqdt:/# exit
exit
[root@master01 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP   16d
nginx-svc    ClusterIP   10.100.53.31   <none>        80/TCP    3m53s
[root@master01 ~]# curl http://10.100.53.31
web1
[root@master01 ~]# curl http://10.100.53.31
web2
或
[root@master01 ~]# while true;do curl 10.100.53.31;sleep 1; done
[root@master01 ~]# kubectl patch svc nginx-svc -p '{"spec":{"sessionAffinity":"ClientIP"}}'
service/nginx-svc patched

[root@master01 ~]# curl 10.100.53.31
web1
多次访问,会话粘贴
设置回sessionAffinity为None
[root@master01 ~]# kubectl patch svc nginx-svc -p '{"spec":{"sessionAffinity":"None"}}'
service/my-service patched

测试
[root@master01 ~]# curl 10.100.53.31
web1
多次访问,回到负载均衡
或
[root@master01 ~]# while true;do curl 10.100.53.31;sleep 1; done
web1
多次访问,会话粘贴

六、修改为ipvs调度方式(拓展)

部署方式不同,修改方法不一样。

本次主要介绍使用kubeadm部署集群方式,二进制部署较为简单。

二进制部署修改:/etc/kubernetes/kube-proxy.yaml文件即可。

从kubernetes1.8版本开始,新增了kube-proxy对ipvs的支持,在kubernetes1.11版本中被纳入了GA.

6.1 修改为IPVS调度方式前升级内核

现使用Centos7u6发布版本,默认内核版本为3.10.0,使用kubernetes为1.18.0时,可升级内核版本至4.18.0或5.6.0版本。

在所有节点中安装,需要重启操作系统更换内核。以下升级方法供参考。

[root@localhost ~]# yum -y install perl

[root@localhost ~]# rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org

[root@localhost ~]# yum -y install https://www.elrepo.org/elrepo-release-7.0-4.el7.elrepo.noarch.rpm

[root@localhost ~]# yum  --enablerepo="elrepo-kernel"  -y install kernel-ml.x86_64 
此处升级为5.0以上版本。

[root@localhost ~]# grub2-set-default 0

[root@localhost ~]# grub2-mkconfig -o /boot/grub2/grub.cfg

[root@localhost ~]# reboot

6.2 修改kube-proxy的配置文件

[root@master01 ~]# kubectl edit configmap kube-proxy -n kube-system
     26     iptables:
     27       masqueradeAll: false
     28       masqueradeBit: 14
     29       minSyncPeriod: 0s
     30       syncPeriod: 30s
     31     ipvs:
     32       excludeCIDRs: null
     33       minSyncPeriod: 0s
     34       scheduler: ""	  # 可以在这里修改ipvs的算法,默认为rr轮循算法
     35       strictARP: false
     36       syncPeriod: 30s
     37     kind: KubeProxyConfiguration
     38     metricsBindAddress: 127.0.0.1:10249
     39     mode: "ipvs"	  # 默认""号里为空,加上ipvs

6.3 查看kube-system的namespace中kube-proxy有关的pod

[root@master01 ~]# kubectl get pods -n kube-system |grep kube-proxy
kube-proxy-69mv6                           1/1     Running   6          2d18h
kube-proxy-jpc6c                           1/1     Running   4          4d16h
kube-proxy-kq65l                           1/1     Running   4          4d16h
kube-proxy-lmphf                           1/1     Running   5          4d16h

6.4 验证kube-proxy-xxx的pod中的信息

[root@master01 ~]# kubectl logs kube-proxy-jpc6c -n kube-system
W0517 00:55:10.914754       1 server_others.go:559] Unknown proxy mode "", assuming iptables proxy
I0517 00:55:10.923228       1 node.go:136] Successfully retrieved node IP: 192.168.122.32
I0517 00:55:10.923264       1 server_others.go:186] Using iptables Proxier.
I0517 00:55:10.923567       1 server.go:583] Version: v1.18.2
I0517 00:55:10.923965       1 conntrack.go:100] Set sysctl 'net/netfilter/nf_conntrack_max' to 131072
I0517 00:55:10.924001       1 conntrack.go:52] Setting nf_conntrack_max to 131072
I0517 00:55:10.924258       1 conntrack.go:83] Setting conntrack hashsize to 32768
I0517 00:55:10.927041       1 conntrack.go:100] Set sysctl 'net/netfilter/nf_conntrack_tcp_timeout_established' to 86400
I0517 00:55:10.927086       1 conntrack.go:100] Set sysctl 'net/netfilter/nf_conntrack_tcp_timeout_close_wait' to 3600
I0517 00:55:10.927540       1 config.go:315] Starting service config controller
I0517 00:55:10.927556       1 shared_informer.go:223] Waiting for caches to sync for service config
I0517 00:55:10.927576       1 config.go:133] Starting endpoints config controller
I0517 00:55:10.927594       1 shared_informer.go:223] Waiting for caches to sync for endpoints config
I0517 00:55:11.027749       1 shared_informer.go:230] Caches are synced for service config
I0517 00:55:11.027858       1 shared_informer.go:230] Caches are synced for endpoints config

6.5 重新启动kube-proxy

删除kube-proxy-xxx的所有pod,让它重新拉取新的kube-proxy-xxx的pod

[root@master01 ~]# kubectl delete pod kube-proxy-69mv6 -n kube-system
pod "kube-proxy-69mv6" deleted

[root@master01 ~]# kubectl delete pod kube-proxy-jpc6c -n kube-system
pod "kube-proxy-jpc6c" deleted

[root@master01 ~]# kubectl delete pod kube-proxy-kq65l -n kube-system
pod "kube-proxy-kq65l" deleted

[root@master01 ~]# kubectl delete pod kube-proxy-lmphf -n kube-system
pod "kube-proxy-lmphf" deleted

[root@master01 ~]# kubectl get pods -n kube-system |grep kube-proxy
kube-proxy-2mk2b                           1/1     Running   0          2m23s
kube-proxy-5bj87                           1/1     Running   0          30s
kube-proxy-7qq9l                           1/1     Running   0          52s
kube-proxy-tjtqf                           1/1     Running   0          80s

随意查看其中1个或3个kube-proxy-xxx的pod,验证是否为IPVS方式了

[root@master1 ~]# kubectl logs kube-proxy-tjtqf -n kube-system
I0517 02:32:26.557696       1 node.go:136] Successfully retrieved node IP: 192.168.122.32
I0517 02:32:26.557745       1 server_others.go:259] Using ipvs Proxier.
W0517 02:32:26.557912       1 proxier.go:429] IPVS scheduler not specified, use rr by default
I0517 02:32:26.560008       1 server.go:583] Version: v1.18.2
I0517 02:32:26.560428       1 conntrack.go:52] Setting nf_conntrack_max to 131072
I0517 02:32:26.561094       1 config.go:315] Starting service config controller
I0517 02:32:26.562251       1 shared_informer.go:223] Waiting for caches to sync for service config
I0517 02:32:26.561579       1 config.go:133] Starting endpoints config controller
I0517 02:32:26.562271       1 shared_informer.go:223] Waiting for caches to sync for endpoints config
I0517 02:32:26.662541       1 shared_informer.go:230] Caches are synced for service config
I0517 02:32:26.662566       1 shared_informer.go:230] Caches are synced for endpoints config
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值