<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>route | 伪架构师</title>
    <link>/tags/route/</link>
      <atom:link href="/tags/route/index.xml" rel="self" type="application/rss+xml" />
    <description>route</description>
    <generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>zh</language><lastBuildDate>Mon, 16 Apr 2018 11:48:10 +0800</lastBuildDate>
    <image>
      <url>/img/logo-wide.png</url>
      <title>route</title>
      <link>/tags/route/</link>
    </image>
    
    <item>
      <title>摸索：Istio 路由规则 Alpha v3</title>
      <link>/post/istio-route-alpha1v3/</link>
      <pubDate>Mon, 16 Apr 2018 11:48:10 +0800</pubDate>
      <guid>/post/istio-route-alpha1v3/</guid>
      <description>

&lt;p&gt;Istio 近期的版本中出现了一个新的 API 组：&lt;code&gt;networking.istio.io/v1alpha3&lt;/code&gt;，应该会替代现有的&lt;code&gt;config.istio.io/v1alpha2&lt;/code&gt; API。新的 API 不管是结构上还是功能上、以及命名上，都有很大差异。这里使用一些简单例子，体验一下 Alpha 3 带来的变化。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;注意：正常情况下 istioctl 和 kubectl 都可以用来操作这些对象，但是 kubectl 缺乏验证功能，因此调试阶段使用 istioctl 会更方便一些。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;路由分配&#34;&gt;路由分配&lt;/h2&gt;

&lt;p&gt;过去的路由分配比较简单，使用标签即可。新的版本中，提出了 &lt;a href=&#34;https://istio.io/docs/reference/config/istio.networking.v1alpha3.html#VirtualService&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;VirtualService&lt;/code&gt;&lt;/a&gt; 的概念。VirtualService 由一组路由规则构成，用于对服务实体（原文为 Host，个人认为在 K8S 中对应为 Pod）进行寻址。一旦有流量符合其中规则的选择条件，就会发送流量给对应的服务（或者服务的一个版本/子集）。&lt;/p&gt;

&lt;p&gt;流量的特征除了请求数据之外，还包括流量的来源，这样就能根据一些上下文来进行灵活的定义了。&lt;/p&gt;

&lt;p&gt;这里我们定义来自 sleep 对 php-server 的请求，都转向 v1：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;
apiVersion: networking.istio.io/v1alpha3

kind: VirtualService

metadata:

  name: sleep-server-route

spec:

  hosts:

  - &amp;quot;php-server&amp;quot;

  http:

  - match:

    - sourceLabels:

        app: sleep

    route:

    - destination:

        name: php-server

        subset: v3

  - route:

    - destination:

        name: php-server

        subset: v2

&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;这里的匹配策略是具有从上到下的优先级的，也就是说，最下一条就是缺省路由。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;可以看到，&lt;code&gt;match&lt;/code&gt;中不再包含 &lt;code&gt;source&lt;/code&gt;，这里使用标签来过滤。写完应用之后，我们在 Sleep Pod 中使用 curl 发起请求，会发现并没有生效。这是因为，&lt;strong&gt;在 v3 中，目标规则不再是小透明了。&lt;/strong&gt;，路由定义必须以目标策略为基础。&lt;/p&gt;

&lt;p&gt;因此这里需要定义一个 &lt;code&gt;DestinationRule&lt;/code&gt; 对象，来满足上面的目标需求：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;
apiVersion: networking.istio.io/v1alpha3

kind: DestinationRule

metadata:

  name: phpserver

spec:

  name: php-server

  subsets:

  - name: v1

    labels:

      version: v1

  - name: v2

    labels:

      version: v2

  - name: v3

    labels:

      version: v3

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;上面的文件，创建了名为 &lt;code&gt;phpserver&lt;/code&gt; 的目标规则，并在下级使用标签创建了三个子集。再次测试，会发现按照我们的要求执行了。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;注意：VirtualService 中引用的 Destination.name 似乎对应的是目标规则中的 spec.name，而不是 metadata.name。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;断路器&#34;&gt;断路器&lt;/h2&gt;

&lt;p&gt;这部分的 API 变化较大。可以在上面的 DestinationRule 中加入熔断策略：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;
  - name: v2

    labels:

      version: v2

  trafficPolicy:

    connectionPool:

      http:

        http1MaxPendingRequests: 1

        maxRequestsPerConnection: 1

      tcp:

        maxConnections: 100

    outlierDetection:

      http:

        baseEjectionTime: 180.000s

        consecutiveErrors: 1

        interval: 1.000s

        maxEjectionPercent: 100

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;接下来就可以使用 Fortio 或其他工具来测试熔断效果了，具体操作可以参考官方文档的&lt;a href=&#34;https://istio.io/docs/tasks/traffic-management-v1alpha3/circuit-breaking.html&#34; target=&#34;_blank&#34;&gt;断路器一节&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;

&lt;p&gt;新版本 API 加入了相当多的非 K8S 特性，另外突出了 Gateway，VirtualService 等主要对象，使得各个定义的条理性大为增强。但是目前这一组 API 仍然是 Alpha 阶段，因此还是存在相当大的变数的，但是个人推测的是，新 API 会得到更大的支持力度，因此可靠性应该更强。总之 Alpha 有风险，使用需谨慎。&lt;/p&gt;

&lt;h2 id=&#34;参考链接&#34;&gt;参考链接&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;VirtualService&lt;/code&gt;: &lt;code&gt;https://istio.io/docs/reference/config/istio.networking.v1alpha3.html#VirtualService&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;断路器&lt;/code&gt;：&lt;code&gt;https://istio.io/docs/tasks/traffic-management-v1alpha3/circuit-breaking.html&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
    <item>
      <title>istio 三日谈之二 路由规则</title>
      <link>/post/istio-route-rules/</link>
      <pubDate>Fri, 28 Jul 2017 17:35:28 +0800</pubDate>
      <guid>/post/istio-route-rules/</guid>
      <description>

&lt;p&gt;路由控制是 istio 的最常用功能了，经过前面的准备，我们已经基本可以进行这些内容的尝试了。&lt;/p&gt;

&lt;p&gt;注意下面的路由规则都忽略了对来源的过滤，会显得比较呆板或者说没用，但是在加入过滤条件之后，就完全不可同日而语了。具体的过滤规则的写法可以参考官方文档或者 istio 中的 bookinfo 实例。&lt;/p&gt;

&lt;h2 id=&#34;创建-frontend-v2&#34;&gt;创建 frontend-v2&lt;/h2&gt;

&lt;p&gt;为了展示路由分配的能力，我们首先创建一个名为&lt;code&gt;frontend-v2&lt;/code&gt;的&lt;code&gt;Deployment&lt;/code&gt;，这个&lt;code&gt;deploy&lt;/code&gt;跟之前的 v1 共享同一个 PVC，也就是共享同一套页面。利用环境变量来控制输出。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: frontend-v2
spec:
  replicas: 1
  template:
    metadata:
      labels:
        name: frontend
        version: &amp;quot;2&amp;quot;
    spec:
      containers:
      - name: php
        image: 10.211.55.86:5000/php:7.1.7-apache
        ports:
        - containerPort: 80
          protocol: TCP
        volumeMounts:
        - name: wwwroot
          mountPath: /var/www/html
        env:
        - name: &amp;quot;SERVICE_VERSION&amp;quot;
          value: &amp;quot;2&amp;quot;
      volumes:
      - name: wwwroot
        persistentVolumeClaim:
          claimName: frontend-v1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;同前面的 v1 一样，这个&lt;code&gt;Deployment&lt;/code&gt;也需要使用&lt;code&gt;istioctl kube-inject&lt;/code&gt;进行注入，最后使用&lt;code&gt;kubectl apply -f&lt;/code&gt; 运行。&lt;/p&gt;

&lt;h2 id=&#34;流量分配&#34;&gt;流量分配&lt;/h2&gt;

&lt;h3 id=&#34;首先创建如下路由规则&#34;&gt;首先创建如下路由规则&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;default.yaml&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;type: route-rule
name: frontend-default
spec:
  destination: svc-frontend.default.svc.cluster.local
  precedence: 1
  route:
  - tags:
      version: &amp;quot;2&amp;quot;
    weight: 100
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;destination：必须是服务的 fqdn&lt;/li&gt;
&lt;li&gt;precedence：整数，优先级，越大越先&lt;/li&gt;
&lt;li&gt;route：数组

&lt;ul&gt;
&lt;li&gt;tag：&lt;strong&gt;Pod&lt;/strong&gt; 的标签选择器。&lt;/li&gt;
&lt;li&gt;weigh: 整数，权重，分配到当前路由的比率。&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;创建之后，使用&lt;code&gt;istioctl create -f default.yaml&lt;/code&gt;，创建这一规则。接下来我们使用&lt;code&gt;kubectl exec -it&lt;/code&gt;进入 tool pod 进行测试：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ curl svc-frontend/index.php

-----------------------------
From: frontend-797054967-r12m5
Version: 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;返回内容表明这一服务调用的是最初的 v1 版本的 frontend。&lt;/p&gt;

&lt;p&gt;接下来修改 default.yaml 的&lt;code&gt;version &amp;quot;1&amp;quot;&lt;/code&gt;为&lt;code&gt;version &amp;quot;2&amp;quot;&lt;/code&gt;，然后用&lt;code&gt;istioctl replace -f default.yaml&lt;/code&gt;更新路由规则。再次验证：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ curl svc-frontend/index.php

-----------------------------
From: frontend-v2-90739004-xpmrn
Version: 2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这里可以看到，这一响应来自于 v2 版本的 Pod，并且返回的版本号也是 2。&lt;/p&gt;

&lt;p&gt;然后我们再次修改路由规则，测试一下路由分配：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;type: route-rule
name: frontend-default
spec:
  destination: svc-frontend.default.svc.cluster.local
  precedence: 1
  route:
  - tags:
      version: &amp;quot;2&amp;quot;
    weight: 10
  - tags:
      version: &amp;quot;1&amp;quot;
    weight: 90
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;根据上面的路由规则，对  svc-frontend 这一服务的访问，应该有 10% 流量分给版本 2，其余的 90% 分配给了版本 1。我们在 tool pod 中使用如下脚本测试这一分配：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;#!/bin/bash
for i in {1..100}
do
  curl -s svc-frontend/index.php | grep Version
done
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;执行效果：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$  ./curl.batch.sh  | grep 2 | wc -l
10
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;可以看到，完全符合之前我们的路由设置。&lt;/p&gt;

&lt;h2 id=&#34;超时策略&#34;&gt;超时策略&lt;/h2&gt;

&lt;p&gt;为了保障服务质量，我们有时会要求对某些服务的返回时间进行限制&lt;/p&gt;

&lt;p&gt;前面提到，我们生成了一个&lt;code&gt;delay.php&lt;/code&gt;，用于进行延时测试，文件内容如下：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-php&#34;&gt;&amp;lt;?php
header(&amp;quot;Content-type: text/plain&amp;quot;);
sleep(4);
echo &amp;quot;\n-----------------------------\n&amp;quot;;
echo &amp;quot;\nFrom: &amp;quot;.gethostname().&amp;quot;\n&amp;quot;;
echo &amp;quot;Version: &amp;quot;.$_ENV[&#39;SERVICE_VERSION&#39;].&amp;quot;\n&amp;quot;;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;正常执行&lt;code&gt;time curl -s svc-frontend/delay.php&lt;/code&gt;，会返回如下结果：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;-----------------------------
From: frontend-797054967-r12m5
Version: 1

real    0m4.025s
user    0m0.005s
sys     0m0.004s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;我们在这里加入一个策略，两秒超时：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;type: route-rule
name: front-timeout
spec:
  destination: svc-frontend.default.svc.cluster.local
  precedence: 9
  route:
  - tags:
      version: &amp;quot;1&amp;quot;
  httpReqTimeout:
    simpleTimeout:
      timeout: 2s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;再次测试，则会返回超时的结果：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;upstream request timeout
real    0m2.015s
user    0m0.006s
sys     0m0.003s
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;重试策略&#34;&gt;重试策略&lt;/h2&gt;

&lt;p&gt;在服务超时的时候，我们可能会希望请求自动重试。&lt;/p&gt;

&lt;p&gt;这一测试要求保留前面的超时策略，以便形成失败结果：&lt;/p&gt;

&lt;p&gt;策略文件如下：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;type: route-rule
name: front-timeout
spec:
  destination: svc-frontend.default.svc.cluster.local
  precedence: 9
  route:
  - tags:
      version: &amp;quot;1&amp;quot;
  httpReqRetries:
    simpleRetry:
      attempts: 3
      perTryTimeout: 2s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这里表示每次尝试的超时时间是两秒，重试三次。使用 curl 测试：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ time curl -s svc-frontend/delay.php
upstream request timeout
real    0m8.136s
user    0m0.005s
sys     0m0.006s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;时间为 8 秒，相当于四次超时的时间。&lt;/p&gt;

&lt;h2 id=&#34;rewrite&#34;&gt;Rewrite&lt;/h2&gt;

&lt;p&gt;和反向代理的情况类似，有时我们需要对进入服务的 URL 进行重写，下面的路由策略会将 &lt;code&gt;/front&lt;/code&gt; 替换为 &lt;code&gt;/&lt;/code&gt; 进行访问：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;type: route-rule
name: front-timeout
spec:
  destination: svc-frontend.default.svc.cluster.local
  precedence: 9
  match:
    httpHeaders:
      uri:
        prefix: &amp;quot;/front/&amp;quot;
  rewrite:
    uri: &amp;quot;/&amp;quot;
  route:
  - tags:
      version: &amp;quot;1&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;注意这里对&lt;code&gt;uri&lt;/code&gt;的操作，是使用 rewrite 中的 uri 替换 match 中的 uri，二者的对应关系是强制的。&lt;/p&gt;

&lt;p&gt;在 tool 里面进行测试访问：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ curl http://svc-frontend/front/index.php
-----------------------------

From: frontend-797054967-r12m5
Version: 1
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;故障注入&#34;&gt;故障注入&lt;/h2&gt;

&lt;p&gt;微服务测试过程中，能够自动生成一些错误，无疑是个很有帮助的事情。目前 istio 支持两种故障的模拟：时延和中断&lt;/p&gt;

&lt;h2 id=&#34;时延&#34;&gt;时延&lt;/h2&gt;

&lt;p&gt;下面的规则会为每个对该服务的请求都生成 7 秒的时延：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;type: route-rule
name: fdelay
spec:
  destination: svc-frontend.default.svc.cluster.local
  precedence: 9
  route:
  - tags:
      version: &amp;quot;1&amp;quot;
  httpFault:
    delay:
      percent: 100
      fixedDelay: 7s
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;percent: 产生时延的比例&lt;/li&gt;
&lt;li&gt;fixedDelay: 时间&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;使用 curl 验证，可以看到的确多出了 7 秒的处理时间。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ time curl -s http://svc-frontend/index.php
-----------------------------

From: frontend-797054967-r12m5
Version: 1

real    0m7.028s
user    0m0.007s
sys     0m0.003s
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;中断&#34;&gt;中断&lt;/h2&gt;

&lt;p&gt;这一功能可以模拟服务中断的情景，下面的 yaml 定义了该服务 100% 会返回 403 错误。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;type: route-rule
name: fdelay
spec:
  destination: svc-frontend.default.svc.cluster.local
  precedence: 9
  route:
  - tags:
      version: &amp;quot;1&amp;quot;
  httpFault:
    abort:
      percent: 100
      httpStatus: 403
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;curl 的验证结果如下：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$  curl -v svc-frontend/error.php
* Connected to svc-frontend (10.100.186.68) port 80 (#0)
&amp;gt; GET /error.php HTTP/1.1
&amp;gt; User-Agent: curl/7.38.0
&amp;gt; Host: svc-frontend
&amp;gt; Accept: */*
&amp;gt;
&amp;lt; HTTP/1.1 403 Forbidden
&amp;lt; date: Fri, 28 Jul 2017 01:27:52 GMT
* Server envoy is not blacklisted
&amp;lt; server: envoy
&amp;lt; content-length: 0
&amp;lt;
* Connection #0 to host svc-frontend left intact
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
  </channel>
</rss>
