Search…
⌃K

Best Practices

Integrating Helm

When working with Helm you can keep your Velocity configuration in a separate Helm Values file. Then, before importing to Velocity, you need to generate K8s YAML files that include Velocity annotations and templates.
A typical Helm setup includes:
  1. 1.
    A Helm chart that specifies the basic application configurations. The chart must include an added section that enables overriding annotations from a separate Values file, as seen in the example below.
  2. 2.
    A Values file with all the production configurations that is used when deploying to production
  3. 3.
    A Values file for Velocity, which overrides your production configurations with dev/test configurations. This file will include the added Velocity annotations and templates.

Generating K8s resource files for Velocity

With the above setup, running the following command will create a template from the Helm Chart, inject the production configuration, and add the required values for Velocity. resulting in a K8s resource file that can be read by Velocity.
helm template <chart name> -f values/prod.yaml -f values/velocity.yaml

Example: A Helm Chart that specifies the basic application configurations.

Pay attention to lines 5-8 which enable overriding annotations from a separate Values file.
1
apiVersion: apps/v1
2
kind: Deployment
3
metadata:
4
name: {{ include "chart.fullname" . }}
5
{{- with .Values.annotations }}
6
annotations:
7
{{- toYaml . | nindent 4 }}
8
{{- end }}
9
spec:
10
selector:
11
matchLabels:
12
{{- include "chart.selectorLabels" . | nindent 6 }}
13
template:
14
metadata:
15
{{- with .Values.podAnnotations }}
16
annotations:
17
{{- toYaml . | nindent 8 }}
18
{{- end }}
19
spec:
20
containers:
21
- name: {{ .Chart.Name }}
22
securityContext:
23
{{- toYaml .Values.securityContext | nindent 12 }}
24
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
25
imagePullPolicy: {{ .Values.image.pullPolicy }}
26
envFrom:
27
- secretRef:
28
name: db-credentials
29
optional: false
30
env:
31
- name: SECRET_KEY_BASE
32
value: {{ .Values.secretKeyBase | quote}}
33
- name: RESULT_CREATE_TOKEN
34
value: {{ .Values.authToken | quote}}
35
- name: CALLBACK_URL
36
value: {{ .Values.callbackUrl | quote}}
37
- name: MYSQL_DATABASE_URL
38
value: {{ .Values.mysqlDbUrl | quote}}
39
- name: POSTGRES_DATABASE_URL
40
value: {{ .Values.postgresDbUrl | quote}}
41
- name: ANALYTICS_URL
42
value: {{ .Values.analyticsUrl | quote}}
43
- name: REDIS_URL
44
value: {{ .Values.redisUrl | quote}}
45
ports:
46
- name: http
47
containerPort: 3000
48
protocol: TCP
49
---
50
apiVersion: v1
51
kind: Secret
52
metadata:
53
name: db-credentials
54
annotations:
55
velocity.tech.v1/dependsOn: postgres # Velocity dependencies declaration
56
type: Opaque
57
data:
58
DB_USER: {{ .Values.postgres_user | b64enc }}
59
DB_PASSWORD: {{ .Values.postgres_pass | b64enc }}

A Values file for Velocity

annotations:
velocity.tech.v1/id: backend
velocity.tech.v1/dependsOn: mysql-database, postgres
env:
SECRET_KEY_BASE: "{velocity.v1.generate:random}"
RESULT_CREATE_TOKEN: "{velocity.v1.generate:random}"
CALLBACK_URL: "{velocity.v1:backend.exposures(port=http).public.uri}"
MYSQL_DATABASE_URL: "{velocity.v1:mysql-database.exposures(port=mysqlport).uri}/{velocity.v1:mysql-database.exports.dbname}"
ANALYTICS_URL: "{velocity.v1:analytics.exposures(port=analyticsport).uri}"
REDIS_URL: "{velocity.v1:backend-cache.exposures(port=redisport).uri}"
POSTGRES_DATABASE_URL: "{velocity.v1:postgres.exposures(port=postgresport).uri}"
postgres_user: "{velocity.v1:postgres.exposures(port=postgresport).user}"
postgres_pass: "{velocity.v1:postgres.exposures(port=postgresport).password}"

Dry Run

The veloctl env create command accepts a --dry-run flag that will allow you to validate your Velocity blueprints without actually creating an environment.

Example usage:

veloctl env create -f <resource.yml> --dry-run
In the above, we are passing a single k8s YAML file to the veloctl env create command with the -f argument, which will create an environment in Velocity that contains any Velocity Services defined within the k8s YAML definition.
This command can be used in conjunction with tools like Helm or Kustomize by piping the output of calls to these tools into a construction like you see above, so that you only need to execute a single command to validate all of the Velocity blueprints included in your project, like so:
helm template <path/to/chart/dir> --values <path/to/velocity-values.yml> | veloctl env create -f - --dry-run
In addition to validating your Velocity blueprints, the --dry-run flag will also provide you with a wealth of information about your specific Velocity environment, including example autogenerated properties and properties associated with specific Velocity services being validated.

Example output:

Unassociated Resources
Kind Name Validation Depends On
ConfigMap configmap Valid
Velocity Resources
Kind Name Validation Depends On
Velocity Service mongo Valid
├─ Service mongodb Valid
└─ Deployment.apps mongodb Valid
Auto-generated properties
Use properties by placing them in templates and embedding them in your deployment files
Syntax: {velocity.v1.<Property>}
Example: {velocity.v1.envName}
Property Resulted Value
aws.accountID **************
aws.region eu-central-1
domainName viron.dev
domainSuffix fearful-hex.viron.dev
envName fearful-hex
gcp.projectName viron-dev
gcp.zone europe-west2-b
tlsSecretName wildcard-cert
test Test
Velocity Service properties
Use properties by placing them in templates and embedding them in your deployment files
Syntax: `{velocity.v1:<Velocity Service>.<Property>}`
Example: `{velocity.v1:server.exposures(port=tcp).host}`
Velocity Service Property Resulted Value
mongo exposures(port=tcp).user root
exposures(port=tcp).password password1234
exposures(port=tcp).host mongodb
exposures(port=tcp).port 27017
exposures(port=tcp).scheme mongodb
exposures(port=tcp).uri mongodb://root:[email protected]:27017
Debug Information
- Overriding deployment `mongodb`'s replica count to `1`
- Overriding deployment `mongodb`'s strategy type to `Recreate`
Success

Understanding --dry-run output:

Unassociated Resources: here, you will find any k8s resources included in your Helm chart that do not include a Velocity ID, and are thus not counted as Velocity services. Items listed here are not necessarily indicative of an error, although it is important to note that Velocity will not be able to access any parameters defined within these specific resource definitions.
Velocity Resources: a list of Velocity services, and their underlying Kubernetes resources.
Auto-generated Properties: a list of accessible properties derived from your Velocity environment that can be accessed dynamically via Velocity Templates.
Velocity Service Properties: a list of accessible properties exposed via Velocity Annotations within specific Velocity Services.
Debug information: Velocity enforces certain rules at environment creation, such as reducing the number of replicas of a given k8s resource to 1 so as to minimize cloud resource consumption during development. When rules such as these are applied, they will be listed here.

Troubleshooting invalid configuration using --dry-run output:

As shown in the following example, --dry-run output will include references to specific files that contain configuration errors, such as missing dependencies, along with suggested corrections.

Template Output

The veloctl env create command also accepts a --template flag, which will output the Kubernetes resources that will be applied to the cluster (after resolving the velocity templates) when creating the environment.

Example usage:

veloctl env create -f <resource.yml> --template
This should help to debug the resulting Velocity template and ensure that any included annotations are being resolved to the right expression format and structure.

Example input resource.yml:

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
name: backend-ingress
spec:
rules:
- host: "backend-{velocity.v1.domainSuffix}"
http:
paths:
- backend:
service:
name: viron-backend
port:
number: 80
path: /
pathType: Prefix
tls:
- hosts:
- "backend-{velocity.v1.domainSuffix}"
secretName: wildcard-cert

Example output:

veloctl env create -f resource.yml --template
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
checksum/velocity-hash: 2a680504423617985d7cbf11f7b7b90ed30172f3af0cc9d285f1a8bccfc36197
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
creationTimestamp: null
name: backend-ingress
spec:
rules:
- host: backend-scared-doctor-doom.viron.dev
http:
paths:
- backend:
service:
name: viron-backend
port:
number: 80
path: /
pathType: Prefix
tls:
- hosts:
- backend-scared-doctor-doom.viron.dev
secretName: wildcard-cert
status:
loadBalancer: {}