kubernetes雲原生紀元:領悟 Ingress Nginx(下)
續領悟Ingress Nginx(中)
文章目錄
解決https 證書問題
ingress-nginx 配置證書
-
生產證書
首先生成一個證書
gen-secret.sh
腳步生成證書,輸出一個key 一個密鑰
注意這裏我生成完後直接在kubernetes 創建了secret
kubectl create secret tls mooc-tls --key mooc.key --cert mooc.crt
gen-secret.sh
#!/bin/bash
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout mooc.key -out mooc.crt -subj "/CN=*.mooc.com/O=*.mooc.com"
kubectl create secret tls mooc-tls --key mooc.key --cert mooc.crt
生成證書
[root@master-001 ~]# sh gen-secret.sh
Generating a 2048 bit RSA private key
.........+++
..........................+++
writing new private key to 'mooc.key'
-----
secret/mooc-tls created
我們查看 ,tls.crt是kubernetes 的規範
[root@master-001 ~]# kubectl get secret mooc-tls -o yaml
apiVersion: v1
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURKekNDQWcrZ0F3SUJBZ0lKQUlCTGUrTEVEcEJSTUEwR0NTcUdTSWIzRFFFQkN3VUFNQ...
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2QUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktZd2dnU2lBZ0VBQW9JQkF.....
kind: Secret
metadata:
creationTimestamp: "2020-01-28T13:48:54Z"
name: mooc-tls
namespace: dev
resourceVersion: "334008"
selfLink: /api/v1/namespaces/dev/secrets/mooc-tls
uid: d12f095c-a79b-4765-a06f-62d32d731eeb
type: kubernetes.io/tls
- 證書掛載到ingress-controller
修改nginx-ingress-controller,在配置中增加==–default-ssl-certifcate=default/mooc-tls==,意思是指定default命名空間下的mooc-tls
[root@master-001 ~]# vi nginx-ingress-controller.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
name: nginx-ingress-controller
namespace: ingress-nginx
spec:
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
updateStrategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
annotations:
prometheus.io/port: "10254"
prometheus.io/scrape: "true"
creationTimestamp: null
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
containers:
- args:
- /nginx-ingress-controller
- --configmap=$(POD_NAMESPACE)/nginx-configuration
- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
- --udp-services-configmap=$(POD_NAMESPACE)/udp-services
- --publish-service=$(POD_NAMESPACE)/ingress-nginx
- --annotations-prefix=nginx.ingress.kubernetes.io
- --default-ssl-certifcate=default/mooc-tls #看這裏
# 增加數據卷掛載,
volumeMounts:
- mountPath: /etc/nginx/template
name: nginx-template
readOnly: true
# end
env:
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
image: siriuszg/nginx-ingress-controller:latest
imagePullPolicy: Always
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
name: nginx-ingress-controller
ports:
- containerPort: 80
hostPort: 80
name: http
protocol: TCP
- containerPort: 443
hostPort: 443
name: https
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
resources: {}
securityContext:
allowPrivilegeEscalation: true
capabilities:
add:
- NET_BIND_SERVICE
drop:
- ALL
runAsUser: 33
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
hostNetwork: true
nodeSelector:
kubernetes.io/os: linux
app: ingress
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: nginx-ingress-serviceaccount
serviceAccountName: nginx-ingress-serviceaccount
terminationGracePeriodSeconds: 300
# 通過configmap指定我們上面創建的nginx.tmpl
volumes:
- name: nginx-template-volume
configMap:
name: nginx-template
items:
- key: nginx.tmpl
path: nginx.tmpl
更新一下
[root@master-001 ~]# kubectl apply -f nginx-ingress-controller.yaml
daemonset.apps/nginx-ingress-controller configured
3 . 指定域名使用創建的tls
然後具體給哪個服務指定一下域名使用哪個tls ,我們給你web-demo 服務指定一下
測試的機器上必須有
web-demo
這個服務
web-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: web-demo
namespace: dev
spec:
rules:
- host: web-dev.mooc.com
http:
paths:
- backend:
serviceName: web-demo
servicePort: 80
path: /
tls:
- hosts:
- web-dev.mooc.com
secretName: mooc-tls #指定我們剛創建的tls
創建一下
[root@master-001 ~]# kubectl apply -f web-ingress.yaml
ingress.extensions/web-demo configured
否則沒有他就不會創建一個web-dev.mooc.com
的https的服務
- 訪問測試
直接在瀏覽器訪問https://web-dev.mooc.com 就可以看到他返回了,表示我們這裏配置證書成功
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-UyEMmyjS-1580869872957)(/Users/zck/Library/Application Support/typora-user-images/image-20200128225447406.png)]
解決問題訪問控制
ingress-nginx session保持
web服務需要會話保持的,需要訪問同一個後端
環境:
有一個service ,有兩個後端一個是web版本一個spring-boot版本,service 輪訓訪問這個兩個後端
配置信息在領悟 Ingress Nginx(上)環境部分有,這裏不展示
Web 版本訪問
spring-boot版本訪問
我們直接修改ingress的配置增加session保持
就可以實現只是訪問一個後端
ingress-session.yaml
#ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/affinity: cookie # cookine保存
nginx.ingress.kubernetes.io/session-cookie-hash: sha1 # session 算法
nginx.ingress.kubernetes.io/session-cookie-name: route # 隨便起的一個名字 ,cookie 名字
name: spring-boot-demo
# namespace: dev
spec:
rules:
- host: spring-boot.demo.com
http:
paths:
- path: /
backend:
serviceName: spring-boot-demo
servicePort: 80
創建下
[root@master-001 ~]# kubectl apply -f ingress-session.yaml
ingress.extensions/spring-boot-demo created
這樣他就一直保持一個後端訪問了
ingress+ 金絲雀模式 流量控制
小流量
剛上線不知道服務有沒有問題先把流量切到剛上線的服務切10%,沒有問題開20%,50%,100%。
流量控制基於金絲雀模式
ingress-nginx 從 0.21.0 開始支持金絲雀(canary)模式
金絲雀annotations使Ingress規範可以作爲路由到請求的替代服務
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "version"
nginx.ingress.kubernetes.io/canary-by-header-value: "canary"
nginx.ingress.kubernetes.io/canary-by-cookie: "canary-cookie"
nginx.ingress.kubernetes.io/canary-weight: <weight>
nginx.ingress.kubernetes.io/canary-by-header
用於通知Ingress將請求路由到Canary Ingress中指定的服務的標頭。當請求標頭設置always時,它將被路由到金絲雀。當標頭設置never爲時,它將永遠不會被路由到金絲雀。對於任何其他值,將忽略標頭,並通過優先級將請求與其他金絲雀規則進行比較。nginx.ingress.kubernetes.io/canary-by-header-value:
要匹配的標頭值,用於通知Ingress將請求路由到Canary Ingress中指定的服務。當請求標頭設置爲此值時,它將被路由到金絲雀。對於任何其他標頭值,標頭將被忽略,並且請求與其他金絲雀規則的優先級進行比較。此註釋必須與nginx.ingress.kubernetes.io/canary-by-header一起使用。nginx.ingress.kubernetes.io/canary-by-header允許自定義標頭值而不是使用硬編碼值的擴展。如果nginx.ingress.kubernetes.io/canary-by-header未定義註釋,則沒有任何效果。
nginx.ingress.kubernetes.io/canary-by-cookie:
用於通知Ingress將請求路由到Canary Ingress中指定的服務的cookie。當cookie值設置always時,它將被路由到金絲雀。當cookie被設置never時,它將永遠不會被路由到金絲雀。對於任何其他值,將忽略cookie並將請求與其他金絲雀規則進行優先比較。
nginx.ingress.kubernetes.io/canary-weight:
該路由到金絲雀Ingress中指定的服務的隨機請求的整數(0 – 100)百分比。權重爲0意味着該金絲雀規則不會向Canary入口中的服務發送任何請求。權重爲100意味着所有請求都將被髮送到Ingress中指定的替代服務。
優先順序如下: canary-by-header -> canary-by-cookie -> canary-weight
已知限制目前,每個Ingress規則最多可以應用一個金絲雀入口。
場景:我現在有兩個服務分別是web-canary-a
和web-canary-b
同時都有service,然後有一個ingress名字是web-canary-a
,他只訪問 web-canary-a的服務,這時候我們要上線web-canary-b
web-canary-a.yaml
#deploy
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-canary-a
namespace: canary
spec:
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
selector:
matchLabels:
app: web-canary-a
replicas: 1
template:
metadata:
labels:
app: web-canary-a
spec:
containers:
- name: web-canary-a
image: hub.zhang.com/kubernetes/spring-boot-demo:v1 #版本不一樣
ports:
- containerPort: 8080
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 20
periodSeconds: 10
failureThreshold: 3
successThreshold: 1
timeoutSeconds: 5
readinessProbe:
httpGet:
path: /
port: 8080
scheme: HTTP
initialDelaySeconds: 20
periodSeconds: 10
failureThreshold: 1
successThreshold: 1
timeoutSeconds: 5
---
#service
apiVersion: v1
kind: Service
metadata:
name: web-canary-a
namespace: canary
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8080
selector:
app: web-canary-a
type: ClusterIP
web-canary-b.yaml
#deploy
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-canary-b
namespace: canary
spec:
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
selector:
matchLabels:
app: web-canary-b
replicas: 1
template:
metadata:
labels:
app: web-canary-b
spec:
containers:
- name: web-canary-b
image: hub.zhang.com/kubernetes/spring-boot-demo:v2 #版本不一樣
ports:
- containerPort: 8080
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 20
periodSeconds: 10
failureThreshold: 3
successThreshold: 1
timeoutSeconds: 5
readinessProbe:
httpGet:
path: /
port: 8080
scheme: HTTP
initialDelaySeconds: 20
periodSeconds: 10
failureThreshold: 1
successThreshold: 1
timeoutSeconds: 5
---
#service
apiVersion: v1
kind: Service
metadata:
name: web-canary-b
namespace: canary
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8080
selector:
app: web-canary-b
type: ClusterIP
ingress-common.yaml
#ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: web-canary-a
namespace: canary
spec:
rules:
- host: canary.demo.com
http:
paths:
- path: /
backend:
serviceName: web-canary-a #只是指定web-canary-a的service
servicePort: 80
全部創建一下:
[root@master-001 ~]# kubectl apply -f web-canary-a.yaml
deployment.apps/web-canary-a created
service/web-canary-a created
[root@master-001 ~]# kubectl apply -f web-canary-b.yaml
deployment.apps/web-canary-b created
service/web-canary-b created
[root@master-001 ~]# kubectl apply -f ingress-common.yaml
ingress.extensions/web-canary-a created
這個時候我們只能訪問web-canary-a
的服務
ingress + 金絲雀模式 流量定向訪問
還是跟上面的流量控制一樣都依賴金絲雀模式實現
這個時候我們要上線web-canary-b
而且流量只是給web-canary-b
10%
主要使用 金絲雀模式的 nginx.ingress.kubernetes.io/canary-weight:
同一個域名服務canary.demo.com
nginx.ingress.kubernetes.io/canary: “true” # 開啓金絲雀
nginx.ingress.kubernetes.io/canary-weight: “10” # 流量權重分配爲10
nginx.ingress.kubernetes.io/canary-weight:
該路由到金絲雀Ingress中指定的服務的隨機請求的整數(0 – 100)百分比。權重爲0意味着該金絲雀規則不會向Canary入口中的服務發送任何請求。權重爲100意味着所有請求都將被髮送到Ingress中指定的替代服務。
ingress-weight.yaml
#ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: web-canary-b
namespace: canary
annotations:
nginx.ingress.kubernetes.io/canary: "true" # 開啓金絲雀
nginx.ingress.kubernetes.io/canary-weight: "10" # 流量權重分配爲10
spec:
rules:
- host: canary.demo.com
http:
paths:
- path: /
backend:
serviceName: web-canary-b
servicePort: 80
創建下
[root@master-001 ~]# kubectl apply -f ingress-weight.yaml
ingress.extensions/web-canary-b created
我們偶爾可以看到web-canary-b
,大部分都web-canary-b
沒問題就把 nginx.ingress.kubernetes.io/canary-weight: 改成90
這樣全部百分90都是web-canary-b
#ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: web-canary-b
namespace: canary
annotations:
nginx.ingress.kubernetes.io/canary: "true" # 開啓金絲雀
nginx.ingress.kubernetes.io/canary-weight: "90" # 流量權重分配爲90
spec:
rules:
- host: canary.demo.com
http:
paths:
- path: /
backend:
serviceName: web-canary-b
servicePort: 80
[root@master-001 ~]# kubectl apply -f ingress-weight.yaml
ingress.extensions/web-canary-b configured
還有一種場景就是我不讓用戶去訪問我們要上線的服務,讓測試人員去訪問,測試完成我在走上線流程。
nginx.ingress.kubernetes.io/canary-by-cookie:
用於通知Ingress將請求路由到Canary Ingress中指定的服務的cookie。當cookie值設置always時,它將被路由到金絲雀。當cookie被設置never時,它將永遠不會被路由到金絲雀。對於任何其他值,將忽略cookie並將請求與其他金絲雀規則進行優先比較
主要使用 金絲雀模式的 nginx.ingress.kubernetes.io/canary-by-cookie:
ingress-cookie.yaml
#ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: web-canary-b
namespace: canary
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-cookie: "web-canary" # 設置金絲雀cookie 名字
spec:
rules:
- host: canary.demo.com
http:
paths:
- path: /
backend:
serviceName: web-canary-b
servicePort: 80
創建下
[root@master-001 ~]# kubectl apply -f ingress-cookie.yaml
ingress.extensions/web-canary-b configured
我們訪問下發現全是web-canary-a
版本
這個時候怎麼訪問web-canary-b
呢需要添加一個cookie名字上面我們在配置中寫的是web-canary
,cookie值是always
注意:發現只有火狐瀏覽器可以添加cookie
這裏可以實現一個流量的定向訪問了,這種手動加cookie只是測試,
但是我們真實中舉個例子:
我們新上線的服務只是讓女性訪問,看下女性的反饋,男性還是訪問之前的,這樣我們就可以根據登錄用戶性別做出判斷,在程序設置cookie 值=always了。
除了 nginx.ingress.kubernetes.io/canary-by-cookie:
進行定向流量之外還可以通過header實現:nginx.ingress.kubernetes.io/canary-by-header:
主要使用 金絲雀模式的 nginx.ingress.kubernetes.io/canary-by-header:
還是通過web-canary-b
測試
ingress-header.yaml
#ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: web-canary-b
namespace: canary
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "web-canary"
spec:
rules:
- host: canary.demo.com
http:
paths:
- path: /
backend:
serviceName: web-canary-b
servicePort: 80
創建下
[root@master-001 ~]# kubectl apply -f ingress-header.yaml
ingress.extensions/web-canary-b configured
這時候瀏覽器已經只是訪問web-canary-a
了,
我們做測試可以用curl
方便測試,我們看大加上header web-canary 值等於always
就訪問到web-canary-a
了
➜ ~ curl -H 'web-canary: always' http://canary.demo.com/
😄😂我有變了啦啦......%
把nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "version"
nginx.ingress.kubernetes.io/canary-by-header-value: "canary"
nginx.ingress.kubernetes.io/canary-by-cookie: "canary-cookie"
nginx.ingress.kubernetes.io/canary-weight: <weight>
組合使用
優先級順序canary-by-header -> canary-by-cookie -> canary-weight
如果header
就按他來,沒有就按 cookie
,沒有cookie
就按權重weight
分配流量。
#ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: web-canary-b
namespace: canary
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "web-canary"
nginx.ingress.kubernetes.io/canary-by-cookie: "web-canary"
nginx.ingress.kubernetes.io/canary-weight: "90"
spec:
rules:
- host: canary.demo.com
http:
paths:
- path: /
backend:
serviceName: web-canary-b
servicePort: 80
創建下
[root@master-001 ~]# kubectl apply -f ingress-compose.yaml
ingress.extensions/web-canary-b configured
之前我們也講過金絲雀但是沒有配合ingress,ingress+金絲雀模式能把流量控制的很精準。