Custom Event Hooks
Velocity's Run Policy annotation allows users to hook a custom execution to environment creation, update, and destruction.
These custom events are defined as Kubernetes Jobs. By default, a K8s Job will run only once -- upon environment creation.
However, you can change this default behavior and trigger a custom event on environment creation and update with the
velocity.tech.v1/runPolicy:always
annotation. You can also run any clean-up action either immediately before or after your environment's services are torn down with the
velocity.tech.v1/runPolicy: destroy/beforeAll
and velocity.tech.v1/runPolicy: destroy/afterAll
annotations respectfully. To demonstrate this functionality, we'll create an AWS Cloudfront distribution, which will be tied to a Velocity environment but will exist outside the scope of the environment. Then, we will ensure that this Cloudfront distribution is torn down when the associated environment is destroyed with a K8s Job that includes the
velocity.tech.v1/runPolicy
annotation. NOTE: this functionality can extend to any resource you'd like to associate with your Velocity environment creation, update or destroy actions.
Prerequisites:
Update your AWS IAM with the following:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl",
"cloudfront:GetDistribution",
"cloudfront:ListDistributions",
"cloudfront:UpdateDistribution",
"cloudfront:CreateDistribution",
"cloudfront:GetDistributionConfig",
"cloudfront:DeleteDistribution"
],
"Resource": "*"
}
]
}
Create the environment:
veloctl env create -f https://raw.githubusercontent.com/techvelocity/velocity-blueprints/main/examples/custom-event-hooks.yaml

As shown above, we are creating three distinct K8s Jobs and one S3 Bucket.
job-seed-s3
will upload our example HTML and CSS files into the bucket. job-init-cloudfront
will create the Cloudfront distribution that will serve the uploaded files, and job-cleanup-cloudfront
contains the custom cleanup hook that will be triggered at environment destruction.The following YAML manifests will be applied to your Velocity environment.
First, there is an S3 bucket that will store the data that the Cloudfront distribution will serve.
apiVersion: s3.services.k8s.aws/v1alpha1
kind: Bucket
metadata:
annotations:
velocity.tech.v1/id: bucket # Velocity service identifier
velocity.tech.v1/exports-bucket-name: path="spec.name" # Velocity annotation to export the bucket name for other services to use
name: "{velocity.v1.generate:cloudResourcePrefix(seed=bucket)}-{velocity.v1.envName}-demo-bucket"
spec:
name: "{velocity.v1.generate:cloudResourcePrefix(seed=bucket)}-{velocity.v1.envName}-demo-bucket"
Next, we have a Job that will seed the S3 bucket with data that we'll pass as a K8s configMap.
kind: ConfigMap
apiVersion: v1
metadata:
name: configmap-seed-s3
data:
index.html: <!DOCTYPE html>
<html lang="en">
<head>
<title>Hello world!</title>
<meta charset="utf-8">
<link rel="stylesheet" href="./style.css"/>
</head>
<body>
<h1>Hello world!</h1>
</body>
</html>
style.css: |
body {
background: #236192;
font-family: Helvetica, Arial, sans-serif;
color: #ffffff;
max-width: 75em;
margin: 0 auto;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
}
---
apiVersion: batch/v1
kind: Job
metadata:
name: job-seed-s3
annotations:
velocity.tech.v1/id: job-seed-s3 # Velocity service identifier
velocity.tech.v1/dependsOn: bucket # Velocity dependencies declaration
spec:
template:
metadata:
name: job-seed-s3
spec:
restartPolicy: Never
containers:
- name: "seed-s3"
image: amazon/aws-cli
command: [/bin/bash, -c]
args:
- |
aws s3 cp /scripts/index.html s3://$(echo $BUCKET_NAME)/index.html \
--acl public-read && \
aws s3 cp /scripts/style.css s3://$(echo $BUCKET_NAME)/style.css --acl public-read
envFrom:
- secretRef:
name: aws-cred-developer
env:
- name: BUCKET_NAME
value: "{velocity.v1:bucket.exports.bucket-name}"
- name: AWS_REGION
value: "{velocity.v1.aws.region}"
volumeMounts:
- mountPath: /scripts
name: seed-s3-vol
volumes:
- name: seed-s3-vol
configMap:
name: configmap-seed-s3 name: configmap-seed-s3
The
envFrom.secretRef
value holds a set of keys that denote en vars for the AWS cli to pickup -- specifically, your AWS secret key, access key and session token. Next, there is a K8s Job that will create the Cloudfront distribution.
apiVersion: batch/v1
kind: Job
metadata:
name: job-init-cloudfront
annotations:
velocity.tech.v1/id: job-init-cloudfront # Velocity service identifier
velocity.tech.v1/dependsOn: bucket # Velocity dependencies declaration
spec:
template:
metadata:
name: job-init-cloudfront
spec:
restartPolicy: Never
containers:
- name: "init-cloudfront"
image: amazon/aws-cli
command: ["/bin/bash", "-c"]
args:
- |-
set -e
yum install jq -y
echo "Creating cloudfront distribution with an S3 bucket origin..."
ORIGIN_DOMAIN_NAME=$BUCKET_NAME.s3.eu-central-1.amazonaws.com
aws cloudfront create-distribution \
--origin-domain-name $ORIGIN_DOMAIN_NAME \
--default-root-object index.html > distribution.json
echo "Deploying Cloudfront Distribution..."
DIST_ID=$(cat distribution.json | jq -r '.Distribution.Id')
aws cloudfront wait distribution-deployed --id $DIST_ID
echo "Cloudfront Distribution deployed successfully"
envFrom:
- secretRef:
name: aws-cred-developer
env:
- name: BUCKET_NAME
value: "{velocity.v1:bucket.exports.bucket-name}"
- name: AWS_REGION
value: "{velocity.v1.aws.region}"
Finally, there is a K8s Job that will tear down the Cloudfront distribution on environment destruction.
apiVersion: batch/v1
kind: Job
metadata:
name: job-cleanup-cloudfront
annotations:
velocity.tech.v1/id: job-cleanup-cloudfront # Velocity service identifier
velocity.tech.v1/dependsOn: bucket # Velocity dependencies declaration
velocity.tech.v1/runPolicy: destroy/afterAll
spec:
template:
metadata:
name: job-cleanup-cloudfront
spec:
restartPolicy: Never
containers:
- name: "cleanup-cloudfront"
image: amazon/aws-cli
command: ["/bin/bash", "-c"]
args:
- |-
set -e
yum install jq -y
echo "Disabling Cloudfront Distribution..."
QUERY="(DistributionList.Items[].{ID: Id, OriginDomainName: Origins.Items[0].DomainName}[?contains(OriginDomainName, '$BUCKET_NAME')] | [0]).ID"
CF_ID=$(aws cloudfront list-distributions --query "$QUERY" --output text)
aws cloudfront get-distribution-config --id $CF_ID > config.json
cat config.json | jq '.DistributionConfig | .Enabled = false' > disabled-config.json
CF_ETAG=$(cat config.json | jq -r '.ETag')
aws cloudfront update-distribution --id $CF_ID --if-match $CF_ETAG \
--distribution-config "file://$(pwd)/disabled-config.json" > disabled-config-res.json
echo "Waiting for Cloudfront Distribution to be ready for deletion..."
aws cloudfront wait distribution-deployed --id $CF_ID
echo "Destroying Cloudfront Distribution..."
CF_ETAG_DISABLED=$(cat disabled-config-res.json | jq -r '.ETag')
aws cloudfront delete-distribution --id $CF_ID --if-match $CF_ETAG_DISABLED
echo "Finished destroying Cloudfront Distribution"
envFrom:
- secretRef:
name: aws-cred-developer
env:
- name: BUCKET_NAME
value: "{velocity.v1:bucket.exports.bucket-name}"
- name: AWS_REGION
value: "{velocity.v1.aws.region}"
When we run the following command, the above custom event hook,
job-cleanup-cloudfront
, will be kicked off after all services in the environment have been torn down, because it includes the velocity.tech.v1/runPolicy: destroy/afterAll
annotation.veloctl env destroy
Custom events in Velocity are defined as Kubernetes Jobs. By default, Jobs will run once upon environment creation. However, this default behavior can be modified with the
velocity.tech.v1/runPolicy:
annotation, such that custom events can be triggered at event creation, update, and destruction as needed. Last modified 2mo ago