基于Kubernetes的云原生DevOps
目录
序 1
前言 3
使用代码示例
https://github.com/cloudnativedevops/demo
第1章 云革命 11
1.1 云的诞生 12
1.1.1 购买时间 12
1.1.2 基础设施即服务 13
1.2 开发运维拉开序幕 14
1.2.1 没有人真正理解开发运维 15
1.2.2 业务优势 16
1.2.3 基础设施即代码 17
1.2.4 共同学习 17
1.3 容器的到来 18
1.3.1 的技术 18
1.3.2 箱子带来的启发 19
1.3.3 将软件放入容器 20
1.3.4 即插即用的应用程序 21
1.4 容器的编排 22
1.5 Kubernetes 23
1.5.1 从Borg 到Kubernetes 23
1.5.2 什么因素导致Kubernetes 如此有价值? 24
1.5.3 Kubernetes 会消失吗? 26
1.5.4 Kubernetes 并非 26
1.6 云原生 28
1.7 运维的未来 30
1.7.1 分布式开发运维 31
1.7.2 有些仍然是中心式 31
1.7.3 开发人员生产力工程 31
1.7.4 你就是未来 32
1.8 小结 33
第2章 Kubernetes 简介 35
2.1 次运行容器 35
2.1.1 安装Docker 桌面版 36
2.1.2 什么是Docker ? 37
2.1.3 运行容器镜像 37
2.2 演示应用程序 38
2.2.1 查看源代码 38
2.2.2 Go 简介 39
2.2.3 演示应用程序的原理 40
2.3 建立容器 40
2.3.1 了解Dockerfile 41
2.3.2 限度的容器镜像 42
2.3.3 运行Docker image build 42
2.3.4 命名镜像 43
2.3.5 端口转发 43
2.4 容器仓库 44
2.4.1 容器仓库的身份验证 45
2.4.2 命名和推送镜像 45
2.4.3 运行镜像 46
2.5 Kubernetes 入门 46
2.5.1 运行演示应用 47
2.5.2 如果容器无法启动 48
2.6 Minikube 48
2.7 小结 48
第3章 获取Kubernetes 51
集群的构建、微调以及故障排除等。有关这方面的资源有很多,我们特别推荐Brendan Burns与Craig Tracey的著作《Managing Kubernetes: Operating Kubernetes Clusters in the Real World》(O'Reilly 出版)
3.1 集群架构 52
3.1.1 控制平面 52
实际上,控制平面由如下几个组件组成:
- kube-apiserver
这是控制平面的前端服务器,负责处理API请求。 - etcd
这是Kubernetes的数据库,用于存储所有信息:集群上存在哪些节点、哪些资源等。 - kube- scheduler
决定在何处运行新创建的Pod。 - kube-controller-manager
负责运行资源控制器,例如部署等。 - cloud-controller-manager
负责与云提供商(在基于云的集群中)进行交互,管理负载均衡器以及磁盘卷之类的资源。
3.1.2 节点组件 53
Kubernetes集群中的每个工作节点会运行以下组件:
- kubelet
负责容器的运行时,启动调度到节点上的工作负载,并监视其状态。 - kube-proxy
网络代理,负责路由不同节点上的Pod之间的请求,以及Pod与互联网之间的请求。
3.1.3 高可用性 54
3.2 自托管Kubernetes 的成本 56
3.2.1 超出预期的工作量 56
3.2.2 不仅仅是初始设置 57
3.2.3 不能完全依赖工具 58
3.2.4 Kubernetes 的难度很大 59
Kelsey Hightower编写的教程(Kubernetes the Hard Way》(参考链接:
https://oreil.ly/Chk5v)是掌握Kubernetes集群所有底层组件的最佳方式之一。
3.2.5 管理费用 59
3.2.6 从托管服务开始 59
3.3 托管Kubernetes 服务 60
3.3.1 Google Kubernetes Engine(GKE) 61
3.3.2 集群自动伸缩 62
3.3.3 亚马逊的Elastic Container Service for Kubernetes(EKS) 62
3.3.4 Azure Kubernetes Service(AKS) 63
3.3.5 OpenShift 63
3.3.6 IBM Cloud Kubernetes Service 63
3.4 Kubernetes 安装程序 64
3.5.1 kops 64
3.4.2 Kubespray 65
3.4.3 TK8 65
3.4.4 困难模式的Kubernetes 66
3.4.5 kubeadm 66
3.4.6 Tarmak 66
3.4.7 Rancher Kubernetes Engine(RKE) 66
3.4.8 Puppet Kubernetes 模块 67
3.4.9 Kubeformation 67
3.5 购买还是构建:我们的建议 62
3.5.1 运行更少软件 62
运行更少软件的理念拥有三大支柱:
- 选择标准的技术。
- 外包千篇一律的繁重工作。
- 创建持久的竞争优势。
3.5.2 尽可能使用托管Kubernetes 68
3.5.3 如何应对提供商锁定? 69
3.5.4 根据需要使用标准的Kubernetes 自托管工具 70
3.5.5 当你的选择受到限制时 70
3.5.6 裸金属与内部服务器 70
3.6 无集群容器服务 71
3.6.1 Amazon Fargate 72
3.6.2 Azure Container Instances(ACI) 72
3.7 小结 73
第4章 Kubernetes 对象 75
4.1 部署 75
你真正想要的是一种管理程序, 能够持续检查容器是否正在运行,如果容器停止运行,则立即再次启动。在传统的服务器中,你可以使用systemd. runit 或supervisord等工具来执行此操作。Docker 也有类似的功能,可想而知Kubernetes也有管理程序的功能,那就是部署。
4.1.1 监督与调度 76
实际上,部署并不会直接管理副本,它会自动创建一个 名叫“副本集”(ReplicaSet)
的关联对象,并由副本集来管理副本。
4.1.2 重新启动容器 76
4.1.3 查询部署 77
4.2 Pod 78
4.3 副本集 79
部署不会直接管理Pod,因为管理Pod是副本集(ReplicaSet) 对象的工作。
4.4 维持所需状态 80
4.5 Kubernetes 调度器 81
我们说过,部署会创建Pod,而Kubernetes会启动所需的Pod,但我们还没有详细解释事情的发生经过。
负责这部分处理的组件是Kubernetes调度器(scheduler)。
调度器的工作是监视未调度的Pod队列,从中获取下一个Pod,然后找到一个节点来运行它。调度器会根据一系列不同的条件,包括Pod的资源请求,选择一个合适的节点。
在Pod被调度到某个节点后,该节点上运行的kubelet就会启动它的容器。
Stripe的工程师Julia Evans撰写的这篇文章清晰地解释了Kubernetes 的调度(参
考链接: https://oreil.ly/APoqF) 。
4.6 YAML 格式的资源清单 82
由于Kubernetes本质上是一个声明式系统,能够持续保持实际状态与所需状态时
;就一致, 因此你只需修改所需状态(即部署规范),其余的工作交给Kubernetes
可以了。
4.6.1 资源就是数据 82
4.6.2 部署清单 83
4.6.3 使用kubectl apply 84
4.6.4 服务资源 85
假设你想与Pod建立网络连接(例如我们的示例应用程序)。那么应该怎么做呢?
你可以找出Pod的IP地址,然后直接连接到该地址和应用程序的端口上,但是,当Pod重启时,IP地址可能会改变,因此你必须不断查找并确保总是连接到正确的地址。
更糟糕的是,我们可能有多个Pod副本,每个副本都有不同的地址。任何需要连接这些Pod的应用程序都必须维护这些地址的列表,这个办法可不理想。
幸运的是,我们有更好的方法:服务资源可以提供一个不变的IP 地址或DNS名称,井自动路由到与之匹配的Pod上。我们将在9.6节中讨论Ingress 资源,该资源允许使用更高级的路由,而且还可以使用TLS证书。
4.6.5 使用kubectl 查询集群 88
如果想查看某个Pod (或任何其他资源)的详细信息,可以使用kubectl describe。
4.6.6 资源的高级使用方式 89
这些值能不能只指定一次, 然后在Kubernetes清单的其他地方直接引用呢?
例如,如果能够定义container.name和container.port等变量,然后在YAML文件需要的地方引用,那就太好了。如此来, 如果需要更改应用程序的名称或监听的端口号,则只需更改一个地方,所有清单都会自动更新。
4.7 Helm:Kubernetes 包管理器 90
Kubernetes有一款流行的包管理器叫做Helm,它的工作方式如上一节所述。 你可以使用helm命令行工具来安装和配置应用程序(你自己的或其他人的应用程序),而且还可以创建名为Helm Chart的软件包,通过该软件包指定运行应用程序所需的资源、依赖项以及可配置的设置。
你需要知道,与APT或Yum等工具使用的二进制软件包不同,Helm
Chart实际上并不包含容器镜像本身。它与Kubernetes部署一样,只包含可在何处找到镜像的元数据。
在安装Helm Chart时,Kubernetes 会从指定的地方找到并下载二进制容器镜像。实际上,Helm Chart只是Kubernetes YAML清单的包装而已。
4.7.1 安装Helm 90
4.7.2 安装Helm Chart 91
4.7.3 Chart、Repository 与Release 87
以下是你需要了解的Helm三大术语:
- Chart是一个Helm包,其中包含在Kubernetes中运行应用程序所需的所有资源定义。
- Repository是收集和共享Chart的地方。
- Release是在Kubernetes 集群中运行的Chart的一个实例。
4.7.4 查看Helm Release 88
还有一个CNCF项目Artifact Hub (参考链接: https:/artifacthub.io) 提
供了许多流行的Helm Chart的示例。
4.8 小结 93
第5章 资源管理 95
5.1 了解资源 95
5.1.1 资源单位 96
5.1.2 资源请求 96
5.1.3 资源约束 97
5.1.4 服务质量 94
Kubernetes会根据Pod的请求和限制,判断它属干哪种服务质量(Quality of Service,简称QoS) 等级(参考链接: https://oreil.ly/x0m1T) : Guaranteed (有保证的)、Burstable (不稳定的)还是BestEffort (尽力而为)。
5.2 管理容器的生命周期 99
5.2.1 存活探针 99
对于HTTP服务器容器,常见的存活探针规范如下:
livenessProbe:
httpGet:
path: /healthz
port: 8888
initialDelaySeconds: 3
periodSeconds: 3
failureThreshold: 2
5.2.2 探针延迟及频率 100
5.2.3 其他类型的探针 101
对于不使用HTTP 的网络服务器,可以使用tcpSocket :
livenessProbe:
tcpSocket:
port: 8888
5.2.4 就绪探针 97
与存活探针不同,就绪探针失败会干掉并重启Pod。
5.2.5 启动探针 98
如果配置了启动探针(startupProbe) ,存活探针就会等到它执行成功,然后再开始存话检查。如果启动探针迟迟不能成功,Kubernetes 就会干掉Pod,并重启Pod。
5.2.6 gRPC 探针 99
gRPC拥有标准的健康检查协议,大多数gRPC服务都支持该协议,如果需要
Kubemetes的存活探针来进行健康检查,则可以使用grpc-health-probe工具(参考链接: https://oreil.ly/sJp7V/)) 。
5.2.7 基于文件的就绪探针 99
你可以让应用程序在容器的文件系统上创建一个 文件,比如/tmp/healthy
,并使用exec就绪探针来检查该文件存在与否。
5.2.8 minReadySeconds 100
5.2.9 Pod 中断预算 104
5.3 命名空间 106
命名空间可以根据各种目的将集群划分成小块。
5.3.1 使用命名空间 107
5.3.2 应该使用哪些命名空间? 107
5.3.3 服务地址 108
尽管在逻辑上命名空间彼此隔离,但它们仍然可以与其他命名空间中的服务通信。
服务的DNS名称通常遵循以下格式:
服务.命名空间.svc.cluster.1ocal
5.3.4 资源配额 109
5.3.5 默认资源请求和约束 111
5.4 优化集群的成本 . 112
5.4.1 优化部署 112
5.4.2 优化Pod 113
5.4.3 Pod 垂直自动伸缩器 114
5.4.4 优化节点 114
5.4.5 优化存储 116
5.4.6 清理未使用的资源 117
5.4.7 检查备用容量 120
5.4.8 使用预留实例 120
5.4.9 抢占式(Spot)实例 121
5.4.10 保持工作负载均衡 123
5.5 小结 126
第6章 集群运维 129
6.1 集群的规模与伸缩 129
6.1.1 容量规划 130
6.1.2 节点与实例 133
6.1.3 伸缩集群 136
6.2 一致性检查 138
6.2.1 CNCF 认证 139
Kubernetes管理员认证(CKA)
如果想成为官方认证的Kubernetes管理员(Certified Kubernetes Administrator, 简称CKA),你需要证明自己掌握了在生产中管理Kubernetes集群的关键技术,包括安装和配置、网络、维护,以及有关API、安全性和故障排除的知识。如何参加培训以及如何注册参加考试的更多信息,请参见CNCF官网(地址: https://oreil.ly/810Ot )。
6.2.2 Sonobuoy 一致性测试 141
6.2.3 Kubernetes审计日志
假设你在集群中发现了某个问题,例如某个不认识的Pod,你想知道它的来源。那么,怎样才能搞清楚谁在集群上做了些什么?这时,你可以检查Kubernetes审计日志(参考链接: https://oreil.ly/3NS5l) 。
启用审计日志记录后,集群API的所有请求都会被记录,且带时间戳,明确记录了谁发送了这些请求(哪个服务账号),请求的详细信息(例如查询的资源),以及响应是什么。
6.3 混乱测试 144
6.3.1 生产环境是无法复制的 144
6.3.2 Chaoskube 145
6.3.3 kube-monkey 146
6.3.4 PowerfulSeal 146
6.4 小结 147
第7章 强大的Kubernetes 工具 . 141
7.1 掌握kubectl 141
7.1.1 Shell 别名 141
我们在.bash.profile 或.zshrc文件中设置了下述别名:
alias k=kubectl
7.1.2 使用缩写的标志 150
7.1.3 缩写资源的类型 151
7.1.4 自动补齐kubectl 命令 151
7.1.5 获取帮助 152
7.1.6 获取有关Kubernetes 资源的帮助 152
7.1.7 显示更详细的输出 153
7.1.8 使用JSON 数据和jq 145
如果你还没有jq (参考链接: https://stedolan.github.io/jq/download)。
jq是非常强大的查询和转换JSON数据的工具。
网上有一个非常方便的jq练习环境(地址: https://jqplay.org/),你可以粘贴JSON数据,并尝试通过不同的jq查询获得想要的准确结果。
7.1.9 监视对象 147
kubectl提供的--watch标志(缩写为-w)可以省去这些麻烦。
每当有一个匹配的Pod状态发生变化时,就可以在终端中看到更新
7.1.10 描述对象 155
7.2 处理资源 147
7.2.1 命令式的kubectl 命令 147
你还可以通过kubectl edit 命令查看和修改任何资源:
上述命令会用默认的编辑器打开代表指定资源的YAML清单文件。
保存好文件并退出编辑器后,kubectl 会更新资源,与运行kubectl apply 应用资源清单文件的效果完全样。
7.2.2 何时不应该使用命令式的命令 157
7.2.3 生成资源清单 158
7.2.4 导出资源 159
7.2.5 对比资源的差异 159
7.3 处理容器 151
7.3.1 查看容器的日志 160
7.3.2 附着到容器 162
7.3.3 利用kubespy 监视Kubernetes 资源 153
你可以试试看kubespy (参考链接: https://oreil.ly/YqyBk) ,这是一款非常出色的来自Pulumi项目的工具。Kubespy可以监视集群内部的单个资源,并向你展示
一段时间内的情况。
7.3.4 转发容器端口 153
我们曾使用kubectl port-forward将Kubernetes服务转发到本地计算机的端口上。其实,如果你想直接连接到特定的Pod,也可以使用它转发容器端口。只需指定Pod名称以及本地和远程端口即可:
上述命令会将本地计算机上的端口9999转发到容器的端口8888上,然后你就可以使用Web浏览器连接到该端口了。
7.3.5 在容器上执行命令 155
如果Pod中有多个容器,则默认情况下,kubectl exec 将在第一个容器中运行命令。或者,你可以使用-c标志指定容器:
7.3.6 容器的故障排除 156
你可以看到此处kubectl run 使用了一组常见的标志:
--rm
这个标志告诉Kubernetes删除这个命令在容器内创建的资源,以免弄乱节点的本地存储。
-it
这个标志以交互式的方式(i) 通过终端(t) 来运行容器,如此一来你就可以在终端中看到容器的输出,并在有需要的时候通过键盘输入。
--restart=Never
这个标志告诉Kubernetes不要在容器退出时重启容器。由于这个容器只需运行一次,因此可以禁用默认的重启策略。
--command --
这个标志指定了要运行的命令,用于取代容器的默认入口。--之后的所有内容将作为命令行的参数传递给容器。
7.3.7 BusyBox 命令 166
7.3.8 将BusyBox 添加到容器 157
但如果容器中没有/bin/sh,该怎么办?
为了构建易于调试且镜像非常小的容器,最简单的方法是,在构建时将busybox可执行文件复制到容器中。仅1MiB就能换来一个shell和一组UNIX实用程序,这个代价很小。
在上述Dockerfile文件中,--from-busybox:1.28引用了公开的BusyBox库镜像。
7.3.9 在容器上安装程序 168
7.3.10 通过kubesquash 实时调试 168
7.4 上下文与命名空间 159
kubectl引入了上下文(context) 的概念。集群、用户以及
俞名空间组合在一起就构成了上下文。
kubectl命令总是在当前的上下文中执行。
你可以使用命令切换上下文:
kubectl config use-context mynamespace
7.4.1 kubectx 与kubens 171
7.4.2 kube-ps1 172
7.5 Kubernetes shell 与工具 173
7.5.1 kube-shell 173
7.5.2 Click 173
7.5.3 Kubed-sh 174
7.5.4 Stern 174
7.6 Kubernetes IDE 164
7.6.1 Lens 164
Lens(参考链接:https://oreil.ly/5JwOQ)是一款GUI应用程序,其工作方式类似于专门用于与Kubernetes集群交互的高级可视化工具和IDE。
7.7 构建自己的Kubernetes 工具 175
7.8 小结 176
第8章 运行容器 179
8.1 容器与Pod 179
8.1.1 什么是容器? 180
8.1.2 Kubernetes中的容器运行时 171
2020年11月,Kubernetes的维护人员宣布(参考链接: https://oreil.ly/D8jVd) 将弃用Kubernetes中的Docker运行时,并使用容器运行时接口(Container Runtime InTerface,简称CRI) (参考链接: https://oreil.ly/K5qJw) 来代替。这并不意味着,将来Kubernetes中再也见不到Docker容器了,也不意味着Docker无法再作为Kubernetes上下文之外的工具继续帮助我们与容器交互。只要容器符合开放容器倡议(Open Container Initiative, 简称OCI) (参考链接:https://oreil.ly/OXs0C)。, 就可以在Kubernetes中运行。
8.1.3 容器中有什么? 181
8.1.4 Pod 中有什么? 172
Pod 代表一组需要相互通信和共享数据的容器,它们需要一起调度, 一起启动和停止,而且还需要在同一台物理计算机上运行。
举一个例子,在本地缓存中保存数据的应用程序,比如Memeached (参考链接: https://memcached.org/about)。你需要运行两个进程:应用程序,以及存储和检索数据的memcached服务器进程。最好将它们分到两个单独的容器,每个容器只需要关心构建和运行自己的进程即可。
8.2 容器清单 173
下面的示例是带有两个容器的部署中template.spec节的写法:
spec:
containers:
- name: container1
image: example/container1
- name: container2
image: example/container2
8.2.1 镜像标识符 174
实际上,每个镜像标识符都有四个不同的部分:镜像仓库的主机名、镜像仓库的命名空间、镜像仓库以及标签。除了镜像名称以外,其他都是可选项。镜像标识符会用到所有的字段,如下所示:
docker.io/cloudnatived/demo:hello
8.2.2 latest 标签 175
8.2.3 容器摘要 176
8.2.4 基础镜像标签 176
8.2.5 端口 177
8.2.6 资源请求和约束 177
8.2.7 镜像拉取策略 178
8.2.8 环境变量 178
8.3 容器安全 179
8.3.1 以非root 用户身份运行容器 190
8.3.2 阻止Root 容器 191
8.3.3 设置只读文件系统 192
8.3.4 禁用权限提升 192
8.3.5 能力 193
8.3.6 Pod 安全上下文 195
8.3.7 Pod 安全策略 195
8.3.8 Pod 服务账号 196
8.4 卷 197
你可能还记得,每个容器都有自己的文件系统,而且这个文件系统只能由该容器自己访问,并且是暂时的,如果重新启动容器,所有不属于容器镜像的数据都将丢失。
但是,较为复杂的应用程序可能既需要与同一个Pod中的其他容器共享数据,又要在重新启动时保存数据。Kubernetes 的卷(Volume) 对象可以提供这两种功能。
8.4.1 emptyDir 卷 185
Pod创建了一个emptyDir卷并挂载到容器上:
apiVersion: v1
kind: Pod
...
spec:
volumes:
- name: cache-volume
emptyDir: {}
containers:
- name: demo
image: cloudnatived/demo:hello
volumeMounts:
- mountPath: /cache
name: cache-volume
首先,在Pod规范的volumes部分中,创建一个名为cache-volume的emptyDir卷:
接下来,Pod中的任何容器都可以挂载并使用cache-volume卷。
8.4.2 持久卷 199
8.5 重启策略 200
8.6 ImagePullSecret 188
镜像拉取机密 200
8.7 初始化容器 189
初始化容器必须在Pod中的其他容器启动之前成功运行并退出:
如果你需要在启动应用程序之前做最后的检查,或运行任何类型的引导脚本,则可以考虑初始化容器。
8.8 小结 201
第9章 管理Pod 191
9.1 标签 191
9.1.1 什么是标签? 191
标签是附加到Kubernetes对象(比如Pod)上的键值对。 标签的主要作用
是指定用户关心的相关对象的标识属性,但对核心系统而言,标签没有直接性的语义含义。Kubernetes文档(地址: https://oreil.ly/C4j1y)
当标签与选择器-起使用时,标签的真正威力才能体现出来。
9.1.2 选择器 204
9.1.3 高级选择器 205
9.1.4 标签的其他用途 207
9.1.5 标签与注释 208
9.2 节点亲和性 208
9.2.1 硬亲和性 209
9.2.2 软亲和性 210
9.3 Pod 的亲和性与反亲和性 211
9.3.1 将Pod 调度到一起 211
9.3.2 分开Pod 212
9.3.3 软反亲和性 213
9.3.4 何时使用Pod 亲和性 214
9.4 污点与容忍 214
9.5 Pod 控制器 203
其实,直接使用docker container run 运行容器就可以达到这种效果,但非常有局限性:
- 如果容器由于某种原因退出,则必须手动重启。
- 容器只有一个副本:而且在手动运行的情况下,无法在多个副本之间实现负载均衡。
- 如果想实现高可用的副本,则必须决定在哪些节点上运行它们,并注意保持集群均衡。
- 更新容器时,必须注意依次停止每个正在运行的镜像,然后拉取并重启新镜像。
而Kubernetes的诞生就是为了通过控制器将你从这些工作中解放出来。
9.5.1 守护进程集 204
假设你想将所有应用程序的日志发送到中央日志服务器。
一种方式是在每个应用程序中加人一段代码,连接到日志记录服务、进行身份验证、写入日志等,但这会导致很多代码重复,效率很低。
还有一种方法,你可以在每个Pod中运行一个额外的容器, 充当日志记录代理 (这种方式又称为Sidecar模式)。这意味着应用程序无需了解如何与日志记录服务通信,但是也意味着每个节点上都需要运行日志记录代理的多个副本。
为此Kubernetes提供了一个特殊的控制器对象:守护进程集(DaemonSet) 。
9.5.2 状态集 205
但有时候,你需要按照特定的编号顺序启动Pod,而且还需要通过编号识别它们。
如果创建一个名为redis的状态集(StatefulSet),则第一个启动的Pod将被命名为redis-0,而且Kubernetes会等到该Pod准备好之后再启动下一个Pod,即redis-1。
9.5.3 作业 206
作业(Job)只运行一定的次数。 之后,作业就会被视为完成。
9.5.4 定时作业 208
在UNIX环境中,计划作业由cron守护程序运行(这个名字来自希腊语,意思是“时间”)。因此,它们被称为“定时作业”(CronJob) ,Kubernetes 的定时作业对象的作用与此完全相同。
9.5.5 Pod 水平自动伸缩器 222
9.5.6 操作器与自定义资源定义(CRD) 211
如果应用程序需要比状态集更复杂的管理,或复杂的资源类型,则可以自行创建新型的对象,也就是“自定义资源定义”(Custom Resource Definition, CRD)。
9.6 Ingress 资源 212
而Ingress可以将外部的流量路由到集群,并分配给正确的微
服务。你可以将Ingress的概念想象成负载均衡器,它可以与服
务协同工作。
9.6.1 Ingress 规则 228
9.6.2 通过Ingress 终止TLS 229
9.6.3 Ingress 控制器 230
9.7 服务网格 217
服务网格(Service Mesh)工具还可以为流经网络的请求添加指
标和日志记录,以记录请求所花费的时间,或跟踪请求从哪里开始以及途径的各种微服务。
9.7.1 Istio 217
Istio的安装文档(参考链接: https://oreil.ly/SWldX) 。此外,《Istio: Up and Running》(参考链接: https://oreil.ly/KuTMV) (O'Reilly 出版)
9.7.2 Linkerd 217
Linkerd (参考链接: https://linkerd.io/) 提供了许多服务网格的核心功能,与Istio相比,它占用的空间更小,而且复杂度更低。你可以利用它设置服务之间的TLS、收集请求率和延迟的指标、实施蓝绿部署以及重试请求。
9.8 Envoy 232
9.9 小结 233
第10章 配置与机密数据 235
10.1 ConfigMap 236
10.1.1 创建ConfigMap 236
10.1.2 利用ConfigMap 设置环境变量 237
10.1.3 利用ConfigMap 设置整个环境 240
10.1.4 在命令参数中使用环境变量 241
10.1.5 利用ConfigMap 创建配置文件 228
更为复杂的应用程序往往需要从磁盘文件中读取配置。
这段数据恰好是合法的YAML,但请不要误解,它可以是JSON、TOML、纯文本或任何其他格式。不论是何种形式,最终Kubernetes都会将整个数据块原样写人容器的文件。
10.1.6 配置发生变化后更新Pod 230
如果你使用的是Helm Chart ,则我们有一个妙招可以让它自动检测配置变化并重新加载Pod,将如下注释添加到部署规范即可:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
如此一来,部署模板就包含了配置设置的哈希值,因此一旦这些配置发生变化,哈希值也会变化。只需运行helm upgrade ,Helm就会检测到部署规范已发生变化,然后重新启动所有Pod.
10.2 Kubernetes Secret 231
大多数应用程序都有一些机密且敏感的配置数据,比如密码或API密钥等。
Kubernetes提供了一种专门存储机密数据的特殊对象: Secret。
10.2.1 利用机密数据设置环境变量 231
10.2.2 将Secret 写入文件 232
10.2.3 读取Secrest 233
10.2.4 Secret的访问权 235
10.2.5 静态加密 235
10.2.6 防止Secret和ConfigMap被修改 235
10.3 Secret 管理策略 236
10.3.1 在版本控制中加密机密 236
10.3.2 使用专业的机密管理工具 237
10.4 使用Sops 加密机密数据 238
10.4.1 使用Sops 加密文件 239
10.4.2 使用Sops 加密文件 256
10.4.3 使用KMS 后端 241
10.5 Sealed Secrets 241
10.6 小结 242
第11章 安全与备份 243
11.1 访问控制与权限 243
11.1.1 按集群管理访问 243
11.1.2 基于角色的访问控制 244
11.1.3 角色 245
这一切都由Kubernetes角色控制。角色(Role) 描述了一组特定的权限。
11.1.4 将角色绑定到用户 246
如何才能将角色关联到用户呢?你可以使用角色绑定(Role Binding) 来实现。
11.1.5 我需要哪些角色? 247
11.1.6 保护集群管理员的权限 247
11.1.7 应用程序与部署 248
11.1.8 RBAC 故障排除 248
11.2 集群的安全扫描 249
11.2.1 Gatckeeper/OPA 250
11.2.2 kube-bench 250
11.2.3 Kubescape 251
11.3 容器安全扫描 251
11.3.1 Clair 252
11.3.2 Aqua 252
11.3.3 Anchore Engine 253
11.3.4 Synk 253
11.4 备份 254
11.4.1 Kubernetes 需要备份吗? 255
11.4.2 备份etcd 255
11.4.3 备份资源状态 256
11.4.4 备份集群状态 256
11.4.5 大小灾害 257
11.4.6 Velero 257
Velero (地址: https://velero.io, 原名Ark)是一款免费的开源工具,可以备份和还原集群状态以及持久性数据。
11.5 监控集群状态 261
11.5.1 Kubectl 261
控制平面状态
kubectl get componentstatuses 命令(简写kubectl get cs) 可以提供有关控制平面组件(调度器、控制器管理器和etcd等)运行状况的信息:
# kubectl get componentstatuses
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
controller-manager Healthy ok
etcd-0 Healthy {"health":"true","reason":""}
scheduler Healthy ok
11.5.2 CPU 和内存利用率 263
kubectl top 命令提供了集群的概况信息。如果是节点,该命令将显示每个节点的CPU和内存容量,以及每个节点当前的利用率:
# kubectl top nodes
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
node2 2929m 41% 10361Mi 77%
11.5.3 云提供商控制台 264
11.5.4 Kubernetes 仪表板 264
11.5.5 Weave Scope 265
11.5.6 kube-ops-view 266
11.5.7 node-problem-detector 266
node problem-detector (参考链接: https://oreil.ly/rE7Sl) 是一款 Kubernetes插件,能够检测并报告各种节点级别的问题,包括硬件问题,比如CPU或内存错误、文件系统损坏以及无响应的容器运行时。
目前,node-problem-detector 通过将事件发送到Kubernetes API来报告问题,而且还提供了一个Go客户端库,你可以利用这个库将其集成到自己的工具中。
11.6 延伸阅读 266
11.7 小结 266
第12章 部署Kubernetes 应用程序 269
12.1 使用Helm 构建清单 269
我们想要的是能够将原始清单文件与应用程序的用户可能需要调整的特定设置和变量分开。
12.1.1 Helm Chart 包含什么? 270
每个Helm Chart都有一个标准的结构。 首先,我们可以看到同名目录中的 Chart(在我们的例子中为demo)
demo
├── Chart.yaml
├── production-values.yaml
├── staging-values.yaml
├── templates
│ ├── deployment.yaml
│ └── service.yaml
└── values.yaml
values.yaml文件
values.yaml的文件,其中包含Chart作者公开的、可供用户修改的设置:
12.1.2 Helm 模板 271
那么,这些变量会在哪里引用呢?请看templates子目录。
这些文件正是前面示例中的部署和服务的清单文件,不同之处在于它们是模板,它们不直接包含容器名称等内容,但它们包含占位符,Helm可以利用values.yaml中的真实值替换这个占位符。
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.container.name }}-{{ .Values.environment }}
spec:
replicas: {{ .Values.replicas }}
大括号指明了Helm应替换成变量值的位置,但实际上它们属于Go模板语法。
Co模板格式非常强大,除了简单的变量替换之外,还有很多用途:它支持循环、表达式,条件分支,甚至函数调用。
12.1.3 插值变量 272
12.1.4 引用模板中的值 274
12.1.5 指定依赖项 274
12.2 部署Heml Chart 275
12.2.1 设置变量 275
12.2.2 在Helm Release 中指定值 276
12.2.3 使用Helm 更新应用程序 277
12.2.4 回滚到以前的版本 278
12.2.5 创建Helm Chart 库 278
12.2.6 使用Sops 管理Helm Chart 的机密数据 279
12.3 使用Helmfile 管理多个Chart 281
12.3.1 Helmfile 中有什么? 282
12.3.2 Chart 元数据 283
12.3.3 应用Helmfile 284
12.4 高级清单管理工具 285
12.4.1 Kustomize 285
12.4.2 Tanka 287
12.4.3 Kapitan 288
12.4.4 kompose 288
12.4.5 Ansible 289
12.4.6 kubeval 289
12.5 小结 290
第13章 开发流程 293
13.1 开发工具 293
13.1.1 Skaffold 294
Skaffold (参考链接: https://oreil.ly/UTaRj) 是谷歌的一款开源工具, 旨在提供快速的本地开发工作流程。在本地开发时,它会自动重构容器,并将这些更改部署到本地或远程集群。
13.1.2 Telepresence 296
13.1.3 Waypoint 296
Waypoint (参考链接: https://www.waypointproject.io)引人 了一个声明式文件waypoint.hcl, 使用Waypoint等标准的打包程序意味着,即便各个应用程序使用不同的构建和部署步骤,你依然可以标准化CI/CD工具和流程。
13.1.4 Knative 297
而Knative (参考链接:https://oreil.ly/SXohX) 的野心更大。它的目标是提供一 种将各种工作负载部署到Kubernetes的标准机制,不仅包括容器化的应用程序,还包括无服务器风格的函数。
Knative同时集成了Kubernetes 和Istio ,提供了一个完整的应用程序/函数部署平台,包括设置构建过程、自动部署以及事件处理机制。
13.1.5 OpenFaaS 297
13.1.6 Crossplane 297
13.2 部署策略 299
13.2.1 滚动更新 300
如果采用滚动更新(RollingUpdate) ,则一次只能升级一个 Pod,直到所有副本都被替换成新版本。
13.2.2 重建 300
在重建(Recreate)模式下,所有正在运行的副本都会被立即终止,然后创建新副本。
13.2.3 maxSurge 和maxUnavailable 301
13.2.4 蓝绿部署 302
蓝绿部署不需要.次性干掉并替换所有的Pod,我们可以创建一个全新的部署,然后单独启动一系列新版本的Pod,与旧版本的部署并存。
13.2.5 彩虹部署 303
每次部署更新时,你都需要建立一套新颜色的Pod。等到所有旧Pod的连接都被排空后,才可以关闭。
13.2.6 金丝雀部署 303
有关运行金丝雀部署的详细示例,请参见Kubernetes 文档(地址: https://oreil.ly/PqUe0 )。
13.1.2 Draft 310
13.3 使用Helm 处理迁移 304
13.3.1 Helm 的钩子 304
Helm的钩子允许你控制部署期间各种操作发生的顺序。如果出现问题,还可以放弃升级。
annotations:
"helm.sh/hook": pre-upgrade
"helm.sh/hook-delete-policy": hook-succeeded
pre-upgrade设置告诉Helm在升级之前应用这个作业清单。
13.3.2 处理失败的钩子 305
13.3.3 其他钩子 305
13.3.4 钩子连接 306
Helm还能够使用helm.sh/hook-weight属性,将钩子按照一定的顺序连接在一起。
13.4 小结 307
第14章 Kubernetes 的持续部署 309
14.1 什么是持续部署? 309
持续部署(Continuous Deployment, CD)指的是将构建自动部署到生产环境。
CD常常 与持续集成(Continuous Integration,即CI)相结合,后者的目标是自动集成和测试开发人员对主线分支所做的更改。其基本思想是,如果分支上的更以任合并到主线时会破坏构建,持续集成就会立即通知你,而不是等到你修改完可文并最终合并的时候再通知你出现了问题。
持续部署的机制通常称为“流水线”,即一系列的自动化操作,从开发人员的机器上拿到代码,通过一 系列测试和验收阶段,最终推送到生产环境。
14.2 CD 工具 310
14.3 托管CI/CD工具 311
14.3.1 Azure 流水线 311
14.3.2 谷歌云构建 311
14.3.3 Codefresh 311
Codefresh (参考链接: https://codefreshio) 是项托管服务。这款工具的一大特色是,能够针对每个功能分支部署临时的预发布环境。
14.3.4 GitHub Actions 312
14.3.5 GitLab CI 312
GitLab CI (参考链接: https://oreil.ly/e5f11) ,可用于测试和部署代码。
14.4 自托管CI/CD工具 312
14.4.1 Jenkins 312
Jenkins (参考链接: https://jenkins.io)是一款使用非常广泛的CD工具,已有很多年的历史。它拥有工作流程中所需的一切插件,包括Docker、kubectl和Helm。此外,还有一个专门在Kubernetes集群中运行Jenkins的辅助项目,名叫JenkinsX (参考链接: https://jenkins-x.io) 。
14.4.2 Drone 312
Drone (参考链接: https://oreil.ly/qtXoR) 是款面向容器的工具, 其本身也是用容器构建的。
14.4.3 Tekton 313
14.4.4 Concourse 313
Concourse (参考链接: https:/concourse-ci.org) 是一款用 Go编写的开源CD工具。Concourse已有官方发布的稳定Helm Chart(参考链接: https://oreil.ly/UCvPz),可部署到Kubernetes上。
14.4.5 Spinnaker 313
Spinnaker (参考链接: https://spinnaker.io) 。你可以阅读一下免费的电子书《Continuous Delivery with Spinnaker》(O' Reilly出版,参考链接: https://oreil.ly/hkb64) 。
14.4.6 Argo 313
Argo 还提供了一款流行的流水线工具(参考链接: http:aproj.github.io) ,可用于运行任何类型的流水线工作流,不仅限于CICD。
14.4.7 Keel 314
14.5 Google 云构建的CD 流水线 314
14.5.1 设置Google 云和GKE 314
14.5.2 分叉demo 代码库 315
14.5.3 创建Artifact Registry容器存储库 315
14.5.4 配置云构 316
14.5.5 构建测试容器 316
14.5.6 运行测试 317
14.5.7 构建应用程序容器 318
14.5.8 替换变 318
14.5.9 Git SHA标签 318
14.5.10 验证Kubernetes 清单 319
14.5.11 发布镜像 319
14.5.12 创建第一个构建触发器 319
14.5.13 测试触发器 320
14.5.14 利用CI/CD 流水线部署 321
14.5.15 创建部署触发器 323
14.5.16 调整示例流水线 324
14.6 GitOps 324
高级的GitOps需要使用源代码控制(Git 是最流行的源代码控制工具之一) 自动跟踪和管理基础设施。
Flux
流行的GitOps工具,名叫Flux (参考链接: https://oreil.ly/Eoqs6) 。该工具可以自动将变更部署到Kubernetes集群,它不仅可以轮询Git代码库,监视代码变更,而且还可以自动将变更应用到集群内运行的Pod。
14.7 小结 338
第15章 可观察性和监控 329
15.1 什么是可观察性? 329
15.1.1 什么是监控? 329
15.1.2 黑盒监控 330
15.1.3 “正常”指什么? 331
15.1.4 日志 333
日志记录的局限性
虽然日志非常有帮助,但也有其局限性。日志记录什么或不记录什么,是由程序员在编写应用程序时决定的。因此,就像黑盒检查一样, 日志只能回答问题,或发现可以提前预知的问题。
由于日志必须记录足够的信息才能诊断可能出现的问题, 因此通常日志中的信噪比都很低。
15.1.5 指标 335
15.1.6 跟踪 336
而跟踪则可以记录某个用户请求的整个生命周期。
一些流行的分布式跟踪工具包括Zipkin (参考链接: https:/zipkinio) 、Jaeger (参考链接: https://www.jaegertracing.io) 和LightStep (参考链接: https://lightstep.com/product)。工程师Masroor Hasan写了一篇博客文章《Distributed Tracing Infrastructure with Jaeger on Kubernetes》(参考链接: htps://oreil.ly/esVav) ,描述了如何使用Jaeger在Kubernetes中实现分布式跟踪。
15.1.7 可观察性 337
15.2 可观测性流水线 339
其次,系统与特定解决方案或提供商的集成越紧密,修改或尝试其他方案的难度就越大。
有一种解决该问题的方法日益流行,那就是“可观察性流水线”(参考链接:
https://oreil.l/Vyn5M)
15.3 Kubernetes 中的监控 340
有许多第三方服务可以执行这种监控,包括Uptime Robot. Pingdom 和Wormly等。
15.3.1 外部的黑盒检查 341
15.3.2 内部健康检查 342
15.4 小结 344
第16章 Kubernetes 指标 347
16.1 什么是指标? 347
16.1.1 时间序列数据 348
16.1.2 计数器和计量器 348
16.1.3 指标可以告诉我们什么? 349
16.2 选择指标 349
16.2.1 服务:RED 模式 350
RED模式(Requests Errors Duration,请求-错误-持续时间) 是一种经典的
可观察性工具,最早可追溯到在线服务的早期时代。谷歌的《Site Reliability Engineering》书 (参考链接: https://oreil.ly/zD72v/) 提出了“四个黄金信号”的概念,即请求、错误、持续时间和饱和度(我们稍后再讨论饱和度)
16.2.2 资源:USE 模式 351
由Netflix的性能工程师Brendan Gregg提出的USE模式(参考链接: https://oreil.ly/PpB0f)则是一种自 下而上的方法,旨在帮助我们分析性能问题并发现瓶颈。USE代表利用率(Utilization) 、饱和度(Saturation) 与错误(Errors)。
16.2.3 业务指标 352
16.2.4 Kubernetes 指标 353
16.3 分析指标 357
16.3.1 简单的平均值有什么问题? 358
16.3.2 平均值、中位数和离群值 358
16.3.3 百分位数 359
我们通常感兴趣的是用户感受到的最糟糕的延迟,而不是平均延迟。
获得此类信息的方法是将数据分解成百分位。第90百分位延迟(通常称为P90)指的是该延迟值超过了90%的用户感受到的延迟值。
16.3.4 将百分位数应用于指标数据 360
16.3.5 最坏的情况 361
16.3.6 比百分位数更好的方式 362
16.4 通过仪表板显示指标的图表 363
16.4.1 所有服务都使用标准布局 363
Tom Werkie在Weaveworks博客文章(地址: https://oreil.ly/GTzpX) 中提出了以下标准格式:
- 一行显示一个服务。
- 左侧是请求和错误率,错误显示为占请求的百分比。
- 右侧是延迟。
16.4.2 利用主仪表板构建信息发射源 364
为此,你应该创建一个主仪表板,显示所有服务的请求、错误和持续时间的聚合信息。请坚持使用简单的折线图来显示总请求、总错误百分比以及总延迟。与复杂的图表相比,这类图更易于理解,而且可视化的效果也更准确。
理想情况下,你可以使用信息发射源(也叫大屏幕,或超大可视图)。通过一个大屏幕显示关键的可观察性数据,让相关团队或办公室中的每个人都可以看到。
16.4.3 在仪表板上显示预示故障 365
16.5 根据指标发出警报 366
16.5.1 警报有什么问题? 367
16.5.2 值班不应该成为地狱 368
16.5.3 紧急、重大且需要付诸行动的警报 368
16.5.4 跟踪警报、工作时间外的呼叫 369
16.6 指标工具和服务 370
16.6.1 Prometheus 370
16.6.2 谷歌的Operations Suite 373
16.6.3 AWS Cloudwatch 373
16.6.4 Azure Monitor 374
16.6.5 Datadog 374
16.6.6 New Relic 375
16.7 小结 375
后记 379
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [翻译] 为什么 Tracebit 用 C# 开发
· 腾讯ima接入deepseek-r1,借用别人脑子用用成真了~
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· DeepSeek崛起:程序员“饭碗”被抢,还是职业进化新起点?
· RFID实践——.NET IoT程序读取高频RFID卡/标签