Istio在程序中注入Sidecar的方式有两种:分别是手动注入和自动注入。
手动注入是通过Istio命令将Sidecar Proxy程序注入到已经存在的资源编排YAML文件里,手动注入通常适用于程序已经在K8S集群中部署的环境,可以通过istioctl kube-inject
命令将Proxy的YAML参数与程序的YAML进行结合,然后执行kubectl apply
命令将已经部署的Pod资源手动注入Sidecar Proxy。
自动注入与命名空间namespace有关,通过指定的命名空间打上Sidecar自动注入的标签,当在该命名空间下再次创建Pod资源时会自动注入Proxy代理程序。
程序注入Sidecar的原理:创建Pod的请求交给apiserver—>Istio通过k8s的准入控制将proxy容器再Pod中添加—>将信息同步到etcd数据库。
即使应用程序注入了Sidecar,以网格环境运行,也是可以通过service的服务发现地址直接连接到应用程序,越过代理程序。
程序接入Istio服务网格后的访问流程如下图所示:用户通过nodeport端口映射访问到Istio的ingressgateway服务,由ingressgateway将请求转发到应用程序对应的gateway资源,然后通过配置的virtualservice资源,将请求转发到应用程序的service资源,最后由程序容器提供应用服务,程序之间的流量请求都是通过Istio-proxy完成。
Istio的samples/目录中提供了一些测试用例,便于我们研究Istio服务,注入Sidecar就以samples目录中的httpbin程序为例实现。
通过istioctl kube-inject
命令指定已存在的资源编排YAML文件,会将Sidecar代理程序注入到YAML文件中,但是不会直接覆盖原有YAML文件,而是直接输出到终端,我们可以通过重定向的方式将注入Sidecar后的YAML重新写入到新的文件,也可以直接交给kubectl命令执行。
1)首先在K8S集群中部署httpbin服务
主要是为了查看注入前和注入后的区别。
1.创建httpbin资源
[root@k8s-master httpbin]# kubectl create -f httpbin-nodeport.yaml
service/httpbin created
deployment.apps/httpbin created
2.查看资源的状态
[root@k8s-master httpbin]# kubectl get Pod,svc
NAME READY STATUS RESTARTS AGE
Pod/httpbin-84cddc85d4-pf6hs 1/1 Running 0 20m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/httpbin NodePort 10.102.187.192 8000:30187/TCP 20m
service/kubernetes ClusterIP 10.96.0.1 443/TCP 4d3h
#可以看到httpbind的Pod资源中只有一个容器,传统的在K8S中部署的方式。
2)手动为httpbin服务注入Sidecar代理程序
1.查看注入Sidecar的配置参数
[root@k8s-master httpbin]# istioctl kube-inject -f httpbin-nodeport.yaml
2.为应用程序注入Sidecar代理
[root@k8s-master httpbin]# kubectl apply -f <(istioctl kube-inject -f httpbin-nodeport.yaml)
service/httpbin configured
deployment.apps/httpbin configured
3.观察注入Sidecar后Pod资源的变量
[root@k8s-master httpbin]# kubectl get Pod
NAME READY STATUS RESTARTS AGE
httpbin-d6f4f66c6-sgglh 2/2 Running 0 20m
#可以看到Pod中运行的容器数量明显变成了2个,一个是程序容器一个是proxy代理程序。
4.进入proxy的容器
[root@k8s-master httpbin]# kubectl exec -it httpbin-d6f4f66c6-sgglh -c istio-proxy bash
Istio-proxy@httpbin-d6f4f66c6-sgglh:/$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
Istio-p+ 1 0.1 0.9 763560 38292 ? Ssl 07:51 0:02 /usr/local/bin/pilot-agent proxy Sidecar --domain default.svc.cluster.local --serviceCluster httpbin.default --proxyLogLevel=warning --proxyComponen
Istio-p+ 12 0.4 1.0 187524 42440 ? Sl 07:51 0:05 /usr/local/bin/envoy -c etc/Istio/proxy/envoy-rev0.json --restart-epoch 0 --drain-time-s 45 --parent-shutdown-time-s 60 --service-cluster httpbin.de
#可以看到proxy容器中运行了两个程序,pilot-agent进程主要负责热更新envoy的配置内容,envoy就是Sidecar代理程序,负责流量的管理,当在控制中心更新了proxy的配置,pilot-agent就会加载最新的配置内容然后通知envoy更新配置。
为应用程序自动注入Sidecar是通过namespace中的标签实现的,打完注入标签后,新创建的Pod资源会自动注入Sidecar,打标签之前的Pod资源是不会注入Sidecar。
1)将namespace设置自动注入
1.创建namespace
[root@k8s-master ~]# kubectl create ns sidecar-test
namespace/Sidecar-test created
2.为namespace添加Sidecar自动注入的标签
[root@k8s-master ~]# kubectl label namespace sidecar-test istio-injection=enabled
namespace/sidecar-test labeled
#enabled为开启自动注入 #disabled为关闭自动注入
3.查看namespace的标签
[root@k8s-master httpbin]# kubectl get ns --show-labels
NAME STATUS AGE LABELS
default Active 4d5h
Istio-system Active 3d5h istio-injection=disabled
kube-node-lease Active 4d5h
kube-public Active 4d5h
kube-system Active 4d5h
sidecar-test Active 5m18s istio-injection=enabled #开启自动注入
2)创建Pod资源验证是否自动注入Sidecar
1.创建pod资源
[root@k8s-master httpbin]# kubectl create deploy nginx-1 --image=nginx:1.15 --replicas=1 -n sidecar-test
deployment.apps/nginx-1 created
2.查看pod资源
[root@k8s-master httpbin]# kubectl get pod -n sidecar-test
NAME READY STATUS RESTARTS AGE
nginx-1-d4c8f4989-bzw2n 2/2 Running 0 64s
3.查看pod资源中的容器列表
[root@k8s-master httpbin]# kubectl get pod nginx-1-d4c8f4989-bzw2n -n sidecar-test -o jsonpath={.spec.containers[*].name}
nginx Istio-proxy
#运行的应用程序自动会注入sidecar的容器
应用程序注入Sidecar之后,所有的流量通信都会经过Sidecar代理程序,程序已经在网格中部署了,想要在集群外部访问到网格中的应用程序,就需要通过Istio的ingressgateway资源了。
首先需要为应用程序创建一个Gateway资源,然后创建一个VirtualService资源,关联Gateway以及应用程序的Service资源,即可完成从外界访问服务网格中的程序。
大致流程:
1)请求—>Istio ingressgateway—>创建的Gateway以及VirtualService资源会将转发规则配置在IngressGateway中。
2)首先转发到Virtual Service资源—>根据VirtualService资源绑定的Gateway资源设置的端口—>最后将请求转发到对应的Service资源上。
1)httpbin程序Gateway以及VirtualService资源编排文件内容
[root@k8s-master httpbin]# vim httpbin-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway #资源类型为Gateway
metadata:
name: httpbin-gateway #资源的名称
spec:
selector: #定义选择器
istio: ingressgateway #关联istio的ingressgateway
servers: #定义服务列表
- port: #定义服务使用的端口号
number: 80 #端口号为80
name: http #端口的名称
protocol: HTTP #端口的协议
hosts: #允许进入的主机
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts: #定义流量要发送的主机
- "*"
gateways: #关联gateway资源
- httpbin-gateway
http: #定义http流量路由有序列表规则
- route: #默认规则,可以重定向或者转发流量
- destination: #定义流量转发的目标
host: httpbin #将流量转发到应用程序的service资源,在这里指定程序的service资源
port: #指定service资源的端口号
number: 8001
2)创建httpbin程序的gateway以及virtualservice资源
1.创建资源
[root@k8s-master httpbin]# kubectl apply -f httpbin-gateway.yaml
gateway.networking.istio.io/httpbin-gateway created
virtualservice.networking.istio.io/httpbin created
2.查看资源的状态
[root@k8s-master httpbin]# kubectl get gateway,virtualservice
NAME AGE
gateway.networking.istio.io/httpbin-gateway 16s
NAME GATEWAYS HOSTS AGE
virtualservice.networking.istio.io/httpbin ["httpbin-gateway"] ["*"] 16s
3)通过Istio的ingressgateway访问应用程序
我们创建的gateway资源使用的是80端口,因此需要访问Istio的ingressgateway资源映射出80端口的nodeport端口。
[root@k8s-master httpbin]# kubectl get svc -n Istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
Istio-ingressgateway LoadBalancer 10.107.107.206 15021:32381/TCP,80:31105/TCP,443:30793/TCP,15012:32259/TCP,15443:31377/TCP 3d5h
Istiod ClusterIP 10.109.130.252 15010/TCP,15012/TCP,443/TCP,15014/TCP 3d5h
#80映射的端口80:31105/TCP
浏览器输入http://192.168.20.10:31105/
地址访问网格中的httpbin程序,使用IP访问只能请求一个服务,后面会使用域名访问。
Istio服务网格中也有很多类似于K8S的控制器资源,Istio在K8S集群中部署完成后,会通过服务发现的方式将Istio的控制器资源类型注入到K8S的Apiserver中,因此我们就可以通过kubectl命令将Istio的资源在K8S集群中创建。
使用istioctl或者kubectl创建的pod资源会通过apiserver部署在K8S集群中,并将信息存储在Etcd。
当pod资源注入了Sidecar proxy代理程序之后,那么Pod中的应用程序就是以网格的模式部署了,程序之间的调用都是通过proxy代理程序完成,通过为应用程序创建Istio的virtualservice资源将资源转发规则写入到Istio的ingressgateway组件之后,我们就可以通过ingressgateway映射的端口访问到网格中的应用程序。