Kubernetes完整详细学习笔记
文章目录
一.Kubernetes集群介绍与搭建
二.资源管理
2.1 命令式对象管理
2.2 命令式对象配置
2.3 声明式对象配置
三.Namespace
3.1 Namespace介绍
3.2 Namespace使用
3.2.1 查看命名空间
3.2.2 创建与删除
四.Pod
4.1 Pod介绍
4.2 Pod基本管理
4.3 Pod 配置
4.3.1 Pod的基本使用
4.3.2 Pod启动
4.3.3 环境变量
4.3.4 端口配置
4.4 容器探测
4.4.1 exec模式实例:
4.4.2 TCPSocket模式实例
4.4.3 HTTPGet模式实例
4.4.4 重启策略
4.5 Pod调度
4.5.1 定向调度
4.5.2 亲和性调度
五.Pod控制器
5.1 Pod控制器介绍
5.2 Pod控制器:ReplicaSet
5.2.1 ReplicaSet介绍
5.2.2 RS实例测试
5.2.3 弹性扩缩容
5.3 Pod控制器:Deployment
5.3.1 Deployment介绍
5.3.2 Deployment实例测试
5.3.3 弹性扩缩容
5.4 Pod控制器:DaemonSet
5.4.1 DaemonSet介绍
5.4.2 DaemonSet实例测试
六.Service
6.1 Service介绍
6.2 ClusterIP 模式
6.2.1 ClusterIP 模式介绍
6.2.2 ClusterIP模式实例测试
6.3 NodePort模式
6.3.1 NodePort介绍
6.3.2 NodePort模式实例测试
七.数据存储
7.1 数据存储介绍
7.2 EmptyDir模式
7.2.1 EmptyDir模式介绍
7.2.2 EmptyDir模式实例测试
7.3 HostPath模式
7.3.1 HostPath模式介绍
7.3.2 HostPath模式实例测试
7.4 NFS模式
7.4.1 NFS模式介绍
7.4.2 NFS模式实例测试
7.5 PV与PVC模式
7.5.1 PV与PVC模式介绍
7.5.2 创建PV
7.5.3 创建PVC
7.5.4 创建Pod使用存储
7.6 ConfigMap模式
7.6.1 ConfigMap模式介绍
7.6.2 ConfigMap模式实例测试
7.7 Secret模式
7.7.1 Secret模式介绍
7.7.2 Secret模式实例测试
小结
一.Kubernetes集群介绍与搭建
搭建过程参考我的另一篇博客完成搭:
Kubernetes详细介绍及平台搭建_kubernetes 开源平台-CSDN博客
二.资源管理
在kubernetes中,所有的内容都被抽象为资源,而用户则需要通过操作资源的方式来管理kubernetes;kubernetes实质上就是一个集群系统,我们可以在集群上面进行各种服务的部署,所有部署的服务事实上就是在kubernetes上运行的容器,并将指定的程序在容器中运行,但kubernetes中最小的管理单元不是容器,是pod,所以只能将容器放在pod当中;Pod可以提供服务之后,就要考虑如何访问Pod中服务,kubernetes提供了Service资源实现这个功能。kubernetes的核心,就是学习如何对集群上的Pod、Pod控制器、Service、存储等各种资源进行操作
Kubernetes的资源管理方式分为三类:
(1)陈述式命令(命令式对象管理) 直接去管理kubernetes,类似于我们直接在docker 中 docker run 命令;
例:kubectl run nginx-pod --image=nginx:latest --port=80
(2)陈述式对象配置(命令式对象配置) 通过命令配置和配置文件去管理kubernetes的资源,类似于类似于 docker-compose.yml;
例:kubectl create/patch -f nginx-pod.yaml
(3)声明式对象配置(声明式对象配置) 通过apply命令和配置文件去管理资源;
例:kubectl apply -f nginx-pod.yaml
类型 | 操作对象 | 适用环境 | 优点 | 缺点 |
命令式对象管理 | 对象 | 测试 | 简单 | 只能操作活动对象,无法审计、跟踪 |
命令式对象配置 | 文件 | 开发 | 可以审计、跟踪 | 项目大时,配置文件多,操作麻烦 |
声明式对象配置 | 目录 | 开发 | 支持目录操作 | 意外情况下难以调试 |
2.1 命令式对象管理
kubectl是kubernetes集群的命令行工具,通过它能够对集群本身进行管理,并能够在集群上进行容器化应用的安装部署。格式为:
kubectl [command] [type] [name] [flags]
comand:指定要对资源执行的操作,例如create、get、delete
type:指定资源类型,比如deployment、pod、service
name:指定资源的名称,并且名称大小写敏感
flags:指定额外的可选参数
例如:
查询k8s集群节点
[root@master ~]# kubectl get nodes
[root@master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready control-plane,master 142m v1.23.0
node Ready <none> 141m v1.23.0
在这里可以查看到节点的状态,持续时间,以及kubernetes版本信息
查询所有的pod
[root@master ~]# kubectl get pods
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-5c4c85f44b-pw8tq 1/1 Running 0 140m
volume-hostpath 2/2 Running 0 85m
在这里可以查看到pod的具体名称,状态,重启此时,持续时间。
查询k8s集群信息
[root@master ~]# kubectl cluster-info
想查看更详细的信息可以在后面加上一个dump,但是会非常冗长
[root@master ~]# kubectl cluster-info
Kubernetes control plane is running at https://192.168.100.110:6443
CoreDNS is running at https://192.168.100.110:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
内容反馈为kubernetes集群的master节点IP,kubeDNS服务地址,调试信息等;
查询kubernetes版本信息
[root@master ~]# kubectl version
[root@master ~]# kubelet --version
Kubernetes v1.23.0
2.2 命令式对象配置
命令式对象配置就是使用命令配合配置文件一起来操作kubernetes资源
创建一个nginxpod.yaml
内容:
apiVersion: v1
kind: Namespace
metadata:
name: base
---
apiVersion: v1
kind: Pod
metadata:
name: nginxpod
namespace: base
spec:
containers:
- name: nginx-containers
image: nginx:latest
保存后使用create命令进行创建资源
[root@master ~]# kubectl apply -f nginxpod.yaml
namespace/base configured
pod/nginxpod created
创建完成后,我们发现一共创建了两个资源,一个namespace,一个pod
使用命令查看我们创建的资源:
[root@master ~]# kubectl get -f nginxpod.yaml
NAME STATUS AGE
namespace/base Active 111m
NAME READY STATUS RESTARTS AGE
pod/nginxpod 1/1 Running 0 46s
使用delete命令删除资源:
[root@master ~]# kubectl delete -f nginxpod.yaml
namespace "base" deleted
pod "nginxpod" deleted
命令式对象配置的方式操作资源,可以简单的认为:命令 + yaml配置文件(里面是命令需要的各种参数)
2.3 声明式对象配置
声明式对象配置跟命令式对象配置很相似,但是它只有一个命令apply。
[root@master ~]# kubectl apply -f nginxpod.yaml
namespace/base configured
pod/nginxpod created
实声明式对象配置就是使用apply描述一个资源最终的状态(在yaml中定义状态) 使用apply操作资源: 如果资源不存在,就创建,相当于 kubectl create 如果资源已存在,就更新
三.Namespace
3.1 Namespace介绍
Namespace 提供了一个隔离的环境,使得不同的用户、团队或项目可以在同一个物理集群上运行,而不会相互干扰。Namespace 可以看作是一种资源命名空间,它允许集群管理员对资源进行分组和管理。Namespace 是 Kubernetes 集群管理的重要组成部分,它提供了一种灵活、高效的方式来组织和隔离资源,使得集群的管理和使用更加方便和安全。
kubernetes集群中的所有的Pod都是可以相互访问的。但是在实际中,可能不想让两个Pod之间进行互相的访问,那此时就可以将两个Pod划分到不同的namespace下。kubernetes通过将集群内部的资源分配到不同的Namespace中,可以形成逻辑上的"组",以方便不同的组的资源进行隔离使用和管理。
3.2 Namespace使用
3.2.1 查看命名空间
查看所有命名空间:
[root@master ~]# kubectl get ns
NAME STATUS AGE
default Active 12m
kube-node-lease Active 12m
kube-public Active 12m
kube-system Active 12m
default 所有未指定Namespace的对象都会被分配在default命名空间
kube-node-lease 集群节点之间的心跳维护,v1.13开始引入
kube-public 此命名空间下的资源可以被所有人访问(包括未认证用户)
kube-system所有由Kubernetes系统创建的资源都处于这个命名空间
[root@master ~]# kubectl get ns default
NAME STATUS AGE
default Active 16m
[root@master ~]# kubectl get ns kube-system
NAME STATUS AGE
kube-system Active 16m
以指定格式进行查看:
[root@master ~]# kubectl get ns default -o yaml
apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2025-02-05T05:13:43Z"
labels:
kubernetes.io/metadata.name: default
name: default
resourceVersion: "206"
uid: 91fc2241-733f-4b2f-bede-972a1f32cbb1
spec:
finalizers:
- kubernetes
status:
phase: Active
查看详细信息:
[root@master ~]# kubectl describe ns default
Name: default
Labels: kubernetes.io/metadata.name=default
Annotations: <none>
Status: Active
No resource quota.
No LimitRange resource.
3.2.2 创建与删除
命令形式创建:
[root@master ~]# kubectl create namespace hello
namespace/hello created
[root@master ~]# kubectl get ns
NAME STATUS AGE
default Active 20m
hello Active 5s
kube-node-lease Active 20m
kube-public Active 20m
kube-system Active 20m
Yaml文件格式创建:
[root@master ~]# vi world.yaml
apiVersion: v1
kind: Namespace
metadata:
name: world
[root@master ~]# kubectl apply -f world.yaml
namespace/world created
[root@master ~]# kubectl get ns
NAME STATUS AGE
---
world Active 5s
命令删除命名空间:
[root@master ~]# kubectl delete ns hello
namespace "hello" deleted
[root@master ~]# kubectl get ns
NAME STATUS AGE
default Active 23m
kube-node-lease Active 23m
kube-public Active 23m
kube-system Active 23m
world Active 112s
删除yaml文件创建的命名空间:delete -f +文件路径
[root@master ~]# kubectl delete -f world.yaml
namespace "world" deleted
[root@master ~]# kubectl get ns
NAME STATUS AGE
default Active 24m
kube-node-lease Active 24m
kube-public Active 24m
kube-system Active 24m
四.Pod
4.1 Pod介绍
Pod是在K8s集群中运行部署应用或服务的最小单元,它是可以支持多容器的。Pod的设计理念是支持多个容器在一个Pod中共享网络地址和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务.比如你运行一个操作系统发行版的软件仓库,一个Nginx容器用来发布软件,另一个容器专门用来从源仓库做同步,这两个容器的镜像不太可能是一个团队开发的,但是他们一块儿工作才能提供一个微服务;这种情况下,不同的团队各自开发构建自己的容器镜像,在部署的时候组合成一个微服务对外提供服务。
Pod创建过程:
用户通过kubectl或其他api客户端提交需要创建的pod信息给apiServer,apiServer开始生成pod对象的信息,并将信息存入etcd,然后返回确认信息至客户端,apiServer开始反映etcd中的pod对象的变化,其它组件使用watch机制来跟踪检查apiServer上的变动,scheduler发现有新的pod对象要创建,开始为Pod分配主机并将结果信息更新至apiServer,node节点上的kubelet发现有pod调度过来,尝试调用docker启动容器,并将结果回送至apiServer,apiServer将接收到的pod状态信息存入etcd中。
Pod的生命周期:
在整个生命周期中,Pod会出现5种状态,分别如下:
挂起(Pending):apiserver已经创建了pod资源对象,但它尚未被调度完成或者仍处于下载镜像的过程中
运行中(Running):pod已经被调度至某节点,并且所有容器都已经被kubelet创建完成
成功(Succeeded):pod中的所有容器都已经成功终止并且不会被重启
失败(Failed):所有容器都已经终止,但至少有一个容器终止失败,即容器返回了非0值的退出状态
未知(Unknown):apiserver无法正常获取到pod对象的状态信息,通常由网络通信失败所导致
4.2 Pod基本管理
命令式创建pod并运行:
nginx pod名
--namespace 指定命名空间
--image 指定镜像
--port 指定端口
[root@master ~]# kubectl run nginx --namespace default --image=nginx:latest --port=80
pod/nginx created
查看Pod:#default是默认命名空间,查看时可以不加-n 选项
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 66s
查看Pod详细信息:
#如果需要指定命名空间就加-n namespace 选项即可。
[root@master ~]# kubectl describe pod nginx
Name: nginx
Namespace: default
Priority: 0
Node: node/192.168.100.120
Start Time: Wed, 05 Feb 2025 13:52:37 +0800
Labels: run=nginx
Annotations: cni.projectcalico.org/containerID: b67fbb2f171ecff0707601143e4b624303f58aaf5e0faa6b4d71bd29675cea26
cni.projectcalico.org/podIP: 10.244.167.129/32
cni.projectcalico.org/podIPs: 10.244.167.129/32
Status: Running
IP: 10.244.167.129
IPs:
IP: 10.244.167.129
Containers:
nginx:
Container ID: docker://a6cddb73578647cda67ed1c0865807c38c298f7ee55ebe56b3c39a7b219c6365
Image: nginx:latest
Image ID: docker-pullable://nginx@sha256:bc2f6a7c8ddbccf55bdb19659ce3b0a92ca6559e86d42677a5a02ef6bda2fcef
Port: 80/TCP
Host Port: 0/TCP
State: Running
Started: Wed, 05 Feb 2025 13:52:57 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-dgctz (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
kube-api-access-dgctz:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 2m45s default-scheduler Successfully assigned default/nginx to node
Normal Pulling 2m44s kubelet Pulling image "nginx:latest"
Normal Pulled 2m25s kubelet Successfully pulled image "nginx:latest" in 19.705450711s
Normal Created 2m25s kubelet Created container nginx
Normal Started 2m25s kubelet Started container nginx
访问Pod:
获取Pod的IP:
[root@master ~]# kubectl get pod nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 4m53s 10.244.167.129 node <none> <none>
访问Pod:
[root@master ~]# curl 10.244.167.129
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
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>
删除Pod:
[root@master ~]# kubectl delete pod nginx
pod "nginx" deleted
[root@master ~]# kubectl get pod
No resources found in default namespace.
当前Pod并不是使用控制器创建,所以并没有容器的重启策略与重建策略。
4.3 Pod 配置
使用kubectl get explain pod.spec.containers可以查询到所有有关Pod的所有配置选项。
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
在kubernetes中基本所有资源的一级属性都是一样的,主要包含5部分:
apiVersion 版本,由kubernetes内部定义,版本号必须可以用 kubectl api-versions 查询
kind 类型,由kubernetes内部定义,版本号必须可以用 kubectl api-resources 查询
metadata 元数据,主要是资源标识和说明,常用的有name、namespace、labels等
spec 描述,这是配置中最重要的一部分,里面是对各种资源配置的详细描述
status 状态信息,里面的内容不需要定义,由kubernetes自动生成
在上面的属性中,spec是接下来研究的重点,继续看下它的常见子属性:
containers <[]Object> 容器列表,用于定义容器的详细信息
nodeName 根据nodeName的值将pod调度到指定的Node节点上
nodeSelector <map[]> 根据NodeSelector中定义的信息选择将该Pod调度到包含这些label的Node 上
hostNetwork 是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
volumes <[]Object> 存储卷,用于定义Pod上面挂在的存储信息
restartPolicy 重启策略,表示Pod在遇到故障的时候的处理策略
4.3.1 Pod的基本使用
编写一个yaml文件:
[root@master ~]# vi nginx.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-base
namespace: base
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
[root@master ~]# kubectl apply -f nginx.yaml
pod/nginx-base created
[root@master ~]# kubectl get pods -n base
NAME READY STATUS RESTARTS AGE
nginx-base 1/1 Running 0 9s
创建一个名为nginx的Pod,在base命名空间之下,镜像使用nginx:latest,镜像策略为本地不存在则去镜像仓库拉取。
三种镜像策略:
imagePullPolicy,用于设置镜像拉取策略,kubernetes支持配置三种拉取策略:
Always:总是从远程仓库拉取镜像(一直远程下载)
IfNotPresent:本地有则使用本地镜像,本地没有则从远程仓库拉取镜像
Never:只使用本地镜像,从不去远程仓库拉取,本地没有就报错 (一直使用本地)
4.3.2 Pod启动
busybox是类似于一个工具类的集合,kubernetes集群启动管理后,它会自动关闭。解决方法就是让其一直在运行,这就用到了command配置。
我们增加busybox,并为busybox添加command字段:
# 进入pod中的busybox容器,查看文件内容
# kubectl exec pod名称 -n 命名空间 -it -c 容器名称 /bin/sh 在容器内部执行命令
#使用这个命令就可以进入某个容器的内部,然后进行相关操作了
[root@master ~]# vi nginx_busybox.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-base
namespace: base
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
- name: busybox
image: busybox:latest
command: ["/bin/sh","-c","touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt; sleep 3; done;"]
[root@master ~]# kubectl apply -f nginx_busybox.yaml
pod/pod-base created
[root@master ~]# kubectl exec pod-base -n base -it -c busybox /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # cat /tmp/hello.txt
06:37:46
06:37:49
06:37:52
4.3.3 环境变量
创建pod-env.yaml,执行文件:
[root@master ~]# vi pod-env.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-env
namespace: base
spec:
containers:
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","while true;do /bin/echo $(date +%T);sleep 60; done;"]
env:
- name: "username"
value: "admin"
- name: "password"
value: "123456"
[root@master ~]# kubectl apply -f pod-env.yaml
pod/pod-env created
#进入容器内查看:
[root@master ~]# kubectl exec pod-env -n base -c busybox -it /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # echo $username
admin
/ # echo $password
123456
/ #
4.3.4 端口配置
常见配置:
name <string> # 端口名称,如果指定,必须保证name在pod中是唯一
containerPort<integer> # 容器要监听的端口(0<x<65536)
protocol <string> # 端口协议。必须是UDP、TCP或SCTP。默认为“TCP”。
测试案例:##注意缩进##
apiVersion: v1
kind: Pod
metadata:
name: nginx-base
namespace: base
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- name: nginxport
containerPort: 80
protocol: TCP
查看nginx的详细信息,可以查看到端口设置为了80:
[root@master ~]# kubectl describe pod nginx-base -n base
Name: nginx-base
Namespace: base
------
Port: 80/TCP
Host Port: 0/TCP
State: Running
4.3.5 资源配额
容器中的程序要运行,肯定是要占用一定资源的,比如cpu和内存等,如果不对某个容器的资源做限制,那么它就可能吃掉大量资源,导致其它容器无法运行。针对这种情况,kubernetes提供了对内存和cpu的资源进行配额的机制
这种机制主要通过resources选项实现
limits:用于限制运行时容器的最大占用资源,当容器占用资源超过limits时会被终止,并进行重启。
requests :用于设置容器需要的最小资源,如果环境资源不够,容器将无法启动。
可配置的参数有:
resources: # 资源配额
limits: # 限制资源(上限)
cpu: "2" # CPU限制,单位是core数
memory: "10Gi" # 内存限制 可以使用Gi、Mi、G、M等形式
requests: # 请求资源(下限)
cpu: "1" # CPU限制,单位是core数
memory # 内存限制
测试实例:
apiVersion: v1
kind: Pod
metadata:
name: nginx-base
namespace: base
spec:
containers:
- name: nginx
image: nginx:latest
resources:
limits:
memory: "5Gi"
requests:
memory: "10Mi"
执行文件并查看:
[root@master ~]# kubectl describe pod -n base nginx-base
Name: nginx-base
Namespace: base
------
Restart Count: 0
Limits:
memory: 5Gi
Requests:
memory: 10Mi
4.4 容器探测
容器探测用于检测容器中的应用实例是否正常工作,是保障业务可用性的一种传统机制。如果经过探测,实例的状态不符合预期,那么kubernetes就会把该问题实例" 摘除 ",不承担业务流量。kubernetes提供了两种探针来实现容器探测,分别是:
liveness probes:存活性探针,用于检测应用实例当前是否处于正常运行状态,如果不是,k8s会重启容器
readiness probes:就绪性探针,用于检测应用实例当前是否可以接收请求,如果不能,k8s不会转发流量
为了使健康检查能够对Pod的运行状况进行诊断,kubelet会调用容器中为探针实现的处理程序,这些处理程序分为三大类:
Exec:在容器内执行命令。
TCPSocket:对指定端口上,容器的IP地址执行TCP检查。
HTTPGet:在容器的IP上执行HTTP GET请求。
处理程序的返回状态也分为三种:
Success:容器通过诊断。
Failed:容器无法通过诊断。
Unknown:诊断失败,状态不确定,将不采取任何措施。
无论使用哪种类型的探针(tcpSocket、httpGet 或 exec),如果 livenessProbe 失败,Kubernetes 会重启容器(而不是整个 Pod)。Pod 内的其他容器如果没有失败,通常不会受影响。tcpSocket:检查是否能够通过指定端口与容器建立 TCP 连接。httpGet:检查是否能够通过 HTTP 请求访问容器的指定路径(如 /health)。exec:执行指定的命令,若命令返回非零状态,认为探针失败。如果一个 Pod 中的多个容器都不断失败,或者容器在 重启后依然无法恢复健康,Kubernetes 会根据其 Pod 的重启策略(restartPolicy)决定是否继续重启容器,或者 删除 Pod 重新创建。默认情况下,Pod 的 restartPolicy 是 Always,这意味着如果容器失败,Kubernetes 会不断重启该容器,直到容器变为健康为止。
4.4.1 exec模式实例:
apiVersion: v1
kind: Pod
metadata:
name: nginx-base
namespace: base
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- name: nginx-port
containerPort: 80
livenessProbe:
exec:
command: ["/bin/cat","/tmp/hello.txt"]
我们使用的是liveness probe,并且在command字段查看了一个完全不存在的文件,这就会导致liveness probe 会检测到我们的Pod是异常状态,那么就会导致Pod会被删除,重新进行相关操作:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 118s default-scheduler Successfully assigned base/nginx-base to node
Normal Pulled 98s kubelet Successfully pulled image "nginx:latest" in 19.759000548s
Normal Pulled 46s kubelet Successfully pulled image "nginx:latest" in 21.551206926s
Normal Created 46s (x2 over 98s) kubelet Created container nginx
Normal Started 46s (x2 over 98s) kubelet Started container nginx
Warning Unhealthy 18s (x6 over 88s) kubelet Liveness probe failed: /bin/cat: /tmp/hello.txt: No such file or directory
#检测到Pod异常,重启策略
Normal Killing 18s (x2 over 68s) kubelet Container nginx failed liveness probe, will be restarted
Normal Pulling 18s (x3 over 117s) kubelet Pulling image "nginx:latest"
当我们将command字段查看的文件换成一个存在的文件:
livenessProbe:
exec:
command: ["/bin/ls","/tmp/"]
将Pod创建之后将不会出现Pod异常,Pod被正常创建不会被重启:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 69s default-scheduler Successfully assigned base/nginx-base to node
Normal Pulling 68s kubelet Pulling image "nginx:latest"
Normal Pulled 49s kubelet Successfully pulled image "nginx:latest" in 19.705980073s
Normal Created 49s kubelet Created container nginx
Normal Started 49s kubelet Started container nginx
4.4.2 TCPSocket模式实例
tcpSocket 就是访问某个端口,看是不是通的:
apiVersion: v1
kind: Pod
metadata:
name: nginx-base
namespace: base
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- name: nginx-port
containerPort: 80
livenessProbe:
tcpSocket:
port: 8080 #访问8080测试端口异常情况
此时我们查看容器详情可以发现:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 52s default-scheduler Successfully assigned base/nginx-base to node
Normal Pulled 32s kubelet Successfully pulled image "nginx:latest" in 19.788718541s
Normal Created 32s kubelet Created container nginx
Normal Started 32s kubelet Started container nginx
Normal Pulling 2s (x2 over 52s) kubelet Pulling image "nginx:latest"
Warning Unhealthy 2s (x3 over 22s) kubelet Liveness probe failed: dial tcp 10.244.167.138:8080: connect: connection refused
Normal Killing 2s kubelet Container nginx failed liveness probe, will be restarted
[root@master ~]# kubectl get pods -n base
NAME READY STATUS RESTARTS AGE
nginx-base 0/1 CrashLoopBackOff 5 (1s ago) 4m51s
由于端口异常在这里的反馈信息为访问8080端口失败,并一直在重启pod,重启次数会不断增长。当重启次达到一定次数后,状态信息会变为CrashLoopBackOff,意为表示 Pod 中的一个容器启动后遇到问题,然后不断尝试重启但失败,解决办法也很简单,我们还需要将端口改为我们设置的正确的映射端口即可。
4.4.3 HTTPGet模式实例
apiVersion: v1
kind: Pod
metadata:
name: nginx-base
namespace: base
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- name: nginx-port
containerPort: 80
livenessProbe:
httpGet:
scheme: HTTP
port: 80
path: /abc #访问一个不存在的路径观察效果
此时查看Pod的详细信息可以发现:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 62s default-scheduler Successfully assigned base/nginx-base to node
Normal Pulled 42s kubelet Successfully pulled image "nginx:latest" in 19.307081658s
Normal Created 42s kubelet Created container nginx
Normal Started 42s kubelet Started container nginx
Normal Pulling 12s (x2 over 62s) kubelet Pulling image "nginx:latest"
Warning Unhealthy 12s (x3 over 32s) kubelet Liveness probe failed: HTTP probe failed with statuscode: 404
发现了错误代码404,尝试访问路径,但是未找到因为我们指定的是一个不错在的路径,于是Pod就会触发机制。
4.4.4 重启策略
在上一节中,所有的Pod发生问题时,它们都进入了重启策略当中,而重启策略是我们可以自行设置的:
- Always :容器失效时,自动重启该容器,这也是默认值。
- OnFailure : 容器终止运行且退出码不为0时重启
- Never : 不论状态为何,都不重启该容器
在containers字段下进行设置:
restartPolicy: Never # 设置重启策略为Never
设置之后创建Pod就会对应其设置的重启策略进行。
4.5 Pod调度
在默认情况下,一个Pod在哪个Node节点上运行,是由Scheduler组件采用相应的算法计算出来的,这个过程是不受人工控制的。但是在实际使用中,这并不满足的需求,因为很多情况下,我们想控制某些Pod到达某些节点上,那么应该怎么做呢?这就要求了解kubernetes对Pod的调度规则,kubernetes提供了四大类调度方式:
自动调度:运行在哪个节点上完全由Scheduler经过一系列的算法计算得出
定向调度:NodeName、NodeSelector
亲和性调度:NodeAffinity、PodAffinity、PodAntiAffinity
污点(容忍)调度:Taints、Toleration
4.5.1 定向调度
定向调度,指的是利用在pod上声明nodeName或者nodeSelector,以此将Pod调度到期望的node节点上。注意,这里的调度是强制的,这就意味着即使要调度的目标Node不存在,也会向上面进行调度,只不过pod运行失败而已。
nodeName模式:
nodeName定向调度值得是我在创建pod的yaml文件中直接声明nodeName,以此期望pod调度到指定的node的节点上,这里的调度是强制性的,就算node不是真实存在的,也会被调度过去,但是pod会运行报错。
测试实例:
apiVersion: v1
kind: Pod
metadata:
name: nginx-base
namespace: base
spec:
containers:
- name: nginx
image: nginx:latest
nodeName: node
将Pod定向调度为node节点,进行查看:
[root@master ~]# kubectl get pods -n base nginx-base
NAME READY STATUS RESTARTS AGE
nginx-base 1/1 Running 0 27s
[root@master ~]# kubectl describe pod -n base nginx-base
Name: nginx-base
Namespace: base
Priority: 0
Node: node/192.168.100.120 ##Pod被调度到node节点
Start Time: Wed, 05 Feb 2025 18:30:57 +0800
Labels: <none>
测试当node不存在时,会如何调度:
[root@master ~]# vi nginx.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-base
namespace: base
spec:
containers:
- name: nginx
image: nginx:latest
nodeName: node100
[root@master ~]# kubectl apply -f nginx.yaml
pod/nginx-base created
[root@master ~]# kubectl get pods -n base nginx-base
NAME READY STATUS RESTARTS AGE
nginx-base 0/1 Pending 0 2s
[root@master ~]# kubectl describe pod -n base nginx-base
Name: nginx-base
Namespace: base
Priority: 0
Node: node100/
Labels: <none>
Annotations: <none>
Status: Pending
IP:
IPs: <none>
此时我们可以查看到,Pod状态是被挂起的状态,这就意味着,虽然node100不存在,但Pod仍然被算法调度过去了,这证明nodeName定向调度是强制性的。
NodeSelector
NodeSelector用于将pod调度到添加了指定标签的node节点上。它是通过kubernetes的label-selector机制实现的,也就是说,在pod创建之前,会由scheduler使用MatchNodeSelector调度策略进行label匹配,找出目标node,然后将pod调度到目标节点,该匹配规则是强制约束。
测试实例:
将master节点标签定义为node=10,将node节点定义为node=11
[root@master ~]# kubectl label node master node=10
node/master labeled
[root@master ~]# kubectl label node node node=11
node/node labeled
编写文件,将Pod调度到node=10节点上(master)
apiVersion: v1
kind: Pod
metadata:
name: nginx-base
namespace: base
spec:
containers:
- name: nginx
image: nginx:latest
nodeSelector:
node: "10"
但在这里可能会发生报错,原因为Unschedulable 错误,可能是 master 节点 taint 了(默认情况下,Kubernetes 通常会 taint master 以防止调度非控制平面 Pod)。
执行命令后即恢复正常:
[root@master ~]# kubectl taint nodes master node-role.kubernetes.io/master-
查看Pod是否被正常调度:
[root@master ~]# kubectl get pods -n base -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-base 1/1 Running 0 3m42s 10.244.219.68 master <none> <none>
4.5.2 亲和性调度
定向调度的两种定向调度的方式,使用起来非常方便,但是也有一定的问题,那就是如果没有满足条件的Node,那么Pod将不会被运行,即使在集群中还有可用Node列表也不行,这就限制了它的使用场景。基于上面的问题,kubernetes还提供了一种亲和性调度(Affinity)。它在NodeSelector的基础之上的进行了扩展,可以通过配置的形式,实现优先选择满足条件的Node进行调度,如果没有,也可以调度到不满足条件的节点上,使调度更加灵活。
亲和性调度分为三类:
nodeAffinity(node亲和性): 以node为目标,解决pod可以调度到哪些node的问题
podAffinity(pod亲和性) : 以pod为目标,解决pod可以和哪些已存在的pod部署在同一个拓扑域中的问题
podAntiAffinity(pod反亲和性) : 以pod为目标,解决pod不能和哪些已存在pod部署在同一个拓扑域中的问题
NodeAffinity:
apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: default
spec:
containers:
- name: nginx
image: nginx:latest
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node
operator: In
values: ["11"]
requiredDuringSchedulingIgnoredDuringExecution:Pod 只有在满足这些条件时才会被调度;nodeSelectorTerms:至少需要满足列表中的一个条件。matchExpressions:节点必须匹配的标签表达式。key:要匹配的标签的键;operator:这是匹配操作符,In 表示节点的标签值必须在 values 列表中。values:一个字符串列表,包含了 key 可能的值。
在执行完文件后我们查看该Pod的详细信息,我们可以观察到,在pod创建之初就被分到了标签为11的node节点上面。
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 19s default-scheduler Successfully assigned base/nginx to node
Normal Pulling 18s kubelet Pulling image "nginx:latest"
五.Pod控制器
5.1 Pod控制器介绍
Pod控制器是管理pod的中间层,使用Pod控制器之后,只需要告诉Pod控制器,想要多少个什么样的Pod就可以了,它会创建出满足条件的Pod并确保每一个Pod资源处于用户期望的目标状态。如果Pod资源在运行中出现故障,它会基于指定策略重新编排Pod。
在kubernetes中,有很多类型的pod控制器,每种都有自己的适合的场景,常见的有:
ReplicaSet:保证副本数量一直维持在期望值,并支持pod数量扩缩容,镜像版本升级
Deployment:通过控制ReplicaSet来控制Pod,并支持滚动升级、回退版本
Horizontal Pod Autoscaler:可以根据集群负载自动水平调整Pod的数量,实现削峰填谷
DaemonSet:在集群中的指定Node上运行且仅运行一个副本,一般用于守护进程类的任务
5.2 Pod控制器:ReplicaSet
5.2.1 ReplicaSet介绍
ReplicaSet会确保Pod副本数在任一时刻都精确满足期望值。用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的Pod来替代;而如果异常多出来的容器也会自动回收。虽然ReplicaSet可以独立使用,但一般还是建议使用 Deployment 来自动管理ReplicaSet,这样就无需担心跟其他机制的不兼容问题(比如ReplicaSet不支持rolling-update但Deployment支持)。也就是说Replicaset通常不会直接创建,而是在创建最高层级的deployment资源时自动创建。
ReplicaSet 主要功能
确保Pod数量:它会确保Kubernetes中有指定数量的Pod在运行,如果少于指定数量的Pod,RC就会创建新的,反之这会删除多余的,保证Pod的副本数量不变。
确保Pod健康:当Pod不健康,比如运行出错了,总之无法提供正常服务时,RC也会杀死不健康的Pod,重新创建新的。
弹性伸缩:在业务高峰或者低峰的时候,可以用过RC来动态的调整Pod数量来提供资源的利用率,当然我们也提到过如果使用HPA这种资源对象的话可以做到自动伸缩。
滚动升级:滚动升级是一种平滑的升级方式,通过逐步替换的策略,保证整体系统的稳定性。
5.2.2 RS实例测试
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: nginx
namespace: default
spec:
replicas: 4
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:latest
本yaml定义了在default命名空间中始终有 4个标签为 app: nginx-pod 的 nginx:latest Pod 副本处于运行状态。如果这些 Pod 中的任何一个失败或被删除,ReplicaSet 会创建新的 Pod 来替换它们,以保持4个副本的总数。
查看pod与rs:
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-6fv4l 1/1 Running 0 113s
nginx-t5fb8 1/1 Running 0 113s
nginx-vllmp 1/1 Running 0 113s
nginx-xvfx5 1/1 Running 0 113s
[root@master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx 4 4 4 2m8s
5.2.3 弹性扩缩容
缩容:(扩容与更换镜像同理)
[root@master ~]# kubectl edit rs nginx
edit 是 kubectl 命令行工具的一个命令,它允许用户直接编辑 Kubernetes 资源对象的配置。当你想要修改一个已经存在的资源,系统会打开一个文本编辑器,允许你直接编辑 pod-rs ReplicaSet 的 YAML 或JSON 配置文件。
编辑文件,将replicas数值,保存退出数据自动更新。
[root@master ~]# kubectl edit rs nginx
---
spec:
replicas: 3
selector:
matchLabels:
app: nginx-pod
replicaset.apps/nginx edited
此时查看资源:
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-6fv4l 1/1 Running 0 5m40s
nginx-t5fb8 1/1 Running 0 5m40s
nginx-xvfx5 1/1 Running 0 5m40s
[root@master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx 3 3 3 5m42s
5.3 Pod控制器:Deployment
5.3.1 Deployment介绍
Deploy:为了更好的管理kubernetes的服务编排问题,在1.2后续的kubernetes版本中就加入了Deployment控制器,但这种控制器并不是直接管理pod,而是通过管理ReplicaSet来更加简介的管理pod,简单的说就是Deployment管理ReplicaSet,ReplicaSet来管理pod。
Deployment功能:
支持ReplicaSet的所有功能
支持发布的停止、继续
支持滚动升级和回滚版本
5.3.2 Deployment实例测试
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:latest
查看资源:
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-7d4578b56c-lc9bs 1/1 Running 0 109s 10.244.167.144 node <none> <none>
nginx-7d4578b56c-lll86 1/1 Running 0 109s 10.244.219.71 master <none> <none>
[root@master ~]# kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
nginx-7d4578b56c 2 2 2 118s nginx nginx:latest app=nginx-pod,pod-template-hash=7d4578b56c
如此看一查看到,创建的deoloyment给我们创建了一个ReplicaSet,并在replicaset下进行创建pod。
5.3.3 弹性扩缩容
扩容:
[root@master ~]# kubectl scale deploy nginx --replicas=6
deployment.apps/nginx scaled
[root@master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-7d4578b56c 6 6 2 4m37s
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-7d4578b56c-7grgl 1/1 Running 0 43s
nginx-7d4578b56c-jvrvz 1/1 Running 0 43s
nginx-7d4578b56c-lc9bs 1/1 Running 0 5m14s
nginx-7d4578b56c-lll86 1/1 Running 0 5m14s
nginx-7d4578b56c-q5rjj 1/1 Running 0 43s
nginx-7d4578b56c-r5kgd 1/1 Running 0 43s
(也可以使用edit进入文件进行更改)
缩容同理,缩容我们实验edit进入文件内部更改:
[root@master ~]# kubectl edit deploy nginx
spec:
progressDeadlineSeconds: 600
replicas: 2
revisionHistoryLimit: 10
selector:
matchLabels:
deployment.apps/nginx edited
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-7d4578b56c-lc9bs 1/1 Running 0 6m32s
nginx-7d4578b56c-lll86 1/1 Running 0 6m32s
[root@master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-7d4578b56c 2 2 2 6m37s
5.4 Pod控制器:DaemonSet
5.4.1 DaemonSet介绍
DaemonSet 是 Kubernetes 中的一个控制器,它确保在集群中的每个节点上都运行一个指定的 Pod 的副本。这在需要在每个节点上运行守护进程或后台任务时非常有用,比如日志收集、监控、缓存、存储、安全服务等。
Pod:DaemonSet 确保在集群中的每个节点上都运行一个 Pod 的副本。当新的节点加入集群时,DaemonSet 会自动在新节点上创建 Pod。如果 Pod 因为某些原因停止运行,DaemonSet 会自动重启这个 Pod。可以通过节点选择器和节点亲和性来控制哪些节点上运行 Pod。当更新 DaemonSet 的定义时,Kubernetes 会自动更新所有节点上的 Pod。
DaemonSet控制器的特点:每当向集群中添加一个节点时,指定的Pod 副本也将添加到该节点上,当节点从集群中移除时,Pod 也就被垃圾回收了。
5.4.2 DaemonSet实例测试
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx
namespace: default
spec:
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:latest
查看资源:
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-clfhb 1/1 Running 0 8m29s 10.244.167.147 node <none> <none>
nginx-lzvcz 1/1 Running 0 8m29s 10.244.219.74 master <none> <none>
[root@master ~]#
由于我是双节点(一主一从),并且taint master我以关闭;在正常情况下,DaemonSet会去判断集群node的数量进行创建,在我不关闭taint的时候,也就会存在一个pod,他是根据node的数量而不是集群机器总数。
六.Service
6.1 Service介绍
Service:是一种抽象的概念,为一组具有相同功能的 Pod 提供了一个稳定的网络访问入口。Service为Pod提供了一个稳定的网络地址和DNS名称,使得其他应用程序可以通过该地址和名称与Pod进行通信。Kubernetes中的服务用于暴露应用,使得Pod之间或Pod与外部通信能够稳定进行。即使Pod被销毁或重新创建,Service仍然提供稳定的访问地址。在kubernetes中,pod是应用程序的载体,我们可以通过pod的ip来访问应用程序,但是pod的ip地址不是固定的,这也就意味着不方便直接采用pod的ip对服务进行访问。为了解决这个问题,kubernetes提供了Service资源,Service会对提供同一个服务的多个pod进行聚合,并且提供一个统一的入口地址。通过访问Service的入口地址就能访问到后面的pod服务。
Service类型:
ClusterIP:这是默认的 Service 类型。它为 Service 分配一个集群内部的虚拟 IP 地址,只能在集群内部访问。
NodePort:在每个节点上开放一个特定的端口,通过节点的 IP 地址和该端口可以访问 Service 后端的 Pod。这种类型允许从集群外部访问服务。
LoadBalancer:使用云提供商的负载均衡器,为 Service 提供外部可访问的 IP 地址。通常在云环境中使用。
6.2 ClusterIP 模式
6.2.1 ClusterIP 模式介绍
无论后端的 Pod IP 地址如何变化,通过 ClusterIP 都能始终访问到对应的服务。对于运行在 Kubernetes 集群内部的应用程序,ClusterIP 提供了一种方便的方式来进行服务间的通信。各个微服务可以通过 ClusterIP 来访问其他服务,而无需知道具体的 Pod 信息。当有多个 Pod 被同一个 Service 的标签选择器选中时,ClusterIP 会将请求自动分发到这些 Pod 上,实现负载均衡。Kubernetes 会根据一定的负载均衡策略(如轮询、随机等)将请求分配到不同的 Pod 上,从而提高服务的性能和可用性。通过负载均衡,可以有效地利用集群中的资源,避免单个 Pod 过载,同时也提高了系统的容错能力。如果某个 Pod 出现故障,请求会被自动分发到其他正常的 Pod 上,不会影响整个服务的可用性。
6.2.2 ClusterIP模式实例测试
先创建一个Deployment作为实验对象:
[root@master ~]# vi deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
[root@master ~]# kubectl apply -f deployment.yaml
deployment.apps/nginx created
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-5c4c85f44b-5xgrd 1/1 Running 0 2m54s
nginx-5c4c85f44b-bgk4h 1/1 Running 0 2m54s
nginx-5c4c85f44b-n2gp8 1/1 Running 0 2m54s
创建Service资源:
[root@master ~]# vi service.yaml
apiVersion: v1
kind: Service
metadata:
name: clusterip
namespace: default
spec:
selector:
app: nginx-pod
type: ClusterIP
ports:
- port: 80
targetPort: 80
[root@master ~]# kubectl apply -f service.yaml
service/clusterip created
部署完成后我们查看pod的IP:
[root@master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
clusterip ClusterIP 10.104.230.162 <none> 80/TCP 7s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 24h
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-5c4c85f44b-5xgrd 1/1 Running 0 6m17s 10.244.167.149 node <none> <none>
nginx-5c4c85f44b-bgk4h 1/1 Running 0 6m17s 10.244.219.75 master <none> <none>
nginx-5c4c85f44b-n2gp8 1/1 Running 0 6m17s 10.244.167.148 node <none> <none>
我们可以发现,我们并未指定其ClusterIP的具体值,直接帮我们生成了一个随机的IP,我们也可以自己指定IP,增加clusterIP选项添加IP即可。
测试访问:
为了让效果更加明显,修改index.html文件将其设置为各自pod的clusterip:
[root@master ~]# kubectl exec -it nginx-5c4c85f44b-bgk4h /bin/sh
# echo "10.244.219.75" > /usr/share/nginx/html/index.html
# exit
...
测试访问:
[root@master ~]# curl 10.244.167.149
10.244.167.149
[root@master ~]# curl 10.244.167.148
10.244.167.148
[root@master ~]# curl 10.244.219.75
10.244.219.75
6.3 NodePort模式
6.3.1 NodePort介绍
在之前的样例中,创建的Service的ip地址只有集群内部才可以访问,如果希望将Service暴露给集群外部使用,那么就要使用到另外一种类型的Service,称为NodePort类型。NodePort的工作原理其实就是将service的端口映射到Node的一个端口上,然后就可以通过NodeIp:NodePort来访问service。
6.3.2 NodePort模式实例测试
部署Pod:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
部署NodePort:
apiVersion: v1
kind: Service
metadata:
name: nodeport
namespace: default
spec:
selector:
app: nginx-pod
type: NodePort
ports:
- port: 80
nodePort: 30001
targetPort: 80
使用curl命令访问node:nodeport:
[root@master ~]# curl http://192.168.100.120:30001/
10.244.167.132 ##我自己写入的,为了效果明显
[root@master ~]# curl http://192.168.100.120:30001/
10.244.167.132
[root@master ~]# curl http://192.168.100.120:30001/
10.244.167.132
七.数据存储
7.1 数据存储介绍
在kubernetes中的容器的生命周期可能会很短,会被频繁地创建和销毁。那么容器在销毁时,保存在容器中的数据也会被清除。这种结果对用户来说,在某些情况下是不乐意看到的。为了持久化保存容器的数据,kubernetes引入了Volume的概念。
Volume访问到后面的pod服务。是Pod中能够被多个容器访问的共享目录,它被定义在Pod上,然后被一个Pod里的多个容器挂载到具体的文件目录下,kubernetes通过Volume实现同一个Pod中不同容器之间的数据共享以及数据的持久化存储。Volume的生命容器不与Pod中单个容器的生命周期相关,当容器终止或者重启时,Volume中的数据也不会丢失。
kubernetes的Volume支持多种类型,比较常见的有下面几个:
简单存储:EmptyDir、HostPath、NFS
高级存储:PV、PVC
配置存储:ConfigMap、Secret
7.2 EmptyDir模式
7.2.1 EmptyDir模式介绍
EmptyDir在 Pod 被分配到一个节点上时创建,并且只要该 Pod 在该节点上运行,它就会一直存在。其主要作用是为 Pod 中的容器提供临时存储。EmptyDir是最基础的Volume类型,一个EmptyDir就是Host上的一个空目录。
7.2.2 EmptyDir模式实例测试
创建yaml文件:
apiVersion: v1
kind: Pod
metadata:
name: volume-emptydir
namespace: base
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: logs-volume
mountPath: /var/log/nginx
- name: busybox
image: busybox:latest
command: ["/bin/sh", "-c", "tail -f /logs/access.log"]
volumeMounts:
- name: logs-volume
mountPath: /logs
volumes:
- name: logs-volume
emptyDir: {}
在volumes部分定义了一个名为logs-volume的存储卷,类型为emptyDir: {},这直接表明了该存储卷是临时的。定义 volumes 部分并在容器中使用 volumeMounts,可以将存储卷挂载到容器的特定目录,使得容器可以像访问本地文件系统一样访问存储卷中的数据。
Kubernetes使用 EmptyDir 类型的存储卷实现了同一个 Pod 内不同容器之间的数据共享。在这个例子中,nginx 容器产生的日志可以被写入到挂载的 /var/log/nginx 目录,而 busybox 容器通过挂载同一个 EmptyDir 卷到 /logs 目录,可以实时查看 nginx 容器产生的日志文件,实现了不同容器之间的数据传递和共享,体现了 EmptyDir 作为临时存储的用途。由于 EmptyDir 的生命周期与 Pod 绑定,当 Pod 被删除时,存储在其中的数据也会被删除。这适用于存储一些临时数据,比如在这个实验中的日志文件,这些数据在 Pod 的运行期间是有用的,但不需要长期保存。
验证:
[root@master ~]# kubectl exec -it volume-emptydir -n base -c busybox -- ls /logs
access.log error.log
[root@master ~]# kubectl exec -it volume-emptydir -n base -c nginx -- ls /var/log/nginx
access.log error.log
7.3 HostPath模式
7.3.1 HostPath模式介绍
HostPath卷将主机节点上的文件或目录挂载到 Pod 中的容器中。这使得容器可以访问主机上的特定文件或目录,通常用于在容器和主机之间共享数据,或者在开发和测试环境中提供特定的配置文件或数据。这样的设计就可以保证Pod销毁了,但是数据依据可以存在于Node主机上。
7.3.2 HostPath模式实例测试
编写文件:
apiVersion: v1
kind: Pod
metadata:
name: volume-hostpath
namespace: default
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: logs-volume
mountPath: /var/log/nginx
- name: busybox
image: busybox:latest
command: ["/bin/sh","-c","tail -f /logs/access.log"]
volumeMounts:
- name: logs-volume
mountPath: /logs
volumes:
- name: logs-volume
hostPath:
path: /root/logs
type: DirectoryOrCreate
创建完成之后,访问测试,访问nginx,再到node节点查看日志是否生成:
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-5c4c85f44b-pw8tq 1/1 Running 0 55m 10.244.167.132 node <none> <none>
volume-hostpath 2/2 Running 0 55s 10.244.167.135 node <none> <none>
[root@master ~]# curl 10.244.167.135
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
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>
## 到node节点查看日志:
[root@node ~]# ls logs/
access.log error.log
[root@node ~]# cat logs/access.log
10.244.219.64 - - [06/Feb/2025:06:36:24 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.29.0" "-"
7.4 NFS模式
7.4.1 NFS模式介绍
在 Kubernetes 中使用 NFS 时,不是创建一个临时的volume,而是创建一个持久化存储卷(PersistentVolume,PV),通过 NFS 协议连接到外部的 NFS 服务器提供的存储资源。这个存储卷可以被多个 Pod 重复使用,并且数据在 Pod 被删除或重新调度后仍然保留在 NFS 服务器上,而不是像临时存储卷(EmptyDir)那样在 Pod 生命周期结束时数据被删除。
NFS服务器介绍:NFS是一个网络文件存储系统,可以搭建一台NFS服务器,然后将Pod中的存储直接连接到NFS系统上,这样的话,无论Pod在节点上怎么转移,只要Node跟NFS的对接没问题,数据就可以成功访问。
7.4.2 NFS模式实例测试
在每个节点分别下载nfs-utils,主节点下载nfs作为服务器使用,要在的每个node节点上都安装下nfs,这样的目的是为了node节点可以驱动nfs设备
[root@master yaml]# yum install nfs-utils -y
[root@master yaml]# mkdir -pv /root/data/nfs
[root@master yaml]# vi /etc/exports
/root/data/nfs 192.168.100.0/24(rw,no_root_squash)
#在配置文件下添加可执行的IP并赋予权限
编写yaml文件
apiVersion: v1
kind: Pod
metadata:
name: volume-nfs
namespace: default
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: logs-volume
mountPath: /var/log/nginx
- name: busybox
image: busybox:latest
command: ["/bin/sh","-c","tail -f /logs/access.log"]
volumeMounts:
- name: logs-volume
mountPath: /logs
volumes:
- name: logs-volume
nfs:
server: 192.168.100.110
path: /root/data/nfs
执行完成后,查看pod的详细信息查看挂载地址是否生效,访问nginx,查看日志是否正确输出至挂载点:
[root@master ~]# kubectl describe pod volume-nfs
.......
Volumes:
logs-volume:
Type: NFS (an NFS mount that lasts the lifetime of a pod)
Server: 192.168.100.110
Path: /root/data/nfs
ReadOnly: false
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP
volume-nfs 2/2 Running 0 2m23s 10.244.167.136 node <none> <none>
[root@master ~]# curl 10.244.167.136
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
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@master ~]# ls data/nfs/
access.log error.log
[root@master ~]# cat data/nfs/access.log
10.244.219.64 - - [06/Feb/2025:06:46:25 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.29.0" "-"
7.5 PV与PVC模式
7.5.1 PV与PVC模式介绍
PV(Persistent Volume)是持久化卷的意思,是对底层的共享存储的一种抽象。一般情况下PV由kubernetes管理员进行创建和配置,它与底层具体的共享存储技术有关,并通过插件完成与共享存储的对接。它代表了实际的存储设备或存储系统中的一块存储区域,例如 NFS 共享、云存储等。
PVC(Persistent Volume Claim)是持久卷声明的意思,是用户对于存储需求的一种声明。换句话说,PVC其实就是用户向kubernetes系统发出的一种资源需求申请。它由用户创建,用于向 Kubernetes 集群请求一定数量和特定访问模式的存储。
访问模式:
ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
ReadOnlyMany(ROX): 只读权限,可以被多个节点挂载
ReadWriteMany(RWX):读写权限,可以被多个节点挂载
回收策略(persistentVolumeReclaimPolicy)
当PV不再被使用了之后,对其的处理方式。三种策略:
Retain (保留) 保留数据,需要管理员手工清理数据
Recycle(回收) 清除 PV 中的数据,效果相当于执行 rm -rf /thevolume/*
Delete (删除) 与 PV 相连的后端存储完成 volume 的删除操作。
PV资源清单:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv2
spec:
nfs: # 存储类型,与底层真正存储对应
capacity: # 存储能力,目前只支持存储空间的设置
storage: 2Gi
accessModes: # 访问模式
storageClassName: # 存储类别
persistentVolumeReclaimPolicy: # 回收策略
PVC是资源的申请,用来声明对存储空间、访问模式、存储类别需求信息。
资源清单:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc
namespace: dev
spec:
accessModes: # 访问模式
selector: # 采用标签对PV选择
storageClassName: # 存储类别
resources: # 请求空间
requests:
storage: 5Gi
7.5.2 创建PV
删除之前创建过的NFS文件下的文件,在重新编写配置文件,在配置文件中写入三个PV,并赋予权限,创建挂载目录:
[root@master yaml]# vi /etc/exports
/root/data/nfs/pv1 192.168.100.0/24(rw,no_root_squash)
/root/data/nfs/pv2 192.168.100.0/24(rw,no_root_squash)
/root/data/nfs/pv3 192.168.100.0/24(rw,no_root_squash)
[root@master yaml]# systemctl restart nfs
[root@master yaml]# mkdir -pv /root/data/nfs/{pv1,pv2,pv3}
创建PV:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv1
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: /root/data/nfs/pv1
server: 192.168.100.110
#模版
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv2
spec:
capacity:
storage: 2Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: /root/data/nfs/pv2
server: 192.168.100.110
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv3
spec:
capacity:
storage: 3Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: /root/data/nfs/pv3
server: 192.168.100.110
[root@master ~]# kubectl apply -f pv.yaml
persistentvolume/pv1 created
persistentvolume/pv2 created
persistentvolume/pv3 created
[root@master ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv1 1Gi RWX Retain Available 5s
pv2 2Gi RWX Retain Available 5s
pv3 3Gi RWX Retain Available 5s
PV创建成功。
7.5.3 创建PVC
创建yaml文件创建PVC:
[root@master ~]# cat pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc1
namespace: default
spec:
accessModes:
- ReadWriteMany #RWX
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc2
namespace: default
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 2Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc3
namespace: default
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 3Gi
[root@master ~]# kubectl apply -f pvc.yaml
persistentvolumeclaim/pvc1 created
persistentvolumeclaim/pvc2 created
persistentvolumeclaim/pvc3 created
[root@master ~]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc1 Bound pv1 1Gi RWX 6s
pvc2 Bound pv2 2Gi RWX 6s
pvc3 Bound pv3 3Gi RWX 6s
此时查看PV,发现PV的状态信息发生变化:从可用变为了已绑定
Available(可用): 表示可用状态,还未被任何 PVC 绑定
Bound(已绑定): 表示 PV 已经被 PVC 绑定
Released(已释放): 表示 PVC 被删除,但是资源还未被集群重新声明
Failed(失败): 表示该 PV 的自动回收失败
7.5.4 创建Pod使用存储
[root@master ~]# cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod1
namespace: default
spec:
containers:
- name: busybox
image: busybox:latest
command: ["/bin/sh","-c","while true;do echo pod1 >> /root/out.txt; sleep 10; done;"]
volumeMounts:
- name: volume
mountPath: /root/
volumes:
- name: volume
persistentVolumeClaim:
claimName: pvc1
readOnly: false
---
apiVersion: v1
kind: Pod
metadata:
name: pod2
namespace: default
spec:
containers:
- name: busybox
image: busybox:latest
command: ["/bin/sh","-c","while true;do echo pod2 >> /root/out.txt; sleep 10; done;"]
volumeMounts:
- name: volume
mountPath: /root/
volumes:
- name: volume
persistentVolumeClaim:
claimName: pvc2
readOnly: false
[root@master ~]# kubectl apply -f pod.yaml
pod/pod1 created
pod/pod2 created
查询挂载点是否有日志生成:
[root@master ~]# cat data/nfs/pv2/out.txt
pod2
pod2
pod2
pod2
pod2
pod2
pod2
7.6 ConfigMap模式
7.6.1 ConfigMap模式介绍
ConfigMap 用于存储非敏感的配置数据。它可以将配置信息从容器化应用的代码中解耦出来,从而使得配置管理更加灵活。
特点:
用途:存储配置数据(例如数据库连接字符串、配置文件、环境变量等)。
存储方式:数据以键值对的形式存储,数据本身是明文的。
灵活性:可以通过环境变量、命令行参数或挂载文件的方式将 ConfigMap 数据传递给应用。
更新:可以在不重新创建 Pod 的情况下更新 ConfigMap,但若是挂载为文件,则需要重启 Pod 才会生效。
7.6.2 ConfigMap模式实例测试
创建实例文件:
[root@master ~]# cat configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: configmap
namespace: default
data:
info: |
username:admin
password:123456
[root@master ~]# kubectl apply -f configmap.yaml
configmap/configmap created
[root@master ~]# kubectl describe cm
Name: configmap
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
info:
----
username:admin
password:123456
BinaryData
......
创建Pod使用ConfigMap:
[root@master ~]# cat configmap_pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-configmap
namespace: default
spec:
containers:
- name: nginx
image: nginx:latest
volumeMounts:
- name: config
mountPath: /configmap/config
volumes:
- name: config
configMap:
name: configmap
[root@master ~]# kubectl apply -f configmap_pod.yaml
pod/pod-configmap created
[root@master ~]# kubectl exec -it pod-configmap /bin/sh
# cd /configmap
# ls
config
# cd config
# ls
info
# cat info
username:admin
password:123456
# 可以看到映射已经成功,每个configmap都映射成了一个目录
# key--->文件 value---->文件中的内容
#此时如果更新configmap的内容, 容器中的值也会动态更新
7.7 Secret模式
7.7.1 Secret模式介绍
Secret 用于存储敏感信息,如密码、API 密钥、TLS 证书等。它与 ConfigMap 的主要区别是,Secret 默认会对数据进行 Base64 编码,并且可以加密存储。
特点:
用途:存储敏感信息(例如数据库密码、OAuth 令牌、证书等)。
存储方式:数据以 Base64 编码存储,默认不加密,但可以配置加密存储。
安全性:比 ConfigMap 更加安全,支持通过 Kubernetes 的加密机制进行存储和传输。
挂载方式:可以通过环境变量、挂载为文件或在 Pod 的容器中作为文件来使用。
7.7.2 Secret模式实例测试
首先使用base64对数据进行编码:
[root@master ~]# echo 'admin' | base64
YWRtaW4K
[root@master ~]# echo '123456' | base64
MTIzNDU2Cg==
创建secret:
[root@master ~]# cat secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: secret
namespace: default
type: Opaque
data:
username: YWRtaW4=
password: MTIzNDU2
[root@master ~]# kubectl apply -f secret.yaml
secret/secret created
[root@master ~]# kubectl describe secret secret
Name: secret
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password: 6 bytes
username: 5 bytes
创建Pod使用secret:
apiVersion: v1
kind: Pod
metadata:
name: pod-secret
namespace: default
spec:
containers:
- name: nginx
image: nginx:latest
volumeMounts:
- name: config
mountPath: /secret/config
volumes:
- name: config
secret:
secretName: secret
[root@master ~]# kubectl apply -f secret_pod.yaml
pod/pod-secret created
[root@master ~]# kubectl exec -it pod-secret /bin/sh
# cd secret
# ls
config
# cd config
# ls
password username
# cat password
123456
# cat username
admin
至此,已经实现了利用secret实现了信息的编码。
小结
作品不易,请务必珍惜,会持续更新。