使用Kubernetes部署一个三层容器化应用基础架构

我们需要构建的东西

  1. 一个使用minikube的Kubernetes环境,包含一个(1)主节点/控制平面节点和三个(3)工作节点。
  2. 一个Kubernetes应用部署,将部署一个三层应用架构(Web/Apache、Node.js和Postgres数据库)。

注意:在这个示例中,我们不会有任何应用程序的源代码。我们将更加关注应用程序的架构和基础设施。

先决条件

  • 熟悉Linux系统和命令。
  • 熟悉Docker容器和编排方法,如Docker Compose和Swarm。
  • 您的系统已安装Docker。
  • 访问命令行工具。

Kubernetes是什么?

与Docker Swarm类似,Kubernetes是领先的容器编排工具之一,但适用于更大型和更复杂的应用工作负载。它提供了更高的灵活性、可扩展性、可靠性和特定性,以便部署工作负载。

那么...Kubernetes比Docker Swarm更好,对吗?

不一定!尽管Docker Swarm更轻量级,但通常被认为更易于使用和扩展。就像技术领域的任何事物一样,这真的取决于想要构建的内容。

一些关键的区别

Kubernetes在Docker之上添加了一层抽象,因此它有自己的一套API来创建网络、容器和卷。就像 docker 一样,我们可以通过 kubectl CLI访问API引擎。

Pods

Pods是部署的基本单位。它们与Swarm中的服务/容器非常相似,但在其上有一层抽象(你会经常听到这个词)。一个节点内可以有多个Pod,一个Pod内可以有多个容器。这可能有点令人困惑,但只要知道,当我们提到"Pods"时,就相当于"容器"。

服务:

在Swarm中,服务指的是容器/任务定义和部署。在Kubernetes中,服务指的是用于内部通信或与外部服务通信的Pod的网络和稳定的终端点/地址。有三种主要类型的服务:ClusterIP、NodePort和LoadBalancer。

让我们开始吧!

安装minikube和Hyperkit

在开始构建我们的容器化应用之前,我们需要创建一个本地开发环境。minikube是一个很棒的工具,它允许我们在本地机器上实现多节点的Kubernetes集群,并且已经预装了kubectl。

以你认为合适的方式在你的系统上安装minikube,但对于我来说(macOS),Homebrew软件包管理器是最直接的方法,它还允许我们安装所需的虚拟机环境。

yml 复制代码
brew install minikube

要在本地运行一个多节点集群,minikube需要一个虚拟机驱动程序,因此我们需要安装一个虚拟机工具,比如Hyperkit、VirtualBox或Parallels。我将使用Hyperkit,但你可以自由选择。

yml 复制代码
brew install hyperkit

集群设置

如果你还记得Docker Swarm,我们的容器工作负载运行在"节点"上,这些节点可以是物理或虚拟机/服务器,提供高可用性和容错性。在Swarm中,节点被分配为管理节点或工作节点的角色。在Kubernetes中,原则是相同的,但节点被分为控制平面的角色 - 包含所有主节点 - 和工作节点。让我们在minikube中设置我们的集群。

  1. 一个(1)主/控制平面节点。
  2. 三个工作节点。

默认情况下,minikube将我们的本地机器分配为主节点/控制平面节点,其他所有节点都作为工作节点。

yml 复制代码
minikube start --driver hyperkit --nodes 4

现在,我们可以使用 kubectl 命令来获取我们的节点

yml 复制代码
kubectl get nodes

限制Pod分配

我们只希望将Pod调度到工作节点上,因此我们需要向控制平面添加特殊指令,以形式化一个污点。污点允许节点通过告诉调度器不要调度任何Pod,除非它们具有匹配的容忍度来排斥一组Pod。

yml 复制代码
kubectl taint nodes node_name key1=value1:NoSchedule 

部署前端网页层

类似于Docker Compose,一个应用的整个基础设施可以使用单个YAML文件部署;然而,Kubernetes的YAML文件可能会更加复杂和详细。虽然可以使用单个YAML文件,但如果将部署配置拆分为几个有组织的文件,可能更容易管理。

我们将从前端Web层开始,部署包含Apache Web服务器的Pod。

我已将我的"kube_app"应用程序目录组织成"前端","后端"和"数据库"层。

前端网络服务

我们一直在使用Docker Swarm,所以你可能对"服务"这个术语很熟悉。在Docker中,服务是在容器上运行的镜像或镜像类型,比如Apache、NGINX、Node、Postgres等等。它本质上是一个容器/任务的描述和角色,将在集群中部署。

Kubernetes服务是指用于容器组内部通信或与外部服务通信的网络和稳定的终端/地址。主要有三种类型的服务:ClusterIP、NodePort和LoadBalancer。

ClusterIP创建虚拟IP以允许Pod之间进行通信。我们的集群被赋予了一个默认的ClusterIP,这样控制平面和工作节点就可以相互通信。

yml 复制代码
kubectl get services

NodePort允许控制平面公开和分配特定端口以供外部访问。这是我们访问80端口上的网站所需的服务类型。

创建一个名为 frontend-kube-app.yml 的新YAML文件。

yml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: web-httpd-service
spec:
  type: NodePort
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  selector:
    app: web-httpd
---

每个Kubernetes对象或类型都指向特定的API组,因此了解应该指向哪个 apiVersion 非常重要。找到这个的一个简单方法是查看 api-resources 并找到对象的版本。

yml 复制代码
kubectl api-resources

metadata 下,我们可以给我们的服务起一个名字(必填)。

我们将 type 指定为 Nodeport ,并开放80端口。

selector 的概念和标签非常重要。该服务使用选择器来允许流量访问具有匹配标签的Pod。

--- 表示一个分隔符,表示对象的结束。

提示:不要试图在文档之间来回切换,你可以使用 explain 命令获取关于对象的每个部分的详细信息。例如,你可以使用点表示法来深入研究特定领域,比如 kubectl explain service.spec ,它会给出该类别下每个选项的解释。

前端网站部署

现在我们准备创建一个部署!部署更类似于Docker服务。它是关于Pod的指令和规范的集合,包括镜像、副本数量、端口、重启策略等等...

在同一个文件中,在服务对象下面:

yml 复制代码
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-httpd-deployment
spec:
  selector:
    matchLabels:
      app: web-httpd
  replicas: 10
  template:
    metadata:
      labels:
        app: web-httpd
    spec:
      containers:
        - name: web-httpd
          image: httpd:2.4.55
          ports:
            - containerPort: 80

我们保持得很简单,但你可以看到更详细的规格会使这变得稍微复杂一些。

正如我们所看到的,Pod部署属于kind: Deployment,并拥有自己的API组。我们还应该注意到 selector 部分,我们给它一个与web-httpd-service选择器相同的 matchlabel ,这样它们就知道彼此如何连接。

template 下,我们可以提供容器的信息,例如名称、镜像和端口。

部署Pod和服务

我们准备部署我们的第一个Pod!这是容易的部分。我们所要做的就是配置并指向我们的YAML文件。

yml 复制代码
kubectl apply -f ./frontend/frontend-kube-app.yml

我们可以运行 kubectl get all -o wide 来获取我们集群中所有服务和Pod的详细信息。

好的!我们的十个Pod都已经启动并运行,我们可以看到它们都没有分配到主节点/控制平面节点上。

我们还可以看到我们的NodePort服务及其端口映射。让我们尝试通过使用任何一个节点的IP地址和NodePort端口(右侧的数字)来访问Web服务器。我们可以通过运行 kubectl get nodes -o wide 来获取节点的IP地址。

它成功了!我们刚刚将我们的第一个Kubernetes pod部署到了我们的集群中!

部署后端应用层

既然我们已经完成了第一阶段,接下来基本上就是重复洗涤的过程了,只是根据您的需求来调整规格。

由于我们目前没有任何应用程序源代码或需要连接任何东西,我们只需为应用程序后端创建一个简单的 Deployment 。在 backend 目录中,创建一个名为 backend-kube-app.yml 的新YAML文件。

yml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nodejs-app-deployment
spec:
  selector:
    matchLabels:
      app: nodejs-app
  replicas: 4
  template:
    metadata:
      labels:
        app: nodejs-app
    spec:
      containers:
        - name: nodejs-app
          image: node:19-alpine3.16
          command: ["sleep", "100000"]

为了测试目的,我们将输入一段 commandsleep ,以保持容器的开启和运行。

再次运行 apply 命令并获取结果。

yml 复制代码
kubectl apply -f ./backend/backend-kube-app.yml
yml 复制代码
kubectl get all -o wide

太棒了!我们提供的4个Pod都成功运行了。

部署后端数据库层

我们已经准备好进入最后阶段,并为我们的应用程序部署数据库(Postgres)。数据库可能会稍微复杂一些,所以让我们来分解一下我们所需要的内容:

  1. 一个 ConfigMap 用于存储用户名和密码等秘密信息。
  2. 定义和分配存储空间给数据库A的 PersistantVolumePersistantVolumeClaim
  3. 连接数据库的 Service
  4. 定义并部署数据库Pod到我们的集群。

创建一个ConfigMap

将数据与代码分离始终是最佳实践。在开发中,通过ConfigMap是一个很好的方法来实现这一点。Kubernetes为此目的拥有自己的API组。

在数据库目录中,创建一个名为 postgres-config.yml 的新YAML文件

yml 复制代码
apiVersion: v1
kind: ConfigMap
metadata:
  name: postgres-config
  labels:
    app: postgres-db
data:
  POSTGRES_DB: postgresdb
  POSTGRES_USER: admin
  POSTGRES_PASSWORD: mypass

在这里,我们将存储环境变量,例如数据库名称、用户和密码。再次特别注意 labels ,因为这是我们的部署将用来连接配置的内容。

将ConfigMap应用到集群中。

yml 复制代码
kubectl apply -f ./database/postgres-config.yml

创建一个持久卷和持久卷声明

由于Pod是短暂的,也就是说一旦它们消失,它们所携带的所有数据也会消失,因此我们需要为我们的数据库提供持久存储。在这里,我们将定义容量、访问方式和卷的主机路径。

一旦我们创建了卷,我们需要一个 PersistantVolumeClaim ,它定义了用户请求和使用PV资源的方式。

创建一个名为 postgres-pvc-pv.yml 的新YAML文件。

yml 复制代码
kind: PersistentVolume
apiVersion: v1
metadata:
  name: postgres-pv-volume  # Sets PV's name
  labels:
    type: local  # Sets PV's type to local
    app: postgres-db
spec:
  storageClassName: manual
  capacity:
    storage: 5Gi # Sets PV Volume
  accessModes:
    - ReadWriteMany
  hostPath:
    path: "/mnt/data"
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: postgres-pv-claim  # Sets name of PVC
  labels:
    app: postgres-db
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteMany  # Sets read and write access
  resources:
    requests:
      storage: 5Gi  # Sets volume size

将PV和PVC应用于集群。

yml 复制代码
kubectl apply -f ./database/postgres-pvc-pv.yml

创建服务

现在,我们只需创建一个简单的NodePort服务,并暴露端口5432。

创建一个名为 database-kube-app.yml 的新YAML文件。

yml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: postgres # Sets service name
  labels:
    app: postgres-db # Labels and Selectors
spec:
  type: NodePort # Sets service type
  ports:
    - port: 5432 # Sets port to run the postgres application
  selector:
    app: postgres-db
---

创建部署

最后,我们将为我们的Postgres数据库创建部署选项(在同一个文件中)。

yml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgres-db-deployment  # Sets Deployment name
spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgres-db
  template:
    metadata:
      labels:
        app: postgres-db
    spec:
      containers:
        - name: postgres-db
          image: postgres:10.1 # Sets Image
          imagePullPolicy: "IfNotPresent"
          ports:
            - containerPort: 5432  # Exposes container port
          envFrom:
            - configMapRef: # Maps env variable from ConfigMap
                name: postgres-config
          volumeMounts:
            - mountPath: /var/lib/postgresql/data
              name: postgres-volume
      volumes:
        - name: postgres-volume
          persistentVolumeClaim:
            claimName: postgres-pv-claim # Maps claim from PersistantVolumeClaim

我们可以从配置和持久卷声明(这就是为什么名称和标签很重要!)中映射我们的环境变量 envFrom 和卷。

将服务和部署应用到集群中。

yml 复制代码
kubectl apply -f ./database/postgres-pvc-pv.yml

测试数据库连接

为了保险起见,让我们测试一下,看看我们能否连接到数据库。

yml 复制代码
kubectl exec -it [pod-name] --  psql -h localhost -U admin --password -p 5432 postgresdb

输入数据库密码并输入 \l 以列出所有数据库。

我们进来了!

成功!

恭喜!我们刚刚成功部署了一个高可用性和容错性的应用基础架构,使用了Kubernetes!Kubernetes和容器化应用的美妙之处在于,我们可以将其打包并在任何环境中导入,几乎不需要进行任何修改。

删除

完成后,我们可以运行 minikube stop 来停止环境,或者运行 minikube delete 来删除所有资源。

相关推荐
稻草人22223 小时前
java Excel 导出 ,如何实现八倍效率优化,以及代码分层,方法封装
后端·架构
数据智能老司机4 小时前
精通 Python 设计模式——创建型设计模式
python·设计模式·架构
数据智能老司机5 小时前
精通 Python 设计模式——SOLID 原则
python·设计模式·架构
bobz9659 小时前
k8s svc 实现的技术演化:iptables --> ipvs --> cilium
架构
云舟吖9 小时前
基于 electron-vite 实现一个 RPA 网页自动化工具
前端·架构
brzhang10 小时前
当AI接管80%的执行,你“不可替代”的价值,藏在这20%里
前端·后端·架构
Lei活在当下21 小时前
【业务场景架构实战】4. 支付状态分层流转的设计和实现
架构·android jetpack·响应式设计
架构师沉默1 天前
设计多租户 SaaS 系统,如何做到数据隔离 & 资源配额?
java·后端·架构
资源开发与学习1 天前
Kubernetes集群核心概念 Service
kubernetes
容器魔方1 天前
Bloomberg 正式加入 Karmada 用户组!
云原生·容器·云计算