一、ingress
1.概述
ingress相当于一个7层负载均衡器。是K8S反向代理的抽象,工作原理类似于Nginx,可以理解成ingress里简历诸多映射规则,Ingress Controller通过监听则这些配置并转化成Nginx的反向代理配置,然后对外部提供服务
ingress:K8S中的一个对象,作用定义请求如何转发带service的规则
ingress controller:具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,通过配置尽心请求转发。实现方式有很多Nginx、Contour、Haproxy等
Ingress(以 Nginx 为例)的工作原理如下:
1.用户编写 Ingress 规则,说明哪个域名对应 kubernetes 集群中的哪个 Service
2.Ingress 控制器动态感知 Ingress 服务规则的变化,然后生成一段对应的 Nginx 反向代理配置
3.Ingress 控制器会将生成的 Nginx 配置写入到一个运行着的 Nginx 服务中,并动态更新
4.到此为止,其实真正在工作的就是一个 Nginx 了,内部配置了用户定义的请求转发规则

2.使用
1)环境准备 搭建ingress环境
bash
# 创建文件夹
mkdir ingress-controller
cd ingress-controller
# 获取ingress-nginx,使用的是0.30版本
wget https://gitcode.com/mirrors/ingress-nginx/raw/nginx-0.30.0/deploy/static/mandatory.yaml
wget https://gitcode.com/mirrors/ingress-nginx/raw/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml
# 创建ingress-nginx
kubectl apply -f ./
# 查看ingress-nginx
kubectl get pod -n ingress-nginx
# 查看serive
kubectl get svc -n ingress-nginx
2)创建两个不同控制器显示效果
创建两个deployment分别为tomcat、nginx两个不同的页面来显示ingress-nginx效果
bash
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: dev
spec:
replicas: 3
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deployment
namespace: dev
spec:
replicas: 3
selector:
matchLabels:
app: tomcat-pod
template:
metadata:
labels:
app: tomcat-pod
spec:
containers:
- name: tomcat
image: tomcat:8.5-jre10-slim
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: dev
spec:
selector:
app: nginx-pod
clusterIP: None
type: ClusterIP
ports:
- port: 80
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: tomcat-service
namespace: dev
spec:
selector:
app: tomcat-pod
clusterIP: None
type: ClusterIP
ports:
- port: 8080
targetPort: 8080
3)创建ingress-http.yaml
内部的nginx负载均衡策略
bash
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-http
namespace: dev
spec:
rules:
- host: nginx.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: nginx-service
port:
number: 80
- host: tomcat.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: tomcat-service
port:
number: 8080
其中pathType中三种路径的区别
(1)ImplementationSpecific
匹配规则:路径作为前缀匹配,支持$精准锁定结尾
bash
path: /api
pathType: ImplementationSpecific
# 匹配:/api、/api/、/api/user、/api/list/123
# 不匹配:/apis、/a
bash
path: /api$
pathType: ImplementationSpecific
# 仅匹配/api
# /api/、/api/user 都不匹配
(2)Prefix
匹配规则:路径是 URL 的前缀,自动区分路径分段,不会跨单词匹配
bash
path: /api
pathType: Prefix
# 匹配成功:/api、/api/、/api/user、/api/list
# 不匹配:/apis、/ap、/aapi
(3)Exact
匹配规则:URL 必须和 path 字符串一字不差完全相等,多一个斜杠、少一个字符都不行。
bash
path: /api
pathType: Exact
# 仅匹配/api
(4)https代理
创建证书
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/C=CN/ST=BJ/L=BJ/O=nginx/CN=xiaobai.com"
内部的nginx负载均衡策略https代理
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-https
namespace: dev
spec:
tls:
- hosts:
- www.nginx.com
- www.tomcat.com
secretName: tls-secret # 指定秘钥
rules:
- host: www.nginx.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: nginx-service
port:
number: 80
- host: www.tomcat.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: tomcat-service
port:
number: 8080
二、数据存储
Volume是pod中能被多个容器访问的共享目录,被定义在pod上,然后被一个pod多个容器挂载到具体的文件目录下,K8S通过Volume实现同一个Pod中不同容器的数据存储与持久化存储且与Pod的生命周期无关,容器重启和终止数据不会丢失
1.K8S中的Vloume支持多种类型,常见的有一下几个:
简单存储:EmptyDir、HostPath、NFS
高级存储:PV、PVC
配置存储:ConfigMap、Secret
1.基本存储
1)EmptyDir
EmptyDir是最基础的数据类型,一个Empty就是Host上的一个空目录
Emptyis是Pod被分配到Node时创建的,初始内容为空,且无需指定宿主机的目录文件,K8S会自动分配一个目录,当Pod销毁时,Empty数据会被永久删除。用途:
1.临时空间,例如用于某些应用程序所需的临时目录,无须永久保留
2.一个容器需要从另一个容器中获取数据的目录
示例:一个pod中准备两个容器,声明一个Volume分别挂在两个容器的目录中,然后nginx容器负责向Volume中写日志,busybox中通过命令将日志内容读取到控制台

创建volume-emptydir.yaml
bash
apiVersion: v1
kind: Pod
metadata:
name: volume-emptydir
namespace: nginx-ns
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: logs-volume
mountPath: /var/log/nginx
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","tail -f /log/access.log"]
volumeMounts:
- name: logs-volume
mountPath: /logs
volumes:
- name: logs-volume
emptyDir: {}
测试创建pod
bash
# 创建Pod
kubectl create -f volume-emptydir.yaml
# 查看pod
kubectl get pods volume-emptydir -n nginx-ns -o wide
# 访问pod产生日志
curl 10.244.1.62
# 通过kubectl logs命令查看容器的标准输出
kubectl logs -f volume-emptydir -n nginx -c busybox
此时每访问一次就会产生一行日志

且当容器重新创建之后不会持续保存

2)HostPath
若想简单的实现数据的持久化存储可以选择HostPath。 HostPath就是将node主机中一个实际目录挂到pod中,以供容器使用,这样设计就可以保证Pod销毁了,但是数据依旧可以存在于Node主机上
常见volume-hostpath.yaml
bash
apiVersion: v1
kind: Pod
metadata:
name: volume-hostpath
namespace: nginx-ns
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: logs-volume
mountPath: /var/log/nginx
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","tail -f /logs/access.log"]
volumeMounts:
- name: logs-volume
mountPath: /logs
volumes:
- name: logs-volume
hostPath:
path: /root/logs
type: DirectoryOrCreate
此时当容器创建后会在他创建Pod的节点上创建一个目录/root/logs来挂载到容器中,此时就算是节点重新创建也是不会消失的
此时删除pod后重启不会文件不会消失

3)NFS
Hostpath可以解决数据持久化的问题,但是一旦Node节点故障了,Pod如果转移到了别的节点,又会出现问题了,此时需要准备单独的网络存储系统,比较常用的用NFS、CIFS。
NFS是一个网络文件存储系统,可以搭建一台NFS服务器,然后将Pod中的存储直接连接到NFS系统上,这样的话,无论Pod在节点上怎么转移,只要Node跟NFS的对接没问题,数据就可以成功访问。

1)准备一台nfs服务器,直接使用master节点做nfs服务器
bash
# 在服务器上安装nfs服务
yum install nfs-utils -y
# 准备一个共享目录
mkdir /root/data/nfs -pv
# 将共享目录的读写权限给192.168.22.0/24网段中的所有主机
vim /etc/exports
more /etc/exports
/root/data/nfs 192.168.22.0(rw,no_root_squash)
# 启动nfs服务器
systemctl restart nfs
2)接下来在每个node节点上都安装nfs,这样的目的就是为了node节点可以驱动nfs设备
bash
# 在node上安装nfs服务,但是不用启动
yum install nfs-untils -y
3)接下来,就可以编写volume-nfs.yaml
bash
apiVersion: v1
kind: Pod
metadata:
name: volume-nfs
namespace: nginx-ns
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: logs-volume
mountPath: /var/log/nginx
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","tail -f /logs/access.log"]
volumeMounts:
- name: logs-volume
mountPath: /logs
volumes:
- name: logs-volume
hostPath:
path: /root/logs
type: DirectoryOrCreate
创建pod节点此时随机调度到node2节点上了

此时里面有这几条日志目录

删除pod节点重新创建,将其创建到node1节点上访问日志

此时就实现了不同节点上的持久化存储
2.高级存储
前面已经使用NFS提供了存储但是就要要求用户会搭建NFS系统,并且会在yaml中配置nfs。但是K8S中支持的存储系统有很多,要求全部掌握不显示。为屏蔽底层存储实现细节方便使用,于是就有了PV和PVC两种资源对象

使用PV和PVC后可以进一步细分
存储:存储工程师维护
PV:K8S管理员维护
PVC:K8S用户维护
1)PV
PV是存储资源的抽象,下面是资源清单文件
bash
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv2
spec:
nfs: # 存储类型,与底层真正存储对应
capacity: # 存储能力,目前只支持存储空间的设置
storage: 2Gi
accessModes: # 访问模式
storageClassName: # 存储类别
persistentVolumeReclaimPolicy: # 回收策略
PVC 的关键配置参数说明:
访问模式(accessModes): 用于描述用户应用对存储资源的访问权限
选择条件(selector): 通过Label selector的设置,可使PVC对于系统中已存在的PV进行筛选
存储类别(storageClassName): PVC在定义时可以设定需要的后端存储的类别,只有设置了该class的pv才能被系统选出
资源请求(Resources): 描述对存储资源的请求
- 存储类型:底层实际存储的类型,kubernetes 支持多种存储类型,每种存储类型的配置都有所差异
- 存储能力(capacity):目前只支持存储空间的设置 (storage=1Gi),不过未来可能会加入 IOPS、吞吐量等指标的配置
- 访问模式(accessModes):用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:
- ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
- ReadOnlyMany(ROX):只读权限,可以被多个节点挂载
- ReadWriteMany(RWX):读写权限,可以被多个节点挂载
- 回收策略(persistentVolumeReclaimPolicy): 当 PV 不再被使用了之后,对其的处理方式。目前支持三种策略:
- Retain(保留)保留数据,需要管理员手工清理数据
- Recycle(回收)清除 PV 中的数据,效果相当于执行 rm -rf /thevolume/*
- Delete(删除)与 PV 相连的后端存储完成 volume 的删除操作,当然这常见于云服务商的存储服务
- 存储类别:PV 可以通过 storageClassName 参数指定一个存储类别
- 具有特定类别的 PV 只能与请求了该类别的 PVC 进行绑定
- 未设定类别的 PV 则只能与不请求任何类别的 PVC 进行绑定
- 状态(status):一个 PV 的生命周期中,可能会处于 4 中不同的阶段
- Available(可用):表示可用状态,还未被任何 PVC 绑定
- Bound(已绑定):表示 PV 已经被 PVC 绑定
- Released(已释放):表示 PVC 被删除,但是资源还未被集群重新声明
- Failed(失败):表示该 PV 的自动回收失败
实验:
使用NFS作为存储,来演示PV的使用,创建3个PV,对应NFS中的三个暴露的路径
准备NFS环境
bash
# 创建目录
mkdir /root/data/{pv1,pv2,pv3} -pv
# 暴露服务
more /etc/exports
/root/data/pv1 192.168.22.0/24(rw,no_root_spuash)
/root/data/pv2 192.168.22.0/24(rw,no_root_spuash)
/root/data/pv3 192.168.22.0/24(rw,no_root_spuash)
# 重启服务
systemctl restart nfs
创建pv.yaml
bash
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv1
spec:
capacity:
storage: 1Gi
accessModes:
- ReadwriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: /root/data/pv1
server: 192.168.22.156
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv2
spec:
capacity:
storage: 2Gi
accessModes:
- ReadwriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: /root/data/pv2
server: 192.168.22.156
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv3
spec:
capacity:
storage: 3Gi
accessModes:
- ReadwriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: /root/data/pv3
server: 192.168.22.156
创建pv

2)PVC
bash
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc
namespace: dev
spec:
accessModes: # 访问模式
selector: # 采用标签对PV选择
storageClassName: # 存储类别
resources: # 请求空间
requests:
storage: 5Gi
PVC 的关键配置参数说明:
访问模式(accessModes):用于描述用户应用对存储资源的访问权限
选择条件(selector):通过 Label Selector 的设置,可使 PVC 对于系统中已存在的 PV 进行筛选
存储类别(storageClassName):PVC 在定义时可以设定需要的后端存储的类别,只有设置了该 class 的 pv 才能被系统选出
资源请求(Resources ):描述对存储资源的请求
创建pvc.yaml申请pv
bash
apiVersion: v1
kind: PersistentVolumeClain
metadata:
name: pvc1
namespace: nginx-ns
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClain
metadata:
name: pvc2
namespace: nginx-ns
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClain
metadata:
name: pvc2
namespace: nginx-ns
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
创建pvc

此时STATUS被状态就是Bound绑定状态一般来说申请pv的时候分配是按照申请的大小分配的但是这里都是1Gi因此分配的时候就按照顺序了
3)创建pod使用pvc
创建pods.yaml,使用pv
bash
apiVersion: v1
kind: Pod
metadata:
name: pod1
namespace: nginx-ns
spec:
containers:
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","while true;do echo pod1 >> /root/out.txt; sleep 10;done;"]
volumeMounts:
- name: volume
mountPath: /root/
volumes:
- name: volume
persistentVolumeClaim:
claimName: pvc1
readOnly: false
---
apiVersion: v1
kind: Pod
metadata:
name: pod2
namespace: nginx-ns
spec:
containers:
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","while true;do echo pod2 >> /root/out.txt; sleep 10;done;"]
volumeMounts:
- name: volume
mountPath: /root/
volumes:
- name: volume
persistentVolumeClaim:
claimName: pvc2
readOnly: false
创建好之后pv、pvc、还有pod的情况

创建好之后访问到pv下分别查看pv1 pv2下的内容

此时两个节点下的写入的内容就对应上面的配置文件
4)生命周期
PVC和PV是一一对应的,PV和PVC中间相互尊重下面的生命周期
**资源供应:**用户先手动创建底层存储和PV
**资源绑定:**用户创建PVC,K8S根据PVC的声明去寻找PV并绑定
用户定义好PVC后会根据PVC对资源的请求找存在且满足条件的PV进行绑定就能使用 这个PVC了若没找到就是无线Pending的状态,直到管理员创建一个符合要求的PV
**资源使用:**用户可在 pod 中像 volume 一样使用 pvc,Pod 使用 Volume 的定义,将 PVC 挂载到容器内的某个路径进行使用
**资源释放:**用户删除 pvc 来释放 pv
当存储资源使用完毕后,用户可以删除 PVC,与该 PVC 绑定的 PV 将会被标记为 "已释放",但还不能立刻与其他 PVC 进行绑定。通过之前 PVC 写入的数据可能还被留 在存储设备上,只有在清除之后该 PV 才能再次使用
**资源回收:**kubernetes 根据 pv 设置的回收策略进行资源的回收
对于 PV,管理员可以设定回收策略,用于设置与之绑定的 PVC 释放资源之后如何处 理遗留数据的问题。只有 PV 的存储空间完成回收,才能供新的 PVC 绑定和使用
3.配置存储
1)ConfigMap
ConfigMap是一种比较特殊的存储卷,它的主要作用是用来存储配置信息的。
创建configmap.yaml
bash
apiVersion: v1
kind: ConfigMap
metadata:
name: configmap
namespace: nginx-ns
data:
info: |
username:admin
password:123456
使用配置文件创建configmap
bash
# 创建configmap
kubectl apply -f configmap.yaml
# 查看configmap详情
kubectl describe cm configmap -n nginx-ns
运行情况

创建pod-configmap.yaml,将上面的configmap文件挂载进去
bash
apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: nginx-ns
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: config
mountPath: /var/share/nginx
volumes:
- name: config
configMap:
name: configmap
进入容器查看配置文件挂载情况

2)secret
在K8S中,存在一中ConfigMap相似的对象,称为Secret对象,通常用于存储敏感信息,例如密码、密钥、证书等等
首先使用base64对数据编码(这只是编码不是加密)
bash
echo -n "admin" | base 64
YWRtaW4=
echo -n "123456" | base64
MTIzNDU2
编写secret.yaml,并创建Secret
bash
apiVersion: v1
kind: Secret
metadata:
name: secret
namespace: nginx-ns
type: Opaque
data:
username: YWRtaW4=
password: MTIzNDU2
创建pod-secret.yaml将上面创建的secret挂载进去

创建pod挂载使用
bash
apiVersion: v1
kind: Pod
metadata:
name: pod-secret
namespace: nginx-ns
spec:
containers:
- name: nginx
image: nginx:latest
volumeMounts:
- name: config
mountPath: /var/share/nginx
volumes:
- name: config
secret:
secretName: secret
进入容器内查看
直接就是明文
