Istio 之 VirtualService-虛擬服務-
VirtualService(虛擬服務)
VirtualService
中文名稱虛擬服務,是 istio 中一個重要的資源, 它定義了一系列針對指定服務的流量路由規則。每個路由規則都針對特定協議的匹配規則。如果流量符合這些特徵,就會根據規則發送到服務註冊表中的目標服務(或者目標服務的子集或版本)。
學習目標
-
VirtualService 和 k8s service 的區別
-
exportTo 生效命名空間
-
基於 TLS 的 HTTPS 請求
-
基於 TCP 的各種服務
VirtualService 和 k8s service 的區別
如果沒有 Istio virtual service,僅僅使用 k8s service 的話,那麼只能實現最基本的流量負載均衡轉發,但是就不能實現類似按百分比來分配流量等更加複雜、豐富、細粒度的流量控制了。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: my-namespace
spec:
hosts:
- "svc.test.com"
http:
- match:
- uri:
prefix: /
route:
- destination:
host: nginx-web-svc.default.svc.cluster.local # 代理的SVC
exportTo 生效命名空間
1. 當前名稱空間有效
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: my-namespace
spec:
exportTo:
- "."
hosts:
- "svc.test.com"
http:
- match:
- uri:
prefix: /
route:
- destination:
host: nginx-web-svc.default.svc.cluster.local # 代理的SVC
2. 所有名稱空間有效
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: my-namespace
spec:
exportTo:
- "*"
hosts:
- "svc.test.com"
http:
- match:
- uri:
prefix: /
route:
- destination:
host: nginx-web-svc.default.svc.cluster.local # 代理的SVC
VirtualService + Gateway
Gateway 名稱列表,Sidecar 會據此使用路由。VirtualService 對象可以用於網格中的 Sidecar,也可以用於一個或多個 Gateway。這裏公開的選擇條件可以在協議相關的路由過濾條件中進行覆蓋。保留字 mesh 用來指代網格中的所有 Sidecar。當這一字段被省略時,就會使用缺省值(mesh),也就是針對網格中的所有 Sidecar 生效。如果提供了 gateways 字段,這一規則就只會應用到聲明的 Gateway 之中。要讓規則同時對 Gateway 和網格內服務生效,需要顯式的將 mesh 加入 gateways 列表。
單個 gateway
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: web-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: httpd
protocol: HTTP
hosts:
- "svc.test.com"
- port:
number: 80
name: nginx
protocol: HTTP
hosts:
- "svc.test.com"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: my-namespace
spec:
hosts:
- "svc.test.com"
gateways:
- web-gateway
http:
- match:
- uri:
prefix: /
route:
- destination:
host: nginx-web-svc.default.svc.cluster.local
port:
number: 80
測試結果
/ # while true; do wget -q -O- http://svc.test.com:32623 ;sleep 1; done
<html><body><h1>It works!</h1></body></html>
<h1>Welcome to nginx!</h1>
<h1>Welcome to nginx!</h1>
<html><body><h1>It works!</h1></body></html>
多個 Gateway
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: web-gateway-nginx
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: nginx
protocol: HTTP
hosts:
- "svc.test.com"
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: web-gateway-httpd
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: httpd
protocol: HTTP
hosts:
- "svc.test.com"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: my-namespace
spec:
hosts:
- "svc.test.com"
gateways:
- web-gateway-nginx
- web-gateway-httpd
http:
- match:
- uri:
prefix: /
route:
- destination:
host: nginx-web-svc.default.svc.cluster.local
port:
number: 80
測試結果
/ # while true; do wget -q -O- http://svc.test.com:32623 ;sleep 1; done
<html><body><h1>It works!</h1></body></html>
<html><body><h1>It works!</h1></body></html>
<html><body><h1>It works!</h1></body></html>
<h1>Welcome to nginx!</h1>
<html><body><h1>It works!</h1></body></html>
<h1>Welcome to nginx!</h1>
<html><body><h1>It works!</h1></body></html>
不同命名空間下的 Gateway
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: web-gateway-httpd
namespace: test
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: httpd
protocol: HTTP
hosts:
- "svc.test.com"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: my-namespace
spec:
hosts:
- "svc.test.com"
gateways:
- test/web-gateway-httpd
http:
- match:
- uri:
prefix: /
route:
- destination:
host: httpd-web-svc.test.svc.cluster.local
port:
number: 80
省略 gateways 跨域
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: nginx-web
labels:
app: nginx
deploy: nginx
server: web
spec:
selector:
matchLabels:
app: nginx
deploy: nginx
server: web
template:
metadata:
labels:
app: nginx
deploy: nginx
server: web
spec:
containers:
- name: nginx
image: alvinos/nginx:v1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-web-svc
labels:
app: nginx-web-svc
deploy: nginx-web-svc
spec:
ports:
- port: 80
targetPort: 80
name: nginx
protocol: TCP
selector:
server: web
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: web-gateway-nginx
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: nginx
protocol: HTTP
hosts:
- "svc.test.com"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: allow
spec:
hosts:
- "svc.test.com"
gateways:
- default/web-gateway-nginx
http:
- corsPolicy:
allowCredentials: true # 響應頭表示是否可以將對請求的響應暴露給頁面。返回true則可以,其他值均不可以。
allowOrigins: # 響應頭指定了該響應的資源是否被允許與給定的origin共享。
- exact: "http://svc.test.com:32623" # 完全匹配
match:
- uri:
prefix: /
route:
- destination:
host: nginx-web-svc.default.svc.cluster.local
port:
number: 80
allowOrigins prefix(前綴匹配)
http:
- corsPolicy:
allowCredentials: true # 響應頭表示是否可以將對請求的響應暴露給頁面。返回true則可以,其他值均不可以。
allowOrigins: # 響應頭指定了該響應的資源是否被允許與給定的origin共享。
- prefix: "http://svc.test.com"
allowOrigins regex(正則匹配)
http:
- corsPolicy:
allowCredentials: true # 響應頭表示是否可以將對請求的響應暴露給頁面。返回true則可以,其他值均不可以。
allowOrigins: # 響應頭指定了該響應的資源是否被允許與給定的origin共享。
- regex: ".*"
設置 exposeHeaders
http:
- corsPolicy:
allowCredentials: true
allowOrigins:
- prefix: "http://localhost"
exposeHeaders: # 響應頭指定了該響應首部添加響應header頭
- test
- test2
設置 allowHeaders
allowHeaders:
- X-Custom-Header
- content-type
設置 allowMethods
allowMethods:
- GET
- DELETE
長短 fqdn
# 在default名稱空間創建vs
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: my-fqdn
spec:
hosts:
- "nginx.default.svc.cluster.local" # 長fqdn
- "nginx" # 短fqdn
http:
- match:
- uri:
prefix: /
route:
- destination:
host: nginx-web-svc.default.svc.cluster.local
port:
number: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
ports:
- port: 80
name: http
selector:
app: nginx
基於 TLS 的 HTTPS 請求
一個有序列表,對應的是透傳 TLS 和 HTTPS 流量。路由過程通常利用 ClientHello 消息中的 SNI 來完成。TLS 路由通常應用在 https-、tls- 前綴的平臺服務端口,或者經 Gateway 透傳的 HTTPS、TLS 協議端口,以及使用 HTTPS 或者 TLS 協議的 ServiceEntry 端口上。注意:沒有關聯 VirtualService 的 https- 或者 tls- 端口流量會被視爲透傳 TCP 流量。
1、創建證書
# 因爲是測試環境,我在這裏手動簽發證書,如果是生產環境最好在雲服務商哪裏購買證書
[root@kubernetes-master-01 cert]# openssl genrsa -out tls.key 2048
[root@kubernetes-master-01 cert]# openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=ShangHai/L=ShangHai/O=Ingress/CN=svc.test.com
2、創建 secret
[root@kubernetes-master-01 cert]# kubectl -n default create secret tls nginx-tls --cert=tls.crt --key=tls.key
secret/nginx-tls created
[root@kubernetes-master-01 cert]# kubectl get secrets
NAME TYPE DATA AGE
nginx-tls kubernetes.io/tls 2 19s
3、創建 Nginx 配置文件
---
kind: ConfigMap
apiVersion: v1
metadata:
name: tls
labels:
app: tls
data:
nginx.conf: |
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 443 ssl;
ssl_certificate /etc/nginx-server-certs/tls.crt;
ssl_certificate_key /etc/nginx-server-certs/tls.key;
server_name _;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
}
4、創建 Deployment 資源
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: tls
spec:
selector:
matchLabels:
app: tls
template:
metadata:
labels:
app: tls
spec:
containers:
- name: nginx
imagePullPolicy: IfNotPresent
image: nginx
volumeMounts:
- mountPath: /etc/nginx/nginx.conf
name: nginxconfig
readOnly: true
subPath: nginx.conf
- mountPath: /etc/nginx-server-certs
name: nginx-tls
readOnly: true
volumes:
- name: nginxconfig
configMap:
name: tls
items:
- key: nginx.conf
path: nginx.conf
- name: nginx-tls
secret:
secretName: nginx-tls
---
kind: Service
apiVersion: v1
metadata:
name: tls
labels:
app: tls
spec:
ports:
- port: 443
targetPort: 443
name: tls
selector:
app: tls
5、創建 Gateway 資源
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: tls
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 443
name: tls
protocol: HTTPS
hosts:
- "svc.test.com"
tls:
mode: PASSTHROUGH
6、創建 VirtualService 資源
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: nginx
spec:
hosts:
- tls.test.com
gateways:
- tls
tls:
- match:
- port: 443
sniHosts:
- tls.test.com
route:
- destination:
host: tls.default.svc.cluster.local
port:
number: 443
基於 TCP 的各種服務
一個針對透傳 TCP 流量的有序路由列表。TCP 路由對所有 HTTP 和 TLS 之外的端口生效。進入流量會使用匹配到的第一條規則。
1、創建基礎服務
---
apiVersion: v1
kind: Service
metadata:
name: tcp-echo
labels:
app: tcp-echo
service: tcp-echo
spec:
ports:
- name: tcp
port: 3306
selector:
app: tcp-echo
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tcp-echo
spec:
replicas: 1
selector:
matchLabels:
app: tcp-echo
version: v1
template:
metadata:
labels:
app: tcp-echo
version: v1
spec:
containers:
- name: tcp-echo
image: mysql:5.7
imagePullPolicy: IfNotPresent
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456"
ports:
- containerPort: 3306
2、創建網關服務
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: tcp-echo-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 31400
name: tcp
protocol: TCP
hosts:
- "mysql.test.com"
3、創建 VirtualService 資源
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: tcp-echo
spec:
hosts:
- "mysql.test.com"
gateways:
- tcp-echo-gateway
tcp:
- match:
- port: 31400
route:
- destination:
host: tcp-echo
port:
number: 3306
4、部署結果
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/4vT7ApEq9X1JiLB45sG4lQ