Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(server): support dedicated database #1728

Merged
merged 25 commits into from
Jan 3, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
965410c
feat(server): support dedicated database
0fatal Dec 8, 2023
48de2d2
chore(build): add default deploy manifest
0fatal Dec 8, 2023
8b71531
chore(server): cannot change database type when update bundle
0fatal Dec 8, 2023
616189e
fix(server): fix import
0fatal Dec 11, 2023
b46ed35
feat(server): add dedicated database specs to bundle
0fatal Dec 11, 2023
950261f
fix(server): wait for app start for long time
0fatal Dec 11, 2023
152a4d6
fix monitor metrics label
0fatal Dec 12, 2023
66c4523
fix
0fatal Dec 13, 2023
324c8ec
change ddb capacity price unit
0fatal Dec 14, 2023
4263c87
filter ddb cpu/memory metrics labels
0fatal Dec 15, 2023
0632314
Merge remote-tracking branch 'upstream/main' into feat/mongo-isolation
maslow Dec 20, 2023
2f9d1bb
chore: merge upstream main
maslow Dec 20, 2023
5e1440b
refactor(build): change mongodb to kb mongodb
0fatal Dec 20, 2023
e0fbd8c
refactor dedicated database fields
0fatal Dec 21, 2023
ec89664
add assert and change db host
0fatal Dec 21, 2023
8adf28f
fix miss limit ratio
0fatal Dec 21, 2023
4dcacbd
add kb-mongodb service monitor
0fatal Dec 21, 2023
59abd5a
install jq first when deploy
0fatal Dec 21, 2023
ae6948f
cannot reduce ddb capacity
0fatal Dec 22, 2023
8f07c5e
add default databaseCapacity
0fatal Dec 22, 2023
fa10bf5
add empty field fallback
0fatal Dec 22, 2023
0c18585
project request resources of ddb to empty
0fatal Dec 22, 2023
1124f40
fix request resources
0fatal Dec 22, 2023
ae3344c
disabled ddb replicas change
0fatal Dec 22, 2023
f760217
change deploy manifest sa
0fatal Jan 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build/charts/laf-server/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ spec:
value: {{ .Values.default_region.tls.wildcard_certificate_secret_name | quote}}
- name: DEFAULT_REGION_PROMETHEUS_URL
value: {{ .Values.default_region.prometheus_url }}
- name: DEFAULT_REGION_DEPLOY_MANIFEST
value: {{ .Values.default_region.deploy_manifest }}
- name: SITE_NAME
value: {{ .Values.siteName | quote}}
{{- with .Values.nodeSelector }}
Expand Down
1 change: 1 addition & 0 deletions build/charts/laf-server/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ default_region:
runtime_exporter_secret: ""
# prometheus
prometheus_url: ""
deploy_manifest: ""
jwt:
secret: laf_server_abc123
expires_in: 7d
Expand Down
50 changes: 50 additions & 0 deletions build/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,55 @@ helm install minio -n ${NAMESPACE} \
## 5. install laf-server
SERVER_JWT_SECRET=$PASSWD_OR_SECRET
RUNTIME_EXPORTER_SECRET=$PASSWD_OR_SECRET
DEPLOY_MANIFEST='{
"database": "
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: <%- name %>
annotations: {}
name: <%- name %>
namespace: {namespace}
spec:
affinity:
nodeLabels: {}
podAntiAffinity: Preferred
tenancy: SharedNode
topologyKeys: []
clusterDefinitionRef: mongodb
clusterVersionRef: mongodb-5.0
componentSpecs:
- componentDefRef: mongodb
monitor: true
name: mongodb
replicas: <%- replicas %>
resources:
limits:
cpu: <%- limitCPU %>m
memory: <%- limitMemory %>Mi
requests:
cpu: <%- requestCPU %>m
memory: <%- requestMemory %>Mi
serviceAccountName: <%- name %>
volumeClaimTemplates:
- name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: <%- capacity %>Mi
terminationPolicy: Delete
tolerations: []
"
}'
DEPLOY_MANIFEST=$(echo "$DEPLOY_MANIFEST" | sed "s/{namespace}/$NAMESPACE/g")

helm install server -n ${NAMESPACE} \
--set databaseUrl=${DATABASE_URL} \
--set jwt.secret=${SERVER_JWT_SECRET} \
Expand All @@ -91,6 +140,7 @@ helm install server -n ${NAMESPACE} \
--set default_region.tls.enabled=false \
--set default_region.runtime_exporter_secret=${RUNTIME_EXPORTER_SECRET} \
$([ "$ENABLE_MONITOR" = "true" ] && echo "--set default_region.prometheus_url=${PROMETHEUS_URL}") \
--set default_region.deploy_manifest=${DEPLOY_MANIFEST}
./charts/laf-server

## 6. install laf-web
Expand Down
32 changes: 32 additions & 0 deletions server/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@nestjs/common": "^9.0.0",
"@nestjs/config": "^2.2.0",
"@nestjs/core": "^9.2.1",
"@nestjs/event-emitter": "^2.0.3",
"@nestjs/jwt": "^10.0.1",
"@nestjs/mapped-types": "*",
"@nestjs/passport": "^9.0.0",
Expand Down
2 changes: 2 additions & 0 deletions server/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { APP_INTERCEPTOR } from '@nestjs/core'
import { AppInterceptor } from './app.interceptor'
import { InterceptorModule } from './interceptor/interceptor.module'
import { MonitorModule } from './monitor/monitor.module'
import { EventEmitterModule } from '@nestjs/event-emitter'

@Module({
imports: [
Expand Down Expand Up @@ -76,6 +77,7 @@ import { MonitorModule } from './monitor/monitor.module'
GroupModule,
InterceptorModule,
MonitorModule,
EventEmitterModule.forRoot(),
],
controllers: [AppController],
providers: [
Expand Down
33 changes: 22 additions & 11 deletions server/src/application/application-task.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { DatabasePhase } from 'src/database/entities/database'
import { DomainPhase } from 'src/gateway/entities/runtime-domain'
import { StoragePhase } from 'src/storage/entities/storage-user'
import { ApplicationNamespaceMode } from 'src/region/entities/region'
import { DedicatedDatabaseService } from 'src/database/dedicated-database/dedicated-database.service'

@Injectable()
export class ApplicationTaskService {
Expand All @@ -35,6 +36,7 @@ export class ApplicationTaskService {
private readonly clusterService: ClusterService,
private readonly storageService: StorageService,
private readonly databaseService: DatabaseService,
private readonly dedicatedDatabaseService: DedicatedDatabaseService,
private readonly runtimeDomainService: RuntimeDomainService,
private readonly bucketDomainService: BucketDomainService,
private readonly triggerService: TriggerService,
Expand Down Expand Up @@ -119,20 +121,27 @@ export class ApplicationTaskService {
storage = await this.storageService.create(app.appid)
}

// reconcile database
let database = await this.databaseService.findOne(appid)
if (!database) {
this.logger.log(`Creating database for application ${appid}`)
database = await this.databaseService.create(app.appid)
}

// reconcile runtime domain
let runtimeDomain = await this.runtimeDomainService.findOne(appid)
if (!runtimeDomain) {
this.logger.log(`Creating gateway for application ${appid}`)
runtimeDomain = await this.runtimeDomainService.create(appid)
}

// reconcile database
const dedicatedDatabase = await this.dedicatedDatabaseService.findOne(appid)
if (!dedicatedDatabase) {
let database = await this.databaseService.findOne(appid)
if (!database) {
this.logger.log(`Creating database for application ${appid}`)
database = await this.databaseService.create(app.appid)
}

if (database?.phase !== DatabasePhase.Created) {
return await this.unlock(appid)
}
}

// waiting resources' phase to be `Created`
if (runtimeDomain?.phase !== DomainPhase.Created) {
return await this.unlock(appid)
Expand All @@ -142,10 +151,6 @@ export class ApplicationTaskService {
return await this.unlock(appid)
}

if (database?.phase !== DatabasePhase.Created) {
return await this.unlock(appid)
}

// update application phase to `Created`
await db.collection<Application>('Application').updateOne(
{ _id: app._id, phase: ApplicationPhase.Creating },
Expand Down Expand Up @@ -260,6 +265,12 @@ export class ApplicationTaskService {
return await this.unlock(appid)
}

const dedicatedDatabase = await this.dedicatedDatabaseService.findOne(appid)
if (dedicatedDatabase) {
await this.dedicatedDatabaseService.remove(appid)
return await this.unlock(appid)
}

// delete application storage
const storage = await this.storageService.findOne(appid)
if (storage) {
Expand Down
57 changes: 54 additions & 3 deletions server/src/application/application.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export class ApplicationController {
@ApiResponseObject(ApplicationWithRelations)
@Post()
async create(@Body() dto: CreateApplicationDto, @InjectUser() user: User) {
const error = dto.autoscaling.validate()
const error = dto.validate() || dto.autoscaling.validate()
if (error) {
return ResponseUtil.error(error)
}
Expand Down Expand Up @@ -334,6 +334,14 @@ export class ApplicationController {
}
}

const origin = app.bundle
if (
(origin.resource['dedicatedDatabase.limitCPU'] && dto.databaseCapacity) ||
(origin.resource.databaseCapacity && dto.dedicatedDatabase)
) {
return ResponseUtil.error('cannot change database type')
}

const checkSpec = await this.checkResourceSpecification(dto, regionId)
if (!checkSpec) {
return ResponseUtil.error('invalid resource specification')
Expand All @@ -353,13 +361,29 @@ export class ApplicationController {
const doc = await this.application.updateBundle(appid, dto, isTrialTier)

// restart running application if cpu or memory changed
const origin = app.bundle
const isRunning = app.phase === ApplicationPhase.Started
const isCpuChanged = origin.resource.limitCPU !== doc.resource.limitCPU
const isMemoryChanged =
origin.resource.limitMemory !== doc.resource.limitMemory
const isAutoscalingCanceled =
!doc.autoscaling.enable && origin.autoscaling.enable
const isDedicatedDatabaseChanged =
!isEqual(
origin.resource['dedicatedDatabase.limitCPU'],
doc.resource['dedicatedDatabase.limitCPU'],
) ||
!isEqual(
origin.resource['dedicatedDatabase.limitMemory'],
doc.resource['dedicatedDatabase.limitMemory'],
) ||
!isEqual(
origin.resource['dedicatedDatabase.replicas'],
doc.resource['dedicatedDatabase.replicas'],
) ||
!isEqual(
origin.resource['dedicatedDatabase.capacity'],
doc.resource['dedicatedDatabase.capacity'],
)

if (!isEqual(doc.autoscaling, origin.autoscaling)) {
const { hpa, app } = await this.instance.get(appid)
Expand All @@ -368,7 +392,10 @@ export class ApplicationController {

if (
isRunning &&
(isCpuChanged || isMemoryChanged || isAutoscalingCanceled)
(isCpuChanged ||
isMemoryChanged ||
isAutoscalingCanceled ||
isDedicatedDatabaseChanged)
) {
await this.application.updateState(appid, ApplicationState.Restarting)
}
Expand Down Expand Up @@ -489,15 +516,39 @@ export class ApplicationController {
case 'memory':
return option.specs.some((spec) => spec.value === dto.memory)
case 'databaseCapacity':
if (!dto.databaseCapacity) return true
return option.specs.some(
(spec) => spec.value === dto.databaseCapacity,
)
case 'storageCapacity':
return option.specs.some((spec) => spec.value === dto.storageCapacity)
// dedicated database
case 'dedicatedDatabase.cpu':
return (
!dto.dedicatedDatabase ||
option.specs.some(
(spec) => spec.value === dto.dedicatedDatabase.cpu,
)
)
case 'dedicatedDatabase.memory':
return (
!dto.dedicatedDatabase ||
option.specs.some(
(spec) => spec.value === dto.dedicatedDatabase.memory,
)
)
case 'dedicatedDatabase.capacity':
return (
!dto.dedicatedDatabase ||
option.specs.some(
(spec) => spec.value === dto.dedicatedDatabase.capacity,
)
)
default:
return true
}
})

return checkSpec
}
}
Loading