# 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快速入門指南
- 邊緣計算
- 人工智能