# Ingress解析
Ingress 是从Kubernetes集群外部访问集群内部服务的入口,这篇文章部分译自Kubernetes官方文档[Ingress Resource](https://kubernetes.io/docs/concepts/services-networking/ingress/),后面的章节会讲到使用[Traefik](https://github.com/containous/traefik)来做Ingress controller,文章末尾给出了几个相关链接。
**术语**
在本篇文章中你将会看到一些在其他地方被交叉使用的术语,为了防止产生歧义,我们首先来澄清下。
- 节点:Kubernetes集群中的一台物理机或者虚拟机。
- 集群:位于Internet防火墙后的节点,这是kubernetes管理的主要计算资源。
- 边界路由器:为集群强制执行防火墙策略的路由器。 这可能是由云提供商或物理硬件管理的网关。
- 集群网络:一组逻辑或物理链接,可根据Kubernetes[网络模型](https://kubernetes.io/docs/admin/networking/)实现群集内的通信。 集群网络的实现包括Overlay模型的 [flannel](https://github.com/coreos/flannel#flannel) 和基于SDN的OVS。
- 服务:使用标签选择器标识一组pod成为的Kubernetes[服务](https://kubernetes.io/docs/user-guide/services/)。 除非另有说明,否则服务假定在集群网络内仅可通过虚拟IP访问。
## 什么是Ingress?
通常情况下,service和pod仅可在集群内部网络中通过IP地址访问。所有到达边界路由器的流量或被丢弃或被转发到其他地方。从概念上讲,可能像下面这样:
```
internet
|
------------
[ Services ]
```
Ingress是授权入站连接到达集群服务的规则集合。
```
internet
|
[ Ingress ]
--|-----|--
[ Services ]
```
你可以给Ingress配置提供外部可访问的URL、负载均衡、SSL、基于名称的虚拟主机等。用户通过POST Ingress资源到API server的方式来请求ingress。 [Ingress controller](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-controllers)负责实现Ingress,通常使用负载平衡器,它还可以配置边界路由和其他前端,这有助于以HA方式处理流量。
## 先决条件
在使用Ingress resource之前,有必要先了解下面几件事情。Ingress是beta版本的resource,在kubernetes1.1之前还没有。你需要一个`Ingress Controller`来实现`Ingress`,单纯的创建一个`Ingress`没有任何意义。
GCE/GKE会在master节点上部署一个ingress controller。你可以在一个pod中部署任意个自定义的ingress controller。你必须正确地annotate每个ingress,比如 [运行多个ingress controller](https://git.k8s.io/ingress#running-multiple-ingress-controllers) 和 [关闭glbc](https://git.k8s.io/ingress-gce/BETA_LIMITATIONS.md#disabling-glbc).
确定你已经阅读了Ingress controller的[beta版本限制](https://github.com/kubernetes/ingress-gce/blob/master/BETA_LIMITATIONS.md#glbc-beta-limitations)。在非GCE/GKE的环境中,你需要在pod中[部署一个controller](https://git.k8s.io/ingress-nginx/README.md)。
## Ingress Resource
最简化的Ingress配置:
```yaml
1: apiVersion: extensions/v1beta1
2: kind: Ingress
3: metadata:
4: name: test-ingress
5: spec:
6: rules:
7: - http:
8: paths:
9: - path: /testpath
10: backend:
11: serviceName: test
12: servicePort: 80
```
*如果你没有配置Ingress controller就将其POST到API server不会有任何用处*
**配置说明**
**1-4行**:跟Kubernetes的其他配置一样,ingress的配置也需要`apiVersion`,`kind`和`metadata`字段。配置文件的详细说明请查看[部署应用](https://kubernetes.io/docs/user-guide/deploying-applications), [配置容器](https://kubernetes.io/docs/user-guide/configuring-containers)和 [使用resources](https://kubernetes.io/docs/user-guide/working-with-resources).
**5-7行**: Ingress [spec](https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#spec-and-status) 中包含配置一个loadbalancer或proxy server的所有信息。最重要的是,它包含了一个匹配所有入站请求的规则列表。目前ingress只支持http规则。
**8-9行**:每条http规则包含以下信息:一个`host`配置项(比如for.bar.com,在这个例子中默认是*),`path`列表(比如:/testpath),每个path都关联一个`backend`(比如test:80)。在loadbalancer将流量转发到backend之前,所有的入站请求都要先匹配host和path。
**10-12行**:正如 [services doc](https://kubernetes.io/docs/user-guide/services)中描述的那样,backend是一个`service:port`的组合。Ingress的流量被转发到它所匹配的backend。
**全局参数**:为了简单起见,Ingress示例中没有全局参数,请参阅资源完整定义的[api参考](https://releases.k8s.io/master/staging/src/k8s.io/api/extensions/v1beta1/types.go)。 在所有请求都不能跟spec中的path匹配的情况下,请求被发送到Ingress controller的默认后端,可以指定全局缺省backend。
## Ingress controllers
为了使Ingress正常工作,集群中必须运行Ingress controller。 这与其他类型的控制器不同,其他类型的控制器通常作为`kube-controller-manager`二进制文件的一部分运行,在集群启动时自动启动。 你需要选择最适合自己集群的Ingress controller或者自己实现一个。
- kubernetes当前支持并维护[GCE](https://git.k8s.io/ingress-gce/README.md)和[nginx](https://git.k8s.io/ingress-nginx/README.md)两种controller.
- F5(公司)[支持并维护](https://support.f5.com/csp/article/K86859508) [F5 BIG-IP Controller for Kubernetes](http://clouddocs.f5.com/products/connectors/k8s-bigip-ctlr/latest).
- [Kong](https://konghq.com/) 同时支持并维护[社区版](https://discuss.konghq.com/c/kubernetes)与[企业版](https://konghq.com/api-customer-success/)的 [Kong Ingress Controller for Kubernetes](https://konghq.com/blog/kubernetes-ingress-controller-for-kong/).
- [Traefik](https://github.com/containous/traefik) 是功能齐全的 ingress controller([Let’s Encrypt](https://letsencrypt.org/), secrets, http2, websocket…), [Containous](https://containo.us/services) 也对其提供商业支持。
- [Istio](https://istio.io/zh) 使用CRD Gateway来[控制Ingress流量](https://istio.io/zh/docs/tasks/traffic-management/ingress/)。
## 在你开始前
以下文档描述了Ingress资源中公开的一组跨平台功能。 理想情况下,所有的Ingress controller都应该符合这个规范,但是我们还没有实现。 GCE和nginx控制器的文档分别在[这里](https://git.k8s.io/ingress-gce/README.md)和[这里](https://git.k8s.io/ingress-nginx/README.md)。如果您使用F5 BIG-IP controller, 请参看[这里](http://clouddocs.f5.com/containers/latest/kubernetes/kctlr-k8s-ingress-ctlr.html).
**确保您查看控制器特定的文档,以便您了解每个文档的注意事项。**
## Ingress类型
### 单Service Ingress
Kubernetes中已经存在一些概念可以暴露单个service(查看[替代方案](https://kubernetes.io/docs/concepts/services-networking/ingress/#alternatives)),但是你仍然可以通过Ingress来实现,通过指定一个没有rule的默认backend的方式。
ingress.yaml定义文件:
```yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
backend:
serviceName: testsvc
servicePort: 80
```
使用`kubectl create -f`命令创建,然后查看ingress:
```bash
$ kubectl get ing
NAME RULE BACKEND ADDRESS
test-ingress - testsvc:80 107.178.254.228
```
`107.178.254.228`就是Ingress controller为了实现Ingress而分配的IP地址。`RULE`列表示所有发送给该IP的流量都被转发到了`BACKEND`所列的Kubernetes service上。
### 简单展开
如前面描述的那样,kubernetes pod中的IP只在集群网络内部可见,我们需要在边界设置一个东西,让它能够接收ingress的流量并将它们转发到正确的端点上。这个东西一般是高可用的loadbalancer。使用Ingress能够允许你将loadbalancer的个数降低到最少,例如,假如你想要创建这样的一个设置:
```
foo.bar.com -> 178.91.123.132 -> / foo s1:80
/ bar s2:80
```
你需要一个这样的ingress:
```yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo
backend:
serviceName: s1
servicePort: 80
- path: /bar
backend:
serviceName: s2
servicePort: 80
```
使用`kubectl create -f`创建完ingress后:
```bash
$ kubectl get ing
NAME RULE BACKEND ADDRESS
test -
foo.bar.com
/foo s1:80
/bar s2:80
```
只要服务(s1,s2)存在,Ingress controller就会将提供一个满足该Ingress的特定loadbalancer实现。 这一步完成后,您将在Ingress的最后一列看到loadbalancer的地址。
### 基于名称的虚拟主机
Name-based的虚拟主机在同一个IP地址下拥有多个主机名。
```
foo.bar.com --| |-> foo.bar.com s1:80
| 178.91.123.132 |
bar.foo.com --| |-> bar.foo.com s2:80
```
下面这个ingress说明基于[Host header](https://tools.ietf.org/html/rfc7230#section-5.4)的后端loadbalancer的路由请求:
```yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
serviceName: s1
servicePort: 80
- host: bar.foo.com
http:
paths:
- backend:
serviceName: s2
servicePort: 80
```
**默认backend**:一个没有rule的ingress,如前面章节中所示,所有流量都将发送到一个默认backend。你可以用该技巧通知loadbalancer如何找到你网站的404页面,通过制定一些列rule和一个默认backend的方式。如果请求header中的host不能跟ingress中的host匹配,并且/或请求的URL不能与任何一个path匹配,则流量将路由到你的默认backend。
### TLS
你可以通过指定包含TLS私钥和证书的[secret](https://kubernetes.io/docs/user-guide/secrets)来加密Ingress。 目前,Ingress仅支持单个TLS端口443,并假定TLS termination。 如果Ingress中的TLS配置部分指定了不同的主机,则它们将根据通过SNI TLS扩展指定的主机名(假如Ingress controller支持SNI)在多个相同端口上进行复用。 TLS secret中必须包含名为`tls.crt`和`tls.key`的密钥,这里面包含了用于TLS的证书和私钥,例如:
```yaml
apiVersion: v1
data:
tls.crt: base64 encoded cert
tls.key: base64 encoded key
kind: Secret
metadata:
name: testsecret
namespace: default
type: Opaque
```
在Ingress中引用这个secret将通知Ingress controller使用TLS加密从将客户端到loadbalancer的channel:
```yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: no-rules-map
spec:
tls:
- secretName: testsecret
backend:
serviceName: s1
servicePort: 80
```
请注意,各种Ingress controller支持的TLS功能之间存在差距。 请参阅有关[nginx](https://git.k8s.io/ingress-nginx/README.md#https),[GCE](https://git.k8s.io/ingress-gce/README.md#frontend-https)或任何其他平台特定Ingress controller的文档,以了解TLS在你的环境中的工作原理。
Ingress controller启动时附带一些适用于所有Ingress的负载平衡策略设置,例如负载均衡算法,后端权重方案等。更高级的负载平衡概念(例如持久会话,动态权重)尚未在Ingress中公开。 你仍然可以通过service loadbalancer获取这些功能。 随着时间的推移,我们计划将适用于跨平台的负载平衡模式加入到Ingress资源中。
还值得注意的是,尽管健康检查不直接通过Ingress公开,但Kubernetes中存在并行概念,例如[准备探查](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/),可以使你达成相同的最终结果。 请查看特定控制器的文档,以了解他们如何处理健康检查([nginx](https://git.k8s.io/ingress-nginx/README.md),[GCE](https://git.k8s.io/ingress-gce/README.md#health-checks))。
## 更新Ingress
假如你想要向已有的ingress中增加一个新的Host,你可以编辑和更新该ingress:
```Bash
$ kubectl get ing
NAME RULE BACKEND ADDRESS
test - 178.91.123.132
foo.bar.com
/foo s1:80
$ kubectl edit ing test
```
这会弹出一个包含已有的yaml文件的编辑器,修改它,增加新的Host配置。
```yaml
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
serviceName: s1
servicePort: 80
path: /foo
- host: bar.baz.com
http:
paths:
- backend:
serviceName: s2
servicePort: 80
path: /foo
..
```
保存它会更新API server中的资源,这会触发ingress controller重新配置loadbalancer。
```bash
$ kubectl get ing
NAME RULE BACKEND ADDRESS
test - 178.91.123.132
foo.bar.com
/foo s1:80
bar.baz.com
/foo s2:80
```
在一个修改过的ingress yaml文件上调用`kubectl replace -f`命令一样可以达到同样的效果。
## 跨可用域故障
在不同云供应商之间,跨故障域的流量传播技术有所不同。 有关详细信息,请查看相关Ingress controller的文档。 有关在federation集群中部署Ingress的详细信息,请参阅federation文档。
## 未来计划
- 多样化的HTTPS/TLS模型支持(如SNI,re-encryption)
- 通过声明来请求IP或者主机名
- 结合L4和L7 Ingress
- 更多的Ingress controller
请跟踪[L7和Ingress的proposal](https://github.com/kubernetes/kubernetes/pull/12827),了解有关资源演进的更多细节,以及[Ingress repository](https://github.com/kubernetes/ingress/tree/master),了解有关各种Ingress controller演进的更多详细信息。
## 替代方案
你可以通过很多种方式暴露service而不必直接使用ingress:
- 使用[Service.Type=LoadBalancer](https://kubernetes.io/docs/user-guide/services/#type-loadbalancer)
- 使用[Service.Type=NodePort](https://kubernetes.io/docs/user-guide/services/#type-nodeport)
- 使用[Port Proxy](https://git.k8s.io/contrib/for-demos/proxy-to-service)
- 部署一个[Service loadbalancer](https://github.com/kubernetes/contrib/tree/master/service-loadbalancer) 这允许你在多个service之间共享单个IP,并通过Service Annotations实现更高级的负载平衡。
## 参考
- [Kubernetes Ingress Resource](https://kubernetes.io/docs/concepts/services-networking/ingress/)
- [使用NGINX Plus负载均衡Kubernetes服务](http://dockone.io/article/957)
- [使用 NGINX 和 NGINX Plus 的 Ingress Controller 进行 Kubernetes 的负载均衡](http://www.cnblogs.com/276815076/p/6407101.html)
- [Kubernetes : Ingress Controller with Træfɪk and Let's Encrypt](https://blog.osones.com/en/kubernetes-ingress-controller-with-traefik-and-lets-encrypt.html)
- [Kubernetes : Træfɪk and Let's Encrypt at scale](https://blog.osones.com/en/kubernetes-traefik-and-lets-encrypt-at-scale.html)
- [Kubernetes Ingress Controller-Træfɪk](https://docs.traefik.io/user-guide/kubernetes/)
- [使用Istio控制Ingress流量](https://istio.io/zh/docs/tasks/traffic-management/ingress/)
- 序言
- 云原生
- 云原生(Cloud Native)的定义
- CNCF - 云原生计算基金会简介
- CNCF章程
- 云原生的设计哲学
- Play with Kubernetes
- 快速部署一个云原生本地实验环境
- Kubernetes与云原生应用概览
- 云原生应用之路——从Kubernetes到Cloud Native
- 云原生编程语言
- 云原生编程语言Ballerina
- 云原生编程语言Pulumi
- 云原生的未来
- Kubernetes架构
- 设计理念
- Etcd解析
- 开放接口
- CRI - Container Runtime Interface(容器运行时接口)
- CNI - Container Network Interface(容器网络接口)
- CSI - Container Storage Interface(容器存储接口)
- Kubernetes中的网络
- Kubernetes中的网络解析——以flannel为例
- Kubernetes中的网络解析——以calico为例
- 具备API感知的网络和安全性管理开源软件Cilium
- Cilium架构设计与概念解析
- 资源对象与基本概念解析
- Pod状态与生命周期管理
- Pod概览
- Pod解析
- Init容器
- Pause容器
- Pod安全策略
- Pod的生命周期
- Pod Hook
- Pod Preset
- Pod中断与PDB(Pod中断预算)
- 集群资源管理
- Node
- Namespace
- Label
- Annotation
- Taint和Toleration(污点和容忍)
- 垃圾收集
- 控制器
- Deployment
- StatefulSet
- DaemonSet
- ReplicationController和ReplicaSet
- Job
- CronJob
- Horizontal Pod Autoscaling
- 自定义指标HPA
- 准入控制器(Admission Controller)
- 服务发现
- Service
- Ingress
- Traefik Ingress Controller
- 身份与权限控制
- ServiceAccount
- RBAC——基于角色的访问控制
- NetworkPolicy
- 存储
- Secret
- ConfigMap
- ConfigMap的热更新
- Volume
- Persistent Volume(持久化卷)
- Storage Class
- 本地持久化存储
- 集群扩展
- 使用自定义资源扩展API
- 使用CRD扩展Kubernetes API
- Aggregated API Server
- APIService
- Service Catalog
- 资源调度
- QoS(服务质量等级)
- 用户指南
- 资源对象配置
- 配置Pod的liveness和readiness探针
- 配置Pod的Service Account
- Secret配置
- 管理namespace中的资源配额
- 命令使用
- Docker用户过度到kubectl命令行指南
- kubectl命令概览
- kubectl命令技巧大全
- 使用etcdctl访问kubernetes数据
- 集群安全性管理
- 管理集群中的TLS
- kubelet的认证授权
- TLS bootstrap
- 创建用户认证授权的kubeconfig文件
- IP伪装代理
- 使用kubeconfig或token进行用户身份认证
- Kubernetes中的用户与身份认证授权
- Kubernetes集群安全性配置最佳实践
- 访问Kubernetes集群
- 访问集群
- 使用kubeconfig文件配置跨集群认证
- 通过端口转发访问集群中的应用程序
- 使用service访问群集中的应用程序
- 从外部访问Kubernetes中的Pod
- Cabin - Kubernetes手机客户端
- Kubernetic - Kubernetes桌面客户端
- Kubernator - 更底层的Kubernetes UI
- 在Kubernetes中开发部署应用
- 适用于kubernetes的应用开发部署流程
- 迁移传统应用到Kubernetes中——以Hadoop YARN为例
- 最佳实践概览
- 在CentOS上部署Kubernetes集群
- 创建TLS证书和秘钥
- 创建kubeconfig文件
- 创建高可用etcd集群
- 安装kubectl命令行工具
- 部署master节点
- 安装flannel网络插件
- 部署node节点
- 安装kubedns插件
- 安装dashboard插件
- 安装heapster插件
- 安装EFK插件
- 生产级的Kubernetes简化管理工具kubeadm
- 使用kubeadm在Ubuntu Server 16.04上快速构建测试集群
- 服务发现与负载均衡
- 安装Traefik ingress
- 分布式负载测试
- 网络和集群性能测试
- 边缘节点配置
- 安装Nginx ingress
- 安装配置DNS
- 安装配置Kube-dns
- 安装配置CoreDNS
- 运维管理
- Master节点高可用
- 服务滚动升级
- 应用日志收集
- 配置最佳实践
- 集群及应用监控
- 数据持久化问题
- 管理容器的计算资源
- 集群联邦
- 存储管理
- GlusterFS
- 使用GlusterFS做持久化存储
- 使用Heketi作为Kubernetes的持久存储GlusterFS的external provisioner
- 在OpenShift中使用GlusterFS做持久化存储
- GlusterD-2.0
- Ceph
- 用Helm托管安装Ceph集群并提供后端存储
- 使用Ceph做持久化存储
- 使用rbd-provisioner提供rbd持久化存储
- OpenEBS
- 使用OpenEBS做持久化存储
- Rook
- NFS
- 利用NFS动态提供Kubernetes后端存储卷
- 集群与应用监控
- Heapster
- 使用Heapster获取集群和对象的metric数据
- Prometheus
- 使用Prometheus监控kubernetes集群
- Prometheus查询语言PromQL使用说明
- 使用Vistio监控Istio服务网格中的流量
- 分布式跟踪
- OpenTracing
- 服务编排管理
- 使用Helm管理Kubernetes应用
- 构建私有Chart仓库
- 持续集成与发布
- 使用Jenkins进行持续集成与发布
- 使用Drone进行持续集成与发布
- 更新与升级
- 手动升级Kubernetes集群
- 升级dashboard
- 领域应用概览
- 微服务架构
- 微服务中的服务发现
- 使用Java构建微服务并发布到Kubernetes平台
- Spring Boot快速开始指南
- Service Mesh 服务网格
- 企业级服务网格架构
- Service Mesh基础
- Service Mesh技术对比
- 采纳和演进
- 定制和集成
- 总结
- Istio
- 安装并试用Istio service mesh
- 配置请求的路由规则
- 安装和拓展Istio service mesh
- 集成虚拟机
- Istio中sidecar的注入规范及示例
- 如何参与Istio社区及注意事项
- Istio教程
- Istio免费学习资源汇总
- 深入理解Istio Service Mesh中的Envoy Sidecar注入与流量劫持
- 深入理解Istio Service Mesh中的Envoy Sidecar代理的路由转发
- Linkerd
- Linkerd 使用指南
- Conduit
- Condiut概览
- 安装Conduit
- Envoy
- Envoy的架构与基本术语
- Envoy作为前端代理
- Envoy mesh教程
- SOFAMesh
- SOFAMesh中的Dubbo on x-protocol
- SOFAMosn
- 使用 SOFAMosn 构建 SOFAMesh
- 大数据
- Spark standalone on Kubernetes
- 运行支持Kubernetes原生调度的Spark程序
- Serverless架构
- 理解Serverless
- FaaS-函数即服务
- OpenFaaS快速入门指南
- 边缘计算
- 人工智能