使用 Kubernetes 部署和管理 Web 应用程序
什么是 Kubernetes?
Kubernetes的官方定义是: 它是一个开源的容器编排框架, 最初由谷歌于2014年开发, 但现在由云原生和计算基金会负责维护.
因此, 在这个基础上, Kubernetes 可以管理容器, 无论是 docker 容器还是其他任何容器技术, Kubernetes 都可以管理.
这意味着, Kubernetes 可以帮助你在不同的 Deployment 环境中管理由许多容器组成的应用程序, 无论是内部 Deployment , 裸机, 云还是混合云, 当然也包括边缘设备.
Kubernetes 能解决什么问题?
容器技术在行业中的出现带来了许多优势, 因为它有效地将"在我的机器上可以运行"的说法转变为"在任何地方都可以运行".
通过容器, 你可以将应用程序打包成单一的, 可移植的二进制文件, 并在各种环境中进行 Deployment .
容器化技术的兴起导致我们运行的容器数量大幅增加, 因为应用程序现在被解耦为更小, 更易于管理的组件.
然而, 容器化的激增也带来了挑战, 例如管理日益增多的容器, 解决安全问题以及处理复杂的网络问题.
在我们继续拥抱容器化带来的好处时, 找到能有效缓解这些挑战并保持应用程序效率和可靠性的解决方案至关重要, 而这正是 Kubernetes 所要解决的问题.
协作工具的功能
协作工具具有以下主要功能:
- 高可用性: 确保应用程序无停机时间, 并始终可供用户访问.
- 可扩展性和性能: 允许应用程序在需求增加时快速扩展, 并在需求减少时缩减, 从而灵活地适应不断变化的负载.
- 灾难恢复: 在发生数据丢失或Server故障等问题时, 实施恢复基础设施的机制, 确保对应用程序可用性和功能的影响降至最低.
Kubernetes 架构
Kubernetes 集群至少由一个主节点(master node)组成, 主节点与多个工作节点(worker node)相连. 每个工作节点运行一个名为 Kubelet 的进程.
Kubelet 是 Kubernetes 生态系统中的一个组件, 用于促进集群内的通信和在节点上执行任务, 如运行和调试应用程序等.
每个工作节点上都 Deployment 有不同应用的容器, 因此根据工作负载的分布情况, 每个工作节点上运行的容器数量也不同.
工作节点实际上就是我们运行应用程序的地方, 你可能会想知道主节点里有什么.
主节点:
主节点负责管理和控制 Kubernetes 集群. 它由多个进程组成, 共同维护集群的整体健康和功能:
- **API Server **: API Server 是一个容器, 是进入 Kubernetes 集群的主要入口. 它既是使用 Kubernetes 面板时的UI, 也是用于脚本的 API, 还是通过 kubectl 使用的命令行工具.
- Controller Manager: Controller Manager监控集群状态, 确保及时处理任何问题. 例如, 它可以检测容器是否发生故障, 并启动创建新容器的进程.
- Scheduler: Scheduler会根据工作负载将容器智能地分配给工作节点. 它会考虑资源需求和当前利用率等因素, 以确定最适合 Deployment 下一个容器的工作节点.
- etcd 键值存储: etcd 数据存储在任何给定时间都会维护集群的当前状态. 它是集群配置和状态的核心信息源.
虚拟网络
虚拟网络在促进 Kubernetes 集群内的通信方面发挥着至关重要的作用. 通过将所有节点互联起来, 它创建了一个强大, 统一的机器, 实现了容器之间的无缝交互和工作负载在集群中的高效分配.
Kubernetes 的主要组件
在本节中, 我们将探讨你经常会遇到的一些主要 Kubernetes 组件, 如 pod, Service, Deployment , secret 和ConfigMap. 为了便于更好地理解, 我们将通过一个涉及 Web 应用程序和数据库的简单用例进行讲解. 我将演示每个 Kubernetes 组件如何在 Deployment 和管理该设置中发挥作用, 并讨论每个组件的具体职责.
Pod
pod 是 kubernetes Deployment 的最小单元, 是容器的抽象层, 将一个或多个密切相关的容器封装在一个单元内.
如果你有使用 Docker 容器或映像的经验, 你可以把 pod 看作是一个运行时环境, 或者是容器之上的一个附加层.
这种设计选择使 Kubernetes 能够从底层容器技术中抽象出来, 从而实现灵活性, 并有可能在不直接交互的情况下使用其他容器技术.
通常情况下, pod 是为运行单个容器而设计的. 但在某些情况下, 你可能需要在一个 pod 中运行多个容器. 这可能包括辅助容器(协助主容器完成特定任务)或初始容器(在主容器开始运行前执行设置任务).
通信是如何进行的?
Kubernetes 提供了一个内置的虚拟网络, 确保每个 pod 都能收到自己唯一的 IP 地址, 而不是容器.
这个内部 IP 地址有助于 pod 之间的通信, 让应用程序容器等组件与数据库容器无缝互动.
Kubernetes 中的 pod 是短暂的, 这意味着它们很容易被终止或失败.
例如, 如果一个数据库容器因其中的应用程序出现问题而崩溃, 就会创建一个新容器来替代它.
但是, 这个新容器将被分配一个不同的 IP 地址, 如果其他组件正在使用其 IP 地址与数据库通信, 这就会造成不便, 而且每次重新启动 pod 时持续调整 IP 地址也不现实.
为了解决这个问题, Kubernetes 引入了另一个称为"Service"的组件:
Service
Kubernetes 中的Service实质上提供了一个稳定或永久的 IP 地址, 可与每个 pod 关联. 在我们的例子中, Web 应用程序 pod 和数据库 pod 将各自拥有自己的专用Service. 这样做的主要好处是, Service和 pod 的生命周期并不相互关联. 即使 pod 出现故障或被终止, Service及其 IP 地址也不会受到影响. 因此, 无需持续更新通信端点.
要通过浏览器访问应用程序, 你需要在 Kubernetes 中创建一个外部Service.
外部Service允许与外部源进行通信, 使你的应用程序可以公开访问.
不过, 重要的是要保证数据库的安全, 不要让它暴露在公众请求之下. 为此, 你可以为数据库创建一个内部Service. 在Service创建过程中, 可以指定Service类型(外部或内部), 确保应用程序的每个组件都有适当的访问权限和安全性.
我们已经看到了 Kubernetes 的一些基本组件, 我们只有一台Server, 几个正在运行的容器和一些Service. 没有什么很酷的东西, 但我们正朝着这个方向前进.
ConfigMap
Kubernetes 中的 Pod 使用Service相互通信. 例如, 网络应用可能会使用名为 mando-db-service 的Service端点连接数据库. 传统上, 配置数据库 URL 需要更新应用程序属性文件或构建映像. 如果Service端点发生变化, 这一过程就会既耗时又低效.
Kubernetes 通过ConfigMap解决了这个问题, 它允许你将数据库 URL 等外部配置与应用程序分开存储. ConfigMap 与 pod 相连, 因此当你需要更新Service端点时, 只需调整 ConfigMap 即可, 无需重建应用程序或经历复杂的 Deployment 周期.
虽然 ConfigMap 非常适合存储一般配置数据, 但可能不适合存储数据库用户名和密码等敏感信息. 在ConfigMap中存储此类凭据可能不安全. 为了安全地处理敏感数据, Kubernetes 提供了另一个名为 Secret 的组件, 专门用于存储和管理敏感信息.
Secret
Kubernetes 中的 Secret 的作用与 ConfigMap 类似, 但它们是专门为存储凭证等敏感数据而设计的. 虽然 Secret 以 base64 编码存储数据, 但这并不提供自动加密或绝对安全. 为确保存储在 Secret 中的敏感数据得到适当加密和安全, 建议结合 Kubernetes Secret 使用第三方加密工具或其他安全措施.
Volume
在我们当前的设置中, 如果应用程序使用的数据库 pod 重新启动, 任何生成的应用程序数据都会丢失. 这很不方便, 因为你希望数据能长期可靠地存在. 在 Kubernetes 中, 你可以使用Volume来实现这一点.
Volume的工作原理是将硬盘等物理存储设备附加到 pod 上. 该存储可以位于同一Server节点, Kubernetes 集群外的远程机器, 云存储或内部存储. 当 pod 重新启动时, 所有数据都会保持持久.
重要的是要明白, Kubernetes 并不直接管理数据持久性. 相反, 你可以把存储想象成插入群集的外置硬盘. 作为 Kubernetes 管理员, 你有责任确保数据得到备份和妥善管理.
Deployment
为了尽量减少停机时间并利用分布式系统和容器的优势, 我们可以在多台Server上复制应用程序. 我们可以创建运行在不同节点上的副本, 所有副本都连接到同一个Service, 而不是依赖单个 pod. 由于该Service有一个静态 IP 地址并充当负载平衡器, 因此它可以将传入的请求分配给最不繁忙的 pod.
与手动创建多个 pod 相比, 我们可以定义应用程序 pod 的蓝图, 并指定要运行的副本数量. 这种蓝图称为"Deployment".
在实践中, 你将创建 Deployment 而不是单个 pod, 因为 Deployment 允许你指定副本的数量, 并可根据需要轻松地扩大或缩小规模.
请记住, pod 是对容器的抽象, 而 Deployment 则是对 pod 的抽象, 这使得与 pod 进行交互, 复制和配置更加方便. 如果一个 pod 出现故障, Service会将请求转发给另一个可用的 pod, 确保用户仍可访问应用程序.
Statefulset
你可能想知道数据库 pod 的情况, 以及在出现故障时如何处理. 由于数据库具有状态(数据), 因此使用 Deployment 来复制数据库是不可行的. 在创建数据库副本时, 它们都需要访问相同的共享数据存储. 为了避免数据不一致, 需要一种机制来管理哪些 pod 正在向存储写入数据, 哪些 pod 正在从存储读取数据. 在 Kubernetes 中, 这个组件被称为 StatefulSet.
StatefulSets 专为有状态应用或数据库(如 MySQL, MongoDB 或任何其他有状态Service)而设计. 与其使用 Deployment , 不如使用 StatefulSets 创建有状态应用程序. 与 Deployment 一样, StatefulSets 也会处理 Pod 的复制和上下扩展. 不过, 它们还能确保数据库读写操作同步, 避免出现任何数据不一致的问题.
有了应用程序的两个副本和数据库的两个副本, 再加上负载平衡, 我们的设置就更加稳健了. 如果其中一个节点发生故障而无法运行, 另一个节点仍可同时运行应用程序和数据库. 这就确保了用户仍可访问应用程序, 避免了停机时间, 提高了系统的整体可靠性.
利用这些核心组件, 你可以构建强大的应用程序, 使其具有高可用性, 可扩展性和弹性. 通过利用 Kubernetes 及其各种组件, 你可以创建高效, 稳健和灵活的系统, 以适应你的应用需求并提供无缝的用户体验.
Kubernetes 配置
Kubernetes 集群内的所有配置都是通过主节点通过一个称为 API Server 的进程来管理的. 各种 Kubernetes 客户端(如 Kubernetes UI 面板, API 脚本或 kubectl 等命令行工具)与 API Server 通信, 并向其发送配置请求. API Server 是进入集群的主要和唯一入口. 这些请求必须采用 YAML 或 JSON 格式, 这是 Kubernetes 配置文件的公认文件格式.
Kubernetes 中的配置是声明式的, 这意味着你可以在 YAML 文件中指定所需的结果, Kubernetes 会努力实现该状态. 例如, 如果你声明需要一个 pod 的两个副本, 而其中一个出现故障, Controller Manager就会检测到一个 pod 运行不正常. 然后, 它会采取适当措施恢复所需的状态, 确保你声明的配置得到维护, 系统与你的意图保持一致.
每个 Kubernetes 配置文件都有三个主要部分:
- 元数据: 这包括定义的资源名称等信息.
- 规范: Kubernetes 中的每个组件都有自己的规格集, 也就是你想应用于资源的属性或属性.
- 状态(可选): 该部分表示资源在集群中的当前状态. 它通常由 Kubernetes 本身管理, 可能不会包含在你的初始配置文件中.
Yaml 配置
Kubernetes 配置文件的格式是 YAML, 这种格式简单易懂, 但缩进非常严格. 如果文件的缩排不正确, 就会被视为无效. 不过, 一旦熟悉了语法, 使用起来就相当简单了.
你可以将配置文件与应用程序代码一起存储, 因为 Deployment 和Service配置作为基础架构即代码(IaC)方法的一部分应用于集群. 这种做法有助于确保整个应用程序及其基础架构的一致性和可维护性.
Minikube 和 Kubectl - 本地设置
什么是 Minikube?
在 Kubernetes 世界中, 当建立集群时, 你通常需要多个控制面板和工作节点. 不过, 如果你想在本地进行实验, 有一种名为 Minikube 的开源工具可以简化这一过程. Minikube 创建了一个单节点集群, 主进程和工作进程都运行在同一个节点上. 该节点安装了 Docker 运行时, 让你能在本地环境中轻松测试和学习 Kubernetes 概念.
如何安装 Minikube
使用 Macbook 的用户可以通过运行以下命令轻松安装 Minikube:
brew install minikube
Minikube需要驱动程序才能运行, 你需要安装docker或虚拟机
Kubectl是什么?
kubectl是一种命令行界面(CLI)工具, 为与Kubernetes集群交互提供了强大的功能. 它允许你执行各种操作, 从创建和管理 pod, Service和 Deployment 等资源, 到向上或向下扩展应用程序, 推出更新和监控集群健康状况.
作为管理 Kubernetes 集群的主要工具, kubectl 为构建和 Deployment 现代云原生应用提供了一个灵活, 可扩展的平台. 无论你是在企业内部还是在云中运行集群, 它都能提供一个简单一致的界面来与你的集群进行交互, 并提供广泛的选项来定制和微调你的 Kubernetes Deployment , 以满足你的特定需求.
Lens
Lens 是一个 Kubernetes UI, 为查看和管理集群提供了一个用户友好的界面. 与 Visual Studio 等有多种用途的工具不同, Lens 是专为 Kubernetes 设计的, 具有直观, 易用的GUI.
K8sgpt
这是一款功能强大的新工具, 利用了 OpenAI 的尖端技术 Chat GPT. 要使用它, 只需连接到 ChatGPT API. 它可以在几秒钟内扫描你的整个集群, 并提供有价值的反馈和建议. 这个工具非常方便, 可以大大简化你使用 Kubernetes 的工作.
启动 Minikube
minikube start
这将启动 minikube 并在我们的机器中创建一个本地集群:
然后, 我们可以通过运行:
minikube status
现在, 我们可以开始使用安装 Minikube 时安装的 kubectl 与集群交互.
让我们运行:
kubectl get nodes
我们可以查看节点并了解其运行情况, 这样我们就可以继续使用 kubernetes 部署应用程序了:
Demo 项目概述
我们将 Deployment 一个 mango db 数据库和一个 Web 应用程序, 后者将使用外部配置 DB URL 和来自ConfigMap的凭据以及 secret 连接到 mango db 数据库, 最后我们将使我们的 Web 应用程序可通过浏览器从外部访问.
让我们生成 Deployment 应用程序所需的配置. 首先, 我们将创建一个 ConfigMap 来保存数据库端点信息, 然后创建一个 Secret 来保存 MongoDB 用户名和密码. 最后, 我们将为 MongoDB 和 Web 应用程序创建 Deployment 和Service.
mango-config.yaml
创建很简单, 你可以参考 Kubernetes 文档:
apiVersion: v1
kind: ConfigMap
metadata:
name: mongo-config
data:
mongo-url: mongo-service
数据: 我们定义为外部配置的所有键值对. 值是我们将为 mango db 数据库创建的Service.
mongo-secret.yaml
你可以参考文档, 了解如何创建 secret:
apiVersion: v1
kind: Secret
metadata:
name: mongo-secret
type: Opaque
data:
mongo-user: bW9uZ291c2Vy
mongo-password: bW9uZ29wYXNzd29yZA==
类型是 secret
类型为opeque--默认为任意键值对
密文中的值是以 base 64 编码的, 要做到这一点很简单, 只需在终端上使用以下命令:
echo -n mongouser | base64
查看 mongo 用户名
echo -n mongopassword | base64
查看 mongo 密码
创建 Deployment 时, 我们可以引用其中的任何值
mongo.yaml
我们将为 mongo Deployment 和Service创建一个文件:
apiVersion: apps/v1
kind: Deployment
metadata:
name: mongo-deployment
labels:
app: mongo
spec:
replicas: 1
selector:
matchLabels:
app: mongo
template:
metadata:
labels:
app: mongo
spec:
containers:
- name: mongodb
image: mongo:5.0
ports:
- containerPort: 27017
env:
- name: MONGO_INITDB_ROOT_USERNAME
valueFrom:
secretKeyRef:
name: mongo-secret
key: mongo-user
- name: MONGO_INITDB_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mongo-secret
key: mongo-password
resources:
limits:
memory: "128Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: mongo-service
spec:
selector:
app: mongo
ports:
- protocol: TCP
port: 27017
targetPort: 27017
Template* Deployment 中 pod 的配置
Container* 将使用哪个镜像和哪个端口
Label
Label 是附加到 k8s 资源的键值对, 这意味着你可以为从 pod 到 Deployment 的任何组件贴 Label .
为我们的组件提供额外的标识符, 我们可以使用所有 pod 共享的特定 Label 来识别所有 pod 复制.
Selector matchLabel
它将匹配使用以下配置创建的所有 pod
webapp.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp-deployment
labels:
app: webapp
spec:
replicas: 1
selector:
matchLabels:
app: webapp
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: webapp
image: nanajanashia/k8s-demo-app:v1.0
ports:
- containerPort: 3000
env:
- name: USER_NAME
valueFrom:
secretKeyRef:
name: mongo-secret
key: mongo-user
- name: USER_PWD
valueFrom:
secretKeyRef:
name: mongo-secret
key: mongo-password
- name: DB_URL
valueFrom:
configMapKeyRef:
name: mongo-config
key: mongo-url
resources:
limits:
memory: "128Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: webapp-service
spec:
type: NodePort
selector:
app: webapp
ports:
- protocol: TCP
port: 3000
targetPort: 3000
nodePort: 30100
部署所有资源
部署资源非常简单, 你可以运行以下代码:
kubectl apply -f mongo-config.yaml
kubectl apply -f mongo-secret.yaml
kubectl apply -f mongo-deployment.yaml
kubectl apply -f webapp.yaml
运行后, 我们就能检查集群中是否一切运行正常:
kubectl get all
接下来, 我们可以使用我们提供的Service访问应用程序:
kubectl get svc
接下来获取 Minikube 的 IP 地址:
minikube ip
获取 Minikube 的 IP 地址并从浏览器访问应用程序, 然后添加我们的Service正在监听的端口.
感谢你真的阅读完了, 这是一次很好的学习, 我希望这能引发你尝试玩转 kubernetes, 看看它能带来什么.
好吧, 今天的内容就分享到这里啦!
一家之言, 欢迎拍砖!
Happy Coding! Stay GOLDEN!