网络研讨会系列:深入了解Kubernetes
本文补充了关于在云中部署和管理容器化工作负载的 网络研讨会系列 。 该系列涵盖了容器的基本知识,包括管理容器生命周期、部署多容器应用程序、扩展工作负载以及使用 Kubernetes。 它还强调了运行有状态应用程序的最佳实践。
本文补充了该系列的第四部分,A Closer Look at Kubernetes。
介绍
Kubernetes 是一个用于管理容器化应用的开源容器编排工具。 在本系列的上一篇教程中,您在DigitalOcean上配置了Kubernetes。 现在集群已启动并运行,您可以在其上部署容器化应用程序。
在本教程中,您将了解当您在 Kubernetes 中部署 Pod、将其公开为服务以及通过复制控制器对其进行扩展时,这些原语如何协同工作。
先决条件
要完成本教程,您应该首先完成本系列的上一篇教程,Kubernetes 入门。
第 1 步 - 了解 Kubernetes 原语
Kubernetes 公开了一个 API,客户端用来创建、扩展和终止应用程序。 每个操作都针对 Kubernetes 管理的多个对象之一。 这些对象构成了 Kubernetes 的基本构建块。 它们是您管理容器化应用程序的原语。
以下是对 Kubernetes 的关键 API 对象的总结:
- Clusters:计算、存储和网络资源池。
- Nodes:在集群中运行的主机。
- Namespaces:集群的逻辑分区。
- Pods:部署单元。
- Labels 和 Selectors:用于识别和服务发现的键值对。
- Services:属于同一应用程序的 Pod 集合。
- 副本集:确保可用性和可扩展性。
- Deployment:管理应用程序生命周期。
让我们更详细地看看这些。
运行 Kubernetes 集群的 Nodes 也被视为对象。 它们可以像 Kubernetes 的任何其他 API 对象一样进行管理。 为了实现应用程序的逻辑分离,Kubernetes 支持创建 Namespaces。 例如,一个组织可以对 Kubernetes 集群进行逻辑分区,以运行开发、测试、登台和生产环境。 每个环境都可以放置在独立管理的专用命名空间中。 Kubernetes 通过 主节点 公开其 API。
虽然 Kubernetes 运行 Docker 容器,但这些容器不能直接部署。 相反,应用程序需要以 Kubernetes 理解的格式打包。 这种格式使 Kubernetes 能够有效地管理容器化应用程序。 这些应用程序可能包含一个或多个需要协同工作的容器。
Kubernetes 中打包和部署的基本单元称为 Pod。 每个 Pod 可能包含一个或多个需要一起管理的容器。 例如,一个 Web 服务器 (Nginx) 容器和一个缓存 (Redis) 容器可以打包在一起作为 Pod。 Kubernetes 将属于 Pod 的所有容器视为一个逻辑单元。 每次创建新 Pod 时,都会创建 Pod 定义中声明的所有容器。 Pod 中的所有容器共享相同的上下文,例如 IP 地址、主机名和存储。 它们通过进程间通信 (IPC) 而不是远程调用或 REST API 相互通信。
一旦容器被打包并部署在 Kubernetes 上,就需要公开它们以供内部和外部访问。 某些容器(如数据库和缓存)不需要暴露给外界。 由于其他消费者和最终用户将直接访问 API 和 Web 前端,因此它们必须向公众公开。 在 Kubernetes 中,容器根据策略在内部或外部公开。 这种机制将降低将敏感工作负载(例如数据库)暴露给公众的风险。
Kubernetes 中的 Pod 通过 Services 公开。 每个服务与端口和协议信息一起被声明为内部或外部端点。 包括其他 Pod 在内的内部消费者和 API 客户端等外部消费者依赖 Kubernetes 服务进行基本交互。 服务支持 TCP 和 UDP 协议。
Kubernetes 中的每个对象,例如 Pod 或 Service,都与称为 Labels 和 Selectors 的附加元数据相关联。 标签是附加到 Kubernetes 对象的键/值对。 这些标签唯一地标识一个或多个 API 对象。 选择器将一个 Kubernetes 对象与另一个相关联。 例如,在 Service 中定义的 Selector 可以帮助 Kubernetes 找到所有具有与 Selector 值匹配的 Label 的 Pod。 这种关联可以动态发现对象。 在运行时创建的具有相同标签的新对象将被立即发现并与相应的选择器相关联。 这种服务发现机制可以实现高效的动态配置,例如横向扩展和横向扩展操作。
切换到容器的优势之一是快速扩展。 由于与虚拟机相比容器是轻量级的,因此您可以在几秒钟内扩展它们。 对于高可用性和可扩展的设置,您需要部署应用程序的多个实例,并确保这些应用程序的最少数量的实例始终在运行。 为了解决容器化应用程序的这种配置问题,Kubernetes 引入了 Replica Sets 的概念,旨在始终运行一个或多个 Pod。 当需要在集群中运行多个 Pod 实例时,它们会被打包为 Replica Set。 Kubernetes 将确保 Replica Set 中定义的 Pod 数量始终处于运行模式。 如果一个 Pod 因硬件或配置问题而终止,Kubernetes 控制平面将立即启动另一个 Pod。
Deployment 对象是 Pod 和副本集的组合。 这个原语为 Kubernetes 应用程序带来了类似 PaaS 的功能。 它允许您以最少的停机时间对现有部署执行滚动升级。 部署还支持金丝雀部署和蓝/绿部署等模式。 它们处理容器化应用程序的应用程序生命周期管理 (ALM) 的基本部分。
第 2 步 – 列出 Kubernetes 节点和命名空间
假设您已按照 在 DigitalOcean 中设置 Kubernetes 集群的步骤,运行以下命令列出所有节点和可用命名空间:
kubectl get nodes
OutputNAME STATUS ROLES AGE VERSION spc3c97hei-master-1 Ready master 10m v1.8.7 spc3c97hei-worker-1 Ready <none> 4m v1.8.7 spc3c97hei-worker-2 Ready <none> 4m v1.8.7
kubectl get namespaces
OutputNAME STATUS AGE default Active 11m kube-public Active 11m kube-system Active 11m stackpoint-system Active 4m
当未指定命名空间时,kubectl
以默认命名空间为目标。
现在让我们启动一个应用程序。
第 3 步 - 创建和部署 Pod
Kubernetes 对象在 YAML 文件中声明并通过 kubectl
CLI 提交给 Kubernetes。 让我们定义一个 Pod 并部署它。
创建一个名为 Simple-Pod.yaml
的新 YAML 文件:
nano Simple-Pod.yaml
添加以下代码,它定义了一个基于 Nginx Web 服务器的具有一个容器的 Pod。 它通过 TCP 协议暴露在端口 80
上。 请注意,该定义包含标签 name
和 env
。 我们将使用这些标签来识别和配置特定的 Pod。
Simple-Pod.yaml
apiVersion: "v1" kind: Pod metadata: name: web-pod labels: name: web env: dev spec: containers: - name: myweb image: nginx ports: - containerPort: 80 name: http protocol: TCP
运行以下命令创建 Pod。
kubectl create -f Simple-Pod.yaml
Outputpod "web-pod" created
让我们验证 Pod 的创建。
kubectl get pods
OutputNAME READY STATUS RESTARTS AGE web-pod 1/1 Running 0 2m
在下一步中,我们将让这个 Pod 可以访问公共 Internet。
第 4 步 - 通过服务公开 Pod
服务在内部或外部公开一组 Pod。 让我们定义一个使 Nginx pod 公开可用的服务。 我们将通过 NodePort 公开 Nginx,该方案使 Pod 可以通过在集群的每个节点上打开的任意端口访问。
创建一个名为 Simple-Service.yaml
的新文件,其中包含定义 Nginx 服务的代码:
简单服务.yaml
apiVersion: v1 kind: Service metadata: name: web-svc labels: name: web env: dev spec: selector: name: web type: NodePort ports: - port: 80 name: http targetPort: 80 protocol: TCP
Service 会发现在同一个 Namespace 中与 Label 匹配 name: web
的所有 Pod。 YAML 文件的选择器部分明确定义了这种关联。
我们通过 type: NodePort 声明指定 Service 的类型为 NodePort。
然后使用 kubectl 提交到集群。
kubectl create -f Simple-Service.yml
您将看到此输出表明服务已成功创建:
Outputservice "web-svc" created
让我们获取 Pod 可用的端口。
kubectl get services
OutputNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.3.0.1 <none> 443/TCP 28m web-svc NodePort 10.3.0.143 <none> 80:32097/TCP 38s
从这个输出中,我们看到服务在端口 32097
上可用。 让我们尝试连接到其中一个工作节点。
使用 DigitalOcean 控制台获取其中一个工作节点的 IP 地址。
使用 curl
命令向端口 31930
上的节点之一发出 HTTP 请求。
curl http://your_worker_1_ip_address:32097
您将看到包含 Nginx 默认主页的响应:
Output<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> ... Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
您已经定义了一个 Pod 和一个服务。 现在让我们看看使用 Replica Sets 进行缩放。
第 5 步 – 通过副本集扩展 Pod
副本集确保集群中至少有最少数量的 Pod 正在运行。 让我们删除当前的 Pod,并通过 Replica Set 重新创建三个 Pod。
首先,删除现有的 Pod。
kubectl delete pod web-pod
Outputpod "web-pod" deleted
现在创建一个新的副本集声明。 Replica Set 的定义与 Pod 相同。 关键区别在于它包含定义需要运行的 Pod 数量的副本元素。 与 Pod 一样,它也包含标签作为元数据,有助于服务发现。
创建文件 Simple-RS.yml
并将此代码添加到文件中:
简单的RS.yml
apiVersion: apps/v1beta2 kind: ReplicaSet metadata: name: web-rs labels: name: web env: dev spec: replicas: 3 selector: matchLabels: name: web template: metadata: labels: name: web env: dev spec: containers: - name: myweb image: nginx ports: - containerPort: 80 name: http protocol: TCP
保存并关闭文件。
现在创建副本集:
kubectl create -f Simple-RS.yml
Outputreplicaset "web-rs" created
然后检查 Pod 的数量:
kubectl get pods
OutputNAME READY STATUS RESTARTS AGE web-rs-htb58 1/1 Running 0 38s web-rs-khtld 1/1 Running 0 38s web-rs-p5lzg 1/1 Running 0 38s
当我们通过 NodePort 访问 Service 时,请求将被发送到 Replica Set 管理的 Pod 之一。
让我们通过删除其中一个 Pod 并看看会发生什么来测试 Replica Set 的功能:
kubectl delete pod web-rs-p5lzg
Outputpod "web-rs-p5lzg" deleted
再次查看 pod:
kubectl get pods
OutputNAME READY STATUS RESTARTS AGE web-rs-htb58 1/1 Running 0 2m web-rs-khtld 1/1 Running 0 2m web-rs-fqh2f 0/1 ContainerCreating 0 2s web-rs-p5lzg 1/1 Running 0 2m web-rs-p5lzg 0/1 Terminating 0 2m
一旦 Pod 被删除,Kubernetes 就会创建另一个 Pod 以确保保持所需的计数。
现在让我们看看部署。
第 6 步 - 处理部署
虽然您可以将容器部署为 Pod 和副本集,但部署可以更轻松地升级和修补您的应用程序。 您可以使用 Deployment 就地升级 Pod,而使用 Replica Set 则无法做到这一点。 这使得以最少的停机时间推出新版本的应用程序成为可能。 它们为应用程序管理带来了类似 PaaS 的功能。
在创建 Deployment 之前删除现有的 Replica Set。 这也将删除关联的 Pod:
kubectl delete rs web-rs
Outputreplicaset "web-rs" deleted
现在定义一个新的部署。 创建文件 Simple-Deployment.yaml
并添加以下代码:
简单部署.yaml
apiVersion: apps/v1beta2 kind: Deployment metadata: name: web-dep labels: name: web env: dev spec: replicas: 3 selector: matchLabels: name: web template: metadata: labels: name: web spec: containers: - name: myweb image: nginx ports: - containerPort: 80
创建部署并验证创建。
kubectl create -f Simple-Deployment.yml
Outputdeployment "web-dep" created
查看部署:
kubectl get deployments
OutputNAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE web-dep 3 3 3 3 1m
由于 Deployment 会创建 Pod,因此根据 YAML 文件中的副本声明,将运行三个 Pod。
kubectl get pods
OutputNAME READY STATUS RESTARTS AGE web-dep-8594f5c765-5wmrb 1/1 Running 0 2m web-dep-8594f5c765-6cbsr 1/1 Running 0 2m web-dep-8594f5c765-sczf8 1/1 Running 0 2m
我们之前创建的 Service 将继续将请求路由到 Deployment 创建的 Pod。 这是因为 Labels 包含与原始 Pod 定义相同的值。
通过删除部署和服务来清理资源。
kubectl delete deployment web-dep
Outputdeployment "web-dep" deleted
kubectl delete service web-svc
Outputservice "web-svc" deleted
有关部署的更多详细信息,请参阅 Kubernetes 文档。
结论
在本教程中,您在使用 Pod、服务、副本集和部署部署 Nginx Web 服务器时探索了 Kubernetes 的基本构建块。
在本系列的下一部分中,您将学习如何打包、部署、扩展和管理多容器应用程序。