以 FastGPT 为例,代码如何创建模板。本示例假设您已经对 Kubernetes 资源文件有一定的了解,并且仅解释一些模板特有的参数。模板文件主要分为两个部分。
apiVersion: app.sealos.io/v1
kind: Template
metadata:
name: ${{ defaults.app_name }}
spec:
title: 'FastGpt'
url: 'https://fastgpt.run/'
gitRepo: 'https://github.com/labring/FastGPT'
author: 'sealos'
description: 'Fast GPT allows you to use your own openai API KEY to quickly call the openai interface, currently integrating Gpt35, Gpt4 and embedding. You can build your own knowledge base.'
readme: 'https://raw.githubusercontent.com/labring/FastGPT/main/README.md'
icon: 'https://avatars.githubusercontent.com/u/50446880?s=96&v=4'
templateType: inline
defaults:
app_name:
type: string
value: fastgpt-${{ random(8) }}
app_host:
type: string
value: ${{ random(8) }}
inputs:
root_passowrd:
description: 'Set root password. login: username: root, password: root_passowrd'
type: string
default: ${{ SEALOS_NAMESPACE }}
required: true
openai_key:
description: 'openai api key'
type: string
default: ''
required: true
database_type:
description: 'type of database'
required: false
type: choice
default: 'mysql'
options:
- sqlite
- mysql
如代码所示,元数据 CR 是常规的 Kubernetes 自定义资源类型,下表列出了需要填写的字段。
代码 | 描述 |
---|---|
templateType |
inline 表示这是一个内联模板,所有 yaml 文件都集成在一个文件中。 |
defaults |
定义要填充到资源文件中的默认值,例如应用程序名称(app_name)、域名(app_host)等。 |
inputs |
定义部署应用程序时用户需要的一些参数,例如电子邮件、API-KEY 等。如果没有,则可以省略此项 |
任何被 ${{ }}
包围的字符都是变量,变量分为以下几种类型:
SEALOS_
全大写字母的预定义系统内置变量,例如${{ SEALOS_NAMESPACE }}
,是 Sealos 本身提供的变量。有关所有当前支持的系统变量,请参阅系统变量。functions()
函数,例如${{ random(8) }}
,是 Sealos 本身提供的函数。有关所有当前支持的函数,请参阅函数。defaults
是填充随机值时解析的名称和值列表。inputs
是在部署应用程序时由用户填写的,输入将呈现为前端表单。
spec.defaults
是在解析模板时填充为默认值的名称、类型和值的映射。
名称 | 描述 |
---|---|
type |
string 或 number 表示变量的类型,唯一的区别是在渲染时字符串类型将被引用,而数字类型不会。 |
value |
变量的值,如果值是函数,则将被渲染。 |
在目前的版本实现中, defaults
必须要有一个 app_name
的字段,且其中需要包含 ${{ random(8) }}
的随机数来作为应用的唯一名字,否则会报错.
spec.defaults
是一个定义的对象映射,被解析并显示为用户反应的表单输入。
名称 | 描述 |
---|---|
description |
输入的描述。将呈现为输入占位符。 |
default |
输入的默认值。 |
required |
输入是否必需。 |
type |
必须是 string | number | choice | boolean 中的一个 |
options ? |
当类型为 choice 时,设置可用选项列表。 |
如上所示的输入将在前端呈现为表单输入:
模板 | 视图 |
inputs:
root_passowrd:
description: 'Set root password. login: username: root, password: root_passowrd'
type: string
default: ''
required: true
openai_key:
description: 'openai api key'
type: string
default: ''
required: true |
${{ SEALOS_NAMESPACE }}
Sealos 用户部署的命名空间。${{ SEALOS_CLOUD_DOMAIN }}
Sealos 集群的域名后缀。${{ SEALOS_CERT_SECRET_NAME }}
Sealos 用于存储 TLS 证书的 secret 名称。
${{ random(length) }}
生成长度为length
的随机字符串。- TODO:
${{ if() }}
${{ endif() }}
条件渲染。
此部分通常由一组资源类型组成:
- 应用程序
Deployment
、StatefulSet
、Service
- 外部访问
Ingress
- 底层依赖
Database
、Object Storage
每个资源可以重复任意次数,没有顺序。
应用程序是一个由多个 Deployment
、StatefulSet
、Service
或/和 Job
、Secret
、ConfigMap
、Custom Resource
组成的列表。
代码
apiVersion: apps/v1
kind: Deployment
metadata:
name: ${{ defaults.app_name }}
annotations:
originImageName: c121914yu/fast-gpt:latest
deploy.cloud.sealos.io/minReplicas: '1'
deploy.cloud.sealos.io/maxReplicas: '1'
labels:
cloud.sealos.io/app-deploy-manager: ${{ defaults.app_name }}
app: ${{ defaults.app_name }}
spec:
replicas: 1
revisionHistoryLimit: 1
selector:
matchLabels:
app: ${{ defaults.app_name }}
template:
metadata:
labels:
app: ${{ defaults.app_name }}
spec:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ${{ defaults.app_name }}
annotations:
originImageName: c121914yu/fast-gpt:latest
deploy.cloud.sealos.io/minReplicas: '1'
deploy.cloud.sealos.io/maxReplicas: '1'
labels:
cloud.sealos.io/app-deploy-manager: ${{ defaults.app_name }}
app: ${{ defaults.app_name }}
spec:
replicas: 1
revisionHistoryLimit: 1
selector:
matchLabels:
app: ${{ defaults.app_name }}
template:
metadata:
labels:
app: ${{ defaults.app_name }}
spec:
containers:
- name: ${{ defaults.app_name }}
image: c121914yu/fast-gpt:latest
env:
- name: MONGO_PASSWORD
valueFrom:
secretKeyRef:
name: ${{ defaults.app_name }}-mongo-conn-credential
key: password
- name: PG_PASSWORD
valueFrom:
secretKeyRef:
name: ${{ defaults.app_name }}-pg-conn-credential
key: password
- name: ONEAPI_URL
value: ${{ defaults.app_name }}-key.${{ SEALOS_NAMESPACE }}.svc.cluster.local:3000/v1
- name: ONEAPI_KEY
value: sk-xxxxxx
- name: DB_MAX_LINK
value: 5
- name: MY_MAIL
value: ${{ inputs.mail }}
- name: MAILE_CODE
value: ${{ inputs.mail_code }}
- name: TOKEN_KEY
value: fastgpttokenkey
- name: ROOT_KEY
value: rootkey
- name: MONGODB_URI
value: >-
mongodb://root:$(MONGO_PASSWORD)@${{ defaults.app_name }}-mongo-mongo.${{ SEALOS_NAMESPACE }}.svc:27017
- name: MONGODB_NAME
value: fastgpt
- name: PG_HOST
value: ${{ defaults.app_name }}-pg-pg.${{ SEALOS_NAMESPACE }}.svc
- name: PG_USER
value: postgres
- name: PG_PORT
value: '5432'
- name: PG_DB_NAME
value: postgres
resources:
requests:
cpu: 100m
memory: 102Mi
limits:
cpu: 1000m
memory: 1024Mi
command: []
args: []
ports:
- containerPort: 3000
imagePullPolicy: Always
volumeMounts: []
volumes: []
---
apiVersion: v1
kind: Service
metadata:
name: ${{ defaults.app_name }}
labels:
cloud.sealos.io/app-deploy-manager: ${{ defaults.app_name }}
spec:
ports:
- port: 3000
selector:
app: ${{ defaults.app_name }}
经常更改的是以下字段:
代码 | 描述 |
---|---|
metadata.annotations metadata.labels |
更改以匹配 Launchpad 的要求,例如 originImageName 、minReplicas 、maxReplicas 。 |
spec.containers[].image |
更改为您的 Docker 镜像。 |
spec.containers[].env |
为容器配置环境变量。 |
spec.containers[].ports.containerPort |
更改为与您的 Docker 镜像对应的端口。 |
${{ defaults.app_name }} |
您可以使用 ${{ defaults.xxxx }} |${{ inputs.xxxx }} 变量来设置在 Template CR 中定义的参数。 |
如果应用程序需要从外部访问,则需要添加以下代码:
代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ${{ defaults.app_name }}
labels:
cloud.sealos.io/app-deploy-manager: ${{ defaults.app_name }}
cloud.sealos.io/app-deploy-manager-domain: ${{ defaults.app_host }}
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/proxy-body-size: 32m
nginx.ingress.kubernetes.io/server-snippet: |
client_header_buffer_size 64k;
large_client_header_buffers 4 128k;
nginx.ingress.kubernetes.io/ssl-redirect: 'false'
nginx.ingress.kubernetes.io/backend-protocol: HTTP
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/client-body-buffer-size: 64k
nginx.ingress.kubernetes.io/proxy-buffer-size: 64k
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($request_uri ~* \.(js|css|gif|jpe?g|png)) {
expires 30d;
add_header Cache-Control "public";
}
spec:
rules:
- host: ${{ defaults.app_host }}.${{ SEALOS_CLOUD_DOMAIN }}
http:
paths:
- pathType: Prefix
path: /()(.*)
backend:
service:
name: ${{ defaults.app_name }}
port:
number: 3000
tls:
- hosts:
- ${{ defaults.app_host }}.${{ SEALOS_CLOUD_DOMAIN }}
secretName: ${{ SEALOS_CERT_SECRET_NAME }}
请注意,出于安全目的,host
字段需要随机设置。您可以将 ${{ random(8) }}
设置为 defaults.app_host
,然后使用 ${{ defaults.app_host }}
。
几乎所有应用程序都需要底层依赖,例如 database
、cache
、object storage
等。您可以添加以下代码来部署我们提供的一些底层依赖:
我们使用 kubeblocks
提供数据库资源支持。您可以直接使用以下代码来部署数据库:
MongoDB
apiVersion: apps.kubeblocks.io/v1alpha1
kind: Cluster
metadata:
finalizers:
- cluster.kubeblocks.io/finalizer
labels:
clusterdefinition.kubeblocks.io/name: mongodb
clusterversion.kubeblocks.io/name: mongodb-5.0
sealos-db-provider-cr: ${{ defaults.app_name }}-mongo
annotations: {}
name: ${{ defaults.app_name }}-mongo
generation: 1
spec:
affinity:
nodeLabels: {}
podAntiAffinity: Preferred
tenancy: SharedNode
topologyKeys: []
clusterDefinitionRef: mongodb
clusterVersionRef: mongodb-5.0
componentSpecs:
- componentDefRef: mongodb
monitor: true
name: mongodb
replicas: 1
resources:
limits:
cpu: 1000m
memory: 1024Mi
requests:
cpu: 100m
memory: 102Mi
serviceAccountName: ${{ defaults.app_name }}-mongo
volumeClaimTemplates:
- name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
storageClassName: openebs-backup
terminationPolicy: Delete
tolerations: []
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
sealos-db-provider-cr: ${{ defaults.app_name }}-mongo
app.kubernetes.io/instance: ${{ defaults.app_name }}-mongo
app.kubernetes.io/managed-by: kbcli
name: ${{ defaults.app_name }}-mongo
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
sealos-db-provider-cr: ${{ defaults.app_name }}-mongo
app.kubernetes.io/instance: ${{ defaults.app_name }}-mongo
app.kubernetes.io/managed-by: kbcli
name: ${{ defaults.app_name }}-mongo
rules:
- apiGroups:
- ''
resources:
- events
verbs:
- create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
sealos-db-provider-cr: ${{ defaults.app_name }}-mongo
app.kubernetes.io/instance: ${{ defaults.app_name }}-mongo
app.kubernetes.io/managed-by: kbcli
name: ${{ defaults.app_name }}-mongo
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ${{ defaults.app_name }}-mongo
subjects:
- kind: ServiceAccount
name: ${{ defaults.app_name }}-mongo
namespace: ${{ SEALOS_NAMESPACE}}
PostgreSQL
apiVersion: apps.kubeblocks.io/v1alpha1
kind: Cluster
metadata:
finalizers:
- cluster.kubeblocks.io/finalizer
labels:
clusterdefinition.kubeblocks.io/name: postgresql
clusterversion.kubeblocks.io/name: postgresql-14.8.0
sealos-db-provider-cr: ${{ defaults.app_name }}-pg
annotations: {}
name: ${{ defaults.app_name }}-pg
spec:
affinity:
nodeLabels: {}
podAntiAffinity: Preferred
tenancy: SharedNode
topologyKeys: []
clusterDefinitionRef: postgresql
clusterVersionRef: postgresql-14.8.0
componentSpecs:
- componentDefRef: postgresql
monitor: true
name: postgresql
replicas: 1
resources:
limits:
cpu: 1000m
memory: 1024Mi
requests:
cpu: 100m
memory: 102Mi
serviceAccountName: ${{ defaults.app_name }}-pg
switchPolicy:
type: Noop
volumeClaimTemplates:
- name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: openebs-backup
terminationPolicy: Delete
tolerations: []
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
sealos-db-provider-cr: ${{ defaults.app_name }}-pg
app.kubernetes.io/instance: ${{ defaults.app_name }}-pg
app.kubernetes.io/managed-by: kbcli
name: ${{ defaults.app_name }}-pg
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
sealos-db-provider-cr: ${{ defaults.app_name }}-pg
app.kubernetes.io/instance: ${{ defaults.app_name }}-pg
app.kubernetes.io/managed-by: kbcli
name: ${{ defaults.app_name }}-pg
rules:
- apiGroups:
- ''
resources:
- events
verbs:
- create
- apiGroups:
- ''
resources:
- configmaps
verbs:
- create
- get
- list
- patch
- update
- watch
- delete
- apiGroups:
- ''
resources:
- endpoints
verbs:
- create
- get
- list
- patch
- update
- watch
- delete
- apiGroups:
- ''
resources:
- pods
verbs:
- get
- list
- patch
- update
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
sealos-db-provider-cr: ${{ defaults.app_name }}-pg
app.kubernetes.io/instance: ${{ defaults.app_name }}-pg
app.kubernetes.io/managed-by: kbcli
name: ${{ defaults.app_name }}-pg
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ${{ defaults.app_name }}-pg
subjects:
- kind: ServiceAccount
name: ${{ defaults.app_name }}-pg
namespace: ${{ SEALOS_NAMESPACE }}
MySQL
apiVersion: apps.kubeblocks.io/v1alpha1
kind: Cluster
metadata:
finalizers:
- cluster.kubeblocks.io/finalizer
labels:
clusterdefinition.kubeblocks.io/name: apecloud-mysql
clusterversion.kubeblocks.io/name: ac-mysql-8.0.30
sealos-db-provider-cr: ${{ defaults.app_name }}-mysql
annotations: {}
name: ${{ defaults.app_name }}-mysql
spec:
affinity:
nodeLabels: {}
podAntiAffinity: Preferred
tenancy: SharedNode
topologyKeys: []
clusterDefinitionRef: apecloud-mysql
clusterVersionRef: ac-mysql-8.0.30
componentSpecs:
- componentDefRef: mysql
monitor: true
name: mysql
replicas: 1
resources:
limits:
cpu: 1000m
memory: 1024Mi
requests:
cpu: 100m
memory: 102Mi
serviceAccountName: ${{ defaults.app_name }}-mysql
volumeClaimTemplates:
- name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
storageClassName: openebs-backup
terminationPolicy: Delete
tolerations: []
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
sealos-db-provider-cr: ${{ defaults.app_name }}-mysql
app.kubernetes.io/instance: ${{ defaults.app_name }}-mysql
app.kubernetes.io/managed-by: kbcli
name: ${{ defaults.app_name }}-mysql
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
sealos-db-provider-cr: ${{ defaults.app_name }}-mysql
app.kubernetes.io/instance: ${{ defaults.app_name }}-mysql
app.kubernetes.io/managed-by: kbcli
name: ${{ defaults.app_name }}-mysql
rules:
- apiGroups:
- ''
resources:
- events
verbs:
- create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
sealos-db-provider-cr: ${{ defaults.app_name }}-mysql
app.kubernetes.io/instance: ${{ defaults.app_name }}-mysql
app.kubernetes.io/managed-by: kbcli
name: ${{ defaults.app_name }}-mysql
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ${{ defaults.app_name }}-mysql
subjects:
- kind: ServiceAccount
name: ${{ defaults.app_name }}-mysql
namespace: ${{ SEALOS_NAMESPACE }}
Redis
apiVersion: apps.kubeblocks.io/v1alpha1
kind: Cluster
metadata:
finalizers:
- cluster.kubeblocks.io/finalizer
labels:
clusterdefinition.kubeblocks.io/name: redis
clusterversion.kubeblocks.io/name: redis-7.0.6
sealos-db-provider-cr: ${{ defaults.app_name }}-redis
annotations: {}
name: ${{ defaults.app_name }}-redis
spec:
affinity:
nodeLabels: {}
podAntiAffinity: Preferred
tenancy: SharedNode
topologyKeys: []
clusterDefinitionRef: redis
clusterVersionRef: redis-7.0.6
componentSpecs:
- componentDefRef: redis
monitor: true
name: redis
replicas: 1
resources:
limits:
cpu: 1000m
memory: 1024Mi
requests:
cpu: 100m
memory: 102Mi
serviceAccountName: ${{ defaults.app_name }}-redis
switchPolicy:
type: Noop
volumeClaimTemplates:
- name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
storageClassName: openebs-backup
- componentDefRef: redis-sentinel
monitor: true
name: redis-sentinel
replicas: 1
resources:
limits:
cpu: 100m
memory: 100Mi
requests:
cpu: 100m
memory: 100Mi
serviceAccountName: ${{ defaults.app_name }}-redis
terminationPolicy: Delete
tolerations: []
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
sealos-db-provider-cr: ${{ defaults.app_name }}-redis
app.kubernetes.io/instance: ${{ defaults.app_name }}-redis
app.kubernetes.io/managed-by: kbcli
name: ${{ defaults.app_name }}-redis
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
sealos-db-provider-cr: ${{ defaults.app_name }}-redis
app.kubernetes.io/instance: ${{ defaults.app_name }}-redis
app.kubernetes.io/managed-by: kbcli
name: ${{ defaults.app_name }}-redis
rules:
- apiGroups:
- ''
resources:
- events
verbs:
- create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
sealos-db-provider-cr: ${{ defaults.app_name }}-redis
app.kubernetes.io/instance: ${{ defaults.app_name }}-redis
app.kubernetes.io/managed-by: kbcli
name: ${{ defaults.app_name }}-redis
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ${{ defaults.app_name }}-redis
subjects:
- kind: ServiceAccount
name: ${{ defaults.app_name }}-redis
namespace: ${{ SEALOS_NAMESPACE }}
当部署数据库时,您只需要关注数据库使用的资源:
代码 | 描述 |
---|---|
replicas |
实例数量 |
resources |
分配 CPU 和内存 |
storage |
卷大小 |
数据库的用户名/密码设置为一个 secret,以供将来使用。可以通过以下代码将其添加到环境变量中。添加后,您可以通过 $(MONGO_PASSWORD) 在容器中读取 MONGODB 密码。
...
spec:
containers:
- name: ${{ defaults.app_name }}
...
env:
- name: MONGO_PASSWORD
valueFrom:
secretKeyRef:
name: ${{ defaults.app_name }}-mongo-conn-credential
key: password
...
为了方便用户管理和变更通过模板部署的应用,系统会在实际部署的时候部署一个app.sealos.io/v1, Kind=Instance
的 CRD作为应用的实例.
CRD本身会完全按照 app.sealos.io/v1, Kind=Template
的模板格式与字段进行迁移,其中处理逻辑为:
- 把 template 当中的所有变量/函数全部替换为一个确定的值
- 将 kind 从
Template
改为Instance
- Apply 这个模板的实例到用户的 ns
对于所有的通过模板市场部署的资源,包括系统资源比如 deploy
, service
以及自定义资源比如 app
, kb数据库
等,都会全部统一增加一个标签: cloud.sealos.io/deploy-on-sealos: $app_name
.
其中 app_name
为用户部署的应用的名称, 默认是以一个随机数作为结尾,比如 fastgpt-zu1n048s
.