istio.io/archive/v1.2/zh/blog/2018/egress-https/index.html

168 lines
43 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html><html lang=zh itemscope itemtype=https://schema.org/WebPage><head><meta charset=utf-8><meta http-equiv=x-ua-compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name=theme-color content=#466BB0><meta name=title content="使用外部 Web 服务"><meta name=description content="描述基于 Istio Bookinfo 示例的简单场景。"><meta name=author content="Vadim Eisenberg"><meta name=keywords content=microservices,services,mesh,traffic-management,egress,https><meta property=og:title content="使用外部 Web 服务"><meta property=og:type content=website><meta property=og:description content="描述基于 Istio Bookinfo 示例的简单场景。"><meta property=og:url content=/v1.2/zh/blog/2018/egress-https/><meta property=og:image content=/v1.2/img/istio-whitelogo-bluebackground-framed.svg><meta property=og:image:alt content="Istio Logo"><meta property=og:image:width content=112><meta property=og:image:height content=150><meta property=og:site_name content=Istio><meta name=twitter:card content=summary><meta name=twitter:site content=@IstioMesh><title>Istioldie 1.2 / 使用外部 Web 服务</title><script async src="https://www.googletagmanager.com/gtag/js?id=UA-98480406-2"></script><script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}
gtag('js',new Date());gtag('config','UA-98480406-2');</script><link rel=alternate type=application/rss+xml title="Istio Blog" href=/v1.2/feed.xml><link rel="shortcut icon" href=/v1.2/favicons/favicon.ico><link rel=apple-touch-icon href=/v1.2/favicons/apple-touch-icon-180x180.png sizes=180x180><link rel=icon type=image/png href=/v1.2/favicons/favicon-16x16.png sizes=16x16><link rel=icon type=image/png href=/v1.2/favicons/favicon-32x32.png sizes=32x32><link rel=icon type=image/png href=/v1.2/favicons/android-36x36.png sizes=36x36><link rel=icon type=image/png href=/v1.2/favicons/android-48x48.png sizes=48x48><link rel=icon type=image/png href=/v1.2/favicons/android-72x72.png sizes=72x72><link rel=icon type=image/png href=/v1.2/favicons/android-96x96.png sizes=96xW96><link rel=icon type=image/png href=/v1.2/favicons/android-144x144.png sizes=144x144><link rel=icon type=image/png href=/v1.2/favicons/android-192x192.png sizes=192x192><link rel=manifest href=/v1.2/manifest.json><meta name=apple-mobile-web-app-title content=Istio><meta name=application-name content=Istio><link rel=stylesheet href="https://fonts.googleapis.com/css?family=Work+Sans:400|Chivo:400|Work+Sans:500,300,600,300italic,400italic,500italic,600italic|Chivo:500,300,600,300italic,400italic,500italic,600italic"><link rel=stylesheet href=/v1.2/css/all.css><script src=/v1.2/js/themes_init.min.js></script></head><body class="language-unknown archive-site"><script>const branchName="release-1.2";const docTitle="使用外部 Web 服务";const iconFile="\/v1.2/img/icons.svg";const buttonCopy='复制到剪切板';const buttonPrint='打印';const buttonDownload='下载';</script><script src="https://www.google.com/cse/brand?form=search-form" defer></script><script src=/v1.2/js/all.min.js data-manual defer></script><header><nav><a id=brand href=/v1.2/zh/><span class=logo><svg viewBox="0 0 300 300"><circle cx="150" cy="150" r="146" stroke-width="2" /><path d="M65 240H225L125 270z"/><path d="M65 230l60-10V110z"/><path d="M135 220l90 10L135 30z"/></svg></span><span class=name>Istioldie 1.2</span></a><div id=hamburger><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#hamburger"/></svg></div><div id=header-links><a title="了解如何部署、使用和运维 Istio。" href=/v1.2/zh/docs/>文档</a>
<span title="关于使用 Istio 的博客文章。">博客</span>
<a title=关于Istio的常见问题。 href=/v1.2/zh/faq/>FAQ</a>
<a title=关于Istio的说明。 href=/v1.2/zh/about/>关于</a><div class=menu><button id=gearDropdownButton class=menu-trigger title=选项和设置 aria-label="Options and Settings" aria-controls=gearDropdownContent><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#gear"/></svg></button><div id=gearDropdownContent class=menu-content aria-labelledby=gearDropdownButton role=menu><a tabindex=-1 role=menuitem lang=en id=switch-lang-en>English</a>
<a tabindex=-1 role=menuitem lang=zh id=switch-lang-zh class=active>中文</a><div role=separator></div><a tabindex=-1 role=menuitem class=active id=light-theme-item>亮主题</a>
<a tabindex=-1 role=menuitem id=dark-theme-item>暗主题</a><div role=separator></div><a tabindex=-1 role=menuitem id=syntax-coloring-item>代码高亮</a><div role=separator></div><h6>本站的其它版本</h6><a tabindex=-1 role=menuitem onclick="navigateToUrlOrRoot('https://istio.io/blog\/2018\/egress-https\/');return false;">当前版本</a>
<a tabindex=-1 role=menuitem onclick="navigateToUrlOrRoot('https://preliminary.istio.io/blog\/2018\/egress-https\/');return false;">下个版本</a>
<a tabindex=-1 role=menuitem href=https://archive.istio.io>旧版本</a></div></div><button id=search-show title=搜索istio.io aria-label=Search><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#magnifier"/></svg></button></div><form id=search-form name=cse role=search><input type=hidden name=cx value=013699703217164175118:iwwf17ikgf4>
<input type=hidden name=ie value=utf-8>
<input type=hidden name=hl value=en>
<input type=hidden id=search-page-url value=/v1.2/search.html>
<input id=search-textbox class=form-control name=q type=search aria-label=搜索istio.io>
<button id=search-close title="Cancel search" type=reset aria-label="Cancel search"><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#cancel-x"/></svg></button></form></nav></header><main class=primary><div id=sidebar-container class="sidebar-container sidebar-offcanvas"><nav id=sidebar aria-label="Section Navigation"><div class=directory><div class=card><button class="header dynamic" id=card0 title="2019 年的博客文章。" aria-controls=card0-body><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#blog"/></svg>2019 年的博客文章</button><div class=body aria-labelledby=card0 role=region id=card0-body><ul role=tree aria-expanded=true class=leaf-section aria-labelledby=card0><li role=none><a role=treeitem title="Istio 1.1.3。" href=/v1.2/zh/blog/2019/announcing-1.1.3/>安全更新:发布 Istio 1.1.3</a></li><li role=none><a role=treeitem title="Istio 1.0.7 的补丁版本。" href=/v1.2/zh/blog/2019/announcing-1.0.7/>安全更新:发布 Istio 1.0.7</a></li><li role=none><a role=treeitem title="Istio 1.1.2 的补丁版本。" href=/v1.2/zh/blog/2019/announcing-1.1.2/>安全更新:发布 Istio 1.1.2</a></li><li role=none><a role=treeitem title="Istio 1.1 发布声明。" href=/v1.2/zh/blog/2019/announcing-1.1/>宣布 Istio 1.1 发布</a></li><li role=none><a role=treeitem title="Istio 1.1 性能概览." href=/v1.2/zh/blog/2019/istio1.1_perf/>面向性能而架构的 Istio 1.1</a></li><li role=none><a role=treeitem title="Istio 1.0.6 补丁版本。" href=/v1.2/zh/blog/2019/announcing-1.0.6/>Istio 1.0.6 发布</a></li><li role=none><a role=treeitem title="在多集群服务网格环境中配置 Istio 的路由规则。" href=/v1.2/zh/blog/2019/multicluster-version-routing/>多集群服务网格中的分版本路由</a></li><li role=none><a role=treeitem title=宣布新的博客策略。 href=/v1.2/zh/blog/2019/sail-the-blog/>博客策略更新</a></li><li role=none><a role=treeitem title="评估加入 Egress gateway 对性能造成的影响。" href=/v1.2/zh/blog/2019/egress-performance/>Egress gateway 性能测试</a></li><li role=none><a role=treeitem title="Istio 将数据面组件注入到现存部署之中的过程。" href=/v1.2/zh/blog/2019/data-plane-setup/>Istio Sidecar 注入过程解密</a></li><li role=none><a role=treeitem title="使用 AppSwitch 解决应用程序启动顺序和启动延迟。" href=/v1.2/zh/blog/2019/appswitch/>使用 AppSwitch 进行 Sidestepping 依赖性排序</a></li><li role=none><a role=treeitem title="如何使用 cert-manager 手工部署一个自定义 Ingress 网关。" href=/v1.2/zh/blog/2019/custom-ingress-gateway/>使用 Cert-Manager 部署一个自定义 Ingress 网关</a></li><li role=none><a role=treeitem title="Istio 推出新的讨论板。" href=/v1.2/zh/blog/2019/announcing-discuss.istio.io/>宣布 discuss.istio.io</a></li></ul></div></div><div class=card><button class="header dynamic" id=card1 title="2017 年的博客文章。" aria-controls=card1-body><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#blog"/></svg>2017 年的博客文章</button><div class=body aria-labelledby=card1 role=region id=card1-body><ul role=tree aria-expanded=true class=leaf-section aria-labelledby=card1><li role=none><a role=treeitem title=提高可用,降低延迟。 href=/v1.2/zh/blog/2017/mixer-spof-myth/>Mixer 和 SPOF 神话</a></li><li role=none><a role=treeitem title="概要说明 Mixer 的插件架构。" href=/v1.2/zh/blog/2017/adapter-model/>Mixer 适配器模型</a></li><li role=none><a role=treeitem title="Istio 0.2 公告。" href=/v1.2/zh/blog/2017/0.2-announcement/>宣布 Istio 0.2</a></li><li role=none><a role=treeitem title="Istio 的策略如何关联 Kubernetes 的网络策略 。" href=/v1.2/zh/blog/2017/0.1-using-network-policy/>Istio 使用网络策略</a></li><li role=none><a role=treeitem title="使用 Istio 创建自动缩放的金丝雀部署。" href=/v1.2/zh/blog/2017/0.1-canary/>使用 Istio 进行金丝雀部署</a></li><li role=none><a role=treeitem title="Istio Auth 0.1 公告。" href=/v1.2/zh/blog/2017/0.1-auth/>使用 Istio 增强端到端安全</a></li><li role=none><a role=treeitem title="Istio 0.1 宣布。" href=/v1.2/zh/blog/2017/0.1-announcement/>初次了解 Istio</a></li></ul></div></div><div class=card><button class="header dynamic" id=card2 title="2018 年的博客文章。" aria-controls=card2-body><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#blog"/></svg>2018 年的博客文章</button><div class="body default" aria-labelledby=card2 role=region id=card2-body><ul role=tree aria-expanded=true class=leaf-section aria-labelledby=card2><li role=none><a role=treeitem title="Istio 1.0.5 补丁版本发布。" href=/v1.2/zh/blog/2018/announcing-1.0.5/>Istio 1.0.5 发布</a></li><li role=none><a role=treeitem title="Istio 1.0.4 补丁版本发布。" href=/v1.2/zh/blog/2018/announcing-1.0.4/>Istio 1.0.4 发布</a></li><li role=none><a role=treeitem title="如何在不部署 Sidecar 代理的情况下使用 Istio 进行流量管理。" href=/v1.2/zh/blog/2018/incremental-traffic-management/>增量式应用 Istio 第一部分,流量管理</a></li><li role=none><a role=treeitem title="描述了一个基于 Istio 的 Bookinfo 示例的简单场景。" href=/v1.2/zh/blog/2018/egress-mongo/>使用外部 MongoDB 服务</a></li><li role=none><a role=treeitem title="Istio 1.0.3 修补版本。" href=/v1.2/zh/blog/2018/announcing-1.0.3/>宣布 Istio 1.0.3</a></li><li role=none><a role=treeitem title="Istio 1.0.2 补丁版本." href=/v1.2/zh/blog/2018/announcing-1.0.2/>Istio 1.0.2 发布</a></li><li role=none><a role=treeitem title="Istio 1.0.1 补丁版本。" href=/v1.2/zh/blog/2018/announcing-1.0.1/>Istio 1.0.1 发布</a></li><li role=none><a role=treeitem title="Istio 在 Twitch 举办了为期一天的直播庆祝 1.0 的发布。" href=/v1.2/zh/blog/2018/istio-twitch-stream/>Istio 在 Twitch 上全天直播</a></li><li role=none><a role=treeitem title="惠普如何在 Istio 上构建其下一代鞋类个性化平台。" href=/v1.2/zh/blog/2018/hp/>Istio 是惠普 FitStation 平台的改变者</a></li><li role=none><a role=treeitem title="Istio 1.0 已生产就绪。" href=/v1.2/zh/blog/2018/announcing-1.0/>宣布 Istio 1.0</a></li><li role=none><a role=treeitem title="使用 AppSwitch 自动接入应用并降低延迟。" href=/v1.2/zh/blog/2018/delayering-istio/>使用 AppSwitch 精简 Istio 层次</a></li><li role=none><a role=treeitem title="描述 Istio 的授权功能以及如何在各种用例中使用它。" href=/v1.2/zh/blog/2018/istio-authorization/>基于 Istio 的 Micro-Segmentation 授权</a></li><li role=none><a role=treeitem title="如何通过 Stackdriver 将 Istio 访问日志导出到 BigQuery、GCS、Pub/Sub 等不同的接收器。" href=/v1.2/zh/blog/2018/export-logs-through-stackdriver/>通过 Stackdriver 将日志导出到 BigQuery、GCS、Pub/Sub</a></li><li role=none><a role=treeitem title="描述如何配置 Istio 进行 HTTP Egress 流量监控和访问策略。" href=/v1.2/zh/blog/2018/egress-monitoring-access-control/>HTTP Egress 流量监控和访问策略</a></li><li role=none><a role=treeitem title="Istio v1alpha3 路由 API 介绍,动机及其设计原则。" href=/v1.2/zh/blog/2018/v1alpha3-routing/>Istio v1aplha3 路由 API 介绍</a></li><li role=none><a role=treeitem title="描述如何在AWS上使用网络负载均衡器配置 Istio Ingress。" href=/v1.2/zh/blog/2018/aws-nlb/>使用AWS NLB 配置 Istio Ingress</a></li><li role=none><a role=treeitem title="使用 Kubernetes 命名空间和 RBAC 为 Istio 构建软性多租户环境。" href=/v1.2/zh/blog/2018/soft-multitenancy/>Istio 的软性多租户支持</a></li><li role=none><a role=treeitem title=介绍更安全,低风险的部署和发布到生产。 href=/v1.2/zh/blog/2018/traffic-mirroring/>用于在生产环境进行测试的 Istio 流量镜像功能</a></li><li role=none><a role=treeitem title="描述基于 Istio 的 Bookinfo 示例的简单场景。" href=/v1.2/zh/blog/2018/egress-tcp/>使用外部 TCP 服务</a></li><li role=none><span role=treeitem class=current title="描述基于 Istio Bookinfo 示例的简单场景。">使用外部 Web 服务</span></li></ul></div></div></div></nav></div><div class=article-container><button tabindex=-1 id=sidebar-toggler title=折叠导航栏><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#pull"/></svg></button><nav aria-label=Breadcrumb><ol><li><a href=/v1.2/zh/>Istio</a></li><li><a href=/v1.2/zh/blog/ title="关于使用 Istio 的博客文章。">博客</a></li><li><a href=/v1.2/zh/blog/2018/ title="2018 年的博客文章。">2018 年的博客文章</a></li><li>使用外部 Web 服务</li></ol></nav><article aria-labelledby=title><div class=title-area><div><h1 id=title>使用外部 Web 服务</h1><p class=subtitle>HTTPS 流量的出口规则</p><p class=byline><span>作者</span>
<span class=attribution>Vadim Eisenberg</span><span> | </span><span><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#calendar"/></svg><span>&nbsp;</span>2018年1月31日</span><span> | </span><span title="744 字"><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#clock"/></svg><span>&nbsp;</span>阅读大约需要 4 分钟</span></p></div></div><nav class=toc-inlined aria-label="Table of Contents"><div><hr><ol><li role=none aria-label=初始设定><a href=#%e5%88%9d%e5%a7%8b%e8%ae%be%e5%ae%9a>初始设定</a><ol><li role=none aria-label="Bookinfo 使用 HTTPS 访问 Google 图书网络服务"><a href=#bookinfo-%e4%bd%bf%e7%94%a8-https-%e8%ae%bf%e9%97%ae-google-%e5%9b%be%e4%b9%a6%e7%bd%91%e7%bb%9c%e6%9c%8d%e5%8a%a1>Bookinfo 使用 HTTPS 访问 Google 图书网络服务</a><li role=none aria-label="启用对 Google Books 网络服务的 HTTPS 访问"><a href=#%e5%90%af%e7%94%a8%e5%af%b9-google-books-%e7%bd%91%e7%bb%9c%e6%9c%8d%e5%8a%a1%e7%9a%84-https-%e8%ae%bf%e9%97%ae>启用对 Google Books 网络服务的 HTTPS 访问</a><li role=none aria-label="清除对 Google 图书网络服务的 HTTPS 访问权限"><a href=#%e6%b8%85%e9%99%a4%e5%af%b9-google-%e5%9b%be%e4%b9%a6%e7%bd%91%e7%bb%9c%e6%9c%8d%e5%8a%a1%e7%9a%84-https-%e8%ae%bf%e9%97%ae%e6%9d%83%e9%99%90>清除对 Google 图书网络服务的 HTTPS 访问权限</a></ol></li><li role=none aria-label="由 Istio 发起的 TLS"><a href=#%e7%94%b1-istio-%e5%8f%91%e8%b5%b7%e7%9a%84-tls>由 Istio 发起的 TLS</a><li role=none aria-label="具有 TLS 的 Bookinfo 起源于 Google Books 网络服务"><a href=#%e5%85%b7%e6%9c%89-tls-%e7%9a%84-bookinfo-%e8%b5%b7%e6%ba%90%e4%ba%8e-google-books-%e7%bd%91%e7%bb%9c%e6%9c%8d%e5%8a%a1>具有 TLS 的 Bookinfo 起源于 Google Books 网络服务</a><ol><li role=none aria-label="清除 TLS 原始数据到 Google Books 网络服务"><a href=#%e6%b8%85%e9%99%a4-tls-%e5%8e%9f%e5%a7%8b%e6%95%b0%e6%8d%ae%e5%88%b0-google-books-%e7%bd%91%e7%bb%9c%e6%9c%8d%e5%8a%a1>清除 TLS 原始数据到 Google Books 网络服务</a><li role=none aria-label="Istio 双向 TLS 的关系"><a href=#istio-%e5%8f%8c%e5%90%91-tls-%e7%9a%84%e5%85%b3%e7%b3%bb>Istio 双向 TLS 的关系</a></ol></li><li role=none aria-label=结论><a href=#%e7%bb%93%e8%ae%ba>结论</a><li role=none aria-label=相关内容><a href=#see-also>相关内容</a></li></ol><hr></div></nav><div><aside class="callout tip"><div class=type><svg class="large-icon"><use xlink:href="/v1.2/img/icons.svg#callout-tip"/></svg></div><div class=content>此博客文章于 2018 年 8 月 9 日更新。它反映并使用了 Istio 1.0 的新功能。</div></aside></div><p><a href=/v1.2/zh/blog/2018/v1alpha3-routing/>v1alpha3 流量管理 API</a>。如果您需要使用旧版本,请按照文档进行操作
<a href=https://archive.istio.io/v0.7/blog/2018/egress-https.html>使用外部 Web 服务归档版</a></p><p>在许多情况下,在 <em>service mesh</em> 中的微服务序并不是应用程序的全部,有时,
网格内部的微服务需要使用在服务网格外部的遗留系统提供的功能,虽然我们希望逐步将这些系统迁移到服务网格中。
但是在迁移这些系统之前,必须让服务网格内的应用程序能访问它们。还有其他情况,
应用程序使用外部组织提供的 Web 服务,通常是通过万维网提供的服务。</p><p>在这篇博客文章中,我修改了<a href=/v1.2/zh/docs/examples/bookinfo/>Istio Bookinfo 示例应用程序</a>让它可以
从外部 Web 服务(<a href=https://developers.google.com/books/docs/v1/getting_started>Google Books APIs</a> )获取图书详细信息。
我将展示如何使用 <em>mesh-external service entries</em> 在 Istio 中启用外部 HTTPS 流量。最后,
我解释了当前与 Istio 出口流量控制相关的问题。</p><h2 id=初始设定>初始设定</h2><p>为了演示使用外部 Web 服务的场景,我首先使用安装了 <a href=/v1.2/zh/docs/setup/kubernetes/install/kubernetes/#安装步骤>Istio</a>
Kubernetes 集群, 然后我部署 <a href=/v1.2/zh/docs/examples/bookinfo/>Istio Bookinfo 示例应用程序</a>,
此应用程序使用 <em>details</em> 微服务来获取书籍详细信息,例如页数和发布者, 原始 <em>details</em> 微服务提供书籍
详细信息,无需咨询任何外部服务。</p><p>此博客文章中的示例命令适用于 Istio 1.0+,无论启用或不启用<a href=/v1.2/zh/docs/concepts/security/#双向-tls-认证>双向 TLS</a>
Bookinfo 配置文件位于 Istio 发行存档的 <code>samples/bookinfo</code> 目录中。</p><p>以下是原始 <a href=/v1.2/zh/docs/examples/bookinfo/>Bookinfo 示例应用程序</a>中应用程序端到端体系结构的副本。</p><figure style=width:80%><div class=wrapper-with-intrinsic-ratio style=padding-bottom:59.086918235567985%><a data-skipendnotes=true href=/v1.2/docs/examples/bookinfo/withistio.svg title="原 Bookinfo 应用程序"><img class=element-to-stretch src=/v1.2/docs/examples/bookinfo/withistio.svg alt="原 Bookinfo 应用程序"></a></div><figcaption>原 Bookinfo 应用程序</figcaption></figure><p>执行<a href=/v1.2/zh/docs/examples/bookinfo/#部署应用>部署应用程序</a><a href=/v1.2/zh/docs/examples/bookinfo/#确认应用在运行中>确认应用正在运行</a>,以及
<a href=/v1.2/zh/docs/examples/bookinfo/#应用缺省目标规则>应用默认目标规则</a>中的步骤部分。</p><h3 id=bookinfo-使用-https-访问-google-图书网络服务>Bookinfo 使用 HTTPS 访问 Google 图书网络服务</h3><p>让我们添加一个新版本的 <em>details</em> 微服务_v2_<a href=https://developers.google.com/books/docs/v1/getting_started>Google Books APIs</a>中获取图书详细信息。
它设定了服务容器的 <code>DO_NOT_ENCRYPT</code> 环境变量为 <code>false</code>。此设置将指示已部署服务使用 HTTPS而不是 HTTP )来访问外部服务。</p><div><a data-skipendnotes=true style=display:none href=https://raw.githubusercontent.com/istio/istio/release-1.2/samples/bookinfo/platform/kube/bookinfo-details-v2.yaml>Zip</a><pre><code class=language-bash data-expandlinks=true>$ kubectl apply -f @samples/bookinfo/platform/kube/bookinfo-details-v2.yaml@ --dry-run -o yaml | kubectl set env --local -f - &#39;DO_NOT_ENCRYPT=false&#39; -o yaml | kubectl apply -f -
</code></pre></div><p>现在,应用程序的更新架构如下所示:</p><figure style=width:80%><div class=wrapper-with-intrinsic-ratio style=padding-bottom:65.1654485092242%><a data-skipendnotes=true href=/v1.2/blog/2018/egress-https/bookinfo-details-v2.svg title="Bookinfo 的 details V2 应用程序"><img class=element-to-stretch src=/v1.2/blog/2018/egress-https/bookinfo-details-v2.svg alt="Bookinfo 的 details V2 应用程序"></a></div><figcaption>Bookinfo 的 details V2 应用程序</figcaption></figure><p>请注意Google Book 服务位于 Istio 服务网格之外,其边界由虚线标记。</p><p>现在让我们将指向 <em>details</em> 微服务的所有流量定向到 _details v2_</p><div><a data-skipendnotes=true style=display:none href=https://raw.githubusercontent.com/istio/istio/release-1.2/samples/bookinfo/networking/virtual-service-details-v2.yaml>Zip</a><pre><code class=language-bash data-expandlinks=true>$ kubectl apply -f @samples/bookinfo/networking/virtual-service-details-v2.yaml@
</code></pre></div><p>请注意,<code>VirtualService</code> 依赖于您在<a href=/v1.2/zh/docs/examples/bookinfo/#应用缺省目标规则>应用默认目标规则</a>部分中创建的目标规则。</p><p><a href=/v1.2/zh/docs/examples/bookinfo/#确定-ingress-的-ip-和端口>确定 ingress 的 IP 和端口</a>之后,
让我们访问应用程序的网页。</p><p>糟糕&hellip;页面显示 _Error fetching product details_而不是书籍详细信息</p><figure style=width:80%><div class=wrapper-with-intrinsic-ratio style=padding-bottom:36.18649965205289%><a data-skipendnotes=true href=/v1.2/blog/2018/egress-https/errorFetchingBookDetails.png title=获取产品详细信息的错误消息><img class=element-to-stretch src=/v1.2/blog/2018/egress-https/errorFetchingBookDetails.png alt=获取产品详细信息的错误消息></a></div><figcaption>获取产品详细信息的错误消息</figcaption></figure><p>好消息是我们的应用程序没有崩溃, 通过良好的微服务设计,我们没有让<strong>故障扩散</strong>。在我们的例子中,
失败的 <em>details</em> 微服务不会导致 <code>productpage</code> 微服务失败, 尽管 <em>details</em> 微服务失败,
仍然提供了应用程序的大多数功能, 我们有<strong>优雅的服务降级</strong>:正如您所看到的,评论和评级正确显示,
应用程序仍然有用。</p><p>那可能出了什么问题? 啊&hellip;&hellip;答案是我忘了启用从网格内部到外部服务的流量,在本例中是 Google Book Web 服务。
默认情况下Istio sidecar 代理(<a href=https://www.envoyproxy.io>Envoy proxies</a>
<strong>阻止到集群外目的地的所有流量</strong>, 要启用此类流量,我们必须定义<a href=/v1.2/zh/docs/reference/config/istio.networking.v1alpha3/#serviceentry>mesh-external service entry</a></p><h3 id=启用对-google-books-网络服务的-https-访问>启用对 Google Books 网络服务的 HTTPS 访问</h3><p>不用担心,让我们定义<strong>网格外部 <code>ServiceEntry</code></strong> 并修复我们的应用程序。您还必须定义 <em>virtual
service</em> 使用 <a href=https://en.wikipedia.org/wiki/Server_Name_Indication>SNI</a>对外部服务执行路由。</p><pre><code class=language-bash data-expandlinks=true>$ kubectl apply -f - &lt;&lt;EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: googleapis
spec:
hosts:
- www.googleapis.com
ports:
- number: 443
name: https
protocol: HTTPS
location: MESH_EXTERNAL
resolution: DNS
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: googleapis
spec:
hosts:
- www.googleapis.com
tls:
- match:
- port: 443
sni_hosts:
- www.googleapis.com
route:
- destination:
host: www.googleapis.com
port:
number: 443
weight: 100
EOF
</code></pre><p>现在访问应用程序的网页会显示书籍详细信息而不会出现错误:</p><figure style=width:80%><div class=wrapper-with-intrinsic-ratio style=padding-bottom:34.82831114225648%><a data-skipendnotes=true href=/v1.2/blog/2018/egress-https/externalBookDetails.png title=正确显示书籍详细信息><img class=element-to-stretch src=/v1.2/blog/2018/egress-https/externalBookDetails.png alt=正确显示书籍详细信息></a></div><figcaption>正确显示书籍详细信息</figcaption></figure><p>您可以查询您的 <code>ServiceEntry</code> </p><pre><code class=language-bash data-expandlinks=true>$ kubectl get serviceentries
NAME AGE
googleapis 8m
</code></pre><p>您可以删除您的 <code>ServiceEntry</code> </p><pre><code class=language-bash data-expandlinks=true>$ kubectl delete serviceentry googleapis
serviceentry &#34;googleapis&#34; deleted
</code></pre><p>并在输出中看到删除了 <code>ServiceEntry</code></p><p>删除 <code>ServiceEntry</code> 后访问网页会产生我们之前遇到的相同错误,即 <em>Error fetching product details</em>,
正如我们所看到的,,与许多其他 Istio 配置一样,<code>ServiceEntry</code><strong>动态定义</strong>的 , Istio 运算符可以动态决定
它们允许微服务访问哪些域, 他们可以动态启用和禁用外部域的流量,而无需重新部署微服务。</p><h3 id=清除对-google-图书网络服务的-https-访问权限>清除对 Google 图书网络服务的 HTTPS 访问权限</h3><div><a data-skipendnotes=true style=display:none href=https://raw.githubusercontent.com/istio/istio/release-1.2/samples/bookinfo/platform/kube/bookinfo-details-v2.yaml>Zip</a><a data-skipendnotes=true style=display:none href=https://raw.githubusercontent.com/istio/istio/release-1.2/samples/bookinfo/networking/virtual-service-details-v2.yaml>Zip</a><pre><code class=language-bash data-expandlinks=true>$ kubectl delete serviceentry googleapis
$ kubectl delete virtualservice googleapis
$ kubectl delete -f @samples/bookinfo/networking/virtual-service-details-v2.yaml@
$ kubectl delete -f @samples/bookinfo/platform/kube/bookinfo-details-v2.yaml@
</code></pre></div><h2 id=由-istio-发起的-tls>由 Istio 发起的 TLS</h2><p>这个故事有一个警告。假设您要监视您的微服务使用 <a href=https://developers.google.com/apis-explorer/>Google API</a> 的哪个特定集
<a href=https://developers.google.com/books/docs/v1/getting_started>书籍</a><a href=https://developers.google.com/calendar/>日历</a><a href=https://developers.google.com/tasks/>任务</a>等)
假设您要强制执行仅允许使用<a href=https://developers.google.com/books/docs/v1/getting_started>图书 API</a>的策略。
假设您要监控您的微服务访问的标识符。对于这些监视和策略任务,您需要知道 URL 路径。
考虑例如 URL <a href="https://www.googleapis.com/books/v1/volumes?q=isbn:0486424618"><code>www.googleapis.com/books/v1/volumes?q=isbn:0486424618</code></a>
在该网址中,路径段指定了<a href=https://developers.google.com/books/docs/v1/getting_started>图书 API</a>
<code>/books</code> 和路径段的 <a href=https://en.wikipedia.org/wiki/International_Standard_Book_Number>ISBN</a> 代码
<code>/volumes?q=isbn:0486424618</code>。但是,在 HTTPS 中,所有 HTTP 详细信息(主机名,路径,标头等)都是加密的
sidecar 代理的这种监督和策略执行是无法实现的。Istio 只能通过 <a href=https://tools.ietf.org/html/rfc3546#section-3.1>SNI</a>_Server Name Indication_得知加密请求中的主机名称在这里就是 <code>www.googleapis.com</code></p><p>为了允许 Istio 基于域执行出口请求的过滤,微服务必须发出 HTTP 请求, 然后Istio 打开到目标的 HTTPS 连接(执行 TLS 发起),
根据微服务是在 Istio 服务网格内部还是外部运行,
微服务的代码必须以不同方式编写或以不同方式配置, 这与<a href=/v1.2/zh/docs/concepts/what-is-istio/#设计目标>最大化透明度</a>
的 Istio 设计目标相矛盾, 有时我们需要妥协&hellip;&hellip;</p><p>下图显示了如何执行外部服务的 HTTPS 流量, 在顶部Istio 服务网格外部的微服务发送常规 HTTPS 请求,
端到端加密, 在底部Istio 服务网格内的相同微服务必须在 pod 内发送未加密的 HTTP 请求,
这些请求被 sidecar Envoy 代理拦截 , sidecar 代理执行 TLS 发起,因此 pod 和外部服务之间的流量被加密。</p><figure style=width:60%><div class=wrapper-with-intrinsic-ratio style=padding-bottom:95.1355088590701%><a data-skipendnotes=true href=/v1.2/blog/2018/egress-https/https_from_the_app.svg title="对外发起 HTTPS 流量的两种方式:微服务自行发起,或由 Sidecar 代理发起"><img class=element-to-stretch src=/v1.2/blog/2018/egress-https/https_from_the_app.svg alt="对外发起 HTTPS 流量的两种方式:微服务自行发起,或由 Sidecar 代理发起"></a></div><figcaption>对外发起 HTTPS 流量的两种方式:微服务自行发起,或由 Sidecar 代理发起</figcaption></figure><p>以下是我们如何在 <a href=https://raw.githubusercontent.com/istio/istio/release-1.2/samples/bookinfo/src/details/details.rb>Bookinfo 的 details 微服务代码</a>
中使用 Ruby <a href=https://docs.ruby-lang.org/en/2.0.0/Net/HTTP.html>net/http 模块</a></p><pre><code class=language-ruby data-expandlinks=true>uri = URI.parse(&#39;https://www.googleapis.com/books/v1/volumes?q=isbn:&#39; + isbn)
http = Net::HTTP.new(uri.host, uri.port)
...
unless ENV[&#39;DO_NOT_ENCRYPT&#39;] === &#39;true&#39; then
http.use_ssl = true
end
</code></pre><p>请注意,默认的 HTTPS 端口 <code>443</code> 的取值是 <code>URI.parse</code> 通过对 URI (<code>https://</code>) 的解析得来的,
当在 Istio 服务网格内运行时,微服务必须向端口 <code>443</code> 发出 HTTP 请求,该端口是外部服务侦听的端口。
当定义 <code>WITH_ISTIO</code> 环境变量时,请求在没有 SSL普通 HTTP )的情况下执行。</p><p>我们将 <code>WITH_ISTIO</code> 环境变量设置为 <em>&ldquo;true&rdquo;</em> <a href=https://raw.githubusercontent.com/istio/istio/release-1.2/samples/bookinfo/platform/kube/bookinfo-details-v2.yaml>details 的部署配置文件</a>,
<code>container</code> 部分:</p><pre><code class=language-yaml data-expandlinks=true>env:
- name: DO_NOT_ENCRYPT
value: &#34;true&#34;
</code></pre><p>在下一节中,您将配置 TLS 发起以访问外部 Web 服务。</p><h2 id=具有-tls-的-bookinfo-起源于-google-books-网络服务>具有 TLS 的 Bookinfo 起源于 Google Books 网络服务</h2><ol><li><p>部署 <em>details v2</em> 版本,将 HTTP 请求发送到 <a href=https://developers.google.com/books/docs/v1/getting_started>Google Books API</a>
<a href=https://raw.githubusercontent.com/istio/istio/release-1.2/samples/bookinfo/platform/kube/bookinfo-details-v2.yaml><code>bookinfo-details-v2.yaml</code></a> 中,
<code>DO_NOT_ENCRYPT</code> 变量设置为 true。</p><div><a data-skipendnotes=true style=display:none href=https://raw.githubusercontent.com/istio/istio/release-1.2/samples/bookinfo/platform/kube/bookinfo-details-v2.yaml>Zip</a><pre><code class=language-bash data-expandlinks=true>$ kubectl apply -f @samples/bookinfo/platform/kube/bookinfo-details-v2.yaml@
</code></pre></div></li><li><p>将指向 <em>details</em> 微服务的流量定向到 _details v2_。</p><div><a data-skipendnotes=true style=display:none href=https://raw.githubusercontent.com/istio/istio/release-1.2/samples/bookinfo/networking/virtual-service-details-v2.yaml>Zip</a><pre><code class=language-bash data-expandlinks=true>$ kubectl apply -f @samples/bookinfo/networking/virtual-service-details-v2.yaml@
</code></pre></div></li><li><p><code>www.google.apis</code> 创建网格外部 <code>ServiceEntry</code>,并执行目标规则以执行 TLS 发起。</p><pre><code class=language-bash data-expandlinks=true>$ kubectl apply -f - &lt;&lt;EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: googleapis
spec:
hosts:
- www.googleapis.com
ports:
- number: 443
name: http-port-for-tls-origination
protocol: HTTP
resolution: DNS
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: originate-tls-for-googleapis
spec:
host: www.googleapis.com
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
portLevelSettings:
- port:
number: 443
tls:
mode: SIMPLE # 访问 edition.cnn.com 时启动 HTTPS
EOF
</code></pre><p>注意,前缀为 <code>http-</code> <code>ServiceEntr</code> 指定了端口为 <code>443</code>,其协议指定为 <code>HTTP</code>
请注意,您不需要使用端口 443 发送 TLS 发起的 HTTP 请求。
<a href=/v1.2/zh/docs/tasks/traffic-management/edge-traffic/egress-tls-origination/>出口流量的 TLS</a>
显示了如何使用端口重写执行 TLS 发起。</p></li><li><p>访问应用程序的网页,并验证是否显示图书详细信息。</p></li><li><p>检查 <em>details v2</em> 的 sidecar 代理的日志,并查看 HTTP 请求。</p><pre><code class=language-bash data-expandlinks=true>$ kubectl logs $(kubectl get pods -l app=details -l version=v2 -o jsonpath=&#39;{.items[0].metadata.name}&#39;) istio-proxy | grep googleapis
[2018-08-09T11:32:58.171Z] &#34;GET /books/v1/volumes?q=isbn:0486424618 HTTP/1.1&#34; 200 - 0 1050 264 264 &#34;-&#34; &#34;Ruby&#34; &#34;b993bae7-4288-9241-81a5-4cde93b2e3a6&#34; &#34;www.googleapis.com:443&#34; &#34;172.217.20.74:443&#34;
EOF
</code></pre><p>请注意日志中的 URL 路径,可以监视路径并根据它来应用访问策略。要了解有关 HTTP 出口流量的监控和访问策略
的更多信息,请查看<a href=https://archive.istio.io/v0.8/blog/2018/egress-monitoring-access-control/#logging>归档博客之出口流量监控之日志</a></p></li></ol><h3 id=清除-tls-原始数据到-google-books-网络服务>清除 TLS 原始数据到 Google Books 网络服务</h3><div><a data-skipendnotes=true style=display:none href=https://raw.githubusercontent.com/istio/istio/release-1.2/samples/bookinfo/platform/kube/bookinfo-details-v2.yaml>Zip</a><a data-skipendnotes=true style=display:none href=https://raw.githubusercontent.com/istio/istio/release-1.2/samples/bookinfo/networking/virtual-service-details-v2.yaml>Zip</a><pre><code class=language-bash data-expandlinks=true>$ kubectl delete serviceentry googleapis
$ kubectl delete destinationrule originate-tls-for-googleapis
$ kubectl delete -f @samples/bookinfo/networking/virtual-service-details-v2.yaml@
$ kubectl delete -f @samples/bookinfo/platform/kube/bookinfo-details-v2.yaml@
</code></pre></div><h3 id=istio-双向-tls-的关系>Istio 双向 TLS 的关系</h3><p>请注意在这种情况下TLS 的源与 Istio 应用的 <a href=/v1.2/zh/docs/concepts/security/#双向-tls-认证>双向 TLS</a> 无关,
无论 Istio 双向 TLS 是否启用,外部服务的 TLS 源都将起作用 , 保证服务网<strong></strong>的服务到服务通信,
并为每个服务提供强大的身份认证, 在此博客文章中的 <strong>外部服务</strong>的情况下,我们有<strong>单向</strong> TLS
这是用于保护 Web 浏览器和 Web 服务器之间通信的相同机制 , TLS 应用于与外部服务的通信,
以验证外部服务器的身份并加密流量。</p><h2 id=结论>结论</h2><p>在这篇博文中,我演示了 Istio 服务网格中的微服务如何通过 HTTPS 使用外部 Web 服务, 默认情况下,
Istio 会阻止集群外主机的所有流量, 要启用此类流量,请使用 mesh-external,必须为服务网格创建 <code>ServiceEntry</code> ,
可以通过 HTTPS 访问外部站点,当微服务发出 HTTPS 请求时,流量是端到端加密的,但是 Istio 无法监视 HTTP 详细信息,
例如请求的 URL 路径。当微服务发出 HTTP 请求时Istio 可以监视请求的 HTTP 详细信息并强制执行基于 HTTP 的访问策略。
但是,在这种情况下,微服务和 sidecar 代理之间的流量是未加密的。在具有非常严格的安全要求的组织中,
可以禁止未加密的部分流量。</p><nav id=see-also><h2>相关内容</h2><div class=see-also><div class=entry><p class=link><a data-skipendnotes=true href=/v1.2/zh/blog/2019/egress-performance/>Egress gateway 性能测试</a></p><p class=desc>评估加入 Egress gateway 对性能造成的影响。</p></div><div class=entry><p class=link><a data-skipendnotes=true href=/v1.2/zh/blog/2018/egress-mongo/>使用外部 MongoDB 服务</a></p><p class=desc>描述了一个基于 Istio 的 Bookinfo 示例的简单场景。</p></div><div class=entry><p class=link><a data-skipendnotes=true href=/v1.2/zh/blog/2018/egress-monitoring-access-control/>HTTP Egress 流量监控和访问策略</a></p><p class=desc>描述如何配置 Istio 进行 HTTP Egress 流量监控和访问策略。</p></div><div class=entry><p class=link><a data-skipendnotes=true href=/v1.2/zh/blog/2018/egress-tcp/>使用外部 TCP 服务</a></p><p class=desc>描述基于 Istio 的 Bookinfo 示例的简单场景。</p></div><div class=entry><p class=link><a data-skipendnotes=true href=/v1.2/zh/docs/tasks/traffic-management/edge-traffic/egress_sni_monitoring_and_policies/>Egress TLS 流量中的 SNI 监控及策略</a></p><p class=desc>如何为 Egress TLS 流量配置 SNI 监控并应用策略。</p></div><div class=entry><p class=link><a data-skipendnotes=true href=/v1.2/zh/docs/tasks/traffic-management/edge-traffic/egress-gateway-tls-origination/>Egress 网关的 TLS 发起过程</a></p><p class=desc>描述了配置 Egress 网关来发起对外部服务进行 TLS 通信的过程。</p></div></div></nav></article><nav class=pagenav><div class=left><a title="描述基于 Istio 的 Bookinfo 示例的简单场景。" href=/v1.2/zh/blog/2018/egress-tcp/><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#left-arrow"/></svg>使用外部 TCP 服务</a></div><div class=right></div></nav><div id=endnotes-container aria-hidden=true><h2>链接</h2><ol id=endnotes></ol></div></div><div class=toc-container><nav class=toc aria-label="Table of Contents"><div id=toc><ol><li role=none aria-label=初始设定><a href=#%e5%88%9d%e5%a7%8b%e8%ae%be%e5%ae%9a>初始设定</a><ol><li role=none aria-label="Bookinfo 使用 HTTPS 访问 Google 图书网络服务"><a href=#bookinfo-%e4%bd%bf%e7%94%a8-https-%e8%ae%bf%e9%97%ae-google-%e5%9b%be%e4%b9%a6%e7%bd%91%e7%bb%9c%e6%9c%8d%e5%8a%a1>Bookinfo 使用 HTTPS 访问 Google 图书网络服务</a><li role=none aria-label="启用对 Google Books 网络服务的 HTTPS 访问"><a href=#%e5%90%af%e7%94%a8%e5%af%b9-google-books-%e7%bd%91%e7%bb%9c%e6%9c%8d%e5%8a%a1%e7%9a%84-https-%e8%ae%bf%e9%97%ae>启用对 Google Books 网络服务的 HTTPS 访问</a><li role=none aria-label="清除对 Google 图书网络服务的 HTTPS 访问权限"><a href=#%e6%b8%85%e9%99%a4%e5%af%b9-google-%e5%9b%be%e4%b9%a6%e7%bd%91%e7%bb%9c%e6%9c%8d%e5%8a%a1%e7%9a%84-https-%e8%ae%bf%e9%97%ae%e6%9d%83%e9%99%90>清除对 Google 图书网络服务的 HTTPS 访问权限</a></ol></li><li role=none aria-label="由 Istio 发起的 TLS"><a href=#%e7%94%b1-istio-%e5%8f%91%e8%b5%b7%e7%9a%84-tls>由 Istio 发起的 TLS</a><li role=none aria-label="具有 TLS 的 Bookinfo 起源于 Google Books 网络服务"><a href=#%e5%85%b7%e6%9c%89-tls-%e7%9a%84-bookinfo-%e8%b5%b7%e6%ba%90%e4%ba%8e-google-books-%e7%bd%91%e7%bb%9c%e6%9c%8d%e5%8a%a1>具有 TLS 的 Bookinfo 起源于 Google Books 网络服务</a><ol><li role=none aria-label="清除 TLS 原始数据到 Google Books 网络服务"><a href=#%e6%b8%85%e9%99%a4-tls-%e5%8e%9f%e5%a7%8b%e6%95%b0%e6%8d%ae%e5%88%b0-google-books-%e7%bd%91%e7%bb%9c%e6%9c%8d%e5%8a%a1>清除 TLS 原始数据到 Google Books 网络服务</a><li role=none aria-label="Istio 双向 TLS 的关系"><a href=#istio-%e5%8f%8c%e5%90%91-tls-%e7%9a%84%e5%85%b3%e7%b3%bb>Istio 双向 TLS 的关系</a></ol></li><li role=none aria-label=结论><a href=#%e7%bb%93%e8%ae%ba>结论</a><li role=none aria-label=相关内容><a href=#see-also>相关内容</a></li></ol></div></nav></div></main><footer><div class=user-links><a class=channel title="Go download Istio 1.2.5 now" href=https://github.com/istio/istio/releases/tag/1.2.5 aria-label="Download Istio"><span>download</span><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#download"/></svg>
</a><a class=channel title="加入 Istio discussion board 参与讨论获取帮助" href=https://discuss.istio.io aria-label="Istio discussion board"><span>discuss</span><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#discourse"/></svg></a>
<a class=channel title="Stack Overflow 中列举了针对实际问题以及部署、配置和使用 Istio 的各项回答" href=https://stackoverflow.com/questions/tagged/istio aria-label="Stack Overflow"><span>stack overflow</span><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#stackoverflow"/></svg></a>
<a class=channel title="在 Slack 上与 Istio 社区交互讨论开发问题(仅限邀请)" href=https://istio.slack.com aria-label=slack><span>slack</span><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#slack"/></svg></a>
<a class=channel title="关注我们的 Twitter 来获取最新信息" href=https://twitter.com/IstioMesh aria-label=Twitter><span>twitter</span><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#twitter"/></svg></a><div class=tag>对于用户</div></div><div class=info><p class=copyright>中文内容由 ServiceMesher 社区维护,部分文档可能稍微滞后于英文版本,同步工作持续进行中<br>Istio 归档
1.2.5<br>&copy; 2019 Istio Authors, <a href=https://policies.google.com/privacy>隐私政策</a><br>归档于 2019年9月12日</p></div><div class=dev-links><a class=channel title="Istio 的代码在 GitHub 上开发" href=https://github.com/istio/community aria-label=GitHub><span>github</span><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#github"/></svg></a>
<a class=channel title="如果您想深入了解 Istio 的技术细节,请查看我们日益完善的设计文档" href=https://groups.google.com/forum/#!forum/istio-team-drive-access aria-label="team drive"><span>drive</span><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#drive"/></svg></a>
<a class=channel title="如果您想为 Istio 项目做出贡献,请考虑加入我们的工作组" href=https://github.com/istio/community/blob/master/WORKING-GROUPS.md aria-label="working groups"><span>working groups</span><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#working-groups"/></svg></a><div class=tag>对于开发者</div></div></footer><div id=scroll-to-top-container aria-hidden=true><button id=scroll-to-top title=回到顶部><svg class="icon"><use xlink:href="/v1.2/img/icons.svg#top"/></svg></button></div></body></html>