kubernetes | Ingress
2022年3月17日 · 3909 字 · 8 分钟 · Kubernetes
一、引言
在 Kubernetes 中,Ingress 是一种 API 对象,用于管理外部访问集群服务的方式,通常是 HTTP 和 HTTPS 流量。可以将 Ingress 理解为一个智能的路由器,它根据请求的 URL 路径或主机名将流量路由到不同的服务。 主要功能:
路由:Ingress 可以根据请求的 URL 路径或主机名将流量路由到不同的服务。例如,你可以将 example.com/api 的请求路由到一个服务,而将 example.com/app 的请求路由到另一个服务。负载均衡:Ingress 可以在多个后端服务之间分配流量,从而实现负载均衡。SSL/TLS 终止:Ingress 可以处理 SSL/TLS 加密,允许你在 Ingress 控制器中配置证书,而不是在每个服务中配置。基于主机和路径的路由:Ingress 支持基于主机名和路径的路由规则,使得多个服务可以通过同一个 IP 地址和端口进行访问。
NodePort
1、把端口号对外暴露,通过 IP + 端口号 进行访问。
1)使用 Service 里面的 NodePort 实现。
2、NodePort 缺陷
1)在每个节点上都会启动端口,在访问时候通过任何节点,通过节点 IP + 暴露端口号 实现访问。
2)意味着每个端口只能使用一次,一个端口对应一个应用。
3)实际访问中都是用域名,根据不同域名跳转到不同端口服务中。
二、Ingress 概述
通常情况下,service 和 pod 的 IP 仅可在集群内部访问。集群外部的请求需要通过负载均衡转发到 service 在 Node 上暴露的 NodePort 上,然后再由 kube-proxy 将其转发给相关的 Pod。
Ingress 为 Kubernetes 集群中的服务提供了入口,可以提供负载均衡、SSL 终止和基于名称的虚拟主机,在生产环境中常用的 Ingress 有 Treafik、Nginx、HAProxy、Istio 等。在 Kubernetes v1.1 版中添加的 Ingress 用于从集群外部到集群内部 Service 的 HTTP 和 HTTPS 路由,流量从 Internet 到 Ingress 再到 Services 最后到 Pod 上,通常情况下,Ingress 部署在所有的 Node 节点上。Ingress 可以配置提供服务外部访问的 URL、负载均衡、终止 SSL,并提供基于域名的虚拟主机。但 Ingress 不会暴露任意端口或协议。
三、Ingress 工作流程
Ingress 公开了从集群外部到集群内服务的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 资源上定义的规则控制。
可以将 Ingress 配置为服务提供外部可访问的 URL、负载均衡流量、终止 SSL/TLS,以及提供基于名称的虚拟主机等能力。 Ingress 控制器 通常负责通过负载均衡器来实现 Ingress,尽管它也可以配置边缘路由器或其他前端来帮助处理流量。
Ingress 不会公开任意端口或协议。 将 HTTP 和 HTTPS 以外的服务公开到 Internet 时,通常使用 Service.Type=NodePort 或 Service.Type=LoadBalancer 类型的服务。
四、Ingress 控制器 (官方维护)
4.1、官方维护 Ingress 控制器
为了让 Ingress 资源工作,集群必须有一个正在运行的 Ingress 控制器。
与作为 kube-controller-manager 可执行文件的一部分运行的其他类型的控制器不同, Ingress 控制器不是随集群自动启动的。 基于此页面,你可选择最适合你的集群的 ingress 控制器实现。
Kubernetes 作为一个项目,目前支持和维护 AWS, GCE 和 nginx Ingress 控制器。
4.2、其他 Ingress 控制器
AKS应用程序网关 Ingress 控制器 是一个配置 Azure 应用程序网关 的 Ingress 控制器。Ambassador API网关是一个基于 Envoy 的 Ingress 控制器。Apache APISIX Ingress控制器 是一个基于 Apache APISIX 网关 的 Ingress 控制器。Avi Kubernetes Operator使用 VMware NSX Advanced Load Balancer 提供第 4 到第 7 层的负载均衡。BFE Ingress控制器 是一个基于 BFE 的 Ingress 控制器。Citrix Ingress控制器 可以用来与 Citrix Application Delivery Controller 一起使用。Contour是一个基于 Envoy 的 Ingress 控制器。EnRoute是一个基于 Envoy API 网关, 可以作为 Ingress 控制器来执行。Easegress IngressController是一个基于 Easegress API 网关,可以作为 Ingress 控制器来执行。F5 BIG-IP的用于 Kubernetes 的容器 Ingress 服务 让你能够使用 Ingress 来配置 F5 BIG-IP 虚拟服务器。Gloo是一个开源的、基于 Envoy 的 Ingress 控制器,能够提供 API 网关功能,HAProxy Ingress针对 HAProxy 的 Ingress 控制器。
用于 Kubernetes 的HAProxy Ingress控制器 也是一个针对 HAProxy 的 Ingress 控制器。Istio Ingress是一个基于 Istio 的 Ingress 控制器。
用于 Kubernetes 的Kong Ingress控制器 是一个用来驱动 Kong Gateway 的 Ingress 控制器。
用于 Kubernetes 的NGINX Ingress控制器 能够与 NGINX Web 服务器(作为代理) 一起使用。Skipper HTTP路由器和反向代理可用于服务组装,支持包括 Kubernetes Ingress 这类使用场景, 设计用来作为构造你自己的定制代理的库。Traefik Kubernetes Ingress提供程序 是一个用于 Traefik 代理的 Ingress 控制器。Tyk Operator使用自定义资源扩展 Ingress,为之带来 API 管理能力。Tyk Operator 使用开源的 Tyk Gateway & Tyk Cloud 控制面。Voyager是一个针对 HAProxy 的 Ingress 控制器。
五、安装 Nginx-Ingress
访问架构图:

5.1、helm 安装 Ingress
# 1. 新建 ingress 存放目录
[root@kubernetes-master-001 ~]# mkdir ingress && cd ingress
# 2. 添加官方 ingress-nginx 的 helm 仓库
[root@kubernetes-master-001 ~/ingress]# helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
"ingress-nginx" has been added to your repositories
# 3. 搜索仓库中已有的 ingress-nginx 版本信息 (建议安装 0.40.2 以上的版本)
[root@kubernetes-master-001 ~/ingress]# helm search repo ingress-nginx
NAME CHART VERSION APP VERSION DESCRIPTION
ingress-nginx/ingress-nginx 4.0.9 1.0.5 Ingress controller for Kubernetes using NGINX a...
# 4. 拉取 ingress-nginx 的包
helm pull [repo 名称 /chart 名称]
[root@kubernetes-master-001 ~/ingress]# helm pull ingress-nginx/ingress-nginx
# 5. 解压包,修改 values.yaml 配置文件
[root@kubernetes-master-001 ~/ingress]# tar -xf ingress-nginx-4.0.9.tgz && cd ingress-nginx
# 6. 修改 values.yaml
# 修改镜像
# 注释掉 registry,image,digest,并打开 repository
repository: willdockerhub/ingress-nginx-controller
tag: "v1.0.5"
repository: jettech/kube-webhook-certgen
tag: v1.5.2
repository: mirrorgooglecontainers/defaultbackend-amd64
tag: "1.5"
# 修改 dns 策略
dnsPolicy: ClusterFirstWithHostNet
# 使用 hostNetwork, 即使用宿主机上的端口 80 443
hostNetwork: false
# 使用 DaemonSet, 将 ingress 部署在指定节点上
kind: DaemonSet
# 节点选择,将需要部署的节点打上 ingress=true 的 label
nodeSelector:
kubernetes.io/os: linux
ingress: "true"
# 选择节点打 label
kubectl label node node01 ingress=true
# 创建一个 ingress 的 namespace
kubectl create ns ingress-nginx
# 创建 ingress
# 如果提示 cannot re-use a name that is still in use
# 则先 helm uninstall ingress-nginx --namespace ingress-nginx
# 如果安装完成后无法访问其他节点日志,则需要配置 hosts,将所有节点配置到 hosts 中即可
helm install ingress-nginx ingress-nginx -n ingress-nginx
5.2、直接部署安装
#1. 部署 ingress-nginx 比较简单,直接下载 github 上的 deploy.yaml 部署即可,由于网络问题镜像如果拉取失败,我们可以直接去 GitHub 复制这个 yaml 文件
[root@kubernetes-master-001 ~]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.0.0/deploy/static/provider/baremetal/deploy.yaml
#2. 修改镜像地址
[root@kubernetes-master-001 ~]# sed -i's@k8s.gcr.io/ingress-nginx/controller:v1.0.0\(.*\)@willdockerhub/ingress-nginx-controller:v1.0.0@' deploy.yaml
[root@kubernetes-master-001 ~]# sed -i's@k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0\(.*\)$@hzde0128/kube-webhook-certgen:v1.0@' deploy.yaml
#3. 安装 ingress-nginx
[root@kubernetes-master-001 ~]# kubectl apply -f ingress-1.0.0.yaml
namespace/ingress-nginx created
serviceaccount/ingress-nginx created
configmap/ingress-nginx-controller created
clusterrole.rbac.authorization.k8s.io/ingress-nginx configured
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx configured
role.rbac.authorization.k8s.io/ingress-nginx created
rolebinding.rbac.authorization.k8s.io/ingress-nginx created
service/ingress-nginx-controller-admission created
service/ingress-nginx-controller created
deployment.apps/ingress-nginx-controller created
ingressclass.networking.k8s.io/nginx configured
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission configured
serviceaccount/ingress-nginx-admission created
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission configured
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission configured
role.rbac.authorization.k8s.io/ingress-nginx-admission created
rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
job.batch/ingress-nginx-admission-create created
job.batch/ingress-nginx-admission-patch created
#4. 查看 ingress-nginx 状态
[root@kubernetes-master-001 ~]# kubectl get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-fgcrk 0/1 Completed 0 20m
ingress-nginx-admission-patch-b6d96 0/1 Completed 0 20m
ingress-nginx-controller-6b64bc6f47-4sd7g 1/1 Running 0 20m
[root@kubernetes-master-001 ~]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT (S) AGE
ingress-nginx-controller NodePort 10.107.105.141 <none> 80:31386/TCP,443:31083/TCP 20m
ingress-nginx-controller-admission ClusterIP 10.103.7.53 <none> 443/TCP 20m
六、部署示例验证
6.1、创建 Pod
[root@kubernetes-master-001 ~]# kubectl create deployment web --image=nginx
deployment.apps/web created
[root@kubernetes-master-001 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
web-96d5df5c8-prps4 1/1 Running 0 44s
6.2、对外暴露应用
[root@kubernetes-master-001 ~]# kubectl expose deployment web --port=80 --target-port=80 --type=NodePort
service/web exposed
[root@kubernetes-master-001 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT (S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4d23h
web NodePort 10.106.214.3 <none> 80:30645/TCP 4d23h
6.3、创建 Ingress 规则
ingress-http.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx" # 最关键的标记。K8s 本身不自带 Ingress 的“处理能力”,你必须安装一个 Ingress Controller(如 Nginx Ingress)。这个注解告诉集群:“这条路由规则由 Nginx 控制器来接管”。
spec:
rules:
- host: example.ingredemo.com # 只有 HTTP 请求头中的 Host 字段匹配 example.ingredemo.com 时,规则才会生效。
http:
paths:
- path: "/"
pathType: Prefix # Prefix:前缀匹配。例如 / 会匹配所有以 / 开头的请求(即所有请求)。
backend:
service:
name: web
port:
number: 80
操作
[root@kubernetes-master-001 ~]# kubectl apply -f ingress-http.yaml
ingress.networking.k8s.io/example-ingress created
[root@kubernetes-master-001 ~]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT (S) AGE
ingress-nginx-controller NodePort 10.107.105.141 <none> 80:31386/TCP,443:31083/TCP 3h55m
ingress-nginx-controller-admission ClusterIP 10.103.7.53 <none> 443/TCP 3h55m
[root@kubernetes-master-001 ~]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
example-ingress <none> example.ingredemo.com 80 5s
七、Ingress-Nginx 优化
上面每次部署 ingres-nginx 都随机一个 nodePort ,而使用 ingres-nginx 访问的时候也要以 域名:端口 的形式去访问如何直接使用域名去访问呢?下面介绍 hostNetwork 的方式部署 Ingress-Nginx。
7.1、下载 Ingress-Nginx
[root@kubernetes-master-001 ~]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.0.0/deploy/static/provider/baremetal/deploy.yaml
[root@kubernetes-master-001 ~]# sed -i's@k8s.gcr.io/ingress-nginx/controller:v1.0.0\(.*\)@willdockerhub/ingress-nginx-controller:v1.0.0@' deploy.yaml
[root@kubernetes-master-001 ~]# sed -i's@k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0\(.*\)$@hzde0128/kube-webhook-certgen:v1.0@' deploy.yaml
7.2、使用 hostNetwork
默认 ingress-nginx 随机提供 nodeport 端口,开启 hostNetwork 启用 80、443 端口。 修改 Deployment 下面的 spec
参数如下:
spec:
hostNetwork: true # 新增
dnsPolicy: ClusterFirst
containers:
- name: controller
image: willdockerhub/ingress-nginx-controller:v1.0.0 # 更换镜像地址
imagePullPolicy: IfNotPresent
lifecycle:
7.3、修改负载均衡问题
把 kind: Deployment 改为 kind: DaemonSet 模式,这样每台 node 上都有 ingress-nginx-controller pod 副本。
参数如下:
# Source: ingress-nginx/templates/controller-deployment.yaml
apiVersion: apps/v1
#kind: Deployment # 注释
kind: DaemonSet # 新增
metadata:
labels:
helm.sh/chart: ingress-nginx-4.0.1
7.4、修改 ingressClass 问题
如果不关心 ingressClass 或者很多没有 ingressClass 配置的 ingress 对象,
添加参数 ingress-controller --watch-ingress-without-class=true 。
args:
- /nginx-ingress-controller
- --publish-service=$(POD_NAMESPACE)/ingress-nginx-dev-v1-test-controller
- --election-id=ingress-controller-leader
- --controller-class=k8s.io/ingress-nginx
- --configmap=$(POD_NAMESPACE)/ingress-nginx-dev-v1-test-controller
- --validating-webhook=:8443
- --validating-webhook-certificate=/usr/local/certificates/cert
- --validating-webhook-key=/usr/local/certificates/key
- --watch-ingress-without-class=true # 新增
7.5. 部署检查 ingress
#1. 部署 ingress
[root@kubernetes-master-001 ~]# kubectl apply -f deploy.yaml
namespace/ingress-nginx created
serviceaccount/ingress-nginx created
configmap/ingress-nginx-controller created
clusterrole.rbac.authorization.k8s.io/ingress-nginx unchanged
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx unchanged
role.rbac.authorization.k8s.io/ingress-nginx created
rolebinding.rbac.authorization.k8s.io/ingress-nginx created
service/ingress-nginx-controller-admission created
service/ingress-nginx-controller created
daemonset.apps/ingress-nginx-controller created
ingressclass.networking.k8s.io/nginx unchanged
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission configured
serviceaccount/ingress-nginx-admission created
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission unchanged
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission unchanged
role.rbac.authorization.k8s.io/ingress-nginx-admission created
rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
job.batch/ingress-nginx-admission-create created
job.batch/ingress-nginx-admission-patch created
#2. 部署 pod
[root@kubernetes-master-001 ~]# kubectl get pod -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-admission-create-cm5h4 0/1 Completed 0 4m4s 10.244.1.97 kubernetes-node-002 <none> <none>
ingress-nginx-admission-patch-49wc7 0/1 Completed 1 4m4s 10.244.1.98 kubernetes-node-002 <none> <none>
ingress-nginx-controller-cks5x 1/1 Running 0 4m5s 192.168.13.102 kubernetes-node-002 <none> <none>
ingress-nginx-controller-cqgfb 1/1 Running 0 4m4s 192.168.13.101 kubernetes-node-001 <none> <none>
#3.node 节点检查端口
[root@kubernetes-node-002 ~]# netstat -lntp |grep 443
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 70037/nginx: master
tcp6 0 0 :::8443 :::* LISTEN 70016/nginx-ingress
tcp6 0 0 :::443 :::* LISTEN 70037/nginx: master
[root@kubernetes-node-002 ~]# netstat -lntp |grep 80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 70037/nginx: master
tcp6 0 0 :::80 :::* LISTEN 70037/nginx: master
[root@kubernetes-node-001 ~]# netstat -lntp |grep 443
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 93825/nginx: master
tcp6 0 0 :::8443 :::* LISTEN 93765/nginx-ingress
tcp6 0 0 :::443 :::* LISTEN 93825/nginx: master
[root@kubernetes-node-001 ~]# netstat -lntp |grep 80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 93825/nginx: master
tcp6 0 0 :::80 :::* LISTEN 93825/nginx: master
八、Ingress 与 Ingress-Controller
8.1、Ingress 与 Ingress-Controller 的关系
在 Kubernetes 中,它们是“配置”与“程序”的关系:
Ingress (资源对象):就像是一份路由说明书。它只是一条记录,告诉集群:example.com 应该去访问 web 服务。它存放在 etcd 数据库里,自己不会干活。Nginx-Ingress-Controller (执行程序):这是真正的反向代理服务器。它是一个一直运行的 Pod,任务是:- 时刻盯着 API Server:“有没有新的 Ingress 说明书(YAML)发布?”
- 一旦发现新规则,它就自动修改内部的
nginx.conf。 - 执行
nginx -s reload,让配置生效,开始引导流量。
8.2、为什么要以 Pod 形式运行
将 Nginx 运行在 Pod 里有几个核心优势:
- 动态扩容:如果你的网站流量暴增,可以直接增加 Ingress Pod 的副本数。
- 高可用:如果承载 Nginx 的某个节点挂了,K8s 会自动在其他节点重启这个 Pod,保证入口不挂。
- 自愈性:Nginx 配置写错导致进程崩溃?K8s 会帮你自动拉起。
8.3、安装方式
Kubernetes 官方代码库里并不包含 Nginx 的二进制文件,它只定义了 Ingress 的标准。
- 如果你用的是自建集群(二进制或 Kubeadm):你必须手动部署,通常是执行官方提供的 deploy.yaml 或者使用 Helm。
- 如果你用的是云平台(如阿里云 ACK):云厂商通常会在创建集群时询问你是否勾选“安装 Ingress 组件”,它们会帮你预装好。
8.4、外部流量是怎么进到这个 Pod
既然 Nginx 运行在 Pod 里,它也有一个 Pod IP。那外面的用户怎么访问这个 Pod 呢?通常有三种方案:
- NodePort:给 Nginx Pod 再套一个 Service,暴露一个 30000+ 的端口。
- LoadBalancer:配合云厂商的负载均衡器(SLB),直接给 Nginx Pod 映射一个公网 IP。
- HostNetwork:让 Nginx Pod 直接占用宿主机的 80/443 端口。这对性能最好,但一个节点只能跑一个副本。
8.5、核心工作流
- 编写 YAML:定义域名和路径。
- Controller 监测:运行在 Pod 里的 Nginx-Ingress-Controller 发现了你的 YAML。
- 配置转化:它把 YAML 转化成 nginx.conf 里的 upstream 和 server 块。
- 流量分发:外部请求打到 Nginx Pod -> Nginx 根据配置 -> 直接转发给后端的业务 Pod IP。
8.6、Ingress 规则
查看集群中定义了哪些 IngressClass
kubectl get ingressclass
输出示例:
| NAME | CONTROLLER |
|---|---|
nginx-public | k8s.io/ingress-nginx-public |
nginx-internal | k8s.io/ingress-nginx-internal |