Kubernetes(v1.21)网络

GA666666 2022-12-08 AM 17℃ 1条

第一章:Kubernetes 网络

1.1 概述

  • Kubernetes 网络解决四个方面的问题:

    • ① 一个 Pod 中容器之间通过本地回路(loopback)通信。
    • ② 集群网络在不同 Pod 之间提供通信;换言之,Pod 和 Pod 之间能互相通信(通过 calico 网络插件实现 Pod 之间网络的扁平化;当然,Node 节点之间的通信也是通过 calico 网络插件)。
    • ③ Service 资源允许我们对外暴露 Pod 中运行的应用程序,以支持来自集群之外的访问;换言之,Service 和 Pod 之间能互相通信。
    • ④ 可以使用 Service 来发布仅供集群内部使用的服务。

1.png

1.2 Kubernetes 网络架构图

1.2.1 架构图

Kubernetes 网络架构图.jpg

1.2.2 访问流程

访问流程.png

第二章:Service

2.1 概述

  • 在 Kubernetes 中,Pod 是应用程序的载体,我们可以通过 Pod 的 IP 来访问应用程序,但是 Pod 的 IP 地址不是固定的,这就意味着不方便直接采用 Pod 的 IP 对服务进行访问。
  • 为了解决这个问题,Kubernetes 提供了 Service 资源,Service 会对提供同一个服务的多个 Pod 进行聚合,并且提供一个统一的入口地址,通过访问 Service 的入口地址就能访问到后面的 Pod 服务。

2.png

  • Service 在很多情况下只是一个概念,真正起作用的其实是 kube-proxy 服务进程,每个 Node 节点上都运行了一个 kube-proxy 的服务进程。当创建 Service 的时候会通过 API Server 向 etcd 写入创建的 Service 的信息,而 kube-proxy 会基于监听的机制发现这种 Service 的变化,然后它会将最新的 Service 信息转换为对应的访问规则(其实,就是 EndPoint,后面讲)。

3.png

  • 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 协议:

OSI 网络模型和 TCP-IP 协议.png

注意:

  • 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

4.gif

  • 为了方便测试,修改 Pod 中 Nginx 的 index.html :
kubectl exec -it xxx -c nginx -- /bin/sh
openssl rand -base64 8 > /usr/share/nginx/html/index.html

5.gif

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

6.gif

  • 原理:

7.png

  • 注意:

    • 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

8.png

2.2.3 EndPoint(端点)

  • Endpoint 是 Kubernetes 中的一个资源对象,存储在etcd 中,用来记录一个 Service 对应的所有 Pod 的访问地址,它是根据Service配置文件中的 Selector 描述产生的(当然,也可以自定义端点)。
  • 一个 Service 由一组 Pod 组成,这些 Pod 通过 Endpoints 暴露出来,Endpoints 是实现实际服务的端点集合。换言之,Service 和 Pod 之间的联系是通过 Endpoints 实现的。

9.png

  • 示例:查询端点信息
# endpoint 的别名是 ep
kubectl get endpoint

10.png

  • 示例:删除一个 Pod ,Deployment 会将 Pod 重建,Endpoints 的内容随着 Pod 发生变化。
kubectl delete pod xxx
# 10.96.101.172 是 service 的地址
curl 10.96.101.172

11.gif

  • 示例:创建自定义的 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

12.gif

鉴于有些人认为像 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

13.gif

  • 总结:网络层次

14.png

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

15.gif

2.2.6 删除 Service

  • 命令:
kubectl delete -f k8s-svc.yaml

16.gif

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

17.gif

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 。

18.png

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

19.gif

2.6 LoadBalancer 类型的 Service

  • LoadBalancer 和 NodePort 很相似,目的都是向外部暴露一个端口,区别在于 LoadBalancer 会在集群的外部再来做一个负载均衡设备,而这个设备需要外部环境的支持,外部服务发送到这个设备上的请求,会被设备负载之后转发到集群中。这个功能需要云平台厂商的支持;换言之,加钱吧。

20.png

  • 示例:执行也没用
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 就可以访问到外部的服务了,但是需要注意目标服务的 跨域 问题。

21.png

  • 示例:
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 。

22.png

3.2 Ingress nginx 和 nginx ingress

3.2.1 nginx Ingress(不用)

  • nginx Ingress是 Nginx 官网适配 k8s 的,分为开源版和 nginx plus 版(收费)。
  • 官网地址

23.png

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 节点上安装,后面再讲。

24.gif

  • 安装 Ingress (需要关闭 Node 节点的 80 和 443 端口,不能有其他进程占用):
kubectl apply -f deploy.yaml

25.gif

  • 验证是否安装成功:只需要在部署了 ingress 的主机,执行如下的命令:
netstat -ntlp | grep 80
netstat -ntlp | grep 443
  • 卸载:
kubectl delete -f deploy.yaml

3.4 Ingress 工作原理

26.png

  • 工作原理:

    • ① 用户编写 Ingress 规则,说明哪个域名对应 k8s 集群中的哪个 Service。
    • ② Ingress 控制器动态感知 Ingress 服务规则的变化,然后生成一段对应的 Nginx 的反向代理配置。
    • ③ Ingress 控制器会将生成的 Nginx 配置写入到一个运行着的 Nginx 服务中,并动态更新。

3.5 准备工作

  • 为了后面的实验比较方便,创建如下图所示的模型:

27.png

  • 创建实验所需的 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

28.gif

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 类型作相同处理。
注意: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

29.gif

  • 示例的示意图:

30.png

  • 测试示例(后面有更简单的测试方法):
  • 第一种方案:

    • ① 在 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 命令:

30.gif

为什么这么干?因为我使用了科学上网,网络出现了问题。
  • 第二种方案:

    • ① 重新建立一个虚拟机(安装有 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
    • ② 通过浏览器访问:

31.gif

  • 证明:ingress 规则会生效到所有安装了 IngressController 的机器的 nginx 配置
cat nginx.conf |  grep nginx.xudaxian.com -A 20

32.gif

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 路径重写

路径重写,经常用于前后端分离。

33.png

  • 示例:
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

34.gif

  • 示例:
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 进行金丝雀的部署,原理如下所示:

35.png

  • 但是,也是有缺点的,就是不能自定义灰度逻辑,如:指定用户进行灰度(新功能只让 VIP 先体验一个月,一个月之后再将新功能解锁,让所有用户都体验到)。
  • Ingress 金丝雀发布的原理如下所示:

36.png

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

37.gif

  • 部署普通的 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

38.gif

  • 测试 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

39.gif

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

40.gif

  • 测试:
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

41.gif

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 地址)。

42.png

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 场景

标签: none

非特殊说明,本博所有文章均为博主原创。

评论啦~



唉呀 ~ 仅有一条评论


  1. 云原生 - GA666666 Blog ~ 个人博客
    云原生 - GA666666 Blog ~ 个人博客

    [...]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[...]

    回复 2024-02-21 11:07