1044 lines
44 KiB
HTML
1044 lines
44 KiB
HTML
<!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是来自Google,IBM和Lyft的一个Service Mesh(服务网格)开源项目,是Google继Kubernetes之后的又一大作,本文将演示如何从裸机开始从零搭建Istio及Bookinfo示例程序。">
|
||
<meta property="og:description" content="Istio是来自Google,IBM和Lyft的一个Service Mesh(服务网格)开源项目,是Google继Kubernetes之后的又一大作,本文将演示如何从裸机开始从零搭建Istio及Bookinfo示例程序。" />
|
||
<meta property="twitter:description" content="Istio是来自Google,IBM和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>WHAT’S 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是来自Google,IBM和Lyft的一个Service Mesh(服务网格)开源项目,是Google继Kubernetes之后的又一大作,Istio架构先进,设计合理,刚一宣布就获得了Linkerd,nginmesh等其他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在架构设计上支持各种服务部署平台,包括kubernetes,cloud foundry,Mesos等,但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->Manage Environment->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->kubernetes->KUBERNETES->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="$PATH:/home/ubuntu/istio-0.2.10/bin"
|
||
</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 <none> 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 <none> 9091/TCP,9093/TCP,9094/TCP,9102/TCP,9125/UDP,42422/TCP 26s
|
||
istio-pilot 10.43.211.140 <none> 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 <(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 <none> 9080/TCP 6m
|
||
kubernetes 10.43.0.1 <none> 443/TCP 5d
|
||
productpage 10.43.19.154 <none> 9080/TCP 6m
|
||
ratings 10.43.50.160 <none> 9080/TCP 6m
|
||
reviews 10.43.219.248 <none> 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 >> 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
|
||
- "15001"
|
||
- -u
|
||
- "1337"
|
||
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='{.spec.containers[*].name}'
|
||
|
||
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='{.status.containerStatuses[0].containerID}' | cut -c 10-21)
|
||
|
||
PID=$(sudo docker inspect --format '{{ .State.Pid }}' $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/">WHAT’S A SERVICE MESH? AND WHY DO I NEED ONE?</a></li>
|
||
<li><a href="https://thenewstack.io/hackers-guide-kubernetes-networking/">A Hacker’s 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">←
|
||
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 →</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 © 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>
|