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/