Taking FastGPT as an example here to demonstrate how to create a template. This example assumes that you already have a certain understanding of Kubernetes resource files, and will only explains some parameters unique to the template. The template file is mainly divided into two parts.
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://github.com/raw/labring/FastGPT/main/README.md'
icon: 'https://github.com/avatars/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
As demo shows, the metatda CR is a regular Kubernetes custom resource type, and the following table lists the fields that need to be filled in.
Code | Description |
---|---|
templateType |
inline indicates this is an inline mode template, all yaml files are integrated in one file. |
defaults |
Define default values to be filled into the resource file, such as application name (app_name), domain name (app_host), etc. |
inputs |
Define some parameters needed by the user when deploying the application, such as Email, API-KEY, etc. If none, this item can be omitted |
Any characters enclosed in ${{ }}
are variables, and the variables are divided into these types:
SEALOS_
pre-defined system built-in variables with upper case letters, such as${{ SEALOS_NAMESPACE }}
, are variables provided by Sealos itself. For all currently supported system variables, please refer to System Variables.functions()
functions, such as${{ random(8) }}
, are functions provided by Sealos itself. For all currently supported functions, please refer to Functions.defaults
is a list of names and values that are filled in by parsing, usually used for random values.inputs
filled in by the user when deploying the application, inputs will be rendered into frontend form.
spec.defaults
is a map of names, types and values that are filled as defaults when parsing the template.
Name | Description |
---|---|
type |
string or number stands for the type of the variable, the only difference is that the string type will be quoted when rendered, and the number type will not. |
value |
The value of the variable, if the value is a function, it will be rendered. |
In the current implementation, defaults
must have a field named app_name
, and it must contain a random string generated by ${{ random(8) }}
as the unique name of the application, otherwise an error will occur.
spec.defaults
is a map of defined objects that are parsed and shown as form inputs for user to react.
Name | Description |
---|---|
description |
The description of the input. Will be rendered as input placeholder. |
default |
The default value of the input. |
required |
Whether the input is required. |
type |
Must be one of string | number | choice | boolean |
options ? |
When type is choice , set list of available options. |
Inputs as demoed above will be rendered as form inputs in the frontend:
Template | View |
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 }}
The namespace where Sealos user is deployed.${{ SEALOS_CLOUD_DOMAIN }}
The domain suffix of the Sealos cluster.${{ SEALOS_CERT_SECRET_NAME }}
The name of the secret that Sealos uses to store the tls certificate.
${{ random(length) }}
generate a random string of lengthlength
.- TODO:
${{ if() }}
${{ endif() }}
Conditional rendering.
This part generally consists of a group of types of resources:
- Applications
Deployment
,StatefulSet
,Service
- External Access,
Ingress
- Underlying Requirements,
Database
,Object Storage
Each resources can repeat any times without order.
Applications is list of as many as Deployment
, StatefulSet
, Service
Or/And Job
, Secret
, ConfigMap
, Custom Resource
as you want.
Demo
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 }}
Frequently changes with the following fields:
Code | Description |
---|---|
metadata.annotations metadata.labels |
Change to match launchpad's requirements, like originImageName , minReplicas , maxReplicas . |
spec.containers[].image |
Change to your Docker image. |
spec.containers[].env |
Configure environment variables for the container |
spec.containers[].ports.containerPort |
Change to the port corresponding to your Docker image |
${{ defaults.app_name }} |
You can use the ${{ defaults.xxxx }} |${{ inputs.xxxx }} variables to set parameters defined in the Template CR . |
If the application needs to be accessed externally, you need to add the following code:
Demo
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 }}
Please note that the host
field needs to be randomly set for security purpose. You can use ${{ random(8) }}
set to defaults.app_host
and use ${{ defaults.app_host }}
then.
Almost all applications needs underlying requirements, such as database
, cache
, object storage
etc. You can add the following code to deploy some underlying requirements we provided:
We using kubeblocks
to provide database resources support. You can directly use the following code to deploy a database:
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 }}
When deploy databases, you only need to concern about the resources used by the database:
Code | Description |
---|---|
replicas |
Number of instances |
resources |
Allocate CPU and memory |
storage |
Volume size |
The database username/password is set into one secret for future usage. It can be added to the environment variables through the following code. After adding, you can read the MONGODB password in the container through $(MONGO_PASSWORD).
...
spec:
containers:
- name: ${{ defaults.app_name }}
...
env:
- name: MONGO_PASSWORD
valueFrom:
secretKeyRef:
name: ${{ defaults.app_name }}-mongo-conn-credential
key: password
...
To facilitate users to manage and modify applications deployed through templates, the system will deploy an app.sealos.io/v1, Kind=Instance
CRD as the instance of the template during actual deployment.
The CRD itself will be migrated according to the format and fields the same of app.sealos.io/v1, Kind=Template
, and the processing logic is as follows:
- Replace all variables/functions in the template with a determined value.
- Change the kind from
Template
toInstance
. - Apply the instance of this template to the user's namespace.
For all resources deployed through the templates, including system resources such as deploy
, service
, and custom resources such as app
, kb database
, etc., a unified label cloud.sealos.io/deploy-on-sealos: $app_name
will be added.
Where app_name
is the name of the application deployed by the user, which is by default a random string, such as fastgpt-zu1n048s
.