应用场景

Ingress 是 K8S Service 暴露内部服务的一种方式,比起 ClusterIP,NodePort,LoadBalancer等方式,Ingress 具有较多的优势。ClusterIP 仅限集群内部访问,NodePort 需要额外开放较多端口资源,LoadBalancer 需要云服务商提供支持,Ingress 无需云服务商支持,也无需开放太多端口,是比较好的解决方案。

  • http同端口暴露服务过多,NodePortLoadBlancer不能有效管理域名
  • 快速暴露服务(不需要手动去添加nginx代理文件)

数据流

  • Service-NodePort–> ingress-nginx-controller–>应用svc–>pod

pod:通过Deployment类型,动态调整资源,主要用于容器编排

svc:统一资源,CLUSTER-IP、PORT是固定的,pod调整的时候,svc会动态调整,对用户无感知,端口可以重复

ingress:ingress-nginx这个其实就是一个代理服务器,将svc进行代理,可以想成负载均衡器?

Ingress Controller:实际的pod服务,主要是读取ingress配置信息,动态调整控制器配置

如果Ingress Controller提供的是对外服务, 则实际上实现的是边缘路由器[Endpoint(Pod上)]的功能

服务访问方式

  • NodePort 通过 kube-proxy 暴露的端口进行访问
  • LoadBalancer
  • Ingress

ingress-nginx

  • 定义Ingress之前,需要先部署Ingress Controller
  • controller其实就是一个nginx代理安装在node上面,并且数量是可以控制的(不一定每个node都需要安装),当性能不够的时候可以新增
  • 网上很多文档都是基于:nginx-0.26.1/deploy/static/mandatory.yaml,这个版本是最后一个版本将deploy放在代码目录的,后续版本将deploy迁移到新的controller-xxx 分支上面:deploy/static/provider/cloud/deploy.yaml
  • 新版本的deploy.yaml改动较大,更标准
  • 私有k8s建议使用:controller-xxx/deploy/static/provider/cloud/deploy.yaml
  • 因为main版本有可能是开发版本,存在不稳定因素,所以使用controller-xxx版本
  • 另一个推荐方式:Using Helm 通过Helm安装

版本对比

deploy.yaml 包含了 ingress-nginx-controller 的 service声明,但是需要处理一下,因为 type: LoadBalancer 是不支持的

baremetal 和 main 主要区别就是:type类型

# main分支
https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml

# controller-v0.48.1 分支
https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.48.1/deploy/static/provider/cloud/deploy.yaml

# nginx-0.26.1 分支
https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.26.1/deploy/static/mandatory.yaml

# nginx-0.26.2 分支 这里将 deploy 独立拆分为:controller-xxx 分支
# Deployment documentation moved! See /docs/deploy.

# 目前使用:controller-v0.48.1分支作为发布,建议使用controller版本,因为main版本有可能是开发版本,存在不稳定因素

# controller分支和main分支的区别
helm.sh/chart: ingress-nginx-3.34.0 ==> helm.sh/chart: ingress-nginx-3.35.0

# mandatory.yaml和deploy.yaml的区别较大
# 新增说明文档
# 标签变更:
app.kubernetes.io/part-of: ingress-nginx ==> app.kubernetes.io/instance: ingress-nginx
# 新增标签
helm.sh/chart: ingress-nginx-3.35.0

# 命名更加规范了,切此项新增了较多的标签
kind: ServiceAccount
metadata:
  name: nginx-ingress-serviceaccount
# 改为
kind: ServiceAccount
metadata:
  name: ingress-nginx

发布安装

# 下载
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.48.1/deploy/static/provider/cloud/deploy.yaml

# 单独镜像下载
# docker pull registry.aliyuncs.com/google_containers/nginx-ingress-controller:v0.48.1@sha256:e9fb216ace49dfa4a5983b183067e97496e7a8b307d2093f4278cd550c303899

# 修改源(k8s.gcr.io被墙,无法下载),注意版本对应关系
# k8s.gcr.io/ingress-nginx/controller 对应 registry.aliyuncs.com/google_containers/nginx-ingress-controller
sed -i 's#k8s.gcr.io/ingress-nginx/controller#registry.aliyuncs.com/google_containers/nginx-ingress-controller#g' deploy.yaml

# 发布
kubectl apply -f deploy.yaml

# 检测
kubectl get pods -n ingress-nginx \
  -l app.kubernetes.io/name=ingress-nginx --watch -o wide

deploy.yaml 流程说明

  1. Namespace 创建命名空间,这样可以将相关资源独立出来
  2. ServiceAccount Pod中的进程调用Kubernetes API而设计,创建Namespace的时候会生成一个default值 参考
  3. ConfigMap 保存配置文件,查看:kubectl describe configmap ingress-nginx-controller -n ingress-nginx
  4. ClusterRole 授权,负责整个Kubernetes集群范围内的权限,查看:kubectl describe clusterrole -n ingress-nginx
  5. ClusterRoleBinding 资源/账号绑定对应的ClusterRole权限 subjects对应的资源具有roleRef对应的权限
  6. Role 授权,负责命名空间(namespace)内的权限
  7. RoleBinding 命名空间下的权限绑定
  8. Service 创建服务:ingress-nginx-controller-admission,type: ClusterIP
  9. Service 创建服务:ingress-nginx-controller,type: LoadBalancer 这个服务无法申请EXTERNAL-IP,因为没有自建的负载均衡器
  10. Deployment 创建pod:ingress-nginx
  11. ValidatingWebhookConfiguration 验证钩子,准入钩子(Admission Webhooks) 动态准入控制
  12. ServiceAccount 创建钩子账号 name: ingress-nginx-admission
  13. ClusterRole 集群钩子权限
  14. ClusterRoleBinding 集群钩子权限绑定
  15. Role 钩子权限
  16. RoleBinding 钩子权限绑定
  17. Job name: ingress-nginx-admission-create 创建证书,镜像:kube-webhook-certgen 工作原理
  18. Job name: ingress-nginx-admission-patch 提取ca并写入指定的admission webhook 镜像:kube-webhook-certgen工作原理
# 问题(这里没有本地的LoadBalancer服务,所以无法申请到EXTERNAL-IP)
# kubectl get svc -n ingress-nginx ingress-nginx-controller
apiVersion: v1
kind: Service
  ......
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  type: LoadBalancer
  externalTrafficPolicy: Local

双栈 部署ingress-nginx

https://blog.51cto.com/juestnow/2493608

https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/baremetal/deploy.yaml

Ingress · Kubernetes Handbook - Kubernetes 中文指南/云原生应用架构实践手册 · Jimmy Song

helm安装

# nginx可以改成任意自己需要的名称,比如:plat,gm,web,bbs
# 类似云产品的负载均衡器名称
# controller同样会申请:
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
# 导出配置 helm inspect values ingress-nginx/ingress-nginx > values.yaml
# 使用:--set 替换为使用 -f values.yaml
# externalIPs 指定暴露ip
# ingressClass 这个注解的值,一般是具体 Ingress Controller 所提供的默认值,如 nginx、gce、traefik、kong 等
# 多个Ingress控制器的时候需要指定
helm install hello-world ingress-nginx/ingress-nginx \
  --namespace kube-system \
  --set controller.ingressClass=nginx \
  --set controller.publishService.enabled=true \
  --set controller.service.externalIPs={10.0.26.190}

# 查看
kubectl --namespace kube-system get services -o wide -w hello-world-ingress-nginx-controller

# 删除
helm uninstall --namespace kube-system hello-world

k8s之PodIP、ClusterIP和ExternalIP

Kube:使用IPVS和External IP对K8S集群进行外部负载均衡 - 云+社区 - 腾讯云 (tencent.com)

[k8s]k8s pod的4种网络模式最佳实战(externalIPs ) - _毛台 - 博客园 (cnblogs.com)

NodePort,LoadBalancer还是Ingress?我该如何选择 (qq.com)

kube-apiserver
--service-cluster-ip-range 10.26.0.0/16  # 集群网络的ip段,内网任意节点可以访问,外部需要service提供
--service-node-port-range 3000-29999    # 集群节点的端口段

controller-manager
--service-cluster-ip-range=10.26.0.0/16
--cluster-cidr=172.26.0.0/16     # 节点网络(CNI使用?)

# flanneld 优先读取 --subnet-file 参数定义的配置文件,如果不存在则读取 etcd 配置的网络信息
# /etc/kubernetes/flanneld_subnet.env
FLANNEL_NETWORK=172.26.0.0/16	# CNI大网
FLANNEL_SUBNET=172.26.25.1/24	# 子网

# dockerd 读取 flanneld 生成的子网信息:$DOCKER_NETWORK_OPTIONS
EnvironmentFile=-/etc/kubernetes/flanneld_docker.env
ExecStart=/usr/bin/dockerd $DOCKER_NETWORK_OPTIONS

使用 Service 把前端连接到后端 | Kubernetes

# 国内无法使用gcr.io,所以使用docker非官方源进行测试
docker search hello-go-gke
# docker pull vaikulkaz/hello-go-gke:1.0
gcr.io/google-samples/hello-go-gke:1.0
# 改成
vaikulkaz/hello-go-gke:1.0

LoadBalancer服务是发布服务到互联网的标准方式。在GKE中,它会启动一个Network Load Balancer,分配一个单独的IP地址,将所有流量转发到服务中。

腾讯云叫TKE 腾讯云容器服务(Tencent Kubernetes Engine ,TKE)基于原生kubernetes提供以容器为核心的、高度可扩展的高性能容器管理服务。

所以测试网络不要使用:type: LoadBalancer,而是使用: externalIPs: - 192.168.2.12 # 这是我的一台node的ip

---
apiVersion: v1
kind: Service
metadata:
  name: frontend
spec:
  selector:
    app: hello
    tier: frontend
  ports:
  - protocol: "TCP"
    port: 80
    targetPort: 80
    # 不是公有云的话,不要使用:type: LoadBalancer,因为此类型是向GKE、TKE申请:EXTERNAL-IP
  externalIPs:
  - 10.0.26.190 	# 其中一个node的ip
...
# 效果如下
root@k8s-master-01:~# kubectl get service frontend
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
frontend   ClusterIP   10.26.68.2    10.0.26.190    80/TCP    4s
# 集群内部访问
root@k8s-master-01:~# curl 10.0.26.190
{"message":"Hello"}
# 外部节点访问(缺点:单节点代理访问压力,优点:通过service对后端进行了负载)
root@k8s-master-01:~# curl 10.0.26.190
{"message":"Hello"}
# 浏览器访问
# http://10.0.26.190/

Ingress 控制器

ingress控制器那么多,到底该选哪一个?

你必须具有 Ingress 控制器 才能满足 Ingress 的要求。 仅创建 Ingress 资源本身没有任何效果。

Ingress 控制器:traefik istio nginx enovy

目前Ingress暴露集群内服务的行内公认最好的方式,不过由于其重要地位,世面上有非常多的Ingres Controller

这是一个苹果与橘子的比较。

像Traefik或Nginx这样的边缘代理最好与–Istio利用的代理进行比较。 Istio会自动安装Envoy代理,并与每个吊舱相邻。

Istio在Envoy之外提供了几个更高级别的功能,包括路由,ACLing和服务发现和访问策略*,跨越一组服务*。实际上,它将一系列启用Envoy的服务拼接在一起。这种设计模式通常被称为服务网格

Istio目前仅限于单个集群中的Kubernetes部署,尽管工作已经到位以及时消除这些限制。

  • 部署策略:是否支持ab部署、金丝雀部署、蓝绿部署等

借助Istio Ingress,您可以微调流量路由,服务之间的访问授权,平衡,监控,金丝雀发布等.

不过社区现在更推荐使用Ingress Gateways。

替代方案

你可以通过很多种方式暴露 service 而不必直接使用 ingress:

使用多个 Ingress 控制器

你可以在集群中部署任意数量的 ingress 控制器。 创建 ingress 时,应该使用适当的 ingress.class 注解每个 Ingress 以表明在集群中如果有多个 Ingress 控制器时,应该使用哪个 Ingress 控制器。

如果不定义 ingress.class,云提供商可能使用默认的 Ingress 控制器。

理想情况下,所有 Ingress 控制器都应满足此规范,但各种 Ingress 控制器的操作略有不同。

说明: 确保你查看了 ingress 控制器的文档,以了解选择它的注意事项。

参考