k8s之持久化存储pv&pvc
存储资源管理
在基于k8s容器云平台上,对存储资源的使用需求通常包括以下几方面:
1.应用配置文件、密钥的管理;
2.应用的数据持久化存储;
3.在不同的应用间共享数据存储;
k8s支持Volume类型
k8s的Volume抽象概念就是针对以上问题提供的解决方案,k8s的volume类型非常丰富,从临时目录、宿主机目录、ConfigMap、Secret、共享存储(PV和PVC)。
1.临时空目录(随着Pod的销毁而销毁)
emptyDir
2.配置类(将配置文件以Volume的形式挂载到容器内)
ConfigMap:将保存在ConfigMap资源对象中的配置文件信息挂载到容器内的某个目录下
Secret:将保存在Secret资源对象中的密码密钥等信息挂载到容器内的某个文件中。
downwardAPI:将downwardAPI的数据以环境变量或文件的形式注入容器中。
3.本地存储类
hostpath:将宿主机的目录或文件挂载到容器内进行使用。
4.共享存储
PV(Persistent Volume):将共享存储定义为一种“持久存储卷”,可以被多个容器应用共享使用。
PVC(Persistent Volume Claim):用户对存储资源的一次“申请”,PVC申请的对象是PV,一旦申请
成功,应用就能够像使用本地目录一样使用共享存储了。
ConfigMap、Secret、emptyDir、hostPath等属于临时性存储,当pod被调度到某个节点上时,它们随pod的创建而创建,临时占用节点存储资源,当pod离开节点时,存储资源被交还给节点,pod一旦离开这个节点,存储就失效,不具备持久化存储数据的能力。与此相反,持久化存储拥有独立的生命周期,具备持久化存储能力,其后端一般是独立的存储系统如NFS、iSCSI、cephfs、glusterfs等。
pv与pvc
官方文档持久卷 | Kubernetes
1、PV 概念
PersistentVolume(PV)持久卷
是集群中的一块存储,可以由管理员配置或者使用存储类(Storage Class)来动态配置。
持久卷是集群资源。PV持久卷和普通的 Volume 一样,也是使用卷插件来实现的,pv是对诸如NFS、
iSCSI、云存储等各种存储为后端所提供的存储(如:可以从远程的NFS 或分布式对象
存储系统中创建出PV存储空间大小、访问方式)。
PV拥有完全独立的生命周期。
PV 就是从存储设备中的空间创建出一个存储资源。
2、PVC概念
PersistentVolumeClaim(PVC)持久卷申领
PVC用户对存储的请求。概念上与 Pod 类似。Pod会耗用节点资源,而PVC申领会耗用PV资源。Pod
可以请求特定数量的资源(CPU 和内存)。同样 PVC 申领也可以请求特定的大小和访问模式.
不需要指定具体的PV,通过标签选择器来动态匹配PV。只有匹配成功的PV才能被绑定到PVC。一旦
绑定成功,Pod通过PVC访问PV提供的存储资源。
用户不能直接使用PV,需要通过pvc先向系统申请存储空间,PVC的存在使得Pod与具体的存储实现
解耦,提高了可移植性。PVC申领耗用PV资源。PVC 的使用逻辑:在pod中定义一个存储卷(该存储卷类型为PVC),PVC必须与对应的PV建立关系,
PVC会根据配置定义的时候定义申请的空间大小与访问模式去向PV申请存储空间。
pv对比pvc
PV是集群中的资源。 PVC是对这些资源的请求。
PV 和 PVC 可以将 pod 和数据卷解耦,pod 不需要知道确切的文件系统或者支持它的持久化引擎。
PV和PVC的生命周期
PV 和 PVC 之间的相互作用遵循这个生命周期:
Provisioning(配置) ---> Binding(绑定) ---> Using(使用) ---> Releasing(释放)
---> Recycling(回收)
(1)创建Provisioning
PV可以由集群管理员手动创建(静态方式),或通过动态配置的方式由StorageClass自动创建。
(2)绑定Binding
PV可以绑定到一个或多个PVC。当PVC被创建并与PV匹配时,它们将被绑定在一起,形成PV-PVC绑定关系。
(3)使用Using
PV可以被Pod使用,Pod可以通过VolumeMount将PV挂载到容器中,并在容器中访问持久化存储。
Pod 通过 PVC 使用该Volume,并可以通过准入控制StorageProtection(1.9及以前版本为
PVCProtection) 阻止删除正在使用的PVC
(4)释放Releasing
Pod 释放 Volume 并删除 PVC
在释放后,PV可以重新被其他PVC绑定,以供新的Pod使用
(5)回收Reclaiming
回收 PV,保留 PV 以便下次使用,或直接从云存储中删除释放后对PV进行清理和重用的过程。
回收策略:决定PV在释放后的处理方式,包含:
Retain(保留):删除PV或手动清理PV数据,位于外部基础设施中的存储资产在PV删除之后仍然存在
Delete(删除):移除PV并从外部基础设施中移除所关联的存储资产,动态模式的默认策略
Recycle(回收):已弃用
一个PV从创建到销毁的具体流程:
一个PV创建完后状态会变成Available,等待被PVC绑定。
一旦被PVC邦定,PV的状态会变成Bound,就可以被定义了相应PVC的Pod使用。
Pod使用完后会释放PV,PV的状态变成Released。
变成Released的PV会根据定义的回收策略做相应的回收工作。
Kubernetes的共享存储供应模式(PV的模式)
包括静态和动态两种模式
静态模式
静态PV由系统管理员负责创建、提供、维护,系统管理员为用户屏蔽真正提供存储的后端及其实现细节,
普通用户作为消费者,只需通过PVC申请、使用此类资源。需要先创建好PV,然后在将定义好PVC进行
一对一的Bond
动态模式:
如果PVC请求成千上万,需要创建成千上万的PV,对于运维人员来说维护成本很高。为了解决这一问题
K8s提供一种自动创建PV的机制,叫StorageClass,它的作用就是自动创建PV的模板。通过创建StorageClass
定义 PV 的属性,比如存储类型、大小等
创建这种 PV 需要用到的存储插件。有了这两部分信息,Kubernetes 就能够根据用户提交的 PVC,
自动找到对应的 StorageClass,然后 Kubernetes 就会调用 StorageClass 声明的存储插件,自动
创建需要的 PV 并进行绑定。如果用户的PVC中“storage class”的值为"",则表示不能为此PVC动态创建PV。
访问模式
定义了存储卷如何被集群中的节点挂载。访问模式并不直接决定Pod对存储的访问权限,而是决定PV支持哪些节点挂载方式。PV的访问模式主要有以下几种:
ReadWriteOnce 卷被一个节点以读写方式挂载。可以在同一节点上运行的多个Pod访问该卷。
ReadOnlyMany 卷可以被多个节点以只读方式挂载。
ReadWriteMany 卷可以被多个节点以读写方式挂载。
ReadWriteOncePod 卷可以被单个 Pod 以读写方式挂载。在命令行接口(CLI)中,访问模式也使用以下缩写形式:
RWO - ReadWriteOnce
ROX - ReadOnlyMany
RWX - ReadWriteMany
RWOP - ReadWriteOncePod
PV与PVC的绑定
用户创建包含容量、访问模式等信息的PVC,向系统请求存储资源。系统查找已存在PV或者监控新
创建PV,如果与PVC匹配则将两者绑定。
如果PVC创建动态PV,则系统将一直将两者绑定。PV与PVC的绑定是一一对应关系,不能重复绑定。
如果系统一直没有为PVC找到匹配PV,则PVC会一直处在pending状态,直到系统找到匹配PV。实际
绑定的PV容量可能大于PVC中申请的容量。
持久卷pv的类型
PV 持久卷是用插件的形式来实现的。Kubernetes 目前支持以下插件:
- csi - 容器存储接口(CSI)
- fc - Fibre Channel(FC)存储
- hostPath - HostPath 卷 (仅供单节点测试使用;不适用于多节点集群;请尝试使用
local
卷作为替代) - iscsi - iSCSI(IP 上的 SCSI)存储
- local - 节点上挂载的本地存储设备
- nfs - 网络文件系统(NFS)存储
实验mysql基于NFS共享存储实现静态持久化存储
安装NFS
k8s-master 制作nfs服务端作为共享文件系统
[root@k8s-master ~]# yum install -y nfs-utils rpcbind
[root@k8s-master ~]# mkdir /mnt/data #制作共享目录
[root@k8s-master ~]# vim /etc/exports
/mnt/data 192.168.122.0/24(rw,no_root_squash)
[root@k8s-master ~]# systemctl start rpcbind #启动服务
[root@k8s-master ~]# systemctl start nfs
集群中的工作节点都需要安装客户端工具,主要作用是节点能够驱动 nfs 文件系统
只安装,不启动服务
# yum install -y nfs-utils
制作PV
master节点制作pv.yaml(一般这个动作由 kubernetes 管理员完成,也就是我们运维人员)
[root@k8s-master ~]# mkdir /k8s/mysql -p
[root@k8s-master ~]# cd /k8s/mysql/
[root@k8s-master mysql]# vim pv.yaml
apiVersion: v1
kind: PersistentVolume #类型定义为pv
metadata: name: my-pv #pv的名字labels: #定义标签type: nfs
spec:storageClassName: nfs # 存储类型,需要与底层实际的存储一致,这里采用 nfsnfs: # 定义nfs的配置信息server: 192.168.122.24 # NFS 服务器的 IPpath: "/mnt/data" # NFS 上共享的目录capacity: #定义存储能力storage: 3Gi #指定存储空间accessModes: #定义访问模式- ReadWriteMany #读写权限,允许被多个Node挂载persistentVolumeReclaimPolicy: Retain #定义数据回收策略,这里是保留
PV参数详解
1.存储能力(Capacity)
描述存储设备的能力,目前仅支持对存储空间的设置(storage=xx)。
2.访问模式(Access Modes)
对PV进行访问模式的设置,用于描述用户应用对存储资源的访问权限。访问模式如下:
ReadWriteOnce:读写权限,并且只能被单个pod挂载。
ReadOnlyMany:只读权限,允许被多个pod挂载。
ReadWriteMany:读写权限,允许被多个pod挂载。
某些PV可能支持多种访问模式,但PV在挂载时只能使用一种访问模式,多种访问模式不能同时生效。
3.persistentVolumeReclaimPolicy定义数据回收策略
目前支持如下三种回收策略:
1.保留(Retain):该策略表示保留PV中的数据,不进行回收,必须手动处理。
2.回收空间(Recycle):该策略表示在PV释放后自动执行清除操作,使PV可以重新使用。效果相当于
执行 rm -rf /thevolume/*。只有 NFS 和 HostPath 两种类型的 PV支持 Recycle 策略。
3.删除(Delete):该策略表示在PV释放后自动删除PV中的数据。同时也会从外部(如 AWS EBS、
GCE PD、Azure Disk 或 Cinder 卷)中移除所关联的存储资产。 就是把云存储一起删了。
4.storageClassName存储类别(Class)
PV可以设定其存储的类型(Class),通过 storageClassName参数指定一个 StorageClass
资源对象的名称。具有特定“类别”的 PV 只能与请求了该“类别”的 PVC 进行绑定。未设定 “类别”
的 PV 则只能与不请求任何 “类别” 的 PVC 进行绑定。
相当于一个标签。
创建pv
[root@k8s-master mysql]# kubectl apply -f pv.yaml
persistentvolume/my-pv created
[root@k8s-master mysql]# kubectl get pv
PV 生命周期的各个阶段(Phase)
某个 PV 在生命周期中,可以处于以下4个阶段之一:
- Available:可用状态,还未与某个 PVC 绑定。
- Bound:已与某个 PVC 绑定。
- Released:释放,绑定的 PVC 已经删除,但没有被集群回收存储空间 。
- Failed:自动资源回收失败。Access mode解释:
RWO:readwariteonce: 允许同一个node节点上的pod已读写的方式访问
ROX: readonlymany: 允许不同node节点的pod以只读方式访问
RWX: readwritemany: 允许不同的node节点的pod以读写方式访问pv创建成功目前属于可用状态,还没有与pvc绑定,那么现在创建pvc
创建pvc
[root@k8s-master mysql]# vim mysql-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim #定义类型为PVC
metadata:name: mypvc #声明pvc的名称,当做pod的卷使用时会用到
spec:accessModes: #定义访问pvc的模式,与pv拥有一样的模式- ReadWriteMany #读写权限,允许被多个pod挂载resources: #声明可以请求特定数量的资源,目前仅支持 request.storage 的设置,即存储空间大小。requests:storage: 3Gi #定义空间大小storageClassName: nfs #指定绑定pv的类型,即使不指定类型pvc也会自动去匹配对应大小的pv
注意:当我们申请pvc的容量大于pv的容量是无法进行绑定的。
创建pvc
[root@k8s-master mysql]# kubectl apply -f mysql-pvc.yaml
persistentvolumeclaim/mypvc created
[root@k8s-master mysql]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mypvc Bound my-pv 3Gi RWX pv-nfs 37s
status状态
- Available (可用): 表示可用状态,还未被任何PVC绑定 - Bound (已绑定):已经绑定到某个PVC - Released (已释放):对应的PVC已经删除,但资源还没有被集群收回 - Failed:PV自动回收失败
Kubernetes中会自动帮我们查看pv状态为Available并且根据声明pvc容量storage的大小进行筛选匹配,同时还会根据AccessMode进行匹配。如果pvc匹配不到pv会一直处于pending状态。
mysql使用pvc持久卷
创建secret
[root@k8s-master mysql]# echo -n 'Yunjisuan@666' | base64
WXVuamlzdWFuQDY2Ng==
[root@k8s-master mysql]# vim mysql-secret.yaml
apiVersion: v1
data:password: WXVuamlzdWFuQDY2Ng==
kind: Secret
metadata:annotations:name: my-pass
type: Opaque
[root@k8s-master mysql]# kubectl apply -f mysql-secret.yaml
secret/my-pass created
[root@k8s-master mysql]# kubectl get secret
NAME TYPE DATA AGE
default-token-24c52 kubernetes.io/service-account-token 3 6d22h
my-pass Opaque 1 69s
创建myslq-pod文件
[root@k8s-master mysql]# vim mysql-pv.yaml
apiVersion: v1
kind: Pod
metadata:name: my-mysqllabels:db: mysql
spec:containers:- name: my-mysqlimage: daocloud.io/library/mysql:5.7ports:- containerPort: 3306env:- name: MYSQL_ROOT_PASSWORDvalueFrom:secretKeyRef:name: my-passkey: passwordvolumeMounts:- name: mysql-datamountPath: /var/lib/mysqlvolumes:- name: mysql-datapersistentVolumeClaim: #定义卷的类型为pvcclaimName: mypvc #指定对应pvc的名字
[root@k8s-master mysql]# kubectl apply -f mysql-pv.yaml
[root@k8s-master mysql]# kubectl get pod
NAME READY STATUS RESTARTS AGE
my-mysql 1/1 Running 0 8s
[root@k8s-master mysql]# kubectl get pod -o wide
[root@master mysql]# kubectl get pod -l db=mysql -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
my-mysql 1/1 Running 0 24s 10.244.2.80 node-2 <none> <none>
测试
[root@k8s-master ~]# cd /mnt/data/
[root@k8s-master data]# ll
总用量 188484
-rw-r----- 1 polkitd ssh_keys 56 11月 8 21:49 auto.cnf
-rw------- 1 polkitd ssh_keys 1680 11月 8 21:49 ca-key.pem
-rw-r--r-- 1 polkitd ssh_keys 1112 11月 8 21:49 ca.pem
-rw-r--r-- 1 polkitd ssh_keys 1112 11月 8 21:49 client-cert.pem
-rw------- 1 polkitd ssh_keys 1680 11月 8 21:49 client-key.pem
-rw-r----- 1 polkitd ssh_keys 688 11月 8 21:57 ib_buffer_pool
-rw-r----- 1 polkitd ssh_keys 79691776 11月 8 21:59 ibdata1
-rw-r----- 1 polkitd ssh_keys 50331648 11月 8 21:59 ib_logfile0
-rw-r----- 1 polkitd ssh_keys 50331648 11月 8 21:49 ib_logfile1
-rw-r----- 1 polkitd ssh_keys 12582912 11月 8 22:00 ibtmp1
drwxr-x--- 2 polkitd ssh_keys 4096 11月 8 21:49 mysql
drwxr-x--- 2 polkitd ssh_keys 8192 11月 8 21:49 performance_schema
-rw------- 1 polkitd ssh_keys 1680 11月 8 21:49 private_key.pem
-rw-r--r-- 1 polkitd ssh_keys 452 11月 8 21:49 public_key.pem
-rw-r--r-- 1 polkitd ssh_keys 1112 11月 8 21:49 server-cert.pem
-rw------- 1 polkitd ssh_keys 1676 11月 8 21:49 server-key.pem
drwxr-x--- 2 polkitd ssh_keys 8192 11月 8 21:49 sys
动态绑定pv
StorageClass 相当于一个创建 PV 的模板,用户通过 PVC 申请存储卷,StorageClass 通过模板自动创建 PV,然后和 PVC 进行绑定。
StorageClass创建动态存储卷流程
1)集群管理员预先创建存储类(StorageClass);
2)用户创建使用存储类的持久化存储声明(PVC:PersistentVolumeClaim);
3)存储持久化声明通知系统,它需要一个持久化存储(PV: PersistentVolume);
4)系统读取存储类的信息;
5)系统基于存储类的信息,在后台自动创建PVC需要的PV;
6)用户创建一个使用PVC的Pod;
7)Pod中的应用通过PVC进行数据的持久化;
8)而PVC使用PV进行数据的最终持久化处理。
StorageClass支持的动态存储插件:
面试点
PV 和 PVC 有什么区别?
- PV 是由集群管理员创建的存储资源,它定义了存储的容量、访问模式、回收策略等属性。
- PVC 是用户向集群申请存储资源的方式,它指定了所需的存储容量和访问模式。
PV 和 PVC 的生命周期有哪些阶段?
PV 的生命周期包括:
Available:PV 已创建,但尚未绑定到 PVC。
Bound:PV 已经绑定到 PVC。
Released:PV 与 PVC 解绑。
Recycling:PV 正在被清理。
Failed:PV 处于故障状态。PVC 的生命周期包括:
Pending:PVC 已创建,但尚未绑定到 PV。
Bound:PVC 已经绑定到 PV。
Lost:PVC 与 PV 之间的绑定丢失。
dnsPolicy
在 Kubernetes 中,`dnsPolicy` 是一个重要的配置选项,它影响 Pod 如何进行 DNS 解析。以下是 Kubernetes 中支持的几种 `dnsPolicy` 选项:
1. ClusterFirst
- 这是默认的 DNS 策略,意味着当 Pod 需要进行域名解析时,首先会查询集群内部的 CoreDNS 服务。通过 CoreDNS 来做域名解析,表示 Pod 的 `/etc/resolv.conf` 文件被自动配置指向 kube-dns 服务地址。如果集群内的 DNS 服务器不能解析该域名,查询将会被转发到节点的上游 DNS 服务器 。
2. Default
- 当设置为 `Default` 时,Pod 会继承运行所在节点的名称解析配置。这意味着 Pod 的 DNS 配置与宿主机完全一致。请注意,“Default” 不是默认的 DNS 策略;如果没有明确指定 `dnsPolicy`,则默认使用 “ClusterFirst” 。
3. None
- 使用 `None` 策略时,Kubernetes 会忽略集群的 DNS 策略,Pod 将不会收到任何预设的 DNS 配置。为了确保 Pod 仍然可以解析域名,你需要通过 `dnsConfig` 字段来指定自定义的 DNS 配置信息。例如,你可以指定名称服务器(`nameservers`)、搜索路径(`searches`)以及其他选项(`options`) 。
4. ClusterFirstWithHostNet
- 这种策略适用于使用主机网络(`hostNetwork`)的 Pod。在这种情况下,Pod 会首先使用集群内的 DNS 服务器进行解析,然后才会使用主机网络的 DNS 服务器。当 Pod 使用主机网络模式时,应该显式设置其 DNS 策略为 `ClusterFirstWithHostNet` 。
以下是具体的使用示例:
- 使用 `ClusterFirst` 策略:
apiVersion: v1
kind: Pod
metadata:name: example-pod
spec:containers:- name: example-containerimage: nginxdnsPolicy: ClusterFirst
- 使用 `None` 策略,并自定义 DNS 配置:
apiVersion: v1
kind: Pod
metadata:name: my-custom-dns-pod
spec:containers:- name: my-containerimage: my-imagednsPolicy: NonednsConfig:nameservers:- 1.1.1.1- 8.8.8.8searches:- my-domain.com- ns1.my-domain.comoptions:- name: ndotsvalue: "2"
在这个例子中,dnsPolicy被设置为None,这意味着Pod将不使用Kubernetes的默认DNS设置,而是使用dnsConfig中定义的配置。nameservers指定了DNS服务器的地址,searches定义了搜索域,options定义了其他的选项。
Statefulset有状态服务控制器
StatefulSet | Kubernetes
StatefulSet 是 Kubernetes 中用于管理有状态应用的工作负载控制器。与 Deployment 这类主要用于无状态应用的控制器不同,StatefulSet 设计用于处理那些需要持久化存储、稳定唯一网络标识符以及有序滚动更新的应用场景,例如数据库集群、消息队列、文件服务器等。
Service 管理
- Headless Service: 通常会创建一个 Headless Service(无头服务),用来提供 Pod 的 DNS 名称,而不需要为 Service 分配一个 Cluster IP。
- Service Selector: 通过标签选择器关联 Pod 和 Service。
Pod 的标识
- 序号索引:对于具有 N 个副本的 StatefulSet,每个 Pod 都会被分配一个从 00 到 N−1 的唯一整数序号。
- Pod 命名:每个 Pod 的名称形式为
<statefulSetName>-<ordinal>
,其中<ordinal>
是从 00 开始的序号。例如,如果有一个名为my-statefulset
的 StatefulSet,它创建的 Pod 可能命名为my-statefulset-0
、my-statefulset-1
等等。
网络标识
- Headless Service:StatefulSet 通常会创建一个没有 ClusterIP 的 Service(称为 Headless Service 或无头服务),这个 Service 不会为 StatefulSet 中的 Pods 分配集群 IP 地址,而是直接暴露 Pods 的 IP 地址。这意味着你可以直接访问这些 Pods,或者通过 DNS 解析它们的名字来访问它们。
- DNS 记录:Pod 会根据 StatefulSet 的名称和 Pod 的序号派生出它的主机名。组合主机名的格式为
$(StatefulSet 名称)-$(序号)
。例如,一个名为web
的 StatefulSet 将会创建名称分别为web-0
、web-1
、web-2
的 Pods。
Pod 的创建和删除顺序
- 创建顺序:当 StatefulSet 部署 Pod 时,会从编号 00 到最终编号逐一部署每个 Pod,只有前一个 Pod 部署完成并处于运行状态后,下一个 Pod 才会开始部署。
- 删除顺序:在删除或缩容时,StatefulSet 会从最高序号到最低序号依次删除 Pod
k8s有状态服务和无状态服务的区别
无状态服务特点
1、无状态服务不会在本地存储持久化数据.多个实例可共享相同的持久化数据,如nginx/tomcat/负载
均衡等实例。
2、在k8s中启停无状态服务的pod不影响其它pod,而且pod的名字和网络也都是随机生成。
3、管理无状态服务的资源有ReplicaSet、ReplicationController、Deployment
4、随机缩容:创建的pod都是随机的,缩容也是随机的,并不会明确缩容某一个pod,所以缩容任何
一个pod都可以。
有状态服务介绍
1、有状态服务需要在本地存储持久化数据,如:mysql/kafka/zookeeper/redis主从架构
2、实例之间有依赖的关系.比如,主从关系,启动顺序
3、如果停止集群中任一实例pod,就可能会导致数据丢失或者集群失败
4、创建有状态服务的方式:statefulSet管理
更新策略
StatefulSet 支持两种更新策略:RollingUpdate
和 OnDelete
。
- RollingUpdate:这种策略下,新的 Pod 会在旧的 Pod 被终止之前创建,这允许你在更新过程中保持应用的可用性。
- OnDelete:这种策略下,只有在所有旧的 Pods 被删除后才会创建新的 Pods,这可能会导致短暂的服务中断。
StatefulSet组成部分
1. Headless Service:无头服务,用于为Pod资源标识符生成可解析的DNS记录。
2. volumeClaimTemplates:存储卷申请模板,创建pvc,指定pvc名称大小,自动创建pv,且pv由存储类供应。
3. StatefulSet:管理有状态的pod实例的
什么是Headless service?
Headless service不分配cluster IP,通过解析service的域名,返回所有Pod的endpoint列表。
1.headless service会为service分配一个域名
2.StatefulSet会为关联的Pod定义一个不变的Pod Name:名字格式为$(StatefulSet name)-$(pod序号)(pod序号从0开始)
3.StatefulSet会为关联的Pod分配一个dnsName
$<Pod Name>.$<service name>.$<namespace name>.svc.cluster.local
实验
创建pv
1.使用nfs制作pv,准备pv共享的目录
[root@k8s-master ~]# cd /data/vol/
[root@k8s-master vol]# ls
data1 data2 data3 data4 data5
2.定义nfs共享目录
[root@k8s-master ~]# cat /etc/exports
/data/vol/data1 * (rw,no_root_squash)
/data/vol/data2 * (rw,no_root_squash)
/data/vol/data3 * (rw,no_root_squash)
/data/vol/data4 * (rw,no_root_squash)
/data/vol/data5 * (rw,no_root_squash)
3.定义pv并创建pv
[root@k8s-master test-pv]# cat nfs-pv.yml
apiVersion: v1
kind: PersistentVolume
metadata:name: nfs-pv-1labels:app: pv-1namespace: default
spec:nfs:path: /data/vol/data1server: 172.16.229.4accessModes:- ReadWriteOncecapacity:storage: 2GistorageClassName: nfs #由于是手动创建pv,在此通过该参数指定存储类型为nfspersistentVolumeReclaimPolicy: Retain
---
apiVersion: v1
kind: PersistentVolume
metadata:name: nfs-pv-2labels:app: pv-2namespace: default
spec:nfs:path: /data/vol/data2server: 172.16.229.4accessModes:- ReadWriteOncecapacity:storage: 2GistorageClassName: nfspersistentVolumeReclaimPolicy: Retain
---
apiVersion: v1
kind: PersistentVolume
metadata:name: nfs-pv-3labels:app: pv-3namespace: default
spec:nfs:path: /data/vol/data3server: 172.16.229.4accessModes:- ReadWriteOncecapacity:storage: 2GistorageClassName: nfspersistentVolumeReclaimPolicy: Retain
---
apiVersion: v1
kind: PersistentVolume
metadata:name: nfs-pv-4labels:app: pv-4namespace: default
spec:nfs:path: /data/vol/data4server: 172.16.229.4accessModes:- ReadWriteOncecapacity:storage: 2GistorageClassName: nfspersistentVolumeReclaimPolicy: Retain[root@k8s-master test-pv]# kubectl apply -f nfs-pv.yml
persistentvolume/nfs-pv-1 created
persistentvolume/nfs-pv-2 created
persistentvolume/nfs-pv-3 created
persistentvolume/nfs-pv-4 created
[root@k8s-master test-pv]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
nfs-pv-1 2Gi RWO Retain Available nfs 4s
nfs-pv-2 2Gi RWO Retain Available nfs 4s
nfs-pv-3 2Gi RWO Retain Available nfs 4s
nfs-pv-4 2Gi RWO Retain Available nfs 4s
创建statefulset资源
1.定义satefulset与svc资源
[root@k8s-master statefulset]# cat statefulset.yml
apiVersion: v1
kind: Service
metadata:name: web-svclabels:app: web
spec:ports:- port: 80 #定义svc的端口clusterIP: None #定义none表示该svc没有clusterip也称为无头服务selector: #定义标签选择器,关联带有该标签的podapp: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:name: webnamespace: defaultlabels:app: web
spec:replicas: 3selector: #定义statefulset要管理带有某个标签的podmatchLabels:app: nginxserviceName: web-svc #指定管理的svc的名字volumeClaimTemplates: #定义持久化存储卷的申请模版- metadata: #定义模版的名字name: wwwspec:accessModes: ["ReadWriteOnce"] #定义卷的访问模式storageClassName: nfs #定义卷的类型,以上两个值都需要与定义的pv一致才能# 自动匹配到对应的pvresources:requests:storage: 2Gi #定义卷的大小template:metadata:labels:app: nginxspec:containers:- name: nginximage: daocloud.io/library/nginx:1.16imagePullPolicy: IfNotPresentports:- containerPort: 80volumeMounts:- name: www #卷的名字,与卷模版的名字一样即可mountPath: /usr/share/nginx/html
[root@k8s-master statefulset]# kubectl apply -f statefulset.yml
service/web-svc created
statefulset.apps/web created[root@k8s-master ~]# kubectl get sts #sts是statefulset的缩写
NAME READY AGE
web 3/3 64m[root@k8s-master statefulset]# kubectl get pod
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 16s
web-1 1/1 Running 0 11s
web-2 1/1 Running 0 7s注:pod的名字命名是由statefulset的名字加数字,按顺序命名。[root@k8s-master statefulset]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 29d
web-svc ClusterIP None <none> 80/TCP 27s[root@k8s-master statefulset]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www-web-0 Bound nfs-pv-1 2Gi RWO nfs 5m50s
www-web-1 Bound nfs-pv-2 2Gi RWO nfs 5m45s
www-web-2 Bound nfs-pv-3 2Gi RWO nfs 5m41s查看svc详细信息
[root@k8s-master statefulset]# kubectl describe svc web-svc
Name: web-svc
Namespace: default
Labels: app=web
Annotations: <none>
Selector: app=nginx
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: None
IPs: None
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.247.30:80,10.244.247.31:80,10.244.84.158:80
Session Affinity: None
Events: <none>[root@k8s-master statefulset]# kubectl get pod -l app=nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-0 1/1 Running 0 8m50s 10.244.247.30 node-2 <none> <none>
web-1 1/1 Running 0 8m45s 10.244.84.158 node-1 <none> <none>
web-2 1/1 Running 0 8m41s 10.244.247.31 node-2 <none> <none>进入到共享目录data1里面创建一个文件
[root@k8s-master statefulset]# cd /data/vol/data1/
[root@k8s-master data1]# echo 123123 >> index.html
访问挂载data1这个目录做成卷的pod
[root@k8s-master test-pv]# curl 10.244.247.30
123123
使用 StatefulSet 管理的 Pod 具有的特点
1. 唯一序号分配:- StatefulSet 管理的 Pod 会被分配一个唯一的序号,格式为 `<statefulset名称>-<序号>`
(例如:`my-statefulset-0`, `my-statefulset-1`, `my-statefulset-2` 等)。
2. 关联 Service:- 创建 StatefulSet 资源时,需要预先创建一个 Service。- 如果创建的 Service 没有固定的 IP 地址,则可以通过 DNS 解析找到与其关联的 Pod 的
IP 地址。
3. 有序操作:- StatefulSet 管理的 Pod 具有明确的顺序,在执行部署、扩展、收缩、删除及更新操作时,这些
操作将按照指定的顺序依次执行。(扩容1..N,缩容N-1..1)- 新创建的 Pod 名称与被删除的 Pod 名称相同,以保持一致性。
4. 持久化存储:- StatefulSet 包含 `volumeClaimTemplate` 字段,这是一个卷声明模板,用于自动创建
PersistentVolume(PV)和 PersistentVolumeClaim(PVC)。- 自动创建的 PVC 会与 PV 绑定,确保每个 Pod 的数据目录是独立的。- 即使 Pod 被重新调度,也可以继续挂载原有的 PV,从而保证数据的完整性和一致性。
jenkins流水线发布项目到K8S集群实现CI/CD
大致流程
开发人员把做好的项目代码通过git推送到gitlab
然后Jenkins通过 gitlab webhook (前提是配置好),自动从拉取gitlab上面拉取代码下来。
(作用是实现本地 git push 后 jenkins 自动构建部署服务)
然后进行build,编译、生成镜像、然后把镜像推送到Harbor仓库;
然后在部署的时候通过k8s拉取Harbor上面的代码进行创建容器和服务,最终发布完成,然后可以用外网访问
第一阶段,获取代码(Git)
第二阶段,编译打包(Maven)
第三阶段,镜像打包与推送到仓库 (Harbor)
第四阶段,部署应用到k8s集群 (kubectl)
流程图
环境准备
192.168.116.138 master
192.168.116.130 node1
192.168.116.131 node2
192.168.116.141 harbor
192.168.116.142 jenkins ------>充当开发角色模拟提交代码到gitlab
git仓库我们这里使用gitee代替gitlab
测试代码:
https://github.com/bingyue/easy-springmvc-maven
配置jenkins服务器
1.安装git客户端与docker [root@jenkins-server ~]# yum install -y git [root@jenkins-server ~]# yum install -y yum-utils device-mapper-persistent-data lvm2 git [root@jenkins-server ~]# yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo [root@jenkins-server ~]# yum install -y docker 启动并设置开机启动 [root@jenkins-server ~]# systemctl start docker && systemctl enable docker 2.安装jenkins---略 3.jenkins额外安装插件 docker 和pipeline 插件
指定docker环境
由于jenkins最后要将生成的镜像上传到harbor仓库,需要在jenkins上面配置登陆harbor仓库
root@jenkins-server ~]# cat /etc/docker/daemon.json { "insecure-registries": ["192.168.116.141"] } [root@jenkins-server ~]# systemctl restart docker [root@jenkins-server ~]# docker login -u admin -p Harbor12345 192.168.116.141 #测试 Login Succeeded
登陆harbor创建相应项目的仓库
更新公司代码仓库
我这里用的是gitee的仓库,同步的github上一个开源的项目代码
在git服务器上面创建公钥和私钥,将公钥上传到gitee
[root@jenkins-server ~]# ssh-keygen [root@jenkins-server ~]# cd .ssh/ [root@jenkins-server .ssh]# ls id_rsa id_rsa.pub known_hosts [root@jenkins-server .ssh]# cat id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQAB。AAABAQC6rVm2pdguGz+Y72JRBk/lpbh3jfqriNWqv3QlP6iVP+tUTRZiGB5pcjCC8cHg6w64XPj4xRpQcj+Aviq7ORSuPGSk5hCMz9O7/wUMJsP4uVIvm5P/rwQBppdS3+qGE6COkhHdEY+GcjpLFVG2mW+ksQe3W2bvBKe7msNpqgUtQs+z99UXf9LlnGUCrRF/oddPSgq3tJDXZoYzdEb3a7bZDf3j72XOYubX0fcygS1fG615+xnJP9knfoKkr4YSZkxj25TwPEO5JToPtr4tcOpJRqBA7KrookicuiWeIe7J91mRVH1tx9GWnPMMyXqsy0LcyV2rUUhG4c71W0mEfLzn root@jenkins-server
将创建好的仓库克隆到本地
[root@jenkins-server ~]# git clone git@gitee.com:testpm/javaweb.git Cloning into 'javaweb'... warning: You appear to have cloned an empty repository. [root@jenkins-server ~]# ls javaweb 克隆测试代码,将测试代码上传到gitlab [root@jenkins-server ~]# git clone https://github.com/bingyue/easy-springmvc-maven [root@jenkins-server ~]# cd easy-springmvc-maven/ [root@jenkins-server easy-springmvc-maven]# ls pom.xml README.md src [root@jenkins-server easy-springmvc-maven]# cp -r * /root/javaweb/ [root@jenkins-server easy-springmvc-maven]# ls /root/javaweb/ pom.xml README.md src 将代码上传到公司的远程仓库 [root@jenkins-server easy-springmvc-maven]# cd /root/javaweb/ [root@jenkins-server javaweb]# git add . [root@jenkins-server javaweb]# git commit -m "1.0" [root@jenkins-server javaweb]# git push origin master
编写dockerfile用于生成镜像 [root@jenkins-server javaweb]# cat Dockerfile FROM daocloud.io/library/tomcat:8.0.45 RUN rm -rf /usr/local/tomcat/webapps/* ADD ./target/easy-springmvc-maven.war /usr/local/tomcat/webapps/ EXPOSE 8080 ENTRYPOINT ["/usr/local/tomcat/bin/catalina.sh","run"] 重新上传到远程仓库 [root@jenkins-server javaweb]# git add -A [root@jenkins-server javaweb]# git commit -m "v2.0" [root@jenkins-server javaweb]# git push origin master
配置jenkins流水线进行打包编译生成镜像并推送到公司的harbor仓库
基本配置略,开始编写pipeline脚本
root@jenkins-server ~]# cat /root/.ssh/id_rsa -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAuq1ZtqXYLhs/mO9iUQZP5aW4d436q4jVqr90JT+olT/rVE0W YhgeaXIwgvHB4OsOuFz4+MUaUHI/gL4quzkUrjxkpOYQjM/Tu/8FDCbD+LlSL5uT /68EAaaXUt/qhhOgjpIR3RGPhnI6SxVRtplvpLEHt1tm7wSnu5rDaaoFLULPs/fV F3/S5ZxlAq0Rf6HXT0oKt7SQ12aGM3RG92u22Q394+9lzmLm19H3MoEtXxutefsZ yT/ZJ36CpK+GEmZMY9uU8DxDuSU6D7a+LXDqSUagQOyq6KJInLolniHuyfdZkVR9 bcfRlpzzDMl6rMtC3Mldq1FIRuHO9VtJhHy85wIDAQABAoIBAHKhDezVK8ksHEJa BKJCYP9gYsSvH1UDwkiGJdjVnTyAso3ihDMaIlqXruhJccceL7zQAmYoCj+J2CrD G1Q5+dP/68FCMLl2yMqxDzVl/IKXsbrgKuIfYzNsS5GtQ8Ku/LFvSp7YMKzbKaZ/ YdzhnSehOV7DNpLg5eqSXxpcN6+RQAhnpjNDqRAFNsUhJ5jpSx1gUDEVAGM+4K6l Vt6tK+8LuPw31dKkh6I+PYOQAlLfRBI5uk9szXM+cRY0/45rJfUX6K8PFFn4l8go hz2lVxZAJYEkyYVGslAHBuFFcR9pU/29YfZEqGSFUksypbtac4MnXzo4K30pbJuS vq0S4akCgYEA8+2AOrafZ7vbmD4fTb413sXyOTq/lfH4Y/V54tUrGNUIzpYSzV4O u+6GpwhSDxspupoMuvDj3J1Zr24dq1kNfm1cVWfwY2eQE/VoZSCCB33abfqxKR7x SX5KNNPoxUIF+w2biWW6aGY2JJFyeNt/BifY8zq4wrbZ3/JneHIzDnMCgYEAw+p/ +8PUEbLz/BMzHfptMsu/GqDieM4QMjMMlNLRYpSG58PFQwJVFPdQv04l2BZziUeL 0SUe/p6XBaEO642yeMhlrUw75nhEMH+w/Ab+ivwuUi/6g+Fd8gDn2+w8Q5nNe3Ow gdwuN/N3zidwufwylsk9K2HfgouUHsqr171CJr0CgYAzisPFpEEakj9cdAP5UW/g msMMBLXm4TIzLPOMUq7AmIM748olSvKiE0ywjrmIJ50xqMt31N7RBw6kWwg55J9N T55rDYNl/cQb84cTl0Ligl1dT9OPdNJXTTAw6XYN+F17Juzuo2g4FyDpqTIfB4JX sqPNAWN5AVoYUAg9EyRmsQKBgQC/TzICq0terRzLPgRgdbZEL+lBG3GK/c2a93aF rQeB9/90OhtaP+DNRGO5K5qQ0/umRhMl+9W0VTCr8oYbRpbMkwOWoiar+yy7HzW4 JSxSk8a3wtoiBeQy+OdwPdLrQDkDIAlwBY2sXTbUPHc7ZiYQUBpHTp9vXtUY7Fe5 p7n9EQKBgQCgf6HN6JQmTSAjcPd0HFmzpe54PO+5XGjGnUSxqo4ZeOVklRi+b+vn QeeVyItMi2oyt5cNnxL/oSKqXgumKXOAL37x0eLJHLIWX3iHISvS0rIpSkvWEDrD iPj7001u4uBDz1/ivlTpfdpmx5otyTJloP4JRIOUAZsY4WxsORtIOg== -----END RSA PRIVATE KEY-----
复制脚本内容返回上一级页面添加到脚本中
最后完整脚本内容:
pipeline {agent any stages {stage('pull code') {steps {checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'da64354c-fffc-4fbf-9865-bf9c74e25b95', url: 'git@gitee.com:testpm/javaweb.git']]])}}stage('build code') {steps {sh 'cd /root/.jenkins/workspace/test-web1'sh 'mvn clean package'}}stage('build image'){steps {sh 'docker build -t javaweb:v2.0 .'}}stage('push image to harbor') {steps {sh 'docker login -u admin -p Harbor12345 192.168.116.141'sh 'docker tag javaweb:v2.0 192.168.116.141/javapm/javaweb:v2.0'sh 'docker push 192.168.116.141/javapm/javaweb:v2.0 && docker rmi 192.168.116.141/javapm/javaweb:v2.0'}}} }
登陆harbor仓库查看镜像是否上传成功
发布项目到k8s集群,编写deployment进行发布
1.k8s集群配置登陆harbor仓库的secret 2.开始编写yaml文件 [root@master ~]# cd yaml/ [root@master yaml]# cat java-dep.yaml apiVersion: apps/v1 kind: Deployment metadata:name: tomcat-dep spec:selector:matchLabels:app: webreplicas: 2template:metadata:labels:app: webspec:volumes:- name: log-volhostPath:path: /var/javaweb/logcontainers:- name: tomcatimage: 192.168.116.141/javapm/javaweb:v2.0ports:- containerPort: 8080volumeMounts:- mountPath: "/usr/local/tomcat/logs"name: log-volimagePullSecrets:- name: harbor-login创建deployment [root@master yaml]# kubectl apply -f java-dep.yaml deployment.apps/tomcat-dep created [root@master yaml]# kubectl get pod NAME READY STATUS RESTARTS AGE nginx-web 1/1 Running 1 (6h14m ago) 14h tomcat-dep-757df55fb5-2brjh 1/1 Running 0 40s tomcat-dep-757df55fb5-5ppfw 1/1 Running 0 40s
配置Ingress实现访问
下载ingress配置文件: 如果下载不下来记得添加解析 [root@master ~]# cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.116.138 master 192.168.116.130 node1 192.168.116.131 node2 199.232.28.133 raw.githubusercontent.com #解析github的地址 [root@master ~]# cd /mnt/ [root@master mnt]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.0/deploy/static/provider/cloud/deploy.yaml [root@master mnt]# cd [root@master ~]# vim deploy.yaml #修改配置文件,并替换成阿里云的镜像 找到已下apiserver的版本: --- apiVersion: apps/v1 kind: DaemonSet #将原来的Deployment修改为DaemonSet metadata:labels:app.kubernetes.io/component: controllerapp.kubernetes.io/instance: ingress-nginxapp.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginxapp.kubernetes.io/version: 1.3.0name: ingress-nginx-controllernamespace: ingress-nginx spec:minReadySeconds: 0revisionHistoryLimit: 10selector:matchLabels:app.kubernetes.io/component: controllerapp.kubernetes.io/instance: ingress-nginxapp.kubernetes.io/name: ingress-nginxtemplate:metadata:labels:app.kubernetes.io/component: controllerapp.kubernetes.io/instance: ingress-nginxapp.kubernetes.io/name: ingress-nginxspec:hostNetwork: true #添加共享到主机网络containers:- args:- /nginx-ingress-controller- --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller- --election-id=ingress-controller-leader- --controller-class=k8s.io/ingress-nginx- --ingress-class=nginx- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller- --validating-webhook=:8443- --validating-webhook-certificate=/usr/local/certificates/cert- --validating-webhook-key=/usr/local/certificates/keyenv:- name: POD_NAMEvalueFrom:fieldRef:fieldPath: metadata.name- name: POD_NAMESPACEvalueFrom:fieldRef:fieldPath: metadata.namespace- name: LD_PRELOADvalue: /usr/local/lib/libmimalloc.soimage: registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.3.0@sha256:d1707ca76d3b044ab8a28277a2466a02100ee9f58a86af1535a3edf9323ea1b5 #将原来的镜像替换成阿里云仓库的镜像imagePullPolicy: IfNotPresentlifecycle:preStop:exec:command:- /wait-shutdownlivenessProbe:failureThreshold: 5httpGet:path: /healthzport: 10254scheme: HTTPinitialDelaySeconds: 10periodSeconds: 10successThreshold: 1timeoutSeconds: 1name: controllerports:- containerPort: 80name: httpprotocol: TCP- containerPort: 443name: httpsprotocol: TCP- containerPort: 8443name: webhookprotocol: TCPreadinessProbe:failureThreshold: 3httpGet:path: /healthzport: 10254scheme: HTTPinitialDelaySeconds: 10periodSeconds: 10successThreshold: 1timeoutSeconds: 1resources:requests:cpu: 100mmemory: 90MisecurityContext:allowPrivilegeEscalation: truecapabilities:add:- NET_BIND_SERVICEdrop:- ALLrunAsUser: 101volumeMounts:- mountPath: /usr/local/certificates/name: webhook-certreadOnly: truednsPolicy: ClusterFirstnodeSelector:custom/ingress-controller-ready: "true" #指定运行ingress的node标签serviceAccountName: ingress-nginxterminationGracePeriodSeconds: 300volumes:- name: webhook-certsecret:secretName: ingress-nginx-admission --- #注意:一共有两个镜像需要替换成阿里云仓库的镜像: [root@master ~]# cat deploy.yaml | grep imageimage: registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.3.0@sha256:d1707ca76d3b044ab8a28277a2466a02100ee9f58a86af1535a3edf9323ea1b5imagePullPolicy: IfNotPresentimage: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660imagePullPolicy: IfNotPresentimage: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660imagePullPolicy: IfNotPresent
给两个node节点设置lable
[root@master ~]# kubectl label nodes node1 custom/ingress-controller-ready=true node/node1 labeled [root@master ~]# kubectl label nodes node2 custom/ingress-controller-ready=true node/node2 labeled 同时在两个node节点下载镜像 [root@node1 ~]# docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.3.0 [root@node1 ~]# docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.1
创建ingress-controller
[root@master ~]# kubectl apply -f deploy.yaml 查看ingress-controller资源 [root@master ~]# kubectl get pods -n ingress-nginx NAME READY STATUS RESTARTS AGE nginx-ingress-controller-s8vnl 1/1 Running 0 98m nginx-ingress-controller-ztxz4 1/1 Running 0 97m
测试ingress
创建service
[root@master ~]# cd yaml/ [root@master yaml]# vim java-service.yaml apiVersion: v1 kind: Service metadata:name: my-tomcatlabels:run: my-tomcat spec:ports:- port: 80targetPort: 8080selector:app: web创建service root@master yaml]# kubectl apply -f java-service.yaml service/my-tomcat created 查看资源 [root@master yaml]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-web 1/1 Running 1 (7h10m ago) 15h tomcat-dep-757df55fb5-2brjh 1/1 Running 0 57m tomcat-dep-757df55fb5-5ppfw 1/1 Running 0 57m [root@master yaml]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 26h my-tomcat ClusterIP 10.109.127.156 <none> 80/TCP 29s
配置ingress转发文件
[root@master ~]# cat ingress-test.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata:name: test-ingressnamespace: defaultannotations:nginx.ingress.kubernetes.io/rewrite-target: /easy-springmvc-maven/ spec:ingressClassName: nginx #指定ingress的类型rules: #定义转发规则- host: test.tomcat.ingress #指定域名方式http:paths:- path: /easy-springmvc-maven/ #指定访问的路径pathType: Prefix #定义路径的类型backend: #定义转发后端的服务service: #定义转发的servicename: my-tomcatport:number: 80[root@master yaml]# kubectl apply -f ingress-test.yaml ingress.networking.k8s.io/test-ingress created [root@master yaml]# kubectl get ingress NAME CLASS HOSTS ADDRESS PORTS AGE test-ingress <none> test.tomcat.ingress 80 20s
nginx-ingress-controller运行在node1,node2两个节点上。
如果网络中有dns服务器,在dns中把这两个域名映射到nginx-ingress-controller运行的任意一个节点上,如果没有dns服务器只能修改host文件了。
任意一个节点上操作:(客户端解析)
我这里有两个节点部署了控制器,ip分别为172.16.229.5,172.16.229.6 ,如果有多个,可以随便选。(但是由于tomcat都在node2上面,所以就只解析一台)
在wind电脑设置本地解析
192.168.116.131 test.tomcat.ingress
测试访问