在本文中,我们将使用示例微服务应用程序VotingApp来说明可在Kubernetes集群中部署应用程序的几种方式:
- 使用Yaml规范
- 通过Helm chart
- 使用Kustomize
VotingApp
VotingApp是由Docker创建的应用程序,它主要是用来说明docker和Kubernetes的功能。该应用程序遵循微服务架构,由五个服务组成,如下图所示。
VotingApp的整体架构
该应用程序通常用于演示和演示,这是一个很好的示例,因为它使用了多种语言和数据库技术:
- vote:使用Python开发的前端,允许用户在猫和狗之间进行选择
- redis:存储投票的数据库
- worker:从Redis获得投票并将结果存储在Postgres数据库中的服务。该服务存在Java和.NET两个版本
- db:Postgres数据库,worker在该数据库中合并票数
- result:Node.js开发的前端,用于显示结果
原始应用程序托管在GitHub中,本文所用到的,使用3种不同的方式定义该应用程序 的配置在公众号云原生的github代码库里:
- 使用Yaml规范
- 通过helm chart
- 通过kustomize结构
在下文中,我们将使用这三种方式来部署VotingApp,并说明它们之间的区别。
设置演示集群
首先,我们将在本地计算机上快速设置一个Kubernetes集群。在本地运行Kubernetes真的很容易,因为那里有许多可用的解决方案。仅举几个:
- k0s
- k3s
- microK8s
- miniKube
- kind
在本文中,我们使用最新版本的k0s(2021年4月为0.12),并使用vagrant和VirtualBox进行安装。
首先,我们创建一个新文件夹,并Vagrantfile在其中添加以下内容。
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/bionic64"
config.vm.network "private_network", ip: "192.168.33.11"
config.vm.provision "shell", inline: <<-SHELL
curl -sSLf https://get.k0s.sh | sudo sh
sudo k0s install controller --single
sudo systemctl start k0scontroller.service
SHELL
end
接下来,在该文件夹中,运行以下命令,以创建一个VM并在其中安装k0s:
$ vagrant up
接下来,我们在这个新创建的VM中运行一个root shell:
$ vagrant ssh
vagrant @ vagrant:?$ sudo su-
root @ vagrant:?#
使用k0s附带的客户端kubectl,我们可以使用以下命令查看我们的单节点集群(节点进入“Ready ”状态大约需要一分钟):
# k0s kubectl get nodes
NAME STATUS ROLES AGE VERSION
vagrant Ready 40s v1.20.5-k0s1
然后,在公众号云原生的github代码库里找到配置文件,在20210403目录下
下一步,我们将使用原始Yaml规范部署VotingApp。
Yaml规格
该清单文件夹中包含了每个微服务的yaml:
# tree manifests/
manifests/
├── db-deployment.yaml
├── db-service.yaml
├── redis-deployment.yaml
├── redis-service.yaml
├── result-deployment.yaml
├── result-service.yaml
├── vote-deployment.yaml
├── vote-service.yaml
└── worker-deployment.yaml
- vote,result,redis和db都有一个Deployment和Service资源
- worker仅具有一种Deployment资源,因为它不需要公开:worker是一种连接redis和db的启动服务
以下命令使用yaml所有创建应用程序:
#k0s kubectl apply -f manifests/
注意:该命令kubectl apply -f会作用于该文件夹的所有yaml
同样我们需要确保一切正常:
# k0s kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/worker 1/1 1 1 102s
deployment.apps/db 1/1 1 1 103s
deployment.apps/result 1/1 1 1 102s
deployment.apps/vote 1/1 1 1 102s
deployment.apps/redis 1/1 1 1 102s
然后,我们可以使用VM的IP以及在vote-service.yaml和result-service.yaml中指定的nodePort来访问Web界面:vote可在端口31001,端口31001result上访问。我们可以对项目进行投票并查看结果,确认整个应用程序运行良好。
使用原始 manifests部署VotingApp
然后可以使用以下命令删除该应用程序:
# k0s kubectl delete -f manifests
使用yaml清单直接部署应用程序很简单,但是它不提供方便的功能来完全管理应用程序的生命周期或动态配置应用程序(Helm真正发挥作用的领域)。
Helm
通过Helm,我们可以管理(定义,安装,升级)复杂的Kubernetes应用程序。通过Chart的概念,该工具可以轻松地创建,版本控制,共享和发布整个应用程序,Chart是一个包含整个应用程序规范的软件包。Helm还提供了一种模板语言来动态配置应用程序。
在配置库中,helm文件夹包含VotingApp的最简单图表。
# tree helm
helm
├── Chart.yaml
├── templates
│ ├── db-deployment.yaml
│ ├── db-service.yaml
│ ├── _helpers.tpl
│ ├── redis-deployment.yaml
│ ├── redis-service.yaml
│ ├── result-deployment.yaml
│ ├── result-service.yaml
│ ├── vote-deployment.yaml
│ ├── vote-service.yaml
│ └── worker-deployment.yaml
└── values.yaml
该模板文件夹中包含相当多,我们在上一步中使用(当我们部署了从应用程序的同一规格清单文件夹),除了几件事情:
- vote和result服务使用heml模板语言来定义nodePort而不是使用文本值。每个值都是对values.yaml中定义的值的引用(稍后会对此进行详细介绍):
# cat templates/vote-service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: vote
name: vote
spec:
type: NodePort
ports:
- name: "vote-service"
port: 5000
targetPort: 80
nodePort: {{ .Values.vote.port }}
selector:
app: vote
# cat templates/result-service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: result
name: result
spec:
type: NodePort
ports:
- name: "result-service"
port: 5001
targetPort: 80
nodePort: {{ .Values.result.port }}
selector:
app: result
- heml模板还用于worker指定用于此特定服务的图像(版本Java和.NET版本均可用):
# cat templates/worker-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: worker
name: worker
spec:
replicas: 1
selector:
matchLabels:
app: worker
template:
metadata:
labels:
app: worker
spec:
containers:
- image: {{ .Values.worker.image }}
name: worker
- 在以上模板中引用的值在values.yaml中定义:
# cat values.yaml
vote:
port: 31002
result:
port: 31003
worker:
image: lucj/voting:worker.java
现在让我们使用Helm部署VotingApp。
首先,我们需要helm按照以下说明安装二进制文件
接下来,我们voting在helm文件夹中运行以下命令来创建发行版的第一个修订版:
# helm upgrade voting --install --values values.yaml .
我们得到的结果类似于以下内容:
Release "voting" does not exist. Installing it now.
NAME: voting
LAST DEPLOYED: Wed Mar 31 21:02:07 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
在后台,helm读取templates文件夹中的规范,使用来自values.yaml的值创建真实的Yaml清单(Kubernetes可以执行),并要求API服务器创建相应的资源。
创建发行版的第一个修订版后,我们确保所有Pod都处于“运行”状态,以确保一切运行良好:
# k0s kubectl get deploy,pod
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/worker 1/1 1 1 24s
deployment.apps/vote 1/1 1 1 24s
deployment.apps/db 1/1 1 1 24s
deployment.apps/redis 1/1 1 1 24s
deployment.apps/result 1/1 1 1 24s
NAME READY STATUS RESTARTS AGE
pod/db-684b9b49fd-t7k74 1/1 Running 0 23s
pod/vote-767f6d6d79-5qlhd 1/1 Running 0 23s
pod/worker-79bb99bfc6-jhn5r 1/1 Running 0 23s
pod/redis-67db9bd79b-99vs2 1/1 Running 0 23s
pod/result-8cfbc4889-c4z8c 1/1 Running 0 23s
然后,我们可以使用VM的IP和values.yaml中指定的nodePort(用于的31002,用于的31003 )访问voteandresult接口vote``result
使用Helm部署VotingApp
默认情况下worker使用java版本,我们可以通过查看worker规范来验证这一点:
# k0s kubectl get deploy/worker \
-o jsonpath="{ .spec.template.spec.containers[0].image }"
lucj/voting:worker.java
如果我们想尝试一下dotnet版本,我们只需要升级发行版以提供我们想要更改的值,此操作将创建一个新的修订版:
# helm upgrade voting --set worker.image=lucj/voting:worker.dotnet .
然后,我们确保已正确更新部署,并且现在使用dotnet映像的版本:
# k0s kubectl get deploy/worker \
-o jsonpath="{ .spec.template.spec.containers[0].image }"
lucj/voting:worker.dotnet
通过访问vote和resultWeb界面,我们可以轻松地验证此新修订版本是否按预期工作。
如果我们想回到以前的版本,Helm也可以通过rollback使用以前的值创建该发行版的新修订的命令来提供帮助:
# helm rollback voting
Rollback was a success! Happy Helming!
再一次,我们可以验证worker的java镜像已经被使用,并且该应用程序可以正常工作。
然后,我们可以删除该应用程序:
# helm uninstall voting
我们仅通过一个简单的示例对Helm进行了说明,并使用了模板语言定义了几个属性,但是Helm确实具有更多功能,如您在文档中所看到的。在下一步中,我们将说明如何使用Kustomize部署应用程序。
Kustomize
Kustomize引入了一种无模板的方式来定制应用程序配置。它既可以作为独立二进制文件,也可以作为native功能使用kubectl。它基本上从yaml规范列表中定义了一个基准,并允许我们使用其他资源来重载该基准。让我们看看在VotingApp的上下文中这是如何工作的。
在配置库中,kustomize文件夹包含2个子文件夹:
# tree kustomize
kustomize/
├── base
│ ├── db-deployment.yaml
│ ├── db-service.yaml
│ ├── kustomization.yaml
│ ├── redis-deployment.yaml
│ ├── redis-service.yaml
│ ├── result-deployment.yaml
│ ├── result-service.yaml
│ ├── vote-deployment.yaml
│ ├── vote-service.yaml
│ └── worker-deployment.yaml
└── overlays
└── demo
├── front-services.yaml
├── kustomization.yaml
└── vote-ns.yaml
- 该base子文件夹包含我们部署原始heml应用时我们所使用的那些YAML规范。该文件夹还包含kustomization.yaml基本上列出了构成基线的规范的文件夹。
# cat base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- db-deployment.yaml
- db-service.yaml
- redis-deployment.yaml
- redis-service.yaml
- result-deployment.yaml
- result-service.yaml
- vote-deployment.yaml
- vote-service.yaml
- worker-deployment.yaml
以下命令使用标准来部署此基准,kubectl apply但使用的是-k标志:
#k0s kubectl apply -k base /
在这里,我们可以检查所有Pod是否运行良好并可以与VotingApp一起运行:为我们最喜欢的动物投票并查看结果。
然后,我们可以使用相同的-k标志删除该应用程序:
#k0s kubectl delete -k base /
- base文件夹旁边是overlays文件夹,其中包含一个demo子文件夹。最后一个包含几个文件,这些文件用于使base文件夹中现有的内容超载。基本上,从overlays/demo文件夹中部署应用程序就像使用来自基线的资源,对其进行修改,然后根据这些更改运行新版本的应用程序
该demo文件夹包含一个定义vote名称空间的规范,
# cat overlays/demo/vote-ns.yaml
apiVersion: v1
kind: Namespace
metadata:
name: vote
另一个规范front-services.yaml用于重载vote和result服务,以重新定义nodePort的值,
# cat overlays/demo/front-services.yaml
apiVersion: v1
kind: Service
metadata:
name: vote
spec:
ports:
- name: "vote-service"
port: 5000
targetPort: 80
nodePort: 31010
---
apiVersion: v1
kind: Service
metadata:
name: result
spec:
ports:
- name: "result-service"
port: 5001
targetPort: 80
nodePort: 31011
最后,该kustomization.yaml文件定义了从demo文件夹部署应用程序时要考虑的资源:使用了基本清单,将投票清单添加到此列表,应用了战略合并来修改端口号,并且整个应用程序是进入vote命名空间。
# cat overlays/demo/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- ../../base
resources:
- vote-ns.yaml
namespace: vote
patchesStrategicMerge:
- front-services.yaml
以下命令从overlays / demo部署VotingApp folder:
#k0s kubectl apply -k overlays / demo /
然后,我们可以访问VotingApp并再次投票选出我们最喜欢的动物。该vote接口在端口31010上可用,而在端口31011上则可用result。
通过Kustomize通过overlays/demo部署VotingApp
完成后,我们可以-k使用用于创建的相同标志删除应用程序。
#k0s kubectl delete -k base /
关键要点
在本文中,我们概述了可以在Kubernetes中部署应用程序的主要方式:
- 使用原始Yaml specifications是管理应用程序的最简单但配置更少的方法
- Heml是一种更可配置的方法。它使用模板语言,动态值,并简化了管理应用程序整个生命周期的过程。除了可以轻松分发Helm chart外,通过Helm chart还可以使用许多应用程序
- Kustomize是另一种方法,它允许通过基本文件夹定义同一应用程序的多个版本,而该基本文件夹可以通过使用其他资源来重载。Kustomize使通过多个覆盖子文件夹轻松管理应用程序的多个版本
文丨Soundhearer
图丨来源于网络