Home / Keptn v1 Docs / Release 0.19.x / Custom Integrations / Write a Keptn-service
Here you learn how to add additional functionality to your Keptn installation with a custom Keptn-service, SLI-provider, or Action-provider.
A template for writing a new Keptn-service is provided here: keptn-service-template-go. Please note that the master branch of this repository might represent a development state. Check out the releases page and download the code for a release that’s compatible with the Keptn version for which you are developing.
Since a Keptn-service is a Kubernetes service with a deployment and service template, the deployment manifest in the template repository can be re-used; see deploy/service.yaml.
This deployment manifest contains:
A Keptn-service has the following characteristics:
Your Keptn-service must have a subscription to at least one Keptn CloudEvent. The event type to subscribe to looks like:
sh.keptn.event.[task].triggered
In this example, [task]
works as a placeholder for tasks such as: deployment
, test
, evaluation
, remediation
, etc. The task defines the topic the Keptn-service is interested in. Assuming you are writing a Keptn-service for testing, the event type would be: sh.keptn.event.test.triggered
.
Distributor:
sh.keptn.event.[task].triggered
event, a distributor with PUBSUB_TOPIC
set to the specific event type is required, see example below. Alternatively, a default distributor listening to all events (e.g., PUBSUB_TOPIC: sh.keptn.>
) is provided in the deployment manifest of the keptn-service-template-go template (see deploy/service.yaml).The PUBSUB_TOPIC
variable sets the initial subscription for your service. If a subscription has been modified through the Bridge, Keptn prioritizes this information and it discards the value of PUBSUB_TOPIC
. Please, look at the Bridge paragraph later on this page for more information on the subject.
spec:
containers:
- name: distributor
image: keptn/distributor:0.19.3
ports:
- containerPort: 8080
resources:
requests:
memory: "16Mi"
cpu: "25m"
limits:
memory: "128Mi"
cpu: "250m"
env:
- name: PUBSUB_URL
value: 'nats://keptn-nats-cluster'
- name: PUBSUB_TOPIC
value: 'sh.keptn.event.test.triggered'
- name: PUBSUB_RECIPIENT
value: '127.0.0.1'
In addition to forwarding received events for the subscribed topic to the Keptn-service, the distributor also provides the feature to act as a proxy to the Keptn API. Using this feature, the following Keptn API services are reachable for the Keptn-service via the following URLs, if the distributor runs within the same K8s pod as the Keptn-service:
Mongodb-datastore:
http://localhost:8081/mongodb-datastore
Configuration-service:
http://localhost:8081/configuration-service
Shipyard-controller:
http://localhost:8081/controlPlane
To configure this distributor for your Keptn-service, the following environment variables can be adapted. However, in most scenarios only a subset of them needs to be configured. The full list of environment variables is as follows:
Environment variable | Description | Default Value |
---|---|---|
KEPTN_API_ENDPOINT | Keptn API Endpoint - needed when the distributor runs outside of the Keptn cluster | "" |
KEPTN_API_TOKEN | Keptn API Token - needed when the distributor runs outside of the Keptn cluster | "" |
API_PROXY_PORT | Port on which the distributor will listen for incoming Keptn API requests by its execution plane service | 8081 . |
API_PROXY_PATH | Path on which the distributor will listen for incoming Keptn API requests by its execution plane service | / . |
HTTP_POLLING_INTERVAL | Interval (in seconds) in which the distributor will check for new triggered events on the Keptn API | 10 |
EVENT_FORWARDING_PATH | Path on which the distributor will listen for incoming events from its execution plane service | /event |
HTTP_SSL_VERIFY | Determines whether the distributor should check the validity of SSL certificates when sending requests to a Keptn API endpoint via HTTPS | true |
PUBSUB_URL | The URL of the nats cluster the distributor should connect to when the distributor is running within the Keptn cluster | nats://keptn-nats-cluster |
PUBSUB_TOPIC | Comma separated list of topics (i.e. event types) the distributor should listen to | "" |
PUBSUB_RECIPIENT | Hostname of the execution plane service the distributor should forward incoming CloudEvents to | http://127.0.0.1 |
PUBSUB_RECIPIENT_PORT | Port of the execution plane service the distributor should forward incoming CloudEvents to | 8080 |
PUBSUB_RECIPIENT_PATH | Path of the execution plane service the distributor should forward incoming CloudEvents to | / |
DISABLE_REGISTRATION | Disables automatic registration of the Keptn integration to the control plane. | false |
REGISTRATION_INTERVAL | Time duration between trying to re-register to the Keptn control plane. | 10s |
LOCATION | Location the distributor is running on, e.g. “executionPlane-A”. | "" |
DISTRIBUTOR_VERSION | The software version of the distributor. | "" |
VERSION | The version of the Keptn integration. | "" |
K8S_DEPLOYMENT_NAME | Kubernetes deployment name of the Keptn integration. | "" |
K8S_POD_NAME | Kubernetes deployment name of the Keptn integration. | "" |
K8S_NAMESPACE | Kubernetes namespace of the Keptn integration. | "" |
K8S_NODE_NAME | Kubernetes node name the Keptn integration is running on. | "" |
PROJECT_FILTER | Filter events for a specific project, supports a comma-separated list of projects. | "" |
STAGE_FILTER | Filter events for a specific stage, supports a comma-separated list of stages. | "" |
SERVICE_FILTER | Filter events for a specific service, supports a comma-separated list of services. | "" |
The above list of environment variables is pretty long, but in most scenarios only a few of them have to be set. The following examples show how to set the environment variables properly, depending on where the distributor and it’s accompanying execution plane service should run:
Environment variable | Setting |
---|---|
PUBSUB_RECIPIENT | Host name of the Keptn-service. |
PUBSUB_RECIPIENT_PORT | Service port to receive the event (default: 8080 ) |
PUBSUB_RECIPIENT_PATH | Service endpoint to receive the event (default: / ) |
PUBSUB_TOPIC | Event(s) the Keptn-service is subscribed to. To subscribe to multiple events, declare a comma-separated list, e.g.: sh.keptn.event.test.triggered, sh.keptn.event.evaluation.triggered |
If your Keptn-service is running in the same pod as the distributor (which we recommend), and receives events at the port 8080
and the path /
, you will only need to set the PUBSUB_TOPIC
environment variable.
Environment variable | Setting |
---|---|
KEPTN_API_ENDPOINT | The endpoint of the Keptn API, e.g. https://my-keptn.dev/api |
KEPTN_API_TOKEN | Keptn API token |
HTTP_POLLING_INTERVAL | Polling interval in seconds |
PUBSUB_RECIPIENT | Host name of the Keptn-service |
PUBSUB_RECIPIENT_PORT | Service port to receive the event (default: 8080 ) |
PUBSUB_RECIPIENT_PATH | Service endpoint to receive the event (default: / ) |
PUBSUB_TOPIC | Event(s) the Keptn-service is subscribed to. To subscribe to multiple events, declare a comma-separated list, e.g.: sh.keptn.event.test.triggered, sh.keptn.event.evaluation.triggered |
If your Keptn-service is running in the same pod as the distributor (which we recommend), and receives events at the port 8080
and the path /
, you will only need to set the PUBSUB_TOPIC
environment variable.
Bridge:
After the application is deployed, its subscription can be changed directly in the Bridge.
For this, open Keptn Bridge, select a project, and go to the Uniform page.
Then select your service, and click the Add subscription
button.
In this form, you can provide the information for the task subscription:
test
or deployment
)triggered
, started
, of finished
Note: multiple subscriptions can be added for the same service.
Keptn stores this subscriptions information even if the integration is not running.
By default, Keptn keeps this information for 48h after the last contact with the integration.
This time value can be configured using the Helm value shipyardController.config.uniformIntegrationTTL
.
After receiving a triggered
event for a particular task, your Keptn-service must inform Keptn by sending an event of the type:
sh.keptn.event.[task].started
The request body needs to follow the CloudEvent specification and the HTTP header attribute Content-Type
has to be set to application/cloudevents+json
.
Send the event:
The event can be sent to Keptn in either of the following ways:
v1/event
endpoint of Keptn127.0.0.1:8081
The functionality of your Keptn-service depends on the capability you want to add to the continuous delivery or operational workflow. In many cases, the event payload – containing meta-data such as the project, stage, or service name – is first processed and then used to call the REST API of another tool.
After your Keptn-service has completed its functionality, it has to inform Keptn by sending an event of the type:
sh.keptn.event.[task].finished
The request body must follow the CloudEvent specification and the HTTP header attribute Content-Type
must be set to application/cloudevents+json
.
Add property to event header:
Add to the header of the event:
triggeredid
: The value of this property is the id
of the sh.keptn.event.[task].triggered
event.Add data to event payload:
You can send data back to Keptn by adding it to the data block in the event payload. In more details, the data block has a reserved space depending on the event type. If, for example, your Keptn service has a subscription to a sh.keptn.event.test.finished
event, the reserved space is data.test
. Your Keptn-service is allowed to add data there, but must provide at least a value for status
and result
:
status
: [succeeded, errored, unknown] - The status of the task execution.result
: [pass, failed] - The result of a successful task execution.{
"type": "sh.keptn.event.test.finished",
"specversion": "1.0",
"source": "https://github.com/keptn/keptn/jmeter-service",
"id": "ggb878d3-03c0-4e8f-bc3f-454bc1b3d888",
"time": "2019-06-07T07:02:15.64489Z",
"contenttype": "application/json",
"shkeptncontext": "08735340-6f9e-4b32-97ff-3b6c292bc509",
"triggeredid" : "f2b878d3-03c0-4e8f-bc3f-454bc1b3d79d",
"data": {
"test": {
"status": "succeeded",
"result": "pass"
},
"project": "sockshop",
"stage": "staging",
"service": "carts",
"labels": {
"testId": "4711",
"buildId": "build-17",
"owner": "JohnDoe"
}
}
}
Send the event:
The event can be sent to Keptn, in either of the following ways:
v1/event
endpoint of Keptn127.0.0.1:8081
Distributor: To subscribe your service to a Keptn event, a distributor is required. A distributor is part of the above mentioned deployment manifest and shown by the example below:
spec:
selector:
matchLabels:
run: distributor
replicas: 1
template:
metadata:
labels:
run: distributor
spec:
containers:
- name: distributor
image: keptn/distributor:0.19.3
ports:
- containerPort: 8080
resources:
requests:
memory: "16Mi"
cpu: "25m"
limits:
memory: "128Mi"
cpu: "250m"
env:
- name: PUBSUB_URL
value: 'nats://keptn-nats-cluster'
- name: PUBSUB_TOPIC
value: 'sh.keptn.event.deployment.finished'
- name: PUBSUB_RECIPIENT
value: '127.0.0.1'
- name: VERSION
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: 'metadata.labels[''app.kubernetes.io/version'']'
- name: K8S_DEPLOYMENT_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: 'metadata.labels[''app.kubernetes.io/name'']'
- name: K8S_POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: K8S_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: K8S_NODE_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
To configure this distributor for your Keptn-service, two environment variables need to be adapted:
PUBSUB_RECIPIENT
: Defines the service address as specified in the Kubernetes service manifest (e.g., 127.0.0.1 or jmeter-service)PUBSUB_TOPIC
: Defines the event type your Keptn-service is listening to (e.g. sh.keptn.event.test.triggered
or sh.keptn.event.>
).With a service and deployment manifest for your custom Keptn-service (service.yaml
), you are ready to deploy both components in the K8s cluster where Keptn is installed:
kubectl apply -f service.yaml -n keptn
CloudEvents must be sent with the HTTP header Content-Type
set to application/cloudevents+json
. For a detailed look into CloudEvents, please go the Keptn CloudEvent specification.
By default, the distributor automatically extracts error logs from received sh.keptn.<task>.finished
events with data.status=errored
and/or data.result=fail
, that have been sent by your service. These error messages are then forwarded to Keptn’s Log Ingestion API.
Additionally, for easier debugging of errors that occur either during the execution of a task of a sequence, or while performing any other operation, Keptn integration services can send error log events to the Keptn API via the distributor. Examples for those events are listed below.
If the error log event is associated with the execution of a specific task that has been triggered by a sh.keptn.event.<task>.triggered
event, the following properties must be set in order to correlate them to the correct task sequence execution:
shkeptncontext
: The context of the task sequence execution. Can be adapted from the received sh.keptn.event.<task>.triggered
eventtriggeredid
: The id
of the received sh.keptn.event.<task>.triggered
eventdata.task
: The name of the executed task.data.message
: The message you would like to logExample event payload
{
"specversion": "1.0",
"id": "c4d3a334-6cb9-4e8c-a372-7e0b45942f53",
"source": "source-service",
"type": "sh.keptn.log.error",
"datacontenttype": "application/json",
"data": {
"message": "an unexpected error occurred during the execution of my task",
"task": "deployment"
},
"triggeredid": "3f9640b6-1d2a-4f11-95f5-23259f1d82d6",
"shkeptncontext": "a3e5f16d-8888-4720-82c7-6995062905c1",
"shkeptnspecversion": "0.2.3"
}
If the error log event is not associated with an execution of a specific task, the properties shkeptncontext
, triggeredid
, and data.task
are not required. In this case, an example payload would look as follows:
{
"specversion": "1.0",
"id": "c4d3a334-6cb9-4e8c-a372-7e0b45942f53",
"source": "source-service",
"type": "sh.keptn.log.error",
"datacontenttype": "application/json",
"shkeptnspecversion": "0.2.3",
"data": {
"message": "an unexpected error occurred during the execution of my task",
"task": "deployment"
}
}