Kubernetes 技术入门与应用实践
1. Kubernetes ReplicaSets 与自我修复机制
在 Kubernetes 中,ReplicaSet 是一个重要的概念,它负责管理一组相同的 Pod,确保实际运行的 Pod 数量与期望的状态一致。例如,有一个名为
rs-web
的 ReplicaSet,期望状态是运行 3 个 Pod。我们可以通过以下命令查看 Pod 列表:
$ kubectl get pods
输出如下:
NAME READY STATUS RESTARTS AGE
rs-web-nbc8m 1/1 Running 0 4m
rs-web-6bxn5 1/1 Running 0 4m
rs-web-lqhm5 1/1 Running 0 4m
从输出可以看出,Pod 名称由 ReplicaSet 名称和唯一 ID 组成,每个 Pod 包含一个容器且处于运行状态,没有重启记录。
为了测试 ReplicaSet 的自我修复能力,我们可以随机删除一个 Pod:
$ kubectl delete po/rs-web-nbc8m
再次查看 Pod 列表:
$ kubectl get pods
输出如下:
NAME READY STATUS RESTARTS AGE
rs-web-4r587 1/1 Running 0 5s
rs-web-6bxn5 1/1 Running 0 4m30s
rs-web-lqhm5 1/1 Running 0 4m30
可以看到,被删除的 Pod 已被重新创建,这就是 ReplicaSet 的自我修复机制在起作用。我们还可以通过以下命令查看 ReplicaSet 的详细信息:
$ kubectl describe rs
在事件记录中,会显示 ReplicaSet 创建了一个新的 Pod
rs-web-4r587
。最后,在继续操作之前,删除该 ReplicaSet:
$ kubectl delete rs/rs-web
2. Kubernetes Deployments
Kubernetes 遵循单一职责原则,每个对象都有其特定的功能。ReplicaSet 负责实现和协调应用服务的期望状态,管理一组 Pod。而 Deployment 则在 ReplicaSet 的基础上,增加了滚动更新和回滚功能。在 Docker Swarm 中,Swarm 服务集成了 ReplicaSet 和 Deployment 的功能,相比之下,SwarmKit 比 Kubernetes 更加整体化。以下是 Deployment 与 ReplicaSet 的关系图:
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(Deployment):::process --> B(ReplicaSet):::process
B --> C(Pod 1):::process
B --> D(Pod 2):::process
B --> E(Pod 3):::process
3. Kubernetes Services
当处理包含多个应用服务的应用时,我们需要服务发现机制。例如,一个 Web API 服务需要访问支付、运输和订单三个服务,在 API 代码中,我们只需要使用服务名称和端口号来访问这些服务,如
http://payments:3000
。
在 Kubernetes 中,应用服务由 ReplicaSet 的 Pod 表示,但由于分布式系统的特性,Pod 的端点不稳定。为了解决这个问题,Kubernetes Services 提供了稳定的端点。它为 ReplicaSet 或 Deployment 提供可靠的集群 IP 地址(虚拟 IP,VIP)和唯一的端口。服务代理的 Pod 由服务规范中定义的选择器确定,选择器基于标签。例如,选择器
app=web
表示所有带有
app
标签且值为
web
的 Pod 都会被代理。
4. 上下文路由
在 Kubernetes 集群中,我们通常需要配置上下文路由。目前,首选且最具扩展性的方法是使用 IngressController。以下是使用 IngressController 进行上下文路由的工作流程:
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(客户端请求):::process --> B(Ingress 对象):::process
B --> C(IngressController):::process
C --> D(服务):::process
D --> E(Pod):::process
具体步骤如下:
1. 在 Ingress 对象中,定义源(主机和路径)和目标(服务名称和端口)。当 Ingress 对象由 Kubernetes API 服务器创建时,IngressController 中的一个进程会检测到这个变化。
2. 修改 Nginx 反向代理的配置文件。
3. 添加新的路由后,Nginx 重新加载配置,从而能够正确路由所有传入的请求,如
http[s]://example.com/web
。
5. 对比 Docker SwarmKit 与 Kubernetes
为了更好地理解 Kubernetes,我们可以将其与 Docker SwarmKit 进行对比。以下是两者主要资源的对比表格:
| SwarmKit | Kubernetes | 描述 |
| — | — | — |
| Swarm | Cluster | 由各自编排器管理的服务器/节点集合 |
| Node | Cluster member | 作为 Swarm/集群成员的单个主机(物理或虚拟) |
| Manager node | Master | 管理 Swarm/集群的节点,即控制平面 |
| Worker node | Node | 运行应用工作负载的 Swarm/集群成员 |
| Container | Container
| 在节点上运行的容器映像实例(在 Kubernetes 集群中,不能直接运行容器) |
| Task | Pod | 在节点上运行的服务(Swarm)或 ReplicaSet(Kubernetes)实例。一个任务管理单个容器,而一个 Pod 包含一个或多个共享相同网络命名空间的容器 |
| Service | ReplicaSet | 定义和协调由多个实例组成的应用服务的期望状态 |
| Service | Deployment | 具有滚动更新和回滚功能的 ReplicaSet |
| Routing mesh | Service | Swarm 路由网格使用 IPVS 提供 L4 路由和负载均衡。Kubernetes Service 是一个抽象概念,定义了一组逻辑 Pod 和访问它们的策略,是一组 Pod 的稳定端点 |
| Stack | Stack
| 由多个(Swarm)服务组成的应用定义(Stack 不是 Kubernetes 的原生资源,但 Docker Desktop 工具会将其转换为 Kubernetes 集群上的部署) |
| Network | Network policy | Swarm 软件定义网络(SDN)用于隔离容器。Kubernetes 只定义了一个扁平网络,除非明确定义网络策略来限制 Pod 间的通信,否则每个 Pod 都可以访问其他 Pod 和/或节点 |
6. 部署第一个应用
接下来,我们将介绍如何将一个宠物应用部署到 Kubernetes 集群中。该应用由基于 Node 的 Web 组件和 PostgreSQL 数据库组成。
6.1 部署 Web 组件
我们将使用 Docker Desktop 提供的本地单节点 Kubernetes 集群,具体步骤如下:
1. 确保 Docker Desktop 中的 Kubernetes 已开启。
2. 在代码子文件夹
ch17
中创建一个名为
web-deployment.yaml
的文件,内容如下:
# 此处应包含 web-deployment.yaml 的具体内容,但文档中未给出完整代码,可参考实际情况补充
该文件包含了部署 Web 组件的指令,代码行解释如下:
- 第 7 行:定义 Deployment 对象的名称为
web
。
- 第 9 行:声明希望运行一个 Web 组件实例。
- 第 11 - 13 行:通过选择器定义哪些 Pod 将属于该部署,即带有
app
标签值为
pets
和
service
标签值为
web
的 Pod。
- 第 14 行:在 Pod 模板中,为每个 Pod 应用
app
和
service
标签。
- 第 20 行及以后:定义在 Pod 中运行的单个容器,容器映像为
fundamentalsofdocker/ch11-web:2.0
,容器名称为
web
。
- 第 23 和 24 行:声明容器暴露端口 3000 以接收传入流量。
3. 设置
kubectl
的上下文为 Docker Desktop:
$ kubectl config use-context docker-desktop
输出如下:
Switched to context "docker-desktop".
- 使用以下命令部署 Deployment 对象:
$ kubectl create -f web-deployment.yaml
输出如下:
deployment.apps/web created
- 再次检查部署是否成功:
$ kubectl get all
输出应显示 Kubernetes 创建了三个对象:Deployment、相关的 ReplicaSet 和一个 Pod(因为我们只指定了一个副本),且当前状态与期望状态一致。
6. 为了将 Web 服务暴露给外部,我们需要定义一个 NodePort 类型的 Kubernetes Service 对象。在
ch17
文件夹中创建一个名为
web-service.yaml
的文件,内容如下:
# 此处应包含 web-service.yaml 的具体内容,但文档中未给出完整代码,可参考实际情况补充
代码行解释如下:
- 第 7 行:设置 Service 对象的名称为
web
。
- 第 9 行:定义服务类型为 NodePort,因为 Web 组件需要从集群外部访问。
- 第 10 - 13 行:指定通过 TCP 协议暴露端口 3000,Kubernetes 会自动将容器端口 3000 映射到 30000 - 32768 范围内的一个空闲主机端口。
- 第 14 - 16 行:定义服务代理的 Pod 的过滤条件,即带有
app
标签值为
pets
和
service
标签值为
web
的 Pod。
7. 使用以下命令创建 Service 对象:
$ kubectl apply -f web-service.yaml
- 查看所有服务:
$ kubectl get services
输出应显示创建了一个名为
web
的服务,分配了唯一的 ClusterIP
10.96.195.255
,容器端口 3000 已在所有集群节点的端口 30319 上发布。
9. 测试部署:
$ curl localhost:30319/
输出如下:
Pets Demo Application
通过以上步骤,我们完成了 Kubernetes 的入门学习,包括 ReplicaSet、Deployment、Service 等核心概念的理解,以及如何将应用部署到 Kubernetes 集群中。在实际应用中,我们可以根据需求进一步扩展和优化这些配置,实现更复杂的功能。
7. 定义存活和就绪探针
在 Kubernetes 中,为了确保应用服务的稳定性和可靠性,我们需要定义存活和就绪探针。存活探针用于检测容器是否正常运行,如果检测失败,Kubernetes 会自动重启容器。就绪探针用于检测容器是否准备好接收流量,如果检测失败,Kubernetes 会将该容器从服务负载均衡中移除。
以下是一个简单的示例,展示如何在
web-deployment.yaml
文件中定义存活和就绪探针:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 1
selector:
matchLabels:
app: pets
service: web
template:
metadata:
labels:
app: pets
service: web
spec:
containers:
- name: web
image: fundamentalsofdocker/ch11-web:2.0
ports:
- containerPort: 3000
livenessProbe:
httpGet:
path: /healthz
port: 3000
initialDelaySeconds: 15
periodSeconds: 5
readinessProbe:
httpGet:
path: /readyz
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
在上述示例中,我们定义了一个存活探针和一个就绪探针:
- 存活探针:使用 HTTP GET 请求
/healthz
路径,端口为 3000。初始延迟 15 秒后开始检测,每隔 5 秒检测一次。
- 就绪探针:使用 HTTP GET 请求
/readyz
路径,端口为 3000。初始延迟 5 秒后开始检测,每隔 10 秒检测一次。
8. 零停机部署
在生产环境中,我们通常需要对应用服务进行更新,同时确保服务的可用性,这就需要实现零停机部署。Kubernetes 的 Deployment 对象提供了滚动更新和回滚功能,帮助我们实现这一目标。
以下是一个简单的零停机部署示例:
1. 修改
web-deployment.yaml
文件中的容器镜像版本:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 1
selector:
matchLabels:
app: pets
service: web
template:
metadata:
labels:
app: pets
service: web
spec:
containers:
- name: web
image: fundamentalsofdocker/ch11-web:3.0 # 修改镜像版本
ports:
- containerPort: 3000
- 使用以下命令应用更新:
$ kubectl apply -f web-deployment.yaml
- 查看 Deployment 的状态:
$ kubectl rollout status deployment/web
Kubernetes 会逐步替换旧的 Pod 为新的 Pod,确保在更新过程中服务始终可用。如果更新过程中出现问题,我们可以使用以下命令回滚到上一个版本:
$ kubectl rollout undo deployment/web
9. Kubernetes 秘密
在应用服务中,我们经常需要处理敏感数据,如数据库密码、API 密钥等。Kubernetes 提供了秘密(Secrets)对象来安全地存储和管理这些敏感数据。
以下是一个创建和使用秘密的示例:
1. 创建一个包含敏感数据的文件,例如
db-password.txt
,内容为数据库密码:
mysecretpassword
- 使用以下命令创建秘密:
$ kubectl create secret generic db-password --from-file=db-password.txt
-
在
web-deployment.yaml文件中引用该秘密:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 1
selector:
matchLabels:
app: pets
service: web
template:
metadata:
labels:
app: pets
service: web
spec:
containers:
- name: web
image: fundamentalsofdocker/ch11-web:2.0
ports:
- containerPort: 3000
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-password
key: db-password.txt
在上述示例中,我们将数据库密码存储在秘密
db-password
中,并在容器的环境变量
DB_PASSWORD
中引用该秘密。
10. 总结与展望
通过前面的学习,我们了解了 Kubernetes 的核心概念和功能,包括 ReplicaSets、Deployments、Services、上下文路由等,以及如何将应用部署到 Kubernetes 集群中,实现零停机部署和安全管理敏感数据。
以下是一个简单的流程图,总结了将应用部署到 Kubernetes 集群的主要步骤:
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(创建 Deployment):::process --> B(创建 Service):::process
B --> C(定义探针):::process
C --> D(零停机部署):::process
D --> E(管理秘密):::process
在实际应用中,我们可以根据具体需求进一步扩展和优化这些配置,例如使用不同类型的服务(如 LoadBalancer、ExternalName)、配置更复杂的路由规则、使用 Helm 进行应用打包和部署等。同时,我们还可以结合监控和日志工具,对 Kubernetes 集群进行实时监控和故障排查,确保应用的稳定性和可靠性。
总之,Kubernetes 作为目前最流行的容器编排引擎,为我们提供了强大的功能和灵活性,帮助我们更好地管理和部署容器化应用。通过不断学习和实践,我们可以充分发挥 Kubernetes 的优势,构建出高效、稳定的应用系统。
超级会员免费看
2045

被折叠的 条评论
为什么被折叠?



