在本教程中,我们将首先了解Kubernetes和容器编排的一般情况,然后我们将通过一个分步骤的教程,详细介绍如何将一个基于Flask的微服务(以及Postgres和Vue.js)部署到Kubernetes集群。
这是一个中级别的教程。请回顾《用Python、Flask和Docker进行测试驱动开发》课程,以了解这些工具的更多信息。
依赖性。
-
Kubernetes v1.21.0
-
Minikube v1.19.0
-
Docker v20.10.5
-
Docker-Compose v1.28.5
目标
在本教程结束时,你将能够。
- 解释什么是容器编排,以及为什么你可能需要使用一个编排工具
- 讨论使用Kubernetes与其他协调工具(如Docker Swarm和Elastic Container Service(ECS))的利弊。
- 解释以下Kubernetes基元。节点、Pod、服务、标签、部署、入口和体积
- 使用Docker Compose在本地启动一个基于Python的微服务
- 用Minikube配置一个Kubernetes集群在本地运行
- 在Kubernetes集群中设置一个卷来保存Postgres数据
- 使用Kubernetes Secrets来管理敏感信息
- 在Kubernetes上运行Flask、Gunicorn、Postgres和Vue
- 通过Ingress将Flask和Vue暴露给外部用户
什么是容器编排(Container Orchestration)?
当你从在单台机器上部署容器到在多台机器上部署时,你需要一个协调工具来管理(和自动化)整个系统中容器的安排、协调和可用性。
协调工具有助于。
- 跨服务器的容器通信
- 横向扩展
- 服务发现
- 负载平衡
- 安全/TLS
- 零停机时间的部署
- 回滚
- 记录
- 监控
这就是Kubernetes与其他一些协调工具(如Docker Swarm、ECS、Mesos和Nomad)配合的地方。
你应该使用哪一个?
- 如果你需要管理大型、复杂的集群,就使用Kubernetes。
- 如果你刚开始工作和/或需要管理中小型集群,就使用Docker Swarm。
- 如果你已经在使用一些AWS服务,就使用ECS。
工具 | 优点 | 缺点 |
---|---|---|
Kubernetes | 庞大的社区,灵活,大多数功能,时髦 | 设置复杂,学习曲线高,时髦 |
Docker Swarm | 易于设置,非常适合小型集群 | 受限于Docker的API |
ECS | 完全管理的服务,与AWS集成 | 厂商锁定 |
市场上也有一些管理型的Kubernetes服务。
- 谷歌Kubernetes引擎(GKE)
- 弹性Kubernetes服务(EKS)
- Azure Kubernetes服务(AKS)
- DigitalOcean Kubernetes
更多信息,请查看《选择正确的容器化和集群管理工具》博文。
Kubernetes的概念
在深入研究之前,让我们看看你必须从Kubernetes API中获得的一些基本构建块。
- **节点**是为运行Kubernetes而配置的工作机。每个Node都由Kubernetes主站管理。
- **Pod**是一个逻辑上紧密耦合的应用容器组,在Node上运行。Pod中的容器被部署在一起并共享资源(如数据卷和网络地址)。多个Pod可以在一个节点上运行。
- **服务**是一个逻辑上的Pod集合,执行类似的功能。它可以实现负载平衡和服务发现。它是Pod上的一个抽象层;Pod是短暂的,而服务是更持久的。
- **部署**是用来描述Kubernetes的理想状态的。它们决定了Pod的创建、部署和复制的方式。
- **标签**是连接到资源(如Pod)的键/值对,用于组织相关的资源。你可以把它们想成是CSS选择器。比如说。
- 环境-
dev
,test
。prod
- 应用程序版本-
beta
。1.2.1
- 类型-
client
,server
。db
- 环境-
- **Ingress**是一组路由规则,用于控制基于请求主机或路径的服务的外部访问。
- **卷**是用来在容器寿命结束后持久保存数据的。它们对于像Redis和Postgres这样的有状态的应用特别重要。
- *PersistentVolume*定义了一个独立于正常Pod生命周期的存储卷。它是在它所在的特定Pod之外管理的。
- *PersistentVolumeClaim*是一个用户使用PersistentVolume的请求。
欲了解更多信息,请查看学习Kubernetes基础教程以及Kubernetes概念讲座中的Kubernetes概念幻灯片,该讲座是用Kubernetes扩展Flask。
项目设置
克隆flask-vue-kubernetesrepo,然后构建镜像并启动容器。
创建并播种数据库books
表。
在你选择的浏览器中测试以下服务器端的端点。
http://localhost:5001/books/ping
container_id
是应用程序所运行的Docker容器的ID。
导航到http://localhost:8080。确保基本的CRUD功能按预期运行。
在继续前进之前,快速浏览一下代码。
想了解如何建立这个项目?请查看《用Flask和Vue.js开发单页应用程序》博文。
Minikube
Minikube是一个工具,它允许开发者在本地使用和运行Kubernetes集群。这是一个快速启动和运行集群的好方法,因此你可以开始与Kubernetes API互动。
按照官方的入门指南,将Minikube与以下内容一起安装。
- 一个管理程序(如VirtualBox或HyperKit)来管理虚拟机
- Kubectl来部署和管理Kubernetes上的应用程序
如果你使用的是Mac,我们建议用Homebrew安装Kubectl和Minikube。
然后,启动集群,拉出Minikube仪表板。
值得注意的是,配置文件将位于~/.kube目录下,而所有的虚拟机位将位于~/.minikube目录下。
现在我们可以开始通过Kubernetes API创建对象。
如果你遇到Minikube的问题,通常最好是完全删除它并重新开始。
比如说。
创建对象
要在Kubernetes中创建一个新的对象,你必须提供一个 "规格",描述它所期望的状态。
例如。
必要的字段。
apiVersion
-Kubernetes API版本kind
- 你想创建的对象的类型metadata
- 关于该对象的信息,以便它可以被唯一识别spec
- 对象的预期状态
在上面的例子中,该规范将为Flask应用程序创建一个新的部署,并带有一个副本(Pod)。请注意containers
部分。在这里,我们指定了Docker镜像以及应用程序要运行的容器端口。
为了运行我们的应用程序,我们需要设置以下对象。
流量
同样,由于容器是短暂的,我们需要通过PersistentVolume和PersistentVolumeClaim来配置一个卷,以存储Pod之外的Postgres数据。
请注意kubernetes/persistent-volume.yml中的YAML文件。
这个配置将在Node内的"/data/postgres-pv "创建一个hostPathPersistentVolume。卷的大小为2吉字节,访问模式为ReadWriteOnce,这意味着该卷可以被单个节点挂载为读写。
值得注意的是,Kubernetes只支持在单节点集群上使用hostPath。
创建卷。
查看细节。
你应该看到。
你也应该在仪表板上看到这个对象。
kubernetes/persistent-volume-claim.yml。
创建卷的要求。
查看细节。
秘密
秘密是用来处理敏感信息的,如密码、API令牌和SSH密钥。我们将设置一个Secret来存储我们的Postgres数据库凭证。
kubernetes/secret.yml。
user
和password
字段是base64编码的字符串(通过隐蔽性的安全)。
请记住,任何能够访问集群的用户都能够读取明文的值。如果你想在传输过程中和休息时对秘密进行加密,可以看看Vault。
添加Secrets对象。
Postgres
在集群中设置了卷和数据库凭证后,我们现在可以配置Postgres数据库本身。
我们可以使用kubernetes/postgres-deployment.yml。
这里发生了什么?
metadata
name
字段定义了部署的名称------。postgres
labels
定义部署的标签 -name: database
spec
replicas
定义要运行的Pod的数量 -1
selector
定义了部署如何找到要管理的Podtemplate
metadata
labels
指出哪些标签应该被分配给Pod -service: postgres
spec
containers
定义与每个Pod相关的容器volumes
定义卷要求 -postgres-volume-mount
restartPolicy
定义重启政策-Always
此外,Pod的名称是postgres
,图像是postgres:13-alpine
,它将从Docker Hub提取。从Secret对象中获取的数据库凭证也会被传入。
最后,当应用时,卷要求将被安装到Pod中。卷要求被挂载到"/var/lib/postgresql/data"--默认位置--而数据将被存储在PersistentVolume,"/data/postgres-pv"。
创建部署。
状态。
kubernetes/postgres-service.yml。
这里发生了什么?
metadata
name
字段定义了服务名称 -postgres
labels
定义该服务的标签 -name: database
spec
selector
定义服务所适用的Pod标签和值 - 定义服务的类型service: postgres
type
定义了服务的类型ClusterIP
ports
port
定义暴露在集群中的端口
花点时间回到部署规范中去。服务中的
selector
是如何与部署相关联的?
由于服务的类型是ClusterIP
,它不对外公开,所以它只能从集群内部被其他对象访问。
创建该服务。
创建books
数据库,使用Pod名称。
验证创建情况。
你也可以通过以下方式获得Pod名称。
将该值分配给一个变量,然后创建数据库。
花点时间查看Flask项目结构以及Dockerfile和entrypoint.sh文件。
- "services/server"
- services/server/Dockerfile
- services/server/entrypoint.sh
kubernetes/flask-deployment.yml。
这看起来应该与Postgres部署规范类似。最大的区别是,你可以使用我在Docker Hub上预建和预推的镜像,mjhea0/flask-kubernetes
,或者建立和推送你自己的。
比如说。
如果你使用你自己的,请确保在kubernetes/flask-deployment.yml中用你的Docker Hub名称替换mjhea0
。
另外,如果不想把镜像推送到Docker注册中心,在本地构建镜像后,你可以把
image-pull-policy
标志设为Never
,以便始终使用本地镜像。
创建部署。
这将立即启动一个新的Pod。
kubernetes/flask-service.yml。
对
targetPort
以及它与port
的关系感到好奇吗?查看正式的服务指南。
创建服务。
确保Pod与服务相关联。
应用迁移并为数据库添加种子。
验证。
入站
为了使流量能够访问集群内的Flask API,你可以使用NodePort、LoadBalancer或Ingress。
- NodePort在节点上的一个开放端口上暴露一个服务。
- 顾名思义,LoadBalancer创建一个外部负载平衡器,指向集群中的一个服务。
- 与前两种方法不同,Ingress不是服务的一种类型;相反,它位于服务之上,是进入集群的一个入口。
更多信息,请查阅官方发布服务指南。
在这里,我们定义了以下的HTTP规则:1.kubernetes/minikube-ingress.yml。
在这里,我们定义了以下HTTP规则。
/
- 将请求路由到Vue服务(我们还需要设置)。/books
- 将请求路由到Flask服务
启用Ingress插件。
创建Ingress对象。
如果你看到一个
Internal error occurred: failed calling webhook "validate.nginx.ingress.kubernetes.io"
的错误,尝试删除ValidatingWebhookConfiguration
。更多信息,请查看Stack Overflow的这个主题。
接下来,你需要更新你的*/etc/hosts*文件,将请求从我们定义的主机,hello.world
,路由到Minikube实例。
在*/etc/hosts*中添加一个条目。
试试吧。
Vue
继续前进,查看Vue项目以及相关的Docker文件。
- "服务/客户"
- /services/client/Dockerfile
- /services/client/Dockerfile-minikube
kubernetes/vue-deployment.yml。
同样,要么使用我的镜像,要么构建并推送你自己的镜像到Docker Hub。
创建部署。
验证Pod是否与部署一起被创建。
你如何验证Pod和部署在仪表板上被成功创建?
kubernetes/vue-service.yml。
创建服务。
确保hello.world/,按预期工作。
缩放
Kubernetes可以很容易地进行扩展,当流量负荷过大,单个Pod无法处理时,可以根据需要添加额外的Pod。
例如,让我们在集群中添加另一个Flask Pod。
确认。
向服务发出几个请求。
你应该看到不同的container_id
,表明请求正在通过两个副本之间的轮回算法进行适当的路由。
如果你在流量冲击集群的时候缩小规模,会发生什么?打开两个终端窗口,在你的电脑上测试一下。你应该看到流量被适当地重新分配了。再试一次,但这次要扩大规模。
有用的命令
命令 | 解释 |
---|---|
minikube start | 启动一个本地Kubernetes集群 |
minikube ip | 显示集群的IP地址 |
minikube dashboard | 在浏览器中打开Kubernetes仪表板 |
kubectl version | 显示Kubectl的版本 |
kubectl cluster-info | 显示集群的信息 |
kubectl get nodes | 列表中的节点 |
kubectl get pods | 列表中的Pod |
kubectl get deployments | 列出部署情况 |
kubectl get services | 列出服务 |
minikube stop | 停止一个本地Kubernetes集群 |
minikube delete | 移除本地Kubernetes集群 |
查看Kubernetes Cheatsheet了解更多命令。
自动化脚本
准备好把所有东西放在一起了吗?
看看项目根中的deploy.sh脚本。这个脚本。
- 创建一个PersistentVolume和一个PersistentVolumeClaim
- 通过Kubernetes Secrets添加数据库凭证
- 创建Postgres部署和服务
- 创建Flask部署和服务
- 启用Ingress
- 应用Ingress规则
- 创建Vue部署和服务
试试吧!
一旦完成,创建books
数据库,应用迁移,并为数据库播种。
更新*/etc/hosts*,然后在浏览器中进行测试。
总结
在本教程中,我们研究了如何在Kubernetes上运行一个基于Flask的微服务。
至此,你应该对Kubernetes的工作原理有了基本的了解,并且能够部署一个集群,在上面运行一个应用。
其他资源。
- 学习Kubernetes基础知识
- 配置最佳实践
- 使用Kubernetes扩展Flask
- 在Docker Swarm上运行Flask(对比在Docker Swarm和Kubernetes上运行Flask)。
- 用Kubernetes将Node应用部署到谷歌云上
你可以在GitHub上的flask-vue-kubernetesrepo中找到这些代码。