第一章:Kubernetes 网络
1.1 概述
Kubernetes 网络解决四个方面的问题:
- ① 一个 Pod 中容器之间通过
本地回路(loopback)
通信。 - ② 集群网络在不同 Pod 之间提供通信;换言之,Pod 和 Pod 之间能互相通信(通过 calico 网络插件实现 Pod 之间网络的扁平化;当然,Node 节点之间的通信也是通过 calico 网络插件)。
- ③ Service 资源允许我们对外暴露 Pod 中运行的应用程序,以支持来自集群之外的访问;换言之,Service 和 Pod 之间能互相通信。
- ④ 可以使用 Service 来发布仅供集群内部使用的服务。
- ① 一个 Pod 中容器之间通过
1.2 Kubernetes 网络架构图
1.2.1 架构图
1.2.2 访问流程
第二章:Service
2.1 概述
- 在 Kubernetes 中,Pod 是应用程序的载体,我们可以通过 Pod 的 IP 来访问应用程序,但是 Pod 的 IP 地址不是固定的,这就意味着不方便直接采用 Pod 的 IP 对服务进行访问。
- 为了解决这个问题,Kubernetes 提供了 Service 资源,Service 会对提供同一个服务的多个 Pod 进行聚合,并且提供一个统一的入口地址,通过访问 Service 的入口地址就能访问到后面的 Pod 服务。
- Service 在很多情况下只是一个概念,真正起作用的其实是 kube-proxy 服务进程,每个 Node 节点上都运行了一个 kube-proxy 的服务进程。当创建 Service 的时候会通过 API Server 向 etcd 写入创建的 Service 的信息,而 kube-proxy 会基于监听的机制发现这种 Service 的变化,然后它会将最新的 Service 信息转换为对应的访问规则(其实,就是 EndPoint,后面讲)。
- Service 的资源清单:
apiVersion: v1 # 版本
kind: Service # 类型
metadata: # 元数据
name: # 资源名称
namespace: # 命名空间
spec:
selector: # 标签选择器,用于确定当前Service代理那些Pod
app: nginx
type: NodePort # Service的类型,指定Service的访问方式
clusterIP: # 虚拟服务的IP地址
sessionAffinity: # session亲和性,支持ClientIP、None两个选项,默认值为None
ports: # 端口信息
- port: 8080 # Service端口
protocol: TCP # 协议
targetPort : # Pod端口
nodePort: # 主机端口
spec.type 的说明:
- ClusterIP(默认值):通过集群的内部 IP 暴露服务,选择该值时服务只能够在集群内部访问。
- NodePort:通过每个节点上的 IP 和静态端口(NodePort)暴露服务。 NodePort 服务会路由到自动创建的 ClusterIP 服务。 通过请求
<节点 IP>:<节点端口>
,我们可以从集群的外部访问一个 NodePort 服务。 - LoadBalancer:使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的 NodePort 服务和 ClusterIP 服务上。
- ExternalName:通过返回 CNAME 和对应值,可以将服务映射到 externalName 字段的内容(如:foo.bar.example.com)。 无需创建任何类型代理。
- OSI 网络模型和 TCP/IP 协议:
注意:
- Service 会基于 Pod 的探针机制(readinessProbe,就绪探针)完成 Pod 的自动剔除(没有就绪的 Pod)和上线工作。
- Service 即使是无头服务(Headless Service),其他的 Kubernetes 应用资源(如:Pod 等)不能通过 IP 访问,但是可以将 Service 名字当成域名来访问;非无头服务,更是如此了。
- Service 默认使用的协议是 TCP 协议,对应的是 OSI 网络模型中的第四层传输层,所以也有人称 Service 为四层网络负载均衡。
- selector 只有在 Service 的 spec.type 是 ClusterIP、NodePort、LoadBalancer 才有效。
2.2 准备工作
- 在使用 Service 之前,首先利用 Deployment 创建出 3 个Pod 。
vi k8s-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
namespace: default
labels:
app: nginx
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.20.2
resources: # 资源限制
requests:
cpu: 250m
memory: 100Mi
limits:
cpu: 500m
memory: 200Mi
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 5
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
timeoutSeconds: 2
successThreshold: 1
failureThreshold: 3
periodSeconds: 10
ports:
- containerPort: 80
name: nginx
volumeMounts:
- name: localtime
mountPath: /etc/localtime
volumes:
- name: localtime
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
restartPolicy: Always
kubectl apply -f k8s-deploy.yaml
- 为了方便测试,修改 Pod 中 Nginx 的 index.html :
kubectl exec -it xxx -c nginx -- /bin/sh
openssl rand -base64 8 > /usr/share/nginx/html/index.html
2.3 ClusterIP 类型的 Service
2.2.1 创建 Service
- 新建 k8s-svc.yaml:
vi k8s-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: cluster-ip-svc
namespace: default
spec:
selector:
app: nginx
type: ClusterIP # ClusterIP 指的是当前 Service 在 Kubernetes 集群内可以被所有 Kubernetes 资源发现,默认给这个 Service 分配一个集群内的网络。
# 参考 kubeadmin 创建集群
# 由于默认拉取镜像地址k8s.gcr.io国内无法访问,这里需要指定阿里云镜像仓库地址
# kubeadm init \
# --apiserver-advertise-address=192.168.65.100 \
# --image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \
# --kubernetes-version v1.21.0 \
# --service-cidr=10.96.0.0/16 \ # 如果 spec.clusterIP 为空,就会随机分配一个 10.96.0.0 子网范围的 IP 地址。如果不为空,spec.clusterIP 必须是这个范围内的地址,且不能和当前集群内的其他 Service 产生冲突。
# --pod-network-cidr=10.244.0.0/16
# clusterIP: 10.96.1.2
ports:
- name: nginx
port: 80 # service 的端口,访问到 service 的 80 端口
targetPort: 80 # Pod 的端口,派发到 Pod 的 80 端口
- 创建 Service :
kubectl apply -f k8s-svc.yaml
- 原理:
注意:
- ①
curl 10.96.12.53:80
是可以访问到 Pod 中的容器。 - ②
curl 10.96.12.53:6379
不可以访问到 Pod 中的容器。 - ③ 将 Kubernetes 中能分配 IP 地址的都看做是一个小型的、轻巧的、虚拟的 Linux 主机,
10.96.12.53:6379
是因为我们没有在 service 中开启端口。
- ①
2.2.2 查看 Service 的详细信息
- 语法:
kubectl describe svc xxx
- 示例:
kubectl describe svc cluster-ip-svc
2.2.3 EndPoint(端点)
- Endpoint 是 Kubernetes 中的一个资源对象,存储在etcd 中,用来记录一个 Service 对应的所有 Pod 的访问地址,它是根据Service配置文件中的 Selector 描述产生的(当然,也可以自定义端点)。
- 一个 Service 由一组 Pod 组成,这些 Pod 通过 Endpoints 暴露出来,Endpoints 是实现实际服务的端点集合。换言之,Service 和 Pod 之间的联系是通过 Endpoints 实现的。
- 示例:查询端点信息
# endpoint 的别名是 ep
kubectl get endpoint
- 示例:删除一个 Pod ,Deployment 会将 Pod 重建,Endpoints 的内容随着 Pod 发生变化。
kubectl delete pod xxx
# 10.96.101.172 是 service 的地址
curl 10.96.101.172
- 示例:创建自定义的 EndPoint
vi k8s-ep.yaml
apiVersion: v1
kind: Service
metadata:
name: cluster-svc-no-selector
namespace: default
spec:
ports:
- name: http
port: 80
targetPort: 80 # 此时的 targetPort 需要和 Endpoints 的 subsets.addresses.ports.port 相同
---
apiVersion: v1
kind: Endpoints
metadata:
name: cluster-svc-no-selector # 此处的 name 需要和 Service 的 metadata 的 name 相同
namespace: default
subsets:
- addresses:
- ip: 220.181.38.251 # 百度
- ip: 221.122.82.30 # 搜狗
- ip: 61.129.7.47 # QQ
ports:
- name: http # 此处的 name 需要和 Service 的 spec.ports.name 相同
port: 80
protocol: TCP
kubectl apply -f k8s-ep.yaml
鉴于有些人认为像 MySQL 之类的不应该使用 Docker 、k8s 部署,而是应该直接部署在物理机上,那么就可以使用此种方式,将 MySQL 的地址配置在 EndPoint 中,对外暴露一个 Service ,这样 Kubernetes 中的资源(如:Pod)就可以直接使用暴露的 Service 名称来访问,这样可以实时剔除 EndPoint 的信息。换言之,反向代理集群外的服务。
2.2.4 域名解析
- 进入其中 Pod ,使用 nslookup 命令查询 DNS :
kubectl exec -it xxx -- /bin/bash
# 安装 nslookup
apt-get update
apt-get -y install bind-utils
# 其中 cluster-ip-svc 是 Service 的服务名
nslookup -type=a cluster-ip-svc
- 总结:网络层次
2.2.5 会话保持技术
- 基于客户端 IP 地址的会话保持模式,即来自同一个客户端发起的所有请求都尽最大可能转发到固定的一个 Pod 上,只需要在 spec 中添加
sessionAffinity: ClusterIP
选项。 - 示例:
vi k8s-sessionAffinity.yaml
apiVersion: v1
kind: Service
metadata:
name: k8s-session-affinity-svc
namespace: default
spec:
selector:
app: nginx
type: ClusterIP
sessionAffinity: "ClientIP"
sessionAffinityConfig:
clientIP:
timeoutSeconds: 11800 # 30 分钟
ports:
- name: nginx
protocol: TCP
port: 80
targetPort: 80
kubectl apply -f k8s-sessionAffinity.yaml
2.2.6 删除 Service
- 命令:
kubectl delete -f k8s-svc.yaml
2.4 HeadLiness 类型的 Service
- 所谓的 HeadLiness 类型的 Service ,即所谓的无头服务,即不希望 Kubernetes 集群分配 IP ,针对这种情况,Kubernetes 提供了 HeadLinesss Service,这类 Service 不会分配 Cluster IP,如果想要访问 Service ,只能通过 Service 的域名进行查询,一般配合 StatefulSet 使用。
- 语法:
...
spec:
type: ClusterIP # ClusterIP 指的是当前 Service 在集群内可以被所有人发现,默认给这个 Service 分配一个集群内的网络。
clusterIp: None # k8s 不要给这个 service 分配 IP,headless service 无头服务配合 StatefulSet
...
- 示例:
vi k8s-ClusterIPNone.yaml
apiVersion: v1
kind: Service
metadata:
name: cluster-ip-svc
namespace: default
spec:
selector:
app: nginx
type: ClusterIP # ClusterIP 指的是当前 Service 在集群内可以被所有人发现,默认给这个 Service 分配一个集群内的网络。
clusterIP: None # k8s 不要给这个 service 分配 IP,headless service 无头服务配合 StatefulSet
ports:
- name: nginx
protocol: TCP
port: 80 # service 的端口,访问到 service 的 80 端口
targetPort: 80 # Pod 的端口,派发到 Pod 的 80 端口
kubectl apply -f k8s-ClusterIPNone.yaml
2.5 NodePort 类型的 Service
2.5.1 概述
- 在之前的案例中,创建的 Service 的 IP 地址只能在集群内部才可以访问,如果希望 Service 暴露给集群外部使用,那么就需要使用到另外一种类型的 Service,称为 NodePort 类型的 Service。NodePort 的工作原理就是将 Service 的端口映射到 Node 的一个端口上,然后就可以通过
NodeIP:NodePort
来访问 Service 了。 - 语法:
...
spec:
...
type: NodePort # 每台机器都会为这个 service 随机分配一个指定的端口
ports:
- name: nginx
protocol: TCP
port: 80 # service 的端口,访问到 service 的 80 端口
targetPort: 80 # Pod 的端口,派发到 Pod 的 80 端口
nodePort: 31111 # 不指定,默认会在 30000 ~ 32767 范围内随机分配,集群中的所有机器都会打开这个端口,访问 K8s 集群中的任意一条机器都可以访问 Service 代理的 Pod 。
2.5.2 部署 Service
- 创建 Service :
vi k8s-NodePort.yaml
apiVersion: v1
kind: Service
metadata:
name: cluster-ip-svc
namespace: default
spec:
selector:
app: nginx
type: NodePort # 每台机器都会为这个 service 随机分配一个指定的端口
ports:
- name: nginx
protocol: TCP
port: 80 # service 的端口,访问到 service 的 80 端口
targetPort: 80 # Pod 的端口,派发到 Pod 的 80 端口
nodePort: 31111 # 不指定,默认会在 30000 ~ 32767 范围内随机分配,集群中的所有机器都会打开这个端口,访问 K8s 集群中的任意一条机器都可以访问 Service 代理的 Pod 。
kubectl apply -f k8s-NodePort.yaml
2.6 LoadBalancer 类型的 Service
- LoadBalancer 和 NodePort 很相似,目的都是向外部暴露一个端口,区别在于 LoadBalancer 会在集群的外部再来做一个负载均衡设备,而这个设备需要外部环境的支持,外部服务发送到这个设备上的请求,会被设备负载之后转发到集群中。这个功能需要云平台厂商的支持;换言之,加钱吧。
- 示例:执行也没用
apiVersion: v1
kind: Service
metadata:
name: k8s-load-balancer-svc
namespace: default
spec:
selector:
app: nginx
type: LoadBalancer # 负载均衡,开放给云平台实现的,阿里云、百度云等。
ports:
- name: nginx
protocol: TCP
port: 80 # service 的端口,访问到 service 的 80 端口
targetPort: 80 # Pod 的端口,派发到 Pod 的 80 端口
nodePort: 31111
2.7 ExternalName 类型的 Service
- ExternalName 类型的 Service 用于引入集群外部的服务,它通过 externalName 属性指定一个服务的地址,然后在集群内部访问此 Service 就可以访问到外部的服务了,但是需要注意目标服务的
跨域
问题。
- 示例:
apiVersion: v1
kind: Service
metadata:
name: k8s-external-name-svc
namespace: default
spec:
type: ExternalName # ExternalName 类型的 Service 用于引入集群外部的服务,它通过 externalName 属性指定一个服务的地址,然后在集群内部访问此 Service 就可以访问到外部的服务了。
externalName: www.baidu.com # 其他的Pod可以通过访问这个service而访问其他的域名服务,但是需要注意目标服务的跨域问题。
2.8 Pod 指定自己的主机名
- Pod 中还可以设置 hostname 和 subdomain 字段,需要注意的是,一旦设置了 hostname ,那么该 Pod 的主机名就被设置为 hostname 的值,而 subdomain 需要和 svc 中的 name 相同。
- 示例:
apiVersion: v1
kind: Service
metadata:
name: default-subdomain
namespace: default
spec:
selector:
app: nginx
type: ClusterIP
clusterIP: None
ports:
- name: foo
protocol: TCP
port: 1234
targetPort: 1234
---
apiVersion: v1
kind: Pod
metadata:
name: nginx1
namespace: default
labels:
app: nginx
spec:
hostname: nginx1
subdomain: default-subdomain # 必须和 svc 的 name 相同,才可以使用 hostname.subdomain.名称空间.svc.cluster.local 访问,否则访问不到指定的 Pod 。
containers:
- name: nginx
image: nginx:1.20.2
resources:
limits:
cpu: 250m
memory: 500Mi
requests:
cpu: 100m
memory: 200Mi
ports:
- containerPort: 80
name: nginx
volumeMounts:
- name: localtime
mountPath: /etc/localtime
volumes:
- name: localtime
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
restartPolicy: Always
---
apiVersion: v1
kind: Pod
metadata:
name: nginx2
namespace: default
labels:
app: nginx
spec:
hostname: nginx2
subdomain: default-subdomain # 必须和 svc 的 name 相同,才可以使用 hostname.subdomain.名称空间.svc.cluster.local 访问,否则访问不到指定的 Pod 。
containers:
- name: nginx
image: nginx:1.20.2
resources:
limits:
cpu: 250m
memory: 500Mi
requests:
cpu: 100m
memory: 200Mi
ports:
- containerPort: 80
name: nginx
volumeMounts:
- name: localtime
mountPath: /etc/localtime
volumes:
- name: localtime
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
restartPolicy: Always
- 如果 Pod 和 Pod 之间的访问:
Pod 的 hostname.Pod 的 subdomain.名称空间.svc.cluster.local
;换言之,nginx1 访问 nginx2 只需要这样:nginx2.default-subdomain.default.svc.cluster.local
即可(默认的名称空间可以省略,也可以这样nginx2.default-subdomain
)。 - 那么 Pod 和 Service 的访问:
Pod 的 subdomain.名称空间.svc.cluster.local
。
第三章:Ingress
3.1 为什么需要 Ingress ?
- Service 可以使用 NodePort 暴露集群外访问端口,但是性能低、不安全并且端口的范围有限。
- Service 缺少七层(OSI 网络模型)的统一访问入口,负载均衡能力很低,不能做限流、验证非法用户、链路追踪等等。
- Ingress 公开了从集群外部到集群内
服务
的 HTTP 和 HTTPS 路由。流量路由由 Ingress 资源上定义的规则控制。 - 我们使用 Ingress 作为整个集群统一的入口,配置 Ingress 规则转发到对应的 Service 。
3.2 Ingress nginx 和 nginx ingress
3.2.1 nginx Ingress(不用)
- nginx Ingress是 Nginx 官网适配 k8s 的,分为开源版和 nginx plus 版(收费)。
- 官网地址。
3.2.2 ingress nginx
- ingress nginx 是 k8s 官方出品的,会及时更新一些特性,性能很高,被广泛采用。
- 官网地址。
注意:以后如果不特别说明,ingress = ingress nginx 。
3.3 Ingress 安装
- 自建集群采用裸金属安装方式。
- 下载:
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.2/deploy/static/provider/baremetal/deploy.yaml
需要做如下修改:
- ① 修改
k8s.gcr.io/ingress-nginx/controller:v1.1.2
镜像为registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.1.2
。 - ② 修改
k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1
镜像为registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.1
。 - ③ 修改 Service 为 ClusterIP,无需 NodePort 模式。
- ④ 修改 Deployment 为 DaemonSet 。
- ⑤ 修改 Container 使用主机网络,直接在主机上开辟 80 、443 端口,无需中间解析,速度更快,所有各个节点的 80 和 443 端口不能被其它进程占用。
- ⑥ Container 使用主机网络,对应的 dnsPolicy 策略也需要改为主机网络的。
- ⑦ 修改 DaemonSet 的
nodeSelector: ingress-node=true
。这样只需要给 node 节点打上ingress-node=true
标签,即可快速的加入或剔除 ingress-controller的数量
- ① 修改
- 创建文件:
vi deploy.yaml
- deploy.yaml 修改的内容如下:
#GENERATED FOR K8S 1.20
apiVersion: v1
kind: Namespace
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
---
apiVersion: v1
automountServiceAccountToken: true
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- endpoints
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resourceNames:
- ingress-controller-leader
resources:
- configmaps
verbs:
- get
- update
- apiGroups:
- ""
resources:
- configmaps
verbs:
- create
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
annotations:
helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx-admission
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
- namespaces
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx-admission
rules:
- apiGroups:
- admissionregistration.k8s.io
resources:
- validatingwebhookconfigurations
verbs:
- get
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
annotations:
helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx-admission
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
annotations:
helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx-admission
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: v1
data:
allow-snippet-annotations: "true"
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx-controller
namespace: ingress-nginx
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- appProtocol: http
name: http
port: 80
protocol: TCP
targetPort: http
- appProtocol: https
name: https
port: 443
protocol: TCP
targetPort: https
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: ClusterIP # NodePort
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx-controller-admission
namespace: ingress-nginx
spec:
ports:
- appProtocol: https
name: https-webhook
port: 443
targetPort: webhook
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: ClusterIP
---
apiVersion: apps/v1
kind: DaemonSet # Deployment
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
minReadySeconds: 0
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
template:
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
spec:
dnsPolicy: ClusterFirstWithHostNet # dns 调整为主机网络 ,原先为 ClusterFirst
hostNetwork: true # 直接让 nginx 占用本机的 80 和 443 端口,这样就可以使用主机网络
containers:
- args:
- /nginx-ingress-controller
- --election-id=ingress-controller-leader
- --controller-class=k8s.io/ingress-nginx
- --ingress-class=nginx
- --report-node-internal-ip-address=true
- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
- --validating-webhook=:8443
- --validating-webhook-certificate=/usr/local/certificates/cert
- --validating-webhook-key=/usr/local/certificates/key
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: LD_PRELOAD
value: /usr/local/lib/libmimalloc.so
image: registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.1.2 # 修改 k8s.gcr.io/ingress-nginx/controller:v1.1.2@sha256:28b11ce69e57843de44e3db6413e98d09de0f6688e33d4bd384002a44f78405c
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
livenessProbe:
failureThreshold: 5
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
name: controller
ports:
- containerPort: 80
name: http
protocol: TCP
- containerPort: 443
name: https
protocol: TCP
- containerPort: 8443
name: webhook
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources: # 资源限制
requests:
cpu: 100m
memory: 90Mi
limits:
cpu: 500m
memory: 500Mi
securityContext:
allowPrivilegeEscalation: true
capabilities:
add:
- NET_BIND_SERVICE
drop:
- ALL
runAsUser: 101
volumeMounts:
- mountPath: /usr/local/certificates/
name: webhook-cert
readOnly: true
nodeSelector:
node-role: ingress # 以后只需要给某个 node 打上这个标签就可以部署 ingress-nginx 到这个节点上了
# kubernetes.io/os: linux
serviceAccountName: ingress-nginx
terminationGracePeriodSeconds: 300
volumes:
- name: webhook-cert
secret:
secretName: ingress-nginx-admission
---
apiVersion: batch/v1
kind: Job
metadata:
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx-admission-create
namespace: ingress-nginx
spec:
template:
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx-admission-create
spec:
containers:
- args:
- create
- --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc
- --namespace=$(POD_NAMESPACE)
- --secret-name=ingress-nginx-admission
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.1 # k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660
imagePullPolicy: IfNotPresent
name: create
securityContext:
allowPrivilegeEscalation: false
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
securityContext:
fsGroup: 2000
runAsNonRoot: true
runAsUser: 2000
serviceAccountName: ingress-nginx-admission
---
apiVersion: batch/v1
kind: Job
metadata:
annotations:
helm.sh/hook: post-install,post-upgrade
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx-admission-patch
namespace: ingress-nginx
spec:
template:
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx-admission-patch
spec:
containers:
- args:
- patch
- --webhook-name=ingress-nginx-admission
- --namespace=$(POD_NAMESPACE)
- --patch-mutating=false
- --secret-name=ingress-nginx-admission
- --patch-failure-policy=Fail
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.1 # k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660
imagePullPolicy: IfNotPresent
name: patch
securityContext:
allowPrivilegeEscalation: false
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
securityContext:
fsGroup: 2000
runAsNonRoot: true
runAsUser: 2000
serviceAccountName: ingress-nginx-admission
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: nginx
spec:
controller: k8s.io/ingress-nginx
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx-admission
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: ingress-nginx-controller-admission
namespace: ingress-nginx
path: /networking/v1/ingresses
failurePolicy: Fail
matchPolicy: Equivalent
name: validate.nginx.ingress.kubernetes.io
rules:
- apiGroups:
- networking.k8s.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- ingresses
sideEffects: None
- 给 Node 节点打标签:
kubectl label node k8s-node1 node-role=ingress
kubectl label node k8s-node2 node-role=ingress
当然,也可以给 Master 节点打标签,但是 kubeadm 安装 k8s 集群的时候,会给 Master 节点打上污点,即使我们打上标签,也不会进行 Pod 的调度;换言之,Ingress 也不会在 Master 节点上安装,后面再讲。
- 安装 Ingress (需要关闭 Node 节点的 80 和 443 端口,不能有其他进程占用):
kubectl apply -f deploy.yaml
- 验证是否安装成功:只需要在部署了 ingress 的主机,执行如下的命令:
netstat -ntlp | grep 80
netstat -ntlp | grep 443
- 卸载:
kubectl delete -f deploy.yaml
3.4 Ingress 工作原理
工作原理:
- ① 用户编写 Ingress 规则,说明哪个域名对应 k8s 集群中的哪个 Service。
- ② Ingress 控制器动态感知 Ingress 服务规则的变化,然后生成一段对应的 Nginx 的反向代理配置。
- ③ Ingress 控制器会将生成的 Nginx 配置写入到一个运行着的 Nginx 服务中,并动态更新。
3.5 准备工作
- 为了后面的实验比较方便,创建如下图所示的模型:
- 创建实验所需的 Service 以及 Pod 等:
vi k8s-prepare.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
namespace: default
labels:
app: nginx
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.20.2
resources:
requests:
cpu: 100m
memory: 100Mi
limits:
cpu: 250m
memory: 500Mi
ports:
- containerPort: 80
name: nginx
volumeMounts:
- name: localtime
mountPath: /etc/localtime
volumes:
- name: localtime
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
restartPolicy: Always
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deploy
namespace: default
labels:
app: tomcat
spec:
selector:
matchLabels:
app: tomcat
replicas: 3
template:
metadata:
labels:
app: tomcat
spec:
containers:
- name: tomcat
image: tomcat:9-jre8
env:
- name: JAVA_OPTS
value: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap"
resources:
requests:
cpu: 500m
memory: 256Mi
limits:
cpu: 500m
memory: 500Mi
ports:
- containerPort: 8080
name: tomcat
volumeMounts:
- name: localtime
mountPath: /etc/localtime
volumes:
- name: localtime
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: default
spec:
selector:
app: nginx
type: ClusterIP
ports:
- name: nginx
protocol: TCP
port: 80
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: tomcat-svc
spec:
selector:
app: tomcat
type: ClusterIP
ports:
- name: tomcat
protocol: TCP
port: 8080
targetPort: 8080
kubectl apply -f k8s-prepare.yaml
3.6 实战
3.6.1 基本配置
- 语法:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-http
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules: # 规则
- host: it.nginx.com # 指定的监听的主机域名,相当于 nginx.conf 的 server { xxx }
http: # 指定路由规则
paths:
- path: /
pathType: Prefix # 匹配规则,Prefix 前缀匹配 it.nginx.com/* 都可以匹配到
backend: # 指定路由的后台服务的 service 名称
service:
name: nginx-svc # 服务名
port:
number: 80 # 服务的端口
pathType 说明:
- Prefix:基于以
/
分隔的 URL 路径前缀匹配。匹配区分大小写,并且对路径中的元素逐个完成。 路径元素指的是由/
分隔符分隔的路径中的标签列表。 如果每个 p 都是请求路径 p 的元素前缀,则请求与路径 p 匹配。 - Exact:精确匹配 URL 路径,且区分大小写。
- ImplementationSpecific:对于这种路径类型,匹配方法取决于 IngressClass。 具体实现可以将其作为单独的 pathType 处理或者与 Prefix 或 Exact 类型作相同处理。
- Prefix:基于以
注意:ingress 规则会生效到所有安装了 IngressController 的机器的 nginx 配置。
- 示例:
vi k8s-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-http
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
rules: # 规则
- host: nginx.xudaxian.com # 指定的监听的主机域名,相当于 nginx.conf 的 server { xxx }
http: # 指定路由规则
paths:
- path: /
pathType: Prefix # 匹配规则,Prefix 前缀匹配 nginx.xudaxian.com/* 都可以匹配到
backend: # 指定路由的后台服务的 service 名称
service:
name: nginx-svc # 服务名
port:
number: 80 # 服务的端口
- host: tomcat.xudaxian.com # 指定的监听的主机域名,相当于 nginx.conf 的 server { xxx }
http: # 指定路由规则
paths:
- path: /
pathType: Prefix # 匹配规则,Prefix 前缀匹配 tomcat.xudaxian.com/* 都可以匹配到
backend: # 指定路由的后台服务的 service 名称
service:
name: tomcat-svc # 服务名
port:
number: 8080 # 服务的端口
kubectl apply -f k8s-ingress.yaml
- 示例的示意图:
- 测试示例(后面有更简单的测试方法):
第一种方案:
① 在 win 中的 hosts(
C:\Windows\System32\drivers\etc\hosts
) 文件中添加如下的信息:# 用来模拟 DNS ,其中 192.168.65.101 是 ingress 部署的机器,nginx.xudaxian.com 和 tomcat.xudaxian.com 是 ingress 文件中监听的域名 192.168.65.101 nginx.xudaxian.com 192.168.65.101 tomcat.xudaxian.com
- ② 在 win 中使用 curl 命令:
为什么这么干?因为我使用了科学上网
,网络出现了问题。
第二种方案:
① 重新建立一个虚拟机(安装有 CentOS7 系统,并且带有桌面),在 hosts (
/etc/hosts
)文件中添加如下的内容:# 用来模拟 DNS ,其中 192.168.65.101 是 ingress 部署的机器,nginx.xudaxian.com 和 tomcat.xudaxian.com 是 ingress 文件中监听的域名 192.168.65.101 nginx.xudaxian.com 192.168.65.101 tomcat.xudaxian.com
- ② 通过浏览器访问:
- 证明:ingress 规则会生效到所有安装了 IngressController 的机器的 nginx 配置
cat nginx.conf | grep nginx.xudaxian.com -A 20
3.6.2 默认后端
- 示例:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-http
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
defaultBackend: # 指定所有未匹配的默认后端
service:
name: nginx-svc
port:
number: 80
rules:
- host: tomcat.com
http:
paths:
- path: /abc
pathType: Prefix
backend:
service:
name: tomcat-svc
port:
number: 8080
效果:
- tomcat.com 域名的 非
/abc
开头的请求,都会转到 defaultBackend 。- 非 tomcat.com 域名下的所有请求,也会转到 defaultBackend 。
3.6.3 Ingress 中的 nginx 的全局配置
- 官方文档。
- 方式一:在安装的时候,添加配置。
apiVersion: v1
data:
allow-snippet-annotations: "true" # Nginx 的全局配置
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx-controller
namespace: ingress-nginx
- 方式二:编辑 cm :
kubectl edit cm ingress-nginx-controller -n ingress-nginx
# 配置项加上
data:
map-hash-bucket-size: "128" # Nginx 的全局配置
ssl-protocols: SSLv2
3.6.4 限流
- 官方文档。
- 示例:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rate-ingress
namespace: default
annotations: # https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#rate-limiting
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
nginx.ingress.kubernetes.io/limit-rps: "1" # 限流
spec:
rules:
- host: nginx.xudaxian.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
3.6.5 路径重写
- 官方文档。
路径重写,经常用于前后端分离。
- 示例:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-rewrite
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2 # 路径重写
spec:
ingressClassName: nginx
rules:
- host: baidu.com
http:
paths:
- path: /api(/|$)(.*)
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
3.6.6 基于 Cookie 的会话保持技术
- Service 只能基于 ClientIP,但是 ingress 是七层负载均衡,可以基于 Cookie 实现会话保持。
- 示例:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rate-ingress
namespace: default
annotations: # https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#rate-limiting
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
nginx.ingress.kubernetes.io/affinity: "cookie"
spec:
rules:
- host: nginx.xudaxian.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
3.6.7 配置 SSL
- 官方地址。
- 生成证书语法:
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ${KEY_FILE} -out ${CERT_FILE} -subj "/CN=${HOST:baidu.com}/O=${HOST:baidu.com}"
kubectl create secret tls ${CERT_NAME:baidu-tls} --key ${KEY_FILE:tls.key} --cert ${CERT_FILE:tls.cert}
- 示例:生成证书
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.cert -subj "/CN=xudaxian.com/O=xudaxian.com"
kubectl create secret tls xudaxian-tls --key tls.key --cert tls.cert
- 示例:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-tls
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
tls:
- hosts:
- nginx.xudaxian.com # 通过浏览器访问 https://nginx.xudaxian.com
- tomcat.xudaxian.com # 通过浏览器访问 https://tomcat.xudaxian.com
secretName: xudaxian-tls
rules:
- host: nginx.xudaxian.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
- host: tomcat.xudaxian.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tomcat-svc
port:
number: 8080
注意:实际开发的时候,需要自己购买证书。
3.6.8 Ingress 金丝雀发布
3.6.8.1 概述
- 以前使用 Kubernetes 的 Service 配合 Deployment 进行金丝雀的部署,原理如下所示:
- 但是,也是有缺点的,就是不能自定义灰度逻辑,如:指定用户进行灰度(新功能只让 VIP 先体验一个月,一个月之后再将新功能解锁,让所有用户都体验到)。
- Ingress 金丝雀发布的原理如下所示:
3.6.8.2 准备工作
- 部署 Service 和 Deployment:
vi k8s-ingress-canary-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: v1-deployment
labels:
app: v1-deployment
spec:
replicas: 2
selector:
matchLabels:
app: v1-pod
template:
metadata:
name: nginx
labels:
app: v1-pod
spec:
initContainers:
- name: alpine
image: alpine
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","echo v1-pod > /app/index.html;"]
volumeMounts:
- mountPath: /app
name: app
containers:
- name: nginx
image: nginx:1.17.2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
resources:
requests:
cpu: 100m
memory: 100Mi
limits:
cpu: 250m
memory: 500Mi
volumeMounts:
- name: app
mountPath: /usr/share/nginx/html
volumes:
- name: app
emptyDir: {}
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: v1-service
namespace: default
spec:
selector:
app: v1-pod
type: ClusterIP
ports:
- name: nginx
protocol: TCP
port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: v2-deployment
labels:
app: v2-deployment
spec:
replicas: 3
selector:
matchLabels:
app: v2-pod
template:
metadata:
name: v2-pod
labels:
app: v2-pod
spec:
containers:
- name: nginx
image: nginx:1.17.2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
resources:
requests:
cpu: 100m
memory: 100Mi
limits:
cpu: 250m
memory: 500Mi
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: v2-service
namespace: default
spec:
selector:
app: v2-pod
type: ClusterIP
ports:
- name: nginx
protocol: TCP
port: 80
targetPort: 80
kubectl apply -f k8s-ingress-canary-deploy.yaml
- 部署普通的 ingress :
vi k8s-ingress-v1.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-v1
namespace: default
spec:
ingressClassName: "nginx"
rules:
- host: nginx.xudaxian.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: v1-service
port:
number: 80
kubectl apply -f k8s-ingress-v1.yaml
- 测试 ingress :
# curl 来模拟请求
curl -H "Host: canary.example.com" http://EXTERNAL-IP # EXTERNAL-IP 替换为 Nginx Ingress 自身对外暴露的 IP
curl -H "Host: nginx.xudaxian.com" http://192.168.65.101
3.6.8.3 基于 Header 的流量切分
- 示例:
vi k8s-ingress-header.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-canary
namespace: default
annotations:
nginx.ingress.kubernetes.io/canary: "true" # 开启金丝雀
nginx.ingress.kubernetes.io/canary-by-header: "Region" # 基于请求头
# 如果 请求头 Region = always ,就路由到金丝雀版本;如果 Region = never ,就永远不会路由到金丝雀版本。
nginx.ingress.kubernetes.io/canary-by-header-value: "sz" # 自定义值
# 如果 请求头 Region = sz ,就路由到金丝雀版本;如果 Region != sz ,就永远不会路由到金丝雀版本。
# nginx.ingress.kubernetes.io/canary-by-header-pattern: "sh|sz"
# 如果 请求头 Region = sh 或 Region = sz ,就路由到金丝雀版本;如果 Region != sz 并且 Region != sz ,就永远不会路由到金丝雀版本。
spec:
ingressClassName: "nginx"
rules:
- host: nginx.xudaxian.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: v2-service
port:
number: 80
kubectl apply -f k8s-ingress-header.yaml
- 测试:
curl -H "Host: nginx.xudaxian.com" http://192.168.65.101
curl -H "Host: nginx.xudaxian.com" -H "Region: sz" http://192.168.65.101
curl -H "Host: nginx.xudaxian.com" -H "Region: sh" http://192.168.65.101
3.6.8.4 基于 Cookie 的流量切分
- 示例:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-canary
namespace: default
annotations:
nginx.ingress.kubernetes.io/canary: "true" # 开启金丝雀
nginx.ingress.kubernetes.io/canary-by-cookie: "vip" # 如果 cookie 是 vip = always ,就会路由到到金丝雀版本;如果 cookie 是 vip = never ,就永远不会路由到金丝雀的版本。
spec:
ingressClassName: "nginx"
rules:
- host: nginx.xudaxian.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: v2-service
port:
number: 80
curl -H "Host: nginx.xudaxian.com" --cookie "vip=always" http://192.168.65.101
3.6.8.5 基于服务权重的流量切分
- 示例:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-canary
namespace: default
annotations:
nginx.ingress.kubernetes.io/canary: "true" # 开启金丝雀
nginx.ingress.kubernetes.io/canary-weight: "10" # 基于服务权重
spec:
ingressClassName: "nginx"
rules:
- host: nginx.xudaxian.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: v2-service
port:
number: 80
for i in {1..10}; do curl -H "Host: nginx.xudaxian.com" http://192.168.65.101; done;
第四章:NetworkPolicy(网络策略)
4.1 概述
- 网络策略指的是 Pod 间的网络隔离策略,默认情况下是互通的。
Pod 之间的互通是通过如下三个标识符的组合来辨识的:
- ① 其他被允许的 Pod(例外:Pod 无法阻塞对自身的访问)。
- ② 被允许的名称空间。
- ③ IP 组块(例外:与 Pod 运行所在的节点的通信总是被允许的, 无论 Pod 或节点的 IP 地址)。
4.2 Pod 隔离和非隔离
- 默认情况下,Pod 都是非隔离的(non-isolated),可以接受来自任何请求方的网络请求。
- 如果一个 NetworkPolicy 的标签选择器选中了某个 Pod,则该 Pod 将变成隔离的(isolated),并将拒绝任何不被 NetworkPolicy 许可的网络连接。
- 示例:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: networkpol-01
namespace: default
spec:
podSelector: # Pod 选择器
matchLabels:
app: nginx # 选中的 Pod 就被隔离起来了
policyTypes: # 策略类型
- Ingress # Ingress 入站规则、Egress 出站规则
- Egress
ingress: # 入站白名单,什么能访问我
- from:
- podSelector: # 选中的 Pod 可以访问 spec.matchLabels 中筛选的 Pod
matchLabels:
access: granted
ports:
- protocol: TCP
port: 80
egress: # 出站白名单,我能访问什么
- to:
- podSelector: # spec.matchLabels 中筛选的 Pod 能访问的 Pod
matchLabels:
app: tomcat
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: dev # spec.matchLabels 中筛选的 Pod 能访问 dev 命名空间下的所有
ports:
- protocol: TCP
port: 8080
4.3 场景
- 官方文档。
[...]Kubernetes 概念 Kubernetes(v1.21)工作负载 Kubernetes(v1.21)配置和存储Kubernetes(v1.21)网络Kubernetes(v1.21)调度原理Kubernetes(v1.21)安全K8s - Ingress 限流K8s-Pod重启策略Kubernetes滚动更新解决Mac/Windows版Desktop Docker中自带的K8s无法访问pod[...]