Ingress
管理群集中服務的外部訪問的API對象,通常是HTTP。
Ingress可以提供負載平衡,SSL 終止和基于名稱的虛擬主機。
Ingress是什么
Ingress, Kubernetes v1.1開始增加的,暴露集群 services 的 http和https的路由。流量路由規則的控制是定義在Ingress resource。
internet | [ Ingress ] --|-----|-- [ Services ]
Ingress可以給service提供集群外部訪問的URL、負載均衡、SSL終止、基于名稱的虛擬主機。 Ingress controller 負責實現Ingress的功能, 通常是一個負載均衡器, 它監聽Ingress和service的變化,并根據規則配置負載均衡并提供訪問入口。
Ingress不會暴露任意端口或協議。將HTTP和HTTPS以外的服務公開給Internet通常使用Service.Type = NodePort或Service.Type = LoadBalancer。
The Ingress Resource
最簡單的Ingress Resource示例如下
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
與其他的Kubernetes resources一樣,Ingress需要apiVersion
, kind
, 和 metadata
屬性.
有關配置的其他屬性配置,參見 deploying applications, configuring containers, managing resources.
Ingress經常使用注釋來配置一些選項,具體取決于Ingress控制器, 參見例子 rewrite-target annotation.
不同的 Ingress controller 支持不同的注釋. 閱讀你選擇的Ingress controller的文檔,查看支持那些注釋.
Ingress規范具有配置負載均衡器或代理服務器所需的所有信息。 最重要的是,它包含與所有傳入請求匹配的規則列表。 Ingress資源僅支持HTTP流量的規則。
Ingress 規則
每個http規則都包含以下信息:
- 可選主機。 在此示例中,未指定主機,因此該規則適用于通過指定的IP地址的所有入站HTTP流量。 如果提供了主機(例如,foo.bar.com),則規則適用于該主機。
- 路徑列表(例如,/ testpath),每個路徑都會定義serviceName和servicePort關聯后端。 主機和路徑都必須與傳入請求的內容匹配,以便負載均衡器能夠直接引用到后端服務。
- 后端是在 services 文檔中定義的服務名稱和端口名稱的組合. 對Ingress匹配的主機和路由規則的HTTP(和HTTPS)請求將被發送到列出的后端。
默認后端通常在Ingress控制器中配置,該控制器將為與規范中的路徑不匹配的請求提供服務。
默認后端
沒有規則的Ingress將所有流量發送到單個默認后端。 默認后端通常是Ingress控制器的一個配置選項,并且未在Ingress資源中指定。
Ingress類型
1、單服務Ingress
現有的Kubernetes概念允許公開單個服務 (參見 alternatives)。也可以通過指定沒有規則的默認后端來使用Ingress執行此操作。
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
backend:
serviceName: testsvc
servicePort: 80
如果你使用 kubectl apply -f
你將會看到如下信息:
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。
2、路由到多服務的Ingress
多服務配置根據請求的HTTP URI將流量從單個IP地址路由到多個服務。Ingress允許將負載均衡器的數量降至最低。例如,設置如下:
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
只要服務(s1,s2)存在,Ingress控制器就會提供滿足Ingress特定實現的負載均衡器。創建完成后,可以在Address 字段中查看負載均衡器的地址。
3、基于名稱的虛擬主機
虛擬主機Ingress即根據名字的不同轉發到不同的后端服務上,而他們共用同一個的IP地址
foo.bar.com --| |-> foo.bar.com s1:80
| 178.91.123.132 |
bar.foo.com --| |-> bar.foo.com s2:80
下面是一個基于Host header路由請求的Ingress:
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
如果你創建的Ingress resouce 沒有在rules中定義任何主機,然后,基于 Ingress controller 的IP地址的web請求能夠匹配到沒有名稱的虛擬主機。例如,以下Ingress resource 會將first.bar.com
請求路由到service1
,將second.foo.com
路由到service2
,其他只有IP地址沒有定義hostname(即沒有在header中定義hostname)將會路由到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
4、TLS
您可以通過指定包含TLS私鑰和證書的 secret 來加固Ingress。目前,Ingress僅支持一個TLS的端口 443,并假定TLS終止。如果Ingress中的TLS配置部分指定了不同的主機,它們將根據通過SNI TLS擴展指定的主機名在同一端口上復用(假設Ingress控制器支持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保護從客戶端到負載均衡器的信道。你需要確保你創建的TLS Secret來自包含sslexample.foo.com的CN的證書。
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支持的TLS功能不盡相同。 請參閱有關nginx,GCE或任何其他Ingress controller的文檔,以了解TLS的支持情況。
4、負載均衡
Ingress controller通過一些負載均衡策略設置進行自舉,該策略設置適用于所有Ingress,例如負載平衡算法,后端權重方案等。 其他的一些高級的負載平衡概念(例如,持久會話,動態權重)沒有通過Ingress公布。 不過你仍然可以通過負載均衡器獲得這些功能。
值得注意的是,即使健康檢查沒有直接通過Ingress公開,Kubernetes中也存在類似概念,例如readiness探針,它們可以實現相同的最終結果。你可以參閱controller的文檔,了解它們如何處理健康檢查 ( nginx, GCE)。
5、更新Ingress
要更新現有的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 s1: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
kubectl edit ingress test
這應該會彈出一個包含現有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
..
保存yaml將更新API服務器中的資源,這會告訴Ingress controller重新配置負載均衡器。
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 s1:80 (10.8.0.90:80)
bar.baz.com
/foo s2: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
你可以通過在修改的Ingress yaml文件,然后調用kubectl replace -f
來實現同樣的目的。
Ingress Controllers
Ingress 正常工作需要集群中運行 Ingress Controller。Ingress Controller 與其他作為 kube-controller-manager 中的在集群創建時自動啟動的 controller 成員不同,需要用戶選擇最適合自己集群的 Ingress Controller.
Kubernetes項目目前支持和維護GCE and nginx controllers。
Ingress Controller 以 Kubernetes Pod 的方式部署,以 daemon 方式運行,保持 watch Apiserver 的 /ingress 接口以更新 Ingress 資源,以滿足 Ingress 的請求。比如可以使用 Nginx Ingress Controller:
其他 Ingress Controller 還有:
Ambassador API Gateway is an Envoy based ingress controller with community or commercial support from Datawire.
AppsCode Inc. offers support and maintenance for the most widely used HAProxy based ingress controller Voyager.
Contour is an Envoy based ingress controller provided and supported by Heptio.
Citrix provides an Ingress Controller for its hardware (MPX), virtualized (VPX) and free containerized (CPX) ADC for baremetal and cloud deployments.
F5 Networks provides support and maintenance for the F5 BIG-IP Controller for Kubernetes.
Gloo is an open-source ingress controller based on Envoy which offers API Gateway functionality with enterprise support from solo.io.
HAProxy based ingress controller jcmoraisjr/haproxy-ingress which is mentioned on the blog post HAProxy Ingress Controller for Kubernetes. HAProxy Technologies offers support and maintenance for HAProxy Enterprise and the ingress controller jcmoraisjr/haproxy-ingress.
Istio based ingress controller Control Ingress Traffic.
Kong offers community or commercial support and maintenance for the Kong Ingress Controller for Kubernetes.
NGINX, Inc. offers support and maintenance for the NGINX Ingress Controller for Kubernetes.
Traefik is a fully featured ingress controller (Let’s Encrypt, secrets, http2, websocket), and it also comes with commercial support by Containous.
使用多個Ingress controllers
你可以在集群中部署多個 any number of ingress controllers. 當你在集群中部署多個ingress controllers時,你創建ingress時需要使用注釋指定 ingress.class
,這樣集群才能選取正確的ingress controller.
當你沒有指定ingress.class
,云提供商可能會使用默認的ingress 入口.
一般而言,所有Ingress controllers都應滿足此規范,但各種Ingress controllers的運行方式略有不同。
查看Ingress controller的文檔以了解選擇它的注意事項
我們接下來會具體介紹kubernetes/ingress-nginx,以此作為一個示例來介紹Ingress controllers.
ingress-nginx
Kubernetes是一個開源容器調度和編排系統,最初由Google創建,然后捐贈給Cloud Native Computing Foundation。 Kubernetes自動調度容器在服務器集群中運行,解放了開發人員和運維人員容器編排的復雜的任務。 Kubernetes目前時最受歡迎的容器調度和編排系統。
NGINX Ingress Controller 為Kubernetes應用程序提供企業級交付服務,為開源NGINX和NGINX Plus的用戶帶來便捷.使用NGINX Ingress Controller 可以提供一下特性,負載平衡、SSL / TLS終止、URI重寫、SSL / TLS加密。NGINX Plus還可以為有狀態的應用提供session 持久化支持,API的jwt身份驗證等功能。
ingress-nginx 安裝
1、先決條件和通用部署命令
默認配置監視所有命名空間的Ingress對象。 要更改此行為,請使用--watch-namespace將范圍限制為特定命名空間。
如果多個Ingress為同一主機定義不同的路徑,則 ingress controller 將合并定義。
如果你正在使用GKE,則需要使用以下命令將當前用戶初始化為集群管理員:kubectl create clusterrolebinding cluster-admin-binding \ --clusterrole cluster-admin \ --user $(gcloud config get-value account)
yaml 文件:
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
部署方式有兩種,一種是創建service 使用NodePort暴露ingress-nginx,另外一種方式是使用本機網絡,添加hostNetwork: true
我們接下來使用這兩種方式進行部署:
1、創建ingress-nginx-service(官方文檔)
1.1、首先根據mandatory.yaml 文件創建對應的ingress相關
[root@k8s ~]# kubectl apply -f mandatory.yaml
namespace/ingress-nginx created
deployment.extensions/default-http-backend created
service/default-http-backend created
configmap/nginx-configuration created
configmap/tcp-services created
configmap/udp-services created
serviceaccount/nginx-ingress-serviceaccount created
clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created
role.rbac.authorization.k8s.io/nginx-ingress-role created
rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created
deployment.extensions/nginx-ingress-controller created
驗證安裝
檢查ingress controller pods 是否正常啟動,請運行下面的命令:
kubectl get pods --all-namespaces -l app.kubernetes.io/name=ingress-nginx --watch
[root@k8s ~]# kubectl get pods --all-namespaces -l app.kubernetes.io/name=ingress-nginx --watch
NAMESPACE NAME READY STATUS RESTARTS AGE
ingress-nginx nginx-ingress-controller-65795b86d-28lfr 1/1 Running 0 2m55s
1.2、創建ingress-nginx-service.yaml文件,并apply
ingress-nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30080
- name: https
port: 443
targetPort: 443
protocol: TCP
nodePort: 30443
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
[root@k8s ~]# kubectl apply -f ingress-nginx-service.yaml
service/ingress-nginx created
1.3、測試
Ingress Controller 部署部署好了,現在要寫ingress的規則,注入到ingress-nginx pod的配置文件中
[root@k8s ~]# cat test-nginx-service.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-service-ingress
namespace: default
spec:
rules:
- host: ancs.nginx.com
http:
paths:
- path:
backend:
serviceName: nginx
servicePort: 80
[root@k8s ~]# kubectl apply -f test-nginx-service.yaml
ingress.extensions/test-service-ingress created
查看ingress
[root@k8s ~]# kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
test-service-ingress ancs.nginx.com 80 33s
訪問的客戶端的機器配置下域名解析
現在我們可以通過ancs.nginx.com:30080來訪問到后端代理的pod了
這里是使用http訪問的,如果要用https,首先我們要創建一個證書,步驟如下:
自簽證書
[root@k8s https]# openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/C=CN/ST=Beijing/L=Beijing/O=ancs/CN=ancs.nginx.com"
Generating a 2048 bit RSA private key
......................+++
...........................+++
writing new private key to 'tls.key'
-----
[root@k8s https]# ls
tls.crt tls.key
當然也可以使用cfssl自簽證書。It‘s up to you!
創建 secret 資源, 證書生成好了,然后把證書轉成secret
[root@k8s https]# kubectl create secret tls ancs-secret --key tls.key --cert tls.crt
secret/ancs-secret created
修改test-nginx-service.yaml文件
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-service-ingress
namespace: default
spec:
tls:
- hosts:
- ancs.nginx.cn
secretName: ancs-secret
rules:
- host: ancs.nginx.com
http:
paths:
- path:
backend:
serviceName: nginx
servicePort: 80
現在我們可以通過https訪問了
2、使用宿主機網絡,增加 hostNetwork: true
2.1 修改mandatory.yaml配置文件,在container中增加配置項 hostNetwork: true 表示使用本機網絡
注意事項:
在創建ingress-nginx-controller容器之前,需要修改kube-proxy配置
在/opt/kubernetes/cfg/kube-proxy配置文件里增加一行:--masquerade-all=true 然后重啟kube-proxy 。
[root@k8s cfg]# cat kube-proxy
KUBE_PROXY_OPTS="--logtostderr=true
--v=4
--hostname-override=10.0.52.14
--cluster-cidr=10.0.0.0/24
--proxy-mode=ipvs
--masquerade-all=true
--kubeconfig=/opt/kubernetes/cfg/kube-proxy.kubeconfig"
配置項--masquerade-all的意思,參見官網說明kube-proxy,里面描述為:
--masquerade-all
If using the pure iptables proxy, SNAT all traffic sent via Service cluster IPs (this not commonly needed)
中文翻譯:
--masquerade-all
如果使用純 iptables 代理,SNAT 所有通過服務句群 IP 發送的流量(這通常不需要)
說人話的意思就是:
在kube-proxy中添加一個標志,以便為群集外流量維護偽裝規則。 就像是:
iptables -t nat -I POSTROUTING ! -s "${CLUSTER_CIDR}" -j MASQUERADE
2.2、啟動ingress-controller容器
[root@k8s ~]# kubectl apply -f mandatory.yaml
namespace/ingress-nginx unchanged
deployment.extensions/default-http-backend unchanged
service/default-http-backend unchanged
configmap/nginx-configuration unchanged
configmap/tcp-services unchanged
configmap/udp-services unchanged
serviceaccount/nginx-ingress-serviceaccount unchanged
clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole unchanged
role.rbac.authorization.k8s.io/nginx-ingress-role unchanged
rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding unchanged
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding unchanged
deployment.extensions/nginx-ingress-controller configured
[root@k8s ~]# kubectl get pods --all-namespaces -l app.kubernetes.io/name=ingress-nginx --watch
NAMESPACE NAME READY STATUS RESTARTS AGE
ingress-nginx nginx-ingress-controller-6b8cc9b76d-98szp 0/1 ContainerCreating 0 31s
ingress-nginx nginx-ingress-controller-6b8cc9b76d-98szp 0/1 Running 0 43s
ingress-nginx nginx-ingress-controller-6b8cc9b76d-98szp 1/1 Running 0 47s
2.3、Ingress部署
2.3.1、 http部署和上面一樣,參考上面就可以了。不再重復描述了。
2.3.2、https部署(使用cfssl)
利用cfssl頒發證書:
- 生成ca證書
cat << EOF | tee ca-config.json
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"www": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
EOF
cat << EOF | tee ca-csr.json
{
"CN": "www.ancs.com",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"ST": "Beijing"
}
]
}
EOF
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
- 生成server證書:
cat << EOF | tee ancs-csr.json
{
"CN": "www.ancs.com",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"ST": "Beijing"
}
]
}
EOF
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=www ancs-csr.json | cfssljson -bare www.ancs.com
- 生成密鑰
[root@k8s cfssl]# kubectl create secret tls ancs-secret --cert=www.ancs.com.pem --key=www.ancs.com-key.pem
secret/ancs-secret created
- 部署ingress
[root@k8s ~]# cat test-https-nginx-service.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-service-ingress
namespace: default
spec:
tls:
- hosts:
- ancs.nginx.cn
secretName: ancs-secret
rules:
- host: ancs.nginx.com
http:
paths:
- path:
backend:
serviceName: nginx
servicePort: 80
[root@k8s ~]# kubectl apply -f test-https-nginx-service.yaml
ingress.extensions/test-service-ingress created
[root@k8s ~]#
*配置hosts
-
瀏覽器訪問
https.png
至此,我們ingress 部署就算完成了。