Istio与vm融合

最近在搞ISTIO与VM集成的方案,官网上有一些文档,按照流程部署下去发现问题不少。下面对在遇到验证中遇到的一些问题和调试经验都整理了一下,供大家参考。

部署

接下来的实验的拓扑图如下所示:

基础网络准备

为了使VM与已经部署了ISTIO的K8S集群连通,我们需要先把VM加入到k8s集群,这样会自动部署flannel网络,保障POD网络可通。这块如果使用kubeadm来部署的k8s的话,比较简单,直接kubeadm join就可以加入一个新的集群了。

为了让VM的应用可以直接使用服务名称来通信,需要修改vm的域名解析服务的配置文件 (从k8s的任意一个pod上拷贝/etc/resolv.conf)

1
2
3
4
5
6
7
8
9
10
11
12
cat /etc/resolv.conf
# Your system has been configured with 'manage-resolv-conf' set to true.
# As a result, cloud-init has written this file with configuration data
# that it has been provided. Cloud-init, by default, will write this file
# a single time (PER_ONCE).
#
#nameserver 183.60.83.19
#nameserver 183.60.82.98

nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

预安装

1
2
3
kubectl create namespace istio-system

helm template install/kubernetes/helm/istio-init --name istio-init --namespace istio-system | kubectl apply -f -

安装istio

主要是需要指定 meshExpansion 扩展:

1
2
3
4
helm install --set global.meshExpansion.enabled=true install/kubernetes/helm/istio --name istio --namespace istio-system --values install/kubernetes/helm/istio/values-istio-demo.yaml

# 或者安装istio(带meshExpansion-认证)
helm install --set global.meshExpansion.enabled=true install/kubernetes/helm/istio --name istio --namespace istio-system --values install/kubernetes/helm/istio/values-istio-demo-auth.yaml

cluster.env

1
2
3
4
5
6
7
8
cat << EOF > cluster.env
ISTIO_CP_AUTH=MUTUAL_TLS # 需要使用这个值,很重要
ISTIO_SERVICE_CIDR=10.244.0.0/16 # Pod子网CIDR
ISTIO_INBOUND_PORTS=3306,9080 # VM上对外提供服务的端口号
POD_NAME=details # 似乎作用不大,可以随意
EOF

sudo cp cluster.env /var/lib/istio/envoy

准备证书

1
2
3
4
5
6
7
8
9
kubectl -n istio-system get secret istio.default -o jsonpath='{.data.root-cert\.pem}' |base64 --decode > root-cert.pem

kubectl -n istio-system get secret istio.default -o jsonpath='{.data.key\.pem}' |base64 --decode > key.pem

kubectl -n istio-system get secret istio.default -o jsonpath='{.data.cert-chain\.pem}' |base64 --decode > cert-chain.pem

sudo mkdir -p /etc/certs

sudo cp {root-cert.pem,cert-chain.pem,key.pem} /etc/certs

安装sidecar

Debian包

针对Ubuntu,可以直接从官方下载安装包:

1
2
3
curl -L https://storage.googleapis.com/istio-release/releases/1.1.6/deb/istio-sidecar.deb > istio-sidecar.deb

sudo dpkg -i istio-sidecar.deb

RPM包

针对CentOS系统,需要自己编译安装包:

  • 编译

    在本地的GOPATH目录下克隆istio,然后在istio的根目录执行

    1
    2
    3
    cd /go/src/github.com/istio/istio
    make rpm/builder-image
    make rpm/proxy
  • 安装

    然后在/go/src/out/目录下可以找到对应的rpm包。
    在安装rpm包的时候,会发现没有GLIBC_2.18,解决方法如下:

    下载:wget http://mirrors.ustc.edu.cn/gnu/libc/glibc-2.18.tar.gz
    解压:tar -zxvf glibc-2.18.tar.gz

    进入解压文件夹,创建文件夹build, 运行configure配置:

    1
    2
    3
    4
    5
    6
    mkdir build
    cd build

    ../configure --prefix=/usr
    make -j4
    sudo make install

准备用户

1
2
sudo useradd istio-proxy
sudo chown -R istio-proxy /etc/certs /var/lib/istio/envoy

启动服务

1
2
sudo systemctl start istio-auth-node-agent
sudo systemctl start istio

sidecar.env

内容如下

1
2
3
4
5
## cat sidecar.env  | grep -v '#' 
ISTIO_SERVICE=details
ISTIO_SVC_IP=10.244.3.0
ENVOY_USER=istio-proxy
ISTIO_AGENT_FLAGS="--zipkinAddress zipkin.istio-system:9411 --proxyLogLevel debug"

重启ISTIO服务

1
systemctl restart istio

部署业务

首先使用bookinfo中的示例来部署整个调用链中的服务和workload。

1
kubectl apply -f istio-1.1.6/samples/bookinfo/platform/kube/bookinfo.yaml

等k8s中所有服务都起来之后,删除details这个deployment以及其对应的services。然后在github上找到details的ruby代码文件,拷贝到VM上保存为ruby_server.rb

在VM上需要直接使用ubuntu用户来运行该服务:

1
ruby ./ruby_server.rb 9080

在k8s集群里面,重新创建details服务:

1
2
istioctl -n default register details 10.244.3.0 http:9080
# 这里的 10.244.3.0 是VM的IP地址,http为通信协议,9080为details服务对外暴露的端口号

部署istio转发规则

1
2
kubectl apply -f istio-1.1.6/samples/bookinfo/networking/destination-rule-all.yaml
kubectl apply -f istio-1.1.6/samples/bookinfo/networking/virtual-service-all-v1.yaml

效果展示

调用链


Granfana

待解决问题

VM网络转发

到当前,bookinfo的流量转发应该能够正常,但是还存在一个问题:

如果直接在vm上通过service名称来访问k8s中的其他服务,将无法经过sidecar。其主要原因是iptables,通过查看配置可以看到:

1
2
3
4
5
# iptables -t nat -nvL OUTPUT
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
744K 82M KUBE-SERVICES all -- * * 0.0.0.0/0 0.0.0.0/0 /* kubernetes service portals */
2285 137K ISTIO_OUTPUT tcp -- * * 0.0.0.0/0 0.0.0.0/0

由于我们在VM上部署了k8s,kube-proxy的KUBE-SERVICES链要优先于ISTIO_OUTPUT导致上面的问题。

Prometheus监控vm-envoy

由于prometheus对所有sidecar的envoy监控是通过k8s来做服务发现的,而VM的envoy并没有在k8s中体现出来。这块需要我们手动配置prometheus的target。

具体通过修改istio-system命令空间下prometheus configmap的配置, 添加vm-envoy-stats任务。

1
2
3
4
5
6
7
8
9
10
11
12
13
global:
scrape_interval: 15s
scrape_timeout: 10s
evaluation_interval: 1m
scrape_configs:
- job_name: vm-envoy-stats
scrape_interval: 15s
scrape_timeout: 10s
metrics_path: /stats/prometheus
scheme: http
static_configs:
- targets:
- 10.244.3.0:15090

kiali视图

当前还没有办法在kiali上展现出vm上流量的视图,虽然可以展示出details的service信息,但是一直报该service缺少了sidecar。我认为这应该和kialai对pod的映射有关,后续考虑看一下它的实现逻辑,应该有解决的方法。

调试经验

查看envoy的配置信息

对于pod的sidecar,直接通过nsenter进入到pid的net namespace下(对于VM直接在VM上)执行以下命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# curl localhost:15000/help
admin commands are:
/: Admin home page
/certs: print certs on machine
/clusters: upstream cluster status
/config_dump: dump current Envoy configs (experimental)
/contention: dump current Envoy mutex contention stats (if enabled)
/cpuprofiler: enable/disable the CPU profiler
/healthcheck/fail: cause the server to fail health checks
/healthcheck/ok: cause the server to pass health checks
/heapprofiler: enable/disable the heap profiler
/help: print out list of admin commands
/hot_restart_version: print the hot restart compatibility version
/listeners: print listener addresses
/logging: query/change logging levels
/memory: print current allocation/heap usage
/quitquitquit: exit the server
/reset_counters: reset all counters to zero
/runtime: print runtime values
/runtime_modify: modify runtime values
/server_info: print server version/status information
/stats: print server stats
/stats/prometheus: print server stats in prometheus format

当然, 对于pod如果是指查看xds的配置,可以直接执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# istioctl ps
NAME CDS LDS EDS RDS PILOT VERSION
details.default SYNCED SYNCED SYNCED (50%) SYNCED istio-pilot-59954cff67-wxgnr 1.1.3
istio-egressgateway-7dbbb87698-ds9j2.istio-system SYNCED SYNCED SYNCED (100%) NOT SENT istio-pilot-59954cff67-wxgnr 1.1.3
istio-ingressgateway-565b894b5f-rn2l2.istio-system SYNCED SYNCED SYNCED (100%) NOT SENT istio-pilot-59954cff67-wxgnr 1.1.3
productpage-v1-79458795bc-jdvg6.default SYNCED SYNCED SYNCED (50%) SYNCED istio-pilot-59954cff67-wxgnr 1.1.3
ratings-v1-5b7cd6c58f-559nb.default SYNCED SYNCED SYNCED (50%) SYNCED istio-pilot-59954cff67-wxgnr 1.1.3
ratings-v2-mysql-vm-74978d9b97-mlv8r.default SYNCED SYNCED SYNCED (50%) SYNCED istio-pilot-59954cff67-wxgnr 1.1.3
reviews-v1-54c7c79486-wrw6f.default SYNCED SYNCED SYNCED (50%) SYNCED istio-pilot-59954cff67-wxgnr 1.1.3
reviews-v2-7dc5785684-zccst.default SYNCED SYNCED SYNCED (50%) SYNCED istio-pilot-59954cff67-wxgnr 1.1.3
reviews-v3-6c464d7bf4-5px2m.default SYNCED SYNCED SYNCED (50%) SYNCED istio-pilot-59954cff67-wxgnr 1.1.3

# istioctl pc listeners productpage-v1-79458795bc-jdvg6.default
ADDRESS PORT TYPE
10.244.1.130 9080 HTTP
10.103.241.209 31400 TCP
10.103.241.209 8060 TCP
10.107.214.136 16686 TCP
....
# 通过指定-o json可以查看到更详细的配置信息

查看envoy是否GRPC上报telemetry到mixer

需要先打开envoy的日志模块,具体如下:

1
2
3
4
curl -X POST localhost:15000/logging?level=info
curl -X POST localhost:15000/logging?grpc=trace

tailf /var/log/istio/istio.err.log

可以看到如下信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  strings {
key: 3
value: -8
}
strings {
key: 17
value: -11
}
...
}
default_words: "kubernetes://details.default"
default_words: "details.default.svc.cluster.local"
default_words: "istio-envoy"
default_words: "Wed, 29 May 2019 07:33:10 GMT"
default_words: "178"
default_words: "origin.ip"
default_words: "default"
default_words: "kubernetes://productpage-v1-79458795bc-jdvg6.default"
default_words: "istio://default/services/details"
...
global_word_count: 221

这里就是envoy的mixer filter上报到mixer的attribute信息。每一个key都对应着mixer中内置的attribute关键字的index,每一个value对应default_workds索引。具体参考这篇文章。

之前遇到一个问题,发现envoy有通过grpc Report到mixer;同时在mixer的accessLog也能够看到logentry生成到stdio的访问日志。但是prometheus始终无法从istio-telemetry采集到istio_requests_total的指标。后来调查发现是手动通过istioctl register注册服务的时候,没有指定其协议类型导致的。

查看envoy的业务流量访问日志

istio默认是不看业务流量访问日志的,因为日志量太大。如果需要调试,需要手动修改istio-system中的configmap的配置。

1
2
3
4
5
6
7
8
9
kubectl -n istio-system edit cm istio

#
apiVersion: v1
data:
mesh: "# Set the following variable to true to disable policy checks by the Mixer.\n#
Note that metrics will still be reported to the Mixer.\ndisablePolicyChecks: true\n\n#
Set enableTracing to false to disable request tracing.\nenableTracing: true\n\n#
Set accessLogFile to empty string to disable access log.\naccessLogFile: \"/dev/stdout\"\n\n#

修改最后一行为/dev/stdout,这样通过查看业务pod的istio-proxy container的日志就可以看到流量的access-log了。
当然,对于VM可以直接修改这个值为一个目录,然后在VM上重启istio服务就可以在日志文件中看到流量信息。

1
2
3
4
5
6
# kc logs --tail=5 -f productpage-v1-79458795bc-jdvg6 -c istio-proxy

[2019-05-29T07:57:21.444Z] "GET /productpage?u=normal HTTP/1.1" 200 - "-" 0 4083 5034 5034 "-" "curl/7.47.0" "9d5d739a-9fbd-9659-ab58-2619a6792936" "productpage.default.svc.cluster.local:9080" "127.0.0.1:9080" inbound|9080|http|productpage.default.svc.cluster.local - 10.244.1.130:9080 10.244.3.0:51704 -
[2019-05-29T07:57:29.495Z] "GET /details/0 HTTP/1.1" 200 - "-" 0 178 2 2 "-" "curl/7.47.0" "366fc77a-d9d5-9971-9a3b-60576e1ca230" "details:9080" "10.244.3.0:9080" outbound|9080||details.default.svc.cluster.local - 10.102.237.154:9080 10.244.1.130:35582 -
[2019-05-29T07:57:29.500Z] "GET /reviews/0 HTTP/1.1" 500 - "-" 0 3926 2510 2509 "-" "curl/7.47.0" "366fc77a-d9d5-9971-9a3b-60576e1ca230" "reviews:9080" "10.244.1.155:9080" outbound|9080|v3|reviews.default.svc.cluster.local - 10.109.123.127:9080 10.244.1.130:35202 -
[2019-05-29T07:57:32.012Z] "GET /reviews/0 HTTP/1.1" 500 - "-" 0 3926 2510 2509 "-" "curl/7.47.0" "366fc77a-d9d5-9971-9a3b-60576e1ca230" "reviews:9080" "10.244.1.155:9080" outbound|9080|v3|reviews.default.svc.cluster.local - 10.109.123.127:9080 10.244.1.130:35258 -

查看流表转发流程


istio中流量的转发流程可以参考jimmy的这张图, 下面要说的是具体chain中的规则。

  • inbound流量
1
2
3
4
5
# iptables -t nat -nvL PREROUTING
Chain PREROUTING (policy ACCEPT 15 packets, 900 bytes)
pkts bytes target prot opt in out source destination
1969K 174M KUBE-SERVICES all -- * * 0.0.0.0/0 0.0.0.0/0 /* kubernetes service portals */
162K 9707K ISTIO_INBOUND tcp -- * * 0.0.0.0/0 0.0.0.0/0

首先查看PREROUTING chain,可以看到,流量被送到ISTIO_INBOUND。

1
2
3
4
5
# iptables -t nat -nvL ISTIO_INBOUND
Chain ISTIO_INBOUND (1 references)
pkts bytes target prot opt in out source destination
2536 152K ISTIO_IN_REDIRECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:3306
343 20580 ISTIO_IN_REDIRECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:9080

在ISTIO_INBOUND中,VM提供对外服务的端口3306和9080的流量被转发到 ISTIO_IN_REDIRECT。这里如果VM上面有新添加服务端口,需要修改了cluster.env之后重启istio服务。

1
2
3
4
# iptables -t nat -nvL ISTIO_IN_REDIRECT
Chain ISTIO_IN_REDIRECT (2 references)
pkts bytes target prot opt in out source destination
2962 178K REDIRECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 redir ports 15001

在 ISTIO_IN_REDIRECT中,流量被送到了envoy处理。

  • outbound流量

同理,这里只给出对应的链表规则:

1
2
3
4
5
# iptables -t nat -nvL OUTPUT
Chain OUTPUT (policy ACCEPT 24 packets, 2927 bytes)
pkts bytes target prot opt in out source destination
782K 86M KUBE-SERVICES all -- * * 0.0.0.0/0 0.0.0.0/0 /* kubernetes service portals */
5033 302K ISTIO_OUTPUT tcp -- * * 0.0.0.0/0 0.0.0.0/0
1
2
3
4
5
6
7
8
9
10
11
 # iptables -t nat -nvL ISTIO_OUTPUT
Chain ISTIO_OUTPUT (1 references)
pkts bytes target prot opt in out source destination
0 0 ISTIO_REDIRECT all -- * lo 0.0.0.0/0 !127.0.0.1
790 47400 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0 owner UID match 1000
4387 263K RETURN all -- * * 0.0.0.0/0 0.0.0.0/0 owner UID match 0
0 0 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0 owner GID match 1000
0 0 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0 owner GID match 0
0 0 RETURN all -- * * 0.0.0.0/0 127.0.0.1
0 0 ISTIO_REDIRECT all -- * * 0.0.0.0/0 10.244.0.0/16
2 120 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0

这里的uid 1000其实就是envoy进程的uid,而0是root。之所以这样设置,是因为如果将root的流量都干掉了,将导致ssh无法连接主机。继续查看ISTIO_REDIRECT链的规则:

1
2
3
4
# iptables -t nat -nvL ISTIO_REDIRECT
Chain ISTIO_REDIRECT (2 references)
pkts bytes target prot opt in out source destination
0 0 REDIRECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 redir ports 15001

这样就基本明白了inbound和outbound流量被送进envoy之前的转发过程了。

0%