集群内服务之间的通信
在Docker环境中,由于Docker Engine自DNS server,我们使用容器名来访问其他容器,因为容器是不稳定的,当容器宕掉,再重新启动相同镜像的容器,IP地址会改变,所以我们不使用IP访问其他容器;同样的,在Kubernetes集群中,由于我们使用kube-DNS,我们常用Service Name来访问某个服务。Service资源对象能保证其背后的容器副本始终是最新的IP。
集群内服务访问外部服务
利用External name访问:
集群内访问外部服务可以利用集群内服务Service Name不变这个特性,对Service名称和外部服务地址做一个映射,使之访问Service名称既是访问外部服务。例如下面的例子是将svc1和外部服务xxx.xxx.xxx.xxx做了对应关系。
apiVersion: v1
kind: Service
metadata:
name: svc1
namespace: default
spec:
externalName: somedomain.org
ports:
- port: 3306
protocol: TCP
targetPort: 3306
sessionAffinity: None
type: ExternalName
status:
loadBalancer: {}
优点: 利用Externalname访问集群外部服务的优点是不仅可以访问外部的ip:port的服务,也可以访问带有domain的service name.
利用Service的Endpoint来访问
Kubernetes中同一个Service name可以有多个不同的副本。一个服务背后是多个Endpoint。Endpoint解决Service Name映射到某个容器的问题,在Endpoint中不仅可以指定集群内容器的IP,还可以指定集群外IP(只需要集群内是可以访问到外面IP就行),我们可以利用这个特性使用集群外部的服务。
apiVersion: v1
kind: Service
metadata:
name: mysql-production
spec:
ports:
- port: 3306
---
kind: Endpoints
apiVersion: v1
metadata:
name: mysql-production
namespace: default
subsets:
- addresses:
- ip: 192.168.1.25
ports:
- port: 3306
缺点: 利用Endpoint方式适合外部服务是IP的情况,也可以指定端口,不适用于外部服务是domain name的情况。
Istio enabled 集群访问外部的方式
默认情况下,来自istio-enabled Pod的所有出站流量都会重定向到期Sidecar代理,集群外部URL的可访问性取决于代理的配置。默认情况下,Istio将Envoy代理配置为允许传递未知服务的请求。
有三种Istio Enabled集群访问外部服务的方法:
- 允许Envoy代理将请求传递到未在网格内配置过的服务。
- 配置service entries以提供对外部服务的受控访问。
- 对于特定范围的IP,完全绕过Envoy代理。
Envoy转发流量到外部服务
首先要开启Istio的安装选线:
global.outboundTrafficPolicy.mode:ALLOW_ANY
获取这个Istio配置的方法:
kubectl get configmap istio -n istio-system -o yaml | grep -o "mode: ALLOW_ANY"
如果你在安装的时候这个选项设置的是"REGISTRY_ONLY” name你需要通过下面命令来修改:
kubectl get configmap istio -n istio-system -o yaml | sed 's/mode: REGISTRY_ONLY/mode: ALLOW_ANY/g' | kubectl replace -n istio-system -f -
这样就可以直接从目标repo向外发送请求了。 例如你可以从你的目标repo中发送一个curl命令去 https://www.google.com
缺点:虽然可以达到k8s集群内访问外部服务的结果,但丢失了对外部服务流量Istio的监控和控制。比如,外部服务的调用没有记录到Mixer的日志中。
ServiceEntry控制对外部服务的访问(推荐)
使用Istio ServiceEntry配置,你可以Istio急群众访问任何公开的服务。这种方式可以在不丢失Istio的流量监控和控制的情况下,配置对外部HTTP服务和外部HTTPS服务的访问。
注意这种也需要配置:
global.outboundTrafficPolicy.mode: ALLOW_ANY
举个例子:
- 创建一个ServiceEntry,允许对外部服务的访问:
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: google
spec:
hosts:
- www.google.com
ports:
- number: 443
name: https
protocol: HTTPS
resolution: DNS
location: MESH_EXTERNAL
EOF
- 从SOURCE_POD往外部HTTPS服务发送请求:
kubectl exec -it $SOURCE_POD -c sleep -- curl -I https://www.google.com | grep "HTTP/"
3.检查SOURCE_POD的sidecar代理的日志:
kubectl logs $SOURCE_POD -c istio-proxy | tail
这样发送的请求都可以从Mixer查询到相应的访问记录。 最后也可以通过在ServiceEntry中设置对外部服务的访问路由和访问限制。
直接访问外部服务
要让特定范围的IP完全绕过Istio,可以配置Envoy sidecars以防止他们拦截外部请求。要设置绕过Istio,需要更改: global.proxy.includeIPRanges 或 global.proxy.excludeIPRanges 配置选项,并使用 kubectl apply 命令更新 istio-sidecar-injector 的配置。istio-sidecar-injector 配置的更新,影响的是新部署应用的 pod。(这种方法与第一种方法的差别在于完全禁止了指定IP的所有Istio功能。)
- 配置代理绕行 排除所有外部IP重定向到Sidecar代理的一种简单方法就是将:global.proxy.includeIPRanges 配置选项设置为内部集群服务使用的 IP 范围。这些 IP 范围值取决于集群所在的平台。
eg: 如果kubernetes集群IP 范围是 10.0.0.1/24,则使用下面的命令:
istioctl manifest apply <the flags you used to install Istio> --set values.global.proxy.includeIPRanges="10.0.0.1/24"
- 直接访问外部服务 直接从应用pod内cur外部服务(HTTP/HTTPS),你不会看到任何与Istio sidecar有关的请求头。并且发送到外部服务的请求既不会出现在Sidecar的日志中,也不会出现在Mixer日志中。绕过Istio sidecar意味着你不能再监视对外部服务的访问。