第一章: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 的资源清单:
  1. apiVersion: v1 # 版本
  2. kind: Service # 类型
  3. metadata: # 元数据
  4. name: # 资源名称
  5. namespace: # 命名空间
  6. spec:
  7. selector: # 标签选择器,用于确定当前Service代理那些Pod
  8. app: nginx
  9. type: NodePort # Service的类型,指定Service的访问方式
  10. clusterIP: # 虚拟服务的IP地址
  11. sessionAffinity: # session亲和性,支持ClientIP、None两个选项,默认值为None
  12. ports: # 端口信息
  13. - port: 8080 # Service端口
  14. protocol: TCP # 协议
  15. targetPort : # Pod端口
  16. 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 。
  1. vi k8s-deploy.yaml
  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: nginx-deploy
  5. namespace: default
  6. labels:
  7. app: nginx
  8. spec:
  9. selector:
  10. matchLabels:
  11. app: nginx
  12. replicas: 3
  13. template:
  14. metadata:
  15. labels:
  16. app: nginx
  17. spec:
  18. containers:
  19. - name: nginx
  20. image: nginx:1.20.2
  21. resources: # 资源限制
  22. requests:
  23. cpu: 250m
  24. memory: 100Mi
  25. limits:
  26. cpu: 500m
  27. memory: 200Mi
  28. livenessProbe:
  29. tcpSocket:
  30. port: 80
  31. initialDelaySeconds: 5
  32. timeoutSeconds: 5
  33. successThreshold: 1
  34. failureThreshold: 3
  35. periodSeconds: 10
  36. readinessProbe:
  37. httpGet:
  38. path: /
  39. port: 80
  40. initialDelaySeconds: 5
  41. timeoutSeconds: 2
  42. successThreshold: 1
  43. failureThreshold: 3
  44. periodSeconds: 10
  45. ports:
  46. - containerPort: 80
  47. name: nginx
  48. volumeMounts:
  49. - name: localtime
  50. mountPath: /etc/localtime
  51. volumes:
  52. - name: localtime
  53. hostPath:
  54. path: /usr/share/zoneinfo/Asia/Shanghai
  55. restartPolicy: Always
  1. kubectl apply -f k8s-deploy.yaml

4.gif

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

5.gif

2.3 ClusterIP 类型的 Service

2.2.1 创建 Service

  • 新建 k8s-svc.yaml:
  1. vi k8s-svc.yaml
  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: cluster-ip-svc
  5. namespace: default
  6. spec:
  7. selector:
  8. app: nginx
  9. type: ClusterIP # ClusterIP 指的是当前 Service 在 Kubernetes 集群内可以被所有 Kubernetes 资源发现,默认给这个 Service 分配一个集群内的网络。
  10. # 参考 kubeadmin 创建集群
  11. # 由于默认拉取镜像地址k8s.gcr.io国内无法访问,这里需要指定阿里云镜像仓库地址
  12. # kubeadm init \
  13. # --apiserver-advertise-address=192.168.65.100 \
  14. # --image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \
  15. # --kubernetes-version v1.21.0 \
  16. # --service-cidr=10.96.0.0/16 \ # 如果 spec.clusterIP 为空,就会随机分配一个 10.96.0.0 子网范围的 IP 地址。如果不为空,spec.clusterIP 必须是这个范围内的地址,且不能和当前集群内的其他 Service 产生冲突。
  17. # --pod-network-cidr=10.244.0.0/16
  18. # clusterIP: 10.96.1.2
  19. ports:
  20. - name: nginx
  21. port: 80 # service 的端口,访问到 service 的 80 端口
  22. targetPort: 80 # Pod 的端口,派发到 Pod 的 80 端口
  • 创建 Service :
  1. 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 的详细信息

  • 语法:
  1. kubectl describe svc xxx
  • 示例:
  1. 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

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

10.png

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

11.gif

  • 示例:创建自定义的 EndPoint
  1. vi k8s-ep.yaml
  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: cluster-svc-no-selector
  5. namespace: default
  6. spec:
  7. ports:
  8. - name: http
  9. port: 80
  10. targetPort: 80 # 此时的 targetPort 需要和 Endpoints 的 subsets.addresses.ports.port 相同
  11. ---
  12. apiVersion: v1
  13. kind: Endpoints
  14. metadata:
  15. name: cluster-svc-no-selector # 此处的 name 需要和 Service 的 metadata 的 name 相同
  16. namespace: default
  17. subsets:
  18. - addresses:
  19. - ip: 220.181.38.251 # 百度
  20. - ip: 221.122.82.30 # 搜狗
  21. - ip: 61.129.7.47 # QQ
  22. ports:
  23. - name: http # 此处的 name 需要和 Service 的 spec.ports.name 相同
  24. port: 80
  25. protocol: TCP
  1. kubectl apply -f k8s-ep.yaml

12.gif

鉴于有些人认为像 MySQL 之类的不应该使用 Docker 、k8s 部署,而是应该直接部署在物理机上,那么就可以使用此种方式,将 MySQL 的地址配置在 EndPoint 中,对外暴露一个 Service ,这样 Kubernetes 中的资源(如:Pod)就可以直接使用暴露的 Service 名称来访问,这样可以实时剔除 EndPoint 的信息。换言之,反向代理集群外的服务。

2.2.4 域名解析

  • 进入其中 Pod ,使用 nslookup 命令查询 DNS :
  1. kubectl exec -it xxx -- /bin/bash
  1. # 安装 nslookup
  2. apt-get update
  3. apt-get -y install bind-utils
  1. # 其中 cluster-ip-svc 是 Service 的服务名
  2. nslookup -type=a cluster-ip-svc

13.gif

  • 总结:网络层次

14.png

2.2.5 会话保持技术

  • 基于客户端 IP 地址的会话保持模式,即来自同一个客户端发起的所有请求都尽最大可能转发到固定的一个 Pod 上,只需要在 spec 中添加 sessionAffinity: ClusterIP 选项。

  • 示例:

  1. vi k8s-sessionAffinity.yaml
  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: k8s-session-affinity-svc
  5. namespace: default
  6. spec:
  7. selector:
  8. app: nginx
  9. type: ClusterIP
  10. sessionAffinity: "ClientIP"
  11. sessionAffinityConfig:
  12. clientIP:
  13. timeoutSeconds: 11800 # 30 分钟
  14. ports:
  15. - name: nginx
  16. protocol: TCP
  17. port: 80
  18. targetPort: 80
  1. kubectl apply -f k8s-sessionAffinity.yaml

15.gif

2.2.6 删除 Service

  • 命令:
  1. 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 使用。
  • 语法:
  1. ...
  2. spec:
  3. type: ClusterIP # ClusterIP 指的是当前 Service 在集群内可以被所有人发现,默认给这个 Service 分配一个集群内的网络。
  4. clusterIp: None # k8s 不要给这个 service 分配 IP,headless service 无头服务配合 StatefulSet
  5. ...
  • 示例:
  1. vi k8s-ClusterIPNone.yaml
  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: cluster-ip-svc
  5. namespace: default
  6. spec:
  7. selector:
  8. app: nginx
  9. type: ClusterIP # ClusterIP 指的是当前 Service 在集群内可以被所有人发现,默认给这个 Service 分配一个集群内的网络。
  10. clusterIP: None # k8s 不要给这个 service 分配 IP,headless service 无头服务配合 StatefulSet
  11. ports:
  12. - name: nginx
  13. protocol: TCP
  14. port: 80 # service 的端口,访问到 service 的 80 端口
  15. targetPort: 80 # Pod 的端口,派发到 Pod 的 80 端口
  1. 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 了。
  • 语法:
  1. ...
  2. spec:
  3. ...
  4. type: NodePort # 每台机器都会为这个 service 随机分配一个指定的端口
  5. ports:
  6. - name: nginx
  7. protocol: TCP
  8. port: 80 # service 的端口,访问到 service 的 80 端口
  9. targetPort: 80 # Pod 的端口,派发到 Pod 的 80 端口
  10. nodePort: 31111 # 不指定,默认会在 30000 ~ 32767 范围内随机分配,集群中的所有机器都会打开这个端口,访问 K8s 集群中的任意一条机器都可以访问 Service 代理的 Pod 。

18.png

2.5.2 部署 Service

  • 创建 Service :
  1. vi k8s-NodePort.yaml
  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: cluster-ip-svc
  5. namespace: default
  6. spec:
  7. selector:
  8. app: nginx
  9. type: NodePort # 每台机器都会为这个 service 随机分配一个指定的端口
  10. ports:
  11. - name: nginx
  12. protocol: TCP
  13. port: 80 # service 的端口,访问到 service 的 80 端口
  14. targetPort: 80 # Pod 的端口,派发到 Pod 的 80 端口
  15. nodePort: 31111 # 不指定,默认会在 30000 ~ 32767 范围内随机分配,集群中的所有机器都会打开这个端口,访问 K8s 集群中的任意一条机器都可以访问 Service 代理的 Pod 。
  1. kubectl apply -f k8s-NodePort.yaml

19.gif

2.6 LoadBalancer 类型的 Service

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

20.png

  • 示例:执行也没用
  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: k8s-load-balancer-svc
  5. namespace: default
  6. spec:
  7. selector:
  8. app: nginx
  9. type: LoadBalancer # 负载均衡,开放给云平台实现的,阿里云、百度云等。
  10. ports:
  11. - name: nginx
  12. protocol: TCP
  13. port: 80 # service 的端口,访问到 service 的 80 端口
  14. targetPort: 80 # Pod 的端口,派发到 Pod 的 80 端口
  15. nodePort: 31111

2.7 ExternalName 类型的 Service

  • ExternalName 类型的 Service 用于引入集群外部的服务,它通过 externalName 属性指定一个服务的地址,然后在集群内部访问此 Service 就可以访问到外部的服务了,但是需要注意目标服务的 跨域 问题。

21.png

  • 示例:
  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: k8s-external-name-svc
  5. namespace: default
  6. spec:
  7. type: ExternalName # ExternalName 类型的 Service 用于引入集群外部的服务,它通过 externalName 属性指定一个服务的地址,然后在集群内部访问此 Service 就可以访问到外部的服务了。
  8. externalName: www.baidu.com # 其他的Pod可以通过访问这个service而访问其他的域名服务,但是需要注意目标服务的跨域问题。

2.8 Pod 指定自己的主机名

  • Pod 中还可以设置 hostname 和 subdomain 字段,需要注意的是,一旦设置了 hostname ,那么该 Pod 的主机名就被设置为 hostname 的值,而 subdomain 需要和 svc 中的 name 相同。

  • 示例:

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: default-subdomain
  5. namespace: default
  6. spec:
  7. selector:
  8. app: nginx
  9. type: ClusterIP
  10. clusterIP: None
  11. ports:
  12. - name: foo
  13. protocol: TCP
  14. port: 1234
  15. targetPort: 1234
  16. ---
  17. apiVersion: v1
  18. kind: Pod
  19. metadata:
  20. name: nginx1
  21. namespace: default
  22. labels:
  23. app: nginx
  24. spec:
  25. hostname: nginx1
  26. subdomain: default-subdomain # 必须和 svc 的 name 相同,才可以使用 hostname.subdomain.名称空间.svc.cluster.local 访问,否则访问不到指定的 Pod 。
  27. containers:
  28. - name: nginx
  29. image: nginx:1.20.2
  30. resources:
  31. limits:
  32. cpu: 250m
  33. memory: 500Mi
  34. requests:
  35. cpu: 100m
  36. memory: 200Mi
  37. ports:
  38. - containerPort: 80
  39. name: nginx
  40. volumeMounts:
  41. - name: localtime
  42. mountPath: /etc/localtime
  43. volumes:
  44. - name: localtime
  45. hostPath:
  46. path: /usr/share/zoneinfo/Asia/Shanghai
  47. restartPolicy: Always
  48. ---
  49. apiVersion: v1
  50. kind: Pod
  51. metadata:
  52. name: nginx2
  53. namespace: default
  54. labels:
  55. app: nginx
  56. spec:
  57. hostname: nginx2
  58. subdomain: default-subdomain # 必须和 svc 的 name 相同,才可以使用 hostname.subdomain.名称空间.svc.cluster.local 访问,否则访问不到指定的 Pod 。
  59. containers:
  60. - name: nginx
  61. image: nginx:1.20.2
  62. resources:
  63. limits:
  64. cpu: 250m
  65. memory: 500Mi
  66. requests:
  67. cpu: 100m
  68. memory: 200Mi
  69. ports:
  70. - containerPort: 80
  71. name: nginx
  72. volumeMounts:
  73. - name: localtime
  74. mountPath: /etc/localtime
  75. volumes:
  76. - name: localtime
  77. hostPath:
  78. path: /usr/share/zoneinfo/Asia/Shanghai
  79. 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 安装

  1. 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的数量
  • 创建文件:
  1. vi deploy.yaml
  • deploy.yaml 修改的内容如下:
  1. #GENERATED FOR K8S 1.20
  2. apiVersion: v1
  3. kind: Namespace
  4. metadata:
  5. labels:
  6. app.kubernetes.io/instance: ingress-nginx
  7. app.kubernetes.io/name: ingress-nginx
  8. name: ingress-nginx
  9. ---
  10. apiVersion: v1
  11. automountServiceAccountToken: true
  12. kind: ServiceAccount
  13. metadata:
  14. labels:
  15. app.kubernetes.io/component: controller
  16. app.kubernetes.io/instance: ingress-nginx
  17. app.kubernetes.io/managed-by: Helm
  18. app.kubernetes.io/name: ingress-nginx
  19. app.kubernetes.io/part-of: ingress-nginx
  20. app.kubernetes.io/version: 1.1.2
  21. helm.sh/chart: ingress-nginx-4.0.18
  22. name: ingress-nginx
  23. namespace: ingress-nginx
  24. ---
  25. apiVersion: v1
  26. kind: ServiceAccount
  27. metadata:
  28. annotations:
  29. helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
  30. helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
  31. labels:
  32. app.kubernetes.io/component: admission-webhook
  33. app.kubernetes.io/instance: ingress-nginx
  34. app.kubernetes.io/managed-by: Helm
  35. app.kubernetes.io/name: ingress-nginx
  36. app.kubernetes.io/part-of: ingress-nginx
  37. app.kubernetes.io/version: 1.1.2
  38. helm.sh/chart: ingress-nginx-4.0.18
  39. name: ingress-nginx-admission
  40. namespace: ingress-nginx
  41. ---
  42. apiVersion: rbac.authorization.k8s.io/v1
  43. kind: Role
  44. metadata:
  45. labels:
  46. app.kubernetes.io/component: controller
  47. app.kubernetes.io/instance: ingress-nginx
  48. app.kubernetes.io/managed-by: Helm
  49. app.kubernetes.io/name: ingress-nginx
  50. app.kubernetes.io/part-of: ingress-nginx
  51. app.kubernetes.io/version: 1.1.2
  52. helm.sh/chart: ingress-nginx-4.0.18
  53. name: ingress-nginx
  54. namespace: ingress-nginx
  55. rules:
  56. - apiGroups:
  57. - ""
  58. resources:
  59. - namespaces
  60. verbs:
  61. - get
  62. - apiGroups:
  63. - ""
  64. resources:
  65. - configmaps
  66. - pods
  67. - secrets
  68. - endpoints
  69. verbs:
  70. - get
  71. - list
  72. - watch
  73. - apiGroups:
  74. - ""
  75. resources:
  76. - services
  77. verbs:
  78. - get
  79. - list
  80. - watch
  81. - apiGroups:
  82. - networking.k8s.io
  83. resources:
  84. - ingresses
  85. verbs:
  86. - get
  87. - list
  88. - watch
  89. - apiGroups:
  90. - networking.k8s.io
  91. resources:
  92. - ingresses/status
  93. verbs:
  94. - update
  95. - apiGroups:
  96. - networking.k8s.io
  97. resources:
  98. - ingressclasses
  99. verbs:
  100. - get
  101. - list
  102. - watch
  103. - apiGroups:
  104. - ""
  105. resourceNames:
  106. - ingress-controller-leader
  107. resources:
  108. - configmaps
  109. verbs:
  110. - get
  111. - update
  112. - apiGroups:
  113. - ""
  114. resources:
  115. - configmaps
  116. verbs:
  117. - create
  118. - apiGroups:
  119. - ""
  120. resources:
  121. - events
  122. verbs:
  123. - create
  124. - patch
  125. ---
  126. apiVersion: rbac.authorization.k8s.io/v1
  127. kind: Role
  128. metadata:
  129. annotations:
  130. helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
  131. helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
  132. labels:
  133. app.kubernetes.io/component: admission-webhook
  134. app.kubernetes.io/instance: ingress-nginx
  135. app.kubernetes.io/managed-by: Helm
  136. app.kubernetes.io/name: ingress-nginx
  137. app.kubernetes.io/part-of: ingress-nginx
  138. app.kubernetes.io/version: 1.1.2
  139. helm.sh/chart: ingress-nginx-4.0.18
  140. name: ingress-nginx-admission
  141. namespace: ingress-nginx
  142. rules:
  143. - apiGroups:
  144. - ""
  145. resources:
  146. - secrets
  147. verbs:
  148. - get
  149. - create
  150. ---
  151. apiVersion: rbac.authorization.k8s.io/v1
  152. kind: ClusterRole
  153. metadata:
  154. labels:
  155. app.kubernetes.io/instance: ingress-nginx
  156. app.kubernetes.io/managed-by: Helm
  157. app.kubernetes.io/name: ingress-nginx
  158. app.kubernetes.io/part-of: ingress-nginx
  159. app.kubernetes.io/version: 1.1.2
  160. helm.sh/chart: ingress-nginx-4.0.18
  161. name: ingress-nginx
  162. rules:
  163. - apiGroups:
  164. - ""
  165. resources:
  166. - configmaps
  167. - endpoints
  168. - nodes
  169. - pods
  170. - secrets
  171. - namespaces
  172. verbs:
  173. - list
  174. - watch
  175. - apiGroups:
  176. - ""
  177. resources:
  178. - nodes
  179. verbs:
  180. - get
  181. - apiGroups:
  182. - ""
  183. resources:
  184. - services
  185. verbs:
  186. - get
  187. - list
  188. - watch
  189. - apiGroups:
  190. - networking.k8s.io
  191. resources:
  192. - ingresses
  193. verbs:
  194. - get
  195. - list
  196. - watch
  197. - apiGroups:
  198. - ""
  199. resources:
  200. - events
  201. verbs:
  202. - create
  203. - patch
  204. - apiGroups:
  205. - networking.k8s.io
  206. resources:
  207. - ingresses/status
  208. verbs:
  209. - update
  210. - apiGroups:
  211. - networking.k8s.io
  212. resources:
  213. - ingressclasses
  214. verbs:
  215. - get
  216. - list
  217. - watch
  218. ---
  219. apiVersion: rbac.authorization.k8s.io/v1
  220. kind: ClusterRole
  221. metadata:
  222. annotations:
  223. helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
  224. helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
  225. labels:
  226. app.kubernetes.io/component: admission-webhook
  227. app.kubernetes.io/instance: ingress-nginx
  228. app.kubernetes.io/managed-by: Helm
  229. app.kubernetes.io/name: ingress-nginx
  230. app.kubernetes.io/part-of: ingress-nginx
  231. app.kubernetes.io/version: 1.1.2
  232. helm.sh/chart: ingress-nginx-4.0.18
  233. name: ingress-nginx-admission
  234. rules:
  235. - apiGroups:
  236. - admissionregistration.k8s.io
  237. resources:
  238. - validatingwebhookconfigurations
  239. verbs:
  240. - get
  241. - update
  242. ---
  243. apiVersion: rbac.authorization.k8s.io/v1
  244. kind: RoleBinding
  245. metadata:
  246. labels:
  247. app.kubernetes.io/component: controller
  248. app.kubernetes.io/instance: ingress-nginx
  249. app.kubernetes.io/managed-by: Helm
  250. app.kubernetes.io/name: ingress-nginx
  251. app.kubernetes.io/part-of: ingress-nginx
  252. app.kubernetes.io/version: 1.1.2
  253. helm.sh/chart: ingress-nginx-4.0.18
  254. name: ingress-nginx
  255. namespace: ingress-nginx
  256. roleRef:
  257. apiGroup: rbac.authorization.k8s.io
  258. kind: Role
  259. name: ingress-nginx
  260. subjects:
  261. - kind: ServiceAccount
  262. name: ingress-nginx
  263. namespace: ingress-nginx
  264. ---
  265. apiVersion: rbac.authorization.k8s.io/v1
  266. kind: RoleBinding
  267. metadata:
  268. annotations:
  269. helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
  270. helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
  271. labels:
  272. app.kubernetes.io/component: admission-webhook
  273. app.kubernetes.io/instance: ingress-nginx
  274. app.kubernetes.io/managed-by: Helm
  275. app.kubernetes.io/name: ingress-nginx
  276. app.kubernetes.io/part-of: ingress-nginx
  277. app.kubernetes.io/version: 1.1.2
  278. helm.sh/chart: ingress-nginx-4.0.18
  279. name: ingress-nginx-admission
  280. namespace: ingress-nginx
  281. roleRef:
  282. apiGroup: rbac.authorization.k8s.io
  283. kind: Role
  284. name: ingress-nginx-admission
  285. subjects:
  286. - kind: ServiceAccount
  287. name: ingress-nginx-admission
  288. namespace: ingress-nginx
  289. ---
  290. apiVersion: rbac.authorization.k8s.io/v1
  291. kind: ClusterRoleBinding
  292. metadata:
  293. labels:
  294. app.kubernetes.io/instance: ingress-nginx
  295. app.kubernetes.io/managed-by: Helm
  296. app.kubernetes.io/name: ingress-nginx
  297. app.kubernetes.io/part-of: ingress-nginx
  298. app.kubernetes.io/version: 1.1.2
  299. helm.sh/chart: ingress-nginx-4.0.18
  300. name: ingress-nginx
  301. roleRef:
  302. apiGroup: rbac.authorization.k8s.io
  303. kind: ClusterRole
  304. name: ingress-nginx
  305. subjects:
  306. - kind: ServiceAccount
  307. name: ingress-nginx
  308. namespace: ingress-nginx
  309. ---
  310. apiVersion: rbac.authorization.k8s.io/v1
  311. kind: ClusterRoleBinding
  312. metadata:
  313. annotations:
  314. helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
  315. helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
  316. labels:
  317. app.kubernetes.io/component: admission-webhook
  318. app.kubernetes.io/instance: ingress-nginx
  319. app.kubernetes.io/managed-by: Helm
  320. app.kubernetes.io/name: ingress-nginx
  321. app.kubernetes.io/part-of: ingress-nginx
  322. app.kubernetes.io/version: 1.1.2
  323. helm.sh/chart: ingress-nginx-4.0.18
  324. name: ingress-nginx-admission
  325. roleRef:
  326. apiGroup: rbac.authorization.k8s.io
  327. kind: ClusterRole
  328. name: ingress-nginx-admission
  329. subjects:
  330. - kind: ServiceAccount
  331. name: ingress-nginx-admission
  332. namespace: ingress-nginx
  333. ---
  334. apiVersion: v1
  335. data:
  336. allow-snippet-annotations: "true"
  337. kind: ConfigMap
  338. metadata:
  339. labels:
  340. app.kubernetes.io/component: controller
  341. app.kubernetes.io/instance: ingress-nginx
  342. app.kubernetes.io/managed-by: Helm
  343. app.kubernetes.io/name: ingress-nginx
  344. app.kubernetes.io/part-of: ingress-nginx
  345. app.kubernetes.io/version: 1.1.2
  346. helm.sh/chart: ingress-nginx-4.0.18
  347. name: ingress-nginx-controller
  348. namespace: ingress-nginx
  349. ---
  350. apiVersion: v1
  351. kind: Service
  352. metadata:
  353. labels:
  354. app.kubernetes.io/component: controller
  355. app.kubernetes.io/instance: ingress-nginx
  356. app.kubernetes.io/managed-by: Helm
  357. app.kubernetes.io/name: ingress-nginx
  358. app.kubernetes.io/part-of: ingress-nginx
  359. app.kubernetes.io/version: 1.1.2
  360. helm.sh/chart: ingress-nginx-4.0.18
  361. name: ingress-nginx-controller
  362. namespace: ingress-nginx
  363. spec:
  364. ipFamilies:
  365. - IPv4
  366. ipFamilyPolicy: SingleStack
  367. ports:
  368. - appProtocol: http
  369. name: http
  370. port: 80
  371. protocol: TCP
  372. targetPort: http
  373. - appProtocol: https
  374. name: https
  375. port: 443
  376. protocol: TCP
  377. targetPort: https
  378. selector:
  379. app.kubernetes.io/component: controller
  380. app.kubernetes.io/instance: ingress-nginx
  381. app.kubernetes.io/name: ingress-nginx
  382. type: ClusterIP # NodePort
  383. ---
  384. apiVersion: v1
  385. kind: Service
  386. metadata:
  387. labels:
  388. app.kubernetes.io/component: controller
  389. app.kubernetes.io/instance: ingress-nginx
  390. app.kubernetes.io/managed-by: Helm
  391. app.kubernetes.io/name: ingress-nginx
  392. app.kubernetes.io/part-of: ingress-nginx
  393. app.kubernetes.io/version: 1.1.2
  394. helm.sh/chart: ingress-nginx-4.0.18
  395. name: ingress-nginx-controller-admission
  396. namespace: ingress-nginx
  397. spec:
  398. ports:
  399. - appProtocol: https
  400. name: https-webhook
  401. port: 443
  402. targetPort: webhook
  403. selector:
  404. app.kubernetes.io/component: controller
  405. app.kubernetes.io/instance: ingress-nginx
  406. app.kubernetes.io/name: ingress-nginx
  407. type: ClusterIP
  408. ---
  409. apiVersion: apps/v1
  410. kind: DaemonSet # Deployment
  411. metadata:
  412. labels:
  413. app.kubernetes.io/component: controller
  414. app.kubernetes.io/instance: ingress-nginx
  415. app.kubernetes.io/managed-by: Helm
  416. app.kubernetes.io/name: ingress-nginx
  417. app.kubernetes.io/part-of: ingress-nginx
  418. app.kubernetes.io/version: 1.1.2
  419. helm.sh/chart: ingress-nginx-4.0.18
  420. name: ingress-nginx-controller
  421. namespace: ingress-nginx
  422. spec:
  423. minReadySeconds: 0
  424. revisionHistoryLimit: 10
  425. selector:
  426. matchLabels:
  427. app.kubernetes.io/component: controller
  428. app.kubernetes.io/instance: ingress-nginx
  429. app.kubernetes.io/name: ingress-nginx
  430. template:
  431. metadata:
  432. labels:
  433. app.kubernetes.io/component: controller
  434. app.kubernetes.io/instance: ingress-nginx
  435. app.kubernetes.io/name: ingress-nginx
  436. spec:
  437. dnsPolicy: ClusterFirstWithHostNet # dns 调整为主机网络 ,原先为 ClusterFirst
  438. hostNetwork: true # 直接让 nginx 占用本机的 80 和 443 端口,这样就可以使用主机网络
  439. containers:
  440. - args:
  441. - /nginx-ingress-controller
  442. - --election-id=ingress-controller-leader
  443. - --controller-class=k8s.io/ingress-nginx
  444. - --ingress-class=nginx
  445. - --report-node-internal-ip-address=true
  446. - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
  447. - --validating-webhook=:8443
  448. - --validating-webhook-certificate=/usr/local/certificates/cert
  449. - --validating-webhook-key=/usr/local/certificates/key
  450. env:
  451. - name: POD_NAME
  452. valueFrom:
  453. fieldRef:
  454. fieldPath: metadata.name
  455. - name: POD_NAMESPACE
  456. valueFrom:
  457. fieldRef:
  458. fieldPath: metadata.namespace
  459. - name: LD_PRELOAD
  460. value: /usr/local/lib/libmimalloc.so
  461. 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
  462. imagePullPolicy: IfNotPresent
  463. lifecycle:
  464. preStop:
  465. exec:
  466. command:
  467. - /wait-shutdown
  468. livenessProbe:
  469. failureThreshold: 5
  470. httpGet:
  471. path: /healthz
  472. port: 10254
  473. scheme: HTTP
  474. initialDelaySeconds: 10
  475. periodSeconds: 10
  476. successThreshold: 1
  477. timeoutSeconds: 1
  478. name: controller
  479. ports:
  480. - containerPort: 80
  481. name: http
  482. protocol: TCP
  483. - containerPort: 443
  484. name: https
  485. protocol: TCP
  486. - containerPort: 8443
  487. name: webhook
  488. protocol: TCP
  489. readinessProbe:
  490. failureThreshold: 3
  491. httpGet:
  492. path: /healthz
  493. port: 10254
  494. scheme: HTTP
  495. initialDelaySeconds: 10
  496. periodSeconds: 10
  497. successThreshold: 1
  498. timeoutSeconds: 1
  499. resources: # 资源限制
  500. requests:
  501. cpu: 100m
  502. memory: 90Mi
  503. limits:
  504. cpu: 500m
  505. memory: 500Mi
  506. securityContext:
  507. allowPrivilegeEscalation: true
  508. capabilities:
  509. add:
  510. - NET_BIND_SERVICE
  511. drop:
  512. - ALL
  513. runAsUser: 101
  514. volumeMounts:
  515. - mountPath: /usr/local/certificates/
  516. name: webhook-cert
  517. readOnly: true
  518. nodeSelector:
  519. node-role: ingress # 以后只需要给某个 node 打上这个标签就可以部署 ingress-nginx 到这个节点上了
  520. # kubernetes.io/os: linux
  521. serviceAccountName: ingress-nginx
  522. terminationGracePeriodSeconds: 300
  523. volumes:
  524. - name: webhook-cert
  525. secret:
  526. secretName: ingress-nginx-admission
  527. ---
  528. apiVersion: batch/v1
  529. kind: Job
  530. metadata:
  531. annotations:
  532. helm.sh/hook: pre-install,pre-upgrade
  533. helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
  534. labels:
  535. app.kubernetes.io/component: admission-webhook
  536. app.kubernetes.io/instance: ingress-nginx
  537. app.kubernetes.io/managed-by: Helm
  538. app.kubernetes.io/name: ingress-nginx
  539. app.kubernetes.io/part-of: ingress-nginx
  540. app.kubernetes.io/version: 1.1.2
  541. helm.sh/chart: ingress-nginx-4.0.18
  542. name: ingress-nginx-admission-create
  543. namespace: ingress-nginx
  544. spec:
  545. template:
  546. metadata:
  547. labels:
  548. app.kubernetes.io/component: admission-webhook
  549. app.kubernetes.io/instance: ingress-nginx
  550. app.kubernetes.io/managed-by: Helm
  551. app.kubernetes.io/name: ingress-nginx
  552. app.kubernetes.io/part-of: ingress-nginx
  553. app.kubernetes.io/version: 1.1.2
  554. helm.sh/chart: ingress-nginx-4.0.18
  555. name: ingress-nginx-admission-create
  556. spec:
  557. containers:
  558. - args:
  559. - create
  560. - --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc
  561. - --namespace=$(POD_NAMESPACE)
  562. - --secret-name=ingress-nginx-admission
  563. env:
  564. - name: POD_NAMESPACE
  565. valueFrom:
  566. fieldRef:
  567. fieldPath: metadata.namespace
  568. 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
  569. imagePullPolicy: IfNotPresent
  570. name: create
  571. securityContext:
  572. allowPrivilegeEscalation: false
  573. nodeSelector:
  574. kubernetes.io/os: linux
  575. restartPolicy: OnFailure
  576. securityContext:
  577. fsGroup: 2000
  578. runAsNonRoot: true
  579. runAsUser: 2000
  580. serviceAccountName: ingress-nginx-admission
  581. ---
  582. apiVersion: batch/v1
  583. kind: Job
  584. metadata:
  585. annotations:
  586. helm.sh/hook: post-install,post-upgrade
  587. helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
  588. labels:
  589. app.kubernetes.io/component: admission-webhook
  590. app.kubernetes.io/instance: ingress-nginx
  591. app.kubernetes.io/managed-by: Helm
  592. app.kubernetes.io/name: ingress-nginx
  593. app.kubernetes.io/part-of: ingress-nginx
  594. app.kubernetes.io/version: 1.1.2
  595. helm.sh/chart: ingress-nginx-4.0.18
  596. name: ingress-nginx-admission-patch
  597. namespace: ingress-nginx
  598. spec:
  599. template:
  600. metadata:
  601. labels:
  602. app.kubernetes.io/component: admission-webhook
  603. app.kubernetes.io/instance: ingress-nginx
  604. app.kubernetes.io/managed-by: Helm
  605. app.kubernetes.io/name: ingress-nginx
  606. app.kubernetes.io/part-of: ingress-nginx
  607. app.kubernetes.io/version: 1.1.2
  608. helm.sh/chart: ingress-nginx-4.0.18
  609. name: ingress-nginx-admission-patch
  610. spec:
  611. containers:
  612. - args:
  613. - patch
  614. - --webhook-name=ingress-nginx-admission
  615. - --namespace=$(POD_NAMESPACE)
  616. - --patch-mutating=false
  617. - --secret-name=ingress-nginx-admission
  618. - --patch-failure-policy=Fail
  619. env:
  620. - name: POD_NAMESPACE
  621. valueFrom:
  622. fieldRef:
  623. fieldPath: metadata.namespace
  624. 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
  625. imagePullPolicy: IfNotPresent
  626. name: patch
  627. securityContext:
  628. allowPrivilegeEscalation: false
  629. nodeSelector:
  630. kubernetes.io/os: linux
  631. restartPolicy: OnFailure
  632. securityContext:
  633. fsGroup: 2000
  634. runAsNonRoot: true
  635. runAsUser: 2000
  636. serviceAccountName: ingress-nginx-admission
  637. ---
  638. apiVersion: networking.k8s.io/v1
  639. kind: IngressClass
  640. metadata:
  641. labels:
  642. app.kubernetes.io/component: controller
  643. app.kubernetes.io/instance: ingress-nginx
  644. app.kubernetes.io/managed-by: Helm
  645. app.kubernetes.io/name: ingress-nginx
  646. app.kubernetes.io/part-of: ingress-nginx
  647. app.kubernetes.io/version: 1.1.2
  648. helm.sh/chart: ingress-nginx-4.0.18
  649. name: nginx
  650. spec:
  651. controller: k8s.io/ingress-nginx
  652. ---
  653. apiVersion: admissionregistration.k8s.io/v1
  654. kind: ValidatingWebhookConfiguration
  655. metadata:
  656. labels:
  657. app.kubernetes.io/component: admission-webhook
  658. app.kubernetes.io/instance: ingress-nginx
  659. app.kubernetes.io/managed-by: Helm
  660. app.kubernetes.io/name: ingress-nginx
  661. app.kubernetes.io/part-of: ingress-nginx
  662. app.kubernetes.io/version: 1.1.2
  663. helm.sh/chart: ingress-nginx-4.0.18
  664. name: ingress-nginx-admission
  665. webhooks:
  666. - admissionReviewVersions:
  667. - v1
  668. clientConfig:
  669. service:
  670. name: ingress-nginx-controller-admission
  671. namespace: ingress-nginx
  672. path: /networking/v1/ingresses
  673. failurePolicy: Fail
  674. matchPolicy: Equivalent
  675. name: validate.nginx.ingress.kubernetes.io
  676. rules:
  677. - apiGroups:
  678. - networking.k8s.io
  679. apiVersions:
  680. - v1
  681. operations:
  682. - CREATE
  683. - UPDATE
  684. resources:
  685. - ingresses
  686. 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
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
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 场景