kubernetes(三)

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-0my-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-0web-1web-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 支持两种更新策略:RollingUpdateOnDelete

  • 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

测试访问

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/454446.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring MVC文件请求处理-MultipartResolver

Spring Boot中的MultipartResolver是一个用于解析multipart/form-data类型请求的策略接口&#xff0c;通常用于文件上传。 对应后端使用MultipartFile对象接收。 RequestMapping("/upload")public String uploadFile(MultipartFile file) throws IOException {Strin…

十一、数据库配置

一、Navicat配置 这个软件需要破解 密码是&#xff1a;123456&#xff1b; 新建连接》新建数据库 创建一个表 保存出现名字设置 双击打开 把id设置为自动递增 这里就相当于每一次向数据库添加一个语句&#xff0c;会自动增长id一次 二、数据库的增删改查 1、Vs 建一个控…

磁编码器的工作原理和特点

目录 概述 1 磁编码器的构造 1.1 霍尔元件 1.2 永磁体 1.3 永磁体和霍尔元件的配置 2 磁编码器的工作原理 2.1 原理介绍 2.2 电气信号转换成角度 2.3 旋转角度传感器IC 3 磁编码器的特点和主要应用 概述 本文主要介绍磁编码器的构造原理&#xff0c;工作特性和应用特…

C/C++函数调用约定:__cdecl、__stdcall、__fastcall和__thiscall

目录 1.引言 2.常见函数调用约定 2.1.__cdecl 2.2.__stdcall 2.3.__fastcall 2.4.__thiscall 3.几种调用约定比较 4.注意事项 1.引言 在C和C编程中&#xff0c;函数调用约定&#xff08;Calling Convention&#xff09;定义了函数如何接收参数、如何返回值以及由谁来清…

【小沐学Golang】基于Go语言搭建静态文件服务器

文章目录 1、简介2、安装2.1 安装版2.2 压缩版 3、基本操作3.1 go run3.2 go build3.3 go install3.4 go env3.5 go module 4、文件服务器4.1 filebrowser4.2 gohttpserver4.3 goFile 5、FAQ5.1 go.mod 为空5.2 超时 结语 1、简介 https://golang.google.cn/ Go语言诞生于2007…

word表格跨页后自动生成的顶部横线【去除方法】

Hello World! Its been a long time. 这一年重心放在了科研、做事、追寻新的经历上&#xff0c;事有正事、琐事、幸事、哀事&#xff0c;内心与认知成长了一些&#xff0c;思想成熟了几分&#xff0c;技艺也有若干收获。不管怎样&#xff0c;来打个卡吧&#xff0c;纪念一下&…

Web前端高级工程师培训:使用 Node.js 构建一个 Web 服务端程序(3)

11、HTTP 协议 11-1、协议的定义 HTTP 是一种能够获取如 HTML 这样的网络资源的 protocol(通讯协议)。它是在 Web 上进行数据交换的基础&#xff0c;是一种 client-server 协议&#xff0c;也就是说&#xff0c;请求通常是由像浏览器这样的接受方发起的。一个完整的Web文档通…

Tailwind Starter Kit 一款极简的前端快速启动模板

Tailwind Starter Kit 是基于TailwindCSS实现的一款开源的、使用简单的极简模板扩展。会用Tailwincss就可以快速入手使用。Tailwind Starter Kit 是免费开源的。它不会在原始的TailwindCSS框架中更改或添加任何CSS。它具有多个HTML元素&#xff0c;并附带了ReactJS、Vue和Angul…

Docker安装Mysql5.7,解决无法访问DockerHub问题

Docker安装Mysql5.7&#xff0c;解决无法访问DockerHub问题 简介 Docker Hub 无法访问&#xff0c;应用安装失败&#xff0c;镜像拉取超时的解决方案。 摘要 &#xff1a; 当 Docker Hub 无法访问时&#xff0c;可以通过配置国内镜像加速来解决应用安装失败和镜像拉取超时的…

使用爬虫爬取Python中文开发者社区基础教程的数据

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

微信小程序文本收起展开

这里写自定义目录标题 微信小程序文本收起展开常见问题的梯形背景框 微信小程序文本收起展开 参考 https://juejin.cn/post/6963904955262435336 <!-- 常见问题解答 --><view classcontentBottom><view classBottomFirst><text id0 data-id0 class&quo…

python + mitmproxy 爬手机app (1)

起因&#xff0c; 目的: 想爬手机上某鱼。 mitmproxy 简介: 一句话: mitmproxy 就是中间人攻击. (只不过&#xff0c; 你安装&#xff0c;就代表你愿意承担风险。)源码&#xff1a;https://github.com/mitmproxy/mitmproxy文档: https://mitmproxy.org/ 安装过程: 见聊天记…

eCAP超声波测距-ePWM电机调速

目录 eCAP超声波测距 整体框架 关键模块 实验效果 PWM电机调速 DRV8833基本介绍 整体框架 eCAP超声波测距 本实验所用的超声波HC-SR04模块如下图所示&#xff0c;左边为正面图&#xff0c;右边为反面图。 HC-SR04基本工作原理&#xff1a; &#xff08;1&#xff09;采…

spring源码中的,函数式接口,注解@FunctionalInterface

调用方 /org/springframework/beans/factory/support/AbstractBeanFactory.java:333sharedInstance getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It mi…

Kafka之消费者客户端

1、历史上的二个版本 与生产者客户端一样&#xff0c;在Kafka的发展过程当中&#xff0c;消费者客户端主要有两个大的版本&#xff1a; 旧消费者客户端&#xff08;Old Consumer&#xff09;&#xff1a;基于Scala语言开发的版本&#xff0c;又称为Scala消费者客户端。新消费…

rpm 命令

rpm&#xff08;Red Hat Package Manager&#xff09;是 Red Hat Linux 及其衍生发行版&#xff08;如 CentOS、Fedora&#xff09;中用于管理软件包的系统。它允许用户安装、卸载、升级、查询和验证软件包。 一、安装软件包 &#xff08;1&#xff09;安装一个 RPM 软件包&a…

高并发下如何保证接口的幂等性?

前言 接口幂等性问题,对于开发人员来说,是一个跟语言无关的公共问题。本文分享了一些解决这类问题非常实用的办法,绝大部分内容我在项目中实践过的,给有需要的小伙伴一个参考。 不知道你有没有遇到过这些场景: 有时我们在填写某些form表单时,保存按钮不小心快速点了两次…

十二、【智能体】深入剖析:大模型节点的全面解读,举例说明,教你如何在扣子中嵌入代码

大模型节点 大模型节点主要分为5部分&#xff1a; 处理类型 单次批处理 模型类型&#xff1a;目前可以选择的模型有 豆包、通义千问、智谱、MinMax和Kimi输入:此时的参数可以被下面的提示词所用提示词&#xff1a;给大模型使用的提示词输出&#xff1a;经过此大模型处理后的输…

Vehicle Spy3.9如何新建工程—总览

1&#xff1a;写作目的 学习和精通SPY的使用&#xff0c;对于spy&#xff0c;目前主要是通用系用的比较多&#xff0c;本身spy的生产厂家英特佩斯也是美国的公司&#xff0c;除了软件自带教程。中文网上很少能找到相关的中文教程。 故写下这篇文章&#xff0c;帮助自己和大家…

Ubuntu(22.04)本地部署Appsmith

Ubuntu&#xff08;22.04&#xff09;安装Appsmith 简要介绍 Appsmith 是一个开源的低代码开发平台&#xff0c;旨在帮助开发者和非开发者快速构建定制化的内部应用程序和管理工具。通过直观的拖拽界面和丰富的预配置组件&#xff0c;Appsmith 让用户无需编写大量代码即可创建…