从Istio 1.8开始,Sidecar上的Istio代理具备缓存DNS代理的功能。当服务网格收到来自应用程序的DNS查询时,Istio代理将进行透明地拦截并提供解析能力。本文介绍如何启用服务网格中的DNS代理。

前提条件

背景信息

基于Kubernetes服务和定义的服务条目,为应用程序可以访问的所有服务推送主机名到IP地址的映射。来自应用程序的DNS查询被Istio代理透明地拦截并提供解析能力:
  • 如果查询的是服务网格中的服务,Istio代理将直接对应用程序返回查询响应。
  • 如果查询的是服务网格之外的服务,Istio代理将查询请求转发到/etc/resolv.conf中定义的上游名称服务器。

启用服务网格中的DNS代理

通过控制台启用服务网格中的DNS代理

  1. 登录ASM控制台
  2. 在左侧导航栏,选择服务网格 > 网格管理
  3. 网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理
  4. 在网格管理详情页面左上角单击功能设置
  5. 功能设置更新面板流量管理区域选中启用DNS代理功能,然后单击确定
    说明功能设置更新面板流量管理区域去掉选中启用DNS代理功能,可以关闭DNS代理功能。

通过命令行启用服务网格中的DNS代理

通过Aliyun CLI可以开启服务网格中的DNS代理。执行以下命令,开启DNS代理功能。

aliyun servicemesh UpdateMeshFeature --ServiceMeshId=xxxx --DNSProxyingEnabled=true
您也可以执行以下命令,关闭DNS代理功能。
aliyun servicemesh UpdateMeshFeature --ServiceMeshId=xxxx --DNSProxyingEnabled=false

验证DNS代理功能

  1. 在服务网格中创建服务条目
    使用ServiceEntry将https://aliyun.com添加到服务网格内部维护的服务注册表中。
    1. 登录ASM控制台
    2. 在左侧导航栏,选择服务网格 > 网格管理
    3. 网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理
    4. 在网格详情页面左侧导航栏选择流量管理 > 服务条目,然后在右侧页面单击新建
    5. 新建面板,选择命名空间,在文本框输入ServiceEntry的配置信息,单击确定
      apiVersion: networking.istio.io/v1beta1
      kind: ServiceEntry
      metadata:
       name: mydnsproxying-sample
      spec:
       hosts:
       - aliyun.com
       location: MESH_EXTERNAL
       ports:
       - number: 443
         name: https
         protocol: TLS
       resolution: DNS
  2. 在ACK集群中部署Sleep应用。
    1. 使用以下内容,创建名为sleep.yaml的文件。
      ##################################################################################################
      # Sleep service
      ##################################################################################################
      apiVersion: v1
      kind: Service
      metadata:
        name: sleep
        labels:
          app: sleep
      spec:
        ports:
        - port: 80
          name: http
        selector:
          app: sleep
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: sleep
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: sleep
        template:
          metadata:
            labels:
              app: sleep
          spec:
            containers:
            - name: sleep
              image: pstauffer/curl
              command: ["/bin/sleep", "3650d"]
              imagePullPolicy: IfNotPresent
      ---
    2. 执行以下命令,部署Sleep应用。
      kubectl apply -f sleep.yaml
  3. 执行以下命令,登录到Sleep容器中并执行curl命令访问https://aliyun.com。
    kubectl --kubeconfig=config.aliyun.worker.k8s -n mytest exec -it deploy/sleep -c sleep -- sh -c "curl -v https://aliyun.com""

    预期输出:

    * Rebuilt URL to: https://aliyun.com"
    *   Trying 240.240.**.**...
    * TCP_NODELAY set
    * Connected to aliyun.com (240.240.**.**) port 443 (#0)

    可以看到返回的地址是240.240.**.**,该地址是服务网格自动分配的虚拟IP,而不是真实的公开的IP地址。因为服务网格中使用iptables劫持了对kube-dns的请求,并将请求路由到了Pod中运行的Sidecar Proxy。当应用程序pod将aliyun.com解析为虚拟IP并发出请求时,虚拟IP将被替换为Sidecar Proxy中解析的实际公共IP地址。

    总之,由于创建了hosts地址为aliyun.com的ServiceEntry,因此应用程序Pod将在Istio DNS上查询aliyun.com并获得虚拟IP,并且当通过Sidecar Proxy发送请求时,该虚拟IP将被转换为解析后的实际公共IP地址。