安装
需要先准备一个 kubernetes 集群,这里是用的 k3s 安装 的 1.25 版本。
下载 istio
先下载 istio 安装文件,执行:
1
|
curl -L https://istio.io/downloadIstio | sh -
|
如果测试机器下载不了,可以手动下载脚本和安装文件传到测试机器,然后将 istioctl 文件路径加到系统环境变量中:
1
2
|
vim ~/.bashrc # 最后增加 export PATH={/xxx/istio-1.16.1}/bin:$PATH
source ~/.bashrc
|
安装 istio
执行istioctl install --set profile=demo -y
安装官方的 demo 配置组合,在 k3s 集群中,执行出现了以下问题:
1
2
|
root@alton:~# istioctl install --set profile=demo -y
Error: Get "https://127.0.0.1:6443/api?timeout=32s": x509: certificate signed by unknown authority
|
后面才发现问题可能是,以前将 k3s 的 config 进行过复制操作,但是最近认证已经变更了,而~/.kube/config 还是老的,istioctl默认是从~/.kube/config获取集群信息的,导致无法识别,解决办法:重新再执行以下命令复制即可。最好是在安装时,设置环境变量KUBECONFIG="/root/.kube/config",因为k3s的kubectl命令默认使用的配置路径是/etc/rancher/k3s/k3s.yaml。
1
|
cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
|
给命名空间添加标签,指示 Istio 在部署应用的时候,自动注入 Envoy 边车代理:
1
|
kubectl label namespace default istio-injection=enabled
|
部署测试
部署 Bookinfo
使用官网示例,部署 Bookinfo 应用:
1
2
|
cd istio-1.16.1
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
|
等待部署完成,查看 pods:
1
2
3
4
5
6
7
8
|
root@alton:~/zt/istio/istio-1.16.1# kubectl get pods
NAME READY STATUS RESTARTS AGE
reviews-v1-569db879f5-6qgmk 2/2 Running 0 20s
ratings-v1-5f9699cfdf-nk8fn 2/2 Running 0 20s
details-v1-5ffd6b64f7-wdwb7 2/2 Running 0 20s
reviews-v2-65c4dc6fdc-9bbjj 2/2 Running 0 20s
productpage-v1-979d4d9fc-fknt8 2/2 Running 0 20s
reviews-v3-c9c4fb987-nfvrq 2/2 Running 0 20s
|
通过kubectl get pods reviews-v1-569db879f5-6qgmk -oyaml
查看 pods 描述,可以看到注入了一个名为“istio-proxy”的 sidecar pods,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
- args:
- proxy
- sidecar
- --domain
- $(POD_NAMESPACE).svc.cluster.local
- --proxyLogLevel=warning
- --proxyComponentLogLevel=misc:error
- --log_output_level=default:info
- --concurrency
- "2"
image: docker.io/istio/proxyv2:1.16.1
imagePullPolicy: IfNotPresent
name: istio-proxy
ports:
- containerPort: 15090
name: http-envoy-prom
protocol: TCP
readinessProbe:
failureThreshold: 30
httpGet:
path: /healthz/ready
port: 15021
scheme: HTTP
initialDelaySeconds: 1
periodSeconds: 2
successThreshold: 1
timeoutSeconds: 3
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
# 部分省略
|
验证是否部署成功:
1
2
|
root@alton:~/zt/istio/istio-1.16.1# kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>
|
在集群外部访问
要开放访问,您需要创建 Istio 入站网关, 它会在网格边缘把一个路径映射到路由:
1
|
kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
|
如果是通过 Minikube 安装的集群,可以使用 Minikube 隧道提供一个外部负载均衡器。这里使用的 k3s,只能通过机器的 ip 和 nodePort 来访问。
1
2
|
root@alton:~/zt/istio/istio-1.16.1# kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}'
31779
|
查看这个 svc,主要是向集群外部暴露访问地址和端口,上面是获取的 http 的 nodePort 端口。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
apiVersion: v1
kind: Service
metadata:
name: istio-ingressgateway
namespace: istio-system
spec:
allocateLoadBalancerNodePorts: true
clusterIP: 10.43.157.67
clusterIPs:
- 10.43.157.67
externalTrafficPolicy: Cluster
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: status-port
nodePort: 30587
port: 15021
protocol: TCP
targetPort: 15021
- name: http2
nodePort: 31779
port: 80
protocol: TCP
targetPort: 8080
- name: https
nodePort: 30159
port: 443
protocol: TCP
targetPort: 8443
- name: tcp
nodePort: 31621
port: 31400
protocol: TCP
targetPort: 31400
- name: tls
nodePort: 31129
port: 15443
protocol: TCP
targetPort: 15443
selector:
app: istio-ingressgateway
istio: ingressgateway
sessionAffinity: None
type: LoadBalancer
|
在浏览器中,使用http://nodeip:31779/productpage
就可以访问集群了,nodeip 即 k3s 集群 node 的外网 ip 地址。
测试 istio 特性
配置请求路由
需要使用目标规则来定义 subset,使用虚拟服务来配置请求路由到哪个子集。
1
2
3
4
|
// 配置虚拟服务
kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml
// 配置目标规则
kubectl apply -f samples/bookinfo/networking/destination-rule-all.yaml
|
使用http://nodeip:31779/productpage
再次访问集群,多次刷新页面,评论部分不会显示评级星标。
基于用户身份的路由
可以将特定用户的所有流量路由到特定服务版本,可用于线上发布后进行回归测试。下面的例子设置用户 Jason 的所有流量将被路由到服务 reviews:v2,因此在页面上用测用户登陆时,评论处会显示星级。
1
2
3
4
|
// 应用路由设置
kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml
// 查看虚拟服务路由设置
kubectl get virtualservice reviews -o yaml
|
访问外部服务
默认情况下,来自 Istio-enable Pod 的所有出站流量都会重定向到其 Sidecar 代理,集群外部 URL 的可访问性取决于代理的配置。默认情况下,Istio 将 Envoy 代理配置为允许传递未知服务的请求。
先使用遥测 API 来开启 enovy 访问日志:
1
2
3
4
5
6
7
8
9
|
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: mesh-default
namespace: istio-system
spec:
accessLogging:
- providers:
- name: envoy
|
因为前面已经开启了自动注入 sidecar,直接部署示例应用,并设置环境变量为 pod 的名称:
1
2
|
kubectl apply -f samples/sleep/sleep.yaml
export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
|
查看 global.outboundTrafficPolicy.mode 安装选项配置,它配置 sidecar 对外部服务的处理方式,其值有:
- ALLOW_ANY:默认值,允许调用未知的服务。
- REGISTRY_ONLY:阻止任何没有在网格中定义的 HTTP 服务或 service entry 的主机。
查看是否配置为 ALLOW_ANY:
1
2
|
# 输出为 ALLOW_ANY 或者为空,即为允许调用未知的服务
kubectl get istiooperator installed-state -n istio-system -o jsonpath='{.spec.meshConfig.outboundTrafficPolicy.mode}'
|
向外部发送请求进行测试:
1
2
3
|
root@alton:~/zt/istio# kubectl exec "$SOURCE_POD" -c sleep -- curl -sSI https://www.baidu.com | grep "HTTP/"; kubectl exec "$SOURCE_POD" -c sleep -- curl -sI https://kubernetes.io/ | grep "HTTP/"
HTTP/1.1 200 OK
HTTP/2 200
|
重新设置为 REGISTRY_ONLY 再进行测试,这里用istioctl install
进行安装的,重新设置需执行:
1
2
3
|
root@alton:~/zt/istio# istioctl install --set profile=demo -y --set meshConfig.outboundTrafficPolicy.mode=REGISTRY_ONLY
root@alton:~/zt/istio# kubectl get istiooperator installed-state -n istio-system -o jsonpath='{.spec.meshConfig.outboundTrafficPolicy.mode}'
REGISTRY_ONLY
|
再次进行测试,请求已经被阻止了:
1
2
3
|
root@alton:~/zt/istio# kubectl exec "$SOURCE_POD" -c sleep -- curl -sSI https://www.baidu.com | grep "HTTP/"; kubectl exec "$SOURCE_POD" -c sleep -- curl -sI https://kubernetes.io/ | grep "HTTP/"
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to www.baidu.com:443
command terminated with exit code 35
|
测试在服务网格中创建一个 ServiceEntry,以允许访问一个外部的 HTTP 服务:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: httpbin-ext
spec:
hosts:
- httpbin.org
ports:
- number: 80
name: http
protocol: HTTP
resolution: DNS
location: MESH_EXTERNAL
EOF
|
测试向外部 HTTP 发送请求:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
root@alton:~/zt/istio# kubectl exec -it $SOURCE_POD -c sleep -- curl http://httpbin.org/headers
{
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/7.87.0-DEV",
"X-Amzn-Trace-Id": "Root=1-63bb815d-1a017d290b48c2fa34471a3f",
"X-B3-Sampled": "1",
"X-B3-Spanid": "7aeb48cca0f822ad",
"X-B3-Traceid": "3ece8f6c652caa017aeb48cca0f822ad",
"X-Envoy-Decorator-Operation": "httpbin.org:80/*",
#...
}
}
|
查看 sidecar 里面的日志:
1
2
|
root@alton:~/zt/istio# kubectl logs $SOURCE_POD -c istio-proxy | tail
[2023-01-09T02:52:13.283Z] "GET /headers HTTP/1.1" 200 - via_upstream - "-" 0 1189 510 509 "-" "curl/7.87.0-DEV" "535009a8-12ed-9358-8b0a-c54713f83e09" "httpbin.org" "3.229.200.44:80" outbound|80||httpbin.org 10.42.0.30:47352 3.220.55.57:80 10.42.0.30:58464 - default
|