我們前面介紹過用Service做集群代理,Service一般情況下只作用於內部Pod的代理調度,就算有NodePort類型,其訪問節點相對復雜,流程大概如下:
但是我們知道,如果只指定一個NodeIP,隨着業務量增大,這個Node的壓力就會很大,所以我們可能會在前端再加一個代理,代理幾個Node,比如我們在前端加一個NG,流程如下:
在應用小的情況下,這種架構雖然調度復雜,但是也可以使用,但是如果有大量應用,這種管理就非常麻煩,因為 我們要管理大量的NodePort,這個時候使用Ingress就非常方便。
再則,Service的轉發不論是iptables還是ipvs,都是4層的,但是在實際中基本都https請求,https是7層,4層是沒辦法對起進行SSL校驗的,如果我們是第二幅流程圖,我們可以在前置NG上配置SSL,但是如果我們是第一幅圖的流程,我們只能在Pod上配置SSL,因為Service上是無法進行校驗,那么就會出現一個問題,SSL的校驗是很耗資源的,我們的客戶端訪問Pod,如果Pod非常多並且訪問模式是輪詢,那么每訪問一次就要做一次SSL校驗,這就非常不科學,我們就只有用類似於第二副圖的架構,Ingress可以很完美的解決這種問題。
一、Ingress
流程圖如上,其中Ingress代理的並不是Pod的Service,而是Pod,之所以在配置的時候是配置的Service,是為了獲取Pod的信息。
Ingress提供外部訪問集群的入口,將外部的HTTP或者HTTPS請求轉發到集群內Service上,流量規則是在Ingress資源上定義。
配置Ingress資源的必要條件是你的kubernetes集群種由Ingress controller。其中Ingress Controller常用的有如下:
- HAProxy Ingress Controller
- Nginx Ingress Controller
- Traefik Ingress Controller
- Kong Ingress Controller
其中最常用的是Nginx Controller和Traefik Ingress Controller。
定義一個簡單的Ingresss:
[root@master ingress]# cat ingress-simple-daemo.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-simple-daemo
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /joker
backend:
serviceName: nginx
servicePort: 80
簡要說明:
apiVersion,kind,metadata,spec都是Kubernetes YAML文件的標准字段,Ingress經常通過annotations來配置一些選項,比如rewrite-target,不同的Ingress Controller支持不同的annotations。對於規則而言,每個HTTP都有如下規則:
- 主機:主機是可選參數,如果不配置表示適用於所有主機HTTP通信,如果配置了表示只適用於該主機;
- 路徑:類似於NG的location,每個路徑后面都有后端ServiceName和ServicePort;
- 后端:后端是ServiceName和ServicePort組合,符合該規則的流量會轉發到這個后端Service上。通常會在Ingress中配置默認后端,以匹配任何不符合規則的請求流量轉發;
- 具體的語法規則可以通過kubectl explain ingress來查看。
1.1、Ingress 類型
1.1.1、單服務Ingress
Kubernetes中已經存在一些概念可以暴露單個service(查看替代方案),但是你仍然可以通過Ingress來實現,通過指定一個沒有rule的默認backend的方式。比如:
[root@master ingress]# cat single-service-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: single-service-ingress
spec:
backend:
serviceName: nginx
servicePort: 80
1.1.2、簡單展開
如前面描述的那樣,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
1.1.3、基於名稱的虛擬主機
如果想實現下面這種需求:
foo.bar.com --| |-> foo.bar.com s1:80
| 178.91.123.132 |
bar.foo.com --| |-> bar.foo.com s2:80
我們就可以這樣配置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
如果要增加配置默認的backend,可以配置成如下Ingress:
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
默認backend:一個沒有rule的ingress,所有流量都將發送到一個默認backend。你可以用該技巧通知loadbalancer如何找到你網站的404頁面,通過制定一些列rule和一個默認backend的方式。如果請求header中的host不能跟ingress中的host匹配,並且/或請求的URL不能與任何一個path匹配,則流量將路由到你的默認backend。
1.1.4、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支持的TLS功能之間存在差距。 請參閱有關nginx,GCE或任何其他平台特定Ingress controller的文檔,以了解TLS在你的環境中的工作原理。
1.2、Ingress更新
如果你想更改你現在正工作的Ingress,比如新增一個HOST,可以使用kubectl edit ingress my-ingress進行更新,在保存退出后其會觸發Ingress Controller重新配置LB。比如我們現有一個ingress:
[root@master ingress]# kubectl get ingresses.
NAME HOSTS ADDRESS PORTS AGE
* 80 58m
然后我們使用kubectl edit ingress ingress-simple-daemo來新增一個HOST:
......
spec:
rules:
- http:
paths:
- backend:
serviceName: nginx-service
servicePort: 8000
path: /joker
- host: bar.baz.com
http:
paths:
- backend:
serviceName: nginx
servicePort: 80
path: /foo
status:
loadBalancer: {}
保存退出后就會生效:
[root@master ingress]# kubectl describe ingresses ingress-simple-daemo
Name: ingress-simple-daemo
Namespace: default
Address:
Default backend: default-http-backend:80 (<none>)
Rules:
Host Path Backends
---- ---- --------
*
/joker nginx-service:8000 (172.20.2.84:80)
bar.baz.com
/foo nginx:80 (172.20.2.79:80,172.20.2.82:80)
Annotations:
kubernetes.io/ingress.class: traefik
kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"networking.k8s.io/v1beta1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"traefik"},"name":"ingress-simple-daemo","namespace":"default"},"spec":{"rules":[{"http":{"paths":[{"backend":{"serviceName":"nginx-service","servicePort":8000},"path":"/joker"}]}}]}}
Events: <none>
二、Nginx Ingress
2.1、安裝
2.1.1 在線安裝
在線安裝直接執行以下命令:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
然后安裝NodePort:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/baremetal/service-nodeport.yaml
2.1.2、離線安裝
到https://github.com/kubernetes/ingress-nginx/tree/master/deploy/static這個下面下載對應的YAML文件,有configmap.yaml,namespace.yaml,rbac.yaml,with-rbac.yaml,可以寫一個如下循環下載:
for yaml in configmap.yaml namespace.yaml rbac.yaml with-rbac.yaml; do wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/$yaml;done
然后執行如下命令安裝,前提先執行namespace.yaml這個YAML文件:
kubectl apply -f namespace.yaml
kubectl apply -f .
然后我們可以執行以下命令查看:
[root@master nginx]# kubectl get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
nginx-ingress-controller-799dbf6fbd-zxvmp 0/1 ContainerCreating 0 12s
然后安裝nodePort:
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/baremetal/service-nodeport.yaml
kubectl apply -f service-nodeport.yaml
然后我修改了nodePort的端口,如下:
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
protocol: TCP
- name: https
port: 443
targetPort: 443
nodePort: 30443
protocol: TCP
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
然后查看結果:
[root@master nginx]# kubectl get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
nginx-ingress-controller-799dbf6fbd-zxvmp 1/1 Running 0 52m
[root@master nginx]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx NodePort 10.68.194.177 <none> 80:30080/TCP,443:30443/TCP 46m
2.2、使用
先創建Pod,service,定義如下YAML:
[root@master test]# cat nginx-ingress-demo.yaml
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-deploy
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: nginx-demo
release: canary
template:
metadata:
name: my-nginx
labels:
app: nginx-demo
release: canary
spec:
containers:
- name: my-nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: default
spec:
selector:
app: nginx-demo
release: canary
ports:
- name: http
port: 80
targetPort: 80
然后執行kubectl apply -f nginx-ingress-demo.yaml,查看結果:
[root@master test]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deploy-549cb5c7ff-65fbb 1/1 Running 0 21s
nginx-deploy-549cb5c7ff-75fmt 1/1 Running 0 21s
nginx-deploy-549cb5c7ff-wg4w7 1/1 Running 0 17s
[root@master test]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.68.0.1 <none> 443/TCP 5d2h
nginx-svc ClusterIP 10.68.214.28 <none> 80/TCP 6m21s
然后定義Ingress Nginx,YAML文件如下:
[root@master test]# cat ingress-nginx.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-nginx
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host:
http:
paths:
- path:
backend:
serviceName: nginx-svc
servicePort: 80
然后查看結果:
[root@master test]# kubectl describe ingresses ingress-nginx
Name: ingress-nginx
Namespace: default
Address: 10.68.194.177
Default backend: default-http-backend:80 (<none>)
Rules:
Host Path Backends
---- ---- --------
*
nginx-svc:80 (172.20.1.61:80,172.20.1.62:80,172.20.2.87:80)
Annotations:
kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"networking.k8s.io/v1beta1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"nginx"},"name":"ingress-nginx","namespace":"default"},"spec":{"rules":[{"host":null,"http":{"paths":[{"backend":{"serviceName":"nginx-svc","servicePort":80},"path":null}]}}]}}
kubernetes.io/ingress.class: nginx
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CREATE 11m nginx-ingress-controller Ingress default/ingress-nginx
Normal UPDATE 77s (x3 over 11m) nginx-ingress-controller Ingress default/ingress-nginx
在流量器訪問:
2.3、TLS
Nginx Ingress不止支持HTTP,還支持HTTPS。我們使用如下命令手動創建證書:
openssl genrsa -out tls.key 2048
openssl req -new -x509 -key tls.key -out tls.crt -subj "/C=CN/ST=Chongqing/L=Chongqing/OU=DevOps/CN=nginx.joker.com"
然后配置Secrect:
kubectl create secret tls tls-secret --key tls.key --cert tls.crt
然后查看:
[root@master test]# kubectl get secret
NAME TYPE DATA AGE
default-token-gmdbb kubernetes.io/service-account-token 3 5d3h
tls-secret kubernetes.io/tls 2 20s
[root@master test]# kubectl describe secrets tls-secret
Name: tls-secret
Namespace: default
Labels: <none>
Annotations: <none>
Type: kubernetes.io/tls
Data
====
tls.crt: 1302 bytes
tls.key: 1679 bytes
配置Ingress nginx:
[root@master test]# cat ingress-nginx-tls.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-nginx-tls
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
tls:
- host:
secretName: tls-secret
rules:
- host:
http:
paths:
- path:
backend:
serviceName: nginx-svc
servicePort: 80
然后查看結果:
[root@master test]# kubectl get ingresses.
NAME HOSTS ADDRESS PORTS AGE
ingress-nginx-tls * 80, 443 4s
瀏覽器訪問:
三、Traefik Ingress
3.1、安裝
創建namespace(namespace.yaml):
apiVersion: v1
kind: Namespace
metadata:
name: ingress-traefik
labels:
app.kubernetes.io/name: ingress-traefik
app.kubernetes.io/part-of: ingress-traefik
---
創建RBAC安全認證(rdac.yaml):
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: traefik-ingress-controller
namespace: ingress-traefik
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: traefik-ingress-controller
rules:
- apiGroups:
- ""
resources:
- services
- endpoints
- secrets
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- ingresses
verbs:
- get
- list
- watch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: traefik-ingress-controller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik-ingress-controller
subjects:
- kind: ServiceAccount
name: traefik-ingress-controller
namespace: ingress-traefik
配置traefik(traefik.yaml):
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: traefik-ingress-controller
namespace: ingress-traefik
labels:
k8s-app: traefik-ingress-lb
spec:
replicas: 1
selector:
matchLabels:
k8s-app: traefik-ingress-lb
template:
metadata:
labels:
k8s-app: traefik-ingress-lb
name: traefik-ingress-lb
spec:
serviceAccountName: traefik-ingress-controller
terminationGracePeriodSeconds: 60
# tolerations:
# - operator: "Exists"
# nodeSelector:
# kubernetes.io/hostname: master
containers:
- image: traefik:v1.7.17
name: traefik-ingress-lb
ports:
- name: http
containerPort: 80
- name: admin
containerPort: 8080
args:
- --api
- --kubernetes
- --logLevel=INFO
---
kind: Service
apiVersion: v1
metadata:
name: traefik-ingress-service
namespace: ingress-traefik
spec:
selector:
k8s-app: traefik-ingress-lb
ports:
- protocol: TCP
port: 80
name: web
nodePort: 38000
- protocol: TCP
port: 8080
nodePort: 38080
name: admin
type: NodePort
然后執行如下命令創建:
kubectl apply -f .
查看其結果:
[root@master traefik]# kubectl get svc -n ingress-traefik
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
traefik-ingress-service NodePort 10.68.173.196 <none> 80:38000/TCP,8080:38080/TCP 9m19s
[root@master traefik]# kubectl get pod -n ingress-traefik
NAME READY STATUS RESTARTS AGE
traefik-ingress-controller-86769d5d99-fvf82 1/1 Running 0 7m10s
Traefik提供一個WEB UI工具,就是上面8080端口,可以通過其映射的NodePort端口在瀏覽器訪問,如下:
3.2、使用
使用和上面nginx ingress一樣,只是在annotations里配置的kubernetes.io/ingress.class: "traefik"。
3.3、配置
生成SSL證書:
openssl req -newkey rsa:2048 -nodes -keyout tls.key -x509 -days 365 -out tls.crt
創建Secret來存儲證書:
# kubectl create secret generic traefik-cert --from-file=tls.crt --from-file=tls.key -n ingress-traefik
配置traefik,讓其支持https,配置文件如下:
defaultEntryPoints = ["http", "https"]
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[[entryPoints.https.tls.certificates]]
CertFile = "/ssl/tls.crt"
KeyFile = "/ssl/tls.key"
將上面的 traefik.toml 配置文件通過一個 ConfigMap 對象掛載到 traefik pod 中去。
創建configMap:
# kubectl create configmap traefik-conf --from-file=traefik.toml -n ingress-traefik
更改traefik的YAML文件:
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: traefik-ingress-controller
namespace: ingress-traefik
labels:
k8s-app: traefik-ingress-lb
spec:
replicas: 1
selector:
matchLabels:
k8s-app: traefik-ingress-lb
name: traefik-ingress-lb
template:
metadata:
labels:
k8s-app: traefik-ingress-lb
name: traefik-ingress-lb
spec:
serviceAccountName: traefik-ingress-controller
terminationGracePeriodSeconds: 60
# tolerations:
# - operator: "Exists"
# nodeSelector:
# kubernetes.io/hostname: master
containers:
- image: traefik:v1.7.17
name: traefik-ingress-lb
volumeMounts:
- name: ssl
mountPath: "/ssl"
- name: config
mountPath: "/config"
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
- name: admin
containerPort: 8080
args:
- --configfile=/config/traefik.toml
- --api
- --kubernetes
- --logLevel=INFO
volumes:
- name: ssl
secret:
secretName: traefik-cert
- name: config
configMap:
name: traefik-conf
---
kind: Service
apiVersion: v1
metadata:
name: traefik-ingress-service
namespace: ingress-traefik
spec:
selector:
k8s-app: traefik-ingress-lb
ports:
- protocol: TCP
port: 80
name: web
nodePort: 38000
- protocol: TCP
port: 8080
nodePort: 38080
name: admin
type: NodePort
然后生成配置清單,並查看日志觀察其是否生效;
# kubectl apply -f traefik.yaml
# kubectl logs traefik-ingress-controller-867f5668dd-7p7tv -n ingress-traefik
time="2019-11-25T08:25:30Z" level=info msg="Using TOML configuration file /config/traefik.toml"
time="2019-11-25T08:25:30Z" level=info msg="No tls.defaultCertificate given for https: using the first item in tls.certificates as a fallback."
time="2019-11-25T08:25:30Z" level=info msg="Traefik version v1.7.17 built on 2019-09-23_06:22:08PM"
time="2019-11-25T08:25:30Z" level=info msg="\nStats collection is disabled.\nHelp us improve Traefik by turning this feature on :)\nMore details on: https://docs.traefik.io/v1.7/basics/#collected-data\n"
time="2019-11-25T08:25:30Z" level=info msg="Preparing server https &{Address::443 TLS:0xc0002b22d0 Redirect:<nil> Auth:<nil> WhitelistSourceRange:[] WhiteList:<nil> Compress:false ProxyProtocol:<nil> ForwardedHeaders:0xc00050a100} with readTimeout=0s writeTimeout=0s idleTimeout=3m0s"
time="2019-11-25T08:25:30Z" level=info msg="Preparing server traefik &{Address::8080 TLS:<nil> Redirect:<nil> Auth:<nil> WhitelistSourceRange:[] WhiteList:<nil> Compress:false ProxyProtocol:<nil> ForwardedHeaders:0xc00050a120} with readTimeout=0s writeTimeout=0s idleTimeout=3m0s"
time="2019-11-25T08:25:30Z" level=info msg="Starting server on :443"
time="2019-11-25T08:25:30Z" level=info msg="Preparing server http &{Address::80 TLS:<nil> Redirect:0xc000843fc0 Auth:<nil> WhitelistSourceRange:[] WhiteList:<nil> Compress:false ProxyProtocol:<nil> ForwardedHeaders:0xc00050a0e0} with readTimeout=0s writeTimeout=0s idleTimeout=3m0s"
time="2019-11-25T08:25:30Z" level=info msg="Starting server on :8080"
time="2019-11-25T08:25:30Z" level=info msg="Starting provider configuration.ProviderAggregator {}"
time="2019-11-25T08:25:30Z" level=info msg="Starting server on :80"
time="2019-11-25T08:25:30Z" level=info msg="Starting provider *kubernetes.Provider {\"Watch\":true,\"Filename\":\"\",\"Constraints\":[],\"Trace\":false,\"TemplateVersion\":0,\"DebugLogGeneratedTemplate\":false,\"Endpoint\":\"\",\"Token\":\"\",\"CertAuthFilePath\":\"\",\"DisablePassHostHeaders\":false,\"EnablePassTLSCert\":false,\"Namespaces\":null,\"LabelSelector\":\"\",\"IngressClass\":\"\",\"IngressEndpoint\":null,\"ThrottleDuration\":0}"
time="2019-11-25T08:25:30Z" level=info msg="ingress label selector is: \"\""
time="2019-11-25T08:25:30Z" level=info msg="Creating in-cluster Provider client"
time="2019-11-25T08:25:30Z" level=info msg="Server configuration reloaded on :443"
time="2019-11-25T08:25:30Z" level=info msg="Server configuration reloaded on :8080"
time="2019-11-25T08:25:30Z" level=info msg="Server configuration reloaded on :80"
3.4、Rewrite
測試demo:
apiVersion: v1
kind: Service
metadata:
name: nginx-demo
spec:
selector:
app: nginx
ports:
- name: nginx
port: 80
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
正常訪問的ingress如下:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-ingress-demo
annotations:
kubernetes.io/ingress.class: "traefik"
spec:
rules:
- host:
http:
paths:
- backend:
serviceName: nginx-demo
servicePort: 80
path: /
但是如果我們把path改為如下:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-ingress-demo
annotations:
kubernetes.io/ingress.class: "traefik"
spec:
rules:
- host:
http:
paths:
- backend:
serviceName: nginx-demo
servicePort: 80
path: /app
那么這時候訪問就會報404.
這時候我們可以在配置里加上rewrite規則,如下:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-ingress-demo
annotations:
kubernetes.io/ingress.class: "traefik"
traefik.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host:
http:
paths:
- backend:
serviceName: nginx-demo
servicePort: 80
path: /app
然后就可以正常訪問了,如下:
為了更友好化,我們可以定義如下:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-ingress-demo
annotations:
kubernetes.io/ingress.class: "traefik"
traefik.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- host:
http:
paths:
- backend:
serviceName: nginx-demo
servicePort: 80
path: /app(/|$)(.*)
但是這種還是會有問題,比如有的靜態資源無法正常顯示,比如靜態資源的路徑在/static下面,現在我們做了 url rewrite 過后,要正常訪問也需要帶上前綴才可以:http://xxx.xxx/static/screen.css,對於圖片或者其他靜態資源也是如此,當然我們去更改頁面引入靜態資源的方式為相對路徑也是可以的,但是畢竟要修改代碼,這個時候我們可以借助 ingress-traefik 中的 configuration-snippet 來對靜態資源做一次跳轉,如下所示: ```yaml apiVersion: extensions/v1beta1 kind: Ingress metadata: name: nginx-ingress-demo annotations: kubernetes.io/ingress.class: "traefik" traefik.ingress.kubernetes.io/rewrite-target: /$2 traefik.ingress.kubernetes.io/configuration-snippet: | rewrite ^/static/(.*)$ /app/static/$1 redirect; rewrite ^/image/(.*)$ /app/image/$1 redirect; spec: rules: - host: http: paths: - backend: serviceName: nginx-demo servicePort: 80 path: /app(/|$)(.*) ```
這時候就可以正常加載靜態資源了。
但是我們還想直接訪問主域名,但是會報404,要解決這種問題,可以app-root的注解,這樣我們訪問主域名的時候就可以跳轉到app-root目錄(真實存在的路徑)下面,如下:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-ingress-demo
annotations:
kubernetes.io/ingress.class: "traefik"
traefik.ingress.kubernetes.io/app-root: /app/
traefik.ingress.kubernetes.io/rewrite-target: /$2
traefik.ingress.kubernetes.io/configuration-snippet: |
rewrite ^/static/(.*)$ /app/static/$1 redirect;
rewrite ^/image/(.*)$ /app/image/$1 redirect;
spec:
rules:
- host:
http:
paths:
- backend:
serviceName: nginx-demo
servicePort: 80
path: /app(/|$)(.*)
但是還有一個問題是我們的 path 路徑其實也匹配了 /app 這樣的路徑,可能我們更加希望我們的應用在最后添加一個 / 這樣的 slash,同樣我們可以通過 configuration-snippet 配置來完成,如下 Ingress 對象:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-ingress-demo
annotations:
kubernetes.io/ingress.class: "traefik"
traefik.ingress.kubernetes.io/app-root: /app/
traefik.ingress.kubernetes.io/rewrite-target: /$2
traefik.ingress.kubernetes.io/configuration-snippet: |
rewrite ^(/app)$ $1/ redirect;
rewrite ^/static/(.*)$ /app/static/$1 redirect;
rewrite ^/image/(.*)$ /app/image/$1 redirect;
spec:
rules:
- host:
http:
paths:
- backend:
serviceName: nginx-demo
servicePort: 80
path: /app(/|$)(.*)