Laf is a cloud development platform offering ready-to-use resources like cloud functions, databases, and storage. It empowers developers to quickly unleash their creativity.
CVE Fixed: https://nvd.nist.gov/vuln/detail/CVE-2023-48225
@see https://github.com/labring/laf/security/advisories/GHSA-hv2g-gxx4-fwxp
⚠️ All private deployments should update to the latest version of laf to fix this CVE.
import cloud from '@lafjs/cloud'
export default async function (ctx: FunctionContext) {
// get bucket
const bucket = cloud.storage.bucket('cloud-bin')
// create file
await bucket.writeFile('test.html', 'hello, laf', { ContentType: 'text/html' })
// read file
const res = await bucket.readFile('test.html')
console.log(await res.Body.transformToString())
// list files
const result = await bucket.listFiles()
console.log(result.Contents)
// delete file
await bucket.deleteFile('test.html')
return { data: 'hi, laf' }
}
The newly added support for node modules caching includes:
node_modules.tar
)offline dependencies installation mode
(runtime)To support offline dependencies installation mode
:
LF_NODE_MODULES_CACHE=always
environment variable to your applicationnode_modules.tar
to {appid}-cloud-bin
bucket manuallyThen the runtime would skip npm install
command, and use node_modules.tar
instead.
You can add npm packages which has different version with built-in packages in runtime.
ObjectId
problem in laf web database managementcheck the change logs.
Full Changelog: https://github.com/labring/laf/compare/v1.0.0-beta.13...v1.0.0-beta.14
# upgrade laf SERVER
kubectl set image deployments/laf-server -n laf-system \
laf-server=docker.io/lafyun/laf-server:1.0.0-beta.14
# upgrade laf WEB
kubectl set image deployments/laf-web -n laf-system \
laf-web=docker.io/lafyun/laf-web:1.0.0-beta.14
sys_db.Runtime
to upgrade runtime images in MongoDbuse sys_db
// runtime version
const version = "1.0.0-beta.14"
const main_image = `docker.io/lafyun/runtime-node:${version}`
const init_image = `docker.io/lafyun/runtime-node:${version}`
db.Runtime.updateOne({ latest: true }, {
$set: {
version: version,
image: {
main: main_image,
init: init_image
}
}
})
db.Runtime.find().pretty()
In this version, we have restructured the cloud function runtime, enhancing the execution performance of cloud functions by over 400%, HTTP request QPS by more than 300% (with CPU usage savings of over 200% under the same concurrency), and Websocket long connection performance by over 500%.
Additionally, we have restructured the function log implementation, now directly using Runtime Pod log streams, which supports real-time log viewing and beautification of log formats.
We have also rewritten application resource monitoring and metered billing, enabling laf in the sealos user namespace to support resource monitoring and metered billing functions.
Full Changelog: https://github.com/labring/laf/compare/v1.0.0-beta.12...v1.0.0-beta.13
# upgrade laf SERVER
kubectl set image deployments/laf-server -n laf-system \
laf-server=docker.io/lafyun/laf-server:1.0.0-beta.13
# upgrade laf WEB
kubectl set image deployments/laf-web -n laf-system \
laf-web=docker.io/lafyun/laf-web:1.0.0-beta.13
sys_db.Runtime
to upgrade runtime images in MongoDbuse sys_db
// runtime version
const version = "1.0.0-beta.13"
const main_image = `docker.io/lafyun/runtime-node:${version}`
const init_image = `docker.io/lafyun/runtime-node:${version}`
db.Runtime.updateOne({ latest: true }, {
$set: {
version: version,
image: {
main: main_image,
init: init_image
}
}
})
db.Runtime.find().pretty()
sys_db.Application
in MongoDbuse sys_db
db.Application.updateMany({ state: 'Running' }, {
$set: {
state: 'Restarting'
}
})
This version of Laf uses a specialized runtime exporter for runtime resource metrics collection, so you will need to install the runtime exporter into the cluster to enable resource monitoring
kubectl apply --namespace=laf-system -f - <<EOF
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: runtime-exporter
name: runtime-exporter
spec:
ports:
- name: http
port: 2342
protocol: TCP
targetPort: http
selector:
app.kubernetes.io/name: runtime-exporter
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/name: runtime-exporter
name: runtime-exporter
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: runtime-exporter
template:
metadata:
labels:
app.kubernetes.io/name: runtime-exporter
spec:
automountServiceAccountToken: true
serviceAccountName: laf-server # It's the same as the laf server's sa.
securityContext: {}
containers:
- image: docker.io/lafyun/runtime-exporter:latest
imagePullPolicy: Always
name: runtime-exporter
ports:
- name: http
containerPort: 2342
protocol: TCP
livenessProbe:
httpGet:
path: /healthz
port: http
readinessProbe:
httpGet:
path: /healthz
port: http
env:
- name: API_SECRET
value: "fafafafa"
- name: NAMESPACE
value: "laf-system" # Depends on the namespace of the runtime.
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
labels:
app.kubernetes.io/name: runtime-exporter
release: prometheus
name: runtime-exporter
spec:
endpoints:
- interval: 60s
path: "/runtime/metrics/fafafafa" # fafafafa is consistent with the runtime exporter's environment variable API_SECRET
scrapeTimeout: 10s
honorLabels: true
namespaceSelector:
matchNames:
- laf-system # Depends on the namespace of the runtime exporter.
selector:
matchLabels:
app.kubernetes.io/name: runtime-exporter
---
# Application billing rules
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
labels:
app.kubernetes.io/name: runtime-exporter
release: prometheus
name: prometheus-laf-billing.rules
spec:
groups:
- name: prometheus-laf-billing.rules
interval: 60s
rules:
- record: laf:billing:cpu
expr: max_over_time(sum by (appid) (laf_runtime_cpu_limit{container!=""})[1h:])
- record: laf:billing:memory
expr: max_over_time(sum by (appid) (laf_runtime_memory_limit{container!=""})[1h:])
EOF
Full Changelog: https://github.com/labring/laf/compare/v1.0.0-beta.11...v1.0.0-beta.12
# upgrade laf SERVER
kubectl set image deployments/laf-server -n laf-system \
laf-server=docker.io/lafyun/laf-server:1.0.0-beta.12
# upgrade laf WEB
kubectl set image deployments/laf-web -n laf-system \
laf-web=docker.io/lafyun/laf-web:1.0.0-beta.12
sys_db
to upgrade runtime images// runtime version
const version = "1.0.0-beta.12"
// const version = "1.0.0-beta.12"
const main_image = `docker.io/lafyun/runtime-node:${version}`
const init_image = `docker.io/lafyun/runtime-node:${version}`
db.Runtime.updateOne({ latest: true }, {
$set: {
version: version,
image: {
main: main_image,
init: init_image
}
}
})
db.Runtime.find().pretty()
sys_db.Region
if you still use apisix gateway:Deprecated: apisix gateway is deprecated in laf, will not be supported in future.
use sys_db
db.Region.updateOne({}, {
$set: {
namespaceConf: {
mode: 'appid',
prefix: '',
fixed: ''
},
'gatewayConf.tls.wildcardCertificateSecretName': null,
'gatewayConf.driver': 'apisix'
}
})
First stop all laf applications by update sys_db
:
use sys_db;
db.Application.updateMany({ state: 'Running' }, {
$set: {
state: 'Stopped',
_restart_flag: 'migration-gateway'
}
})
Waiting for all application stopped.
# stop laf-server
kubectl scale deployment laf-server -n laf-system --replicas=0
# uninstall apisix
helm delete apisix --namespace laf-system
sealos run docker.io/labring/ingress-nginx:v1.8.1 \
-e HELM_OPTS="-n ingress-nginx --set controller.hostNetwork=true --set controller.kind=DaemonSet --set controller.service.enabled=false"
kubectl create namespace laf-runtime
use sys_db
db.Region.updateOne({}, {
$set: {
namespaceConf: {
mode: 'fixed',
prefix: '',
fixed: 'laf-runtime'
},
'gatewayConf.tls.wildcardCertificateSecretName': '',
'gatewayConf.driver': 'nginx'
}
})
# start laf-server
kubectl scale deployment laf-server -n laf-system --replicas=1
Start all applications:
db.Application.updateMany({ state: 'Stopped', _restart_flag: 'migration-gateway' }, {
$set: { state: 'Running' }
})
memberOf
of minio user by @0fatal in https://github.com/labring/laf/pull/1436
try-path
conf by @0fatal in https://github.com/labring/laf/pull/1465
Full Changelog: https://github.com/labring/laf/compare/v1.0.0-beta.10...v1.0.0-beta.11
npmjs
by @0fatal in https://github.com/labring/laf/pull/1315
message
field for AccountChargeReward by @0fatal in https://github.com/labring/laf/pull/1321
Restarting
-> Starting
for app stopped by @0fatal in https://github.com/labring/laf/pull/1324
_id
property by @bingtsingw in https://github.com/labring/laf/pull/1360
Full Changelog: https://github.com/labring/laf/compare/v1.0.0-beta.9...v1.0.0-beta.10
sys_db
to support autoscaling of applications:db.ApplicationBundle.updateMany({}, {
$set: {
autoscaling: {
enable: false,
minReplicas: 1,
maxReplicas: 5,
targetCPUUtilizationPercentage: null,
targetMemoryUtilizationPercentage: null,
},
}
})
sys_db
to support invitation bonus:db.Setting.insertOne({
public: true,
key: 'invitation_profit',
value: 500,
desc: "Set up invitation rebate"
})
# upgrade laf SERVER
kubectl set image deployments/laf-server -n laf-system \
laf-server=docker.io/lafyun/laf-server:1.0.0-beta.10
# upgrade laf WEB
kubectl set image deployments/laf-web -n laf-system \
laf-web=docker.io/lafyun/laf-web:1.0.0-beta.10
sys_db
to upgrade runtime images// runtime version
const version = "1.0.0-beta.10"
// const version = "1.0.0-beta.10"
const main_image = `docker.io/lafyun/runtime-node:${version}`
const init_image = `docker.io/lafyun/runtime-node:${version}`
db.Runtime.updateOne({ latest: true }, {
$set: {
version: version,
image: {
main: main_image,
init: init_image
}
}
})
db.Runtime.find().pretty()
Full Changelog: https://github.com/labring/laf/compare/v1.0.0-beta.8...v1.0.0-beta.9
Upgrade the server and web image version:
run this in your master node to upgrade laf-server & laf-web
kubectl set image deployments/laf-server -n laf-system \
laf-server=docker.io/lafyun/laf-server:1.0.0-beta.9
kubectl set image deployments/laf-web -n laf-system \
laf-web=docker.io/lafyun/laf-web:1.0.0-beta.9
To support new billing mechanism, you should add a new field to Application
collection in system database.
run this in your mongodb shell.
use sys_db;
db.Application.updateMany({}, {
$set: {
billingLockedAt: new Date('1970-01-01T00:00:00.000Z')
}
})
To support multi-level url path in cloud function:
run this in your mongodb shell to upgrade runtime version
use sys_db;
// runtime version
const version = "1.0.0-beta.9"
const main_image = `docker.io/lafyun/runtime-node:${version}`
const init_image = `docker.io/lafyun/runtime-node-init:${version}`
db.Runtime.updateOne({ latest: true }, {
$set: {
version: version,
image: {
main: main_image,
init: init_image
}
}
})
db.Runtime.find().pretty()
Add new environment to laf-server deployments:
kubectl edit deployment/laf-server -n laf-system
env:
- name: METERING_DATABASE_URL
value: >-
mongodb://your-root-user:your-password@mongo-cluster-rs0-0.mongo-cluster-rs0.default.svc.cluster.local:27017/sealos-resources?authSource=admin&replicaSet=rs0&w=majority
Full Changelog: https://github.com/labring/laf/compare/v1.0.0-beta.7...v1.0.0-beta.8
Full Changelog: https://github.com/labring/laf/compare/v1.0.0-beta.6...v1.0.0-beta.7
run this in your master node to upgrade laf-server & laf-web
kubectl set image deployments/laf-server -n laf-system \
laf-server=docker.io/lafyun/laf-server:1.0.0-beta.7
kubectl set image deployments/laf-web -n laf-system \
laf-web=docker.io/lafyun/laf-web:1.0.0-beta.7
run this in your mongodb shell to upgrade runtime version
use sys_db;
// runtime version
const version = "1.0.0-beta.7"
const main_image = `docker.io/lafyun/runtime-node:${version}`
const init_image = `docker.io/lafyun/runtime-node-init:${version}`
db.Runtime.updateOne({ latest: true }, {
$set: {
version: version,
image: {
main: main_image,
init: init_image
}
}
})
db.Runtime.find().pretty()
``
Full Changelog: https://github.com/labring/laf/compare/v1.0.0-beta.5...v1.0.0-beta.6
kubectl set image deployments/laf-server -n laf-system \
laf-server=docker.io/lafyun/laf-server:1.0.0-beta.6
kubectl set image deployments/laf-web -n laf-system \
laf-web=docker.io/lafyun/laf-web:1.0.0-beta.6
It is crucial to update your Minio version to RELEASE.2023-03-22T06-36-24Z
in order to address the critical vulnerability CVE-2023-28432
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: laf-issuer
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: [email protected]
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: apisix
EOF
Full Changelog: https://github.com/labring/laf/compare/v1.0.0-beta.4...v1.0.0-beta.5
Database: Bundle schema changes
limitCountPerUser
fieldresource.limitCountPerUser
fieldsubscriptionOptions
fieldresource.reservedTimeAfterExpired
fieldmaxRenewalTime
fieldspecialPrice
and price
fieldOperations
db.Bundle.updateMany({}, {
$set: {
limitCountPerUser: 1,
maxRenewalTime: 3888000,
subscriptionOptions: [
{
"name": "monthly",
"displayName": "1 Month",
"duration": 2678400,
"price": 0,
"specialPrice": 0
}
],
"resource.reservedTimeAfterExpired": 2678400
}
})
Database: ApplicationBundle schema changes
resource.limitCountPerUser
fieldresource.reservedTimeAfterExpired
fieldbundleId
fieldOperations
db.ApplicationBundle.updateMany({}, {
$set: {
"resource.reservedTimeAfterExpired": 2678400,
bundleId: new ObjectId("6405ffe6103ead6d468b1a17"),
}
})
Database: Region schema changes
storageConf.controlEndpoint
fielddatabaseConf.controlConnectionUri
fieldAPI: remove POST /v1/applications
POST /v1/subscriptions
insteadAPI: remove DELETE /v1/applications/:appid
DELETE v1/subscriptions
insteadDatabase: Add Subscriptions for existed applications
Operations
// write cloud function to insert subscriptions
import cloud from '@lafjs/cloud'
import { MongoClient, ObjectId, Db } from 'mongodb'
const sys_db_uri = cloud.env.SYS_DB_URI
// set your existed bundle id
const bundleId = new ObjectId('6407200ca35fb4d684296d5c')
export async function main(ctx: FunctionContext) {
const client = new MongoClient(sys_db_uri)
await client.connect()
const db = client.db('sys_db')
const apps = await db.collection('Application')
.find()
.toArray()
for(let app of apps) {
const res = await addSubscription(db, app, bundleId)
console.log(app.appid, res)
}
return { data: 'hi, laf' }
}
async function addSubscription(db: Db, app: any, bundleId: ObjectId) {
const sub = {
"bundleId": bundleId,
"appid": app.appid,
"state": "Created",
"phase": "Valid",
"renewalPlan": "Manual",
"expiredAt": new Date('2023-12-31T00:00:00.733Z'),
"lockedAt": new Date('1970-01-01T00:00:00.000Z'),
"createdAt": new Date(),
"updatedAt": new Date(),
"createdBy": app.createdBy,
"input": {
"name": app.name,
"state": app.state,
"regionId": app.regionId,
"runtimeId": app.runtimeId
}
}
return await db.collection('Subscription').insertOne(sub)
}
Config phone auth provider
db.AuthProvider.updateOne({ name: "phone" }, {
$set: {
state: "Enabled",
"config.alisms": {
"accessKeyId": "",
"accessKeySecret": "",
"api_entrypoint": "https://dysmsapi.aliyuncs.com",
"signName": "",
"templateCode": "SMS_000004"
}
}
})
Add Wechat payment channel
// db.PaymentChannel.find().pretty()
db.PaymentChannel.insertOne({
type: "WeChat",
name: "WeChat Pay",
spec: {
mchid: "",
appid: "",
apiV3Key: "",
certificateSerialNumber: "",
privateKey: "-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----",
publicKey: "----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"
},
state: "Active",
createdAt: new Date(),
updatedAt: new Date()
})