Validator CRD User Guide
Catalyst uses the operator pattern with Custom Resource definitions. The same operations that can be made in the Catalyst GUI can be performed directly on Kubernetes with access to the cluster. Bellow are instructions on how to create and configure a validator using the CRD’s directly
Creating a Validator
Creation Example
apiVersion: v1
kind: Secret
metadata:
namespace: canton-dev
name: database-validator-dev-foo
data:
user: "YWRtaW4="
password: "YWRtaW4="
---
apiVersion: v1
kind: Secret
metadata:
namespace: canton-dev
name: cn-app-validator-dev-foo-onboarding-validator
data:
secret: "ZXlKemNHOXVjMjl5YVc1blUzWWlPaUpIYkc5aVlXd3RVM2x1WTJoeWIyNXBlbVZ5TFVadmRXNWtZWFJwYjI0Nk9qRXlNakJqTnpZME9XSXlPVGc1WVRVM09UY3lPVFZpTjJJek5XTm1ZbUZrTnpJMFpXVXhabVV6T0RCak5qRm1NMkZrWWpVeFlUZzFabVl5WVRabU9UWXlZVFV3SWl3aWMyVmpjbVYwSWpvaVNXSmhUVlp0ZDJ0bU5VSkNObGxRUlVWMWNUbHlWbmQ0TDNwb1REUkROekJGUld4TVJWUm1XQzlHYnowaWZRPT0K"
---
apiVersion: v1
kind: Secret
metadata:
namespace: canton-dev
name: cn-app-validator-dev-foo-cns-ui-auth
data:
url: "aHR0cHM6Ly9rZXljbG9hay50ZXN0aW5nLmNhdGFseXN0LmludGVsbGVjdGV1LmlvL2F1dGgvcmVhbG1zL2NhbnRvbi1kZXY="
clientId: "dmFsaWRhdG9yLWRldi1mb28tY25zLXVp"
---
apiVersion: v1
kind: Secret
metadata:
namespace: canton-dev
name: cn-app-validator-dev-foo-wallet-ui-auth
data:
url: "aHR0cHM6Ly9rZXljbG9hay50ZXN0aW5nLmNhdGFseXN0LmludGVsbGVjdGV1LmlvL2F1dGgvcmVhbG1zL2NhbnRvbi1kZXY="
clientId: "dmFsaWRhdG9yLWRldi1mb28td2FsbGV0LXVp"
username: "dmFsaWRhdG9yLWRldi1mb29fd2FsbGV0dXNlcg=="
---
apiVersion: v1
kind: Secret
metadata:
namespace: canton-dev
name: cn-app-validator-dev-foo-ledger-api-auth
data:
client-id: "dmFsaWRhdG9yLWRldi1mb28="
client-secret: "MTBhSDNYeGx4dWxEWHljd2FPWDBwamdqZ0VrSmxsbmI="
ledger-api-user: "c2VydmljZS1hY2NvdW50LXZhbGlkYXRvci1kZXYtZm9v"
url: "aHR0cHM6Ly9rZXljbG9hay50ZXN0aW5nLmNhdGFseXN0LmludGVsbGVjdGV1LmlvL2F1dGgvcmVhbG1zL2NhbnRvbi1kZXYvLndlbGwta25vd24vb3BlbmlkLWNvbmZpZ3VyYXRpb24="
---
apiVersion: catalyst.manager.canton/v1
kind: Validator
metadata:
name: validator-dev-foo
namespace: canton-dev
spec:
application:
spec:
domain: participant-validator-dev-foo
extraPorts:
metrics: 10013
val-http: 5003
resources:
cpuLimit: "2"
cpuRequested: "1"
imagePullSecret: ""
memoryLimit: 6Gi
memoryRequested: 3Gi
replicas: 1
servicePorts:
metrics: 10013
val-http: 5003
type: backend
envVars: []
applicationCantonNameServer:
spec:
domain: cns-validator-dev-foo
extraPorts: {}
port: 8080
resources:
cpuLimit: "1"
cpuRequested: "0.1"
imagePullSecret: ""
memoryLimit: 1536Mi
memoryRequested: 240Mi
replicas: 1
servicePorts: {}
type: ui
envVars: []
applicationWallet:
spec:
domain: wallet-validator-dev-foo
extraPorts: {}
port: 8080
resources:
cpuLimit: "1"
cpuRequested: "0.1"
imagePullSecret: ""
memoryLimit: 1536Mi
memoryRequested: 240Mi
replicas: 1
servicePorts: {}
type: ui
envVars: []
config:
scanAddress: "https://scan.sv-1.dev.global.canton.network.sync.global"
svSponsorAddress: "https://sv.sv-1.dev.global.canton.network.sync.global"
defaultJvmOptions: "-Xms1152M -Xmx1152M -Dscala.concurrent.context.minThreads=4"
partyHint: ieu-foo-001
extraDomains: []
failOnAppVersionMismatch: true
openId:
jwksUrl: "https://keycloak.testing.catalyst.intellecteu.io/auth/realms/canton-dev/protocol/openid-connect/certs"
audience: "https://wallet-validator-dev-foo.canton-dev.testing.catalyst.intellecteu.io/api"
ledgerAuth:
secretName: "cn-app-validator-dev-foo-ledger-api-auth"
confUrlField: "url"
clientIdField: "client-id"
clientSecretField: "client-secret"
userField: "ledger-api-user"
audience: "https://wallet-validator-dev-foo.canton-dev.testing.catalyst.intellecteu.io/api"
tokenField: "token"
useToken: false
database:
port: 5432
pwdField: password
schema: validator
secretName: database-validator-dev-foo
userField: user
participant:
address: participant-validator-dev-foo.canton-dev.svc.cluster.local
adminSecretRef:
usernameField: ledger-api-user
secretName: cn-app-validator-dev-foo-ledger-api-auth
database:
dns: database-validator-dev-foo.canton-dev.svc.cluster.local
port: 5432
pwdField: password
schema: participant
secretName: database-validator-dev-foo
userField: user
nodeIdentifier: IEUDevFoo001
walletApp:
secretName: "cn-app-validator-dev-foo-wallet-ui-auth"
authorityUrlField: "url"
clientIdField: "clientId"
username: "validator-dev-foo_walletuser"
cnsApp:
secretName: "cn-app-validator-dev-foo-cns-ui-auth"
authorityUrlField: "url"
clientIdField: "clientId"
participant:
spec:
daemon: true
resources:
cpuLimit: "2"
cpuRequested: "1"
imagePullSecret: ""
memoryLimit: 6Gi
memoryRequested: 3Gi
replicas: 1
envVars: []
customAuth: true
disableAutoInit: false
disabledWallet: false
imageRepo: ghcr.io/digital-asset/decentralized-canton-sync/docker
imageTag: 0.4.16
migrationId: "0"
migrationMigrating: false
onboardingSecretName: cn-app-validator-dev-foo-onboarding-validator
storageSize: 20Gi
envVars: []
----
apiVersion: v1
kind: Secret
metadata:
namespace: canton-dev
name: database-validator-dev-foo
data:
user: "YWRtaW4="
password: "YWRtaW4="
---
apiVersion: v1
kind: Secret
metadata:
namespace: canton-dev
name: cn-app-validator-dev-foo-onboarding-validator
data:
secret: "ZXlKemNHOXVjMjl5YVc1blUzWWlPaUpIYkc5aVlXd3RVM2x1WTJoeWIyNXBlbVZ5TFVadmRXNWtZWFJwYjI0Nk9qRXlNakJqTnpZME9XSXlPVGc1WVRVM09UY3lPVFZpTjJJek5XTm1ZbUZrTnpJMFpXVXhabVV6T0RCak5qRm1NMkZrWWpVeFlUZzFabVl5WVRabU9UWXlZVFV3SWl3aWMyVmpjbVYwSWpvaVNXSmhUVlp0ZDJ0bU5VSkNObGxRUlVWMWNUbHlWbmQ0TDNwb1REUkROekJGUld4TVJWUm1XQzlHYnowaWZRPT0K"
---
apiVersion: v1
kind: Secret
metadata:
namespace: canton-dev
name: cn-app-validator-dev-foo-cns-ui-auth
data:
url: "aHR0cHM6Ly9rZXljbG9hay50ZXN0aW5nLmNhdGFseXN0LmludGVsbGVjdGV1LmlvL2F1dGgvcmVhbG1zL2NhbnRvbi1kZXY="
clientId: "dmFsaWRhdG9yLWRldi1mb28tY25zLXVp"
---
apiVersion: v1
kind: Secret
metadata:
namespace: canton-dev
name: cn-app-validator-dev-foo-wallet-ui-auth
data:
url: "aHR0cHM6Ly9rZXljbG9hay50ZXN0aW5nLmNhdGFseXN0LmludGVsbGVjdGV1LmlvL2F1dGgvcmVhbG1zL2NhbnRvbi1kZXY="
clientId: "dmFsaWRhdG9yLWRldi1mb28td2FsbGV0LXVp"
username: "dmFsaWRhdG9yLWRldi1mb29fd2FsbGV0dXNlcg=="
---
apiVersion: v1
kind: Secret
metadata:
namespace: canton-dev
name: cn-app-validator-dev-foo-ledger-api-auth
data:
client-id: "dmFsaWRhdG9yLWRldi1mb28="
client-secret: "MTBhSDNYeGx4dWxEWHljd2FPWDBwamdqZ0VrSmxsbmI="
ledger-api-user: "c2VydmljZS1hY2NvdW50LXZhbGlkYXRvci1kZXYtZm9v"
url: "aHR0cHM6Ly9rZXljbG9hay50ZXN0aW5nLmNhdGFseXN0LmludGVsbGVjdGV1LmlvL2F1dGgvcmVhbG1zL2NhbnRvbi1kZXYvLndlbGwta25vd24vb3BlbmlkLWNvbmZpZ3VyYXRpb24="
---
apiVersion: catalyst.manager.canton/v1
kind: Validator
metadata:
name: validator-dev-foo
namespace: canton-dev
spec:
application:
spec:
domain: participant-validator-dev-foo
extraPorts:
metrics: 10013
val-http: 5003
resources:
cpuLimit: "2"
cpuRequested: "1"
imagePullSecret: ""
memoryLimit: 6Gi
memoryRequested: 3Gi
replicas: 1
servicePorts:
metrics: 10013
val-http: 5003
type: backend
envVars: []
applicationCantonNameServer:
spec:
domain: cns-validator-dev-foo
extraPorts: {}
port: 8080
resources:
cpuLimit: "1"
cpuRequested: "0.1"
imagePullSecret: ""
memoryLimit: 1536Mi
memoryRequested: 240Mi
replicas: 1
servicePorts: {}
type: ui
envVars: []
applicationWallet:
spec:
domain: wallet-validator-dev-foo
extraPorts: {}
port: 8080
resources:
cpuLimit: "1"
cpuRequested: "0.1"
imagePullSecret: ""
memoryLimit: 1536Mi
memoryRequested: 240Mi
replicas: 1
servicePorts: {}
type: ui
envVars: []
config:
scanAddress: "https://scan.sv-1.dev.global.canton.network.sync.global"
svSponsorAddress: "https://sv.sv-1.dev.global.canton.network.sync.global"
defaultJvmOptions: "-Xms1152M -Xmx1152M -Dscala.concurrent.context.minThreads=4"
partyHint: ieu-foo-001
extraDomains: []
failOnAppVersionMismatch: true
openId:
jwksUrl: "https://keycloak.testing.catalyst.intellecteu.io/auth/realms/canton-dev/protocol/openid-connect/certs"
audience: "https://wallet-validator-dev-foo.canton-dev.testing.catalyst.intellecteu.io/api"
ledgerAuth:
secretName: "cn-app-validator-dev-foo-ledger-api-auth"
confUrlField: "url"
clientIdField: "client-id"
clientSecretField: "client-secret"
userField: "ledger-api-user"
audience: "https://wallet-validator-dev-foo.canton-dev.testing.catalyst.intellecteu.io/api"
tokenField: "token"
useToken: false
database:
port: 5432
pwdField: password
schema: validator
secretName: database-validator-dev-foo
userField: user
participant:
address: participant-validator-dev-foo.canton-dev.svc.cluster.local
adminSecretRef:
usernameField: ledger-api-user
secretName: cn-app-validator-dev-foo-ledger-api-auth
database:
dns: database-validator-dev-foo.canton-dev.svc.cluster.local
port: 5432
pwdField: password
schema: participant
secretName: database-validator-dev-foo
userField: user
nodeIdentifier: IEUDevFoo001
walletApp:
secretName: "cn-app-validator-dev-foo-wallet-ui-auth"
authorityUrlField: "url"
clientIdField: "clientId"
username: "validator-dev-foo_walletuser"
cnsApp:
secretName: "cn-app-validator-dev-foo-cns-ui-auth"
authorityUrlField: "url"
clientIdField: "clientId"
participant:
spec:
daemon: true
resources:
cpuLimit: "2"
cpuRequested: "1"
imagePullSecret: ""
memoryLimit: 6Gi
memoryRequested: 3Gi
replicas: 1
envVars: []
customAuth: true
disableAutoInit: false
disabledWallet: false
imageRepo: ghcr.io/digital-asset/decentralized-canton-sync/docker
imageTag: 0.4.16
migrationId: "0"
migrationMigrating: false
onboardingSecretName: cn-app-validator-dev-foo-onboarding-validator
storageSize: 20Gi
envVars: []
-
The onboarding secret provided is one time use.
-
The validator name, participant identifier and party hint should be changed when deploying a new validator
-
The yaml defines several secrets:
-
database-validator-dev-foo - provides user credentials for a new postgresql database for a
-
cn-app-validator-dev-foo-onboarding-validator - Canton node onboarding secret
-
cn-app-validator-dev-foo-wallet-ui-auth - Canton wallet application oauth credentials
-
cn-app-validator-dev-foo-cns-ui-auth - Canton dashboard application oauth credentials
-
cn-app-validator-dev-foo-ledger-api-auth - Canton ledger application oauth credentials
-
-
These secrets (names and fields) are referenced by inside the Validator definition itself so it’s necessary to keep them in-sync
-
Pay attention that some data is not provided as part of the secret part, but as a part of the reference itself, f.e. look at the database reference excerpt below, you can see that the port, schema values are specified as raw values, not as a reference:
spec:
config:
database:
port: 5432
schema: validator
secretName: database-validator-dev-foo # <--- part of reference
pwdField: password # <--- part of reference
userField: user # <--- part of reference
Recovery from Id dump
To recover the Canton Coin balances using a Identities Backup, the Catalyst operator expects a secret in following format
Secret:
apiVersion: v1
data:
content: <Identity Backup>
kind: Secret
metadata:
labels:
validator: <validator crd name>
name: id-backup-secret-example
namespace: namespace-of-val
type: Opaque
Then we can create a validator (removing the old of the same name if on the same cluster) with the following added fields
Changes to spec:
spec:
particpant:
nodeIdentifier: "validator-foooooooo"
config:
partyHint: "oldParty"
identitiesImport:
newParticipantIdentifier: "validator-foooooooo"
secretName: "secret-with-identity-dump-party"
isMigrateValidatorParty: true
The participant should have the same node identifier as the newParticipantIdentifier field that is different from the previous validator
Configuring the Validator
Environment variable overrides
In order to add extra environment variables you can add the following fields
spec:
config:
validatorOverrides:
- name: OVERRIDE_EXAMPLE
value: "5432"
participantOverrides: [] #Can be empty or null
walletOverrides:
- name: OVERRIDE_WITH_SECRET
valueFrom:
secretKeyRef:
key: password
name: secret
cnsOverrides:[]
These will override any variables generated by the spec.config
Note:
In older versions all environment variables (operator and user defined) are defined in
-
application.spec.envVars
-
applicationWallet.spec.envVars
-
applicationCantonNameServer.envVars
-
participant.spec.envVars
This made it harder to use the CRD’s and distinguish user vs operator actions.
On upgrade to 1.10 a script will be used to generate the spec.config fields from these. Any new changes will only apply to spec.config so the operator will have the following order of priority to set environment variables.
-
Environment variables defined spec.config overrides
-
Environment variables generated by the standard spec.config fields
-
Environment variables in the deprecated <app>.spec.envVars format
The <app>.spec.envVars format will be removed in a future release. Any changes through the GUI will apply in the new spec.config override fields
Customise annotations
In order to set your own annotations on pods or services managed by catalyst the following fields can be set:
spec:
# Main validator application (backend) resources
application:
spec:
resources:
cpuLimit: "4"
cpuRequested: "2"
memoryLimit: 8Gi
memoryRequested: 4Gi
replicas: 1
# Canton Name Server (CNS) UI application resources
applicationCantonNameServer:
spec:
resources:
cpuLimit: "2"
cpuRequested: "0.5"
memoryLimit: 2Gi
memoryRequested: 512Mi
replicas: 1
# Wallet UI application resources
applicationWallet:
spec:
resources:
cpuLimit: "2"
cpuRequested: "0.5"
memoryLimit: 2Gi
memoryRequested: 512Mi
replicas: 1
# Participant node resources
participant:
spec:
resources:
cpuLimit: "4"
cpuRequested: "2"
memoryLimit: 8Gi
memoryRequested: 4Gi
replicas: 1
#Database persistent volume size
storageSize: 50Gi
Other fields
Update examples:
-
enabled top up
spec:
config:
topUp:
enabled: true
minInterval: 2m
targetThroughput: 80000
-
enable scheduled pruning
spec:
config:
scheduledPrune:
retention: "2m"
cron: "* * * * *"
maxDuration: "30d"
-
provide additional config
spec:
config:
additionalConfigOther: |
canton.validator-apps.validator_backend.participant-bootstrapping-dump {
type = file
file = /participant-bootstrapping-dump/content
new-participant-identifier = "validator-fooooooo"
}
-
set contact point
spec:
config:
contactPoint: "mycompany@mail.com"