一、Kubernetes 的基本概念和术语
一、资源对象
Kubernetes 的基本概念和术语大多是围绕资源对象 Resource Object 来说的,而资源对象在总体上可分为以下两类:
1、某种资源的对象
例如节点 Node) Pod 服务 (Service) 、存储卷 (Volume)。
2、与资源对象相关的事物与动作
例 如标签 Label 、注解 (Annotation 、命名空Namespace 、部署 (Deployment) 资源对象一般包括几个通用属性:版本 、类 Kind 、名称、标签、注解,如下:
1)、在版本信息里包括了 此对象所属的资源组, 些资源对象的属性会随着版本的升级而变化,在定义资源对象时要特别注意这一点
2)、 类别属性用于定义资源对象的类型。
3)、资源对象的名称 Name 标签、注解这三个属性属于资源对象的元数据(metadata)资源对象的名称要唯一,资源对象的标签是很重要的数据,也是 Kubernetes 的一大设计特性,比如通过签来表明资源对象 的特征 、类别,以及通 过标签筛选不同的资源对象并实现对象之间的关联 控制或协作功能
4)、注解可被理解为一种特殊的标签,不过更多地是与程序挂钩,通常用于实现资源对象属性的自定义扩展
我们可以采用 YAML JSON 格式声明(定义或创建) Kubernetes 资源对象,个资源对象都有自己的特定结构定义(可 以理解为数据库中 一个特定的表),并且统一保存在 etcd 这种非关系型数据库中,以实现最快的读写速度 此外,所有资源对象都可以通Kubernetes 提供的 kubectl 具(或者 PI 编程调用)执行增 删、改、查等操作。
例如我们一个Pod的yaml定义文件:
apiVersion: v1
kind: Pod
metadata: name: nginx-pod labels: app: nginx
spec: containers: - name: nginx image: nginx:1.21.6 # 使用特定的Nginx版本,你可以根据需要更改它 ports: - containerPort: 80
1、apiVersion 指定了Kubernetes API的版本。
2、kind 指定了要创建的资源类型,这里是Pod。
3、metadata 包含了Pod的元数据,如名称和标签。
4、spec 描述了Pod的规格。
5、containers 列出了Pod中要运行的容器。name 指定了容器的名称。image 指定了要使用的容器镜像。ports 列出了容器要监听的端口。
二、资源类型
下面我们看下k8s的一些常用的资源类型,主要用于管理和部署容器化应用程序:
1、核心资源类型:
1)、Pod:Kubernetes中运行容器以及调度的最小单位。同一个Pod可以同时运行多个容器,这些容器共享网络、存储等资源,并可以通过localhost进行通信。
2)、Node:集群中的一个物理节点,也就是宿主机,可以运行Pod。
3)、Namespace:用于将集群划分为多个虚拟集群,避免资源冲突。
2、工作负载型资源:
1)、Deployment:用于定义应用程序的部署信息,如副本数、升级策略等。它支持应用的扩缩容、滚动更新等操作。
2)、ReplicaSet:ReplicaSet是Deployment的底层实现,确保指定数量的Pod副本在运行。
3)、StatefulSet:用于管理有状态的应用程序,如数据库。它提供了稳定的持久化存储、有序部署、有序扩展和有序删除等特性。
4)、DaemonSet:确保集群中的每个节点都运行一个Pod的副本。常用于运行集群级别的守护进程,如存储守护进程、日志收集器等。
5)、Job 和 CronJob:Job用于运行一次性任务,而CronJob则用于运行周期性任务。
3、服务发现及负载均衡型资源:
1)、Service:为Pod提供稳定的访问接口,用于服务发现和服务访问。Service的类型包括ClusterIP、NodePort和LoadBalancer。
2)、Ingress:允许从集群外部访问集群内部的HTTP和HTTPS服务。它充当了集群内部和外部之间的网关,并提供了一些高级功能,如SSL/TLS终止、负载均衡和路径匹配等。
4、配置与存储型资源:
1)、ConfigMap:用于存储应用程序配置信息的资源。ConfigMap可以将配置信息从应用程序代码中解耦出来,方便管理和更新。
2)、Secret:用于存储敏感信息的资源,如密码、密钥等。Secret提供了比ConfigMap更强的安全性,可以确保敏感信息在存储和传输过程中的安全性。
3)、Volume 和 CSI:Volume是Kubernetes中的存储卷,用于为Pod提供持久化存储。CSI(容器存储接口)是一种标准,用于扩展Kubernetes以支持各种第三方存储系统。
5)、集群型资源:
包括Role、ClusterRole、RoleBinding、ClusterRoleBinding等,用于控制对集群资源的访问权限。
6)、元数据型资源:
如HPA(Horizontal Pod Autoscaler)用于自动扩展Pod的数量,PodTemplate用于定义Pod的模板等。
三、K8S集群
集群 (C luster) 表示一个由 Master Node 组成的 Kubernetes 集群。
1、Master
Master 指的是集群的控制节点 在每个 Kubemetes 集群中都需要有一个或 组被称为Master 的节点,来负责整个集群的管理和控制 Master 通常占据一个独立的服务器(在高可用部署中建议至少使用 台服务器),是整个集群的“大脑”,如果它发生宕机或者不可用,那么对集群内容器应用的管理都将无法实施。
Maste 上运行着以下关键进程
1)、Kubemetes API Server(kube-apiserver) :提供 HTTP RESTful API 接口的主要服务,Kubernetes 里对所有资源进行增、删 查等操作的唯 入口,也是集群控制的入口进程
2)、Kubernetes Controller Manager ( kube-controller-manager): Kubernetes 里所有 资源对象的自动化控制中心 ,可以将其理解为资源对象的“大总管”。
3)、Kubemetes Scheduler kube-scheduler) :负责资源调度 Pod 调度 的进程,相当千公交公司的调度室另外,在 Master 上通常还需要部署 etcd 服务。
2、Node
Kubemetes 集群中除 Mater 外的其他服务器被称为 Node, Node 在较早的版本中也被称为 Minion Master 一样, Node 可以是一台物理主机,也可以是一台虚拟机 Node,Kubemetes 集群中的工作负载节点,每个 Node 都会被 Master 分配 些工作负载 (Docker容器),当某个 Node 右机时,其上的工作负载会被 Master 自动转移到其他 Node ,Pod都是被调度到Node上面,不会调度到Master上面。在每Node 上都运行着以下关键进程
1)、 kubelet: 负责 Po 对应容器的创建 启停等任务,同时与 Master 密切协作,实现集群管理的基本功能。
2)、 kube-proxy: 实现 Kubemetes Service 的通信与负载均衡机制的服务。
3)、容器运行时(如 Docker) :负责本机的容器创建和管理
Node 以在运行期间动态增加到 Kubernetes 集群中,前提是在这个 Node 上已正确安装、配置和启动了上述关键进程 在默认情况下, kubelet 会向 Master 注册自己,这也是Kubernetes 推荐的 Node 管理方式 。一旦 Node 被纳入集群管理范畴, kubelet 进程就会定
时向 Master 汇报自身的情报,例如操作系统、主机 CPU 和内存使用情况,以及当前有哪Pod 在运行等,这样 Master 就可以获知每个 Node 的资源使用情况,并实现高效均衡的资源调度策略 而某个 Node 在超过指定时间不上报信息时,会被 Master 判定为“失联”,Node 的状态就被标记为不可用 (Not Ready), Master 随后会触发”工作负载大转移”。
kubectl get nodes
:查看当前集群中有多少个 Node
[root@k8s-master feverasa]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready master 352d v1.18.0
k8s-node1 Ready <none> 352d v1.18.0
k8s-node2 Ready <none> 352d v1.18.0
[root@k8s-master feverasa]#
kubectl describe node <node_name>
:看某个 Node 的详细信息
[root@k8s-master feverasa]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready master 352d v1.18.0
k8s-node1 Ready <none> 352d v1.18.0
k8s-node2 Ready <none> 352d v1.18.0
[root@k8s-master feverasa]# kubectl describe node k8s-node1
Name: k8s-node1
Roles: <none>
Labels: beta.kubernetes.io/arch=amd64beta.kubernetes.io/os=linuxkubernetes.io/arch=amd64kubernetes.io/hostname=k8s-node1kubernetes.io/os=linux
Annotations: flannel.alpha.coreos.com/backend-data: {"VNI":1,"VtepMAC":"1e:3d:b5:c4:3f:a4"}flannel.alpha.coreos.com/backend-type: vxlanflannel.alpha.coreos.com/kube-subnet-manager: trueflannel.alpha.coreos.com/public-ip: 192.168.127.129kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.socknode.alpha.kubernetes.io/ttl: 0volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp: Sat, 15 Jul 2023 16:17:25 +0800
Taints: <none>
Unschedulable: false
Lease:HolderIdentity: k8s-node1AcquireTime: <unset>RenewTime: Mon, 01 Jul 2024 20:35:26 +0800
Conditions:Type Status LastHeartbeatTime LastTransitionTime Reason Message---- ------ ----------------- ------------------ ------ -------NetworkUnavailable False Mon, 01 Jul 2024 20:32:30 +0800 Mon, 01 Jul 2024 20:32:30 +0800 FlannelIsUp Flannel is running on this nodeReady True Mon, 01 Jul 2024 20:32:26 +0800 Mon, 01 Jul 2024 20:32:26 +0800 KubeletReady kubelet is posting ready status
Addresses:InternalIP: 192.168.127.129Hostname: k8s-node1
Capacity:cpu: 8ephemeral-storage: 10230Mihugepages-1Gi: 0hugepages-2Mi: 0memory: 2342332Kipods: 110
Allocatable:cpu: 8ephemeral-storage: 9654239217hugepages-1Gi: 0hugepages-2Mi: 0memory: 2239932Kipods: 110
System Info:Machine ID: e29555c44cc4411b8734a1e6d1e82282System UUID: 3BD84D56-4D40-DB60-D894-1E985B5769F9Boot ID: b8a3e705-0a55-40c3-a182-ff7523937f2dKernel Version: 3.10.0-1062.el7.x86_64OS Image: CentOS Linux 7 (Core)Operating System: linuxArchitecture: amd64Container Runtime Version: docker://18.6.1Kubelet Version: v1.18.0Kube-Proxy Version: v1.18.0
PodCIDR: 10.244.1.0/24
PodCIDRs: 10.244.1.0/24
Non-terminated Pods: (7 in total)Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits AGE--------- ---- ------------ ---------- --------------- ------------- ---default spring-test-deployment-69769b84f6-2zrct 0 (0%) 0 (0%) 0 (0%) 0 (0%) 28hkube-system kube-proxy-hlz5s 0 (0%) 0 (0%) 0 (0%) 0 (0%) 352d
Allocated resources:(Total limits may be over 100 percent, i.e., overcommitted.)Resource Requests Limits-------- -------- ------cpu 300m (3%) 0 (0%)memory 190Mi (8%) 340Mi (15%)ephemeral-storage 0 (0%) 0 (0%)hugepages-1Gi 0 (0%) 0 (0%)hugepages-2Mi 0 (0%) 0 (0%)
Events:Type Reason Age From Message---- ------ ---- ---- -------Warning EvictionThresholdMet 29h (x4 over 29h) kubelet, k8s-node1 Attempting to reclaim ephemeral-storageNormal Starting 3m7s kube-proxy, k8s-node1 Starting kube-proxy.
[root@k8s-master feverasa]#
以上命令的运行结果中会展示目标 Node 的如下关键信息:
1)、Node 的基本信息:名称、标签 创建时间等
2)、 Node 当前的运行状态 Node 启动后会做一系列自检工作,比如磁盘空间是否不(DiskPressure ) 、 内存是否不足 (MemoryPressure 网络是否正常NetworkUnavailable PID 资源是否充足 (PIDPressure 在一切正常时才设置Node Ready 状态 (Ready=True 表示 Node 处于健康状态, Master 就可以在其上调度新的任务了( 启动 Pod)。
3)、Node 的主机地址与主机名。
4)、Node 上的资源数量 描述 Node 可用的系统资源,包括 CPU 内存数量 最大可调度 Pod 数量等。
5)、 Node 可分配的资 量:描述 Node 用于分配的资源量。
6)、主机系统信息:包括主机 ID 、系统 UUID Linux Kernel 版本号、操作系统类型与版本 Docker 版本号 belet kube-proxy 的版本号等,当前运行的 Pod 列表概要信息。巳分配的资源使用 要信息,例如资源申请的最小 最大允许使用量占系统总量的百分比
7)、 Node 相关的 Event 信息。
四、应用类Pod
1、基本介绍
Pod是Kubernetes中可以创建和管理的最小单元,也是资源对象模型中由用户创建或部署的最小资源对象模型。
Pod是Kubernetes上运行容器化应用的资源对象,其他资源对象(如控制器、服务等)都是用来支撑或扩展Pod对象功能的,例如Service、Deployment这些。每个Pod就像一个独立的逻辑机器,拥有集群内部唯一的IP地址、主机名、进程等。
Pod 可以由一个或多个容器组合而成。Kubernete 为每个 Pod 分配了唯一 IP 地址,称之为 Pod IP, 一个 Pod 里的多个容器共享 Pod IP 地址 Kubernetes 要求底层网络支待集群内任意两个 Po 之间的 TCP/IP,一个 Pod 里的容器与另外主机上的 Pod 容器能够直接通信。Pod IP 加上容器端口 (containerPort 组成了一个新的概念Endpoint, 表此 Pod 里的 一个服务进程的对外通信地址。
2、pod的简单使用
apiVersion: v1 # 必选,API版本号
kind: Pod # 必选,资源对象名称
metadata: name: spring-test-pod # 必选,Pod的名称 namespace: default # 可选,Pod所属的命名空间,默认为default labels: # 可选,自定义的Pod标签 app: spring-test-pod-label
spec: containers: # 必选,Pod中容器列表 - name: spring-test-container # 必选,容器名称 image: spring_docker_test:0.0.6 # 必选,容器镜像,这里以nginx为例,版本为1.21 imagePullPolicy: IfNotPresent # 可选,镜像拉取策略,IfNotPresent表示本地不存在时拉取 command: [ "java","-jar","app.jar" ] #启动命令ports: # 可选,容器需要暴露的端口列表- name: http # 端口名称 containerPort: 8087 # 容器需要监听的端口号,一般是你容器里面启动对应应用的端口env: # 可选,容器运行前需要设置的环境变量列表 - name: application_name # 环境变量名称 value: "spring-test-application" # 环境变量的值 volumeMounts: # 可选,容器内部存储卷挂载配置 - name: application-volume # 引用Pod定义的共享存储卷名称,一般与下面的spec.containers.volumes对应mountPath: /wls/data # 存储卷在容器内Mount的绝对路径 .volumes: # 可选,Pod上定义的共享存储卷列表 - name: application-volume # 共享存储卷名称 hostPath:path: /home/logstype: DirectoryOrCreate # 目录如果不存就创建
我们对应spring_docker_test
镜像定义Dockerfile
如下:
FROM openjdk:8-jdk-alpine
MAINTAINER feverasa_test.com
RUN mkdir -p /wls/appsystems
COPY SpringBootBasicDemo-0.0.1-SNAPSHOT.jar /wls/appsystems/
WORKDIR /wls/appsystems/
RUN mv SpringBootBasicDemo-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","app.jar"]
我们通过kubectl apply -f my_spring_pod.yaml
根据yaml文件创建对应资源,然后查看对应pods具体信息。
[root@k8s-master k8s]# kubectl apply -f my_spring_pod.yaml
pod/spring-test-pod created
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-pod 1/1 Running 0 5s
[root@k8s-master k8s]# kubectl describe pod spring-test-pod
Name: spring-test-pod
Namespace: default
Priority: 0
Node: k8s-node1/192.168.127.129
Start Time: Mon, 01 Jul 2024 21:28:49 +0800
Labels: app=spring-test-pod-label
Annotations: Status: Running
IP: 10.244.1.161
IPs:IP: 10.244.1.161
Containers:spring-test-container:Container ID: docker://18f534c5feecd1ce283696a2e1c359efb58c6d07eb57d12e23b7474207a7066dImage: spring_docker_test:0.0.6Image ID: docker://sha256:f744de4249b9e60da5f3c04164e28f4da2ba03969854471b95c9d4fc9427b047Port: 8087/TCPHost Port: 0/TCPCommand:java-jarapp.jarState: RunningStarted: Mon, 01 Jul 2024 21:28:50 +0800Ready: TrueRestart Count: 0Environment:application_name: spring-test-applicationMounts:/var/run/secrets/kubernetes.io/serviceaccount from default-token-vzgvh (ro)/wls/data from application-volume (rw)
Conditions:Type StatusInitialized True Ready True ContainersReady True PodScheduled True
Volumes:application-volume:Type: HostPath (bare host directory volume)Path: /home/logsHostPathType: DirectoryOrCreatedefault-token-vzgvh:Type: Secret (a volume populated by a Secret)SecretName: default-token-vzgvhOptional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300snode.kubernetes.io/unreachable:NoExecute for 300s
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Scheduled 17s default-scheduler Successfully assigned default/spring-test-pod to k8s-node1Normal Pulled 16s kubelet, k8s-node1 Container image "spring_docker_test:0.0.6" already present on machineNormal Created 16s kubelet, k8s-node1 Created container spring-test-containerNormal Started 16s kubelet, k8s-node1 Started container spring-test-container
[root@k8s-master k8s]#
在这里我们可以看到当前Pod使用的镜像、当前Pod的IP,启动命令、设置的环境变量Environment、Events等具体信息。
我们再通过kubectl exec -it spring-test-pod sh
进入pod
[root@k8s-master k8s]# kubectl exec -it spring-test-pod sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
/wls/appsystems # pwd
/wls/appsystems
/wls/appsystems # ps -ef
PID USER TIME COMMAND1 root 0:05 java -jar app.jar38 root 0:00 sh45 root 0:00 ps -ef
/wls/appsystems # ifconfig
eth0 Link encap:Ethernet HWaddr 26:C9:BF:77:E8:99 inet addr:10.244.1.162 Bcast:10.244.1.255 Mask:255.255.255.0UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1RX packets:5 errors:0 dropped:0 overruns:0 frame:0TX packets:1 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:0 RX bytes:446 (446.0 B) TX bytes:42 (42.0 B)lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0UP LOOPBACK RUNNING MTU:65536 Metric:1RX packets:0 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)/wls/appsystems # df -h
Filesystem Size Used Available Use% Mounted on
/dev/mapper/centos-home496.7M 335.2M 161.5M 67% /wls/data
/dev/mapper/centos-root
tmpfs 1.1G 0 1.1G 0% /sys/firmware
/wls/appsystems #
这里我们看到当前pod的独立的ip,还有我们挂载的wls/data
目录,我们修改下,再退出去pod对应的宿主机(k8s-node1/192.168.127.129
)看下(需要注意的是,pod是会调度到Node上面去的,我们当前是在master节点上面,是看不到的),
[root@k8s-node1 feverasa]# cd /home/logs/
[root@k8s-node1 logs]# ls
docker_file.txt
[root@k8s-node1 logs]# cat docker_file.txt
Hello My In Pod Inner!!!
[root@k8s-node1 logs]#
3、Pod的生命周期和重启策略
Pod 整个生命周期中被系统定义为各种状态:
1)、挂起(Pending)
这个状态表明 Pod 已经被 Kubernetes 系统接受,但尚未被调度到任何节点上。这可能是因为资源不足、调度策略限制或镜像正在下载中。
2)、运行中(Running)
Pod 已被调度到某个节点上,并且所有容器都已被 kubelet 创建。如果至少有一个容器正在运行,则 Pod 处于 Running 状态。
3)、成功(Succeeded)
Pod 中的所有容器都已经成功终止,并且不会被重启。这通常发生在 Job 类型的 Pod 中,当所有任务执行完毕后,Pod 会进入此状态。
4)、失败(Failed)
Pod 中的所有容器都已经终止,但至少有一个容器以非零状态码退出。这表示至少有一个容器执行失败。
5)、未知(Unknown)
由于某种原因,Kubernetes 无法获取到 Pod 的状态信息,这通常是由于与 Pod 所在的节点通信失败导致的。
Pod 的生命周期还涉及到一些关键事件和过程,如初始化容器的运行(如果定义了的话)、主容器的启动、存活性探测(Liveness Probe)和就绪性探测(Readiness Probe)的执行、容器的停止等。
4、Pod 健康检查和服务可用性检查
Kubemetes Pod 的健康状态可以通过 三类探针来检查存活探针(LivenessProbe)、就绪探针(ReadinessProbe)、启动探针(StartupProbe), 其中最主要的探针为 LivenessProbe、ReadinessProbe这两类探针,kubelet 会定期执行这两类探针来诊断容器的健康状况,并在容器不健康的情况下采取相应的措施,以保证应用程序的可用性和稳定性。
1)、启动探针(StartupProbe)
用于判断容器内的应用程序是否已经启动。如果配置了启动探针,它会先禁止其他的探测(存活探针和就绪探针),直到启动探针成功为止。这主要适用于容器启动时间较长的场景,可以避免在容器还在初始化阶段就进行其他类型的探测。
apiVersion: v1 # 必选,API版本号
kind: Pod # 必选,资源对象名称
metadata: name: spring-test-pod # 必选,Pod的名称 namespace: default # 可选,Pod所属的命名空间,默认为default labels: # 可选,自定义的Pod标签 app: spring-test-pod-label
spec: containers: # 必选,Pod中容器列表 - name: spring-test-container # 必选,容器名称 image: spring_docker_test:0.0.6 # 必选,容器镜像,这里以nginx为例,版本为1.21 imagePullPolicy: IfNotPresent # 可选,镜像拉取策略,IfNotPresent表示本地不存在时拉取 command: [ "java","-jar","app.jar" ] #启动命令ports: # 可选,容器需要暴露的端口列表- name: http # 端口名称 containerPort: 8087 # 容器需要监听的端口号,一般是你容器里面启动对应应用的端口startupProbe:tcpSocket: # 端口检测方式port: 8086initialDelaySeconds: 5 # 初始化时间timeoutSeconds: 2 # 超时时间periodSeconds: 5 # 检测间隔successThreshold: 1 # 检查成功为 1 次表示启动failureThreshold: 20 # 检测失败 20 次表示未启动 restartPolicy: OnFailure
例如上面这个yaml
文件,我们加了StartupProbe
相关配置,我们特意设置的其的探针端口是8086
(我们应用使用的是8087),这样其就会探针失败,然后我们的重启策略时OnFailure
,这样在20次后,其就会自动重启了
[root@k8s-master k8s]# kubectl apply -f my_spring_pod.yaml
pod/spring-test-pod created
[root@k8s-master k8s]#
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-pod 0/1 Pending 0 54s[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-pod 1/1 Running 0 113s
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-pod 1/1 Running 0 116s
[root@k8s-master k8s]# kubectl describe pod spring-test-pod
Name: spring-test-pod
Namespace: default
Priority: 0
Node: k8s-node1/192.168.127.129
Start Time: Tue, 02 Jul 2024 22:08:38 +0800
Labels: app=spring-test-pod-label.............................
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Scheduled <unknown> default-scheduler Successfully assigned default/spring-test-pod to k8s-node1Normal Pulled 23s kubelet, k8s-node1 Container image "spring_docker_test:0.0.6" already present on machineNormal Created 23s kubelet, k8s-node1 Created container spring-test-containerNormal Started 23s kubelet, k8s-node1 Started container spring-test-containerWarning Unhealthy 2s (x4 over 17s) kubelet, k8s-node1 Startup probe failed: dial tcp 10.244.1.183:8086: connect: connection refused
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-pod 1/1 Running 5 14m
这里我们在Events可以看到Startup probe failed
探针失败,然后其自动重启了5次。
2)、就绪探针(ReadinessProbe)
用于判断容器服务是否可用 Ready 状态 ),达到 Ready状态态的 Pod 才可以接收请求。对于被 Service 管理的 Pod, Service与Pod Endpoint 的关联关系也将基于 Pod 是否 Ready 进行设置 。如果在运行过程中 Ready 状态变为 False, 则系统自动将其从 Service 的后端 Endpoint 列表中隔离出去,后续再把恢复到 Ready 状态的 Pod加回后端 Endpoint 列表 这样就能保证客户端在访问 Service 时不会被转发到服务不可用的Pod 实例上 。需要注意的是, ReadinessProbe 也是定期触发执行的,存在于 Pod 的整个生命周期中。
apiVersion: v1 # 必选,API版本号
kind: Pod # 必选,资源对象名称
metadata: name: spring-test-pod # 必选,Pod的名称 namespace: default # 可选,Pod所属的命名空间,默认为default labels: # 可选,自定义的Pod标签 app: spring-test-pod-label
spec: containers: # 必选,Pod中容器列表 - name: spring-test-container # 必选,容器名称 image: spring_docker_test:0.0.6 # 必选,容器镜像,这里以nginx为例,版本为1.21 imagePullPolicy: IfNotPresent # 可选,镜像拉取策略,IfNotPresent表示本地不存在时拉取 command: [ "java","-jar","app.jar" ] #启动命令ports: # 可选,容器需要暴露的端口列表- name: http # 端口名称 containerPort: 8087 # 容器需要监听的端口号,一般是你容器里面启动对应应用的端口readinessProbe:tcpSocket: # 端口检测方式port: 8086initialDelaySeconds: 5 # 初始化时间timeoutSeconds: 2 # 超时时间periodSeconds: 5 # 检测间隔successThreshold: 1 # 检查成功为 1 次表示启动failureThreshold: 20 # 检测失败 20 次表示未启动 restartPolicy: OnFailure
[root@k8s-master k8s]# kubectl apply -f my_spring_pod.yaml
pod/spring-test-pod created
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-pod 0/1 Running 0 6s
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-pod 0/1 Running 0 17s
[root@k8s-master k8s]# kubectl describe pod spring-test-pod
Name: spring-test-pod
Namespace: default
Priority: 0
Node: k8s-node1/192.168.127.129
Start Time: Tue, 02 Jul 2024 22:34:37 +0800
Labels: app=spring-test-pod-label
Annotations: Status: Running
IP: 10.244.1.184
IPs:IP: 10.244.1.184
Containers:spring-test-container:Container ID: docker://ce72386f54cdb75c0d0c35a264ca84b51bdffa7d3e242c5123c5e57d895d0e34Image: spring_docker_test:0.0.6Image ID: docker://sha256:1d25527ddac72a76593d8e286dc3c37232675b860e732771da45f6ffd14266f0Port: 8087/TCP---------------------
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Pulled 33s kubelet, k8s-node1 Container image "spring_docker_test:0.0.6" already present on machineNormal Created 33s kubelet, k8s-node1 Created container spring-test-containerNormal Started 32s kubelet, k8s-node1 Started container spring-test-containerWarning Unhealthy 2s (x6 over 27s) kubelet, k8s-node1 Readiness probe failed: dial tcp 10.244.1.184:8086: connect: connection refused
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-pod 0/1 Running 0 81s
[root@k8s-master k8s]#
上面我们修改探针类型为readinessProbe
,依然探测8086
,可以看到Events其探测失败,然后其的状态一直不能Ready
-0/1
。
3)、存活探针(LivenessProbe)
用于检测容器是否仍在运行,如果存活探针检测失败,kubelet将根据配置的重启策略对容器进行相应的处理(如重启容器)。如果一个容器没配置LivenessProbe 探针,那么 kubelet 认为该容器的 LivenessProbe探针返回的值永远是 Success。
apiVersion: v1 # 必选,API版本号
kind: Pod # 必选,资源对象名称
metadata: name: spring-test-pod # 必选,Pod的名称 namespace: default # 可选,Pod所属的命名空间,默认为default labels: # 可选,自定义的Pod标签 app: spring-test-pod-label
spec: containers: # 必选,Pod中容器列表 - name: spring-test-container # 必选,容器名称 image: spring_docker_test:0.0.6 # 必选,容器镜像,这里以nginx为例,版本为1.21 imagePullPolicy: IfNotPresent # 可选,镜像拉取策略,IfNotPresent表示本地不存在时拉取 command: [ "java","-jar","app.jar" ] #启动命令ports: # 可选,容器需要暴露的端口列表- name: http # 端口名称 containerPort: 8087 # 容器需要监听的端口号,一般是你容器里面启动对应应用的端口env: # 可选,容器运行前需要设置的环境变量列表 - name: application_name # 环境变量名称 value: "spring-test-application" # 环境变量的值 volumeMounts: # 可选,容器内部存储卷挂载配置 - name: application-volume # 引用Pod定义的共享存储卷名称 mountPath: /wls/data # 存储卷在容器内Mount的绝对路径 livenessProbe:tcpSocket: # 端口检测方式port: 8086initialDelaySeconds: 5 # 初始化时间timeoutSeconds: 2 # 超时时间periodSeconds: 5 # 检测间隔successThreshold: 1 # 检查成功为 1 次表示存活failureThreshold: 2 # 检测失败 2 次表示存活volumes: # 可选,Pod上定义的共享存储卷列表 - name: application-volume # 共享存储卷名称 hostPath:path: /home/logstype: DirectoryOrCreate # 目录如果不存就创建restartPolicy: OnFailure
[root@k8s-master k8s]# kubectl apply -f my_spring_pod.yaml
pod/spring-test-pod created
[root@k8s-master k8s]#
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-pod 1/1 Running 0 5s
[root@k8s-master k8s]# kubectl describe pod spring-test-pod
Name: spring-test-pod
Namespace: default
Priority: 0
Node: k8s-node1/192.168.127.129
Start Time: Tue, 02 Jul 2024 22:42:53 +0800
Labels: app=spring-test-pod-label................
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Scheduled <unknown> default-scheduler Successfully assigned default/spring-test-pod to k8s-node1Normal Pulled 10s (x3 over 38s) kubelet, k8s-node1 Container image "spring_docker_test:0.0.6" already present on machineNormal Created 10s (x3 over 38s) kubelet, k8s-node1 Created container spring-test-containerWarning Unhealthy 10s (x4 over 30s) kubelet, k8s-node1 Liveness probe failed: dial tcp 10.244.1.185:8086: connect: connection refusedNormal Killing 10s (x2 over 25s) kubelet, k8s-node1 Container spring-test-container failed liveness probe, will be restartedNormal Started 9s (x3 over 37s) kubelet, k8s-node1 Started container spring-test-container
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-pod 1/1 Running 2 41s
这个我们可以看到其的事件,探测失败,然后进行重启。下面我们将其配置为正确的8087
端口,让其探针成功。
[root@k8s-master k8s]# kubectl apply -f my_spring_pod.yaml
pod/spring-test-pod created
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-pod 1/1 Running 0 4s
[root@k8s-master k8s]# kubectl describe pod spring-test-pod
Name: spring-test-pod
Namespace: default
Priority: 0
Node: k8s-node1/192.168.127.129
Start Time: Tue, 02 Jul 2024 22:46:39 +0800
Labels: app=spring-test-pod-label...........
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Scheduled <unknown> default-scheduler Successfully assigned default/spring-test-pod to k8s-node1Normal Pulled 25s kubelet, k8s-node1 Container image "spring_docker_test:0.0.6" already present on machineNormal Created 25s kubelet, k8s-node1 Created container spring-test-containerNormal Started 25s kubelet, k8s-node1 Started container spring-test-container
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-pod 1/1 Running 0 45s
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-pod 1/1 Running 0 2m11s
可以看到其一切正常。
4)、探针不同实现方式及参数
Pod探针可以通过以下三种方式之一来实现:
1.ExecAction:在容器内执行指定命令,如果命令的返回值为0,则认为容器健康。
image: spring_docker_test:0.0.6
readinessProbe: exec: command: - cat - /tmp/healthy.txt
initialDelaySeconds: 5 # 初始化时间
timeoutSeconds: 2 # 超时时间
periodSeconds: 5 # 检测间隔
successThreshold: 1 # 检查成功为 1 次表示存活
failureThreshold: 2 # 检测失败 2 次表示存活
例如我们当前这个ExecAction
,我们是通过cat /tmp/healthy.txt
这个命令判断,如果cat查看不存在这个文件,就探测失败
2.TCPSocketAction:对指定端口上的容器的IP地址进行TCP检查,如果端口打开,则认为容器健康。
TCPSocketAction
的话,我们前面就是通过TCP
端口判断,这里不再说明了
3.HTTPGetAction:对指定的端口和路径上的容器的IP地址执行HTTP Get请求,如果响应的状态码在200到399之间,则认为容器健康。
image: spring_docker_test:0.0.6
readinessProbe: httpGet: path: /profile/name port: 8087 scheme: HTTP
initialDelaySeconds: 5 # 初始化时间
timeoutSeconds: 2 # 超时时间
periodSeconds: 5 # 检测间隔
successThreshold: 1 # 检查成功为 1 次表示存活
failureThreshold: 2 # 检测失败 2 次表示存活
这里的话,其就会通过端口port+path去调用http请求,HTTP正确返回,就表示探测通过。
5)、重启策略
Pod 重启策略包括 Always Onfailure Never, 默认值为 Always
1、 Always: 当容器失效kubelet自动重启该容器
2、OnFailure: 当容器终止运行且退出码不为0 时,由 kubelet自动 重启该容器
3、Never: 不论容器运行状态如何,kubelet都不会重启该容器。
5、Pod调度
1、node打标签pod调度定向选择
kubectl label nodes <node-name> <label-key>=<label-value>
通过上面这个命令我们可以为对应node打上对应的标签,然后在pod调度的时候,就能进行第一选择。
[root@k8s-master feverasa]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready master 354d v1.18.0
k8s-node1 Ready <none> 354d v1.18.0
k8s-node2 Ready <none> 354d v1.18.0
[root@k8s-master feverasa]# kubectl label nodes k8s-node1 node_id=node1
node/k8s-node1 labeled
[root@k8s-master feverasa]# kubectl describe node k8s-node1
Name: k8s-node1
Roles: <none>
Labels: beta.kubernetes.io/arch=amd64beta.kubernetes.io/os=linuxkubernetes.io/arch=amd64kubernetes.io/hostname=k8s-node1kubernetes.io/os=linuxnode_id=node1............
Lease:HolderIdentity: k8s-node1AcquireTime: <unset>RenewTime: Wed, 03 Jul 2024 20:50:33 +0800...............
Addresses:InternalIP: 192.168.127.129Hostname: k8s-node1...............................
我们可以在Labels
看到我们打上的标签node_id=node1
,同时其也有一些默认的标签。
然后我们再进行pod调度时的选择,这里我们加了nodeSelector
,选择的标签是node2
,也就是我们当前不存在有这个标签的pod。
apiVersion: v1 # 必选,API版本号
kind: Pod # 必选,资源对象名称
metadata: name: spring-test-pod # 必选,Pod的名称 namespace: default # 可选,Pod所属的命名空间,默认为default labels: # 可选,自定义的Pod标签 app: spring-test-pod-label
spec: containers: # 必选,Pod中容器列表 - name: spring-test-container # 必选,容器名称 image: spring_docker_test:0.0.6 # 必选,容器镜像,这里以nginx为例,版本为1.21 imagePullPolicy: IfNotPresent # 可选,镜像拉取策略,IfNotPresent表示本地不存在时拉取 command: [ "java","-jar","app.jar" ] #启动命令ports: # 可选,容器需要暴露的端口列表- name: http # 端口名称 containerPort: 8087 # 容器需要监听的端口号,一般是你容器里面启动对应应用的端口nodeSelector:node_id: node2
我们进行运行,可以看到pod并没有调度创建成功,Events中指明3 node(s) didn't match node selector.
。
[root@k8s-master k8s]# kubectl apply -f my_spring_selector_pod.yaml
pod/spring-test-pod created
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-pod 0/1 Pending 0 8s
[root@k8s-master k8s]# kubectl describe pod spring-test-pod
Name: spring-test-pod
Namespace: default
Priority: 0
Node: <none>
Labels: app=spring-test-pod-label
Annotations: Status: Pending
IP:
IPs: <none>
Containers:spring-test-container:Image: spring_docker_test:0.0.6Port: 8087/TCPHost Port: 0/TCPCommand:java-jarapp.jarLiveness: tcp-socket :8087 delay=5s timeout=2s period=5s #success=1 #failure=2Environment:application_name: spring-test-application...............
Events:Type Reason Age From Message---- ------ ---- ---- -------Warning FailedScheduling <unknown> default-scheduler 0/3 nodes are available: 3 node(s) didn't match node selector.Warning FailedScheduling <unknown> default-scheduler 0/3 nodes are available: 3 node(s) didn't match node selector.
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-pod 0/1 Pending 0 115s
我们将nodeSelector
选择的标签修改为node1
:
[root@k8s-master k8s]# kubectl describe pod spring-test-pod
Name: spring-test-pod
Namespace: default
Priority: 0
Node: k8s-node1/192.168.127.129
Start Time: Wed, 03 Jul 2024 21:20:58 +0800
Labels: app=spring-test-pod-label
Annotations: Status: Running
IP: 10.244.1.191.............
Events:Type Reason Age From Message---- ------ ---- ---- -------Warning FailedScheduling <unknown> default-scheduler 0/3 nodes are available: 1 node(s) had taint {node.kubernetes.io/disk-pressure: }, that the pod didn't tolerate, 2 node(s) didn't match node selector.Warning FailedScheduling <unknown> default-scheduler 0/3 nodes are available: 1 node(s) had taint {node.kubernetes.io/disk-pressure: }, that the pod didn't tolerate, 2 node(s) didn't match node selector.Normal Scheduled <unknown> default-scheduler Successfully assigned default/spring-test-pod to k8s-node1Normal Pulled 13s kubelet, k8s-node1 Container image "spring_docker_test:0.0.6" already present on machineNormal Created 13s kubelet, k8s-node1 Created container spring-test-containerNormal Started 13s kubelet, k8s-node1 Started container spring-test-container
[root@k8s-master k8s]#
[root@k8s-master k8s]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE ...............
spring-test-pod 1/1 Running 0 5m22s 10.244.1.191 k8s-node1 <none> <none>
在这里的Events
中我们可以看到,其在进行选择时,两个不匹配。
2、Node 亲和性调度
NodeAffinity 意为 Node 亲和性的调度策略,是用于替换 NodeSe ector 的全新调度策略。目前有两种节点亲和性表达:
RequiredDuringSchedulingIgnoredDuringExecution: 须满足指定的规则才可以调Pod到Node 上,相当于硬限制。
PreferredDuringSchedulingIgnoredDuringExecution: 强调优先满足指定规则,调度器会尝试调度 Pod Node 上,但并不强求,相当于软限制 。多个优先级规则还可以设置权重 (weight) 值,以定义执行的先后顺序。
apiVersion: v1
kind: Pod
metadata: name: affinity-pod-required
spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: disktype operator: In values: - ssd preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: node_type operator: In values: - pc1containers: - name: with-node-affinity image: nginx ports: - containerPort: 80
其的基本配置就是这样,这个我们就不具体验证了。
3、Node互斥调度
我们前面有亲和性调度,那同时应该也有互斥调度。pod的互斥调度策略(Pod Anti-Affinity)在Kubernetes中用于确保某些Pod尽可能地被调度到与特定Pod不同的节点(Node)上,以满足避免竞争资源、提高系统容错性等需求。
Pod互斥性调度规则可以设置为requiredDuringSchedulingIgnoredDuringExecution
或preferredDuringSchedulingIgnoredDuringExecution
:
1)、requiredDuringSchedulingIgnoredDuringExecution
强制要求:在调度期间,必须满足互斥性规则,即Pod不能被调度到与已有Pod存在互斥关系的节点上。
执行时忽略:一旦Pod被调度到某个节点上,即使后续发生变化(如其他Pod被删除或迁移),也不会重新调度该Pod。
2)、preferredDuringSchedulingIgnoredDuringExecution
优先满足:调度器会尝试将Pod调度到满足互斥性规则的节点上,但如果没有这样的节点,也会调度到其他节点上。
权重与优先级:可以设置多个互斥性规则,并为每个规则设置权重,以定义执行的优先级。
apiVersion: v1
kind: Pod
metadata: name: pod-with-anti-affinity
spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - S1 topologyKey: "kubernetes.io/hostname" containers: - name: main image: nginx
在这个示例中,podAntiAffinity
字段被设置为requiredDuringSchedulingIgnoredDuringExecution
,表示Pod在调度时必须满足互斥性规则。labelSelector
用于选择具有security=S1
标签的Pod作为互斥对象,topologyKey
被设置为kubernetes.io/hostname
,表示互斥性是基于节点级别的,即Pod不能与具有相同security=S1
标签的Pod在同一节点上运行。
4、Taints和Tolerations (污点和容忍)
前面介绍的 NodeAffinity节点亲和性,是在 Pod 上定义的一种属性,使得 Pod 能够被调度到某些 Node 上运行(优先选择或强制要求),Taint 则正好相反,它让 Node 拒绝 Pod的运行,简单地说,被标记为 Taint 的节点就是存在间题的节点,比如磁盘要满了、资源不足、存在安全隐患要进行升级维护,希望新的 Pod 不会被调度过来,但被标记为 Taint节点并非故障节点,仍是有效的工作节点,所以仍需将某些 Pod 调度到这些节点时,可以通过使用 Toleration 属性来实现。
污点是从节点角度出发的一种属性,用于描述节点上的一些不利条件,比如节点具有特定的硬件/软件属性(如内存不足、磁盘类型、特殊用途等),或者节点上运行着一些特殊的、不希望被干扰的工作负载。通过设置污点,节点可以明确地告诉Kubernetes调度器:“我不希望某些Pod调度到我这里来”。
污点的格式为key=value:effect
,其中:
key
和value
是污点的标签,用于标识污点的具体类型或原因。
effect
描述了污点的作用,Kubernetes支持以下三种effect:
1)、PreferNoSchedule
:Kubernetes将尽量避免把Pod调度到具有此污点的Node上,但如果集群中没有其他合适的节点,仍然可能会调度。
2)、NoSchedule
:Kubernetes将不会把Pod调度到具有该污点的Node上,但不会影响当前Node上已经存在的Pod。
3)、NoExecute
:Kubernetes将不会把Pod调度到具有此污点的Node上,并且会尝试将Node上已经存在的、无法容忍该污点的Pod驱逐出去。
例如我们前面看node1的信息时Events
提示的,这个污点就是disk-pressure
磁盘空间不足
1 node(s) had taint {node.kubernetes.io/disk-pressure: }, that the pod didn't tolerate, 2 node(s) didn't match node selector.
我们设置下node的污点:
[root@k8s-master k8s]# kubectl taint nodes k8s-node1 node_num=num_node1:PreferNoSchedule
node/k8s-node1 tainted
[root@k8s-master k8s]#
[root@k8s-master k8s]#
[root@k8s-master k8s]# kubectl describe node k8s-node1
Name: k8s-node1
Roles: <none>
Labels: beta.kubernetes.io/arch=amd64beta.kubernetes.io/os=linuxkubernetes.io/arch=amd64kubernetes.io/hostname=k8s-node1kubernetes.io/os=linuxnode_id=node1................
CreationTimestamp: Sat, 15 Jul 2023 16:17:25 +0800
Taints: node_num=num_node1:PreferNoSchedule
Unschedulable: false............
Events:Type Reason Age From Message---- ------ ---- ---- -------Warning FreeDiskSpaceFailed 60m kubelet, k8s-node1 failed to garbage collect required amount of images. Wanted to free 534777856 bytes, but freed 0 bytesWarning ImageGCFailed 50m kubelet, k8s-node1 failed to garbage collect required amount of images. Wanted to free 531881984 bytes, but freed 0 byteWarning FreeDiskSpaceFailed 3s kubelet, k8s-node1 (combined from similar events): failed to garbage collect required amount of images. Wanted to free 531996672 bytes, but freed 0 bytes
可以看到Taints: node_num=num_node1:PreferNoSchedule
。
apiVersion: v1
kind: Pod
metadata: name: my-pod labels: app: my-app
spec: containers: - name: my-container image: my-image:latest # ... 其他容器配置 ... tolerations: - key: "node_num" operator: "Equal" value: "num_node1" effect: "PreferNoSchedule" # 如果不指定tolerationSeconds,则表示这是一个持久的容忍度 # 可以添加多个容忍度配置,以匹配不同的污点 # - key: "another-taint-key" # operator: "Exists" # effect: "NoExecute" # tolerationSeconds: 300
这个例子中,Pod my-pod
被配置了一个容忍度,它允许该Pod被调度到具有key="node-type"
、value="special"
且effect="NoSchedule"
的污点的节点上。operator
字段设置为Equal
表示Pod将仅容忍value
字段与special
完全相等的污点。
6、InitContainer(初始化容器)
1)、基本介绍
在很多应中,用在启动之前都 要进行如下初始化操作
1、等待其他关联组件正确运行 例如数据库或某个后台服务
2、基于环境 变量或配置模板生成配置文件
3、从远程数据库获取本地所需配置,或者将自身注册到注册中心
4、下载相关依赖包 或者对系统进行一些预配置操作
Kubernetes1.3 版本引入了新特性 InitContainer初始化容器,用于在启动应用 appContainer之前一个或多个初始化容器,完成应用容器所需的预置条件,其与应用容器在本质上是一样的,但它们是仅运行一次就结束的任务, 且必须在前一个成功运行完成后,系统才能继续执行下一个容器。init container 不能设置 readinessProbe 探针,因为必须在它们成功运行后才能继续运行在 Pod 中定义的普通容器。根据pod的重启策略(RestartPolicy),当init container 运行失败而且设置了RestartPolicy=Neve 时, 将会启动失败;而设置为RestartPolicy=Always时, 被系统自动重启。
2)、案例说明
apiVersion: v1 # 必选,API版本号
kind: Pod # 必选,资源对象名称
metadata: name: spring-test-pod # 必选,Pod的名称 namespace: default # 可选,Pod所属的命名空间,默认为default labels: # 可选,自定义的Pod标签 app: spring-test-pod-label
spec:initContainers: - name: init-myservice image: spring_docker_test:0.0.6 command: ['sh', '-c', 'ls'] containers: # 必选,Pod中容器列表 - name: spring-test-container # 必选,容器名称 image: spring_docker_test:0.0.6 # 必选,容器镜像,这里以nginx为例,版本为1.21 imagePullPolicy: IfNotPresent # 可选,镜像拉取策略,IfNotPresent表示本地不存在时拉取 command: [ "java","-jar","app.jar" ] #启动命令ports: # 可选,容器需要暴露的端口列表- name: http # 端口名称 containerPort: 8087 # 容器需要监听的端口号,一般是你容器里面启动对应应用的端口restartPolicy: OnFailure
[root@k8s-master k8s]# kubectl describe pod spring-test-pod
Name: spring-test-pod
Namespace: default
Priority: 0
Node: k8s-node1/192.168.127.129
Start Time: Sat, 06 Jul 2024 16:57:43 +0800
Labels: app=spring-test-pod-label
Annotations: Status: Running
IP: 10.244.1.219......................
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Scheduled 2m21s default-scheduler Successfully assigned default/spring-test-pod to k8s-node1Normal Pulled 2m20s kubelet, k8s-node1 Container image "spring_docker_test:0.0.6" already present on machineNormal Created 2m20s kubelet, k8s-node1 Created container init-myserviceNormal Started 2m20s kubelet, k8s-node1 Started container init-myserviceNormal Pulled 2m20s kubelet, k8s-node1 Container image "spring_docker_test:0.0.6" already present on machineNormal Created 2m20s kubelet, k8s-node1 Created container spring-test-containerNormal Started 2m20s kubelet, k8s-node1 Started container spring-test-container
可以看到我们InitContainer是失败的,然后其在自动重启。下面我们改为正确存在的目录/wls/appsystems
。
五、Deployment
Deployment是Kubernetes中用于管理Pod副本的一种控制器资源对象。它允许用户定义Pod的副本数,并确保这个数量的Pod始终可用。我们知道K8S中Pod是最基本的单位,简单理解,就是1个pods就是我们一个运行的实例。但我们不用k8s,就正常的话,一般是多台机部署我们的应用。同样在K8S中,我们生产也多个实例Pod,这里的Deployment就是用来动态处理这个的,也就是pod的扩容、缩容,滚动更新这些。例如我们当前实例的话,想运行3个实例、再缩小到2个pod这些,就可以用Deployment来做对应的处理。
1、使用案例
apiVersion: apps/v1
kind: Deployment
metadata:name: spring-test-deployment
# namespace: demolabels:app: spring-test
spec:replicas: 3 #Pod副本数量strategy:type: RollingUpdate #更新策略 滚动更新rollingUpdate:maxSurge: 1 maxUnavailable: 1selector:matchLabels:app: spring-testtemplate:metadata:labels:app: spring-testspec:containers:- name: spring-test-containerimage: spring_docker_test:0.0.6command: [ "java","-jar","app.jar" ] #启动命令imagePullPolicy: Neverports:- containerPort: 8087
这里我们可以看到我们当前的资源设置的为Deployment
,然后replicas
副本数为3个。这里我们运行后:
[root@k8s-master k8s]# kubectl apply -f my_spring_deploy.yaml
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-deployment-f9f8cddfd-dbp4q 1/1 Running 0 4m15s
spring-test-deployment-f9f8cddfd-lhwll 1/1 Running 0 4m15s
spring-test-deployment-f9f8cddfd-r5qm7 1/1 Running 0 4m15s
可以看到就运行了3个pod。
2、滚动更新
就如果我们需要更新我们的应用版本,我们首先构建一个新版本的docker镜像:
[root@k8s-node1 docker]# docker build -t spring_docker_test:0.0.7 .
Sending build context to Docker daemon 23.13MB
Step 1/8 : FROM openjdk:8-jdk-alpine8-jdk-alpine: Pulling from library/openjdk
e7c96db7181b: Pull complete
f910a506b6cb: Pull complete
c2274a1a0e27: Pull complete
Digest: sha256:94792824df2df33402f201713f932b58cb9de94a0cd524164a0f2283343547b3
Status: Downloaded newer image for openjdk:8-jdk-alpine---> a3562aa0b991
Step 2/8 : MAINTAINER feverasa_test.com---> Running in 5e9d9dcfec78
Removing intermediate container 5e9d9dcfec78---> 4b548e3e431a
Step 3/8 : RUN mkdir -p /wls/appsystems---> Running in 0b8ae9e6833a
Removing intermediate container 0b8ae9e6833a---> 1d9fe9f3b97a
Step 4/8 : COPY SpringBootBasicDemo-0.0.1-SNAPSHOT.jar /wls/appsystems/---> 3595c9e05546
Step 5/8 : WORKDIR /wls/appsystems/---> Running in c0b200ac6780
Removing intermediate container c0b200ac6780---> 4be2e29bff9f
Step 6/8 : RUN mv SpringBootBasicDemo-0.0.1-SNAPSHOT.jar app.jar---> Running in 07e180d9ef2d
Removing intermediate container 07e180d9ef2d---> ce5c69edd08a
Step 7/8 : EXPOSE 8080---> Running in a544bc22569e
Removing intermediate container a544bc22569e---> 9cbe29fea549
Step 8/8 : ENTRYPOINT ["java","-jar","app.jar"]---> Running in 0ad132d652c8
Removing intermediate container 0ad132d652c8---> 5cc4a8377305
Successfully built 5cc4a8377305
Successfully tagged spring_docker_test:0.0.7
[root@k8s-node1 docker]#
[root@k8s-node1 docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
spring_docker_test 0.0.6 5cc4a8377305 33 seconds ago 151MB
spring_docker_test 0.0.7 5cc4a8377305 33 seconds ago 151MB
flannel/flannel v0.22.0 38c11b8f4aa1 13 months ago 69.8MB
flannel/flannel-cni-plugin v1.1.2 7a2dcab94698 19 months ago 7.97MB
registry.aliyuncs.com/google_containers/kube-proxy v1.18.0 43940c34f24f 4 years ago 117MB
registry.aliyuncs.com/google_containers/pause 3.2 80d28bedfe5d 4 years ago 683kB
registry.aliyuncs.com/google_containers/coredns 1.6.7 67da37a9a360 4 years ago 43.8MB
openjdk
这里我们有了一个版本0.0.7
。我们再修改我们Deploument
中的镜像版本为0.0.7
,再apply
一次我们的Deployment
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-deployment-f9f8cddfd-dbp4q 1/1 Running 0 4m15s
spring-test-deployment-f9f8cddfd-lhwll 1/1 Running 0 4m15s
spring-test-deployment-f9f8cddfd-r5qm7 1/1 Running 0 4m15s
[root@k8s-master k8s]# vim my_spring_deploy.yaml
[root@k8s-master k8s]# kubectl apply -f my_spring_deploy.yaml
deployment.apps/spring-test-deployment configured
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-deployment-5d5c8869bf-4cthv 0/1 Running 0 5s
spring-test-deployment-5d5c8869bf-pwplq 0/1 Running 0 5s
spring-test-deployment-f9f8cddfd-dbp4q 1/1 Running 0 4m54s
spring-test-deployment-f9f8cddfd-lhwll 0/1 Terminating 0 4m54s
spring-test-deployment-f9f8cddfd-r5qm7 1/1 Running 0 4m54s
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-deployment-5d5c8869bf-4cthv 0/1 Running 0 29s
spring-test-deployment-5d5c8869bf-pwplq 0/1 Running 0 29s
spring-test-deployment-f9f8cddfd-dbp4q 1/1 Running 0 5m18s
spring-test-deployment-f9f8cddfd-r5qm7 1/1 Running 0 5m18s
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-deployment-5d5c8869bf-4cthv 1/1 Running 0 35s
spring-test-deployment-5d5c8869bf-d8frx 0/1 Running 0 2s
spring-test-deployment-5d5c8869bf-pwplq 1/1 Running 0 35s
spring-test-deployment-f9f8cddfd-dbp4q 0/1 Terminating 0 5m24s
spring-test-deployment-f9f8cddfd-r5qm7 0/1 Terminating 0 5m24s
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-deployment-5d5c8869bf-4cthv 1/1 Running 0 44s
spring-test-deployment-5d5c8869bf-d8frx 0/1 Running 0 11s
spring-test-deployment-5d5c8869bf-pwplq 1/1 Running 0 44s
spring-test-deployment-f9f8cddfd-r5qm7 0/1 Terminating 0 5m33s
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-deployment-5d5c8869bf-4cthv 1/1 Running 0 71s
spring-test-deployment-5d5c8869bf-d8frx 1/1 Running 0 38s
spring-test-deployment-5d5c8869bf-pwplq 1/1 Running 0 71s
就可以看到其在滚动更新。最后产生了3个新的Pod
实例。
3、扩容、缩容
扩、缩容的话,我们修改replicas
的数量,例如我们缩容的话,修改其数量为2
[root@k8s-master k8s]# vim my_spring_deploy.yaml
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-deployment-5d5c8869bf-4cthv 1/1 Running 0 14m
spring-test-deployment-5d5c8869bf-d8frx 1/1 Running 0 13m
spring-test-deployment-5d5c8869bf-pwplq 1/1 Running 0 14m
[root@k8s-master k8s]# kubectl apply -f my_spring_deploy.yaml
deployment.apps/spring-test-deployment configured
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-deployment-5d5c8869bf-4cthv 1/1 Running 0 14m
spring-test-deployment-5d5c8869bf-d8frx 0/1 Terminating 0 14m
spring-test-deployment-5d5c8869bf-pwplq 1/1 Running 0 14m
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-deployment-5d5c8869bf-4cthv 1/1 Running 0 14m
spring-test-deployment-5d5c8869bf-pwplq 1/1 Running 0 14m
[root@k8s-master k8s]# kubectl describe deploy spring-test-deployment
Name: spring-test-deployment
Namespace: default
CreationTimestamp: Sat, 06 Jul 2024 17:13:36 +0800
Labels: app=spring-test
Annotations: deployment.kubernetes.io/revision: 2
Selector: app=spring-test
Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 1 max unavailable, 1 max surge
Pod Template:Labels: app=spring-testContainers:spring-test-container:Image: spring_docker_test:0.0.7Port: 8087/TCPHost Port: 0/TCPCommand:java-jarapp.jarLiveness: tcp-socket :8087 delay=30s timeout=3s period=3s #success=1 #failure=1Readiness: tcp-socket :8087 delay=30s timeout=5s period=5s #success=1 #failure=10Environment: <none>Mounts: <none>Volumes: <none>
Conditions:Type Status Reason---- ------ ------Available True MinimumReplicasAvailableProgressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: spring-test-deployment-5d5c8869bf (2/2 replicas created)
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal ScalingReplicaSet 22m deployment-controller Scaled up replica set spring-test-deployment-f9f8cddfd to 3Normal ScalingReplicaSet 17m deployment-controller Scaled up replica set spring-test-deployment-5d5c8869bf to 1Normal ScalingReplicaSet 17m deployment-controller Scaled down replica set spring-test-deployment-f9f8cddfd to 2Normal ScalingReplicaSet 17m deployment-controller Scaled up replica set spring-test-deployment-5d5c8869bf to 2Normal ScalingReplicaSet 17m deployment-controller Scaled down replica set spring-test-deployment-f9f8cddfd to 1Normal ScalingReplicaSet 17m deployment-controller Scaled up replica set spring-test-deployment-5d5c8869bf to 3Normal ScalingReplicaSet 17m deployment-controller Scaled down replica set spring-test-deployment-f9f8cddfd to 0Normal ScalingReplicaSet 3m8s deployment-controller Scaled down replica set spring-test-deployment-5d5c8869bf to 2
其就停调了3个中的其中一个pod
。
六、Service
Service是Kubemetes 实现微服务架构的核心概念,通过创建 Service 可以为一组具有相同功能的Pod容器应用提供一个统一的入口地址,Service 主要用于提供网络服务,通过 Service 的定义,能够为客户端应用提供稳定的访问地址(域名或 IP 地址)和负载均衡功能,以及屏蔽后端pod的 Endpoint 的变化,客户端可以无需知道Pods的实际IP地址和端口号,直接通过Service的名称和端口来访问服务,是 Kubemetes实现微服务的核心资源。
1、使用案例
apiVersion: v1
kind: Service
metadata:name: spring-test-service# namespace: demo
spec:selector:app: spring-testports:- protocol: TCPport: 8081targetPort: 8087
上面我们指定了资源类型为Service
,然后其也是使用标签选择器,选择了app: spring-test
,也就是我们上面Deployment定义的标签。profile/name
[root@k8s-master k8s]# kubectl apply -f my_spring_service.yaml
service/spring-test-service created
[root@k8s-master k8s]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 357d <none>
spring-test-service ClusterIP 10.98.191.210 <none> 8081/TCP 17s app=spring-test
[root@k8s-master k8s]# kubectl describe service spring-test-service
Name: spring-test-service
Namespace: default
Labels: <none>
Annotations: Selector: app=spring-test
Type: ClusterIP
IP: 10.98.191.210
Port: <unset> 8081/TCP
TargetPort: 8087/TCP
Endpoints: 10.244.1.250:8087,10.244.1.251:8087,10.244.1.252:8087
Session Affinity: None
Events: <none>
[root@k8s-master k8s]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
spring-test-deployment-5d5c8869bf-255t4 1/1 Running 0 89s 10.244.1.251 k8s-node1 <none> <none>
spring-test-deployment-5d5c8869bf-hgqnt 1/1 Running 0 89s 10.244.1.250 k8s-node1 <none> <none>
spring-test-deployment-5d5c8869bf-zzgnv 1/1 Running 0 89s 10.244.1.252 k8s-node1 <none> <none>
[root@k8s-master k8s]#
上面我们可以看到,我们创建了一个spring-test-service
的Service
,然后其分配了一个10.98.191.210:8081
的EndPoint,其关联了对应标签的Pod
。这个10.98.191.210:8081
就是pod之间互通IP。
然后我们进入到其中一个pod中请求下对应应用的接口
[root@k8s-master k8s]# kubectl exec -it spring-test-deployment-5d5c8869bf-hgqnt sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
/wls/appsystems # wget http://10.98.191.210:8081/profile/name
Connecting to 10.98.191.210:8081 (10.98.191.210:8081)
name 100% |******************************************************************************************************************************************************************************************************************************************| 11 0:00:00 ETA
/wls/appsystems # cat name
Hello butty
/wls/appsystems # rm -rf name
/wls/appsystems # wget http://10.244.1.251:8087/profile/name
Connecting to 10.244.1.251:8087 (10.244.1.251:8087)
name 100% |******************************************************************************************************************************************************************************************************************************************| 11 0:00:00 ETA
/wls/appsystems # cat name
Hello butty
这里我们可以看到,我们使用Service的ClusterIP+Port
-10.98.191.210:8081
或者是pod本身的IP+Port
-10.244.1.251:8087
都是可以的。
2、将Service 暴露到集群外部
Kubernetes Service 创建的 ClusterIP 地址是对后端 Po 列表的一层抽象,对于集群外部来说并没有意义,但有许多 Service 是需要对集群外部提供服务的, Kubernetes 提供了多种机制将 Service 暴露出去,供集群外部的客户端访问 这可以通过 Service 资源对象的类型字段 type
进行设置。
Service 的类型如下:
1)、 ClusterIP:
Kubernetes 会自动设置 Service 的虚拟 IP 地址,仅可被集群内部的客户端应用访问。我们也可手工指定一个 ClusterIP 地址,不过需要确保该IP 在Kubernetes 集群设置的 ClusterIP 地址范围内(通过 kube-apiserver 服务的启动参数–service-cluster-ip-range 设置),并且没有被其它 Service 使用。
我们上面的简单案例就是这种类型。
2)、NodePort:
Service 的端口号映射到 Node的一个端口号上,这样集群中的任意 Node 都可以作为 Service 访问入口地址,即 NodeIP:No dePort
apiVersion: v1
kind: Service
metadata:name: spring-test-service# namespace: demo
spec:selector:app: spring-testports:- protocol: TCPport: 8081targetPort: 8087nodePort: 30080 # 如果你想要通过 NodePort 访问,可以添加这一行type: NodePort # 如果你想要通过 NodePort 访问,使用 NodePort;否则使用 ClusterIP
这里我们就设置了对应类型为NodePort
,然后设置了映射到Node
的对应端口为30080
,然后到另一台机器,通过Node也就是宿主机IP访问对应接口:
[root@k8s-master k8s]# kubectl apply -f my_spring_service.yaml
service/spring-test-service created
[root@k8s-master k8s]#
[root@k8s-master k8s]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 357d
spring-test-service NodePort 10.99.16.75 <none> 8081:30080/TCP 4s
[root@k8s-master k8s]# netstat -tunlp | grep 30080
tcp 0 0 0.0.0.0:30080 0.0.0.0:* LISTEN 3584/kube-proxy
[root@k8s-node1 docker]# curl http://192.168.127.133:30080/profile/name
Hello butty
3)、LoadBalancer
将Service映射到一个已存在的负载均衡器的 IP 地址上,通常在公有云环境中使用,使用云提供商的负载均衡器来暴露Service,实现外部流量的负载均衡。
注意:LoadBalancer类型通常需要云提供商的支持
4)、 ExternalName
Service 映射为一个外部域名地址 ,ExternalName
类型的服务用于将外部服务引入到Kubernetes集群中,通常是将外部服务的域名映射到Kubernetes集群中的一个DNS名称。
apiVersion: v1
kind: Service
metadata:name: external-service
spec:type: ExternalNameexternalName: www.baidu.com
这里我们创建了一个跳转到baidu
的Service
。可以看到我们通过external-service
就能直接映射到baidu
的地址
[root@k8s-master k8s]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
external-service ExternalName <none> www.baidu.com <none> 8s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 358d
spring-test-service NodePort 10.99.16.75 <none> 8081:30080/TCP 113m
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-deployment-5d5c8869bf-255t4 1/1 Running 0 148m
spring-test-deployment-5d5c8869bf-hgqnt 1/1 Running 0 148m
spring-test-deployment-5d5c8869bf-zzgnv 1/1 Running 0 148m
[root@k8s-master k8s]# kubectl exec -it spring-test-deployment-5d5c8869bf-255t4 sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
/wls/appsystems # nslookup external-service
nslookup: can't resolve '(null)': Name does not resolveName: external-service
Address 1: 120.232.145.185
Address 2: 120.232.145.144
/wls/appsystems # nslookup external-service.default.svc.cluster.local
nslookup: can't resolve '(null)': Name does not resolveName: external-service.default.svc.cluster.local
Address 1: 120.232.145.185
Address 2: 120.232.145.144
然后这里我们通过external-service.default.svc.cluster.local
也能解析,这种方式主要是不同命名空间的Service
使用的,其方式是<service-name>.<namespace>.svc.cluster.local
,我们的pod与Service是默认的也就是default
,所以我们也可以省略。
5)、HeadlessService
Headless Service 在 Kubernetes 中是一种特殊的服务类型,它不分配 ClusterIP,而是通过 DNS 记录直接返回匹配该服务 Selector 的 Pod 的 IP 地址列表,其的重定向发生在 DNS 层,而且不会进行代理或转发。例如我们想给集群内部使用DNS域名解析到集群里面对应的Pod
。
apiVersion: v1
kind: Service
metadata:name: external-pod-service
spec:selector:app: spring-test
spec:type: ClusterIP # Headless Service,type字段通常保留为 ClusterIP,clusterIP设置为NoneclusterIP: Noneselector:app: spring-testports:- protocol: TCPport: 8087targetPort: 8087
[root@k8s-master k8s]# kubectl describe service external-pod-service
Name: external-pod-service
Namespace: default
Labels: <none>
Annotations: Selector: app=spring-test
Type: ClusterIP
IP: None
Port: <unset> 8087/TCP
TargetPort: 8087/TCP
Endpoints: 10.244.1.2:8087,10.244.1.253:8087,10.244.1.254:8087
Session Affinity: None
Events: <none>
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-deployment-5d5c8869bf-78tcd 1/1 Running 0 38m
spring-test-deployment-5d5c8869bf-hdrvz 1/1 Running 0 38m
spring-test-deployment-5d5c8869bf-wb74d 1/1 Running 0 38m
[root@k8s-master k8s]# kubectl exec -it spring-test-deployment-5d5c8869bf-hdrvz sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
/wls/appsystems # nslookup external-pod-service
nslookup: can't resolve '(null)': Name does not resolveName: external-pod-service
Address 1: 10.244.1.2 spring-test-deployment-5d5c8869bf-hdrvz
Address 2: 10.244.1.253 10-244-1-253.external-pod-service.default.svc.cluster.local
Address 3: 10.244.1.254 10-244-1-254.external-pod-service.default.svc.cluster.local
/wls/appsystems #
/wls/appsystems # wget http://external-pod-service:8087/profile/name
Connecting to external-pod-service:8087 (10.244.1.253:8087)
name 100% |******************************************************************************************************************************************************************************************************************************************| 11 0:00:00 ETA
/wls/appsystems # cat name
Hello butty
/wls/appsystems # rm -rf name
/wls/appsystems # wget http://external-pod-service:8087/profile/name
Connecting to external-pod-service:8087 (10.244.1.254:8087)
name 100% |******************************************************************************************************************************************************************************************************************************************| 11 0:00:00 ETA
例如我们这里配置headlessService
类型,这个我们通过标签下载器选择到对应的pod。然后集群内部通过http://external-pod-service
就可以找到对应的pod。
上面这是集群内部pod通过headlesservice
的dns
到对应的pod。假如我们另一种是需要通过headlesservice
的dns
到外部的ip
要怎么处理呢,下面我们看下这种案例:
这个是与外部IP交互。在这种用法我们的案例要再引入一个外部IP。我们这里就需要用到我们外面的windows机器,因为我们当前是windows -> vmware -> linux -> k8s集群。在这个案例中,我们在外部windows机器上面运行我们的app.jar
应用,,这个192.168.10.110
就是windows对应的本地IP,这里我们启动在8086端口
D:\>java -jar SpringBootBasicDemo-0.0.1-SNAPSHOT.jar --server.port=8086. ____ _ __ _ _/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/ ___)| |_)| | | | | || (_| | ) ) ) )' |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot :: (v2.5.13)..........................
然后定义我们的Service
,还是另一个对应的Endpoints
,我们手动指定一个Endpoints
apiVersion: v1
kind: Endpoints
metadata:name: external-ip-endpoint
subsets:- addresses:- ip: 192.168.10.110ports:- port: 8086
apiVersion: v1
kind: Service
metadata:name: external-ip-endpoint
spec:clusterIP: Nonetype: ClusterIPports:- port: 8086targetPort: 8086
[root@k8s-master k8s]# kubectl apply -f endpoint.yaml
endpoints/external-ip-endpoint created
[root@k8s-master k8s]# kubectl get endpoints
NAME ENDPOINTS AGE
external-ip-endpoint 192.168.10.110:8086 9s
kubernetes 192.168.127.133:6443 358d
spring-test-service 10.244.1.2:8087,10.244.1.253:8087,10.244.1.254:8087 55m
[root@k8s-master k8s]# kubectl apply -f external_endpoint.yaml
service/external-ip-endpoint created
[root@k8s-master k8s]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
external-ip-endpoint ClusterIP None <none> 8086/TCP 4s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 358d
spring-test-service NodePort 10.107.178.62 <none> 8081:30080/TCP 58m
[root@k8s-master k8s]# kubectl describe service external-ip-endpoint
Name: external-ip-endpoint
Namespace: default
Labels: <none>
Annotations: Selector: <none>
Type: ClusterIP
IP: None
Port: <unset> 8086/TCP
TargetPort: 8086/TCP
Endpoints: 192.168.10.110:8086
Session Affinity: None
Events: <none>
[root@k8s-master k8s]# kubectl get pods
NAME READY STATUS RESTARTS AGE
spring-test-deployment-5d5c8869bf-78tcd 1/1 Running 0 71m
spring-test-deployment-5d5c8869bf-hdrvz 1/1 Running 0 71m
spring-test-deployment-5d5c8869bf-wb74d 1/1 Running 0 71m
[root@k8s-master k8s]# kubectl exec -it spring-test-deployment-5d5c8869bf-hdrvz sh
/wls/appsystems # nslookup external-ip-endpoint
nslookup: can't resolve '(null)': Name does not resolveName: external-ip-endpoint
Address 1: 192.168.10.110 192-168-10-110.external-ip-endpoint.default.svc.cluster.local
/wls/appsystems # wget http://external-ip-endpoint:8086/profile/name
Connecting to external-ip-endpoint:8086 (192.168.10.110:8086)
name 100% |******************************************************************************************************************************************************************************************************************************************| 11 0:00:00 ETA
/wls/appsystems # cat name
Hello butty/wls/appsystems #
3、Ingress的使用
1)、简单介绍
通过前面我们了解 Service 一般是 IP 地址和端口号(ClusterIP:Port) ,即工作在 TCP/IP,而对于基于 HTTP 的服务来说,不同的 URL 地址经常对应到不同的后端服务或者虚拟服务器 (Virtua Host) 。并且,如果启用不同pod的话,对应很多不同的Service的端口,一台宿主机就有多个Service的入口。而Ingress主要就是提供一个统一的入口点,使得外部用户可以通过HTTP、HTTPS域名访问集群内的服务。
Kubemetes 使用了一个 Ingress 策略定义和一个具体提供转发服务的 IngressController, 两者结合,实现了基于灵活 Ingress 策略定义的服务路由功能。例如这个,当我用www.example.com:80/api
访问的是spring-boot-test
对应的Service
,用www.example.com:80/data
访问的是tomcat-test
对应的Service。
2)、案例说明
这个要使用的话,首先我们需要需要安装Ingress-Controller
。
1.部署kubernetes-ingress-controller
这个直接用这个yaml文件的内容– wget https://gitee.com/mirrors/ingress-nginx/raw/nginx-0.30.0/deploy/static/mandatory.yaml
,同时这里面有个镜像
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0
连不通,可以修改为国内的镜像地址。
我们首先部署这个,记住这里有创建对应的namespace
:
apiVersion: v1
kind: Namespace
metadata:name: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx
我们之后创建的pod
、service
这些,也需要在这个namespace
下面,我下面的案例已经修改为ingress-nginx111
了。然后我们部署pod
2.部署Pod
这个与我们前面的案例类似,但我们改了两个地方,一个就是namespace :ingress-nginx111
,还有一个就是我们启动加了前置--server.servlet.context-path=/api
apiVersion: apps/v1
kind: Deployment
metadata:name: spring-test-deploymentnamespace: ingress-nginx111labels:app: spring-test
spec:replicas: 3strategy:type: RollingUpdaterollingUpdate:maxSurge: 1maxUnavailable: 1selector:matchLabels:app: spring-testtemplate:metadata:labels:app: spring-testspec:containers:- name: spring-test-containerimage: spring_docker_test:0.0.7command: [ "java","-jar","app.jar","--server.servlet.context-path=/api" ] #启动命令imagePullPolicy: NeverreadinessProbe:tcpSocket:port: 8087initialDelaySeconds: 30periodSeconds: 5failureThreshold: 10timeoutSeconds: 5successThreshold: 1livenessProbe:tcpSocket:port: 8087initialDelaySeconds: 30periodSeconds: 3failureThreshold: 1timeoutSeconds: 3successThreshold: 1ports:- containerPort: 8087
3.部署Service
apiVersion: v1
kind: Service
metadata:name: ingress-nginx111namespace: ingress-nginx111labels:app.kubernetes.io/name: ingress-nginx111app.kubernetes.io/part-of: ingress-nginx111
spec:type: NodePortports:- name: httpport: 80targetPort: 8087protocol: TCP# HTTPnodePort: 32080- name: httpsport: 443targetPort: 443protocol: TCP# HTTPSnodePort: 32443selector:app: spring-test
4、部署Ingress规则
这个就是ingress转换规则
apiVersion: extensions/v1beta1
kind: Ingress
metadata:name: ingress-spring-appnamespace: default
spec:rules:- host: www.k8s.ingress.comhttp:paths:- path: /api/backend:serviceName: spring-test-serviceservicePort: 8087
这里就是根据host
域名www.k8s.ingress.com
,以及paths
映射路径去到对应Service
,需要看到是这里的host
以及path
都是数组,可以配置多个。
5、查看对应创建的内容
[root@k8s-master k8s]# kubectl get all -n ingress-nginx111
NAME READY STATUS RESTARTS AGE
pod/nginx-ingress-controller-668f87f6d7-8kfkc 1/1 Running 0 30m
pod/spring-test-deployment-7489d5644b-dxbhv 1/1 Running 0 30m
pod/spring-test-deployment-7489d5644b-n5jw5 1/1 Running 0 28m
pod/spring-test-deployment-7489d5644b-z54d2 1/1 Running 0 30mNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ingress-nginx111 NodePort 10.107.153.63 <none> 80:32080/TCP,443:32443/TCP 81mNAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-ingress-controller 1/1 1 1 23h
deployment.apps/spring-test-deployment 3/3 3 3 23hNAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-ingress-controller-668f87f6d7 1 1 1 23h
replicaset.apps/spring-test-deployment-5d5c8869bf 0 0 0 23h
replicaset.apps/spring-test-deployment-7489d5644b 3 3 3 30m
[root@k8s-master k8s]# kubectl describe ingress ingress-spring-app
Name: ingress-spring-app
Namespace: default
Address: 10.107.153.63
Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:Host Path Backends---- ---- --------www.k8s.ingress.com /api/ spring-test-service:8087 (<none>)
Annotations: Events:Type Reason Age From Message---- ------ ---- ---- -------Normal UPDATE 47m (x2 over 49m) nginx-ingress-controller Ingress default/ingress-spring-appNormal CREATE 46m nginx-ingress-controller Ingress default/ingress-spring-appNormal CREATE 30m nginx-ingress-controller Ingress default/ingress-spring-app
[root@k8s-master k8s]#
这里可以看到我们创建的ingress-controller
、service
、pod
、ingress
。
6.验证
下面我们设置本地的host文件的域名映射,在/etc/hosts
文件添加映射
10.107.153.63 www.k8s.ingress.com
我们进行对应请求
[root@k8s-node1 feverasa]# vim /etc/hosts
[root@k8s-node1 feverasa]# curl http://www.k8s.ingress.com:80/api/profile/name
Hello butty
[root@k8s-node1 feverasa]# curl http://10.107.153.63:80/api/profile/name
Hello butty
[root@k8s-node1 feverasa]# curl http://192.168.127.129:32080/api/profile/name
Hello butty