istio 灰度实验
使用nginx模拟2个版本的后端服务,一个nginx做代理转发服务。
先结论:istio在匹配路由时使用服务hosts(services名)做匹配,如果hosts没匹配上路由规则不生效。
2个版本的nginx服务
启动后手工进入修改index.html 为 v1,v2。方便后期验证。
sh
echo v1 > /usr/share/nginx/html/index.html
echo v2 > /usr/share/nginx/html/index.html
yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-v1
labels:
app: nginx
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: nginx
version: v1
template:
metadata:
labels:
app: nginx
version: v1
spec:
containers:
- image: nginx:1.17.8-alpine
name: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-v2
labels:
app: nginx
version: v2
spec:
replicas: 1
selector:
matchLabels:
app: nginx
version: v2
template:
metadata:
labels:
app: nginx
version: v2
spec:
containers:
- image: nginx:1.17.8-alpine
name: nginx
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
ports:
- name: http
port: 80
targetPort: 80
selector:
app: nginx
type: ClusterIP
代理转发服务
yaml
---
apiVersion: v1
data:
nginx.conf: |-
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 131072;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
underscores_in_headers on;
ignore_invalid_headers off;
log_format main '$remote_addr - $remote_user [$time_local] "$host" "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
server {
listen 80;
server_name _;
# Add header
# 这里重点,代理转发服务不能加上源hosts,否则转发会匹配不上istio路由规则。
# proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Scheme $scheme;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;
# Route
location ^~ / {
proxy_pass http://nginx:80;
}
}
}
kind: ConfigMap
metadata:
labels:
app: nginx-route
name: nginx-route
---
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx-route
service: nginx-route
name: nginx-route
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx-route
sessionAffinity: None
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-route
name: nginx-route
spec:
replicas: 1
selector:
matchLabels:
app: nginx-route
template:
metadata:
labels:
app: nginx-route
spec:
containers:
- image: nginx:1.22.1-alpine
imagePullPolicy: IfNotPresent
name: nginx-route
ports:
- containerPort: 80
name: http
protocol: TCP
resources:
limits:
cpu: "2"
memory: 1Gi
requests:
cpu: 20m
memory: 256Mi
volumeMounts:
- mountPath: /etc/nginx/nginx.conf
name: configs
subPath: nginx.conf
volumes:
- configMap:
name: nginx-route
name: configs
配置istio gateway服务
yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: gateway
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: nginx-route
spec:
hosts:
- "*"
gateways:
- gateway
http:
- match:
- uri:
exact: /
route:
- destination:
host: nginx-route
port:
number: 80
# 全部请求到nginx-route转发服务,再根据路由规则转发到不同的后端。
DestinationRule
yaml
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: nginx
spec:
host: nginx
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
查看服务状态
sh
[root@test]# kubectl get pod,svc,configmap
NAME READY STATUS RESTARTS AGE
pod/nginx-route-5458f4b5ff-jnsfm 2/2 Running 3 22h
pod/nginx-v1-7cdbb97474-nds9f 2/2 Running 2 23h
pod/nginx-v2-7f87f869c-gskqw 2/2 Running 2 23h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 23h
service/nginx ClusterIP 10.110.225.75 <none> 80/TCP 23h
service/nginx-route ClusterIP 10.103.42.115 <none> 80/TCP 22h
NAME DATA AGE
configmap/istio-ca-root-cert 1 23h
configmap/nginx-route 1 22h
验证
配置好上面的服务使用crul请求istio-ingressgateway。
1、流量被随机分配到不同的服务。
sh
[root@test]# IG=`kubectl get svc -A | grep ingressgateway | awk '{print $4}'`
[root@test]# for i in `seq 10`; do curl http://$IG;done
v1
v1
v1
v2
v1
v2
v2
v1
v2
v1
2、加上路由规则VirtualService
全部流量都访问v2服务
yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: nginx
spec:
hosts:
- nginx
http:
- route:
- destination:
host: nginx
subset: v2
再请求全部流量都访问的v2
sh
[root@test]# IG=`kubectl get svc -A | grep ingressgateway | awk '{print $4}'`
[root@test]# for i in `seq 10`; do curl http://$IG;done
v2
v2
v2
v2
v2
v2
v2
v2
v2
v2
3、修改nginx-route转发服务,带上源hosts后再请求。
configmap修改后须要重启代理服务生效。
sh
server {
listen 80;
server_name _;
# Add header
# 这里重点,代理转发服务不能加上源hosts,否则转发会匹配不上istio路由规则。
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Scheme $scheme;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;
# Route
location ^~ / {
proxy_pass http://nginx:80;
}
再请求发现又随机到不同的服务而不是按vs配置的只路由到v2服务。
sh
[root@test]# IG=`kubectl get svc -A | grep ingressgateway | awk '{print $4}'`
[root@test]# for i in `seq 10`; do curl http://$IG;done
v1
v2
v1
v2
v1
v2
v1
v1
v1
v2