容器应用的设计模式
@ -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'
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
59
learning/k8s-intermediate/service/network.md
Normal 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 Server(kube-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集群中的一台机器,可以是物理机,也可以是虚拟机。
|
||||
@ -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 排序
|
||||
按字母顺序排序,不代表推荐顺序。本文中的例子对上述所有网络插件都有效
|
||||
:::
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 95 KiB |
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 120 KiB |
|
After Width: | Height: | Size: 155 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
@ -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 |
319
learning/k8s-practice/micro-service/design-pattern.md
Normal 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
|
||||
|
||||

|
||||
|
||||
<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),好处有很多:
|
||||
|
||||
### 代理容器
|
||||
|
||||

|
||||
|
||||
- 应用单一职责原则,每一个容器只负责专注做好一件事。
|
||||
- 隔离,容器之间不会出现互相竞争资源,当一个次要功能(例如日志收集或者缓存)失效或者崩溃的时候,对主要功能的影响降至最小。
|
||||
- 可以对每一个容器进行独立的生命周期管理
|
||||
- 可以对每一个容器进行独立的弹性扩张
|
||||
- 可以方便的替换其中一个容器
|
||||
|
||||
### 适配器容器
|
||||
|
||||

|
||||
|
||||
类似于面向对象的[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模块开发的只需要假定所有的通信都是来自于本机,而把通信的复杂性交给代理容器,去处理诸如负载均衡,安全,过滤请求,必要时中断通信等功能。
|
||||
|
||||

|
||||
|
||||
大家常常会把面向对象的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适配不同容器用不同的接口提供的日志,并提供统一的访问接口。
|
||||
|
||||
### 容器链
|
||||
|
||||

|
||||
|
||||
类似于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
|
||||
|
||||

|
||||
|
||||
通常作为服务的容器有一个启动的过程,在启动过程中,服务是不可用的。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)
|
||||
@ -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/>
|
||||
|
||||
|
||||