容器应用的设计模式

This commit is contained in:
huanqing.shao
2019-11-17 08:50:22 +08:00
parent e4da038f7f
commit 45e5aaa630
24 changed files with 840 additions and 3 deletions

View File

@ -403,7 +403,8 @@ module.exports = {
title: '概述',
collapsable: false,
children: [
'k8s-practice/micro-service/kuboard-view-of-k8s'
'k8s-practice/micro-service/kuboard-view-of-k8s',
'k8s-practice/micro-service/design-pattern'
]
},
{

View File

@ -0,0 +1,59 @@
---
# vssueId: 158
layout: LearningLayout
description: Kubernetes中_网络策略定义了一组Pod是否允许相互通信_或者与网络中的其他端点endpoint通信_本文描述了K8S集群中默认的网络策略
meta:
- name: keywords
content: Kubernetes教程,K8S教程,Kubernetes Network Model, K8S 网络模型
---
# Network Model
<AdSenseTitle>
> 参考文档: [A Guide to the Kubernetes Networking Model](https://sookocheff.com/post/kubernetes/understanding-kubernetes-networking-model/)
Kubernetes 用来在集群上运行分布式系统。分布式系统的本质使得网络组件在 Kubernetes 中是至关重要也不可或缺的。理解 Kubernetes 的网络模型可以帮助你更好的在 Kubernetes 上运行、监控、诊断你的应用程序。
网络是一个很宽泛的领域其中有许多成熟的技术。对于不熟悉网络整体背景的人而言要将各种新的概念、旧的概念放到一起来理解例如网络名称空间、虚拟网卡、IP forwarding、网络地址转换等并融汇贯通是一个非常困难的事情。本文将尝试揭开 Kubernetes 网络的面纱,并讨论 Kubernetes 相关的网络技术,以及这些技术是如何支持 Kubernetes 网络模型的。
文章有点长,分成主要的几个部分:
* 首先讨论一些 Kubernetes 基础的术语,确保大家对关键措辞的理解是一致的
* 然后讨论 Kubernetes 网络模型,及其设计和实现
* 主要的内容是:通过不同的 use case 深入探讨 Kubernetes 中网络流量是如何路由的
[[TOC]]
</AdSenseTitle>
## Kubernetes基本概念
Kubernetes 基于少数几个核心概念,不断完善,提供了非常丰富和实用的功能。本章节罗列了这些核心概念,并简要的做了概述,以便更好地支持后面的讨论。熟悉 Kubernetes 的读者可跳过这个章节。
### Kubernetes API Server
操作 Kubernetes 的方式,是调用 Kubernetes API Serverkube-apiserver的 API 接口。kubectl、kubernetes dashboard、kuboard 都是通过调用 kube-apiserver 的接口实现对 kubernetes 的管理。API server 最终将集群状态的数据存储在 [etcd](https://github.com/coreos/etcd) 中。
### 控制器Controller
控制器Controller是 Kubernetes 中最核心的抽象概念。在用户通过 kube-apiserver 声明了期望的状态以后,控制器通过不断监控 apiserver 中的当前状态,并对当前状态与期望状态之间的差异做出反应,以确保集群的当前状态不断地接近用户声明的期望状态。这个过程实现在一个循环中,参考如下伪代码:
``` go
while true:
X = currentState()
Y = desiredState()
if X == Y:
return # Do nothing
else:
do(tasks to get to Y)
```
例如,当你通过 API Server 创建一个新的 Pod 对象时Kubernetes调度器是一个控制器注意到此变化并做出将该 Pod 运行在集群中哪个节点的决定。然后,通过 API Server 修改 Pod 对象的状态。此时对应节点上的kubelet是一个控制器注意到此变化并将在其所在节点运行该 Pod设置需要的网络使 Pod 在集群内可以访问。此处,两个控制器针对不同的状态变化做出反应,以使集群的当前状态与用户指定的期望状态匹配。
### 容器组Pod
Pod 是 Kubernetes 中的最小可部署单元。一个 Pod 代表了集群中运行的一个工作负载,可以包括一个或多个 docker 容器、挂载需要的存储,并拥有唯一的 IP 地址。Pod 中的多个容器将始终在同一个节点上运行。
### 节点Node
节点是Kubernetes集群中的一台机器可以是物理机也可以是虚拟机。

View File

@ -33,7 +33,7 @@ meta:
* [Romana](https://kubernetes.io/docs/tasks/administer-cluster/network-policy-provider/romana-network-policy/)
* [Weave Net](https://kubernetes.io/docs/tasks/administer-cluster/network-policy-provider/weave-network-policy/)
::: tip
::: tip 排序
按字母顺序排序,不代表推荐顺序。本文中的例子对上述所有网络插件都有效
:::

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,457 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="511.51367"
height="405.07999"
id="svg2"
version="1.1"
inkscape:version="0.48.5 r10040"
sodipodi:docname="dependency_throttling_fsm.svg">
<defs
id="defs4">
<marker
inkscape:stockid="DotL"
orient="auto"
refY="0"
refX="0"
id="DotL"
style="overflow:visible">
<path
id="path3848"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
transform="matrix(0.8,0,0,0.8,5.92,0.8)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend"
style="overflow:visible">
<path
id="path3790"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
transform="matrix(-0.8,0,0,-0.8,-10,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend-7"
style="overflow:visible">
<path
id="path3790-7"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
transform="matrix(-0.8,0,0,-0.8,-10,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="marker5175"
style="overflow:visible">
<path
id="path5177"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
transform="matrix(-0.8,0,0,-0.8,-10,0)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4142136"
inkscape:cx="254.85212"
inkscape:cy="187.3504"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1920"
inkscape:window-height="1025"
inkscape:window-x="-2"
inkscape:window-y="-3"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid2985"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
originx="28.205078px"
originy="-649.5px" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(28.205078,2.2178174)">
<g
id="g4595">
<rect
ry="5"
y="42.362183"
x="180"
height="40"
width="100"
id="rect3773"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
<text
sodipodi:linespacing="125%"
id="text2987"
y="58.172729"
x="230.21973"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
xml:space="preserve"><tspan
y="58.172729"
x="230.21973"
id="tspan2989"
sodipodi:role="line"
style="font-weight:bold;-inkscape-font-specification:Sans Bold">Downloading</tspan><tspan
y="73.172729"
x="230.21973"
sodipodi:role="line"
id="tspan5208"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Monospace;-inkscape-font-specification:Monospace">docker pull</tspan></text>
</g>
<g
id="g4600"
transform="translate(0,20)">
<rect
ry="5"
y="102.36218"
x="180"
height="40"
width="100"
id="rect3775"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
<text
sodipodi:linespacing="125%"
id="text2991"
y="119.33582"
x="229.99121"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
xml:space="preserve"><tspan
y="119.33582"
x="229.99121"
sodipodi:role="line"
id="tspan5210"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:Sans;-inkscape-font-specification:Sans Bold">Blocked</tspan><tspan
y="134.33582"
x="229.99121"
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Monospace;-inkscape-font-specification:Monospace"
id="tspan5080">docker create</tspan></text>
</g>
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
d="m 230,82.362186 0,29.999994 0,10"
id="path3781"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotL);marker-end:url(#Arrow1Lend)"
d="m 230,2.3621826 0,40.0000004"
id="path4815"
inkscape:connector-curvature="0" />
<use
x="0"
y="0"
xlink:href="#path3781"
id="use5189"
transform="translate(0,80)"
width="744.09448"
height="1052.3622" />
<g
id="g5222"
transform="translate(0,80)">
<path
inkscape:connector-curvature="0"
id="path5218"
d="m 235,22.362183 -60,0"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5220"
d="m 175,17.362183 0,10"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<g
transform="translate(0,160)"
id="g5226">
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 235,22.362183 -60,0"
id="path5228"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 175,17.362183 0,10"
id="path5230"
inkscape:connector-curvature="0" />
</g>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
x="170"
y="105.67273"
id="text5238"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5240"
x="170"
y="105.67273">Image is pulled</tspan></text>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
x="170"
y="185.67273"
id="text5242"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5244"
x="170"
y="185.67273">Dependencies satisfied</tspan></text>
<g
id="g4600-5"
transform="translate(0,99.999987)">
<rect
ry="5"
y="102.36218"
x="180"
height="40"
width="100"
id="rect3775-6"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
<text
sodipodi:linespacing="125%"
id="text2991-4"
y="119.33582"
x="229.99121"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
xml:space="preserve"><tspan
y="119.33582"
x="229.99121"
id="tspan2993"
sodipodi:role="line"
style="font-weight:bold;-inkscape-font-specification:Sans Bold">Pending</tspan><tspan
y="134.33582"
x="229.99121"
sodipodi:role="line"
id="tspan5210-9"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Monospace;-inkscape-font-specification:Monospace" /></text>
</g>
<g
id="g4605"
transform="translate(0,119.99999)">
<rect
ry="5"
y="162.36218"
x="180"
height="40"
width="100"
id="rect3777"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
<text
sodipodi:linespacing="125%"
id="text2995"
y="179.33582"
x="230.22559"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
xml:space="preserve"><tspan
y="179.33582"
x="230.22559"
id="tspan2997"
sodipodi:role="line"
style="font-weight:bold;-inkscape-font-specification:Sans Bold">Starting</tspan><tspan
y="194.33582"
x="230.22559"
sodipodi:role="line"
id="tspan5212"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Monospace;-inkscape-font-specification:Monospace">docker start</tspan></text>
</g>
<g
id="g4610"
transform="translate(0,139.99999)">
<rect
ry="5"
y="222.36218"
x="180"
height="40"
width="100"
id="rect3779"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
<text
sodipodi:linespacing="125%"
id="text2999"
y="245.67273"
x="229.58984"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
xml:space="preserve"><tspan
y="245.67273"
x="229.58984"
id="tspan3001"
sodipodi:role="line"
style="font-weight:bold;-inkscape-font-specification:Sans Bold">Ready</tspan></text>
</g>
<use
x="0"
y="0"
xlink:href="#path3781"
id="use5189-7"
transform="translate(0,159.99999)"
width="744.09448"
height="1052.3622" />
<use
height="1052.3622"
width="744.09448"
transform="translate(0,239.99999)"
id="use5191"
xlink:href="#path3781"
y="0"
x="0" />
<g
transform="translate(0,239.99999)"
id="g5226-8">
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 235,22.362183 -60,0"
id="path5228-3"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 175,17.362183 0,10"
id="path5230-7"
inkscape:connector-curvature="0" />
</g>
<g
id="g5232"
transform="translate(0,319.99999)">
<path
inkscape:connector-curvature="0"
id="path5234"
d="m 235,22.362183 -60,0"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5236"
d="m 175,17.362183 0,10"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
x="170"
y="265.67273"
id="text5242-0"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5244-7"
x="170"
y="265.67273">Throttling policy</tspan></text>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
x="170"
y="345.67273"
id="text5246"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5248"
x="170"
y="345.67273">LivenessProbe reports its first OK</tspan></text>
<g
id="g5341"
transform="translate(140,-50)">
<rect
ry="5"
transform="translate(-28.205078,-2.2178174)"
y="414.57999"
x="208.20508"
height="40"
width="100"
id="rect5335"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
<text
sodipodi:linespacing="125%"
id="text5337"
y="436.83582"
x="229.95605"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
xml:space="preserve"><tspan
y="436.83582"
x="229.95605"
id="tspan5339"
sodipodi:role="line"
style="font-weight:bold;-inkscape-font-specification:Sans Bold">Failed</tspan></text>
</g>
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5175)"
d="m 278.20508,324.57999 0,10 120,0 0,30"
id="path5346"
inkscape:connector-curvature="0"
transform="translate(-28.205078,-2.2178174)" />
<g
transform="matrix(-1,0,0,1,600,319.99999)"
id="g6068">
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 235,22.362183 -60,0"
id="path6070"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 175,17.362183 0,10"
id="path6072"
inkscape:connector-curvature="0" />
</g>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
x="430"
y="346.83582"
id="text6074"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan6076"
x="430"
y="346.83582">Time-out</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,319 @@
---
vssueId: 160
layout: LearningLayout
lessAds: false
description: Kubernetes教程_容器和容器编排K8S的广泛使用_让我们可以轻松的构建基于微服务的云原生CloudNative的应用_容器成为了云时代的新的编程单元_类似面向对象概念下的对象_J2EE中的组件或者函数式编程中的函数_本文探讨了容器应用的设计模式和反模式
meta:
- name: keywords
content: Kubernetes教程,K8S教程,容器应用设计模式,K8S培训,K8S教程
---
# 容器应用的设计原则、模式和反模式
<AdSenseTitle>
> 转载文章: [基于容器应用,著名的设计原则、模式和反模式](https://blog.csdn.net/cpongo2/article/details/90172525)
>
> 作者naughty
</AdSenseTitle>
容器和容器编排Kubernetes的广泛使用让我们可以轻松的构建基于微服务的“云原生”Cloud Native的应用。容器成为了云时代的新的编程单元类似面向对象概念下的**对象**J2EE中的**组件**或者函数式编程中的**函数**。
在面向对象时代,有许多著名的设计原则,模式和反模式等,例如:
- [SOLID](https://zh.wikipedia.org/wiki/SOLID_(面向对象设计)) (**单一功能、开闭原则、里氏替换、接口隔离**以及**依赖反转**
- [Design Patterns: Elements of Reusable Object-Oriented Software](https://zh.wikipedia.org/wiki/设计模式:可复用面向对象软件的基础)
- [Anti-Pattern](https://zh.wikipedia.org/wiki/反面模式)
在新的容器背景下,相应的原则和模式有助于帮助我们更好的构建“云原生”的应用。我们可以看到,这些原则和模式并非对之前模式的颠覆和推翻,更像是适应新环境的演进版本。
## 设计原则
### 单一职责原则
单一职责原则 SINGLE CONCERN PRINCIPLE (SCP)
与OO的单一功能相对应每一个容器应该提供单一的职责只关注于做好一件事。单一职责使得容器更容易重用。通常容器对应于一个进程而该进程专注于做好一件事。
<p style="max-width: 360px;">
<img src="./design-pattern.assets/081805_dMnE_1450051.png" alt="K8S教程_容器设计模式_单一职责"/>
</p>
### 高可观测性原则
高可观测性原则 HIGH OBSERVABILITY PRINCIPLE (HOP)
容器像对象一样,应该是一个封装良好的黑盒子。但是在云的环境下,这个黑盒子应该提供良好的观测接口,使得其在云的环境下得到相应的监控和管理。这样,整个应用才能提供一致的生命周期的管理。
<p style="max-width: 480px;">
<img src="./design-pattern.assets/081820_9EV5_1450051.png" alt="K8S教程_容器设计模式_可观测性"/>
</p>
可观测性包含:
- 提供健康检查 Health Check或者心跳
- 提供状态
- 把日志输出到标准输出(STDOUT)和标准出错(STDERR)
- 等等
### 生命周期确认原则
生命周期确认原则 LIFE-CYCLE CONFORMANCE PRINCIPLE (LCP)
生命周期确认原则指的是容器应该提供和平台交互来处理相应的生命周期的变化。
<p style="max-width: 480px;">
<img src="./design-pattern.assets/081854_Zofh_1450051.png" alt="K8S教程_容器设计模式_生命周期确认"/>
</p>
- 捕获并响应Terminate (SIGTERM)信号来尽快优雅的终止服务进程以避免kill (SIGKILL)信号强行终止进程。例如一下的NodeJS代码。
```
process.on('SIGTERM', function () {
console.log("Received SIGTERM. Exiting.")
server.close(function () {
process.exit(0);
});
});
```
- 返回退出码
```
process.exit(0);
```
### 镜像不可变原则
镜像不可变原则 IMAGE IMMUTABILITY PRINCIPLE (IIP)
在运行时,配置可以不同,但是镜像应该是不可变的。
<p style="max-width: 360px;">
<img src="./design-pattern.assets/081936_Dt8b_1450051.png" alt="K8S教程_容器设计模式_镜像不变"/>
</p>
我们可以理解为镜像是个类,是容器是对象实例,类是不变的,而容器是拥有不同配置参数的镜像实例。
### 进程用完既丢原则
进程用完既丢原则 PROCESS DISPOSABILITY PRINCIPLE (PDP)
在云环境下,我们应该假定所有的容器都是临时的,它随时有可能被其它的容器实例所替代。
<p style="max-width: 320px;">
<img src="./design-pattern.assets/082048_0f52_1450051.png" alt="K8S教程_容器设计模式_可替代"/>
</p>
这也就意味着需要把容器的状态保存在容器之外。并且尽可能快速的启动和终止容器。通常越小的容器就越容易实现这一点。
### 自包含原则
自包含原则 SELF-CONTAINMENT PRINCIPLE (S-CP)
容器在构建的时候应该包含所有的依赖,也就是所说容器在运行时不应该有任何的外部依赖。
<p style="max-width: 360px;">
<img src="./design-pattern.assets/082131_DgeT_1450051.png" alt="K8S教程_容器设计模式_无外部依赖"/>
</p>
### 限制运行资源原则
限制运行资源原则 RUNTIME CONFINEMENT PRINCIPLE (RCP)
容器的最佳实践应该是在运行时指定容器对资源配置的需求。例如需要多少的内存CPU等等。这样做可以使得容器编排能都更有效的调度和管理资源。
<p style="max-width: 360px;">
<img src="./design-pattern.assets/082226_Neiw_1450051.png" alt="K8S教程_容器设计模式_限制运行资源原则"/>
</p>
## 模式
许多容器应用的模式和Pod的概念相关Pod是Kubernetes为了有效的管理容器而提出的概念它是容器的集合我们可以理解为“超容器”我随便发明的。Pod包含的容器之间就好像运行在同一台机器上这些容器共享Localhost主机地址可以本机通信共享卷等等。
<p style="max-width: 360px;">
<img src="./design-pattern.assets/003308_McET_1450051.png" style="padding: 10px;" alt="K8S教程_容器设计模式_容器组"/>
</p>
Kubernetes 类似云上OS提供了用容器构建云原生应用的最佳实践。我们看看这些常见的模式都有什么。
### SideCar
![基于容器应用,著名的设计原则、模式和反模式](./design-pattern.assets/aba185d2d2ea48afa38995beca42d658.jpeg)
<p style="max-width: 480px;">
<img src="./design-pattern.assets/640.jpg" alt="K8S教程_容器设计模式_边三轮"/>
</p>
Sidecar是最常见的模式在同一个Pod中我们需要把不同的责任分在不同的容器中对外部提供一个完整的功能。
<p style="max-width: 480px;">
<img src="./design-pattern.assets/081306_lJAf_1450051.png" alt="K8S教程_容器设计模式_SideCar"/>
</p>
这样的例子有很多,例如:
- 上图中的Node后端和提供缓存的Redis
- Web服务器和收集日志的服务
- Web服务器和负责监控服务器性能数据的服务
这样做有点类似面向对象的[组合模式](https://en.wikipedia.org/wiki/Composite_pattern),好处有很多:
### 代理容器
![K8S教程_容器设计模式_Composite Pattern Implementation - UML Class Diagram](./design-pattern.assets/composite-design-pattern-implementation-uml-class-diagram.png)
- 应用单一职责原则,每一个容器只负责专注做好一件事。
- 隔离,容器之间不会出现互相竞争资源,当一个次要功能(例如日志收集或者缓存)失效或者崩溃的时候,对主要功能的影响降至最小。
- 可以对每一个容器进行独立的生命周期管理
- 可以对每一个容器进行独立的弹性扩张
- 可以方便的替换其中一个容器
### 适配器容器
![K8S教程_容器设计模式_Proxy Pattern Implementation - UML Class Diagram](./design-pattern.assets/proxy-design-pattern-implementation-uml-class-diagram.png)
类似于面向对象的[Proxy模式](https://en.wikipedia.org/wiki/Proxy_pattern)利用Pod中一个容器提供对外的访问连接。如下图中Node后端总是通过Service Discovery容器来和外部进行通信。
<p style="max-width: 540px;">
<img src="./design-pattern.assets/081406_IGU6_1450051.png" alt="K8S教程_容器设计模式_适配器容器"/>
</p>
这样做负责Node模块开发的只需要假定所有的通信都是来自于本机而把通信的复杂性交给代理容器去处理诸如负载均衡安全过滤请求必要时中断通信等功能。
![K8S教程_容器设计模式_Adapter Pattern Implementation - UML Class Diagram](./design-pattern.assets/adapter-pattern.png)
大家常常会把面向对象的Proxy模式Bridge模式和[Adapter模式](https://en.wikipedia.org/wiki/Adapter_pattern)搞混因为单单从UML关系图上来看它们都大同小异。似乎只是取了不同的名字。事实也确实如此就像几乎所有的OO模式都是组合模式的衍生所有容器模式都是边车模式的衍生。
在下图的例子中如果Logging Adapter的名字不提及Adapter我们不会认为这是个适配器模式。
<p style="max-width: 540px;">
<img src="./design-pattern.assets/081343_Rzhv_1450051.png" alt="K8S教程_容器设计模式_适配器模式"/>
</p>
其实适配器模式关注的是如果把Pod内部的不同容器的功能通过适配器统一的暴漏出来。在上图中如果我们再多加一个容器它同时会向卷中写入日志的化这样就更清楚了。Logging Adapter适配不同容器用不同的接口提供的日志并提供统一的访问接口。
### 容器链
![K8S教程_容器设计模式_chain of Responsability Implementation - UML Class Diagram](./design-pattern.assets/chain-of-responsability.gif)
类似于OO的[责任链模式](http://www.oodesign.com/chain-of-responsibility-pattern.html),把负责不同功能的容器按照依赖顺序链在一起,也是一种常见的模式。
<p style="max-width: 600px;">
<img src="./design-pattern.assets/081441_MpKK_1450051.png" alt="K8S教程_容器设计模式_责任链"/>
</p>
### 准备就绪的Pod
![K8S教程_容器设计模式_状态机](./design-pattern.assets/ready.svg)
通常作为服务的容器有一个启动的过程在启动过程中服务是不可用的。Kubernetes提供了[Readiness](/learning/k8s-intermediate/workload/pod-lifecycle.html#容器的检查)探测功能。
```
readinessProbe:
httpGet:
path: /
port: 5000
timeoutSeconds: 1
periodSeconds: 5
```
和其它模式相比这个更像是一个使用Kubernetes的最佳实践。
## 反模式
### 构建环境和运行环境混杂在一起
应该使得用于生产的运行环境的镜像尽可能的小,避免在运行环境的镜像中包含构建时的残留。
例如下面的Dockerfile例子
```
FROM ubuntu:14.04
RUN apt-get update
RUN apt-get install gcc
RUN gcc hello.c -o /hello
```
在这个构建的镜像中有很多不需要也不应该出现在生产环境中的东西例如gcc源代码hello.c。这样的结果既不安全直接暴漏源代码也会有性能开销过大的镜像体积导致加载变慢
Docker17.05 以后提供的[multi-stage builds](https://docs.docker.com/develop/develop-images/multistage-build/)也可以解决这个问题。
### 直接使用Pod
避免直接使用Pod用Deployment来管理Pod。利用Deployment可以很方便的对Pod进行扩展和管理。
### 使用latest标签
Latest标签用于标记最近的稳定版本然而在创建容器时尽可能避免在生产环境使用Latest标签。即使使用imagePullPolicy选项为alway。
### 快速失败的任务
Job是Kubernetes提供的只运行一次的容器和service正好相反。要避免快速失败
```
apiVersion: batch/v1
kind: Job
metadata:
name: bad
spec:
template:
metadata:
name: bad
spec:
restartPolicy: Never
containers:
- name: box
image: busybox
command: ["/bin/sh", "-c", "exit 1"]
```
如果你尝试在你的cluster里面创建以上的Job你可能会碰到如下的状态。
```
$ kubectl describe jobs
Name: bad
Namespace: default
Image(s): busybox
Selector: controller-uid=18a6678e-11d1-11e7-8169-525400c83acf
Parallelism: 1
Completions: 1
Start Time: Sat, 25 Mar 2017 20:05:41 -0700
Labels: controller-uid=18a6678e-11d1-11e7-8169-525400c83acf
job-name=bad
Pods Statuses: 1 Running / 0 Succeeded / 24 Failed
No volumes.
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1 {job-controller } Normal SuccessfulCreate Created pod: bad-fws8g
1m 1m 1 {job-controller } Normal SuccessfulCreate Created pod: bad-321pk
1m 1m 1 {job-controller } Normal SuccessfulCreate Created pod: bad-2pxq1
1m 1m 1 {job-controller } Normal SuccessfulCreate Created pod: bad-kl2tj
1m 1m 1 {job-controller } Normal SuccessfulCreate Created pod: bad-wfw8q
1m 1m 1 {job-controller } Normal SuccessfulCreate Created pod: bad-lz0hq
1m 1m 1 {job-controller } Normal SuccessfulCreate Created pod: bad-0dck0
1m 1m 1 {job-controller } Normal SuccessfulCreate Created pod: bad-0lm8k
1m 1m 1 {job-controller } Normal SuccessfulCreate Created pod: bad-q6ctf
1m 1s 16 {job-controller } Normal SuccessfulCreate (events with common reason combined)
```
因为任务快速失败。Kubernetes认为任务没能成功启动尝试创建新的容器以恢复这个失败导致的Cluster会在短时间创建大量的容器这样的结果可能会消耗大量的计算资源。
在Spec中使用.spec.activeDeadlineSeconds来避免这个问题。这个参数定了等待多长时间重试失败的Job。
## 参考资料
- [https://www.redhat.com/cms/managed-files/cl-cloud-native-container-design-whitepaper-f8808kc-201710-v3-en.pdf](https://www.redhat.com/cms/managed-files/cl-cloud-native-container-design-whitepaper-f8808kc-201710-v3-en.pdf)
- [https://www.slideshare.net/luebken/container-patterns](https://www.slideshare.net/luebken/container-patterns)
- [https://github.com/luebken/container-patterns](https://github.com/luebken/container-patterns)
- [https://kubernetes.io/blog/2015/06/the-distributed-system-toolkit-patterns/](https://kubernetes.io/blog/2015/06/the-distributed-system-toolkit-patterns/)
- [http://docs.projectatomic.io/container-best-practices/](http://docs.projectatomic.io/container-best-practices/)
- [https://www.usenix.org/system/files/conference/hotcloud16/hotcloud16_burns.pdf](http://https//www.usenix.org/system/files/conference/hotcloud16/hotcloud16_burns.pdf)
- [https://github.com/gravitational/workshop/blob/master/k8sprod.md](https://github.com/gravitational/workshop/blob/master/k8sprod.md)

View File

@ -1,6 +1,7 @@
---
vssueId: 67
layout: LearningLayout
sharingTitle: 从微服务视角理解Kubernetes并快速在K8S上落地微服务
lessAds: true
description: Kubernetes教程_本文描述了一个经典微服务参考架构_并且通过三个视图集群概览、名称空间、工作负载理解微服务与Kubernetes的映射关系。
meta:
@ -8,7 +9,7 @@ meta:
content: Kubernetes教程,K8S教程,Kubernetes微服务,K8S培训,K8S教程
---
# 从微服务视角理解Kubernetes并快速在K8S上落地微服务
# 从微服务视角理解Kubernetes
<AdSenseTitle/>