Ingress 可以提供負載平衡,SSL 終端和基於名稱的虛擬主機。
Ingress 是什么
通常情況下,service和pod僅可在集群內部網絡中通過IP地址訪問。所有到達邊界路由器的流量或被丟棄或被轉發到其他地方。
internet
|
------------
[ Services ]
Ingress是授權入站連接到達集群服務的規則集合。
internet
|
[ Ingress ]
--|-----|--
[ Services ]
可以給Ingress配置提供外部可訪問的URL、負載均衡、SSL、基於名稱的虛擬主機等。用戶通過POST Ingress資源到API server的方式來請求ingress。Ingress 不會公開任意端口或協議。 將 HTTP 和 HTTPS 以外的服務公開給 Internet 時,通常使用以下類型的服務 Service.Type=NodePort 或者 Service.Type=LoadBalancer.
Ingress 資源
需要一個Ingress Controller來實現Ingress,單純的創建一個Ingress沒有任何意義。
GCE/GKE會在master節點上部署一個ingress controller。你可以在一個pod中部署任意個自定義的ingress controller。
最簡化的Ingress配置:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: test-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /testpath
backend:
serviceName: test
servicePort: 80
配置說明:
1-4行:跟Kubernetes的其他配置一樣,ingress的配置也需要apiVersion,kind和metadata字段。
5-7行: Ingress spec 中包含配置一個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中描述的那樣,backend是一個service:port的組合。Ingress的流量被轉發到它所匹配的backend。
在所有請求都不能跟spec中的path匹配的情況下,請求被發送到Ingress controller的默認后端,可以指定全局缺省backend。
為了使Ingress正常工作,集群中必須運行Ingress controller。
Ingress類型
單Service Ingress
通過指定一個沒有rule的默認backend的方式來實現暴露單個service。
ingress.yaml定義文件:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
backend:
serviceName: testsvc
servicePort: 80
使用kubectl create -f命令創建,然后查看ingress:
$ kubectl get ingress test-ingress
NAME HOSTS ADDRESS PORTS AGE
test-ingress * 107.178.254.228 80 59s
107.178.254.228就是Ingress controller為了實現Ingress而分配的IP地址。RULE列表示所有發送給該IP的流量都被轉發到了BACKEND所列的Kubernetes service上。
簡單擴展
kubernete pod中的IP只在集群網絡內部可見,我們需要在邊界設置一個東西,讓它能夠接收ingress的流量並將它們轉發到正確的端點上。這個東西一般是高可用的loadbalancer。使用Ingress能夠允許你將loadbalancer的個數降低到最少:
foo.bar.com -> 178.91.123.132 -> / foo service1:4200
/ bar service2:8080
需要一個Ingress:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: simple-fanout-example
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo
backend:
serviceName: service1
servicePort: 4200
- path: /bar
backend:
serviceName: service2
servicePort: 8080
使用kubectl create -f創建完ingress后:
$ kubectl describe ingress simple-fanout-example
Name: simple-fanout-example
Namespace: default
Address: 178.91.123.132
Default backend: default-http-backend:80 (10.8.2.3:8080)
Rules:
Host Path Backends
---- ---- --------
foo.bar.com
/foo service1:4200 (10.8.0.90:4200)
/bar service2:8080 (10.8.0.91:8080)
Annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 22s loadbalancer-controller default/test
只要服務存在,Ingress controller就會將提供一個滿足該Ingress的特定loadbalancer實現。 這一步完成后,在Ingress的最后一列可以看到loadbalancer的地址。
基於名稱的虛擬主機
基於名稱的虛擬主機支持將 HTTP 流量路由到同一 IP 地址上的多個主機名。
foo.bar.com --| |-> foo.bar.com service1:80
| 178.91.123.132 |
bar.foo.com --| |-> bar.foo.com service2:80
下面的 Ingress 讓后台的負載均衡器基於 Host header 路由請求。
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
serviceName: service1
servicePort: 80
- host: bar.foo.com
http:
paths:
- backend:
serviceName: service2
servicePort: 80
如果請求header中的host不能跟ingress中的host匹配,並且/或請求的URL不能與任何一個path匹配,則流量將路由到默認backend。
例如,以下Ingress資源會將 first.bar.com 請求的流量路由到 service1,將 second.foo.com 請求的流量路由到 service2, 而所有到IP地址但未在請求中定義主機名的流量流量路由到 service3。
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: first.bar.com
http:
paths:
- backend:
serviceName: service1
servicePort: 80
- host: second.foo.com
http:
paths:
- backend:
serviceName: service2
servicePort: 80
- http:
paths:
- backend:
serviceName: service3
servicePort: 80
TLS
可以通過指定包含TLS私鑰和證書的secret來加密Ingress。 目前,Ingress僅支持單個TLS端口443,並假定TLS termination。 如果Ingress中的TLS配置部分指定了不同的主機,則它們將根據通過SNI TLS擴展指定的主機名(假如Ingress controller支持SNI)在多個相同端口上進行復用。 TLS secret中必須包含名為tls.crt和tls.key的密鑰,這里面包含了用於TLS的證書和私鑰,例如:
apiVersion: v1
kind: Secret
metadata:
name: testsecret-tls
namespace: default
data:
tls.crt: base64 encoded cert
tls.key: base64 encoded key
type: kubernetes.io/tls
在Ingress中引用這個secret將通知Ingress controller使用TLS加密從將客戶端到loadbalancer的channel:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: tls-example-ingress
spec:
tls:
- hosts:
- sslexample.foo.com
secretName: testsecret-tls
rules:
- host: sslexample.foo.com
http:
paths:
- path: /
backend:
serviceName: service1
servicePort: 80
Ingress controller啟動時附帶一些適用於所有Ingress的負載平衡策略設置,例如負載均衡算法,后端權重方案等.
更新 Ingress
假如你想要向已有的ingress中增加一個新的Host,你可以編輯和更新該ingress:
$ kubectl describe ingress test
Name: test
Namespace: default
Address: 178.91.123.132
Default backend: default-http-backend:80 (10.8.2.3:8080)
Rules:
Host Path Backends
---- ---- --------
foo.bar.com
/foo service1:80 (10.8.0.90:80)
Annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 35s loadbalancer-controller default/test
編輯yaml:
$ kubectl edit ingress test
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
serviceName: service1
servicePort: 80
path: /foo
(添加一個host)
- host: bar.baz.com
http:
paths:
- backend:
serviceName: service2
servicePort: 80
path: /foo
..
保存它會更新API server中的資源,這會觸發ingress controller重新配置loadbalancer。
$ kubectl describe ingress test
Name: test
Namespace: default
Address: 178.91.123.132
Default backend: default-http-backend:80 (10.8.2.3:8080)
Rules:
Host Path Backends
---- ---- --------
foo.bar.com
/foo service1:80 (10.8.0.90:80)
bar.baz.com
/foo service2:80 (10.8.0.91:80)
Annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 45s loadbalancer-controller default/test
可以通過 kubectl replace -f 命令調用修改后的 Ingress YAML 文件來獲得同樣的結果。