istio1.1(openshift) 流量路由
1、准备测试应用
准备两个nginx Pod和一个proxy
创建应用
apiVersion: apps.openshift.io/v1 kind: DeploymentConfig metadata: name: www-v1 namespace: dev spec: selector: app: www replicas: 1 template: metadata: labels: app: www version: v1 spec: containers: - name: www image: nginx ports: - containerPort: 80 --- apiVersion: apps.openshift.io/v1 kind: DeploymentConfig metadata: name: www-v2 namespace: dev spec: selector: app: www replicas: 1 template: metadata: labels: app: www version: v2 spec: containers: - name: www image: nginx ports: - containerPort: 80 --- apiVersion: apps.openshift.io/v1 kind: DeploymentConfig metadata: name: www-proxy namespace: dev spec: selector: app: www-proxy replicas: 1 template: metadata: labels: app: www-proxy spec: containers: - name: www image: nginx ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: www namespace: dev spec: selector: app: www ports: - name: http protocol: TCP port: 80 targetPort: 80 --- apiVersion: v1 kind: Service metadata: name: www-proxy namespace: dev spec: selector: app: www-proxy ports: - name: http protocol: TCP port: 80 targetPort: 80
注意Service中的 - name: http一定要加上,后面要匹配流量类型
# oc create -f app.yaml
准备3个Config Maps
www-v1
#获取客户端真实IP set_real_ip_from 10.0.0.0/8; set_real_ip_from 192.168.0.0/16; set_real_ip_from 172.16.0.0/12; set_real_ip_from 100.0.0.0/8; set_real_ip_from 127.0.0.1; real_ip_header X-Forwarded-For; real_ip_recursive on; #日志相关格式配置 log_format json '{"@timestamp":"$time_local",' '"podname":"$hostname",' '"clientip":"$remote_addr",' '"request":"$request",' '"status":"$status",' '"forwarded_proto":"$http_x_forwarded_proto",' '"scheme":"$scheme",' '"request_method": "$request_method",' '"size":"$body_bytes_sent",' '"request_time":"$request_time",' '"upstreamtime":"$upstream_response_time",' '"upstreamhost":"$upstream_addr",' '"http_host":"$host",' '"url":"$uri",' '"forwarded_for":"$http_x_forwarded_for",' '"referer":"$http_referer",' '"agent":"$http_user_agent"}'; access_log /dev/stdout json; error_log /dev/stderr error; server { location / { default_type text/html; return 200 'nginx-v1'; } }
www-v2
#获取客户端真实IP set_real_ip_from 10.0.0.0/8; set_real_ip_from 192.168.0.0/16; set_real_ip_from 172.16.0.0/12; set_real_ip_from 100.0.0.0/8; set_real_ip_from 127.0.0.1; real_ip_header X-Forwarded-For; real_ip_recursive on; #日志相关格式配置 log_format json '{"@timestamp":"$time_local",' '"podname":"$hostname",' '"clientip":"$remote_addr",' '"request":"$request",' '"status":"$status",' '"forwarded_proto":"$http_x_forwarded_proto",' '"scheme":"$scheme",' '"request_method": "$request_method",' '"size":"$body_bytes_sent",' '"request_time":"$request_time",' '"upstreamtime":"$upstream_response_time",' '"upstreamhost":"$upstream_addr",' '"http_host":"$host",' '"url":"$uri",' '"forwarded_for":"$http_x_forwarded_for",' '"referer":"$http_referer",' '"agent":"$http_user_agent"}'; access_log /dev/stdout json; error_log /dev/stderr error; server { location / { default_type text/html; return 200 'nginx-v2'; } }
www-proxy
#获取客户端真实IP set_real_ip_from 10.0.0.0/8; set_real_ip_from 192.168.0.0/16; set_real_ip_from 172.16.0.0/12; set_real_ip_from 100.0.0.0/8; set_real_ip_from 127.0.0.1; real_ip_header X-Forwarded-For; real_ip_recursive on; #日志相关格式配置 log_format json '{"@timestamp":"$time_local",' '"podname":"$hostname",' '"clientip":"$remote_addr",' '"request":"$request",' '"status":"$status",' '"forwarded_proto":"$http_x_forwarded_proto",' '"scheme":"$scheme",' '"request_method": "$request_method",' '"size":"$body_bytes_sent",' '"request_time":"$request_time",' '"upstreamtime":"$upstream_response_time",' '"upstreamhost":"$upstream_addr",' '"http_host":"$host",' '"url":"$uri",' '"forwarded_for":"$http_x_forwarded_for",' '"referer":"$http_referer",' '"agent":"$http_user_agent"}'; access_log /dev/stdout json; error_log /dev/stderr error; server { location / { proxy_http_version 1.1; proxy_pass http://www; } }
挂载
# oc set volume dc/www-v1 --add --overwrite --name=config-volume --mount-path=/etc/nginx/conf.d --source='{"configMap": { "name": "www-v1"}}' # oc set volume dc/www-v2 --add --overwrite --name=config-volume --mount-path=/etc/nginx/conf.d --source='{"configMap": { "name": "www-v2"}}' # oc set volume dc/www-proxy --add --overwrite --name=config-volume --mount-path=/etc/nginx/conf.d --source='{"configMap": { "name": "www-proxy"}}'
为了方便测试www-proxy 需要绑定外部Ingress 比如openshif route
apiVersion: route.openshift.io/v1 kind: Route metadata: name: www-proxy namespace: dev spec: host: www-proxy.ingress.com to: kind: Service name: www-proxy port: targetPort: 80
2、路由流量
默认情况下在内网网络访问www应用,可以看出来流量是轮询的
# curl www-proxy.ingress.com nginx-v2 nginx-v2 nginx-v1 nginx-v2 nginx-v1 nginx-v1
创建istio VirtualService、DestinationRule 路由流量
kind: VirtualService metadata: name: www-intranet namespace: dev spec: hosts: - www http: - route: - destination: host: www subset: v2 --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: www namespace: dev spec: host: www subsets: - labels: version: v1 name: v1 - labels: version: v2 name: v2 trafficPolicy: loadBalancer: simple: ROUND_ROBIN
这里的http要对应Service -name 的值
测试一下,此时应该只会返回"nginx-v2"
# curl www-prxoy.ingress.com nginx-v2 nginx-v2 nginx-v2 nginx-v2 nginx-v2
根据权重路由流量
spec: hosts: - www http: - route: - destination: host: www subset: v1 weight: 20 - destination: host: www subset: v2 weight: 80
测试一下
# curl www-proxy.ingress.com nginx-v1 nginx-v2 nginx-v2 nginx-v2 nginx-v2 nginx-v1 nginx-v2 nginx-v2
下面介绍不通过www-proxy直接路由外部流量,需要额外创建istio Gateway并和VirtualService绑定
apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: default-gateway namespace: dev spec: selector: istio: ingressgateway servers: - hosts: - '*' port: name: http number: 80 protocol: HTTP --- kind: VirtualService metadata: name: www namespace: dev spec: gateways: - default-gateway hosts: - www.ingress.com http: - route: - destination: host: www subset: v1 --- apiVersion: route.openshift.io/v1 kind: Route metadata: labels: app: istio-ingressgateway chart: gateways heritage: Tiller istio: ingressgateway release: istio name: www namespace: istio-system spec: host: www.ingress.com port: targetPort: http2 to: kind: Service name: istio-ingressgateway
注意如果没有外部ingress 使用NodePort的方式引入流量,并且Gateway和VirtualService任意一个hosts没有*,这时候Gateway无法识别具体的host域名
那么可以修改istio-ingressgateway的Deployment用hostPort直接暴露80和443端口,在把istio-ingressgateway的Pod绑定到固定的节点上运行
... - containerPort: 80 hostPort: 80 protocol: TCP - containerPort: 443 hostPort: 443 protocol: TCP ....
下面测试一下
# curl www.ingress.com nginx-v1 nginx-v1 nginx-v1 nginx-v1 nginx-v1