<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>servicemesh | 伪架构师</title>
    <link>/tags/servicemesh/</link>
      <atom:link href="/tags/servicemesh/index.xml" rel="self" type="application/rss+xml" />
    <description>servicemesh</description>
    <generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>zh</language><lastBuildDate>Fri, 12 Jul 2019 11:40:31 +0800</lastBuildDate>
    <image>
      <url>/img/logo-wide.png</url>
      <title>servicemesh</title>
      <link>/tags/servicemesh/</link>
    </image>
    
    <item>
      <title>在 Linkerd2 中进行流量拆分</title>
      <link>/post/split-traffic-in-linkerd2/</link>
      <pubDate>Fri, 12 Jul 2019 11:40:31 +0800</pubDate>
      <guid>/post/split-traffic-in-linkerd2/</guid>
      <description>&lt;p&gt;最新发布的 Linkerd 2.4，加入了对流量拆分的支持。&lt;/p&gt;

&lt;p&gt;安装最新版本之后，可以看到这个流量拆分功能所使用的 API 资源并非来自 Linkerd，而是 SMI 规范的一部分。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ curl -sL https://run.linkerd.io/install | sh
...
$ kubectl api-resources | grep -i split
trafficsplits ts split.smi-spec.io true TrafficSplit
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;和 Istio 的 Service + Selector 的拆分方式不同，Linkerd 其实没有什么特别的上游定义方式，简单的定义独立的 Service 即可。例如我们要从 &lt;code&gt;flaskapp&lt;/code&gt; 服务分流到 v1 和 v2 两个版本，在 Istio 中，需要定义一个 flaskapp 服务，然后使用标签，在 Service 的标签子集中，选择两组 Subset 作为目的地。而在 Linkerd/SMI 中，就需要分别定义三个服务了，例如 flaskapp、flaskapp-v1、flaskapp-v2。下面简单操练一下。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ wget https://raw.githubusercontent.com/fleeto/istio-for-beginner/master/code/flaskapp/flaskapp.istio.yaml
$ linkerd inject flaskapp.istio.yaml | kubectl apply -f -
...
$ wget https://raw.githubusercontent.com/fleeto/istio-for-beginner/master/code/sleep/sleep.yaml
$ linkerd inject sleep.yaml | kubectl apply -f -
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;分别安装了两个版本的 flaskapp，和一个版本的 sleep 服务之后。再创建两个 flaskapp 的分版本服务。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: v1
kind: Service
metadata:
  name: flaskapp-v1
  labels:
    app: flaskapp
spec:
  selector:
    app: flaskapp
    version: v1
  ports:
    - name: http
      port: 80
      targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: flaskapp-v2
  labels:
    app: flaskapp
spec:
  selector:
    app: flaskapp
    version: v2
  ports:
    - name: http
      port: 80
      targetPort: 80
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;创建两个服务之后，就可以尝试拆分了，同样是一个 YAML：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: split.smi-spec.io/v1alpha1
kind: TrafficSplit
metadata:
  name: flask-split
spec:
  service: flaskapp
  backends:
  - service: flaskapp-v1
    weight: 1
  - service: flaskapp-v2
    weight: 500m
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;注意这里的定义和 Istio 也稍有不同，使用权重而非百分比进行分流。&lt;/p&gt;

&lt;p&gt;可以在 Sleep 中进行测试：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ for i in {1..1000}; do curl -sSL http://flaskapp/env/version | grep v1; done | wc -l
660
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;可以看到，按照我们的权重分配，成功进行了分流。但是目前在 SMI 中并没有看到条件选择的相关内容，因此目前的功能还比较初级。可以通过 &lt;a href=&#34;https://flagger.app/&#34; target=&#34;_blank&#34;&gt;Flagger&lt;/a&gt; 的加持，实现更加复杂的功能。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Envoy 和 Istio 的 6.18</title>
      <link>/post/envoy-and-istio-on-6-18/</link>
      <pubDate>Wed, 19 Jun 2019 18:24:32 +0800</pubDate>
      <guid>/post/envoy-and-istio-on-6-18/</guid>
      <description>

&lt;p&gt;地球对面的时间比我们这里晚一点，我们的 618 已经开始返场了，他们还在 618。&lt;/p&gt;

&lt;p&gt;服务网格方面，在这一天有了两个发布：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://eng.lyft.com/announcing-envoy-mobile-5c2067d9ade0&#34; target=&#34;_blank&#34;&gt;Envoy 发布了移动版&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://istio.io/about/notes/1.2/&#34; target=&#34;_blank&#34;&gt;Istio 发布了 1.2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;envoy-mobile&#34;&gt;Envoy Mobile&lt;/h2&gt;

&lt;p&gt;Envoy Mobile 是一个库，目的是可以直接将 Envoy 的功能封装到移动应用之中，&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;跨平台的底层网络支持：HTTP/2、QUIC、gRPC、推送、流、重试和超时策略等底层网络技术的实现以及跨平台都是需要付出大量努力来完成的事情，Evnoy Mobile 试图在客户端以一致的跨平台的方式提供这所有功能。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;xDS 支持：Envoy 的最深套路就是 xDS 了，Envoy 一旦潜入移动应用，就可以通过 xDS 的方式，在服务端对客户端的网络行为作出控制。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;API 的高级支持：用注解方式为 API 提供缓存、优先级等支持&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这个项目还非常早期，但是我觉得非常有意思，强悍的 Envoy 用这种方式为移动应用提供了一个可控的网络抽象的能力，目前已经提供了 Java、Swift、OC 等支持，这会不会成为一种新的边缘能力？&lt;/p&gt;

&lt;h2 id=&#34;istio-1-2&#34;&gt;Istio 1.2&lt;/h2&gt;

&lt;p&gt;补丁版本，没啥好说。&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;https://docs.google.com/document/d/1N0ZFJktK8m01uqqgfDRVB9mpC1iEn9dqkQaa_yMn_kE/edit#&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;https://istio.io/about/notes/1.2/&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;https://eng.lyft.com/announcing-envoy-mobile-5c2067d9ade0&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>SMI：推动服务网格社区举步前行</title>
      <link>/post/moving-the-service-mesh-community-forward/</link>
      <pubDate>Tue, 11 Jun 2019 07:48:13 +0800</pubDate>
      <guid>/post/moving-the-service-mesh-community-forward/</guid>
      <description>

&lt;p&gt;原文：&lt;a href=&#34;https://blog.christianposta.com/servicemesh/moving-the-service-mesh-community-forward/&#34; target=&#34;_blank&#34;&gt;Moving the Service-mesh Community Forward&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;作者：&lt;a href=&#34;https://twitter.com/christianposta&#34; target=&#34;_blank&#34;&gt;Christian Posta&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;在运行一个服务式架构的应用时，往往会面临服务间通信的挑战，服务网格技术正是为此而生。Kubernetes 和容器技术对工作负载的在大量服务器上的部署和进行提供了一个漂亮的抽象，服务网格做的也是类似的工作：他对网络进行抽象，让运维和开发人员能够通过请求路由、可观察性以及策略实施等方式对其进行控制。服务网格带来了各种可能。&lt;/p&gt;

&lt;p&gt;唯一的问题是，就算 Kubernetes 提供了有力的 API 来对底层基础设施进行抽象，从而进行工作负载的调度，可惜的是这其中没有一点能够落地的 API 能够提供服务网格所需要的能力。&lt;/p&gt;

&lt;p&gt;KubeCon EU 2019 上发布的&lt;a href=&#34;https://cloudblogs.microsoft.com/opensource/2019/05/21/service-mesh-interface-smi-release/&#34; target=&#34;_blank&#34;&gt;服务网格接口（SMI）&lt;/a&gt;正试图填补这一空白。在此声明：我为 Solo.io 工作，它是 SMI 的创建者之一，并是一个&lt;a href=&#34;https://medium.com/solo-io/https-medium-com-solo-io-supergloo-ff2aae1fb96f&#34; target=&#34;_blank&#34;&gt;原有统一服务网格产品&lt;/a&gt;的主导者。&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/deislabs/smi-spec&#34; target=&#34;_blank&#34;&gt;SMI 规范&lt;/a&gt;还很稚嫩，目前正在尝试对运行在 Kubernetes 基础之上的服务网格所需的 API 和能力进行统一（这种尝试也有助于为 Kubernetes 之外运行的统一服务网格奠定一个基础）。&lt;/p&gt;

&lt;p&gt;这一举措对服务网格社区来说，带来不少直接利益：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;服务网格的实现可能很复杂；将独立于实现的 API 暴露出来，让系统整体更易理解。&lt;/li&gt;
&lt;li&gt;这一社区充满变化，专注于能力，并通过标准接口来使用服务网格，降低了对特定实现的依赖；对最终用户来说，这是一个很好的启动方式。&lt;/li&gt;
&lt;li&gt;服务网格提供了一组强大的功能用来定义和处理规则（对网络进行编程）；需要有些东西来对这些能力进行编排。不管是厂商提供还是自行实现，将网络编程为特定的实现，这会将你绑定到这一实现，某种程度上也让你的实现变得更加复杂。&lt;/li&gt;
&lt;li&gt;在底层（像服务网格这样）为稳定性奠定基础，给未来的创新打开了新的可能，也给整个生态带来了新的机会。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;最小公分母&#34;&gt;最小公分母&lt;/h2&gt;

&lt;p&gt;社区里有些家伙对这类方法的可行性表示怀疑，反对的声音至关重要。例如我非常尊重的 Tim Hockin，他提到 SMI 方法有可能成为一种&lt;a href=&#34;https://twitter.com/chanwit/status/1137265809988890624&#34; target=&#34;_blank&#34;&gt;最小公分母，对谁都没好处&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;服务网格的能力范围还在扩张之中（目前不同的服务网格实现会有不同的特性），但是 Istio、Linkerd、Consul、App Mesh 等产品在某种程度上还是殊途同归的：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;流量路由功能（路由权重、在七层上提供请求级匹配等）满足了金丝雀发布等功能需求。这项能力的诉求是减小变更的影响范围

&lt;ul&gt;
&lt;li&gt;目前版本的 Istio 和 App Mesh 都已经提供这一功能，Consule 和 Consul 也会很快跟进。&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;顶端指标收集，例如延迟分布、吞吐量、出错率等

&lt;ul&gt;
&lt;li&gt;Istio、App Mesh 和 Linkerd 都提供这一能力，Consul 会在近期提供易于配置的（指标收集）功能。&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;基于服务身份的策略功能

&lt;ul&gt;
&lt;li&gt;Istio 和 Consol 已有这部分功能，Linkerd 和 App Mesh 会在近期加入。&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;语义差别不大&#34;&gt;语义差别不大&lt;/h3&gt;

&lt;p&gt;目前 Istio 的各种特性最为成熟，但是有很多其他的实现也正在跟进。事实上各种实现都很相似，关键的差异是易用性、用户体验、管理能力、集成能力等。而关键的问题：“服务网格应该有什么功能？”，各家的答案差别不大。如果 Istio、Linkerd、Consul、App Mesh 以及其它有兴趣在这一方向发展的厂商和社区能够提供支持，把这些差别不大的功能，做成一套 API 并不会难于登天。&lt;/p&gt;

&lt;h3 id=&#34;无处不在的-envoy-proxy&#34;&gt;无处不在的 Envoy proxy&lt;/h3&gt;

&lt;p&gt;服务网格的讨论中，还有一个很重要的情况就是通用数据平面的同化趋势。4 个著名的服务网格产品中，有 3 个使用的是 Envoy，并且还有其他服务网格供应商看起来也准备在 Envoy 的基础之上构建产品。我发现每个实现的控制面可能有些不同，但是内部的网络 API 都是继承自 Envoy，在同一个数据平面之下，一个跨服务网格的通用抽象也不算是不可思议。正如 Tim 所说，最大的麻烦来自于实现上的分歧。在这种情况下，其实这些产品并非天差地别。即使是控制平面本身，其实现也没有那么大的区别。&lt;/p&gt;

&lt;h3 id=&#34;基于已有实现&#34;&gt;基于已有实现&lt;/h3&gt;

&lt;p&gt;最后，SMI 来自于现存的服务网格产品。它不是凭空想象，也没有财团驱动，更不是由没有经验的团队造出的空中楼阁。恰恰相反，这一社区目前的贡献来自于真实存在的、在生产环境中部署的服务网格实现。从各个发起者的经验来说，做出一套脚踏实地的 API 并不会耸人听闻。&lt;/p&gt;

&lt;h2 id=&#34;厂商主导的-smi&#34;&gt;厂商主导的 SMI&lt;/h2&gt;

&lt;p&gt;另外来自 Zack Butcher 的意见也很醒目：SMI 由卖东西的厂商领导，调性不好。他特别提出：&lt;/p&gt;

&lt;blockquote class=&#34;twitter-tweet&#34;&gt;&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;Here&amp;#39;s the next sniff test: who&amp;#39;s backing the project? Are they users of service meshes trying to drive a standard, or are they vendors (trying to sell me something)? What are their motives, and do they align with giving me, a user, a more usable mesh? 7 &lt;a href=&#34;https://t.co/Fch2IfFVCM&#34;&gt;pic.twitter.com/Fch2IfFVCM&lt;/a&gt;&lt;/p&gt;&amp;mdash; Zack Butcher (@ZackButcher) &lt;a href=&#34;https://twitter.com/ZackButcher/status/1137718684829437952?ref_src=twsrc%5Etfw&#34;&gt;June 9, 2019&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;



&lt;blockquote&gt;
&lt;p&gt;他们的动机是什么？是给我——一个用户，一个更可用的服务网格？&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;SMI 规范的发起者之一，Brendan Burns 有个有趣的回应：&lt;/p&gt;

&lt;blockquote class=&#34;twitter-tweet&#34;&gt;&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;The current state of the art in service mesh where you have to lock yourself into an implementation is bad.&lt;br&gt;&lt;br&gt;Further, no one can build shared tools for all service meshes which is worse.&lt;br&gt;&lt;br&gt;And no one can build Helm charts that include service mesh apis w/o chosing an impl.&lt;/p&gt;&amp;mdash; brendandburns (@brendandburns) &lt;a href=&#34;https://twitter.com/brendandburns/status/1137478260382547968?ref_src=twsrc%5Etfw&#34;&gt;June 8, 2019&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;



&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;从目前服务网格的情况看来，把自己锁定在单一实现上是不好的。更进一步，没有人能够为所有服务网格构建共享工具。除非选择一个实现，否则没有人能构建一个包含服务网格 API 的 Helm Chart。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;

&lt;p&gt;我所在的 Solo.io，我们乐于看到单一的服务网格界面的出现，这是因为我们始终尝试为客户解决：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;不确定选择哪个网格&lt;/li&gt;
&lt;li&gt;想要在网格之上构建产品，但是希望在这一动荡的领域中保护投入&lt;/li&gt;
&lt;li&gt;希望服务网格的管理能有更好的用户体验&lt;/li&gt;
&lt;li&gt;希望将南北流量和东西向的网格进行集成&lt;/li&gt;
&lt;li&gt;希望得到厂商的帮助，但是&amp;hellip;&lt;/li&gt;
&lt;li&gt;无法确信任何网格厂商的动机&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;我们的客户和潜在和客户对于 SMI 的聚合是持肯定态度的，这一新生事物能够帮助他们应对上述这些问题。&lt;/p&gt;

&lt;p&gt;另外企业们发现，在满足其最终需求的情况下，存在竞争的多个公益炕上是很有价值的。正如我熟悉的 Java 和 Java EE 一样。标准化的 API 让企业能够参与并在这些讨论中获益。&lt;/p&gt;

&lt;h2 id=&#34;胜者为王&#34;&gt;胜者为王&lt;/h2&gt;

&lt;p&gt;关于 SMI，最后一个要探讨的想法是：类似容器编排战争的结果，单一厂商或者单一网格产品会成为唯一的赢家。如果预期是这种结局，又希望现在就用上服务网格，SMI 就成为一种有效的防御措施，防止踏入错误阵营无法回头。&lt;/p&gt;

&lt;p&gt;在我看来，真实情况是我们会面对多网格产品并存的情况，我们需要以某种方式进行统一（能力层次、集成方式或者管理方式，或者几个方法的结合）。&lt;/p&gt;

&lt;p&gt;例如我们的客户中的真实用例，他们在自有部署中使用 Istio 提供开发支持，但是其他团队使用的是 AWS，也使用了 AWS 的 App Mesh。他们有切实的需求，想要在这些网格的基础之上进行抽象并构建工具。如果出现了一个社区领导的抽象，他们就会使用并从中获得价值（至少是不用自己做了）。&lt;/p&gt;

&lt;h2 id=&#34;推动服务网格社区举步前行&#34;&gt;推动服务网格社区举步前行&lt;/h2&gt;

&lt;p&gt;目前来说，社区中的健康争论是必要的，以此可以发现问题、机遇和目标，从而帮助我们进一步的探索，为最终用户和平台构建者提供服务网格的强大功能。服务网格展现了有力的应用网络能力，但今时今日，终点还遥遥无期。&lt;/p&gt;

&lt;p&gt;类比容器和编排系统，Kubernetes 让容器变无聊了，服务网格最终也会让应用网络变得无聊。服务网格在加高堆栈的同时，会给用户、社区以及相关厂商带来价值。如果服务网格生态系统进入了寡头局面，这也很棒，我们会面向单一 API 来构建系统；如若不然（我认为这更有可能），我们最好一同努力，摒弃实现差异，努力找出服务网格应该提供的重要功能。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>意外：Servicemesh Interface（SMI）</title>
      <link>/post/servicemesh-interface/</link>
      <pubDate>Tue, 21 May 2019 23:08:25 +0800</pubDate>
      <guid>/post/servicemesh-interface/</guid>
      <description>

&lt;p&gt;在今天的 Kubecon（2019.05.21）上，微软宣布了一个新名词：Service Mesh Interface，简称 SMI，是一个运行于 Kubernetes 之上的服务网格规范，定义了一个能够被多个厂商实现的通用标准，其中包含了能够满足绝大多数通用需求的基本特性。&lt;/p&gt;

&lt;h2 id=&#34;设计重点&#34;&gt;设计重点&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Kubernetes 服务网格的标准接口。&lt;/li&gt;
&lt;li&gt;实现最通用的服务网格用例支持。&lt;/li&gt;
&lt;li&gt;能够支持新晋厂商加入的兼容能力。&lt;/li&gt;
&lt;li&gt;建立有创新空间的生态系统，促进服务网格技术的发展。&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&#34;规范内容&#34;&gt;规范内容&lt;/h2&gt;

&lt;p&gt;SMI 中定义了一组描述能力很有限的对象，用于进行服务网格的控制。的确如前文所说的设计重点一样，仅考虑了最核心（也就是最少）的功能支持，以兼容目前和未来的可能有的网格产品。&lt;/p&gt;

&lt;h3 id=&#34;流量规范&#34;&gt;流量规范&lt;/h3&gt;

&lt;p&gt;这一组 API 对 HTTP 和 TCP 服务自身进行了定义，例如：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: specs.smi-spec.io/v1alpha1
kind: HTTPRouteGroup
metadata:
  name: the-routes
matches:
- name: metrics
  pathRegex: &amp;quot;/metrics&amp;quot;
  methods:
  - GET
- name: health
  pathRegex: &amp;quot;/ping&amp;quot;
  methods: [&amp;quot;*&amp;quot;]
---
apiVersion: specs.smi-spec.io/v1alpha1
kind: TCPRoute
metadata:
  name: tcp-route
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;观察这一段代码样本，其 HTTP 部分，对服务端的路径、动作都做能做出详细的定义。未来这里还将加入对 Header 和 gRPC 的支持，SMI 发起者们认为这是一个很方便利用 OpenAPI 等工具自动生成的部分。它是一个基础，可以用于访问控制、频率限制等高级功能。&lt;/p&gt;

&lt;h3 id=&#34;访问控制&#34;&gt;访问控制&lt;/h3&gt;

&lt;p&gt;SMI 提供了一个很简单的访问控制功能，同样是使用 CRD 的方式，例如下面的代码：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;kind: TrafficTarget
apiVersion: access.smi-spec.io/v1alpha1
metadata:
 name: path-specific
 namespace: default
destination:
 kind: ServiceAccount
 name: service-a
 namespace: default
 port: 8080
specs:
- kind: HTTPRouteGroup
  name: the-routes
  matches:
    - metrics
sources:
- kind: ServiceAccount
  name: prometheus
  namespace: default
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这里可以看到，利用 &lt;code&gt;sources&lt;/code&gt; 和 &lt;code&gt;destination&lt;/code&gt;，对服务的访问能力进行了限制。这两个定义来看，只能包含网格内调用，尚无对 Ingress/Egress 流量的支持。&lt;/p&gt;

&lt;h3 id=&#34;流量拆分&#34;&gt;流量拆分&lt;/h3&gt;

&lt;p&gt;前面提到，流量拆分是在流量规范的基础上定义的，因此其定义相对简单：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: split.smi-spec.io/v1alpha1
kind: TrafficSplit
metadata:
  name: foobar-rollout
spec:
  service: foobar
  backends:
  - service: foobar-v1
    weight: 1
  - service: foobar-v2
    weight: 0m
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这里的服务定义和 Istio 不同，这个对象的候选访问目标，是&lt;strong&gt;选择条件重叠的一组独立服务&lt;/strong&gt;。典型工作流：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;名为 &lt;code&gt;foobar-v1&lt;/code&gt; 的 Deployment，标签为 &lt;code&gt;app: foobar&lt;/code&gt; &lt;code&gt;version: v1&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;服务 &lt;code&gt;foobar&lt;/code&gt;，选择器定义为 &lt;code&gt;app: foobar&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;服务 &lt;code&gt;foobar-v1&lt;/code&gt;，选择标准为 &lt;code&gt;app:foobar&lt;/code&gt; 且 &lt;code&gt;version: v1&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;客户端使用 &lt;code&gt;foobar&lt;/code&gt; 的 FQDN 来完成访问。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;要调整流量分拆，只需调整 &lt;code&gt;backends&lt;/code&gt; 中不同后端服务的权重即可。&lt;/p&gt;

&lt;h3 id=&#34;流量监控&#34;&gt;流量监控&lt;/h3&gt;

&lt;p&gt;指标数据的核心分为两个对象种类：&lt;code&gt;resource&lt;/code&gt; 和 &lt;code&gt;edge&lt;/code&gt;，&lt;code&gt;resource&lt;/code&gt; 代表 &lt;code&gt;pod&lt;/code&gt;、&lt;code&gt;namespace&lt;/code&gt;、&lt;code&gt;node&lt;/code&gt; 等对象，而 &lt;code&gt;edge&lt;/code&gt; 则描述了流量的方向。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: metrics.smi-spec.io/v1alpha1
kind: TrafficMetrics
# See ObjectReference v1 core for full spec
resource:
  name: foo-775b9cbd88-ntxsl
  namespace: foobar
  kind: Pod
edge:
  direction: to
  resource:
    name: baz-577db7d977-lsk2q
    namespace: foobar
    kind: Pod
timestamp: 2019-04-08T22:25:55Z
window: 30s
metrics:
- name: p99_response_latency
  unit: seconds
  value: 10m
- name: p90_response_latency
  unit: seconds
  value: 10m
- name: p50_response_latency
  unit: seconds
  value: 10m
- name: success_count
  value: 100
- name: failure_count
  value: 100
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;监控资源除了满足 Prometheus 等监控系统的使用之外，还能对服务拓扑、集群资源监控以及金丝雀发布等功能提供数据支持。&lt;/p&gt;

&lt;h2 id=&#34;参与厂商&#34;&gt;参与厂商&lt;/h2&gt;

&lt;p&gt;下图是这一新组织的合作方（&lt;strong&gt;没有 Google 好奇怪&lt;/strong&gt;）：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/partners.png&#34; alt=&#34;partners&#34; /&gt;&lt;/p&gt;

&lt;p&gt;其中多数厂商大家都非常熟悉了，有几个补充一下：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Solo.io：产品面很广，除了 Service Mesh 方面大有名气的 SuperGloo 和 Service Mesh hub 之外，还有远程调试、混沌工程、unikernels 以及微服务网关等几个产品。&lt;/li&gt;
&lt;li&gt;Mesery 和 Kinvolk：近期都发表了 Istio vs Linkerd 的性能测试报告。&lt;/li&gt;
&lt;li&gt;Canonical：Ubuntu 母公司。&lt;/li&gt;
&lt;li&gt;Kubecost：对 Kubernetes 集群进行成本分析。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Solo.io 的 Service Mesh Hub 和 SuperGloo 已经更新，宣布对 SMI 的支持。&lt;/p&gt;

&lt;p&gt;根据 Github 的数据，目前贡献前两名分别是 Buoyant 和 HashiCorp。&lt;/p&gt;

&lt;h2 id=&#34;读后感&#34;&gt;读后感&lt;/h2&gt;

&lt;p&gt;在去年 InfoQ 的 《Service Mesh2018年度总结》一文中有这么一段话：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Service Mesh 这一技术的广阔前景，加上 Istio 的疲弱表现，吸引了更多对此技术具有强烈需求或相关技术储备的竞争者出现，除了 AWS 、 F5 这样的公有云方案，以及 Consul、Kong 等同类软件解决方案，还出现了 Solo.io 这样的更加激进的跨云方案加入战团。
Service Mesh技术的浪潮已将业界席卷其中，然而这一年来，角逐者有增无减，2019 年里，Istio 仍是关键——除非 Istio 能够做出符合顶尖项目的水准，否则，Service Mesh 技术很可能会以多极化、市场细分的形式落地。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;好像我们猜到了开头，猜错了结局？&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://link.medium.com/zsUhK6OgSW&#34; target=&#34;_blank&#34;&gt;https://link.medium.com/zsUhK6OgSW&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/deislabs/smi-spec&#34; target=&#34;_blank&#34;&gt;https://github.com/deislabs/smi-spec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://msft.today/hello-service-mesh-interface-smi-a-specification-for-service-mesh-interoperability/&#34; target=&#34;_blank&#34;&gt;https://msft.today/hello-service-mesh-interface-smi-a-specification-for-service-mesh-interoperability/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://skyao.io/publication/201902-service-mesh-2018-summary/&#34; target=&#34;_blank&#34;&gt;https://skyao.io/publication/201902-service-mesh-2018-summary/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Istio 和 Linkerd 的性能测试分析</title>
      <link>/post/performance-benchmark-analysis-of-istio-and-linkerd/</link>
      <pubDate>Sun, 19 May 2019 13:29:38 +0800</pubDate>
      <guid>/post/performance-benchmark-analysis-of-istio-and-linkerd/</guid>
      <description>

&lt;p&gt;原文：&lt;a href=&#34;https://kinvolk.io/blog/2019/05/performance-benchmark-analysis-of-istio-and-linkerd/&#34; target=&#34;_blank&#34;&gt;Performance Benchmark Analysis of Istio and Linkerd&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;作者：&lt;a href=&#34;https://twitter.com/ThiloFM&#34; target=&#34;_blank&#34;&gt;Thilo Fromm&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;动机&#34;&gt;动机&lt;/h2&gt;

&lt;p&gt;过去几年里，服务网格在 Kubernetes 生态中迅速成长。Service Mesh 的&lt;strong&gt;价值&lt;/strong&gt;难以抗拒，然而对摩拳擦掌的用户来说，另一个基础问题就是：&lt;strong&gt;成本&lt;/strong&gt;怎样？&lt;/p&gt;

&lt;p&gt;成本有很多种，可不仅仅是学习新技术时的投入。在这一篇报告中，我们选择了一个易于量化的方面：在一定规模的服务中的资源消耗和性能影响。要进行这个测量，我们设计一系列测试场景，针对候选产品进行测试。我们的的候选包括 Istio（来自 Google 和 IBM 的 Istio 以及 Linkerd（CNCF 项目）。&lt;/p&gt;

&lt;p&gt;Buoyant 是 Linkerd 的首创者，他们和我们取得联系，目的是获得一个 Istio 和 Linkerd 的客观评判。这给我们一个深入服务网格技术的机会，欣然从命。&lt;/p&gt;

&lt;p&gt;Kinvolk 目前有客户正在尝试 Istio。我们的使命是在云原生世界中促进开源技术的发展，这也是我们呈现这一对比报告的根本原因。&lt;/p&gt;

&lt;p&gt;下面使用的测试方案也已经开放给开源社区，地址是 &lt;a href=&#34;https://github.com/kinvolk/service-mesh-benchmark。&#34; target=&#34;_blank&#34;&gt;https://github.com/kinvolk/service-mesh-benchmark。&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;目标&#34;&gt;目标&lt;/h2&gt;

&lt;p&gt;研究过程中我们有三个目标：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;提供一个可重现的测试框架，任何人都可以下载和使用。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;识别最能反应服务网格运行成本的场景和指标。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;根据业界在性能测试方面的最佳实践，例如控制编译来源，处理 Coordinated Omission（CO），来对流行服务网格进行评估。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&#34;场景&#34;&gt;场景&lt;/h2&gt;

&lt;p&gt;我们的目标是在常规大负载集群的操作环境下，理解服务网格的性能表现。这意味着在产生压力的时候，集群应用还有能力在已定时间范围内给出响应。在系统受到压力的时候，用户访问该集群所服务的页面，还能够在一个可忍受的范围内提供服务。在真实世界中，延迟增大到一定程度之后，就会采取措施进行扩容了。&lt;/p&gt;

&lt;p&gt;在本文的测试中，测试负载（每秒 HTTP 请求）的水平是这样设置的——在给应用和服务网格施加压力的时候，运行其上的流量还在一个可控范围之内。&lt;/p&gt;

&lt;h2 id=&#34;指标&#34;&gt;指标&lt;/h2&gt;

&lt;h3 id=&#34;rps-用户体验和-co&#34;&gt;RPS、用户体验和 CO&lt;/h3&gt;

&lt;p&gt;测试中使用一个恒定的请求速率（RPS）发送 hTTP 请求，我们对响应延迟进行测量，来确定服务网格的总体性能。同样的 RPS 也会施加到一个无服务网格的集群上，以此结果来描述集群和应用的性能基线。&lt;/p&gt;

&lt;p&gt;我们的测试过程很注重 CO，在以 UX 为中心的视角下的一个重要因素。负载生成器只会在前一个请求完成之后才发起新请求，而不是为了满足 RPS 要求，不顾之前的请求直接按照时间点发起心情求。&lt;/p&gt;

&lt;p&gt;比如说如果我们要做一个 10 RPS 的延迟测试，我们每隔 100 毫秒就发出一个新请求，也就是一个 10 Hz 的速率。但是如果负载生成器在等待一个耗时超出 100 毫秒的请求的结束的话，那么这个 RPS 最多只能到 9。单一请求造成了高延迟，后续的请求也会受到拖累——处理的并不慢，只是开始得晚了。这种行为有两个缺点：第一个就是刚提到的，单一的高延迟请求造成后续请求的延迟；第二就是请求的发生过程被暂停，不符合 RPS 要求。在真实情况下，高延迟问题很可能因为用户蜂拥而至，产生大量积压。&lt;/p&gt;

&lt;p&gt;我们使用 &lt;a href=&#34;https://github.com/giltene/wrk2&#34; target=&#34;_blank&#34;&gt;wrk2&lt;/a&gt; 来生成负载并在客户端测量延迟。wrk2（Gil Tene）是流行的 http 压测工具 wrk（Will Glozer）的 Fork。wrk2 提供了 RPS 参数，可以用指定速率来生成负载，它通过在发起请求的时间点上测试延迟的方式来消除 CO 问题，还会尝试在请求迟发的情况下以双倍速率生成请求的方式来追赶进度。wrk2 还包含了 Gil Tene 的 HDR 直方图功能，提供了无损精确性的记录。越长的执行时间会有越高的精确度，这样后几个百分位的数据精度更高，也是我们更感兴趣的区域。&lt;/p&gt;

&lt;p&gt;为了完成这个测试，我们对 wrk2 的功能做了扩展，加入了多服务器地址和多 HTTP 资源路径的支持。我们不想将这个功能独立 Fork 出来，而是会和上游合作加入我们的&lt;a href=&#34;https://github.com/kinvolk/wrk2&#34; target=&#34;_blank&#34;&gt;变更&lt;/a&gt;。&lt;/p&gt;

&lt;h3 id=&#34;性能&#34;&gt;性能&lt;/h3&gt;

&lt;p&gt;为了评估性能，我们可以研究一下延迟的分布（直方图），尤其是尾部的最后几个百分位的延迟。这反映了我们本次测试在 UE 上的焦点：一个典型的页面或者服务，需要不止一个请求来完成动作。如果一个请求延迟了，整个动作都会变慢。单一请求的 p99 在更复杂的操作中会有很大影响，例如浏览器访问一个页面，获取页面中的资源并进行顺序渲染——这就是我们看重 p99 的原因。&lt;/p&gt;

&lt;h3 id=&#34;资源消耗&#34;&gt;资源消耗&lt;/h3&gt;

&lt;p&gt;使用服务网格会让集群消耗更多资源，和业务逻辑发生争用。为了更好地理解这一效果，我们同时衡量了服务网格控制平面和应用 Sidecar 中的 CPU 和内存消耗。在测试期间，会用一个较高频率在容器级别收集 CPU 使用率和内存用量，每次运行中会选择组件的最大资源消耗，得出所有运行中的中位数并用于出具结果。&lt;/p&gt;

&lt;p&gt;我们注意到，内存消耗在测试结束时达到高峰。这个情况是合理的，根据上面的讨论，wrk2 用固定频率发起请求，当延迟超过一个阈值时，负载就会开始堆积，所以内存一旦分配就一直要到测试结束才会释放。CPU 使用率也会全程持续走高。&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;/p&gt;

&lt;p&gt;在这个服务网格性能测试过程中，我们使用了一个 5 节点的集群，每个节点使用 24核/48线程的 AMD EPYC CPU，主频为 2.4GHz，64G 内存。我们的工具可以使用可配置的节点数量，可以用不同的配置重新运行。&lt;/p&gt;

&lt;p&gt;负载的生成和延迟的测量都在集群内完成。为了消除噪音和 Ingress Gateway 的数据污染，我们把测试聚焦在应用之间的服务网格。负载生成器作为一个 Pod 部署在集群中，我们保留一个节点，用于负载生成和指标测量，在其它四个节点运行一定数量的应用实例。为了合理的统计分布，我们每次运行都会随机选择一个节点来运行负载生成器。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/clusterlayout.png&#34; alt=&#34;cluster layout&#34; /&gt;&lt;/p&gt;

&lt;p&gt;每次运行之前，会随机选择一个节点专门用于生成负载。其它节点运行应用负责承担负载。&lt;/p&gt;

&lt;p&gt;为了完成这次测试，我们选择 Packet 作为我们的 IaaS 供应商，工作节点我们选择了 c2.medium。Packet 提供了裸金属服务器，这样就让我们避免了虚拟化环境中常见的干扰问题。&lt;/p&gt;

&lt;h3 id=&#34;应用&#34;&gt;应用&lt;/h3&gt;

&lt;p&gt;根据前面的讨论，我们选择 wrk2 生成负载，并对这一工具进行了定制，可以同时访问多个 HTTP 端点。&lt;/p&gt;

&lt;p&gt;我们用来运行测试的目标应用是 Linkerd 的演示应用 &lt;code&gt;Emojivoto&lt;/code&gt;，这个应用自身跟 Linkerd/服务网格 的功能并无相关，Emojivoto 使用一个名为 &lt;code&gt;web-svc&lt;/code&gt;（&lt;code&gt;type: load-balancer&lt;/code&gt;）的 HTTP 微服务作为前端。&lt;code&gt;web-svc&lt;/code&gt; 使用 gRPC 和 &lt;code&gt;emoji-svc&lt;/code&gt;（提供表情符） 以及 &lt;code&gt;voting-svc&lt;/code&gt;（提供可控的投票）后端进行通信。这个应用简单清晰，包含了测试所需的云原生应用的所有要素，因此我们选择它作为测试应用。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/emojivoto.png&#34; alt=&#34;emojivoto&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Emojivoto 应用包含了三个微服务。&lt;/p&gt;

&lt;p&gt;然而只用一个应用进行服务网格测试，是很不现实的，真实世界中的服务网格，应该有复杂的多应用的部署。为了在保持简单的情况下更加仿真，我们用可部署的份数来部署 Emojivoto 应用，每个应用的名字中都加入序号。例如  &lt;code&gt;web-svc-1&lt;/code&gt;、&lt;code&gt;emoji-svc-1&lt;/code&gt;、&lt;code&gt;voting-svc-1&lt;/code&gt; 以及 &lt;code&gt;web-svc-2&lt;/code&gt;、&lt;code&gt;emoji-svc-2&lt;/code&gt;、&lt;code&gt;voting-svc-2&lt;/code&gt;。我们的负载均衡会将请求分发给所有这些 App，观察固定的 RPS。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/manyemojivotos.png&#34; alt=&#34;replica&#34; /&gt;&lt;/p&gt;

&lt;p&gt;循环利用 YAML，并在名字中加入序号，部署多套应用。&lt;/p&gt;

&lt;h3 id=&#34;运行测试和统计的稳健性&#34;&gt;运行测试和统计的稳健性&lt;/h3&gt;

&lt;p&gt;因为我们使用的是 Packet 提供的公共数据中心来运行我们的测试，所以也不能选择特定的服务器来进行部署。服务器的年龄和他的部件（内存、CPU 等），数据中心中的相对位置（同一个机架、房间、安全区），以及节点之间的物理连接，这些情况都会对测试的原始数据产生影响。其它服务器和我们的测试无关，但是在同一个数据中心内，共享同样的物理网络资源，也是可能对测试造成干扰的，最终会产生不可靠的测试数据。我们的每个数据点都有足够的统计分布样本，这样在进行对比的时候就能消除同一网络内外部因素造成的影响——例如 Istio 和 Linkerd 的延迟以及资源消耗方面的对比。我们还使用了不同数据中心的多个集群进行了测试，这也让我们对测试数据的可靠性信心大增。&lt;/p&gt;

&lt;p&gt;为了得到足够的统计分布，我们会每个测试都会运行两次，以得出平均值和标准差，我们在两个集群上同时独立部署，防止遭遇低档硬件或者故障网络，或有服务器被放置在数据中心的角落。&lt;/p&gt;

&lt;p&gt;典型的性能测试一般有几个步骤，这些步骤会在两个集群上同时运行，来消除上面提到的隐患。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;测试之前，重启所有工作节点。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;在两个集群的 &lt;code&gt;istio-stock&lt;/code&gt;、&lt;code&gt;istio-tuned&lt;/code&gt;、&lt;code&gt;linkerd&lt;/code&gt;、&lt;code&gt;bare&lt;/code&gt; 命名空间中，分别：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;安装服务网格（当然，不包含 &lt;code&gt;bare&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;部署 emojivoto 应用。&lt;/li&gt;
&lt;li&gt;部署负载生成器 Job。&lt;/li&gt;
&lt;li&gt;等 Job 结束，每 30 秒拉取一次资源消耗数据。&lt;/li&gt;
&lt;li&gt;拉取测试结果日志，其中包含了延迟指标。&lt;/li&gt;
&lt;li&gt;删除敷在生成 Job 以及 emojivoto。&lt;/li&gt;
&lt;li&gt;删除服务网格。&lt;/li&gt;
&lt;li&gt;回到第一步，测试下一个服务网格（顺序为：Linkerd-&amp;gt;Istio-&amp;gt;Bare）。&lt;/li&gt;
&lt;li&gt;在所有的 4 个测试结束之后，再运行第二次，以满足统计需要。&lt;/li&gt;
&lt;/ol&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;重现性&#34;&gt;重现性&lt;/h3&gt;

&lt;p&gt;w我们使用的是 Kinvolk 最近发布的 Kubernetes 发行版：Lokomotive。用于集群部署以及用于测试的代码都是开源的，保存在 Github 上。允许重新进行测试，也希望能够从其它用户那里得到改进。&lt;/p&gt;

&lt;h3 id=&#34;测试的运行和观测&#34;&gt;测试的运行和观测&lt;/h3&gt;

&lt;p&gt;我们在 &lt;code&gt;bare&lt;/code&gt;（无服务网格）、&lt;code&gt;istio-stock&lt;/code&gt;（无微调）、&lt;code&gt;istio-tuned&lt;/code&gt; 以及 &lt;code&gt;Linkerd&lt;/code&gt; 上，用 500 的 RPS 运行 30 分钟。在两个集群上各运行两次，每种数据就有了 4 个样本。测试集群分布在两个不同地理区域的不同的数据中心，一个是 Packet 的 Sunnyvale 数据中心，另一个是纽约的 Parsippany 数据中心。&lt;/p&gt;

&lt;h3 id=&#34;服务网格的版本&#34;&gt;服务网格的版本&lt;/h3&gt;

&lt;h4 id=&#34;istio-stock-和-tuned&#34;&gt;Istio：stock 和 tuned&lt;/h4&gt;

&lt;p&gt;我们用 &lt;a href=&#34;https://github.com/istio/istio/releases/tag/1.1.6&#34; target=&#34;_blank&#34;&gt;Istio 1.1.6&lt;/a&gt; 运行这一测试，&lt;code&gt;stock&lt;/code&gt; 运行的是根据&lt;a href=&#34;https://istio.io/docs/setup/kubernetes/install/kubernetes/&#34; target=&#34;_blank&#34;&gt;安装文档&lt;/a&gt;进行部署的版本，&lt;code&gt;tuned&lt;/code&gt; 版本则移除了内存限制，禁用了部分 Istio 组件，执行了不少推荐的微调。尤其是我们禁用了 Mixer、Policy、Tracing、Gateways 以及 Prometheus。&lt;/p&gt;

&lt;h4 id=&#34;linkerd&#34;&gt;Linkerd&lt;/h4&gt;

&lt;p&gt;我们使用的是 Linkerd 的 &lt;a href=&#34;https://github.com/linkerd/linkerd2/releases/tag/edge-19.5.2&#34; target=&#34;_blank&#34;&gt;Linkerd2-edge-19.5.2&lt;/a&gt;。我们使用的是 Linkerd 的&lt;a href=&#34;https://linkerd.io/2/getting-started/&#34; target=&#34;_blank&#34;&gt;标准配置&lt;/a&gt;，没有进行任何调整。&lt;/p&gt;

&lt;h3 id=&#34;测试服务网格的上限&#34;&gt;测试服务网格的上限&lt;/h3&gt;

&lt;p&gt;在使用稳定吞吐量开始长期运行之前，我们用一个较短的测试来确定服务网格吞吐量和延迟的范围。我们的目标是找到一个负载点，在这个点上，网格还能够用可接受的性能来处理流量。&lt;/p&gt;

&lt;p&gt;为了我们的测试，我们运行了 30 个 Emojivoto 应用，也就是 90 个微服务，平均下来每个节点有 7.5 个应用 22 个微服务。我们用多个 RPS 各运行 10 分钟，来确定前面所说的负载点。&lt;/p&gt;

&lt;h3 id=&#34;测试运行时间&#34;&gt;测试运行时间&lt;/h3&gt;

&lt;p&gt;我们最有兴趣的是尾部的百分位，因此测试的运行时间就很有影响了。越长的运行时间，在 99.9999 百分位和 100 百分位上的延迟就会越高。为了模拟用户涌入造成的高峰、以及新计算资源加入后的恢复，我们决定了 30 分钟的运行时间。注意，我们认为在多数环境里，尤其是自动伸缩的环境中，新资源的加入周期应该远低于 30 分钟；我们还认为，一个健壮的应用环境中，30 分钟足以应对扩容方面的意外。&lt;/p&gt;

&lt;h2 id=&#34;第一次测试-500-rps-30-分钟&#34;&gt;第一次测试：500 RPS，30 分钟&lt;/h2&gt;

&lt;p&gt;这次测试运行超过 30 分钟，500 RPS。&lt;/p&gt;

&lt;h3 id=&#34;延迟分布&#34;&gt;延迟分布&lt;/h3&gt;

&lt;p&gt;&lt;img src=&#34;images/500RPS-latency.png&#34; alt=&#34;500RPS-latency&#34; /&gt;&lt;/p&gt;

&lt;p&gt;我们在对数中观察到裸金属案例运行中，出现了很大的错误——可能是 Packet 的问题。这个情况在 99.9 和 99.999 上尤其明显，然而其他的数据点还是证明了整体趋势。我们看到 Linkerd 在这方面是胜出的，Istio 的缺省配置和微调配置相差不大，接下来看看资源消耗。&lt;/p&gt;

&lt;h3 id=&#34;内存和-cpu&#34;&gt;内存和 CPU&lt;/h3&gt;

&lt;p&gt;&lt;img src=&#34;images/500RPS-memory_usage.png&#34; alt=&#34;500RPS-memory_usage.png&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/500RPS-cpu_utilization.png&#34; alt=&#34;500RPS-cpu_utilization&#34; /&gt;&lt;/p&gt;

&lt;p&gt;我们在 4 个独立测试运行的过程中，测量了内存分配和 CPU 使用率，在这 4 个样本中，使用了中位数以及最高最低值。Linkerd 控制平面内存消耗的异常点是由 linkerd-prometheus 容器造成的，它消耗了 Linkerd 平面其他组件内存的两倍。&lt;/p&gt;

&lt;p&gt;而 Istio 中，我们看到了几次控制平面容器（Pilot 及其代理）消失的情况。我们不明白其中的原因，也没有深究，也没有把消失的容器计入结果。&lt;/p&gt;

&lt;h2 id=&#34;第二次测试-600-rps-30-分钟&#34;&gt;第二次测试：600 RPS，30 分钟&lt;/h2&gt;

&lt;p&gt;这次测试运行超过 30 分钟，600 RPS。&lt;/p&gt;

&lt;h3 id=&#34;延迟分布-1&#34;&gt;延迟分布&lt;/h3&gt;

&lt;p&gt;&lt;img src=&#34;images/600RPS-latency.png&#34; alt=&#34;600RPS-latency&#34; /&gt;&lt;/p&gt;

&lt;p&gt;我们再次观测到了裸金属测试中的抖动；然而其影响比 500 RPS 的时候更小。我们逼近了 Linkerd 的可接受响应时间的上限，在 100 百分位上的是 3 秒钟的延迟。&lt;/p&gt;

&lt;p&gt;Istio 轻松的把延迟时间推到了分钟级（别忘了 Y 轴是对数），我们还看到了大量的 Socket/HTTP 错误，占了大概 1%-5.2%，中位数在 3.6%。我们要指出，Istio 的 RPS 承受范围在 565 和 571 之间，中位数是 568。Istio 在本次测试中没能达到 600 RPS。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/600RPS-memory_usage.png&#34; alt=&#34;600RPS-memory_usage.png&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/600RPS-cpu_utilization.png&#34; alt=&#34;600RPS-cpu_utilization&#34; /&gt;&lt;/p&gt;

&lt;p&gt;上图的对比不太公平——我们看到的是 Linkerd 在 600 RPS 时候的表现，而 Istio 的是 570 RPS——但我们还是看得出，Istio 这里的资源需求。我们再次观察到 Istio 容器消失的情况，同样做了忽略处理。&lt;/p&gt;

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

&lt;p&gt;与裸金属相比，在常规条件下，Linkerd 和 Istio 的开销都算是可以接受的。当进入高负载状态时，相对于 Istio，Linkerd 能够提供更高的 RPS，并且使用更少的资源。&lt;/p&gt;

&lt;h2 id=&#34;下一步&#34;&gt;下一步&lt;/h2&gt;

&lt;p&gt;基于上面测试的观察，我们认为我们建立了一个良好的测试基础。未来的测试会进行更多的尝试，包括增强现有的测试，以及扩展测试场景。&lt;/p&gt;

&lt;p&gt;我们认为把负载生成器限制在一个 Pod 中是一个最大的限制。这限制了负载的生成能力。如果突破了这一限制，我们就有能力进行更多样的测试方法。然而在多个 Pod 中并列运行，又带来了结果合并的问题。&lt;/p&gt;

&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;以下内容纯属个人胡言乱语&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;也不知道为啥，连续冒出几个性能测试来，与性能相比，更重要的是靠谱和有用好吗。Istio 还是 Linkerd，能长点心么。&lt;/p&gt;

&lt;h2 id=&#34;参考资料&#34;&gt;参考资料&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://linkerd.io/2019/05/18/linkerd-benchmarks/&#34; target=&#34;_blank&#34;&gt;https://linkerd.io/2019/05/18/linkerd-benchmarks/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>服务网格——模式还是技术？</title>
      <link>/post/service-mesh-pattern-not-tech/</link>
      <pubDate>Thu, 16 Aug 2018 10:27:43 +0800</pubDate>
      <guid>/post/service-mesh-pattern-not-tech/</guid>
      <description>

&lt;p&gt;原文：&lt;a href=&#34;https://konghq.com/blog/service-mesh-new-pattern-not-new-technology&#34; target=&#34;_blank&#34;&gt;Service Mesh – A New Pattern, Not A New Technology?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;原作者：&lt;a href=&#34;https://konghq.com/blog/author/marco/&#34; target=&#34;_blank&#34;&gt;Marco Palladino&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;service-mesh-是什么-从何而来&#34;&gt;Service Mesh 是什么？从何而来？&lt;/h2&gt;

&lt;p&gt;近几个月，你会注意到围绕服务网格以及未来软件架构的业内讨论如火如荼。这些讨论围绕着几个供应商，呈现出一种部落战争的态势。这种党争虽然司空见惯，但是其中一些共同话题还是很有意义的——例如企业中 API 应用的快速转型，以及服务网格对流量拓扑的意义。&lt;/p&gt;

&lt;p&gt;服务 API 最初用于在组织边界提供访问内部系统的接口，供外部开发人员访问；这种情况并未持续很久，很快，服务 API 就变成将内部系统连接在一起的粘合剂。而微服务架构的发展，带来了一个无法回避的后果：数据中心内的内部通信持续增长。服务网格适时出现，提供了一种面向现有技术的部署框架，可能成为应对东西向流量增长问题的一个解决方案。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/diagram-04-1.png&#34; alt=&#34;img&#34; /&gt;&lt;/p&gt;

&lt;p&gt;作为 Kong 的 CTO，我也很热衷于参加这些对话，我注意到对服务网格的认知有一个普遍误解。为了消除误会，升级对话，首先我想要明确提出：服务网格是一种模式，而非技术。&lt;/p&gt;

&lt;h2 id=&#34;服务网格是一种模式-而非技术&#34;&gt;服务网格是一种模式，而非技术&lt;/h2&gt;

&lt;p&gt;微服务是模式而非技术，服务网格也是一样。这两种概念的区别貌似很难理解。如果我们从 OOP 的角度来看，模式描述的是接口，不是实现。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/diagram-01.png&#34; alt=&#34;img2&#34; /&gt;&lt;/p&gt;

&lt;p&gt;服务网格这样的部署模式能够利用 Sidecar 增强东西向的流量管理，能给微服务提供强大支援。既然已经对单体应用进行了解耦，并用微服务构建了新的应用，我们的流量模型中，内部流量就会与日俱增。数据中心内，东西向的流量增长原因是我们将单体应用中的函数调用换成了网络调用，这意味着我们的微服务必须融入网络，互相消费。然而地球人都知道——网络靠不住。&lt;/p&gt;

&lt;p&gt;面对日益增长的东西向流量，服务网格通过新的部署架构进行应对。传统的南北向通信中，100 毫秒的延迟虽不够理想，但也在可接受范围之内；但在东西向通信中，这就无法忍受了。这是因为服务间的相互调用会使延迟倍增，跨越多个服务的 API 调用和返回，会造成延迟时间的大幅增加。&lt;/p&gt;

&lt;p&gt;为了降低延迟，引入了独立运行的 Sidecar，这种代理服务器会伴随微服务进程一起运行，用来移除多余的网络跳跃。Sidecar 在请求的执行路径上担任数据平面的角色，并且避免了单点失败，从而提供了更好的应用弹性。然而，每个微服务进程都配合一个代理进程，势必会造成资源的损耗，但同时他也降低了资源耗尽的肯能性。&lt;/p&gt;

&lt;p&gt;经过细致观察不难发现，服务网格中的很多功能，都已经在多年前的 API 管理产品中实现了。比如可观测、网络故障处理和健康检查等功能都是 API 管理的基本配置。这些特性并不新鲜，但服务网格作为一种新的模式，用新思路来完成了这些功能。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/diagram-02.png&#34; alt=&#34;img&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;传统-api-管理方案瞠目其后&#34;&gt;传统 API 管理方案瞠目其后&lt;/h2&gt;

&lt;p&gt;微服务和容器大潮迫使人们更多的关注轻量级进程，服务网格提供的轻量级进程，同时承担了代理和反向代理的角色，伴随微服务进程一同运行。为什么传统的 API 管理方案不采用这种新的部署方案？这是因为他们生于单体时代。这些早于 Docker 和 Kubernetes 面世的 API 管理系统本身就是单体应用，并不适用于新兴的容器生态圈。传统 API 管理方案往往具有重量级的运行时和低下的性能，这些问题在过去的边缘 API 用例中尚可承受，但是对于微服务体系来说，东西向调用量越多，中间环节的延迟就越大。究其根本，传统 API 管理方案的重量大、难度高以及速度慢的缺点是难以满足微服务世界的要求的。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/diagram-05.png&#34; alt=&#34;img&#34; /&gt;&lt;/p&gt;

&lt;p&gt;开发人员了解了这些，传统的 API 管理方案引入了称之为 &amp;ldquo;microgateway&amp;rdquo;（微型网关）的技术，用来处理东西向的流量，并且避免重写现存的臃肿的单体网关方案。问题是这些所谓的微型网关虽然自身变轻了，但还是要依赖传统方案伴行，用于提供策略实施等能力。这不仅是留下陈旧组件的问题，还意味着增加了延迟。如此种种，服务网格就令人耳目一新了——对手太旧了。&lt;/p&gt;

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

&lt;p&gt;传统的 API 管理方案在南北向流量管理中耕耘多年，服务网格的功能相对来说并不新鲜。多数网络方面以及观测方面的能力对东西向和南北向的流量都是通用的，服务网格让我们有机会运行轻量快速的 Sidecar 代理来完成这些通用功能，改变的是部署模式，不是底层功能。&lt;/p&gt;

&lt;p&gt;传统 API 管理方案的功能是服务网格功能的超级，某种意义上来说，普及了可靠性、服务发现和观测能力。服务网格是一种部署模式，用轻量级的方式获得同样的功能。业界经常混淆——有时还加重了这种混淆——很多服务网格方面的讨论，都混淆了特定部署模板和底层技术的界限。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Istio 大入门 - Ingress</title>
      <link>/post/istio-ingress-dive/</link>
      <pubDate>Sat, 11 Aug 2018 14:44:26 +0800</pubDate>
      <guid>/post/istio-ingress-dive/</guid>
      <description>

&lt;blockquote&gt;
&lt;p&gt;本文涉及细节较多，需读者对 Docker、Kubernetes 以及 Istio 有一定了解和实践经验，否则可能难于操作。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Istio 从 v1alpha3 开始，用 Ingress Gateway 组件替代了符合 Kubernetes 规范的 Ingress Controller，因此对入站流量具有了更大的控制能力，但是用法也有了较大不同。&lt;/p&gt;

&lt;p&gt;安装：在使用 Helm 进行 Istio 部署的时候，需要使用下面的设置来启用 Ingress Gateway：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;gateways:
  enabled: true
  istio-ingressgateway:
    enabled: true
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;基本概念&#34;&gt;基本概念&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;VirtualService&lt;/code&gt; 是流量控制的核心组件，起着承上（&lt;code&gt;Gateway&lt;/code&gt;）启下（&lt;code&gt;DestinationRule&lt;/code&gt;）的作用。这三种对象在本文中涉及的主要职责：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Gateway&lt;/code&gt; 对象：

&lt;ul&gt;
&lt;li&gt;选择 Gateway Ingress Controller。&lt;/li&gt;
&lt;li&gt;设置端点开放方式：域名、端口、入站协议等。&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DestinationRule&lt;/code&gt;：

&lt;ul&gt;
&lt;li&gt;定义负载均衡行为。&lt;/li&gt;
&lt;li&gt;定义服务版本子集。&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;VirtualService&lt;/code&gt;：

&lt;ul&gt;
&lt;li&gt;根据 Gateway 选择服务版本。&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;根据 &lt;a href=&#34;https://istio.io/docs/reference/config/istio.networking.v1alpha3/#VirtualService&#34; target=&#34;_blank&#34;&gt;VirtualService 对象文档&lt;/a&gt;中的说明，&lt;code&gt;VirtaulService&lt;/code&gt; 对象中的 &lt;code&gt;gateways&lt;/code&gt; 字段的类型为 &lt;code&gt;string[]&lt;/code&gt;，包括一或多个字符串值。如果省略该字段内容，会隐式的赋值为 &lt;code&gt;[&amp;quot;mesh&amp;quot;]&lt;/code&gt;，&lt;code&gt;mesh&lt;/code&gt; 网关指代所有的网格内通信。如果要对外提供服务，就需要定义 &lt;code&gt;Gateway&lt;/code&gt; 对象，并在 &lt;code&gt;gateways&lt;/code&gt; 字段中进行赋值。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;注意，一旦在 &lt;code&gt;gateways&lt;/code&gt; 中填写了非缺省的对象名称，要继续对内部通信进行流量控制，必须显式的将内置的 &lt;code&gt;mesh&lt;/code&gt; 对象名称也加入到列表之中。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;准备工作&#34;&gt;准备工作&lt;/h2&gt;

&lt;h3 id=&#34;环境准备&#34;&gt;环境准备&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;安装和部署 Kubernetes 以及 Istio，并启用 Ingress Gateway 支持。&lt;/li&gt;
&lt;li&gt;将备用的两个域名（假设为 &lt;code&gt;flask.example2.com&lt;/code&gt; 以及 &lt;code&gt;flask.example1.com&lt;/code&gt;）指向 &lt;code&gt;istio-ingressgateway&lt;/code&gt; 服务的外部 IP。&lt;/li&gt;
&lt;li&gt;为测试域名生成 HTTPS 证书。&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&#34;域名准备&#34;&gt;域名准备&lt;/h3&gt;

&lt;h3 id=&#34;工作负载&#34;&gt;工作负载&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;首先编写一个基于 Flask 的 Python 脚本，并打入镜像，脚本功能很简单，显示环境变量中的 &amp;ldquo;VERSION&amp;rdquo;。&lt;/li&gt;
&lt;li&gt;接下来编写 Dockerfile，安装 Python3、Flask，并进行构建和推送。&lt;/li&gt;
&lt;li&gt;编写 Kubernetes 工作负载文件，常见的 Deployment + Service 模式。&lt;/li&gt;
&lt;li&gt;在 Kubernetes 上运行工作负载。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;以上涉及代码可以在页面尾部获取。&lt;/p&gt;

&lt;h3 id=&#34;目标规则定义&#34;&gt;目标规则定义&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: flask
spec:
  host: flask
  trafficPolicy:
    loadBalancer:
      simple: RANDOM
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这里根据工作负载中的标签，将 &lt;code&gt;flask&lt;/code&gt; 服务拆分为 &lt;code&gt;v1&lt;/code&gt; 和 &lt;code&gt;v2&lt;/code&gt; 两个版本。&lt;/p&gt;

&lt;h2 id=&#34;在外网开放服务&#34;&gt;在外网开放服务&lt;/h2&gt;

&lt;p&gt;这里我们设计，将所有外网请求经过 &lt;code&gt;flask.example1.com&lt;/code&gt; 路由到 &lt;code&gt;v2&lt;/code&gt; 版本上。&lt;/p&gt;

&lt;p&gt;首先要编写一个 &lt;code&gt;Gateway&lt;/code&gt; 定义：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: flask-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - flask.example1.com
        - flask.example2.com
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这里定义了一个 &lt;code&gt;Gateway&lt;/code&gt;，其中要求 80 端口响应两个域名的请求。接下来定义一个 &lt;code&gt;VirtualService&lt;/code&gt;：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
    name: flask
spec:
    hosts:
    - &amp;quot;flask.example1.com&amp;quot;
    gateways:
    - flask-gateway
    http:
    - route:
        - destination:
            host: flask
            subset: v2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;然后使用 curl 进行访问：&lt;code&gt;curl http://flask.example1.com&lt;/code&gt; 会发现返回了字符串 &amp;ldquo;v2&amp;rdquo;，证明我们的定义生效了，该域名指向了 &lt;code&gt;v2&lt;/code&gt; 服务。&lt;/p&gt;

&lt;p&gt;再用 curl 访问第二个域名 &lt;code&gt;curl http://flask.example2.com&lt;/code&gt;，会看到返回了 404，这是因为我们的 &lt;code&gt;Gateway&lt;/code&gt; 虽然接收了请求，但是并没有服务路由完成这一请求。那么可以再定义一个 &lt;code&gt;VirtualService&lt;/code&gt;，让 &lt;code&gt;flask.example2.com&lt;/code&gt; 域名指向 &lt;code&gt;v1&lt;/code&gt;：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
    name: flask1
spec:
    hosts:
    - &amp;quot;flask.example2.com&amp;quot;
    gateways:
    - flask-gateway
    http:
    - route:
        - destination:
            host: flask
            subset: v1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;再次使用 &lt;code&gt;curl http://flask.example2.com&lt;/code&gt;，访问，会看到返回结果变成了 &lt;code&gt;v1&lt;/code&gt;，证明我们的服务定义生效了。&lt;/p&gt;

&lt;h2 id=&#34;将一个域名服务升级为-tls&#34;&gt;将一个域名服务升级为 tls&lt;/h2&gt;

&lt;p&gt;随意修改一个需求，要求开放 &lt;code&gt;flask.example2.com&lt;/code&gt; 为 http，而 &lt;code&gt;flask.example1.com&lt;/code&gt; 升级为 https，既然涉及 https，就要用到证书，&lt;a href=&#34;https://istio.io/zh/docs/tasks/traffic-management/secure-ingress/&#34; target=&#34;_blank&#34;&gt;官方文档（中文版哦）&lt;/a&gt;陈述如下：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;具体说来就是使用 kubectl 命令在命名空间 istio-system 中创建一个 secret 对象，命名为 istio-ingressgateway-certs。Istio 网关会自动载入这个 secret。
这里的 secret 必须 在 istio-system 命名空间中，并且命名为 istio-ingressgateway-certs，否则就不会被正确载入，也就无法 Istio gateway 中使用了。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;接着是使用命令为 &lt;code&gt;flask.example1.com&lt;/code&gt; 的证书创建 &lt;code&gt;Secret&lt;/code&gt;：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl create -n istio-system secret tls \
    istio-ingressgateway-certs \
    --key key.pem --cert cert.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;最后修改我们的 &lt;code&gt;Gateway&lt;/code&gt; 定义：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: flask-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - flask.example2.com
    - port:
        number: 443
        name: https-rocks
        protocol: HTTPS
      tls:
        mode: SIMPLE
        serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
        privateKey: /etc/istio/ingressgateway-certs/tls.key
      hosts:
        - flask.example1.com
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;然后再次使用 curl 分别访问 &lt;code&gt;https://flask.example1.com/version&lt;/code&gt; 以及 &lt;code&gt;http://flask.example2.com/version&lt;/code&gt;，会发现返回了预期结果，而一旦错用 &lt;code&gt;http&lt;/code&gt; 和 &lt;code&gt;https&lt;/code&gt;，就会出现异常，这是因为我们的 &lt;code&gt;Gateway&lt;/code&gt; 限制了端口。&lt;/p&gt;

&lt;p&gt;这里如此操作的原因可以在他的部署中找到：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl get deployment istio-ingressgateway \
    -o yaml -n istio-system
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;返回的 YAML 中会有这么一段&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;...
- mountPath: /etc/istio/ingressgateway-ca-certs
    name: ingressgateway-ca-certs
    readOnly: true
...
volumes:
- name: ingressgateway-certs
secret:
    defaultMode: 420
    optional: true
    secretName: istio-ingressgateway-certs
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;上方代码可以看到，Ingress Gateway 中用可选方式加载了一个名称为 &lt;code&gt;istio-ingressgateway-certs&lt;/code&gt; 的 &lt;code&gt;Secret&lt;/code&gt;，并 Mount 到了 &lt;code&gt;/etc/istio/ingressgateway-ca-certs&lt;/code&gt; 目录之中，这就是上文中要求我们固定 Secret 名称和命名空间的原因。众所周知，&lt;code&gt;tls&lt;/code&gt; 类型的 &lt;code&gt;Secret&lt;/code&gt; 加载后会成为 &lt;code&gt;tls.key&lt;/code&gt; 和 &lt;code&gt;tls.crt&lt;/code&gt; 两个文件，因此在我们的 &lt;code&gt;Gateway&lt;/code&gt; 定义中就使用了 &lt;code&gt;/etc/istio/ingressgateway-certs/tls.crt&lt;/code&gt; 这样的文件名。&lt;/p&gt;

&lt;h2 id=&#34;所有域名都升级为-tls&#34;&gt;所有域名都升级为 tls&lt;/h2&gt;

&lt;p&gt;根据上一节的描写，不难发现按照官方文档，一个 &lt;code&gt;Gateway&lt;/code&gt; 是无法处理两个域名的 https 的：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;tls secret 只能包含一个证书对。&lt;/li&gt;
&lt;li&gt;泛域名证书可以完成这一任务，但因为 Envoy 的限制，这里无法同时使用两个泛域名。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;讨论到这里就很明显了，关键在于如何加载多个证书对，可以修改前面所说的加载指令为加载多个 &lt;code&gt;Secret&lt;/code&gt;，或者干脆换成 &lt;code&gt;Configmap&lt;/code&gt;，当然这样会引起服务中断，&lt;code&gt;Configmap&lt;/code&gt; 用于存放证书也略显粗糙——好在我们还可以换用 &lt;code&gt;Generic&lt;/code&gt; 类型的证书，这里我们可以删除原有 Secret 重新创建 ：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;kubectl delete secret istio-ingressgateway-certs \
    -n istio-system

kubectl create secret generic  \
    istio-ingressgateway-certs \
    -n istio-system \
    --from-file=rocks-crt.pem \
    --from-file=rocks-key.pem \
    --from-file=xyz-crt.pem \
    --from-file=xyz-key.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;接下来改造我们的 &lt;code&gt;Gateway&lt;/code&gt; 定义：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: flask-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 443
      name: https-rocks
      protocol: HTTPS
    tls:
      mode: SIMPLE
      serverCertificate: /etc/istio/ingressgateway-certs/rocks-crt.pem
      privateKey: /etc/istio/ingressgateway-certs/rocks-key.pem
    hosts:
    - &amp;quot;flask.example1.com&amp;quot;
  - port:
      number: 443
      name: https-xyz
      protocol: HTTPS
    tls:
      mode: SIMPLE
      serverCertificate: /etc/istio/ingressgateway-certs/xyz-crt.pem
      privateKey: /etc/istio/ingressgateway-certs/xyz-key.pem
    hosts:
    - &amp;quot;flask.example2.com&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这样一来，我们开放了两个 HTTPS 端口，各自使用不同的证书，分别都可以通过 &lt;code&gt;curl&lt;/code&gt; 命令获得正确结果了。&lt;/p&gt;

&lt;h2 id=&#34;补充&#34;&gt;补充&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;tls.mode&lt;/code&gt; 实际还支持双向和透传两种方式，都可以在流量控制参考中找到相关内容。&lt;/p&gt;

&lt;h2 id=&#34;涉及链接&#34;&gt;涉及链接&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Istio 流量控制参考：&lt;code&gt;https://istio.io/docs/reference/config/istio.networking.v1alpha3/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;用 HTTPS 加密 Gateway：&lt;code&gt;https://istio.io/zh/docs/tasks/traffic-management/secure-ingress/&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&#34;代码&#34;&gt;代码&lt;/h2&gt;

&lt;h3 id=&#34;python-脚本&#34;&gt;Python 脚本&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

from flask import Flask
import os

app = Flask(__name__)

@app.route(&amp;quot;/&amp;quot;)
def hello_world():
    return &amp;quot;Hello, World!&amp;quot;

@app.route(&amp;quot;/version&amp;quot;)
def getversion():
    return os.getenv(&amp;quot;VERSION&amp;quot;)
if __name__ == &amp;quot;__main__&amp;quot;:
    app.run(host=&amp;quot;0.0.0.0&amp;quot;, port=80, debug=True)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;dockerfile&#34;&gt;Dockerfile&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-dockerfile&#34;&gt;FROM alpine
RUN  apk add --update --no-cache python3 &amp;amp;&amp;amp; \
  mkdir /web &amp;amp;&amp;amp; \
  pip3 install Flask
COPY server.py /web
CMD &amp;quot;/web/server.py&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;kubernetes-工作负载&#34;&gt;Kubernetes 工作负载&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: v1
kind: Service
metadata:
  name: flask
  labels:
    app: flask
spec:
  ports:
    - name: http
      port: 80
  selector:
    app: flask
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: flask-v1
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: flask
        version: v1
    spec:
      containers:
        - image: &#39;abc:25000/python-flask-server:v2&#39;
          imagePullPolicy: IfNotPresent
          name: flask
          env:
            - name: VERSION
              value: v1
          ports:
            - containerPort: 80
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: flask-v2
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: flask
        version: v2
    spec:
      containers:
        - image: &#39;abc:25000/python-flask-server:v2&#39;
          imagePullPolicy: IfNotPresent
          name: flask
          env:
            - name: VERSION
              value: v2
          ports:
            - containerPort: 80
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Consul vs Istio</title>
      <link>/post/consul-vs-istio/</link>
      <pubDate>Wed, 11 Jul 2018 19:40:12 +0800</pubDate>
      <guid>/post/consul-vs-istio/</guid>
      <description>&lt;p&gt;原文：&lt;a href=&#34;https://www.consul.io/intro/vs/istio.html&#34; target=&#34;_blank&#34;&gt;Consul vs Istio&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Istio 是一个开源平台，可以为微服务提供连接、管理和加密功能。&lt;/p&gt;

&lt;p&gt;要启用 Istio 的全部功能，必须部署多个服务。控制面包括了 Pilot、Mixer 以及 Citadel 这几个必要组件，数据面的 Envoy Sidecar 也是必不可少的。另外 Istio 需要第三方的服务发现支持，例如 Kubernetes、Consul、Eureka 或者其他别的什么。最后 Istio 需要一个外部系统用来进行存储，通常是 ETCD。换句话说，Istio 需要至少三个独立的服务，以及至少一个分布式系统才算完整。&lt;/p&gt;

&lt;p&gt;Istio 在七层提供了基于路径的路由、流量整形、负载均衡以及遥测功能。Istio 还基于服务认证功能提供了访问控制的支持，能使用七层和四层的属性对访问、路由进行控制。&lt;/p&gt;

&lt;p&gt;Consul 是一个单一的二进制文件，同时提供了服务器和客户端的能力，并自带全部的服务发现、配置、TLS、认证等功能。无需安装额外的系统即可使用，同时还为 Vault 之类的外部系统提供了可选支持，从而进行功能扩展。这一架构让 Consul 能够轻松的安装在任何平台上，也包括物理机。&lt;/p&gt;

&lt;p&gt;Consule 是一个基于 Agent 的模型，集群中的每个节点都需要运行一个 Consul 客户端。客户端软件管理一个本地缓存，缓存的数据来源于服务器。无需任何外部通信，所有的加密服务通信 API 都能在几毫秒的时间内进行响应。这样我们的连接过程发生在边缘，无需和中央服务器进行通信。Istio 将请求流入位于中央的 Mixer 服务，而数据的推送过程又必须由 Pilot 完成。这种机制极大的降低了 Istio 的稳定性，而 Consul 却能够在边缘高效的完成数据更新的分发以及其他工作。&lt;/p&gt;

&lt;p&gt;Consul 的数据面是可插接的。它包含了一个内置的代理服务器，这一服务牺牲了较多性能，换来易用性的提升。用户也可以使用 Envoy 这样的第三方代理。不同的任务会有各自合适的代理，Consul 就提供了这种能力，从而能够支持复杂多样的应用部署。&lt;/p&gt;

&lt;p&gt;除了第三方代理支持，应用可以直接和 Connect 协议进行集成。这样一来，引入 Connect 的开销就可以忽略不计了。任何其他的 Connect 支持的应用，不管使用代理或者 Connect 原生方式，都具备互联互通的能力。&lt;/p&gt;

&lt;p&gt;Consul 只在四层实现了认证和鉴权——TLS 连接是否能够建立。我们认为服务认证应该留在四层，七层要做的事情是路由、遥测等事情。我们鼓励用户借助我们的可插接数据面，为集群所需要的七层功能选择合适的代理服务器。Consul 会在未来加入更多七层特性。&lt;/p&gt;

&lt;p&gt;Consul 实现了自动的 TLS 认证管理，并且提供了完整的轮转支持。即使是一个大型的 Consul 集群中，也能够在无中断的情况下实现自动轮转。认证管理系统也是可插接的，目前通过代码集成在 Consul 中，很快我们会将其剥离成为外部插件。这就 Consul 就有了和任意 PKI 方案协同工作的能力。&lt;/p&gt;

&lt;p&gt;因为 Consul 的服务连接能力（”Connect“）是内置的，他也具备和 Consul 一样的稳定性。2014 年以来，Consule 就在大型企业的生产环境中工作，目前已经有单集群部署 50000 节点的规模。&lt;/p&gt;

&lt;p&gt;这一比较基于我们自己对 Istio 的有限认识，以及和 Istio 用户的交流。如果读者认为其中有不实之处，请点击 &lt;a href=&#34;https://github.com/hashicorp/consul/blob/master/website/source/intro/vs/istio.html.md&#34; target=&#34;_blank&#34;&gt;Edit this page&lt;/a&gt; 提交修改建议。我们会尽快对读者意见进行审核和更新，希望以此来保证本文的准确性。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Conduit 0.5 发布 —— 以及 R.I.P. Conduit</title>
      <link>/post/rip-conduit/</link>
      <pubDate>Sat, 07 Jul 2018 09:20:04 +0800</pubDate>
      <guid>/post/rip-conduit/</guid>
      <description>&lt;p&gt;7 月 6 日，Linkerd 博客再次更新，宣布 Conduit 0.5 发布：在翻炒了无数次 Prometheus 支持的冷饭之后，终于发布了新的功能 —— TLS 支持。&lt;/p&gt;

&lt;p&gt;紧接着一个更加重磅的消息：&lt;strong&gt;0.5 将是 Conduit 最后一个版本，未来将作为 Linkerd 2.0 的基础继续存在&lt;/strong&gt; - Conduit 的 Github 项目将会转移为 Linkerd2。&lt;/p&gt;

&lt;p&gt;回想一下，2017 年 12 月 5 日发布到现在的两百多天里，一共发布了 13 个版本、9 篇文档以及 12 篇博客。大致完成了 Conduit 问世之初的承诺：轻量、快速以及 Service Mesh 该有的种种功能；然而很可惜，第一篇 Conduit 博客中还提到了一点：“Conduit is not Linkerd 2.0. ”。这一次“战略性转移”，也印证了之前大家的担心——如果自身投入不足，又不能有效持续制造焦点、获取社区的持续关注和支持，先驱就变成先烈了。&lt;/p&gt;

&lt;p&gt;Service Mesh 的鏖战尚未开始，已经有人出局了，R.I.P. Conduit。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>HTTP Egress 流量的监控和访问策略管理</title>
      <link>/post/egress-monitoring-access-control/</link>
      <pubDate>Sat, 23 Jun 2018 10:48:57 +0800</pubDate>
      <guid>/post/egress-monitoring-access-control/</guid>
      <description>

&lt;p&gt;原文：&lt;a href=&#34;https://istio.io/blog/2018/egress-monitoring-access-control/&#34; target=&#34;_blank&#34;&gt;Monitoring and Access Policies for HTTP Egress Traffic&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;作者：VADIM EISENBERG 和 RONEN SCHAFFER&lt;/p&gt;

&lt;p&gt;Istio 的主要功能就是在服务网格内部管理微服务之间的通信，除此之外，Istio 还能对 Ingress（从外部进入网格） 和 Egress（从网格发出到外部） 流量进行管理。不管是网格内部流量，还是 Ingress 或者 Egress 流量，Istio 都能够在其中进行访问策略的控制，并完成遥测数据的聚合工作。&lt;/p&gt;

&lt;p&gt;本文中我们会展示如何使用 Istio 在 HTTP Egress 流量中实施监控和访问策略控制。文中谈到的内容针对 &lt;a href=&#34;https://github.com/istio/istio/releases/tag/0.8.0&#34; target=&#34;_blank&#34;&gt;Istio 0.8.0&lt;/a&gt; 及以上是有效的。&lt;/p&gt;

&lt;h1 id=&#34;用例&#34;&gt;用例&lt;/h1&gt;

&lt;p&gt;假设一个组织正在运行的应用需要处理来自于 &lt;code&gt;cnn.com&lt;/code&gt; 的内容。这些应用已经被解构为部署在 Istio 服务网格中的微服务。这些应用要获取 &lt;code&gt;cnn.com&lt;/code&gt; 多个频道的内容：&lt;a href=&#34;https://edition.cnn.com/politics&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/politics&lt;/a&gt;、&lt;a href=&#34;https://edition.cnn.com/sport&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/sport&lt;/a&gt; 以及 &lt;a href=&#34;https://edition.cnn.com/health&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/health&lt;/a&gt;。目前已经&lt;a href=&#34;https://istio.io/docs/tasks/traffic-management/egress-tls-origination/&#34; target=&#34;_blank&#34;&gt;配置 Istio 使其允许访问 &lt;code&gt;edition.cnn.com&lt;/code&gt;&lt;/a&gt;，一切运行良好。然而在某一天，他们决定限制政治方面的内容，技术上讲，就是要阻止对 &lt;a href=&#34;https://edition.cnn.com/politics&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/politics&lt;/a&gt; 的访问，继续允许对 &lt;a href=&#34;https://edition.cnn.com/sport&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/sport&lt;/a&gt; 以及 &lt;a href=&#34;https://edition.cnn.com/health&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/health&lt;/a&gt; 的访问。对 &lt;a href=&#34;https://edition.cnn.com/politics&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/politics&lt;/a&gt; 的访问需要在应用程序、命名空间以及用户的不同粒度上进行访问控制。&lt;/p&gt;

&lt;p&gt;要实现这个目标，运维人员需要监控对外部服务的访问，并分析 Istio 日志来确保对 &lt;a href=&#34;https://edition.cnn.com/politics&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/politics&lt;/a&gt; 的访问都是经过授权的。另外他们还要配置 Istio，让 Istio 自动阻止对 &lt;a href=&#34;https://edition.cnn.com/politics&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/politics&lt;/a&gt; 的（未授权）访问。&lt;/p&gt;

&lt;p&gt;该组织决定防止对新策略发生篡改，通过技术手段执行策略，防止恶意应用访问受限内容。&lt;/p&gt;

&lt;h2 id=&#34;相关任务&#34;&gt;相关任务&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://istio.io/docs/tasks/traffic-management/egress/&#34; target=&#34;_blank&#34;&gt;Egress 流量控制&lt;/a&gt;：网格内应用对（Kubernetes 集群）外部的 HTTP 和 HTTPS 服务的访问方式。&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://istio.io/docs/tasks/traffic-management/egress-tls-origination/&#34; target=&#34;_blank&#34;&gt;TLS 方式访问 Egress 流量&lt;/a&gt;：内部应用使用 HTTP 协议访问需要 HTTPS 的外部服务的能力。&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://istio.io/docs/tasks/traffic-management/egress-gateway/&#34; target=&#34;_blank&#34;&gt;配置 Egress Gateway&lt;/a&gt; ：如何配置 Istio 令其使用独立的 &lt;code&gt;egress gateway&lt;/code&gt; 网关服务来发送 Egress 流量。&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://istio.io/docs/tasks/telemetry/metrics-logs/&#34; target=&#34;_blank&#34;&gt;收集指标和日志&lt;/a&gt;：为网格中的服务配置指标和日志。&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://istio.io/docs/tasks/telemetry/using-istio-dashboard/&#34; target=&#34;_blank&#34;&gt;使用 Grafana 进行指标可视化&lt;/a&gt;：Istio Dashboard 在网格流量监控方面的作用。&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://istio.io/docs/tasks/security/basic-access-control/&#34; target=&#34;_blank&#34;&gt;基础访问控制&lt;/a&gt;：网格内服务的访问控制问题。&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://istio.io/docs/tasks/security/secure-access-control/&#34; target=&#34;_blank&#34;&gt;安全访问控制&lt;/a&gt;：如何使用黑名单和白名单配置访问策略。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;和上面列出的任务不同，本文讲述的是 Istio 对 Egress 流量的监控和访问策略。&lt;/p&gt;

&lt;h2 id=&#34;开始之前&#34;&gt;开始之前&lt;/h2&gt;

&lt;p&gt;依照 &lt;a href=&#34;https://istio.io/docs/tasks/traffic-management/egress-gateway/#perform-tls-origination-with-the-egress-gateway&#34; target=&#34;_blank&#34;&gt;配置 Egress Gateway，使用 Egress Gateway 执行 TLS 访问&lt;/a&gt; 任务中的步骤，不要执行&lt;a href=&#34;https://istio.io/docs/tasks/traffic-management/egress-gateway/#cleanup&#34; target=&#34;_blank&#34;&gt;清理&lt;/a&gt;操作。完成之后，就可在网格之内使用安装了 &lt;code&gt;curl&lt;/code&gt; 的容器来访问  &lt;a href=&#34;https://edition.cnn.com/politics&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/politics&lt;/a&gt; 了。下面的内容中，我们假设名为 &lt;code&gt;SOURCE_POD&lt;/code&gt; 的环境变量中包含了 Pod 名称。&lt;/p&gt;

&lt;h2 id=&#34;配置监控和访问策略&#34;&gt;配置监控和访问策略&lt;/h2&gt;

&lt;p&gt;既然要用安全方式来完成任务，就需要通过 &lt;code&gt;egress gateway&lt;/code&gt; 来进行 egress 传输，这部分内容在 &lt;a href=&#34;https://istio.io/docs/tasks/traffic-management/egress-gateway/&#34; target=&#34;_blank&#34;&gt;配置 Egress Gateway&lt;/a&gt; 中有详细描述。这里所谓的安全方式指的是防止恶意应用绕过 Istio 监控和策略管理进行未经授权的访问。&lt;/p&gt;

&lt;p&gt;我们的场景中，该组织执行了上一节“开始之前”的步骤。这个步骤完成后，开放了对 &lt;code&gt;edition.cnn.com&lt;/code&gt; 的访问，并且配置了响应的 Egress Gateway。现在可以对 &lt;code&gt;edition.cnn.com&lt;/code&gt; 进行监控和策略进行配置了。&lt;/p&gt;

&lt;h3 id=&#34;日志&#34;&gt;日志&lt;/h3&gt;

&lt;p&gt;首先配置一下对 &lt;code&gt;*.cnn.com&lt;/code&gt; 的记录。创建一个 &lt;code&gt;logentry&lt;/code&gt; 和两个 &lt;a href=&#34;https://istio.io/docs/reference/config/policy-and-telemetry/adapters/stdio/&#34; target=&#34;_blank&#34;&gt;stdio&lt;/a&gt; 类型的 &lt;code&gt;handler&lt;/code&gt;，其中一个用 &lt;code&gt;error&lt;/code&gt; 级别的日志来记录受限的访问，另外一个用 &lt;code&gt;info&lt;/code&gt; 级别来记录所有到 &lt;code&gt;*.cnn.com&lt;/code&gt; 的访问。接下来创建 &lt;code&gt;rules&lt;/code&gt; 把 &lt;code&gt;logentry&lt;/code&gt; 定向到 &lt;code&gt;handler&lt;/code&gt; 上。对 &lt;code&gt;*.cnn.com/politics&lt;/code&gt; 的访问会被指派给受限访问的规则，剩余的访问则会被另一条规则接收。要理解 Istio 的 &lt;code&gt;logentries&lt;/code&gt;、&lt;code&gt;rules&lt;/code&gt; 以及 &lt;code&gt;handlers&lt;/code&gt;，可以阅读 &lt;a href=&#34;https://istio.io/blog/2017/adapter-model/&#34; target=&#34;_blank&#34;&gt;Istio Adaper Model&lt;/a&gt; 一文。下面的示意图中包含了刚才讲到的这些实体和依赖关系：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;img/egress-adapters-monitoring-policy.svg&#34; alt=&#34;用于监控 Egress 的 Instance、Rules 以及 Handlers&#34; /&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;创建 &lt;code&gt;logentries&lt;/code&gt;、&lt;code&gt;rules&lt;/code&gt; 以及 &lt;code&gt;handlers&lt;/code&gt;：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;# egress 访问的日志条目
apiVersion: &amp;quot;config.istio.io/v1alpha2&amp;quot;
kind: logentry
metadata:
name: egress-access
namespace: istio-system
spec:
severity: &#39;&amp;quot;info&amp;quot;&#39;
timestamp: request.time
variables:
destination: request.host | &amp;quot;unknown&amp;quot;
path: request.path | &amp;quot;unknown&amp;quot;
source: source.labels[&amp;quot;app&amp;quot;] | source.service | &amp;quot;unknown&amp;quot;
sourceNamespace: source.namespace | &amp;quot;unknown&amp;quot;
user: source.user | &amp;quot;unknown&amp;quot;
responseCode: response.code | 0
responseSize: response.size | 0
monitored_resource_type: &#39;&amp;quot;UNSPECIFIED&amp;quot;&#39;
---
# Handler for error egress access entries
apiVersion: &amp;quot;config.istio.io/v1alpha2&amp;quot;
kind: stdio
metadata:
name: egress-error-logger
namespace: istio-system
spec:
severity_levels:
info: 2 # 输出级别为 error
outputAsJson: true
---
# 访问 *.cnn.com/politics 的规则
apiVersion: &amp;quot;config.istio.io/v1alpha2&amp;quot;
kind: rule
metadata:
name: handle-politics
namespace: istio-system
spec:
match: request.host.endsWith(&amp;quot;cnn.com&amp;quot;) &amp;amp;&amp;amp; request.path.startsWith(&amp;quot;/politics&amp;quot;)
actions:
- handler: egress-error-logger.stdio
instances:
- egress-access.logentry
---
# Info 级别的 Egress 日志
apiVersion: &amp;quot;config.istio.io/v1alpha2&amp;quot;
kind: stdio
metadata:
name: egress-access-logger
namespace: istio-system
spec:
severity_levels:
info: 0 # 输出为 Info 级别
outputAsJson: true
---
# 访问 *.cnn.com 的规则
apiVersion: &amp;quot;config.istio.io/v1alpha2&amp;quot;
kind: rule
metadata:
name: handle-cnn-access
namespace: istio-system
spec:
match: request.host.endsWith(&amp;quot;.cnn.com&amp;quot;)
actions:
- handler: egress-access-logger.stdio
instances:
- egress-access.logentry
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;分别向 &lt;a href=&#34;https://edition.cnn.com/politics&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/politics&lt;/a&gt;、&lt;a href=&#34;https://edition.cnn.com/sport&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/sport&lt;/a&gt; 发送请求，所有请求都应该返回 &lt;code&gt;200 OK&lt;/code&gt;。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl exec -it $SOURCE_POD -c sleep -- bash -c &#39;curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/politics; curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/sport; curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/health&#39;
200
200
200
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;查询 Mixer 的日志，查看日志中出现的请求信息：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;kubectl -n istio-system logs $(kubectl -n istio-system get pods -l istio-mixer-type=telemetry -o jsonpath=&#39;{.items[0].metadata.name}&#39;) mixer | grep egress-access | grep cnn | tail -4
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;返回如下信息：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{&amp;quot;level&amp;quot;:&amp;quot;info&amp;quot;,&amp;quot;time&amp;quot;:&amp;quot;2018-06-18T13:22:58.317448Z&amp;quot;,&amp;quot;instance&amp;quot;:&amp;quot;egress-access.logentry.istio-system&amp;quot;,&amp;quot;destination&amp;quot;:&amp;quot;edition.cnn.com&amp;quot;,&amp;quot;path&amp;quot;:&amp;quot;/politics&amp;quot;,&amp;quot;responseCode&amp;quot;:200,&amp;quot;responseSize&amp;quot;:150448,&amp;quot;source&amp;quot;:&amp;quot;sleep&amp;quot;,&amp;quot;user&amp;quot;:&amp;quot;unknown&amp;quot;}
{&amp;quot;level&amp;quot;:&amp;quot;error&amp;quot;,&amp;quot;time&amp;quot;:&amp;quot;2018-06-18T13:22:58.317448Z&amp;quot;,&amp;quot;instance&amp;quot;:&amp;quot;egress-access.logentry.istio-system&amp;quot;,&amp;quot;destination&amp;quot;:&amp;quot;edition.cnn.com&amp;quot;,&amp;quot;path&amp;quot;:&amp;quot;/politics&amp;quot;,&amp;quot;responseCode&amp;quot;:200,&amp;quot;responseSize&amp;quot;:150448,&amp;quot;source&amp;quot;:&amp;quot;sleep&amp;quot;,&amp;quot;user&amp;quot;:&amp;quot;unknown&amp;quot;}
{&amp;quot;level&amp;quot;:&amp;quot;error&amp;quot;,&amp;quot;time&amp;quot;:&amp;quot;2018-06-18T13:22:58.317448Z&amp;quot;,&amp;quot;instance&amp;quot;:&amp;quot;egress-access.logentry.istio-system&amp;quot;,&amp;quot;destination&amp;quot;:&amp;quot;edition.cnn.com&amp;quot;,&amp;quot;path&amp;quot;:&amp;quot;/politics&amp;quot;,&amp;quot;responseCode&amp;quot;:200,&amp;quot;responseSize&amp;quot;:150448,&amp;quot;source&amp;quot;:&amp;quot;sleep&amp;quot;,&amp;quot;user&amp;quot;:&amp;quot;unknown&amp;quot;}
{&amp;quot;level&amp;quot;:&amp;quot;info&amp;quot;,&amp;quot;time&amp;quot;:&amp;quot;2018-06-18T13:22:59.354943Z&amp;quot;,&amp;quot;instance&amp;quot;:&amp;quot;egress-access.logentry.istio-system&amp;quot;,&amp;quot;destination&amp;quot;:&amp;quot;edition.cnn.com&amp;quot;,&amp;quot;path&amp;quot;:&amp;quot;/health&amp;quot;,&amp;quot;responseCode&amp;quot;:200,&amp;quot;responseSize&amp;quot;:332218,&amp;quot;source&amp;quot;:&amp;quot;sleep&amp;quot;,&amp;quot;user&amp;quot;:&amp;quot;unknown&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;会看到关于三个请求的四条日志。三个 &lt;code&gt;info&lt;/code&gt; 级别的条目是关于 &lt;code&gt;edition.cnn.com&lt;/code&gt; 的，一条 &lt;code&gt;error&lt;/code&gt; 级别的条目就是关于 &lt;code&gt;edition.cnn.com/politics&lt;/code&gt; 的访问。服务网格的运维人员能看到所有的访问情况，并且也能通过对 &lt;code&gt;error&lt;/code&gt; 日志的搜索来查找受限访问。这是在禁止访问之前的第一个监控措施，把所有受限访问都作为错误记录下来，在某些情况下，这就足够安全了。&lt;/p&gt;

&lt;h3 id=&#34;利用路由进行访问控制&#34;&gt;利用路由进行访问控制&lt;/h3&gt;

&lt;p&gt;在启动对 &lt;code&gt;edition.cnn.com&lt;/code&gt; 的访问日志之后，自动启动了一个访问策略，只允许访问 &lt;code&gt;/health&lt;/code&gt; 和 &lt;code&gt;/sport&lt;/code&gt; URL。这样简单的策略控制可以用 Istio 路由来实现。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;重新定义 &lt;code&gt;edition.cnn.com&lt;/code&gt; 的 &lt;code&gt;VirtualService&lt;/code&gt;：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: direct-through-egress-gateway
spec:
hosts:
- edition.cnn.com
gateways:
- istio-egressgateway
- mesh
http:
- match:
- gateways:
  - mesh
  port: 80
route:
- destination:
    host: istio-egressgateway.istio-system.svc.cluster.local
    port:
      number: 443
  weight: 100
- match:
- gateways:
  - istio-egressgateway
  port: 443
  uri:
    regex: &amp;quot;^.health|^.sport&amp;quot;
route:
- destination:
    host: edition.cnn.com
    port:
      number: 443
  weight: 100
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;注意这里加入了一个针对 &lt;code&gt;uri&lt;/code&gt; 的 &lt;code&gt;match&lt;/code&gt; 条件，会检查 URL 路径是不是 &lt;code&gt;/health&lt;/code&gt; 或者 &lt;code&gt;/sport&lt;/code&gt;。另外还要注意的是，这个条件是加入到 &lt;code&gt;VirtualService&lt;/code&gt; 的 &lt;code&gt;istio-egressgateway&lt;/code&gt; 部分，egress gateway 是一个需要注意安全的组件（参见 &lt;a href=&#34;https://istio.io/docs/tasks/traffic-management/egress-gateway/#additional-security-considerations&#34; target=&#34;_blank&#34;&gt;Egress Gateway 的安全考量&lt;/a&gt;），应该慎重对待其安全性，防止影响后续的策略实施过程。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;再次发送之前的三个 HTTP 请求：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl exec -it $SOURCE_POD -c sleep -- bash -c &#39;curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/politics; curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/sport; curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/health&#39;
404
200
200
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;会看到 &lt;a href=&#34;https://edition.cnn.com/politics&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/politics&lt;/a&gt; 返回了 &lt;code&gt;404 Not Found&lt;/code&gt;，&lt;a href=&#34;https://edition.cnn.com/sport&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/sport&lt;/a&gt; 和 &lt;a href=&#34;https://edition.cnn.com/health&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/health&lt;/a&gt; 都返回了 200。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;VirtualService&lt;/code&gt; 的传播和生效可能需要几秒钟的等待。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;查询 Mixer 日志，看看刚才发生的请求在日志中的体现：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;kubectl -n istio-system logs $(kubectl -n istio-system get pods -l istio-mixer-type=telemetry -o jsonpath=&#39;{.items[0].metadata.name}&#39;) mixer | grep egress-access | grep cnn | tail -4
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;得到结果如下：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{&amp;quot;level&amp;quot;:&amp;quot;info&amp;quot;,&amp;quot;time&amp;quot;:&amp;quot;2018-06-19T12:39:48.050666Z&amp;quot;,&amp;quot;instance&amp;quot;:&amp;quot;egress-access.logentry.istio-system&amp;quot;,&amp;quot;destination&amp;quot;:&amp;quot;edition.cnn.com&amp;quot;,&amp;quot;path&amp;quot;:&amp;quot;/politics&amp;quot;,&amp;quot;responseCode&amp;quot;:404,&amp;quot;responseSize&amp;quot;:0,&amp;quot;source&amp;quot;:&amp;quot;sleep&amp;quot;,&amp;quot;sourceNamespace&amp;quot;:&amp;quot;default&amp;quot;,&amp;quot;user&amp;quot;:&amp;quot;unknown&amp;quot;}
{&amp;quot;level&amp;quot;:&amp;quot;error&amp;quot;,&amp;quot;time&amp;quot;:&amp;quot;2018-06-19T12:39:48.050666Z&amp;quot;,&amp;quot;instance&amp;quot;:&amp;quot;egress-access.logentry.istio-system&amp;quot;,&amp;quot;destination&amp;quot;:&amp;quot;edition.cnn.com&amp;quot;,&amp;quot;path&amp;quot;:&amp;quot;/politics&amp;quot;,&amp;quot;responseCode&amp;quot;:404,&amp;quot;responseSize&amp;quot;:0,&amp;quot;source&amp;quot;:&amp;quot;sleep&amp;quot;,&amp;quot;sourceNamespace&amp;quot;:&amp;quot;default&amp;quot;,&amp;quot;user&amp;quot;:&amp;quot;unknown&amp;quot;}
{&amp;quot;level&amp;quot;:&amp;quot;info&amp;quot;,&amp;quot;time&amp;quot;:&amp;quot;2018-06-19T12:39:48.091268Z&amp;quot;,&amp;quot;instance&amp;quot;:&amp;quot;egress-access.logentry.istio-system&amp;quot;,&amp;quot;destination&amp;quot;:&amp;quot;edition.cnn.com&amp;quot;,&amp;quot;path&amp;quot;:&amp;quot;/health&amp;quot;,&amp;quot;responseCode&amp;quot;:200,&amp;quot;responseSize&amp;quot;:334027,&amp;quot;source&amp;quot;:&amp;quot;sleep&amp;quot;,&amp;quot;sourceNamespace&amp;quot;:&amp;quot;default&amp;quot;,&amp;quot;user&amp;quot;:&amp;quot;unknown&amp;quot;}
{&amp;quot;level&amp;quot;:&amp;quot;info&amp;quot;,&amp;quot;time&amp;quot;:&amp;quot;2018-06-19T12:39:48.063812Z&amp;quot;,&amp;quot;instance&amp;quot;:&amp;quot;egress-access.logentry.istio-system&amp;quot;,&amp;quot;destination&amp;quot;:&amp;quot;edition.cnn.com&amp;quot;,&amp;quot;path&amp;quot;:&amp;quot;/sport&amp;quot;,&amp;quot;responseCode&amp;quot;:200,&amp;quot;responseSize&amp;quot;:355267,&amp;quot;source&amp;quot;:&amp;quot;sleep&amp;quot;,&amp;quot;sourceNamespace&amp;quot;:&amp;quot;default&amp;quot;,&amp;quot;user&amp;quot;:&amp;quot;unknown&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这里还能看到 &lt;a href=&#34;https://edition.cnn.com/politics&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/politics&lt;/a&gt; 的访问日志，只不过这次的 &lt;code&gt;responseCode&lt;/code&gt; 是 &lt;code&gt;404&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;使用 Istio 路由之后，我们成功的实现了初步的访问控制，但是如果是更复杂的需要，这种程度还是不够的。例如希望允许特定条件下对 &lt;a href=&#34;https://edition.cnn.com/politics&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/politics&lt;/a&gt; 的访问，这需要一些更复杂的策略，只判断 URL 是不够的。这就需要 &lt;a href=&#34;https://istio.io/blog/2017/adapter-model/&#34; target=&#34;_blank&#34;&gt;Istio Mixer Adapter&lt;/a&gt;，（例如&lt;a href=&#34;https://istio.io/docs/tasks/security/basic-access-control/#access-control-using-whitelists&#34; target=&#34;_blank&#34;&gt;白名单&lt;/a&gt;和&lt;a href=&#34;https://istio.io/docs/tasks/security/basic-access-control/#access-control-using-denials&#34; target=&#34;_blank&#34;&gt;黑名单&lt;/a&gt;）的协助，来协助控制对 URL 路径的允许和禁止行为。借 [Policy Rules] 的帮助，这样就可以使用 &lt;a href=&#34;https://istio.io/docs/reference/config/policy-and-telemetry/expression-language/&#34; target=&#34;_blank&#34;&gt;Istio expression language&lt;/a&gt; 来实现复杂条件的定义，完成包含逻辑控制在内的复杂限制了。这些规则可以在日志和策略检查之间进行复用。另外还可以使用 &lt;a href=&#34;https://istio.io/docs/concepts/security/rbac/&#34; target=&#34;_blank&#34;&gt;Istio RBAC&lt;/a&gt;进行更复杂的控制。&lt;/p&gt;

&lt;p&gt;还有一个额外的需要就是和远程访问策略系统进行集成。如果用例中设计的组织已经有使用一些 &lt;a href=&#34;https://en.wikipedia.org/wiki/Identity_management&#34; target=&#34;_blank&#34;&gt;认证和访问管理系统&lt;/a&gt;，可能会需要配置 Istio 从这些系统中获取访问策略方面的信息。可以通过实现 &lt;a href=&#34;https://istio.io/blog/2017/adapter-model/&#34; target=&#34;_blank&#34;&gt;Istio Mixer Adapter&lt;/a&gt; 的方式来进行集成。&lt;/p&gt;

&lt;p&gt;取消掉前面我们使用路由规则实现的访问控制，接下来使用 Mixer 策略来实现。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;用之前的 &lt;a href=&#34;https://istio.io/docs/tasks/traffic-management/egress-gateway/#perform-tls-origination-with-the-egress-gateway&#34; target=&#34;_blank&#34;&gt;Configure an Egress Gateway&lt;/a&gt; 中的版本替换 &lt;code&gt;edition.cnn.com&lt;/code&gt; 的 &lt;code&gt;VertualService&lt;/code&gt;：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: direct-through-egress-gateway
spec:
hosts:
- edition.cnn.com
gateways:
- istio-egressgateway
- mesh
http:
- match:
- gateways:
  - mesh
  port: 80
route:
- destination:
    host: istio-egressgateway.istio-system.svc.cluster.local
    port:
      number: 443
  weight: 100
- match:
- gateways:
  - istio-egressgateway
  port: 443
route:
- destination:
    host: edition.cnn.com
    port:
      number: 443
  weight: 100
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;再次发送之前的三个到 &lt;code&gt;cnn.com&lt;/code&gt; 的请求，这里会看到三个 200 的成功返回：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl exec -it $SOURCE_POD -c sleep -- bash -c &#39;curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/politics; curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/sport; curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/health&#39;
200
200
200
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;VirtualService&lt;/code&gt; 的传播和生效可能需要几秒钟的等待。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;使用-mixer-策略进行访问控制&#34;&gt;使用 Mixer 策略进行访问控制&lt;/h3&gt;

&lt;p&gt;这一步中，我们使用 &lt;a href=&#34;https://istio.io/docs/reference/config/policy-and-telemetry/adapters/list/&#34; target=&#34;_blank&#34;&gt;Listchecker adapter&lt;/a&gt;，这是白名单的一个变体。用一个静态 URL 列表定义一个 &lt;code&gt;listentry&lt;/code&gt;，然后在 &lt;code&gt;listchecker&lt;/code&gt; 中用 &lt;code&gt;overrides&lt;/code&gt; 字段进行检查。如果有外部的 &lt;a href=&#34;https://en.wikipedia.org/wiki/Identity_management&#34; target=&#34;_blank&#34;&gt;认证和访问管理系统&lt;/a&gt;，可以使用 &lt;code&gt;providerurl&lt;/code&gt; 字段取而代之。下面图示显示了更新之后的 对象关系。注意这里复用了同样的策略，&lt;code&gt;handle-cnn-access&lt;/code&gt; 对日志和访问策略同样生效。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;img/egress-adapters-monitoring-policy.svg&#34; alt=&#34;Egress 监控和访问策略使用的 Instance、Rule 和 Handler&#34; /&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;定义 &lt;code&gt;path-checker&lt;/code&gt; 以及 &lt;code&gt;request-path&lt;/code&gt;：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: &amp;quot;config.istio.io/v1alpha2&amp;quot;
kind: listchecker
metadata:
name: path-checker
namespace: istio-system
spec:
overrides: [&amp;quot;/health&amp;quot;, &amp;quot;/sport&amp;quot;]  # 提供一个静态列表
blacklist: false
---
apiVersion: &amp;quot;config.istio.io/v1alpha2&amp;quot;
kind: listentry
metadata:
name: request-path
namespace: istio-system
spec:
value: request.path
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;修改 &lt;code&gt;handle-cnn-access&lt;/code&gt; 规则，要求将 &lt;code&gt;request-path&lt;/code&gt; 发送给 &lt;code&gt;path-checker&lt;/code&gt;：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;# 访问 cnn.com egress 的规则
apiVersion: &amp;quot;config.istio.io/v1alpha2&amp;quot;
kind: rule
metadata:
name: handle-cnn-access
namespace: istio-system
spec:
match: request.host.endsWith(&amp;quot;.cnn.com&amp;quot;)
actions:
- handler: egress-access-logger.stdio
instances:
  - egress-access.logentry
- handler: path-checker.listchecker
instances:
  - request-path.listentry
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;再次执行 curl 指令，发现 &lt;a href=&#34;http://edition.cnn.com/politics&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/politics&lt;/a&gt; 返回了 404：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl exec -it $SOURCE_POD -c sleep -- bash -c &#39;curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/politics; curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/sport; curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/health&#39;
404
200
200
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;使用-mixer-策略进行访问控制-续&#34;&gt;使用 Mixer 策略进行访问控制（续）&lt;/h3&gt;

&lt;p&gt;在前面我们配置了日志和访问控制之后，新增一个需要就是允许在 &lt;code&gt;policics&lt;/code&gt; 命名空间内的应用能够访问 &lt;code&gt;cnn.com&lt;/code&gt; 的所有内容，并且不受监控。接下来我们在 Istio 中进行配置，完成这一要求。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;创建 &lt;code&gt;polictics&lt;/code&gt; 命名空间&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl create namespace politics
namespace &amp;quot;politics&amp;quot; created
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;在 &lt;code&gt;polictics&lt;/code&gt; 命名空间中启动 &lt;a href=&#34;https://github.com/istio/istio/tree/release-0.8/samples/sleep&#34; target=&#34;_blank&#34;&gt;sleep&lt;/a&gt;。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;如果使用了 &lt;a href=&#34;https://istio.io/docs/setup/kubernetes/sidecar-injection/#automatic-sidecar-injection&#34; target=&#34;_blank&#34;&gt;自动注入 Sidecar&lt;/a&gt;，执行：&lt;code&gt;$ kubectl apply -n politics -f samples/sleep/sleep.yaml&lt;/code&gt;，否则，就需要进行注入了：&lt;code&gt;kubectl apply -n politics -f &amp;lt;(istioctl kube-inject -f samples/sleep/sleep.yaml)&lt;/code&gt;。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;预备使用 &lt;code&gt;policics&lt;/code&gt; 命名空间中的 &lt;code&gt;sleep&lt;/code&gt; pod 来发送请求，这里定义一个环境变量来保存 Pod 名称。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;export SOURCE_POD_IN_POLITICS=$(kubectl get pod -n politics -l app=sleep -o jsonpath={.items..metadata.name})
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;这次从新的 Pod（&lt;code&gt;$SOURCE_POD_IN_POLITICS&lt;/code&gt;）中发送刚才的请求。因为我们还没有给新的命名空间中的应用设置例外，&lt;a href=&#34;http://edition.cnn.com/politics&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/politics&lt;/a&gt; 还是返回了 404。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl exec -it $SOURCE_POD_IN_POLITICS -n politics -c sleep -- bash -c &#39;curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/politics; curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/sport; curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/health&#39;
404
200
200
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;查询 Mixer 日志，会看到来自 &lt;code&gt;politics&lt;/code&gt; 命名空间的访问记录：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;kubectl -n istio-system logs $(kubectl -n istio-system get pods -l istio-mixer-type=telemetry -o jsonpath=&#39;{.items[0].metadata.name}&#39;) mixer | grep egress-access | grep cnn | tail -4
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;查询结果：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{&amp;quot;level&amp;quot;:&amp;quot;info&amp;quot;,&amp;quot;time&amp;quot;:&amp;quot;2018-06-19T17:37:14.639102Z&amp;quot;,&amp;quot;instance&amp;quot;:&amp;quot;egress-access.logentry.istio-system&amp;quot;,&amp;quot;destination&amp;quot;:&amp;quot;edition.cnn.com&amp;quot;,&amp;quot;path&amp;quot;:&amp;quot;/politics&amp;quot;,&amp;quot;responseCode&amp;quot;:404,&amp;quot;responseSize&amp;quot;:76,&amp;quot;source&amp;quot;:&amp;quot;sleep&amp;quot;,&amp;quot;sourceNamespace&amp;quot;:&amp;quot;politics&amp;quot;,&amp;quot;user&amp;quot;:&amp;quot;unknown&amp;quot;}
{&amp;quot;level&amp;quot;:&amp;quot;error&amp;quot;,&amp;quot;time&amp;quot;:&amp;quot;2018-06-19T17:37:14.639102Z&amp;quot;,&amp;quot;instance&amp;quot;:&amp;quot;egress-access.logentry.istio-system&amp;quot;,&amp;quot;destination&amp;quot;:&amp;quot;edition.cnn.com&amp;quot;,&amp;quot;path&amp;quot;:&amp;quot;/politics&amp;quot;,&amp;quot;responseCode&amp;quot;:404,&amp;quot;responseSize&amp;quot;:76,&amp;quot;source&amp;quot;:&amp;quot;sleep&amp;quot;,&amp;quot;sourceNamespace&amp;quot;:&amp;quot;politics&amp;quot;,&amp;quot;user&amp;quot;:&amp;quot;unknown&amp;quot;}
{&amp;quot;level&amp;quot;:&amp;quot;info&amp;quot;,&amp;quot;time&amp;quot;:&amp;quot;2018-06-19T17:37:14.653225Z&amp;quot;,&amp;quot;instance&amp;quot;:&amp;quot;egress-access.logentry.istio-system&amp;quot;,&amp;quot;destination&amp;quot;:&amp;quot;edition.cnn.com&amp;quot;,&amp;quot;path&amp;quot;:&amp;quot;/sport&amp;quot;,&amp;quot;responseCode&amp;quot;:200,&amp;quot;responseSize&amp;quot;:356349,&amp;quot;source&amp;quot;:&amp;quot;sleep&amp;quot;,&amp;quot;sourceNamespace&amp;quot;:&amp;quot;politics&amp;quot;,&amp;quot;user&amp;quot;:&amp;quot;unknown&amp;quot;}
{&amp;quot;level&amp;quot;:&amp;quot;info&amp;quot;,&amp;quot;time&amp;quot;:&amp;quot;2018-06-19T17:37:14.767923Z&amp;quot;,&amp;quot;instance&amp;quot;:&amp;quot;egress-access.logentry.istio-system&amp;quot;,&amp;quot;destination&amp;quot;:&amp;quot;edition.cnn.com&amp;quot;,&amp;quot;path&amp;quot;:&amp;quot;/health&amp;quot;,&amp;quot;responseCode&amp;quot;:200,&amp;quot;responseSize&amp;quot;:334027,&amp;quot;source&amp;quot;:&amp;quot;sleep&amp;quot;,&amp;quot;sourceNamespace&amp;quot;:&amp;quot;politics&amp;quot;,&amp;quot;user&amp;quot;:&amp;quot;unknown&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;上面的输出中可以看到 &lt;code&gt;sourceNamespace&lt;/code&gt; 的值为 &lt;code&gt;politics&lt;/code&gt;。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;重新定义 &lt;code&gt;handle-cnn-access&lt;/code&gt; 以及 &lt;code&gt;handle-politics&lt;/code&gt; 策略，为新的命名空间定义例外的日志和访问策略。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: &amp;quot;config.istio.io/v1alpha2&amp;quot;
kind: rule
metadata:
name: handle-politics
namespace: istio-system
spec:
match: request.host.endsWith(&amp;quot;cnn.com&amp;quot;) &amp;amp;&amp;amp; request.path.startsWith(&amp;quot;/politics&amp;quot;) &amp;amp;&amp;amp; source.namespace != &amp;quot;politics&amp;quot;
actions:
- handler: egress-error-logger.stdio
instances:
- egress-access.logentry
---
# 访问 egress cnn.com 的规则
apiVersion: &amp;quot;config.istio.io/v1alpha2&amp;quot;
kind: rule
metadata:
name: handle-cnn-access
namespace: istio-system
spec:
match: request.host.endsWith(&amp;quot;.cnn.com&amp;quot;) &amp;amp;&amp;amp; source.namespace != &amp;quot;politics&amp;quot;
actions:
- handler: egress-access-logger.stdio
instances:
  - egress-access.logentry
- handler: path-checker.listchecker
instances:
  - request-path.listentry
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;在 &lt;code&gt;$SOURCE_POD&lt;/code&gt; 中重复执行测试：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl exec -it $SOURCE_POD -c sleep -- bash -c &#39;curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/politics; curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/sport; curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/health&#39;
404
200
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;$SOURCE_POD&lt;/code&gt; 是在 &lt;code&gt;default&lt;/code&gt; 命名空间的，所以对 &lt;a href=&#34;http://edition.cnn.com/politics&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/politics&lt;/a&gt; 的访问会被拒绝。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;在 &lt;code&gt;$SOURCE_POD_IN_POLITICS&lt;/code&gt; 中重复执行测试：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl exec -it $SOURCE_POD_IN_POLITICS -n politics -c sleep -- bash -c &#39;curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/politics; curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/sport; curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/health&#39;
200
200
200
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;现在所有访问都可以通过了。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;查看 Mixer 日志，会发现看不到 &lt;code&gt;sourceNamespace&lt;/code&gt; 为 &lt;code&gt;politics&lt;/code&gt; 的条目了：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;kubectl -n istio-system logs $(kubectl -n istio-system get pods -l istio-mixer-type=telemetry -o jsonpath=&#39;{.items[0].metadata.name}&#39;) mixer | grep egress-access | grep cnn
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;dashboard&#34;&gt;Dashboard&lt;/h2&gt;

&lt;p&gt;让运维人员能够可视化的进行 egress 流量监控，也能增强安全性。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;浏览&lt;a href=&#34;https://istio.io/docs/tasks/telemetry/using-istio-dashboard/#viewing-the-istio-dashboard&#34; target=&#34;_blank&#34;&gt;使用 Grafana 进行指标可视化&lt;/a&gt;任务，完成其中的步骤 1-3。&lt;/li&gt;

&lt;li&gt;&lt;p&gt;从 &lt;code&gt;$SOURCE_POD&lt;/code&gt; 发送到 &lt;code&gt;cnn.com&lt;/code&gt; 的请求：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl exec -it $SOURCE_POD -c sleep -- bash -c &#39;curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/politics; curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/sport; curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/health&#39;
404
200
200
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;因为 &lt;code&gt;$SOURCE_POD&lt;/code&gt; 是存在于 &lt;code&gt;default&lt;/code&gt; 命名空间中的，所以对 &lt;a href=&#34;http://edition.cnn.com/politics&#34; target=&#34;_blank&#34;&gt;edition.cnn.com/politics&lt;/a&gt; 的访问会被拒绝。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;从 &lt;code&gt;$SOURCE_POD_IN_POLITICS&lt;/code&gt; 发送到 &lt;code&gt;cnn.com&lt;/code&gt; 的请求：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl exec -it $SOURCE_POD_IN_POLITICS -n politics -c sleep -- bash -c &#39;curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/politics; curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/sport; curl -sL -o /dev/null -w &amp;quot;%{http_code}\n&amp;quot; http://edition.cnn.com/health&#39;
200
200
200
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;滚动 Dashboard 到 HTTP 服务部分的 &lt;code&gt;istio-egressgateway.istio-system.svc.cluster.local&lt;/code&gt; 一节。会看到大致如下的显示：&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;img/dashboard-egress-gateway.png&#34; alt=&#34;istio-gresssgateway dashboard&#34; /&gt;&lt;/p&gt;

&lt;p&gt;在左侧 &lt;code&gt;Requests by Source, Version and Response Code&lt;/code&gt; 中，会看到 default 命名空间中的 &lt;code&gt;unknown&lt;/code&gt; 版本的 sleep 应用收到的 404 返回码。运维人员可以据此发现试图访问受控目标的应用。还可以看到在 &lt;code&gt;polictics&lt;/code&gt; 命名空间中 &lt;code&gt;sleep&lt;/code&gt; 应用收到的 200 返回码，这样也就知道了对受控外部资源的有效访问情况。&lt;/p&gt;

&lt;h2 id=&#34;和-https-egress-控制的比较&#34;&gt;和 HTTPS egress 控制的比较&lt;/h2&gt;

&lt;p&gt;这个用例中，应用使用的是 HTTP 和 Istio Egress Gateway 结合提供 TLS 的。换个方式，应用可以自行发送 TLS 请求给 &lt;code&gt;edition.cnn.com&lt;/code&gt;，本节中我们会对两种方式的优劣进行一些比较。&lt;/p&gt;

&lt;p&gt;HTTP 方式中，请求在本地是明文传输，经由 Sidecar 转发给 Egress Gateway 的。如果 Istio 使用双向 TLS 部署，Sidecar 代理和 Egress Gateway 之间的通信就是加密的。Egress Gateway 解密信息，查看 URL 路径，HTTP 方法和 Header，上报监控数据、执行前置检查。如果请求没有被拒绝，Egress Gateway 就会为外部目标执行 TLS 封装，这样请求就会被再次加密，以密文形式发送给外部目标。下图演示了这种方式中的网络流向。图中 Gateway 方块中的 HTTP 标志，代表报文在 Gateway 解密之后变成明文的阶段。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;img/http-to-gateway.svg&#34; alt=&#34;HTTP egress traffic through an egress gateway&#34; /&gt;&lt;/p&gt;

&lt;p&gt;这种方式的缺陷在于，请求在本机是明文传输的，可能会违反某些组织的安全需要。有些 SDK 的外部服务 URL 包含协议部分都是硬编码的，因此发送 HTTP 请求是不可能的。这种办法的好处是可以获取 HTTP 头、方法以及 URL 路径，并可以据此制定规则。&lt;/p&gt;

&lt;p&gt;在 HTTPS 形式下，从应用到外部目标的请求是端到端加密的。下图演示了这种方式的数据流。在 Gateway 中见到的报文，同样还是 HTTPS。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;img/https-to-gateway.svg&#34; alt=&#34;通过 Egress Gateway 的 HTTPS egress 流量&#34; /&gt;&lt;/p&gt;

&lt;p&gt;端到端的 HTTPS 可能是更好的一种加密方式。然而因为流量是加密通过 Istio 代理和 Egress Gateway 的，因此只能看到源和目的的 IP 以及 &lt;a href=&#34;https://en.wikipedia.org/wiki/Server_Name_Indication&#34; target=&#34;_blank&#34;&gt;SNI&lt;/a&gt;。在 Istio 开通双向 TLS 的情况下，&lt;a href=&#34;https://istio.io/docs/concepts/security/mutual-tls/#identity&#34; target=&#34;_blank&#34;&gt;源身份&lt;/a&gt;也是可知的。Gateway 无法获知 HTTP 头、方法以及 URL 路径，因此基于 HTTP 信息的策略就无法实现了。我们的用例中要求可以访问 &lt;code&gt;edition.cnn.com&lt;/code&gt;。如果 Istio 中启用了双向 TLS，组织可以设置部分应用允许访问 &lt;code&gt;edition.cnn.com&lt;/code&gt;。然而却无法允许或禁止访问特定的 URL。对 &lt;code&gt;/politics&lt;/code&gt; 的允许或者禁止，在这种上下文中都是无法实现的。&lt;/p&gt;

&lt;p&gt;我们认为，这样讲解之后，用户就可以对这两种方法进行优劣势的评估，进而做出合适的选择。&lt;/p&gt;

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

&lt;p&gt;本文中我们展示了 Istio 用 HTTP 访问 Egress 时的监控和策略。其中的监控过程，可以配置日志适配器结合 Istio Dashboard 来完成。而访问策略可以通过配置 &lt;code&gt;VirtualService&lt;/code&gt; 或者配置多种策略适配器来完成。我们演示了一个简单的策略，只允许某些 URL 的访问。我们另外还展示了稍微复杂一些的策略，通过放行指定命名空间中的指定应用，来做出例外。最后，我们比较了两种 HTTPS 过程的优劣，同时也就有不同的控制能力。&lt;/p&gt;

&lt;h2 id=&#34;清理&#34;&gt;清理&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;执行 &lt;a href=&#34;https://istio.io/docs/tasks/traffic-management/egress-gateway/&#34; target=&#34;_blank&#34;&gt;配置 Egress Gateway&lt;/a&gt; 任务中的 &lt;a href=&#34;https://istio.io/docs/tasks/traffic-management/egress-gateway/#cleanup&#34; target=&#34;_blank&#34;&gt;清理&lt;/a&gt;任务。&lt;/li&gt;

&lt;li&gt;&lt;p&gt;删除日志和策略配置：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;kubectl delete logentry egress-access -n istio-system
kubectl delete stdio egress-error-logger -n istio-system
kubectl delete stdio egress-access-logger -n istio-system
kubectl delete rule handle-politics -n istio-system
kubectl delete rule handle-cnn-access -n istio-system
kubectl delete -n istio-system listchecker path-checker
kubectl delete -n istio-system listentry request-path
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;删除 &lt;code&gt;politics&lt;/code&gt; 命名空间&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;执行&lt;a href=&#34;https://istio.io/docs/tasks/telemetry/using-istio-dashboard/&#34; target=&#34;_blank&#34;&gt;使用 Grafana 进行指标可视化&lt;/a&gt;任务中的&lt;a href=&#34;https://istio.io/docs/tasks/telemetry/using-istio-dashboard/#cleanup&#34; target=&#34;_blank&#34;&gt;清理&lt;/a&gt;环节。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
    <item>
      <title>Istio 的软性多租户支持</title>
      <link>/post/soft-multitenancy/</link>
      <pubDate>Fri, 15 Jun 2018 15:20:36 +0800</pubDate>
      <guid>/post/soft-multitenancy/</guid>
      <description>

&lt;p&gt;原文：&lt;a href=&#34;https://istio.io/blog/2018/soft-multitenancy/&#34; target=&#34;_blank&#34;&gt;Istio Soft Multi-tenancy Support&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;作者：&lt;a href=&#34;https://github.com/john-a-joyce&#34; target=&#34;_blank&#34;&gt;John Joyce&lt;/a&gt;, &lt;a href=&#34;https://github.com/rcurran1&#34; target=&#34;_blank&#34;&gt;Rich Curran&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;多租户是一个在各种环境和各种应用中都得到了广泛应用的概念，但是不同环境中，为每租户提供的具体实现和功能性都是有差异的。&lt;a href=&#34;https://github.com/kubernetes/community/blob/master/wg-multitenancy/README.md&#34; target=&#34;_blank&#34;&gt;Kubernetes 多租户工作组&lt;/a&gt;致力于在 Kubernetes 中定义多租户用例和功能。然而根据他们的工作进展来看，恶意容器和负载对于其他租户的 Pod 和内核资源的访问无法做到完全控制，因此只有“软性多租户”支持是可行的。&lt;/p&gt;

&lt;h2 id=&#34;软性多租户&#34;&gt;软性多租户&lt;/h2&gt;

&lt;p&gt;文中提到的“软性多租户”的定义指的是单一 Kubernetes 控制平面和多个 Istio 控制平面以及多个服务网格相结合；每个租户都有自己的一个控制平面和一个服务网格。集群管理员对所有 Istio 控制面都有控制和监控的能力，而租户管理员仅能得到指定 Istio 的控制权。使用 Kubernetes 的命名空间和 RBAC 来完成不同租户的隔离。&lt;/p&gt;

&lt;p&gt;这种模式的一个用例就是企业内部共享的基础设施中，虽然预计不会发生恶意行为，但租户之间的清晰隔离仍然是很有必要的。&lt;/p&gt;

&lt;p&gt;在文章最尾部会对 Istio 未来的多租户模型进行一些描述。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;注意：这里仅就在有限多租户环境中部署 Istio 做一些概要描述。当官方多租户支持实现之后，会在&lt;a href=&#34;/docs/&#34;&gt;文档&lt;/a&gt;中具体呈现。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;部署&#34;&gt;部署&lt;/h2&gt;

&lt;h3 id=&#34;多个-istio-控制面&#34;&gt;多个 Istio 控制面&lt;/h3&gt;

&lt;p&gt;要部署多个 Istio 控制面，首先要在 Istio 清单文件中对所有的 &lt;code&gt;namespace&lt;/code&gt; 引用进行替换。以 &lt;code&gt;istio.yaml&lt;/code&gt; （v0.8 中应该是 &lt;code&gt;istio-demo.yaml&lt;/code&gt;） 为例：如果需要两个租户级的 Istio 控制面，那么第一个租户可以使用 &lt;code&gt;istio.yaml&lt;/code&gt; 中的缺省命名空间也就是 &lt;code&gt;istio-system&lt;/code&gt;；而第二个租户就要生成一个新的 Yaml 文件，并在其中使用不同的命名空间。例如使用下面的命令创建一个使用 &lt;code&gt;istio-system1&lt;/code&gt; 命名空间的 Yaml 文件：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;cat istio.yaml | sed s/istio-system/istio-system1/g &amp;gt; istio-system1.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Istio Yaml 文件包含了 Istio 控制面的部署细节，包含组成控制面的 Pod（Mixer、Pilot、Ingress 以及 CA）。部署这两个控制面 Yaml 文件：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;kubectl apply -f @install/kubernetes/istio.yaml@
kubectl apply -f @install/kubernetes/istio-system1.yaml@
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;会在两个命名空间生成两个 Istio 控制面&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl get pods --all-namespaces
NAMESPACE       NAME                                       READY     STATUS    RESTARTS   AGE
istio-system    istio-ca-ffbb75c6f-98w6x                   1/1       Running   0          15d
istio-system    istio-ingress-68d65fc5c6-dnvfl             1/1       Running   0          15d
istio-system    istio-mixer-5b9f8dffb5-8875r               3/3       Running   0          15d
istio-system    istio-pilot-678fc976c8-b8tv6               2/2       Running   0          15d
istio-system1   istio-ca-5f496fdbcd-lqhlk                  1/1       Running   0          15d
istio-system1   istio-ingress-68d65fc5c6-2vldg             1/1       Running   0          15d
istio-system1   istio-mixer-7d4f7b9968-66z44               3/3       Running   0          15d
istio-system1   istio-pilot-5bb6b7669c-779vb               2/2       Running   0          15d
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果需要 Istio &lt;a href=&#34;/docs/setup/kubernetes/sidecar-injection/&#34;&gt;Sidecar 注入组件&lt;/a&gt;以及&lt;a href=&#34;/docs/tasks/telemetry/&#34;&gt;遥测组件&lt;/a&gt;，也需要根据租户的命名空间定义，修改所需的 Yaml 文件。&lt;/p&gt;

&lt;p&gt;需要由集群管理员、而不是租户自己的管理员来加载这两组 Yaml 文件。另外，要把租户管理员的操作权限限制在各自的命名空间内，还需要额外的 RBAC 配置。&lt;/p&gt;

&lt;h3 id=&#34;区分通用资源和命名空间资源&#34;&gt;区分通用资源和命名空间资源&lt;/h3&gt;

&lt;p&gt;Istio 仓库中的清单文件中会创建两种资源，一种是能够被所有 Istio 控制面访问的通用资源，另一种是每个控制平面一份的专属资源。上面所说的在 Yaml 文件中替换 &lt;code&gt;istio-system&lt;/code&gt; 命名空间的方法自然是很简单的，更好的一种方法就是把 Yaml 文件拆分为两块，一块是所有租户共享的通用部分；另一块就是租户自有的部分。根据 &lt;a href=&#34;https://kubernetes.io/docs/concepts/api-extension/custom-resources/#customresourcedefinitions&#34; target=&#34;_blank&#34;&gt;CRD 资源定义（Custom Resource Definitions）&lt;/a&gt;中的说法，角色和角色绑定资源需要从 Istio 文件中进行剥离。另外，清单文件中提供的角色和角色绑定的定义可能不适合多租户环境，还需要进一步的细化和定制。&lt;/p&gt;

&lt;h3 id=&#34;istio-控制面的-kubernetes-rbac-设置&#34;&gt;Istio 控制面的 Kubernetes RBAC 设置&lt;/h3&gt;

&lt;p&gt;租户管理员应该被限制在单独的 Istio 命名空间中，要完成这个限制，集群管理员需要创建一个清单，其中至少要包含一个 &lt;code&gt;Role&lt;/code&gt; 和 &lt;code&gt;RoleBinding&lt;/code&gt; 的定义，类似下面的文件所示。例子中定义了一个租户管理员，命名为 &lt;code&gt;sales-admin&lt;/code&gt;，他被限制在命名空间 &lt;code&gt;istio-system&lt;/code&gt; 之中。完整的清单中可能要在 &lt;code&gt;Role&lt;/code&gt; 中包含更多的 &lt;code&gt;apiGroups&lt;/code&gt; 条目，来定义租户管理员的资源访问能力。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: istio-system1
  name: ns-access-for-sales-admin-istio-system1
rules:
- apiGroups: [&amp;quot;&amp;quot;] # &amp;quot;&amp;quot; 代表核心 API 资源组
  resources: [&amp;quot;*&amp;quot;]
  verbs: [&amp;quot;*&amp;quot;]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: access-all-istio-system1
  namespace: istio-system1
subjects:
- kind: User
  name: sales-admin
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: ns-access-for-sales-admin-istio-system1
  apiGroup: rbac.authorization.k8s.io
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;关注特定命名空间进行服务发现&#34;&gt;关注特定命名空间进行服务发现&lt;/h3&gt;

&lt;p&gt;除了创建 RBAC 规则来限制租户管理员只能访问指定 Istio 控制平面之外，Istio 清单还需要为 Istio Pilot 指定一个用于应用程序的命名空间，以便生成 xDS 缓存。Pilot 组件提供了命令行参数 &lt;code&gt;--appNamespace, ns-1&lt;/code&gt; 可以完成这一任务。&lt;code&gt;ns-1&lt;/code&gt; 就是租户用来部署自己应用的命名空间。&lt;code&gt;istio-system1.yaml&lt;/code&gt; 中包含的相关代码大致如下：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: istio-pilot
  namespace: istio-system1
  annotations:
    sidecar.istio.io/inject: &amp;quot;false&amp;quot;
spec:
  replicas: 1
  template:
    metadata:
      labels:
        istio: pilot
    spec:
      serviceAccountName: istio-pilot-service-account
      containers:
      - name: discovery
        image: docker.io/&amp;lt;user ID&amp;gt;/pilot:&amp;lt;tag&amp;gt;
        imagePullPolicy: IfNotPresent
        args: [&amp;quot;discovery&amp;quot;, &amp;quot;-v&amp;quot;, &amp;quot;2&amp;quot;, &amp;quot;--admission-service&amp;quot;, &amp;quot;istio-pilot&amp;quot;, &amp;quot;--appNamespace&amp;quot;, &amp;quot;ns-1&amp;quot;]
        ports:
        - containerPort: 8080
        - containerPort: 443
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;在特定命名空间中部署租户应用&#34;&gt;在特定命名空间中部署租户应用&lt;/h3&gt;

&lt;p&gt;现在集群管理员已经给租户创建了命名空间（&lt;code&gt;istio-system1&lt;/code&gt;），并且对 Istio Pilot 的服务发现进行了配置，要求它关注应用的命名空间（&lt;code&gt;ns-1&lt;/code&gt;），创建应用的 Yaml 文件，将其部署到租户的专属命名空间中：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: v1
kind: Namespace
metadata:
  name: ns-1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;然后把每个资源的命名空间都指定到 &lt;code&gt;ns-1&lt;/code&gt;，例如：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: v1
kind: Service
metadata:
  name: details
  labels:
    app: details
  namespace: ns-1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;虽然没有展示出来，但是应用的命名空间也应该有 RBAC 设置，用来对特定资源进行访问控制。集群管理员和租户管理员都有权完成这种 RBAC 限制。&lt;/p&gt;

&lt;h3 id=&#34;在多租户环境中使用-istioctl&#34;&gt;在多租户环境中使用 &lt;code&gt;istioctl&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;定义&lt;a href=&#34;/docs/reference/config/istio.routing.v1alpha1/#RouteRule&#34;&gt;路由规则&lt;/a&gt;或者&lt;a href=&#34;/docs/reference/config/istio.routing.v1alpha1/#DestinationPolicy&#34;&gt;目标策略&lt;/a&gt;时，要确认 &lt;code&gt;istioctl&lt;/code&gt; 命令是针对专有的 Istio 控制面所在的命名空间运行的。另外规则自身的定义也要限制在租户的命名空间里，这样才能保证规则在租户自己的网格中生效。&lt;code&gt;-i&lt;/code&gt; 选项用来在 Istio 控制面所属的命名空间中创建（get 和 describe 也一样）规则。&lt;code&gt;-n&lt;/code&gt; 参数会限制规则的所在范围是租户的网格，取值就是租户应用所在的命名空间。如果 Yaml 文件中的资源已经指定了范围，&lt;code&gt;-n&lt;/code&gt; 参数会被跳过。&lt;/p&gt;

&lt;p&gt;例如下面的命令会创建到 &lt;code&gt;istio-system1&lt;/code&gt; 命名空间的路由规则：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;istioctl –i istio-system1 create -n ns-1 -f route_rule_v2.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;用下面的命令可以查看：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ istioctl -i istio-system1 -n ns-1 get routerule
NAME                  KIND                                  NAMESPACE
details-Default       RouteRule.v1alpha2.config.istio.io    ns-1
productpage-default   RouteRule.v1alpha2.config.istio.io    ns-1
ratings-default       RouteRule.v1alpha2.config.istio.io    ns-1
reviews-default       RouteRule.v1alpha2.config.istio.io    ns-1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&#34;/blog/2018/soft-multitenancy/#multiple-istio-control-planes&#34;&gt;Multiple Istio control planes&lt;/a&gt; 中讲述了更多多租户环境下命名空间的相关问题。&lt;/p&gt;

&lt;h3 id=&#34;测试结果&#34;&gt;测试结果&lt;/h3&gt;

&lt;p&gt;根据前文的介绍，一个集群管理员能够创建一个受限于 RBAC 和命名空间的环境，租户管理员能在其中进行部署。&lt;/p&gt;

&lt;p&gt;完成部署后，租户管理员就可以访问指定的 Istio 控制平面的 Pod 了。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl get pods -n istio-system
NAME                                      READY     STATUS    RESTARTS   AGE
grafana-78d649479f-8pqk9                  1/1       Running   0          1d
istio-ca-ffbb75c6f-98w6x                  1/1       Running   0          1d
istio-ingress-68d65fc5c6-dnvfl            1/1       Running   0          1d
istio-mixer-5b9f8dffb5-8875r              3/3       Running   0          1d
istio-pilot-678fc976c8-b8tv6              2/2       Running   0          1d
istio-sidecar-injector-7587bd559d-5tgk6   1/1       Running   0          1d
prometheus-cf8456855-hdcq7                1/1       Running   0          1d
servicegraph-75ff8f7c95-wcjs7             1/1       Running   0          1d
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;然而无法访问全部命名空间的 Pod：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl get pods --all-namespaces
Error from server (Forbidden): pods is forbidden: User &amp;quot;dev-admin&amp;quot; cannot list pods at the cluster scope
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;访问其他租户的命名空间也是不可以的：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl get pods -n istio-system1
Error from server (Forbidden): pods is forbidden: User &amp;quot;dev-admin&amp;quot; cannot list pods in the namespace &amp;quot;istio-system1&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;租户管理员能够在租户指定的应用命名空间中进行应用部署。例如可以修改一下 &lt;a href=&#34;/docs/guides/bookinfo/&#34;&gt;Bookinfo&lt;/a&gt; 的 Yaml 然后部署到租户的命名空间 &lt;code&gt;ns-0&lt;/code&gt; 中，然后租户管理员就可以在这一命名空间中列出 Pod 了：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl get pods -n ns-0
NAME                              READY     STATUS    RESTARTS   AGE
details-v1-64b86cd49-b7rkr        2/2       Running   0          1d
productpage-v1-84f77f8747-rf2mt   2/2       Running   0          1d
ratings-v1-5f46655b57-5b4c5       2/2       Running   0          1d
reviews-v1-ff6bdb95b-pm5lb        2/2       Running   0          1d
reviews-v2-5799558d68-b989t       2/2       Running   0          1d
reviews-v3-58ff7d665b-lw5j9       2/2       Running   0          1d
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;同样也是不能访问其他租户的应用程序命名空间：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl get pods -n ns-1
Error from server (Forbidden): pods is forbidden: User &amp;quot;dev-admin&amp;quot; cannot list pods in the namespace &amp;quot;ns-1&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果部署了&lt;a href=&#34;/docs/tasks/telemetry/&#34;&gt;遥测组件&lt;/a&gt;, 例如
&lt;a href=&#34;/docs/tasks/telemetry/querying-metrics/&#34;&gt;prometheus&lt;/a&gt;（限制在 Istio 的 &lt;code&gt;namespace&lt;/code&gt;），其中获得的统计结果展示的也只是租户应用命名空间的私有数据。&lt;/p&gt;

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

&lt;p&gt;上面的一些尝试表明 Istio 有足够的能力和安全性，符合少量多租户的用例需求。另外也很明显的，Istio 和 Kubernetes &lt;strong&gt;无法&lt;/strong&gt; 提供足够的能力和安全性来满足其他的用例，尤其是在租户之间要求完全的安全性和隔离的要求的用例。如果容器技术例如 Kubernetes 能够提供更好的安全模型以及隔离能力，我们才能进一步的增强这方面的支持，Istio 的支持并不是很重要。&lt;/p&gt;

&lt;h2 id=&#34;问题&#34;&gt;问题&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;一个租户的 CA(Certificate Authority) 和 Mixer 的 Pod 中产生的 Log 包含了另一个租户的控制面的 &lt;code&gt;info&lt;/code&gt; 信息。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;其他多租户模型的挑战&#34;&gt;其他多租户模型的挑战&lt;/h2&gt;

&lt;p&gt;还有其他值得考虑的多租户部署模型：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;一个网格中运行多个应用程序，每个租户一个应用。集群管理员能控制和监控网格范围内的所有应用，租户管理员只能控制一个特定应用。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;单独的 Istio 控制平面控制多个网格，每个租户一个网格。集群管理员控制和监控整个 Istio 控制面以及所有网格，租户管理员只能控制特定的网格。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;一个云环境（集群控制），多个 Kubernetes 控制面（租户控制）&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;这些选项，有的需要改写代码才能支持，有的无法满足用户要求。&lt;/p&gt;

&lt;p&gt;目前的 Istio 能力不适合第一种方案，这是因为其 RBAC 能力无法覆盖这种租户操作。另外在当前的网格模型中，Istio 的配置信息需要传递给 Envoy 代理服务器，多个租户在同一网格内共存的做法非常不安全。&lt;/p&gt;

&lt;p&gt;再看看第二个方式，目前的 Istio 假设每个 Istio 控制面对应一个网格。要支持这种模型需要大量改写。这种情况需要更好的对资源的范围限制进行调整，同时根据命名空间进行安全限制，此外还需要调整 Istio 的 RBAC 模型。这种模式未来可能会支持，但目前来说是不可能的。&lt;/p&gt;

&lt;p&gt;第三个方式对多数案例都是不合适的，毕竟多数集群管理员倾向于将同一个 Kubernetes 控制面作为 &lt;a href=&#34;https://en.wikipedia.org/wiki/Platform_as_a_service&#34; target=&#34;_blank&#34;&gt;PaaS&lt;/a&gt; 提供给他们的租户。&lt;/p&gt;

&lt;h2 id=&#34;未来&#34;&gt;未来&lt;/h2&gt;

&lt;p&gt;很明显，单一 Istio 控制面控制多个网格可能是下一个功能。还有可能就是在同一个网格中支持多个租户，并提供某种程度的隔离和安全保障。要完成这样的能力，就需要像 Kubernetes 中对命名空间的额操作那样，在一个单独的控制平面中进行分区，社区中发出了 &lt;a href=&#34;https://docs.google.com/document/d/14Hb07gSrfVt5KX9qNi7FzzGwB_6WBpAnDpPG6QEEd9Q&#34; target=&#34;_blank&#34;&gt;这篇文档&lt;/a&gt; 来定义其他的用例，以及要支持这些用例所需要的 Istio 功能。&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;视频：Kubernetes 多租户支持 &lt;a href=&#34;https://www.youtube.com/watch?v=ahwCkJGItkU&#34; target=&#34;_blank&#34;&gt;Multi-Tenancy Support &amp;amp; Security Modeling with RBAC and Namespaces&lt;/a&gt;, 以及&lt;a href=&#34;https://schd.ws/hosted_files/kccncna17/21/Multi-tenancy%20Support%20%26%20Security%20Modeling%20with%20RBAC%20and%20Namespaces.pdf&#34; target=&#34;_blank&#34;&gt;幻灯片&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Kubecon 讨论，关于对”协同软性多租户“的支持 &lt;a href=&#34;https://www.youtube.com/watch?v=YRR-kZub0cA&#34; target=&#34;_blank&#34;&gt;Building for Trust: How to Secure Your Kubernetes&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Kubernetes &lt;a href=&#34;https://kubernetes.io/docs/admin/authorization/rbac/&#34; target=&#34;_blank&#34;&gt;RBAC 文档&lt;/a&gt; 以及 &lt;a href=&#34;https://kubernetes.io/docs/tasks/administer-cluster/namespaces-walkthrough/&#34; target=&#34;_blank&#34;&gt;命名空间文档&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Kubecon 幻灯片 &lt;a href=&#34;https://schd.ws/hosted_files/kccncna17/a9/kubecon-multitenancy.pdf&#34; target=&#34;_blank&#34;&gt;Multi-tenancy Deep Dive&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Google 文档 &lt;a href=&#34;https://docs.google.com/document/d/15w1_fesSUZHv-vwjiYa9vN_uyc--PySRoLKTuDhimjc/edit#heading=h.3dawx97e3hz6&#34; target=&#34;_blank&#34;&gt;Multi-tenancy models for Kubernetes&lt;/a&gt;. (需要授权)&lt;/li&gt;
&lt;li&gt;Cloud Foundry 提出的文档：&lt;a href=&#34;https://docs.google.com/document/d/14Hb07gSrfVt5KX9qNi7FzzGwB_6WBpAnDpPG6QEEd9Q&#34; target=&#34;_blank&#34;&gt;Multi-cloud and Multi-tenancy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.google.com/document/d/12F183NIRAwj2hprx-a-51ByLeNqbJxK16X06vwH5OWE/edit#heading=h.x0f9qplja3q&#34; target=&#34;_blank&#34;&gt;Istio Auto Multi-Tenancy 101&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Istio 安全设置笔记</title>
      <link>/post/istio-security-notes/</link>
      <pubDate>Mon, 11 Jun 2018 00:05:25 +0800</pubDate>
      <guid>/post/istio-security-notes/</guid>
      <description>

&lt;p&gt;&lt;a href=&#34;https://istio.io/&#34; target=&#34;_blank&#34;&gt;Istio&lt;/a&gt; 为网格中的微服务提供了较为完善的安全加固功能，在不影响代码的前提下，可以从多个角度提供安全支撑，&lt;a href=&#34;https://istio.io/docs/tasks/security/&#34; target=&#34;_blank&#34;&gt;官方文档&lt;/a&gt;做了较为详细的介绍，但是也比较破碎，这里尝试做个简介兼索引，实现过程还是要根据官方文档进行。&lt;/p&gt;

&lt;p&gt;Istio 的安全功能主要分为三个部分的实现：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;双向 TLS 支持。&lt;/li&gt;
&lt;li&gt;基于黑白名单的访问控制。&lt;/li&gt;
&lt;li&gt;基于角色的访问控制。&lt;/li&gt;
&lt;li&gt;JWT 认证支持。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;首先回顾一下 Istio 网格中的服务通信过程：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;利用自动或者手工注入，把 Envoy Proxy 注入到每个服务 Pod 中，用 Sidecar 的方式运行。&lt;/li&gt;
&lt;li&gt;Pod 初始化过程里，使用 iptables 劫持所在 Pod 的&lt;strong&gt;出入&lt;/strong&gt;流量。&lt;/li&gt;
&lt;li&gt;服务间的通信，从原来的直接通信，转换为现在的 Envoy 之间通信，Envoy 在这里同时作为客户端和服务端负载均衡组件。&lt;/li&gt;
&lt;li&gt;Envoy 的工作过程中，可能会和 Mixer、Pilot 以及 Citadel 等组件发生互动。&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&#34;双向-tls-支持&#34;&gt;双向 TLS 支持&lt;/h2&gt;

&lt;p&gt;双向 TLS 支持主要针对的是通信方面，把明文传输的服务通信，通过转换为 Envoy 之间的加密通信。这一安全设置较为基础，可以在全局、Namespace 或者单个服务的范围内生效。&lt;/p&gt;

&lt;p&gt;这一功能主要通过两个 Istio CRD 对象来完成：&lt;/p&gt;

&lt;h3 id=&#34;policy&#34;&gt;Policy&lt;/h3&gt;

&lt;p&gt;例如 &lt;a href=&#34;https://istio.io/docs/tasks/security/authn-policy/&#34; target=&#34;_blank&#34;&gt;Basic Authentication Policy&lt;/a&gt; 中的一个样例，用于给单个服务设置 mtls：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: &amp;quot;authentication.istio.io/v1alpha1&amp;quot;
kind: &amp;quot;Policy&amp;quot;
metadata:
  name: &amp;quot;example-2&amp;quot;
spec:
  targets:
  - name: httpbin
  peers:
  - mtls:
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;其中 &lt;code&gt;target&lt;/code&gt; 是可选项，如果去掉的话，作用域将扩展到整个 Namespace。&lt;/p&gt;

&lt;h3 id=&#34;destinationrule&#34;&gt;DestinationRule&lt;/h3&gt;

&lt;p&gt;同样的一个例子里面的目标规则如下：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: &amp;quot;networking.istio.io/v1alpha3&amp;quot;
kind: &amp;quot;DestinationRule&amp;quot;
metadata:
  name: &amp;quot;example-2&amp;quot;
spec:
  host: httpbin.bar.svc.cluster.local
  trafficPolicy:
    tls:
      mode: DISABLE
    portLevelSettings:
    - port:
        number: 1234
      tls:
        mode: ISTIO_MUTUAL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这个也很容易理解，这一规则用于指派对该地址的访问方式：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tls.mode = DISABLE&lt;/code&gt;，这个服务缺省是不开启 tls 支持的，如果取值 &lt;code&gt;ISTIO_MUTUAL&lt;/code&gt;，则代表这个地址（服务）的所有端口都开启 TLS。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;port...ISTIO_MUTUAL&lt;/code&gt;，只针对这一个端口启用 mTLS 支持。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;创建 Policy 之后，Citadel 会生成证书文件，并传递给 Envoy，我们可以在 Envoy 容器（kube-proxy）的 &lt;code&gt;/etc/certs/&lt;/code&gt; 目录中看到这几个 &lt;code&gt;*.pem&lt;/code&gt; 文件。如果使用 &lt;code&gt;openssl x509 -text -noout&lt;/code&gt; 查看 &lt;code&gt;cert-chain.pem&lt;/code&gt; 的证书内容，会看到 spiffe 编码的 ServiceAccount 内容来作为 SAN：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt; X509v3 Subject Alternative Name:
            URI:spiffe://cluster.local/ns/default/sa/default
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;规则生效之后，原有的服务间调用是没有差异的，但是如果在网格之外，就必须 https，结合上面谈到的证书来访问目标服务才能完成访问。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;另外这里也提供了&lt;a href=&#34;https://istio.io/docs/tasks/security/plugin-ca-cert/&#34; target=&#34;_blank&#34;&gt;外部 CA 的支持&lt;/a&gt;，可以使用已有的证书体系来替换网格内的自签发体系。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;基于黑白名单的访问控制&#34;&gt;基于黑白名单的访问控制&lt;/h2&gt;

&lt;h3 id=&#34;黑名单&#34;&gt;黑名单&lt;/h3&gt;

&lt;p&gt;下面的例子来自&lt;a href=&#34;https://raw.githubusercontent.com/istio/istio/release-0.8/samples/bookinfo/kube/mixer-rule-deny-label.yaml&#34; target=&#34;_blank&#34;&gt;官方&lt;/a&gt;，禁止 Reviews 的 v3 版本访问 Ratings 服务。&lt;/p&gt;

&lt;p&gt;首先使用 &lt;code&gt;denier&lt;/code&gt; 适配器定义一个拒绝响应&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: &amp;quot;config.istio.io/v1alpha2&amp;quot;
kind: denier
metadata:
  name: denyreviewsv3handler
spec:
  status:
    code: 7
    message: Not allowed
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这里不需要额外属性输入，因此采用了 &lt;code&gt;checknothing&lt;/code&gt; 模板：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: &amp;quot;config.istio.io/v1alpha2&amp;quot;
kind: checknothing
metadata:
  name: denyreviewsv3request
spec:
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;最后使用 &lt;code&gt;rule&lt;/code&gt; 对象把这两者联系起来，并配合一个表达式来使之生效：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: &amp;quot;config.istio.io/v1alpha2&amp;quot;
kind: rule
metadata:
  name: denyreviewsv3
spec:
  match: destination.labels[&amp;quot;app&amp;quot;] == &amp;quot;ratings&amp;quot; &amp;amp;&amp;amp; source.labels[&amp;quot;app&amp;quot;]==&amp;quot;reviews&amp;quot; &amp;amp;&amp;amp; source.labels[&amp;quot;version&amp;quot;] == &amp;quot;v3&amp;quot;
  actions:
  - handler: denyreviewsv3handler.denier
    instances: [ denyreviewsv3request.checknothing ]
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;白名单&#34;&gt;白名单&lt;/h3&gt;

&lt;p&gt;官方案例设置了一个允许 &lt;code&gt;v2&lt;/code&gt; 和 &lt;code&gt;v3&lt;/code&gt; 版本访问 &lt;code&gt;ratings&lt;/code&gt; 服务的白名单。&lt;/p&gt;

&lt;p&gt;白名单适配器要使用的是 &lt;code&gt;listchecker&lt;/code&gt;，提供了一个允许访问的数组。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: config.istio.io/v1alpha2
kind: listchecker
metadata:
  name: whitelist
spec:
  # providerUrl: 可以从外部 URL 获取列表内容
  overrides: [&amp;quot;v1&amp;quot;, &amp;quot;v2&amp;quot;]  # 静态列表
  blacklist: false
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;需要使用一个模板将 Pod 标签转换为 &lt;code&gt;listchecker&lt;/code&gt; 的版本列表。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: config.istio.io/v1alpha2
kind: listentry
metadata:
  name: appversion
spec:
  value: source.labels[&amp;quot;version&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;最后使用 Rule 进行连接：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: config.istio.io/v1alpha2
kind: rule
metadata:
  name: checkversion
spec:
  match: destination.labels[&amp;quot;app&amp;quot;] == &amp;quot;ratings&amp;quot;
  actions:
  - handler: whitelist.listchecker
    instances:
    - appversion.listentry
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;注意：如果开启了 mTLS，可以使用 &lt;code&gt;source.user == &amp;quot;cluster.local/ns/default/sa/bookinfo-productpage&amp;quot;&lt;/code&gt; 的形式来匹配 ServiceAccount。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;rbac&#34;&gt;RBAC&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Helm 安装时，需要设置 &lt;code&gt;global.rbacEnabled: true&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;RBAC 提供较细粒度的访问控制。另外其中所使用的 &lt;code&gt;ServiceRole&lt;/code&gt; 和 &lt;code&gt;ServiceRoleBinding&lt;/code&gt; 也更直观、更加易于管理。&lt;/p&gt;

&lt;p&gt;例如来自&lt;a href=&#34;https://istio.io/docs/tasks/security/role-based-access-control/&#34; target=&#34;_blank&#34;&gt;官方 Task&lt;/a&gt; 的 &lt;code&gt;ServiceRole&lt;/code&gt; 定义，这个角色允许对指定服务进行只读访问：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: &amp;quot;config.istio.io/v1alpha2&amp;quot;
kind: ServiceRole
metadata:
  name: productpage-viewer
  namespace: default
spec:
  rules:
  - services: [&amp;quot;productpage.default.svc.cluster.local&amp;quot;]
    methods: [&amp;quot;GET&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果在 Namespace 级别进行设置，则可以这样：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;...
  rules:
  - services: [&amp;quot;*&amp;quot;]
    methods: [&amp;quot;GET&amp;quot;]
    constraints:
    - key: &amp;quot;app&amp;quot;
      values: [&amp;quot;productpage&amp;quot;]
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;和 Kubernetes 的 Rolebinding 类似，把用户和角色绑定起来，才能最后生效。&lt;/p&gt;

&lt;p&gt;例如：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;  - user: alice@yahoo.com
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;或者&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;  - properties:
      service: &amp;quot;reviews&amp;quot;
      namespace: &amp;quot;abc&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;subject&lt;/code&gt; 的内容，同样属于 Adapter 模型的实现范围，因此其可选项目仍然是由 Template 的输入产生的。具体样例可以参考 &lt;a href=&#34;https://github.com/istio/istio/blob/release-0.8/samples/bookinfo/kube/istio-rbac-enable.yaml&#34; target=&#34;_blank&#34;&gt;bookinfo 的 rbac 样板&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;jwt-认证&#34;&gt;JWT 认证&lt;/h2&gt;

&lt;p&gt;没有外部认证的需求，因此就先不理了 lol。&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;安全任务：&lt;code&gt;https://istio.io/docs/tasks/security&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Istio RBAC 参考：&lt;code&gt;https://istio.io/docs/reference/config/istio.rbac.v1alpha1/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Istio Adapters 参考：&lt;code&gt;https://istio.io/docs/reference/config/policy-and-telemetry/adapters/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Bookinfo 示例：&lt;code&gt;https://github.com/istio/istio/blob/release-0.8/samples/bookinfo/kube/&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
    <item>
      <title>在 Istio 中使用 Opentracing Baggage 进行传播和路由</title>
      <link>/post/istio-routing-using-opentracing-baggage-distributed-context-propagation/</link>
      <pubDate>Fri, 08 Jun 2018 12:25:23 +0800</pubDate>
      <guid>/post/istio-routing-using-opentracing-baggage-distributed-context-propagation/</guid>
      <description>

&lt;p&gt;原文：&lt;a href=&#34;https://medium.com/jaegertracing/istio-routing-using-opentracing-baggage-distributed-context-propagation-ed8d787a4bef&#34; target=&#34;_blank&#34;&gt;Istio Routing using OpenTracing Baggage/Distributed Context Propagation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;作者：&lt;a href=&#34;https://medium.com/@p.loffay?source=post_header_lockup&#34; target=&#34;_blank&#34;&gt;Pavol Loffay&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;现代服务网格架构提供了很多的新功能，基础设施相关的依赖部分被逐步从代码中移除，极大的降低了编码工作量。除此之外，这一架构的智能路由功能还把金丝雀发布以及类似功能大大的简化了。&lt;/p&gt;

&lt;p&gt;接下来的内容会探讨一下，Istio 路由规则是如何使用 Opentracing Baggage 的。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/kiali-screen.jpg&#34; alt=&#34;kiali&#34; /&gt;&lt;/p&gt;

&lt;p&gt;想像一个场景，这个场景中我们需要通过 &lt;code&gt;User-Agent&lt;/code&gt; Header 来鉴别 Safari 用户，并把它们重定向到服务的一个特定版本去。这是一个典型的金丝雀场景：新版本发布时，首先开放给一部分用户。然而很明显只有第一个服务能够接收到 &lt;code&gt;User-Agent&lt;/code&gt; 头，如果路由规则中涉及到调用关系图中位置较低（靠后）的服务，就不得不把这个 Header 信息传播给所有途中经过的服务。这是一个分布式上下文传播的典型用例，很多跟踪系统都有这个功能。我们接下来会看看 &lt;a href=&#34;http://www.jaegertracing.io/&#34; target=&#34;_blank&#34;&gt;Jaeger&lt;/a&gt; 的 OpenTracing 实现。&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/opentracing/specification/blob/master/specification.md#set-a-baggage-item&#34; target=&#34;_blank&#34;&gt;Baggage 条目&lt;/a&gt;是字符串组成的键值对，和 &lt;code&gt;Span/SpanContext&lt;/code&gt; 互相关联，在一个 Trace 的范围内，会在所有的下游 Span 中进行传播。&lt;/p&gt;

&lt;p&gt;如果你的网格中使用的是 OpenTracing，那么就已经有这个功能了；如果不是，那就有点不幸了：需要通过其他的 &lt;a href=&#34;https://istio.io/docs/tasks/telemetry/distributed-tracing/#understanding-what-happened&#34; target=&#34;_blank&#34;&gt;跟踪 Header&lt;/a&gt; 来传递 &lt;code&gt;User-Agent&lt;/code&gt; 值了，这样就需要修途经的所有服务。&lt;/p&gt;

&lt;p&gt;Istio 缺省使用的 &lt;a href=&#34;https://github.com/openzipkin/b3-propagation&#34; target=&#34;_blank&#34;&gt;B3&lt;/a&gt; 传播是没有提供 Baggage 头的。但是可以用 &lt;a href=&#34;https://github.com/openzipkin/brave&#34; target=&#34;_blank&#34;&gt;Brave&lt;/a&gt;（Zipkin 的 Java 客户端）来配置 Baggage 支持。一般会使用 &lt;code&gt;baggage-key:value&lt;/code&gt; 的格式。Jaeger 实现了一个 B3 解码器，也用同样的格式来处理 Baggage。可以在&lt;a href=&#34;https://github.com/jaegertracing/jaeger/issues/755#issuecomment-393929718&#34; target=&#34;_blank&#34;&gt;这里&lt;/a&gt;查看 B3 Baggage 实现的进度。&lt;/p&gt;

&lt;h2 id=&#34;demo&#34;&gt;Demo&lt;/h2&gt;

&lt;p&gt;可以在当前的活动 Span 中这样设置 Baggage：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;tracer.activeSpan().setBaggageItem(&amp;quot;user-agent&amp;quot;, userAgent);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这必须在第一个服务中完成。最后一个需要完成的任务就是定义一个识别 Baggage Header 的路由。下面的路由定义会查看请求是否包含了带有 &lt;code&gt;user-agent:Safari&lt;/code&gt; 条目的 Baggage，如果有，就进行转发：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  name: recommendation-safari
spec:
  destination:
    namespace: tutorial
    name: recommendation
  precedence: 2
  match:
    request:
      headers:
        baggage-user-agent:
          regex: &amp;quot;.*Safari.*&amp;quot;  
  route:
  - labels:
      version: v2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果是新版本的 Istio（0.8.0 以后）：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: recommendation-safari
spec:
  hosts:
  - recommendation
  http:
  - match:
    - headers:
        baggage-user-agent:
          regex: &amp;quot;.*Safari.*&amp;quot;
    route:
     - destination:
        host: recommendation
        subset: v2
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: recommendation-destination
spec:
  host: recommendation
  subsets:
  - name: v2
    labels:
      version: v2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;现在所有的配置都已经完成，Safari 用户会被重定向到推荐的 v2 服务。&lt;/p&gt;

&lt;p&gt;下面的视频进行了使用 OpenTracing Baggage 进行路由的演示，参见 &lt;a href=&#34;https://github.com/redhat-developer-demos/istio-tutorial&#34; target=&#34;_blank&#34;&gt;Redhat 的 Istio Tutorial&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://youtu.be/sEbs3zkUnK8&#34; target=&#34;_blank&#34;&gt;&lt;img src=&#34;images/yout.png&#34; alt=&#34;video&#34; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;相关链接&#34;&gt;相关链接&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://opentracing.io/&#34; target=&#34;_blank&#34;&gt;OpenTracing&lt;/a&gt;：&lt;code&gt;http://opentracing.io/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/opentracing/specification/blob/master/specification.md#set-a-baggage-item&#34; target=&#34;_blank&#34;&gt;OpenTracing baggage 规范&lt;/a&gt;：&lt;code&gt;https://github.com/opentracing/specification/blob/master/specification.md#set-a-baggage-item&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/jaegertracing/jaeger/issues/755#issuecomment-393929718&#34; target=&#34;_blank&#34;&gt;Jaeger 客户端的 B3 Baggage 支持&lt;/a&gt;：&lt;code&gt;https://github.com/jaegertracing/jaeger/issues/755#issuecomment-393929718&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/redhat-developer-demos/istio-tutorial&#34; target=&#34;_blank&#34;&gt;OpenShift 的 Istio 教程&lt;/a&gt;：&lt;code&gt;https://github.com/redhat-developer-demos/istio-tutorial&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kiali.org/&#34; target=&#34;_blank&#34;&gt;Kiali&lt;/a&gt;: &lt;code&gt;https://kiali.org/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Service Mesh 安全：用 Istio 应对攻击</title>
      <link>/post/service-mesh-security-addressing-attack-vectors-with-istio/</link>
      <pubDate>Thu, 07 Jun 2018 10:10:21 +0800</pubDate>
      <guid>/post/service-mesh-security-addressing-attack-vectors-with-istio/</guid>
      <description>

&lt;p&gt;原文：&lt;a href=&#34;https://aspenmesh.io/2018/06/service-mesh-security-addressing-attack-vectors-with-istio/&#34; target=&#34;_blank&#34;&gt;Service Mesh Security: Addressing Attack Vectors with Istio&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;作者： &lt;strong&gt;Zach Jory&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;把单体应用拆分为微服务之后，会得到不少好处，例如稳定性的提高、持续运行时间的增长以及更好的故障隔离等。然而把大应用拆分为小服务的过程中，也会引入一个风险就是——可能的受攻击面积变大了。从前单体应用中通过函数调用完成的通信，现在都要通过网络完成。提高安全性从而避免这个问题带来的安全影响，是微服务之路上必须要着重考虑的问题。&lt;/p&gt;

&lt;p&gt;Aspen Mesh 的基础是一个开源软件：&lt;a href=&#34;https://istio.io/&#34; target=&#34;_blank&#34;&gt;Istio&lt;/a&gt;，他的关键能力之一就是为微服务提供安全性和策略控制方面的支持。Istio 为 Service Mesh 增加了很多安全特性，但是这并不是说微服务的安全工作就结束了。网络安全策略也是需要着重考虑的问题（推荐阅读：&lt;a href=&#34;https://medium.com/lightspeed-venture-partners/in-the-land-of-microservices-the-network-is-the-king-maker-37de7ec4119a&#34; target=&#34;_blank&#34;&gt;In the land of microservices, the network is the king(maker)&lt;/a&gt;），结合网络策略，可以检测和应对针对服务网格基础设施的攻击，从而解决各种安全威胁。&lt;/p&gt;

&lt;p&gt;后面的内容将会看看 Istio 所能够解决的问题，其中包含边缘通信的流量控制、网格内通信加密以及 7 层策略控制等。&lt;/p&gt;

&lt;h2 id=&#34;边缘通信安全&#34;&gt;边缘通信安全&lt;/h2&gt;

&lt;p&gt;针对不当进入网格的流量，Istio 加入了一个用来进行监控和防范的安全层。Istio 以 Ingress Controller 的形式和 Kubernetes 进行了集成，并完成了 Ingress 的负载均衡任务。用户可以用 Ingress Rule 的方式加入安全控制。可以通过监控来了解进入网格的流量，并通过路由规则来管理非法的边缘通信。&lt;/p&gt;

&lt;p&gt;要保证只有认证用户通过，Istio 的 RBAC（基于角色的访问控制）提供了有弹性的、可定制的访问控制，这种能力在网格内提供了 namespace、service 以及服务方法一级的控制能力。RBAC 引擎监控和跟进 RBAC 策略的变更，在运行时根据 RBAC 策略，根据请求的上下文对请求进行鉴权，最后返回鉴权结果。&lt;/p&gt;

&lt;h2 id=&#34;通信加密&#34;&gt;通信加密&lt;/h2&gt;

&lt;p&gt;边缘通信的安全是个好的开始，但是如果有恶意份子突破了边缘之后，Istio 还为服务之间的通信提供了双向 TLS 认证能力。网格能够对请求和响应进行自动的加密和解密，开发人员就无需在此投入精力了。这个功能还通过对连接的优先复用，减少了连接过程中的运算消耗。&lt;/p&gt;

&lt;p&gt;除了客户端和服务器之间的认证和鉴权能力之外，还让用户能够理解和管理服务间的通信和加密。Istio 把证书和密钥自动分发给服务，代理使用这些输入来给流量进行加密（提供双向 TLS），并周期性的进行证书轮转，从而降低证书暴露造成的威胁。可以利用 TLS 来确认 Istio 中的通信双方的服务实例都是合法的，从而防止中间人攻击。&lt;/p&gt;

&lt;p&gt;Istio 使用 Citadel 来进行密钥管理和认证控制，简化了 TLS 过程。他让用户能够保护流量，同时给每个服务提供基于身份的验证和授权功能。&lt;/p&gt;

&lt;h2 id=&#34;策略控制和执行&#34;&gt;策略控制和执行&lt;/h2&gt;

&lt;p&gt;Istio 给用户在应用级执行策略的能力。对于服务路由、重试、断路以及安全来说，在这一层进行控制是非常恰当的。Istio 为用户提供了黑白名单功能来来对服务进行准入的控制。&lt;/p&gt;

&lt;p&gt;Istio Mixer 可以把扩展集成进系统，用户用标准化的表达式语言来来声明网络以及服务行为方面的约束策略。这样做的好处是，可以用通用 API 在服务边缘来缓存策略的决策结果，如果下游的策略系统出现故障，网络还能保持运行。&lt;/p&gt;

&lt;p&gt;Istio 解决了一些微服务特定的关键问题。例如只允许被批准的服务间通信，加密通信防止通信过程中的入侵，执行应用范围内的策略等。当然还有很多其他方式可以实现这些能力，Mesh 的好处在于将这些能力融会贯通，让用户使用一致的稳定的方式来完成这些任务。&lt;/p&gt;

&lt;p&gt;Aspen Mesh 中正在做一些新的功能，在 Istio 中为用户提供更好的安全能力。近期我们会在博客上发点东西，所以请关注 &lt;a href=&#34;https://aspenmesh.io/blog/&#34; target=&#34;_blank&#34;&gt;Aspen Mesh 博客&lt;/a&gt;。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Conduit 0.4.2 发布</title>
      <link>/post/conduit-0.4.2-release/</link>
      <pubDate>Tue, 05 Jun 2018 10:04:16 +0800</pubDate>
      <guid>/post/conduit-0.4.2-release/</guid>
      <description>

&lt;p&gt;Conduit 0.4.2 是生产就绪之路上的重要一步。这个版本为代理服务器的长期运行做出了很多修复和提高，并提供了更多的遥测功能。同时也为未来的双向 TLS 版本打好了基础。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;生产就绪

&lt;ul&gt;
&lt;li&gt;代理服务器会丢弃 10 分钟未更新的指标，以防长期运行过程中造成的额外的内存增长。&lt;/li&gt;
&lt;li&gt;新增了一个约束，限制一个节点能够路由的服务数量，缺省为 100。这样在代理服务器长期运行的时候，可以在容量到达上限的时候，丢弃闲置最久的客户端，从而达到节约资源的目的。&lt;/li&gt;
&lt;li&gt;代理服务器现在能够正确的处理 HTTP/2 请求的取消。&lt;/li&gt;
&lt;li&gt;修复连接错误时候的请求处理。&lt;/li&gt;
&lt;li&gt;正确处理 DNS 的 TTL。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;conduit inject&lt;/code&gt; 现在可以处理 &lt;code&gt;statefulset&lt;/code&gt; 对象了。&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;遥测

&lt;ul&gt;
&lt;li&gt;新版本的 &lt;code&gt;conduit stat&lt;/code&gt; 现在支持所有的 Kubernetes 资源，能够展示一个命名空间内所有对象的流量统计。&lt;/li&gt;
&lt;li&gt;Conduit Web UI 提供了命名空间概述的展示。&lt;/li&gt;
&lt;li&gt;修复了 Tap 功能的一个 Bug，这个 Bug 让代理服务器无法同时响应多个 Tap 请求。&lt;/li&gt;
&lt;li&gt;修复了故障状态下，无法报告某些 TCP 流的问题。&lt;/li&gt;
&lt;li&gt;加入了首字节响应时间的指标。&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;内部

&lt;ul&gt;
&lt;li&gt;环境配置加入了对友好的时间格式的支持（例如 10s）。&lt;/li&gt;
&lt;li&gt;控制面使用 Kubernetes 1.10.2 客户端。&lt;/li&gt;
&lt;li&gt;更丰富的 Debug 日志，包含了 Socket 和 Stream 的元数据。&lt;/li&gt;
&lt;li&gt;为 TLS 支持对代理做出大量改进。&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;非常感谢 &lt;a href=&#34;https://github.com/carllhw&#34; target=&#34;_blank&#34;&gt;@carllhw&lt;/a&gt;、&lt;a href=&#34;https://github.com/kichristensen&#34; target=&#34;_blank&#34;&gt;@kichristensen&lt;/a&gt; 和 &lt;a href=&#34;https://github.com/sfroment&#34; target=&#34;_blank&#34;&gt;@sfroment&lt;/a&gt; 做出的贡献。&lt;/p&gt;

&lt;h2 id=&#34;从-0-4-1-升级&#34;&gt;从 0.4.1 升级&lt;/h2&gt;

&lt;p&gt;从 0.4.1 升级时，建议首先升级控制面，然后再升级注入。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Istio 0.8 的 Helm Chart 解析</title>
      <link>/post/istio-0.8.0-helm/</link>
      <pubDate>Mon, 04 Jun 2018 09:39:10 +0800</pubDate>
      <guid>/post/istio-0.8.0-helm/</guid>
      <description>

&lt;p&gt;儿童节期间，拖拉了一个多月的 Istio 0.8 正式发布了，这可能是 Istio 1.0 之前的最后一个 LTS 版本，意义重大。&lt;/p&gt;

&lt;p&gt;新版本中，原来的 Kubernetes 安装文件 &lt;code&gt;install/kubernetes/istio.yaml&lt;/code&gt;，变成了 &lt;code&gt;install/kubernetes/istio-demo.yaml&lt;/code&gt;，是的，你没看错，这个 LTS 的安装文件名字叫 demo。查看了一下文档，大概察觉到不靠谱的 Istio 发布组的意图了：这个项目的组件相对比较复杂，原有的一些选项是靠 ConfigMap 以及 istioctl 分别调整的，现在通过重新设计的 Helm Chart，安装选项用 values.yml 或者 helm 命令行的方式来进行集中管理了。下面就由看看 Istio 的 Helm Chart 的安装部署及其结构。&lt;/p&gt;

&lt;h2 id=&#34;使用-helm-安装-istio&#34;&gt;使用 Helm 安装 Istio&lt;/h2&gt;

&lt;p&gt;安装包内的 Helm 目录中包含了 Istio 的 Chart，官方提供了两种方法：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;用 Helm 生成 istio.yaml，然后自行安装。&lt;/li&gt;
&lt;li&gt;用 Tiller 直接安装。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;很明显，两种方法并没有什么本质区别。例如第一个命令：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;helm template install/kubernetes/helm/istio \
    --name istio --namespace  \
    istio-system &amp;gt; $HOME/istio.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这里说的是使用 &lt;code&gt;install/kubernetes/helm/istio&lt;/code&gt; 目录中的 Chart 进行渲染，生成的内容保存到 &lt;code&gt;$HOME/istio.yaml&lt;/code&gt; 文件之中。而第二个命令&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;helm template install/kubernetes/helm/istio \
    --name istio --namespace istio-system \
    --set sidecarInjectorWebhook.enabled=false &amp;gt; $HOME/istio.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;只是设置了 Chart 中的一个变量 &lt;code&gt;sidecarInjectorWebhook.enabled&lt;/code&gt; 为 False。从而禁止自动注入属性生效。&lt;/p&gt;

&lt;p&gt;我们照猫画虎，看看命令二的结果提交到 Kubernetes 中会发生什么事情。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;helm template install/kubernetes/helm/istio --name istio \
--namespace istio-system --set sidecarInjectorWebhook.enabled=false &amp;gt; $HOME/istio.yaml

kubectl create namespace istio-system
kubectl create -f $HOME/istio.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;根据不同的网络情况，可能需要几分钟的等待，最后会看到这些 Pod 在运行：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;istio-citadel-ff5696f6f-h4rdz
istio-cleanup-old-ca-rp5p6
istio-egressgateway-58d98d898c-5jnpz
istio-ingress-6fb78f687f-wsl5q
istio-ingressgateway-6bc7c7c4bc-hhrh7
istio-mixer-post-install-d2kl5
istio-pilot-6c5c6b586c-dqv2w
istio-policy-5c7fbb4b9f-xmv6f
istio-statsd-prom-bridge-6dbb7dcc7f-27tx7
istio-telemetry-54b5bf4847-9gpr7
prometheus-586d95b8d9-gb846
&lt;/code&gt;&lt;/pre&gt;

&lt;ol&gt;
&lt;li&gt;过去的 istio-ca 现已更名 istio-citadel。&lt;/li&gt;
&lt;li&gt;istio-cleanup-old-ca 是一个 job，用于清理过去的 Istio 遗留下来的 CA 部署（包括 sa、deploy 以及 svc 三个对象）。&lt;/li&gt;
&lt;li&gt;istio-mixer-post-install 同样也是一个 job，和上面的 Job 一样，简单的调用 kubectl 创建第三方资源，从而避免了之前的 CDR 需要重复创建的尴尬状况。&lt;/li&gt;
&lt;li&gt;egressgateway、ingress 以及 ingressgateway，可以看出边缘部分的变动很大，以后会另行发文。&lt;/li&gt;
&lt;li&gt;和从前不同，缺省已经打开了监控界面。&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&#34;helm-chart-的安装配置&#34;&gt;Helm Chart 的安装配置&lt;/h3&gt;

&lt;p&gt;下面的配置项目，都可以使用 helm 的 &lt;code&gt;--set key=value&lt;/code&gt; 来设置，可以重复使用，用来设置多个值。&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;选项&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;th&gt;缺省值&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;global.hub&lt;/td&gt;
&lt;td&gt;绝大部分镜像所在的镜像库地址&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker.io/istionightly&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;global.tag&lt;/td&gt;
&lt;td&gt;Istio 使用的绝大部分镜像的 Tag&lt;/td&gt;
&lt;td&gt;&lt;code&gt;circleci-nightly&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;global.proxy.image&lt;/td&gt;
&lt;td&gt;指定 Proxy 的镜像名称&lt;/td&gt;
&lt;td&gt;&lt;code&gt;proxyv2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;global.imagePullPolicy&lt;/td&gt;
&lt;td&gt;镜像拉取策略&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IfNotPresent&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;global.controlPlaneSecurityEnabled&lt;/td&gt;
&lt;td&gt;控制面是否启动 mTLS&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;global.mtls.enabled&lt;/td&gt;
&lt;td&gt;服务间是否缺省启用 mTLS&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;global.mtls.mtlsExcludedServices&lt;/td&gt;
&lt;td&gt;禁用 mTLS 的 FQDN 列表&lt;/td&gt;
&lt;td&gt;&lt;code&gt;- kubernetes.default.svc.cluster.local&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;global.rbacEnabled&lt;/td&gt;
&lt;td&gt;是否创建 RBAC 规则&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;global.refreshInterval&lt;/td&gt;
&lt;td&gt;Mesh 发现间隔&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10s&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;global.arch.amd64&lt;/td&gt;
&lt;td&gt;amd64 架构中的调度策略，0：never；1: least preferred；2：no preference；3：most preferred&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;global.arch.s390x&lt;/td&gt;
&lt;td&gt;amd64 架构中的调度策略，0：never；1: least preferred；2：no preference；3：most preferred&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;global.arch.ppc64le&lt;/td&gt;
&lt;td&gt;amd64 架构中的调度策略，0：never；1: least preferred；2：no preference；3：most preferred&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;galley.enabled&lt;/td&gt;
&lt;td&gt;是否安装 Galley 用于进行服务端的配置验证，需要 1.9 版本以上的 Kubernetes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;上面的内容来自&lt;a href=&#34;https://istio.io/docs/setup/kubernetes/helm-install/&#34; target=&#34;_blank&#34;&gt;官方文档&lt;/a&gt;，其实这是不符合实际情况的（Istio 用户的日常）。在 &lt;code&gt;install/kubernetes/helm/istio/values.yaml&lt;/code&gt; 中，包含这一发行版本中的所有的缺省值。可以直接修改或者新建 values.yaml，并在 helm 命令行使用 &lt;code&gt;-f my-values.yaml&lt;/code&gt; 参数来生成自行定制的 &lt;code&gt;istio.yaml&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&#34;解读-istio-helm-chart-中的模块&#34;&gt;解读 Istio Helm Chart 中的模块&lt;/h2&gt;

&lt;p&gt;打开 Istio 的 Chart 之后，发现其中并没有任何组件的内容，只有两个 Configmap 对象的模板。其安装主体再次很非主流的通过依赖 Chart 的方式实现了完全的模块化。因此这个 Chart 的主体，实际上是 &lt;code&gt;requirements.yaml&lt;/code&gt;，打开这个文件，会看到规规矩矩的列出很多模块，例如：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;  - name: sidecarInjectorWebhook
    version: 0.8.0
    # repository: file://../sidecarInjectorWebhook
    condition: sidecarInjectorWebhook.enabled
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这表明在 &lt;code&gt;sidecarInjectorWebhook&lt;/code&gt; 取值为 &lt;code&gt;enabled&lt;/code&gt; 的时候，就渲染这一模板。因此这里可以看做是模块的启用停用的控制点。这里列出的模块包括：&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;模块&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;egressgateway&lt;/td&gt;
&lt;td&gt;外发流量网关&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;galley&lt;/td&gt;
&lt;td&gt;在 K8S 服务端验证 Istio 的 CRD 资源的合法性&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;grafana&lt;/td&gt;
&lt;td&gt;Dashboard&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;ingress&lt;/td&gt;
&lt;td&gt;Ingress Controller&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;ingressgateway&lt;/td&gt;
&lt;td&gt;Ingress Gateway&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;mixer&lt;/td&gt;
&lt;td&gt;Mixer&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;pilot&lt;/td&gt;
&lt;td&gt;Pilot&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;prometheus&lt;/td&gt;
&lt;td&gt;Prometheus&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;security&lt;/td&gt;
&lt;td&gt;安全相关内容&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;servicegraph&lt;/td&gt;
&lt;td&gt;调用关系图&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;sidecarInjectorWebhook&lt;/td&gt;
&lt;td&gt;自动注入&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;tracing&lt;/td&gt;
&lt;td&gt;Zipkin Jeager 的跟踪服务&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;下面逐一做一下简要说明&lt;/p&gt;

&lt;h3 id=&#34;egressgateway&#34;&gt;egressgateway&lt;/h3&gt;

&lt;p&gt;外发通信的网关。&lt;/p&gt;

&lt;p&gt;他的设置保存在 &lt;code&gt;values.yaml&lt;/code&gt; 的 &lt;code&gt;egressgateway&lt;/code&gt; 一节中（都是保存在同名分支下，后面不再重复）。部署内容包括：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deployment 和 Service：一个 proxy。&lt;/li&gt;
&lt;li&gt;HPA&lt;/li&gt;
&lt;li&gt;RBAC 相关内容&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;可定制项目包括：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;服务端口和类型&lt;/li&gt;
&lt;li&gt;HPA 实例数量上下限&lt;/li&gt;
&lt;li&gt;资源限制&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;galley&#34;&gt;galley&lt;/h3&gt;

&lt;p&gt;之前的 istio 版本中，只能通过 istioctl 验证 Istio 相关 CRD 的有效性，这个模块提供一个在服务端验证 CRD 的方法，他的部署内容包含：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deployement 和 Service。&lt;/li&gt;
&lt;li&gt;RBAC 相关&lt;/li&gt;
&lt;li&gt;用于 CRD 校验的 ValidatingWebhookConfiguration 对象。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;校验目标包含 Pilot（例如 destinationpolicies 和 routerules） 和 Mixer（例如 memquotas 和 prometheuses） 两类 CRD。&lt;/p&gt;

&lt;h3 id=&#34;grafana&#34;&gt;grafana&lt;/h3&gt;

&lt;p&gt;一个带有 Istio 定制 Dashboard 的 Grafana 封装。&lt;/p&gt;

&lt;p&gt;实际上将其镜像中的 Dashboard 复制出来就可以在其他 Grafana 实例上运行了。&lt;/p&gt;

&lt;p&gt;定制内容的 &lt;code&gt;grafana.ingress.*&lt;/code&gt; 中包含 Ingress 的配置，用于外网访问。&lt;/p&gt;

&lt;h3 id=&#34;ingress&#34;&gt;ingress&lt;/h3&gt;

&lt;p&gt;Istio 的 Ingress Controller&lt;/p&gt;

&lt;p&gt;具体部署内容和 egresscontroller 基本一致。&lt;/p&gt;

&lt;h3 id=&#34;ingressgateway&#34;&gt;ingressgateway&lt;/h3&gt;

&lt;p&gt;0.8.0 新增功能，为 Ingress 通信提供 Istio rules/destination 等特性。&lt;/p&gt;

&lt;p&gt;部署内容和 ingress 类似。&lt;/p&gt;

&lt;h3 id=&#34;mixer&#34;&gt;mixer&lt;/h3&gt;

&lt;p&gt;Mixer 负责的是遥测和前置检查，他的 Chart 相对比较复杂，部署内容包括：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;和前面的版本不同，Mixer 的部署分成了两个部分，分别是 Policy 和 Telemetry 两个 Deployment 对象。&lt;/li&gt;
&lt;li&gt;Service 也同样分成两个，其中 telemetry service 多了一个 prometheus 端口&lt;/li&gt;
&lt;li&gt;&lt;code&gt;crds.yaml&lt;/code&gt; 中包含了 mixer 所支持的所有 crd 定义（例如 memquotas 和 prometheuses）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;create-custom-resources-job.yaml&lt;/code&gt; 中包含了用于创建 crd 的 Job 对象。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;pilot&#34;&gt;pilot&lt;/h3&gt;

&lt;p&gt;Pilot 承上启下，负责服务发现和向 Proxy 下发配置。除了常规的 Deployment 和 Service 之外，还包含了 &lt;code&gt;crds.yaml&lt;/code&gt;，用于声明 CRD 资源类型（例如 destinationpolicies 和 routerules）。&lt;/p&gt;

&lt;h3 id=&#34;prometheus&#34;&gt;prometheus&lt;/h3&gt;

&lt;p&gt;这个组件跟前面的 Grafana 类似，也是一个预定义的镜像。这个模板中的 Configmap 就是 Prometheus 的抓取配置，可以直接用到其他的 Prometheus 实例之中。&lt;/p&gt;

&lt;h3 id=&#34;security&#34;&gt;security&lt;/h3&gt;

&lt;p&gt;旧版本中的 Istio-ca&lt;/p&gt;

&lt;p&gt;Security 部分的部署内容包括：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RBAC&lt;/li&gt;
&lt;li&gt;Job：使用 kubectl 清理旧版本 istio-ca 实例。&lt;/li&gt;
&lt;li&gt;Deployment，原 CA。&lt;/li&gt;
&lt;li&gt;Service：开放两个端口，分别服务于 http 和 gRPC。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;servicegraph&#34;&gt;servicegraph&lt;/h3&gt;

&lt;p&gt;Service Graph 支持，和 Grafana 基本一致。&lt;/p&gt;

&lt;h3 id=&#34;sidecarinjectorwebhook&#34;&gt;sidecarInjectorWebhook&lt;/h3&gt;

&lt;p&gt;这一部分的功能是自动为 K8S 对象注入 Envoy。主要包含：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deployment 和 Service&lt;/li&gt;
&lt;li&gt;RBAC 相关&lt;/li&gt;
&lt;li&gt;一个 &lt;code&gt;MutatingWebhookConfiguration&lt;/code&gt; 对象，会监听 Pod 的创建事件，用于自动注入。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;tracing&#34;&gt;tracing&lt;/h3&gt;

&lt;p&gt;Jeager 的跟踪支持，总体情况跟 Prometheus 和 Grafana 等监控组件类似，配置项和暴露服务方面稍有区别：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;配置中包含 Jaeger 的环境变量的控制。&lt;/li&gt;
&lt;li&gt;开启 jaeger 开关，会启用 Jaeger 的几个服务端口。&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Conduit 0.4.0：流量都去哪了？</title>
      <link>/post/conduit-0.4.0-monitor/</link>
      <pubDate>Sat, 21 Apr 2018 18:49:25 +0800</pubDate>
      <guid>/post/conduit-0.4.0-monitor/</guid>
      <description>

&lt;p&gt;原文：&lt;a href=&#34;https://buoyant.io/2018/04/20/conduit-0-4-0-wheres-my-traffic/&#34; target=&#34;_blank&#34;&gt;Conduit 0.4.0: Where’s my traffic?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;本周早些时候我们发布了 &lt;a href=&#34;https://github.com/runconduit/conduit/releases/tag/v0.4.0&#34; target=&#34;_blank&#34;&gt;Conduit v0.4.0&lt;/a&gt;，这一版本在基于 Prometheus 的遥测系统方面，有了很大进步；同时还给微服务的除错提供了新的工具。&lt;/p&gt;

&lt;p&gt;安装后的一分钟里，Conduit 给每个 Kubernetes 部署都提供了一个预配置的 Grafana Dashboard。这些 Dashboard 不只是成功率、请求量以及每服务延迟等常见指标，他还将每个指标按照依赖关系进行了分解。这样你就可以在不修改应用的情况下，轻松地回答“这个服务的流量是从哪里来的？”或者 “Foo 调用 Bar 的成功率如何”之类的问题了。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;img/dashboard.png&#34; alt=&#34;conduit-dashboard-deploy/web&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;我的流量呢&#34;&gt;我的流量呢？&lt;/h2&gt;

&lt;p&gt;在一个微服务形态的应用中，运行中的服务之间的依赖关系是很重要的问题。每服务成功率固然重要，流入服务的请求来自何处同样是不可忽视的问题，更不必说依赖服务的故障情况了。通常这些问题都是最难回答的，但是现在我们有了 Conduit 的帮助，就有机会对这些问题进行简化了。&lt;/p&gt;

&lt;p&gt;为了达成这一目标，0.4.0 中我们把 Conduit 的遥测系统中指标的获取改为拉取方式来实现。这一过程中我们还把 Conduit 的 Rust 代理进行了改进，他的指标中描述了所有请求的源、目的以及健康状况。拉取方式获取指标，降低了代理的复杂度，更加贴近 Prometheus 的生态情况。&lt;/p&gt;

&lt;p&gt;这样，Conduit 的遥测系统现在非常稳定。能深入到 Kubernetes 中任何两个 Deployment、Pod 或者命名空间之间的请求频率、成功率以及延迟等指标。还可以使用 Prometheus 进行各种查询。当然了，我们还把所有的这些集成到了 CLI 工具中，微服务中的 “TOP” 命令，想过么？&lt;/p&gt;

&lt;h2 id=&#34;动手环节&#34;&gt;动手环节&lt;/h2&gt;

&lt;p&gt;我们现在来运行一个简单的例子（要看完整的安装介绍，请参考 &lt;a href=&#34;https://conduit.io/getting-started/&#34; target=&#34;_blank&#34;&gt;Conduit 起步指南&lt;/a&gt;）。&lt;/p&gt;

&lt;p&gt;首先安装 Conduit CLI：&lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl https://run.conduit.io/install | sh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;然后在 Kubernetes 中安装 Conduit：&lt;/p&gt;

&lt;p&gt;&lt;code&gt;conduit install | kubectl apply -f -&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;最后，安装 &lt;code&gt;emojivoto&lt;/code&gt; 演示应用，并且将其加入 Conduit Mesh：&lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl https://raw.githubusercontent.com/runconduit/conduit-examples/master/emojivoto/emojivoto.yml | conduit inject - | kubectl apply -f -&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;演示应用中包含了一个 &lt;code&gt;vote-bot&lt;/code&gt; 服务，不断地在产生流量。这个基于 AI 的机器人在为他最喜欢的表情进行投票，他会变得越来越精明。所以为了安全起见，我们建议你不要让他长期运行。&lt;/p&gt;

&lt;p&gt;让我们看看如何用 Conduit 在演示应用中获取流量走向：&lt;/p&gt;

&lt;p&gt;先看看 Web 服务（确切的说是 Web Deployment）在做什么：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;$ conduit stat -n emojivoto deployment web
NAME  MESHED  SUCCESS     RPS    LATENCY_P50  LATENCY_P95  LATENCY_P99
web      1/1   90.00%  2.0rps            2ms          4ms          9ms
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;voting&lt;/code&gt; 服务只有一个调用者，就是 &lt;code&gt;web&lt;/code&gt; 服务。所以通过跟踪 Web 的依赖项，我们有了第一个需要监测的目标：&lt;code&gt;voting&lt;/code&gt; 服务在被 &lt;code&gt;web&lt;/code&gt; 服务调用的时候，有 83% 的成功率，这样我们就可以看看日志、跟踪或进行其他深入观察。&lt;/p&gt;

&lt;p&gt;这只是 Conduit 众多功能中的一个例子。如果想要进一步探索，可以看看所有命名空间的成功率；各个命名空间以及每个 Deployment 调用某一命名空间的成功率；甚至是 Conduit 组件自身的成功率。&lt;/p&gt;

&lt;p&gt;在 &lt;code&gt;https://youtu.be/R5UDKgX72tg&lt;/code&gt; 还有我们录制的一个关于 Conduit 0.4 的视频。&lt;/p&gt;

&lt;h2 id=&#34;下一步&#34;&gt;下一步&lt;/h2&gt;

&lt;p&gt;我们的未来版本，会把指标和遥测能力扩展到其他的 Kubernetes 对象，例如 Pod 和 RS。另外我们还会把 &lt;code&gt;conduit tap&lt;/code&gt; 命令也应用到这些对象上，让 &lt;code&gt;stat&lt;/code&gt; 和 &lt;code&gt;tap&lt;/code&gt; 完美配合。我们可能还会逐步为 Conduit 加入更多命令，来增强 Conduit 的遥测能力，敬请期待！&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Conduit v0.2.0 发布</title>
      <link>/post/conduit-v0.2-ann/</link>
      <pubDate>Thu, 01 Feb 2018 18:27:52 +0800</pubDate>
      <guid>/post/conduit-v0.2-ann/</guid>
      <description>

&lt;p&gt;原文：&lt;a href=&#34;https://buoyant.io/2018/02/01/announcing-conduit-support-http-1-x-tcp/&#34; target=&#34;_blank&#34;&gt;Announcing Conduit support for HTTP/1.x and TCP&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;里程碑版本，这次发布中新增了对 HTTP/1.x 和 TCP 支持，这样就可以为绝大多数运行在 Kubernetes 上的应用提供支持了。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;数据面

&lt;ul&gt;
&lt;li&gt;Conduit 现在为包括 HTTP/1.x 和 HTTP/2 在内的所有 TCP 流量提供透明代理。&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;控制台界面

&lt;ul&gt;
&lt;li&gt;强化了 &lt;code&gt;tap&lt;/code&gt; 命令的错误处理能力。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tap&lt;/code&gt; 也提供了对 HTTP/1.x 的支持。&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Dashboard

&lt;ul&gt;
&lt;li&gt;界面进行了小幅更新。&lt;/li&gt;
&lt;li&gt;可以在 Dashboard 边栏搜索 Deployment。&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;预告&#34;&gt;预告&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Conduit 将会为绝大多数协议提供自动支持，然而使用 WebSockets、HTTP 隧道/代理或者 MySQL、SMTP 等协议，需要一些额外配置，&lt;a href=&#34;https://conduit.io/adding-your-service/#protocol-support&#34; target=&#34;_blank&#34;&gt;文档（注 1）&lt;/a&gt;中会有详细说明。&lt;/li&gt;
&lt;li&gt;Conduit 还不支持外部 DNS。这一缺憾将在未来版本提供支持。&lt;/li&gt;
&lt;li&gt;目前 Conduit 的遥测管线无法扩展到某些节点，后续版本会解决这个问题。&lt;/li&gt;
&lt;li&gt;Conduit 还是 Alpha 阶段，请&lt;a href=&#34;https://github.com/runconduit/conduit/issues/new&#34; target=&#34;_blank&#34;&gt;提交 Issue 或 PR 来支持我们（注 2）&lt;/a&gt;！&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;引用：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;https://conduit.io/adding-your-service/#protocol-support&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://github.com/runconduit/conduit/issues/new&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
    <item>
      <title>Conduit 登场</title>
      <link>/post/conduit-ann/</link>
      <pubDate>Wed, 06 Dec 2017 09:46:58 +0800</pubDate>
      <guid>/post/conduit-ann/</guid>
      <description>

&lt;p&gt;原文：&lt;a href=&#34;https://buoyant.io/2017/12/05/introducing-conduit/&#34; target=&#34;_blank&#34;&gt;Introducing Conduit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;今天我们要介绍 &lt;a href=&#34;http://conduit.io/&#34; target=&#34;_blank&#34;&gt;Conduit&lt;/a&gt;，面向 Kubernetes 的新的开源 Service Mesh。&lt;/p&gt;

&lt;p&gt;Conduit 横空出世，目标是成为最快、最轻、最简单并且最安全的 Service Mesh。他使用 &lt;a href=&#34;https://www.rust-lang.org/&#34; target=&#34;_blank&#34;&gt;Rust&lt;/a&gt; 构建了快速、安全的数据平面，用 &lt;a href=&#34;https://golang.org/&#34; target=&#34;_blank&#34;&gt;Go&lt;/a&gt; 开发了简单强大的控制平面，总体设计围绕着性能、安全性和可用性进行。更重要的是，Conduit 将会完全吸收过去 18 个月中，我们在 Linkerd 的生产级 Service Mesh 中积累沉淀的真实经验。&lt;/p&gt;

&lt;p&gt;为什么要做一个 Conduit？Linkerd 是世界上最多生产级部署的 Service Mesh。这一产品创造了 &amp;ldquo;Service Mesh&amp;rdquo; 这一词汇，在软件基础设施中成功的开辟了新的领域，为遍及全球的企业客户（例如 Salesforce、Paypal、Expedia、AOL 以及 Monzo）承载了数以万亿计的请求。这一段时间里，我们和客户以及用户们甘苦与共——我们一起开会，设计交叉路线图，凌晨三点起床救火。开源的基础设施和现实世界的对撞中，我们学到了弥足珍贵的经验和教训。&lt;/p&gt;

&lt;p&gt;这中间有个突出的问题就是，Linkerd 的部署模型太重了。虽然 Linkerd 的各个组件，例如 Finagle、Netty、Scala 以及 JVM，都是被广泛采用千锤百炼的，有了这些组件的帮助，在有足够 CPU 和内存支持的情况下，Linkerd 能够达到非常高的负载能力；然而设计过程中鲜有考虑在有限的资源情况下，基于 sidecar 模式的 Kubernetes 部署方式。所以今年年初，我们自问：有了 18 个月的生产级 Service Mesh 的经验，如果要做出一个功能完备又可以在低资源环境下运行的 Service Mesh，我们会怎么做？&lt;/p&gt;

&lt;p&gt;答案就是 Conduit。和 Linkerd 类似，Conduit 是让微服务安全可靠的下一代 Service Mesh。他能透明的管理服务之间的通信，自动提供可测性、可靠性、安全性和弹性的支持。还是跟 Linkerd 相仿，他的数据平面是在应用代码之外运行的轻量级代理，控制平面是一个高可用的控制器。然而和 Linkerd 不同的是，Conduit 的设计更加倾向于 Kubernetes 中的低资源部署。&lt;/p&gt;

&lt;p&gt;Conduit 为什么伟大（hhhhh）：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;轻量高速：Conduit 代理只需要不到 10 MB 实际内存（RSS），p99 延迟在分毫秒以内。&lt;/li&gt;
&lt;li&gt;安全：Rust 的内存使用相当安全，同时还缺省使用了 TLS，Conduit 的安全性与生俱来。&lt;/li&gt;
&lt;li&gt;最小化：Conduit 的特性集被设计为尽量的最小化和可编排，便于使用 gRPC 插件进行定制。&lt;/li&gt;
&lt;li&gt;易用性：内置有聚合的服务指标，强大的客户端工具（想想看，微服务界的 tcpdump），Conduit 为运维人员提供了新的强大的工具来对付生产环境的微服务。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;过去半年中我们一直在努力的构建 Conduit。我们聘请了 &lt;a href=&#34;http://philcalcado.com/&#34; target=&#34;_blank&#34;&gt;Phil&lt;/a&gt;、&lt;a href=&#34;https://github.com/carllerche&#34; target=&#34;_blank&#34;&gt;Carl&lt;/a&gt;、&lt;a href=&#34;http://seanmonstar.com/&#34; target=&#34;_blank&#34;&gt;Sean&lt;/a&gt; 以及 &lt;a href=&#34;https://briansmith.org/&#34; target=&#34;_blank&#34;&gt;Brain&lt;/a&gt; 这样的高手；向 &lt;a href=&#34;https://github.com/tokio-rs/tokio&#34; target=&#34;_blank&#34;&gt;Tokio&lt;/a&gt; 和 &lt;a href=&#34;https://github.com/BuoyantIO/tower&#34; target=&#34;_blank&#34;&gt;Tower&lt;/a&gt; 这样的核心技术投资，让 Conduit 又快又安全。最重要的是，我们决心用 Conduit 解决在 Linkerd 社区遇到的实际问题。&lt;/p&gt;

&lt;h2 id=&#34;linkerd-怎么办&#34;&gt;Linkerd 怎么办？&lt;/h2&gt;

&lt;p&gt;简单说说，Linkerd 是世界上最广泛在生产环境进行使用的 Service Mesh，他会长期存在，我们会持续的进行开发、管理并提供商业支持；我们会保证我们的 Linkerd 用户的幸福感。&lt;/p&gt;

&lt;p&gt;Conduit 不是 Linkerd 2.0。Conduit 面向的是非常特定的环境 —— Kubernetes，而不准备像 Linkerd 一样做出众多的集成支持。我们的大量用户在使用 ECS、Consul、Mesos、ZooKeeper、Nomad、Rancher 或者混合的多环境系统，Linkerd 是目前的最好选择，我们会持续投入进行改善。&lt;/p&gt;

&lt;h2 id=&#34;现在开始&#34;&gt;现在开始！&lt;/h2&gt;

&lt;p&gt;我们刚刚发布了 Conduit 0.1。&lt;a href=&#34;https://conduit.io/&#34; target=&#34;_blank&#34;&gt;来跳坑吧&lt;/a&gt;！目前这是个 Alpha 版本，所以理直气壮的仅提供 HTTP/2 的支持（是的，HTTP/1.1 都不支持）。我们希望我们的早期用户能够尽早接触 Conduit，并从中获得反馈。&lt;/p&gt;

&lt;p&gt;接下来的几个月中，我们会积极工作，推进 Conduit 的生产化进程，预计来年初面世的 0.2 中，会加入 HTTP/1.1 和 TCP 的支持（&lt;a href=&#34;https://conduit.io/roadmap/&#34; target=&#34;_blank&#34;&gt;路线图&lt;/a&gt;）。这一产品的进展和目标会非常公开。最后，我们还会提供 Conduit 的商业支持，如果有兴趣的话可以&lt;a href=&#34;mailto:hello@buoyant.io&#34; target=&#34;_blank&#34;&gt;联系我们&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;想要了解更多？可以订阅我们的发布通知邮件列表，加入 &lt;a href=&#34;http://slack.linkerd.io/?__hstc=9342122.eea97f52bb4b2bba60b0c11bd6dc7c15.1506617171339.1510149418766.1512491813854.6&amp;amp;__hssc=9342122.1.1512491813854&amp;amp;__hsfp=3751614787&#34; target=&#34;_blank&#34;&gt;Linkerd 的 Slack 频道&lt;/a&gt;，或者 Follow &lt;a href=&#34;https://twitter.com/runconduit&#34; target=&#34;_blank&#34;&gt;@runconduit&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;Conduit 是基于 Apache 2.0 协议的开源软件。&lt;/p&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>
    
    <item>
      <title>istio 三日谈之一，环境准备</title>
      <link>/post/istio-env-prepare/</link>
      <pubDate>Fri, 28 Jul 2017 07:00:12 +0800</pubDate>
      <guid>/post/istio-env-prepare/</guid>
      <description>

&lt;p&gt;笔者尝试在一个准生产环境下，利用 istio 来对运行在 Kubernetes 上的微服务进行管理。&lt;/p&gt;

&lt;p&gt;这一篇是第一篇，将一些主要的坑和环境准备工作。&lt;/p&gt;

&lt;p&gt;内容较多，因此无法写成手把手教程，希望读者有一定 Kubernetes 的操作基础。&lt;/p&gt;

&lt;h2 id=&#34;准备镜像&#34;&gt;准备镜像&lt;/h2&gt;

&lt;p&gt;初始运行需要的镜像包括以下几个：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;istio/mixer:0.1.6&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pilot:0.1.6&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;proxy_debug:0.1.6&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;istio-ca:0.1.6&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;首先要解决的自然还是镜像的存放问题，官方在源码中提供了很方便的工具，用来根据模板生成在 Kubernetes 中运行 istio 的 YAML 文件：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;./updateVersion.sh \
	-p 10.211.55.86:5000/istio,0.1.6 \
	-c 10.211.55.86:5000/istio,0.1.6 \
	-x 10.211.55.86:5000/istio,0.1.6
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这一脚本在源码的 install 目录下。&lt;/p&gt;

&lt;h2 id=&#34;kubernetes-环境&#34;&gt;Kubernetes 环境&lt;/h2&gt;

&lt;p&gt;这里我们使用的集群大概情况是：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1.7.1 版本的 Kubernetes&lt;/li&gt;
&lt;li&gt;开启了 RBAC&lt;/li&gt;
&lt;li&gt;预备使用的命名空间为：default&lt;/li&gt;
&lt;li&gt;PVC 自动供给&lt;/li&gt;
&lt;li&gt;无互联网连接&lt;/li&gt;
&lt;li&gt;具有自己的私库&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;启动-istio&#34;&gt;启动 istio&lt;/h2&gt;

&lt;h3 id=&#34;rbac-相关&#34;&gt;RBAC 相关&lt;/h3&gt;

&lt;p&gt;首先，install 目录中提供的 rbac 文件授权范围不足，所以需要手工编辑&lt;code&gt;istio-rbac-beta.yaml&lt;/code&gt;，把其中的几个 RoleBinding，改为 ClusterRoleBinding。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;kubectl create \
	-f istio-rbac-beta.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;另外缺省的 ClusterRole 中缺乏对 Namespace 的权限，新版本已经修正，目前版本仍需添加：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: istio-pilot
rules:
- apiGroups: [&amp;quot;istio.io&amp;quot;]
  resources: [&amp;quot;istioconfigs&amp;quot;, &amp;quot;istioconfigs.istio.io&amp;quot;]
  verbs: [&amp;quot;*&amp;quot;]
- apiGroups: [&amp;quot;extensions&amp;quot;]
  resources: [&amp;quot;thirdpartyresources&amp;quot;, &amp;quot;thirdpartyresources.extensions&amp;quot;, &amp;quot;ingresses&amp;quot;, &amp;quot;ingresses/status&amp;quot;]
  verbs: [&amp;quot;*&amp;quot;]
- apiGroups: [&amp;quot;&amp;quot;]
  resources: [&amp;quot;configmaps&amp;quot;, &amp;quot;endpoints&amp;quot;, &amp;quot;pods&amp;quot;, &amp;quot;services&amp;quot;]
  verbs: [&amp;quot;*&amp;quot;]
- apiGroups: [&amp;quot;&amp;quot;]
  resources: [&amp;quot;namespaces&amp;quot;, &amp;quot;nodes&amp;quot;, &amp;quot;secrets&amp;quot;]
  verbs: [&amp;quot;get&amp;quot;, &amp;quot;list&amp;quot;, &amp;quot;watch&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;启动-istio-组件&#34;&gt;启动 istio 组件&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;kubectl create \
	-f istio.yaml \
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;创建-pvc&#34;&gt;创建 PVC&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: frontend-v1
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;准备工作负载&#34;&gt;准备工作负载&lt;/h2&gt;

&lt;p&gt;这里我们使用官方的 PHP + Apache 镜像作为工作负载来进行下面的测试，例如我们准备好的 YAML 如下：&lt;/p&gt;

&lt;p&gt;Deployment：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: frontend
  labels:
    name: frontend
    version: &amp;quot;1&amp;quot;
spec:
  replicas: 1
  template:
    metadata:
      labels:
        name: frontend
        version: &amp;quot;1&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;1&amp;quot;      
     	volumes:
      - name: wwwroot
        persistentVolumeClaim:
          claimName: frontend-v1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;服务定义：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;kind: Service
apiVersion: v1
metadata:
  name: svc-frontend
  labels:
    name: frontend
    version: &amp;quot;1&amp;quot;
spec:
  type: NodePort
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
    nodePort: 32010  
  selector:
    name: frontend

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

&lt;p&gt;在 Web 目录中我们随便做了个&lt;code&gt;index.php&lt;/code&gt;，用来展示当前所在 Pod 和环境变量中的服务版本号，备用。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tips：一般这类测试，我都懒得重新做一个 Docker 镜像，一般是另外用一个 Pod 挂载同一个 PVC，直接编辑页面文件，或者使用&lt;code&gt;kubectl cp&lt;/code&gt;命令进行拷贝。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;index-php&#34;&gt;index.php&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-php&#34;&gt;&amp;lt;?php
header(&amp;quot;Content-type: text/plain&amp;quot;);
echo &amp;quot;From: &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;h3 id=&#34;delay-php&#34;&gt;delay.php&lt;/h3&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;运行成功后，访问该服务的 nodePort，会看到相应的输出内容。&lt;/p&gt;

&lt;h2 id=&#34;istio-的注入&#34;&gt;istio 的注入&lt;/h2&gt;

&lt;p&gt;首先用&lt;code&gt;kubectl delete -f&lt;/code&gt;删除上文的服务和 Deployment。&lt;/p&gt;

&lt;p&gt;上面为了测试方便，给 Service 使用了 NodePort 类型，这里我们去掉这一服务的 NodePort，用 ClusterIP 的形式运行：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  selector:
    name: frontend
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;接下来进行注入操作&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;istioctl kube-inject -f frontend-v1.yaml &amp;gt; frontend-v1-istio.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;观察注入操作会发现，其中多了一个 Sidecar Container（下面的 Image 节内容已经被我修改为本地私库）：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;    env:
    - name: POD_NAME
      valueFrom:
        fieldRef:
          fieldPath: metadata.name
    - name: POD_NAMESPACE
      valueFrom:
        fieldRef:
          fieldPath: metadata.namespace
    - name: POD_IP
      valueFrom:
        fieldRef:
          fieldPath: status.podIP
    image: 10.211.55.86:5000/istio/proxy_debug:0.1.6
    imagePullPolicy: Always
    name: proxy
    resources: {}
    securityContext:
      runAsUser: 1337
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;另外还在&lt;code&gt;pod.beta.kubernetes.io/init-containers&lt;/code&gt;注解中进行了初始化：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;[{
  &amp;quot;args&amp;quot;: [&amp;quot;-p&amp;quot;, &amp;quot;15001&amp;quot;, &amp;quot;-u&amp;quot;, &amp;quot;1337&amp;quot;],
  &amp;quot;image&amp;quot;: &amp;quot;10.211.55.86:5000/istio/init:0.1&amp;quot;,
  &amp;quot;imagePullPolicy&amp;quot;: &amp;quot;Always&amp;quot;,
  &amp;quot;name&amp;quot;: &amp;quot;init&amp;quot;,
  &amp;quot;securityContext&amp;quot;: {
    &amp;quot;capabilities&amp;quot;: {
      &amp;quot;add&amp;quot;: [&amp;quot;NET_ADMIN&amp;quot;]
    }
  }
}, {
  &amp;quot;args&amp;quot;: [&amp;quot;-c&amp;quot;, &amp;quot;sysctl -w kernel.core_pattern=/tmp/core.%e.%p.%t &amp;amp;&amp;amp; ulimit -c unlimited&amp;quot;],
  &amp;quot;command&amp;quot;: [&amp;quot;/bin/sh&amp;quot;],
  &amp;quot;image&amp;quot;: &amp;quot;10.211.55.86:5000/alpine&amp;quot;,
  &amp;quot;imagePullPolicy&amp;quot;: &amp;quot;Always&amp;quot;,
  &amp;quot;name&amp;quot;: &amp;quot;enable-core-dump&amp;quot;,
  &amp;quot;securityContext&amp;quot;: {
    &amp;quot;privileged&amp;quot;: true
  }
}]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;可以看到上面一共涉及三个镜像：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;docker.io/istio/proxy_debug:0.1&lt;/li&gt;
&lt;li&gt;docker.io/istio/init:0.1&lt;/li&gt;
&lt;li&gt;alpine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;经过一番折腾：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;原有 YAML&lt;/li&gt;
&lt;li&gt;注入，生成新的 YAML&lt;/li&gt;
&lt;li&gt;替换新 YAML 中的镜像地址&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;就把原有的容器应用封装成新的 istio 支持的微服务了。&lt;/p&gt;

&lt;h2 id=&#34;准备测试素材&#34;&gt;准备测试素材&lt;/h2&gt;

&lt;p&gt;另外我们需要准备一个工具服务，用于在 shell 中进行测试：&lt;/p&gt;

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

&lt;p&gt;同样的，这里也需要执行&lt;code&gt;istioctl kube-inject&lt;/code&gt;进行注入，运行之后，就得到一个运行于集群内部的 Linux Shell，&lt;strong&gt;istio 中的路由策略经常是客户端和服务器协同完成的，因此上客户和服务器的 Deployment 都需要进行注入操作&lt;/strong&gt;。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Linkerd &#43; Namerd，实现 Kubernetes 集群的灰度发布</title>
      <link>/post/linerd-on-kubernetes/</link>
      <pubDate>Tue, 14 Feb 2017 06:42:02 +0800</pubDate>
      <guid>/post/linerd-on-kubernetes/</guid>
      <description>

&lt;blockquote&gt;
&lt;p&gt;主要内容源于 &lt;code&gt;https://blog.buoyant.io/2016/11/04/a-service-mesh-for-kubernetes-part-iv-continuous-deployment-via-traffic-shifting/&lt;/code&gt; ，砍掉了 Jenkins 等附加部分，更换了更加易于理解的示例应用，以保证主干突出。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Kubernetes 所提供的 rolling-update 功能提供了一种渐进式的更新过程，然而其滚动过程并不容易控制，对于灰度发布的需要来说，仍稍显不足，这里介绍一种利用 Linkerd 方案进行流量切换的思路。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;官网介绍：linker∙d is a transparent proxy that adds service discovery, routing, failure handling, and visibility to modern software applications。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;本文从实际操作入手，上线两个版本的简单应用，利用这一组合完成流量的切换和测试过程。&lt;/p&gt;

&lt;h2 id=&#34;测试目标&#34;&gt;测试目标&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;同时上线两个版本的应用。两个应用均可工作，利用不同输出进行区分。&lt;/li&gt;
&lt;li&gt;动态调整分配给两个版本的流量。&lt;/li&gt;
&lt;li&gt;利用 CURL 进行流量分配的测试。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;准备工作&#34;&gt;准备工作&lt;/h2&gt;

&lt;p&gt;这里利用一个 1.2 以上版本的 Kubernetes 集群进行演示：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API Server / Registry：10.211.55.62&lt;/li&gt;
&lt;li&gt;Node：10.211.66.63&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;另外因某些原因，需要有能力获取 Dockerhub 的镜像。&lt;/p&gt;

&lt;p&gt;例子程序很简单，用一个 PHP 文件显示环境变量中的内容：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-php&#34;&gt;&amp;lt;?php
echo getenv(&amp;quot;VAR_LABEL&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Docker file 继承自 &lt;code&gt;dustise/lamp:latest&lt;/code&gt;，文件内容如下：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-dockerfile&#34;&gt;FROM dustise/lamp
COPY index.php /web/codebase
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;利用 Docker build 创建镜像，这里命名为 lamp:gray，备用。&lt;/p&gt;

&lt;h2 id=&#34;创建工作负载&#34;&gt;创建工作负载&lt;/h2&gt;

&lt;p&gt;做一个简单的 yaml 文件来加载蓝绿两组应用，名字、环境变量和端口三个位置需要更改：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;---
kind: ReplicationController
apiVersion: v1
metadata:
  name: green
# 此处省略若干
        env:
        - name: VAR_LABEL
          value: &#39;green&#39;
---
kind: Service
apiVersion: v1

# 此处省略若干

  type: NodePort
  ports:
  - protocol: TCP
    nodePort: 32001
    port: 80
    targetPort: 80
    name: http
  selector:
    name: green
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;利用 &lt;code&gt;kubectl create -f green.yaml&lt;/code&gt; （ 以及 blue.yaml ）之后，可以利用 curl 或者浏览器检查运行情况，如果正常，两个端口的访问应该分别会返回 &lt;code&gt;green&lt;/code&gt; 和 &lt;code&gt;blue&lt;/code&gt; ，这里的端口命名很重要，这一名称会被后面的规则引用到。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;注意，这里 NodePort 并非必须，仅为测试方便。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;运行-namerd&#34;&gt;运行 Namerd&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;此处 yaml 主要来自于官网 &lt;code&gt;https://raw.githubusercontent.com/BuoyantIO/linkerd-examples/master/k8s-daemonset/k8s/namerd.yml&lt;/code&gt;
为适应本地环境，将原有 Loadbalancer 类型的服务改为 NodePort&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;略微做一下讲解。&lt;/p&gt;

&lt;p&gt;整个 yaml 由四部分组成：&lt;/p&gt;

&lt;h3 id=&#34;thirdpartyresource&#34;&gt;ThirdPartyResource&lt;/h3&gt;

&lt;p&gt;这部分被用于做 Namerd 的存储后端。&lt;/p&gt;

&lt;h3 id=&#34;configmap&#34;&gt;Configmap&lt;/h3&gt;

&lt;p&gt;作为 Namerd 的配置，其中定义了这样几个内容（详情可参见 &lt;code&gt;https://linkerd.io/config/0.8.5/namerd/index.html#introduction&lt;/code&gt;）：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;管理端口 9990&lt;/li&gt;
&lt;li&gt;storage：存储定义，通过 8001 端口同 Kube Api Server 通信，完成在 ThrdPartyResource 中的访问（8001 端口由 kubectl proxy 指令开通）&lt;/li&gt;
&lt;li&gt;namer：定义服务发现能力由 Kubernetes 提供。&lt;/li&gt;
&lt;li&gt;interface 部分则是定义了两种支持协议。其中 HTTP Controller 可以接收 namerctl 的控制指令。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;rc&#34;&gt;RC&lt;/h3&gt;

&lt;p&gt;这部分不新鲜，除了 namerd 之外，还利用 kubectl proxy 提供通信端口给 namerd，颇有蛇足之嫌。正确的打开方式应该是直接和  Kube API Server 进行通信。&lt;/p&gt;

&lt;h3 id=&#34;service&#34;&gt;Service&lt;/h3&gt;

&lt;p&gt;这里注意服务类型的变更（ LoadBalancer -&amp;gt; NodePort ），需要暴露 4180 和 9990 两个端口，分别作为控制端口和界面端口。&lt;/p&gt;

&lt;p&gt;利用 kubectl 启用之后，就可以在指定的端口查看管理界面了。此时的管理界面没有做任何配置，因此比较单薄。&lt;/p&gt;

&lt;h3 id=&#34;添加规则&#34;&gt;添加规则&lt;/h3&gt;

&lt;p&gt;下面来安装 namerd 的控制工具，namerctl&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;go get -u github.com/buoyantio/namerctl
go install github.com/buoyantio/namerctl
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;接下来创建一条规则：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/host=&amp;gt;/#/io.l5d.k8s/default/http;
/http/*/*/*=&amp;gt;8*/host/blue&amp;amp;2*/host/green;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这段代码表示该服务同时连接 blue 和 green 两个后端服务，按照 &lt;sup&gt;80&lt;/sup&gt;&amp;frasl;&lt;sub&gt;20&lt;/sub&gt; 的比例进行流量分配。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;namerctl dtab create [file name] --base-url&lt;/code&gt;，这里 base-url 取值就是我们给 namerd 设置的 Nodeport。&lt;/p&gt;

&lt;p&gt;接下来就能够看到管理界面上显示出新的规则了。&lt;/p&gt;

&lt;h2 id=&#34;运行-linkerd&#34;&gt;运行 Linkerd&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;这里同样基于官方的 &lt;code&gt;https://raw.githubusercontent.com/BuoyantIO/linkerd-examples/master/k8s-daemonset/k8s/linkerd-namerd.yml&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;需要注意的是，官方给出的 yaml 文件中有一处 bug，使得这个 yaml 只能在缺省的 namespace 和 domain suffix 下运行。需要纠正对 namerd 的访问方式，删除 Namerd 后面的 &lt;code&gt;default.svc.cloud.local&lt;/code&gt; 即可。&lt;/p&gt;

&lt;p&gt;同样的，他的服务端口和管理端口都应该改用 NodePort 方式进行暴露。&lt;/p&gt;

&lt;p&gt;运行后，同样可以看到 Linkerd 的管理界面。&lt;/p&gt;

&lt;h2 id=&#34;测试&#34;&gt;测试&lt;/h2&gt;

&lt;p&gt;下面可以做一个简单的测试，来证明流量分配的有效性：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;for ((i=1;i&amp;lt;=300;i++)); do curl -s &amp;quot;http://10.211.55.63:30001/&amp;quot;;echo &amp;quot;&amp;quot;; done | grep -i blue| wc -l
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;可以看到，随着循环次数的增加，其结果越来越趋近于 &lt;sup&gt;80&lt;/sup&gt;&amp;frasl;&lt;sub&gt;20&lt;/sub&gt; 的分配比例。&lt;/p&gt;

&lt;p&gt;接下来，我们修改上面的 dtab 为如下内容：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/host=&amp;gt;/#/io.l5d.k8s/default/http;
/http/*/*/*=&amp;gt;8*/host/blue&amp;amp;8*/host/green;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;重新进行测试，就可以看到，流量分配已经发生了变化。另外，还可以在 Linkerd 的管理界面上看到网络流量的变化情况。&lt;/p&gt;

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

&lt;p&gt;这一组合基本能够满足流量渐变分配的功能需求，同时也有如豆瓣这样的大厂使用，但他的 dtab 还是个相对复杂的东西，如果在生产上进行使用，还是需要进一步的学习。&lt;/p&gt;

&lt;p&gt;另外，按照其文档中所陈述的功能范围内容来看，仅用来做流量分配还是颇有点大材小用的味道，从个人来说，我倾向于一些更轻量级的解决方法。&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
