原创 吴就业 177 0 2023-07-22
本文为博主原创文章,未经博主允许不得转载。
本文链接:https://wujiuye.com/article/21bb03edef084e37ac801bb4646da783
作者:吴就业
链接:https://wujiuye.com/article/21bb03edef084e37ac801bb4646da783
来源:吴就业的网络日记
本文为博主原创文章,未经博主允许不得转载。
带你体验什么叫“yaml工程师”
“部署即代码”即用代码描述一个应用的部署计划。KubeVela就是实现这一目标的平台,让我们可以编写一个符合OAM模型的yaml来描述应用的部署。这些概念我们先不急着理解。
现实场景中,我们部署一个应用可能会涉及到申请基础设施,然后要知道部署到哪个集群上(环境),以及需要先部署某些需要依赖的中间件。
例如部署一个简单的web服务,我们需要依赖redis中间件。假设现在我们用kubeVela来部署这样一个应用,我们需要用OAM模型来描述它,编写一个application.yaml文件。
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: oam-app
spec:
components:
workflow:
OAM模型将基础设施、中间件、微服务等抽象成组件,一个应用由一到多个组件组成,而工作流则负责编排组件的部署。默认情况下,即便我们不声明工作流步骤,kubeVela也会提供默认的工作流步骤来部署组件。
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: web-demo-app
spec:
components:
- name: web-demo-service
type: webservice
properties:
image: xxx.xxx.xx/web-demo-service:1.0
ports:
- port: 8080
expose: true
redis:
endpoints:
- {}
workflow:
- type: apply-component
name: deploy-web-demo-service
properties:
component: web-demo-service
这段代码描述了web-demo-app这个应用由一个组件组成,并且声明了一个工作流步骤来部署这个组件:
properties.image
指定使用xxx.xxx.xx/web-demo-service:1.0
镜像,properties.ports
指定暴露8080端口。properties.component
指定该工作流步骤用于部署哪个组件。假设部署redis我们使用kubevela提供redis-operator addon插件封装的redis-failover组件,实际部署应用的话需要先安装这个addon插件。
现在我们需要给app添加一个redis-failover组件,并且拿到redis组件部署后输出的Endpoints(访问redis集群的ip和端口)传递给web服务(web-demo-service)。
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: web-demo-app
spec:
components:
- name: web-demo-service
type: webservice
properties:
image: xxx.xxx.xx/web-demo-service:1.0
ports:
- port: 8080
expose: true
redis:
endpoints:
- {} # 待部署后生成
- name: sample-redis
type: redis-failover
properties:
replicas: 1
workflow:
- type: apply-component
name: deploy-sample-redis
properties:
component: sample-redis
- name: read-redis-output
type: read-object
dependsOn:
- deploy-sample-redis
outputs:
- name: redisoutput
valueFrom: output.value.subsets
properties:
apiVersion: v1
kind: Endpoints
name: rfs-sample-redis
- type: apply-component
name: deploy-web-demo-service
properties:
component: web-demo-service
dependsOn:
- read-redis-output
inputs:
- from: redisoutput
parameterKey: values.redis.endpoints
我们给描述文件添加了sample-redis组件,然后增加了deploy-sample-redis和read-redis-output这两个工作流步骤,而deploy-web-demo-service工作流步骤也有所修改。
现在我们来理解一下这三个工作流步骤:
kubevela通常以独立的k8s集群部署,而预发、线上环境都是独立的k8s集群,现在假设我们需要让kubevela将应用部署到线上环境的k8s集群,线上k8s集群名为”prod-cluster”。
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: web-demo-app
spec:
components:
- name: web-demo-service
type: webservice
properties:
image: xxx.xxx.xx/web-demo-service:1.0
ports:
- port: 8080
expose: true
redis:
endpoints:
- {} # 待部署后生成
- name: sample-redis
type: redis-failover
properties:
replicas: 1
workflow:
- type: apply-component
name: deploy-sample-redis
properties:
component: sample-redis
cluster: prod-cluster
- name: read-redis-output
type: read-object
dependsOn:
- deploy-sample-redis
outputs:
- name: redisoutput
valueFrom: output.value.subsets
properties:
apiVersion: v1
kind: Endpoints
name: rfs-sample-redis
cluster: prod-cluster
- type: apply-component
name: deploy-web-demo-service
properties:
component: web-demo-service
cluster: prod-cluster
dependsOn:
- read-redis-output
inputs:
- from: redisoutput
parameterKey: values.redis.endpoints
当然,除了在工作流步骤中指定工作流的依赖关系实现组件按依赖顺序部署,还可以直接在组件中声明这种关系,而参数的传递也同样可以在组件中声明。
除了指定部署到prod-cluster集群外,相同的目标,描述文件可以改成:
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: web-demo-app
spec:
components:
- name: web-demo-service
type: webservice
dependsOn:
- sample-redis
properties:
image: xxx.xxx.xx/web-demo-service:1.0
ports:
- port: 8080
expose: true
redis:
endpoints:
- {} # 待部署后生成
inputs:
- from: redisoutput
parameterKey: properties.values.redis.endpoints
- name: sample-redis
type: redis-failover
properties:
replicas: 1
output:
- name: redisoutput
valueFrom: |
import "vela/op"
#Endpoints: op.#Read & {
value: {
kind: "Endpoints"
apiVersion: "v1"
metadata: {
name: "rfs-sample-redis"
namespace: "default"
}
}
}
#Endpoints.value.subsets
workflow:
- type: deploy
name: deploy-to-prod-cluster
由于没有一个叫read-object的组件,所以这里用到了valueFrom支持的另一种写法:CUE表达式。通过CUE代码读取Endpoints资源,并将Endpoints资源的subsets输出。
现在我们通过OAM模型中的应用策略来指定部署集群。
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: web-demo-app
spec:
components:
- name: web-demo-service
type: webservice
dependsOn:
- sample-redis
properties:
image: xxx.xxx.xx/web-demo-service:1.0
ports:
- port: 8080
expose: true
redis:
endpoints:
- {} # 待部署后生成
inputs:
- from: redisoutput
parameterKey: properties.values.redis.endpoints
- name: sample-redis
type: redis-failover
properties:
replicas: 1
output:
- name: redisoutput
valueFrom: |
import "vela/op"
#Endpoints: op.#Read & {
cluster: "prod-cluster",
value: {
kind: "Endpoints"
apiVersion: "v1"
metadata: {
name: "rfs-sample-redis"
namespace: "default"
}
}
}
#Endpoints.value.subsets
policies:
- name: prod-topology
type: topology
properties:
clusters: ["prod-cluster"]
workflow:
- type: deploy
name: deploy-to-prod-cluster
properties:
policies: ["prod-topology"]
我们描述了类型为topology的应用策略“prod-topology”,topology策略是kubevela内置的策略,描述组件部署到哪些k8s集群,这里指定为只部署到“prod-cluster”集群。然后还需要将该策略配置给deploy-to-prod-cluster工作流步骤。
OAM模型中,组件可以有运维特征,我们给组件配置水平自动扩缩容需要用到运维特征,给组件注入环境变量也可以用到运维特征。
现在,为了验证我们部署的web-demo-service服务能够正常访问,需要用到kubevela内置的expose特征,以NodePort类型暴露8080端口给k8s集群外部访问。
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: web-demo-app
spec:
components:
- name: web-demo-service
type: webservice
dependsOn:
- sample-redis
properties:
image: xxx.xxx.xx/web-demo-service:1.0
ports:
- port: 8080
expose: true
redis:
endpoints:
- {} # 待部署后生成
inputs:
- from: redisoutput
parameterKey: properties.values.redis.endpoints
traits:
- type: expose
properties:
port: [8080]
type: NodePort
- name: sample-redis
type: redis-failover
properties:
replicas: 1
output:
- name: redisoutput
valueFrom: |
import "vela/op"
#Endpoints: op.#Read & {
value: {
kind: "Endpoints"
apiVersion: "v1"
metadata: {
name: "rfs-sample-redis"
namespace: "default"
}
}
}
#Endpoints.value.subsets
policies:
- name: prod-topology
type: topology
properties:
clusters: ["prod-cluster"]
workflow:
- type: deploy
name: deploy-to-prod-cluster
properties:
policies: ["prod-topology"]
此web服务举例还不完整,还缺少申请基础设施的部分:要暴露给浏览器访问,首先还得要有个域名,然后还涉及到ALB(应用层负载均衡)等,因为过于复杂,特别是ALB,不好理解,所以案例把基础设施部分砍掉了。不过通过后面小节内容的学习,我们也能了解到如何通过OAM来描述申请基础设施。
另外,在此web案例中,我们将Redis作为中间件部署,实际上,我们也可以将Redis作为基础设施申请,例如使用阿里云的Redis服务,阿里云的Terraform Provider提供了Redis资源。
参考文献:
声明:公众号、CSDN、掘金的曾用名:“Java艺术”,因此您可能看到一些早期的文章的图片有“Java艺术”的水印。
KubeVela是面向混合云环境的应用交付控制面,不与任何云产商绑定。KubeVela通过提供插件扩展机制,打通了应用交付涉及的基础设施即代码-terraform等能力。编写一个符合OAM模型的application.yaml就能实现将应用部署起来,包括申请基础设施。实现了声明式部署,且一次编写,到处部署。
Go sdk本地开发调试sdk依赖问题;关于复杂嵌套结构体的schema声明;状态死循环监听,以及terraform命令终止时如何终止死循环;资源创建接口的默认可选字段不填遇到的坑;HCL代码输入变量的复杂校验。
很多企业内部为了不与云厂商绑定,避免上云容易下云难的尴尬,以及企业内部可能也会做私有云,或者封装一个混合云平台,因此不能直接用云厂商提供的provider。
通常申请基础设施,我们需要向运维描述我们需要什么基础设施、什么规格,运维根据我们的描述去检查是否已经申请过这样的资源,有就会直接给我们使用基础设施的信息,没有再帮我们申请,然后告诉我们使用基础设施的信息,例如mysql的jdbc和用户名、密码。如果将描述代码化,基础设施的申请自动化,就能实现“基础设施即代码”。而terraform就是实现“将描述代码化”的工具软件。
订阅
订阅新文章发布通知吧,不错过精彩内容!
输入邮箱,提交后我们会给您发送一封邮件,您需点击邮件中的链接完成订阅设置。