Files
davidpaulyoung/public/2017/11/04/istio-install_and_example/index.html
David Young d0d428f3bf build site
2026-05-14 14:23:58 -06:00

1044 lines
44 KiB
HTML
Raw 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="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script>
(function() {
const autoTheme = false;
if (autoTheme) {
document.documentElement.setAttribute('data-auto-theme', 'true');
}
const theme = localStorage.getItem('cleanwhite-theme') ||
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
document.documentElement.setAttribute('data-theme', theme);
})();
</script>
<meta property="og:site_name" content="David Young">
<meta property="og:type" content="article">
<meta property="og:image" content="https://davidpaulyoung.com//img/istio-install_and_example/post-bg.jpg">
<meta property="twitter:image" content="https://davidpaulyoung.com//img/istio-install_and_example/post-bg.jpg" />
<meta name="title" content="Istio及Bookinfo示例程序安装试用笔记" />
<meta property="og:title" content="Istio及Bookinfo示例程序安装试用笔记" />
<meta property="twitter:title" content="Istio及Bookinfo示例程序安装试用笔记" />
<meta name="description" content="Istio是来自GoogleIBM和Lyft的一个Service Mesh服务网格开源项目是Google继Kubernetes之后的又一大作,本文将演示如何从裸机开始从零搭建Istio及Bookinfo示例程序。">
<meta property="og:description" content="Istio是来自GoogleIBM和Lyft的一个Service Mesh服务网格开源项目是Google继Kubernetes之后的又一大作,本文将演示如何从裸机开始从零搭建Istio及Bookinfo示例程序。" />
<meta property="twitter:description" content="Istio是来自GoogleIBM和Lyft的一个Service Mesh服务网格开源项目是Google继Kubernetes之后的又一大作,本文将演示如何从裸机开始从零搭建Istio及Bookinfo示例程序。" />
<meta property="og:url" content="https://davidpaulyoung.com/2017/11/04/istio-install_and_example/" />
<meta property="twitter:card" content="summary" />
<meta name="keyword" content="Von Balthasar, Scripture, Gravel Riding, Ham Radio, Divine Office, Open Source">
<link rel="shortcut icon" href="/img/favicon.ico">
<title>Istio及Bookinfo示例程序安装试用笔记 | David Young Blog</title>
<link rel="canonical" href="/2017/11/04/istio-install_and_example/">
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="/css/hugo-theme-cleanwhite.css">
<link rel="stylesheet" href="/css/theme-variables.css">
<link rel="stylesheet" href="/css/zanshang.min.css">
<link rel="stylesheet" href="/css/font-awesome.all.min.css">
<script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
<script src="/js/hux-blog.min.js"></script>
<script src="/js/lazysizes.min.js"></script>
</head>
<nav class="navbar navbar-default navbar-custom navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header page-scroll">
<button type="button" class="navbar-toggle">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">David Young</a>
</div>
<div id="huxblog_navbar">
<div class="navbar-collapse">
<ul class="nav navbar-nav navbar-right">
<li>
<a href="/">All Posts</a>
</li>
<li>
<a href="/categories/life/">life</a>
</li>
<li>
<a href="/categories/tech/">tech</a>
</li>
<li>
<a href="/categories/tips/">tips</a>
</li>
<li><a href="/archive//">ARCHIVE</a></li>
<li><a href="/notes//">NOTES</a></li>
<li><a href="/about//">ABOUT</a></li>
<li>
<a href="/search"><i class="fa fa-search"></i></a>
</li>
<li>
<a href="#" id="theme-toggle" title="Toggle dark mode" style="opacity: 0;">
<i class="fa fa-moon"></i>
<i class="fa fa-sun" style="display: none;"></i>
</a>
</li>
<script>
(function() {
var theme = localStorage.getItem('cleanwhite-theme') ||
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
var toggleBtn = document.getElementById('theme-toggle');
if (toggleBtn) {
var moonIcon = toggleBtn.querySelector('.fa-moon');
var sunIcon = toggleBtn.querySelector('.fa-sun');
if (theme === 'dark') {
if (moonIcon) moonIcon.style.display = 'none';
if (sunIcon) sunIcon.style.display = 'inline';
toggleBtn.setAttribute('title', 'Switch to light mode');
} else {
if (moonIcon) moonIcon.style.display = 'inline';
if (sunIcon) sunIcon.style.display = 'none';
toggleBtn.setAttribute('title', 'Switch to dark mode');
}
requestAnimationFrame(function() {
toggleBtn.style.transition = 'opacity 0.2s ease';
toggleBtn.style.opacity = '1';
});
}
})();
</script>
</ul>
</div>
</div>
</div>
</nav>
<script>
var $body = document.body;
var $toggle = document.querySelector('.navbar-toggle');
var $navbar = document.querySelector('#huxblog_navbar');
var $collapse = document.querySelector('.navbar-collapse');
$toggle.addEventListener('click', handleMagic)
function handleMagic(e){
if ($navbar.className.indexOf('in') > 0) {
$navbar.className = " ";
setTimeout(function(){
if($navbar.className.indexOf('in') < 0) {
$collapse.style.height = "0px"
}
},400)
}else{
$collapse.style.height = "auto"
$navbar.className += " in";
}
}
document.addEventListener('DOMContentLoaded', function() {
var navLinks = document.querySelectorAll('.navbar-collapse a');
navLinks.forEach(function(link) {
link.addEventListener('click', function() {
if ($navbar.className.indexOf('in') > 0) {
$navbar.className = " ";
setTimeout(function(){
if($navbar.className.indexOf('in') < 0) {
$collapse.style.height = "0px"
}
},400)
}
});
});
});
</script>
<style type="text/css">
header.intro-header {
background-image: url('/img/istio-install_and_example/post-bg.jpg')
}
</style>
<header class="intro-header" >
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<div class="post-heading">
<div class="tags">
<a class="tag" href="/tags/istio" title="Istio">
Istio
</a>
</div>
<h1>Istio及Bookinfo示例程序安装试用笔记</h1>
<h2 class="subheading">手把手教你从零搭建Istio及Bookinfo示例程序</h2>
<span class="meta">
Posted by
赵化冰
on
Saturday, November 4, 2017
</span>
</div>
</div>
</div>
</div>
</header>
<article>
<div class="container">
<div class="row">
<div class="
col-lg-8 col-lg-offset-2
col-md-10 col-md-offset-1
post-container">
<h2 id="服务网格简介">服务网格简介</h2>
<p><strong>服务网格</strong>Service Mesh是为解决微服务的通信和治理而出现的一种<strong>架构模式</strong></p>
<p>服务网格将服务间通讯以及与此相关的管理控制功能从业务程序中下移到一个基础设施层,从而彻底隔离了业务逻辑和服务通讯两个关注点。采用服务网格后,应用开发者只需要关注并实现应用业务逻辑。服务之间的通信,包括服务发现,通讯的可靠性,通讯的安全性,服务路由等由服务网格层进行处理,并对应用程序透明。</p>
<p>让我们来回顾一下微服务架构的发展过程。在出现服务网格之前,我们在微服务应用程序进程内处理服务通讯逻辑,包括服务发现,熔断,重试,超时等逻辑,如下图所示:<br>
<img src="/img/istio-install_and_example/5-a.png" alt="">
<br>
通过对这部分负责服务通讯的逻辑进行抽象和归纳,可以形成一个代码库供应用程序调用。但应用程序还是需要处理和各种语言代码库的调用细节,并且各种代码库互不兼容,导致对应用程序使用的语言和代码框架有较大限制。</p>
<p>如果我们更进一步,将这部分逻辑从应用程序进程中抽取出来,作为一个单独的进程进行部署,并将其作为服务间的通信代理,如下图所示:<br>
<img src="/img/istio-install_and_example/6-a.png" alt="">
<br>
因为通讯代理进程和应用进程一起部署因此形象地把这种部署方式称为“sidecar”三轮摩托的挎斗
<img src="/img/istio-install_and_example/sidecar.jpg" alt="">
应用间的所有流量都需要经过代理由于代理以sidecar方式和应用部署在同一台主机上应用和代理之间的通讯被认为是可靠的。然后由代理来负责找到目的服务并负责通讯的可靠性和安全等问题。</p>
<p>当服务大量部署时随着服务部署的sidecar代理之间的连接形成了一个如下图所示的网格被称之为Service Mesh服务网格从而得出如下的服务网格定义。</p>
<p><em>服务网格是一个基础设施层,用于处理服务间通信。云原生应用有着复杂的服务拓扑,服务网格保证请求可以在这些拓扑中可靠地穿梭。在实际应用当中,服务网格通常是由一系列轻量级的网络代理组成的,它们与应用程序部署在一起,但应用程序不需要知道它们的存在。</em></p>
<p>_William Morgan <em><a href="https://buoyant.io/2017/04/25/whats-a-service-mesh-and-why-do-i-need-one/"><em>WHATS A SERVICE MESH? AND WHY DO I NEED ONE?</em></a></em> _</p>
<p>
<img src="/img/istio-install_and_example/mesh1.png" alt="">
</p>
<p>了解了服务网格的基本概念,下一步介绍一下<a href="https://istio.io/">Istio</a>。Istio是来自GoogleIBM和Lyft的一个Service Mesh服务网格开源项目是Google继Kubernetes之后的又一大作Istio架构先进设计合理刚一宣布就获得了Linkerdnginmesh等其他Service Mesh项目的合作以及Red hat/Pivotal/Weaveworks/Tigera/Datawire等的积极响应。<br>
<img src="/img/istio-install_and_example/Istio-Architecture.PNG" alt="">
<br>
可以设想在不久的将来微服务的标准基础设施将是采用kubernetes进行服务部署和集群管理采用Istio处理服务通讯和治理两者相辅相成缺一不可。</p>
<h2 id="安装kubernetes">安装Kubernetes</h2>
<p>Istio是微服务通讯和治理的基础设施层本身并不负责服务的部署和集群管理因此需要和Kubernetes等服务编排工具协同工作。</p>
<p>Istio在架构设计上支持各种服务部署平台包括kubernetescloud foundryMesos等但Istio作为Google亲儿子对自家兄弟Kubernetes的支持肯定是首先考虑的。目前版本的0.2版本的手册中也只有Kubernetes集成的安装说明其它部署平台和Istio的集成将在后续版本中支持。</p>
<p>从Istio控制面Pilot的架构图可以看到各种部署平台可以通过插件方式集成到Istio中为Istio提供服务注册和发现功能。</p>
<p>
<img src="/img/istio-install_and_example/PilotAdapters.PNG" alt="">
</p>
<p>kubernetes集群的部署较为复杂<a href="http://rancher.com">Rancher</a>提供了kubernetes部署模板通过一键式安装可以大大简化kubernetes集群的安装部署过程。</p>
<p>本文的测试环境为两台虚机组成的集群操作系统是Ubuntu 16.04.3 LTS。两台虚机的地址分别为<br>
Rancher Server: 10.12.25.60<br>
工作节点: 10.12.25.116</p>
<p>通过Rancher安装Kubernetes集群的简要步骤如下</p>
<h3 id="在server和工作节点上安装docker">在server和工作节点上安装docker</h3>
<p>因为k8s并不支持最新版本的docker因此需根据该页面安装指定版本的docker<br>
<a href="http://rancher.com/docs/rancher/v1.6/en/hosts/">http://rancher.com/docs/rancher/v1.6/en/hosts/</a> ,目前是1.12版本。</p>
<pre tabindex="0"><code>curl https://releases.rancher.com/install-docker/1.12.sh | sh
</code></pre><p>如果需要以非root用户执行docker命令参考<a href="http://zhaohuabing.com/2018/02/09/docker-without-sudo/">如何使用非root用户执行docker命令</a></p>
<h3 id="启动rancher-server">启动Rancher server</h3>
<pre tabindex="0"><code>sudo docker run -d --restart=always -p 8080:8080 rancher/server
</code></pre><h3 id="登录rancher管理界面创建k8s集群">登录Rancher管理界面创建k8s集群</h3>
<p>Rancher 管理界面的缺省端口为8080在浏览器中打开该界面通过菜单Default-&gt;Manage Environment-&gt;Add Environment添加一个kubernetes集群。这里需要输入名称kubernetes描述然后选择kubernetes template点击create创建Kubernetes环境。
<img src="/img/istio-install_and_example/Rancher.PNG" alt="">
</p>
<p>点击菜单切换到kubernetes Environment然后点击右上方的Add a host添加一台host到kubernetes集群中。注意添加到集群中的host上必须先安装好符合要求的docker版本。</p>
<p>然后根据Rancher页面上的提示在host上执行脚本启动Rancher agent以将host加入ranch cluster。注意脚本中包含了rancher server的地址在host上必须可以ping通该地址。
<img src="/img/istio-install_and_example/Rancher-add-host.PNG" alt="">
</p>
<p>host加入cluster后Rancher会在host上pull kubernetes的images并启动kubernetes相关服务根据安装环境所在网络情况不同需要等待几分钟到几十分钟不等。</p>
<h3 id="安装并配置kubectl">安装并配置kubectl</h3>
<p>待Rancher界面提示kubernetes创建成功后安装kubernetes命令行工具kubectl</p>
<pre tabindex="0"><code>curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.7.4/bin/linux/amd64/kubectl
chmod +x ./kubectl
sudo mv ./kubectl /usr/local/bin/kubectl
</code></pre><p>登录Rancher管理界面, 将 All Environments-&gt;kubernetes-&gt;KUBERNETES-&gt;CLI create config 的内容拷贝到~/.kube/config 中以配置Kubectl和kubernetes server的连接信息。
<img src="/img/istio-install_and_example/Rancher-kubectl.PNG" alt="">
</p>
<h2 id="安装istio">安装Istio</h2>
<p>Istio提供了安装脚本该脚本会根据操作系统下载相应的Istio安装包并解压到当前目录。</p>
<pre tabindex="0"><code> curl -L https://git.io/getLatestIstio | sh -
</code></pre><p>根据脚本的提示将Istio命令行所在路径加入到系统PATH环境变量中</p>
<pre tabindex="0"><code>export PATH=&#34;$PATH:/home/ubuntu/istio-0.2.10/bin&#34;
</code></pre><p>在kubernetes集群中部署Istio控制面服务</p>
<pre tabindex="0"><code>kubectl apply -f istio-0.2.10/install/kubernetes/istio.yaml
</code></pre><p>确认Istio控制面服务已成功部署。Kubernetes会创建一个istio-system namespace将Istio相关服务部署在该namespace中。</p>
<p>确认Istio相关Service的部署状态</p>
<pre tabindex="0"><code>kubectl get svc -n istio-system
</code></pre><pre tabindex="0"><code>NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-egress 10.43.192.74 &lt;none&gt; 80/TCP 25s
istio-ingress 10.43.16.24 10.12.25.116,... 80:30984/TCP,443:30254/TCP 25s
istio-mixer 10.43.215.250 &lt;none&gt; 9091/TCP,9093/TCP,9094/TCP,9102/TCP,9125/UDP,42422/TCP 26s
istio-pilot 10.43.211.140 &lt;none&gt; 8080/TCP,443/TCP 25s
</code></pre><p>确认Istio相关Pod的部署状态</p>
<pre tabindex="0"><code>kubectl get pods -n istio-system
</code></pre><pre tabindex="0"><code>NAME READY STATUS RESTARTS AGE
istio-ca-367485603-qvbfl 1/1 Running 0 2m
istio-egress-3571786535-gwbgk 1/1 Running 0 2m
istio-ingress-2270755287-phwvq 1/1 Running 0 2m
istio-mixer-1505455116-9hmcw 2/2 Running 0 2m
istio-pilot-2278433625-68l34 1/1 Running 0 2m
</code></pre><p>从上面的输出可以看到这里部署的主要是Istio控制面的服务而数据面的网络代理要如何部署呢<br>
根据前面服务网格的架构介绍可以得知网络代理是随着应用程序以sidecar的方式部署的在下面部署Bookinfo示例程序时会演示如何部署网络代理。</p>
<h2 id="部署bookinfo示例程序">部署Bookinfo示例程序</h2>
<p>在下载的Istio安装包的samples目录中包含了示例应用程序。</p>
<p>通过下面的命令部署Bookinfo应用</p>
<pre tabindex="0"><code>kubectl apply -f &lt;(istioctl kube-inject -f istio-0.2.10/samples/bookinfo/kube/bookinfo.yaml)
</code></pre><p>确认Bookinfo服务已经启动</p>
<pre tabindex="0"><code>kubectl get services
</code></pre><pre tabindex="0"><code>NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
details 10.43.175.204 &lt;none&gt; 9080/TCP 6m
kubernetes 10.43.0.1 &lt;none&gt; 443/TCP 5d
productpage 10.43.19.154 &lt;none&gt; 9080/TCP 6m
ratings 10.43.50.160 &lt;none&gt; 9080/TCP 6m
reviews 10.43.219.248 &lt;none&gt; 9080/TCP 6m
</code></pre><p>在浏览器中打开应用程序页面地址为istio-ingress的External IP</p>
<p><code>http://10.12.25.116/productpage</code><br>
<img src="/img/istio-install_and_example/Bookinfo.PNG" alt="">
</p>
<h2 id="理解istio-proxy实现原理">理解Istio Proxy实现原理</h2>
<p>服务网格相对于sprint cloud等微服务代码库的一大优势是其对应用程序无侵入在不修改应用程序代码的前提下对应用服务之间的通信进行接管Istio是如何做到这点的呢下面通过示例程序的部署剖析其中的原理。</p>
<p>如果熟悉kubernetes的应用部署过程我们知道Bookinfo应用程序的标准部署方式是这样的</p>
<pre tabindex="0"><code>kubectl apply -f istio-0.2.10/samples/bookinfo/kube/bookinfo.yaml
</code></pre><p>但从上面的部署过程可以看到kubectl apply命令的输入并不是一个kubernetes yaml文件而是<code>istioctl kube-inject -f istio-0.2.10/samples/bookinfo/kube/bookinfo.yaml</code>命令的输出。</p>
<p>这段命令在这里起到了什么作用呢通过单独运行该命令并将输出保存到文件中我们可以查看istioctl kube-inject命令到底在背后搞了什么小动作。</p>
<pre tabindex="0"><code>istioctl kube-inject -f istio-0.2.10/samples/bookinfo/kube/bookinfo.yaml &gt;&gt; bookinfo_with_sidecar.yaml
</code></pre><p>对比bookinfo/_with/_sidecar.yaml文件和bookinfo.yaml可以看到该命令在bookinfo.yaml的基础上做了如下改动</p>
<ul>
<li>
<p>为每个pod增加了一个代理container该container用于处理应用container之间的通信包括服务发现路由规则处理等。从下面的配置文件中可以看到proxy container通过15001端口进行监听接收应用container的流量。</p>
</li>
<li>
<p>为每个pod增加了一个init-container该container用于配置iptable将应用container的流量导入到代理container中。</p>
</li>
</ul>
<pre tabindex="0"><code> #注入istio 网络代理
image: docker.io/istio/proxy_debug:0.2.10
imagePullPolicy: IfNotPresent
name: istio-proxy
resources: {}
securityContext:
privileged: true
readOnlyRootFilesystem: false
runAsUser: 1337
volumeMounts:
- mountPath: /etc/istio/proxy
name: istio-envoy
- mountPath: /etc/certs/
name: istio-certs
readOnly: true
#使用init container修改iptable
initContainers:
- args:
- -p
- &#34;15001&#34;
- -u
- &#34;1337&#34;
image: docker.io/istio/proxy_init:0.2.10
imagePullPolicy: IfNotPresent
name: istio-init
</code></pre><p>从上面的分析我们可以看出Istio的kube-inject工具的用途即是将代理sidecar注入了Bookinfo的kubernetes yaml部署文件中。通过该方式不需要用户手动修改kubernetes的部署文件即可在部署服务时将sidecar和应用一起部署。</p>
<p>通过命令查看pod中部署的docker container确认是否部署了Istio代理</p>
<pre tabindex="0"><code>kubectl get pods
NAME READY STATUS RESTARTS AGE
details-v1-3688945616-8hv8x 2/2 Running 0 1d
productpage-v1-2055622944-cslw1 2/2 Running 0 1d
ratings-v1-233971408-8dcnp 2/2 Running 0 1d
reviews-v1-1360980140-474x6 2/2 Running 0 1d
reviews-v2-1193607610-cfhb5 2/2 Running 0 1d
reviews-v3-3340858212-b5c8k 2/2 Running 0 1d
</code></pre><p>查看reviews pod的中的container可以看到pod中除reviews container外还部署了一个istio-proxy container</p>
<pre tabindex="0"><code>kubectl get pod reviews-v3-3340858212-b5c8k -o jsonpath=&#39;{.spec.containers[*].name}&#39;
reviews istio-proxy
</code></pre><p>而应用container的流量是如何被导入到istio-proxy中的呢</p>
<p>原理是Istio proxy在端口15001进行监听pod中应用container的流量通过iptables规则被重定向到15001端口中。下面我们进入pod内部通过相关命令来验证这一点。</p>
<p>先通过命令行找到ratings-v1-233971408-8dcnp pod的PID以用于查看其network namespace內的iptables规则。</p>
<pre tabindex="0"><code>CONTAINER_ID=$(kubectl get po ratings-v1-233971408-8dcnp -o jsonpath=&#39;{.status.containerStatuses[0].containerID}&#39; | cut -c 10-21)
PID=$(sudo docker inspect --format &#39;{{ .State.Pid }}&#39; $CONTAINER_ID)
</code></pre><p>可以使用nsenter命令来进入pod的network namespace执行命令。<br>
使用netstat命令可以看到istio proxy代理的监听端口15001</p>
<pre tabindex="0"><code>sudo nsenter -t ${PID} -n netstat -all | grep 15001
tcp 0 0 *:15001 *:* LISTEN
</code></pre><p>使用iptables命令可以查看到下面的规则</p>
<pre tabindex="0"><code>sudo nsenter -t ${PID} -n iptables -t nat -L -n -v
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
16 960 ISTIO_REDIRECT all -- * * 0.0.0.0/0 0.0.0.0/0 /* istio/install-istio-prerouting */
Chain INPUT (policy ACCEPT 16 packets, 960 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 84838 packets, 7963K bytes)
pkts bytes target prot opt in out source destination
1969 118K ISTIO_OUTPUT tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* istio/install-istio-output */
Chain POSTROUTING (policy ACCEPT 84838 packets, 7963K bytes)
pkts bytes target prot opt in out source destination
Chain ISTIO_OUTPUT (1 references)
pkts bytes target prot opt in out source destination
0 0 ISTIO_REDIRECT all -- * lo 0.0.0.0/0 !127.0.0.1 /* istio/redirect-implicit-loopback */
1969 118K RETURN all -- * * 0.0.0.0/0 0.0.0.0/0 owner UID match 1337 /* istio/bypass-envoy */
0 0 RETURN all -- * * 0.0.0.0/0 127.0.0.1 /* istio/bypass-explicit-loopback */
0 0 ISTIO_REDIRECT all -- * * 0.0.0.0/0 0.0.0.0/0 /* istio/redirect-default-outbound */
Chain ISTIO_REDIRECT (3 references)
pkts bytes target prot opt in out source destination
16 960 REDIRECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* istio/redirect-to-envoy-port */ redir ports 15001
</code></pre><p>从pod所在network namespace的iptables规则中可以看到pod的入口和出口流量分别通过PREROUTING和OUTPUT chain指向了自定义的ISTIO/_REDIRECT chain而ISTIO/_REDIRECT chain中的规则将所有流量都重定向到了istio proxy正在监听的15001端口中。从而实现了对应用透明的通信代理。</p>
<h2 id="测试路由规则">测试路由规则</h2>
<p>多次刷新Bookinfo应用的productpage页面我们会发现该页面中显示的Book Reviews有时候有带红星的评价信息有时有带黑星的评价信息有时只有文字评价信息。<br>
这是因为Bookinfo应用程序部署了3个版本的Reviews服务每个版本的返回结果不同在没有设置路由规则时缺省的路由会将请求随机路由到每个版本的服务上如下图所示</p>
<p>
<img src="/img/istio-install_and_example/withistio.svg" alt="">
</p>
<p>通过创建一条路由规则route-rule.yaml将请求流量都引导到Reviews-v1服务上</p>
<pre tabindex="0"><code>apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: reviews-default
spec:
destination:
name: reviews
precedence: 1
route:
- labels:
version: v1
</code></pre><p>启用该路由规则</p>
<pre tabindex="0"><code>istioctl create -f route-rule.yaml -n default
</code></pre><p>再次打开productpage页面, 无论刷新多少次显示的页面将始终是v1版本的输出即不带星的评价内容。<br>
<img src="/img/istio-install_and_example/Bookinfo-no-star.PNG" alt="">
<br>
删除该路由规则</p>
<pre tabindex="0"><code>istioctl delete -f route_rule.yaml -n default
</code></pre><p>继续刷新productpage页面,将重新随机出现三个版本的评价内容页面。</p>
<h2 id="分布式调用追踪">分布式调用追踪</h2>
<p>首先修改安装包中的 <code>istio-0.2.10/install/kubernetes/addons/zipkin.yaml</code> 部署文件增加Nodeport,以便能在kubernetes集群外部访问zipkin界面。</p>
<pre tabindex="0"><code>apiVersion: v1
kind: Service
metadata:
name: zipkin
namespace: istio-system
spec:
ports:
- name: http
port: 9411
nodePort: 30001
selector:
app: zipkin
type: NodePort
</code></pre><p>部署zipkin服务。</p>
<pre tabindex="0"><code>kubectl apply -f istio-0.2.10/install/kubernetes/addons/zipkin.yaml
</code></pre><p>在浏览器中打开zipkin页面可以追踪一个端到端调用经过了哪些服务以及各个服务花费的时间等详细信息如下图所示<br>
<code>http://10.12.25.116:30001</code><br>
<img src="/img/istio-install_and_example/zipkin.PNG" alt="">
</p>
<h2 id="性能指标监控">性能指标监控</h2>
<p>首先修改安装包中的 <code>istio-0.2.10/install/kubernetes/addons/grafana.yaml</code> 部署文件增加Nodeport,以便能在kubernetes集群外部访问grafana界面。</p>
<pre tabindex="0"><code>apiVersion: v1
kind: Service
metadata:
name: grafana
namespace: istio-system
spec:
ports:
- port: 3000
protocol: TCP
name: http
nodePort: 30002
selector:
app: grafana
type: NodePort
</code></pre><p>prometheus用于收集和存储信息指标grafana用于将性能指标信息进行可视化呈现需要同时部署prometheus和grafana服务。</p>
<pre tabindex="0"><code>kubectl apply -f istio-0.2.10/install/kubernetes/addons/prometheus.yaml
kubectl apply -f istio-0.2.10/install/kubernetes/addons/grafana.yaml
</code></pre><p>首先在浏览器中打开Bookinfo的页面<code>http://10.12.25.116/productpage</code>,刷新几次,以制造一些性能指标数据。</p>
<p>然后打开grafana页面查看性能指标<code>http://10.12.25.116:30002/dashboard/db/istio-dashboard</code>,如下图所示:<br>
<img src="/img/istio-install_and_example/grafana.PNG" alt="">
</p>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://istio.io/docs/">Istio官方文档</a></li>
<li><a href="http://philcalcado.com/2017/08/03/pattern_service_mesh.html">Pattern: Service Mesh</a></li>
<li><a href="https://buoyant.io/2017/04/25/whats-a-service-mesh-and-why-do-i-need-one/">WHATS A SERVICE MESH? AND WHY DO I NEED ONE?</a></li>
<li><a href="https://thenewstack.io/hackers-guide-kubernetes-networking/">A Hackers Guide to Kubernetes Networking</a></li>
</ul>
<div class="entry-shang text-center">
<p>「真诚赞赏,手留余香」</p>
<button class="zs show-zs btn btn-bred">赞赏支持</button>
</div>
<div class="zs-modal-bg"></div>
<div class="zs-modal-box">
<div class="zs-modal-head">
<button type="button" class="close">×</button>
<span class="author"><a href="https://davidpaulyoung.com/"><img src="/img/favicon.png" />David Young</a></span>
<p class="tip"><i></i><span>真诚赞赏,手留余香</span></p>
</div>
<div class="zs-modal-body">
<div class="zs-modal-btns">
<button class="btn btn-blink" data-num="2">2元</button>
<button class="btn btn-blink" data-num="5">5元</button>
<button class="btn btn-blink" data-num="10">10元</button>
<button class="btn btn-blink" data-num="50">50元</button>
<button class="btn btn-blink" data-num="100">100元</button>
<button class="btn btn-blink" data-num="1">任意金额</button>
</div>
<div class="zs-modal-pay">
<button class="btn btn-bred" id="pay-text">2元</button>
<p>使用<span id="pay-type">微信</span>扫描二维码完成支付</p>
<img src="/img/reward/wechat-2.png" id="pay-image"/>
</div>
</div>
<div class="zs-modal-footer">
<label><input type="radio" name="zs-type" value="wechat" class="zs-type" checked="checked"><span ><span class="zs-wechat"><img src="/img/reward/wechat-btn.png"/></span></label>
<label><input type="radio" name="zs-type" value="alipay" class="zs-type" class="zs-alipay"><img src="/img/reward/alipay-btn.png"/></span></label>
</div>
</div>
<script type="text/javascript" src="/js/reward.js"></script>
<hr>
<ul class="pager">
<li class="previous">
<a href="/2017/11/03/hello-world/" data-toggle="tooltip" data-placement="top" title="Welcome to Zhaohuabing Blog">&larr;
Previous Post</a>
</li>
<li class="next">
<a href="/2017/11/07/istio-traffic-shifting/" data-toggle="tooltip" data-placement="top" title="使用Istio实现应用流量转移">Next
Post &rarr;</a>
</li>
</ul>
<link href="https://xxx.xxx.com/dist/Artalk.css" rel="stylesheet" />
<script src="https://xxx.xxx.com/dist/Artalk.js"></script>
<div id="Comments"></div>
<script>
Artalk.init({
el: '#Comments',
pageKey: 'https:\/\/davidpaulyoung.com\/2017\/11\/04\/istio-install_and_example\/',
pageTitle: 'Istio及Bookinfo示例程序安装试用笔记',
server: 'https:\/\/xxx.xxx.com',
site: 'xxx blog',
})
</script>
</div>
<div class="
col-lg-2 col-lg-offset-0
visible-lg-block
sidebar-container
catalog-container">
<div class="side-catalog">
<hr class="hidden-sm hidden-xs">
<h5>
<a class="catalog-toggle" href="#">CATALOG</a>
</h5>
<ul class="catalog-body"></ul>
</div>
</div>
<div class="
col-lg-8 col-lg-offset-2
col-md-10 col-md-offset-1
sidebar-container">
<section>
<hr class="hidden-sm hidden-xs">
<h5><a href="/tags/">FEATURED TAGS</a></h5>
<div class="tags">
<a href="/tags/docker" title="docker">
docker
</a>
<a href="/tags/istio" title="istio">
istio
</a>
<a href="/tags/kubernetes" title="kubernetes">
kubernetes
</a>
<a href="/tags/microservice" title="microservice">
microservice
</a>
<a href="/tags/security" title="security">
security
</a>
<a href="/tags/service-mesh" title="service mesh">
service mesh
</a>
<a href="/tags/tips" title="tips">
tips
</a>
</div>
</section>
<section>
<hr>
<h5>FRIENDS</h5>
<ul class="list-inline">
<li><a target="_blank" href="https://zhaozhihan.com">Linda的博客</a></li>
</ul>
</section>
</div>
</div>
</div>
</article>
<footer>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<ul class="list-inline text-center">
<li>
<a href="mailto:youremail@gmail.com">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fas fa-envelope fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li>
<a target="_blank" href="/your%20wechat%20qr%20code%20image">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fab fa-weixin fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li>
<a target="_blank" href="https://github.com/yourgithub">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fab fa-github fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li>
<a target="_blank" href="https://www.linkedin.com/in/yourlinkedinid">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fab fa-linkedin fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li>
<a target="_blank" href="https://stackoverflow.com/users/yourstackoverflowid">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fab fa-stack-overflow fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li>
<a href='' rel="alternate" type="application/rss+xml" title="David Young" >
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fas fa-rss fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
</ul>
<p class="copyright text-muted">
Copyright &copy; David Young 2026
<br>
<a href="https://themes.gohugo.io/hugo-theme-cleanwhite">CleanWhite Hugo Theme</a> by <a href="https://zhaohuabing.com">Huabing</a> |
<iframe
style="margin-left: 2px; margin-bottom:-5px;"
frameborder="0" scrolling="0" width="100px" height="20px"
src="https://ghbtns.com/github-btn.html?user=zhaohuabing&repo=hugo-theme-cleanwhite&type=star&count=true" >
</iframe>
</p>
</div>
</div>
</div>
</footer>
<script>
function loadAsync(u, c) {
var d = document, t = 'script',
o = d.createElement(t),
s = d.getElementsByTagName(t)[0];
o.src = u;
if (c) { o.addEventListener('load', function (e) { c(null, e); }, false); }
s.parentNode.insertBefore(o, s);
}
</script>
<script>
if($('#tag_cloud').length !== 0){
loadAsync("/js/jquery.tagcloud.js",function(){
$.fn.tagcloud.defaults = {
color: {start: '#bbbbee', end: '#0085a1'},
};
$('#tag_cloud a').tagcloud();
})
}
</script>
<script>
(function() {
function updateTagcloudColors() {
const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
const startColor = isDark ? '#808080' : '#bbbbee';
if($('#tag_cloud').length !== 0 && $.fn.tagcloud) {
$.fn.tagcloud.defaults = {
color: {start: startColor, end: '#0085a1'},
};
$('#tag_cloud a').tagcloud();
}
}
$(document).ready(function() {
updateTagcloudColors();
});
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.attributeName === 'data-theme') {
updateTagcloudColors();
}
});
});
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ['data-theme']
});
})();
</script>
<script>
loadAsync("https://cdn.jsdelivr.net/npm/fastclick@1.0.6/lib/fastclick.min.js", function(){
var $nav = document.querySelector("nav");
if($nav) FastClick.attach($nav);
})
</script>
<script src="/js/theme-toggle.js"></script>
<script type="text/javascript">
function generateCatalog(selector) {
_containerSelector = 'div.post-container'
var P = $(_containerSelector), a, n, t, l, i, c;
a = P.find('h1,h2,h3,h4,h5,h6');
$(selector).html('')
a.each(function () {
n = $(this).prop('tagName').toLowerCase();
i = "#" + $(this).prop('id');
t = $(this).text();
c = $('<a href="' + i + '" rel="nofollow" title="' + t + '">' + t + '</a>');
l = $('<li class="' + n + '_nav"></li>').append(c);
$(selector).append(l);
});
return true;
}
generateCatalog(".catalog-body");
$(".catalog-toggle").click((function (e) {
e.preventDefault();
$('.side-catalog').toggleClass("fold")
}))
loadAsync("\/js\/jquery.nav.js", function () {
$('.catalog-body').onePageNav({
currentClass: "active",
changeHash: !1,
easing: "swing",
filter: "",
scrollSpeed: 700,
scrollOffset: 0,
scrollThreshold: .2,
begin: null,
end: null,
scrollChange: null,
padding: 80
});
});
</script>
</body>
</html>