11 KiB
| title | weight | state | alphaVersion |
|---|---|---|---|
| Get Started With Operations | 300 | alpha | 2.0 |
This guide shows how to use Crossplane Operations to automate day-two
operational tasks. You create an Operation that checks SSL certificate
expiry for a website.
Crossplane calls this Operations. Operations run function pipelines to perform tasks that don't fit the typical resource creation pattern - like certificate monitoring, rolling upgrades, or scheduled maintenance.
An Operation looks like this:
apiVersion: ops.crossplane.io/v1alpha1
kind: Operation
metadata:
name: check-cert-expiry
spec:
mode: Pipeline
pipeline:
- step: check-certificate
functionRef:
name: crossplane-contrib-function-python
input:
apiVersion: python.fn.crossplane.io/v1beta1
kind: Script
script: |
import ssl
import socket
from datetime import datetime
from crossplane.function import request, response
def operate(req, rsp):
hostname = "google.com"
port = 443
# Get SSL certificate info
context = ssl.create_default_context()
with socket.create_connection((hostname, port)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
cert = ssock.getpeercert()
# Parse expiration date
expiry_date = datetime.strptime(cert['notAfter'], '%b %d %H:%M:%S %Y %Z')
days_until_expiry = (expiry_date - datetime.now()).days
# Return results in operation output
response.set_output(rsp, {
"hostname": hostname,
"certificateExpires": cert['notAfter'],
"daysUntilExpiry": days_until_expiry,
"status": "warning" if days_until_expiry < 30 else "ok"
})
The Operation runs once to completion, like a Kubernetes Job.
When you create the Operation, Crossplane runs the function pipeline. The
function checks SSL certificate expiry for google.com and returns the results
in the operation's output.
This basic example shows the concept. In the walkthrough below, you create
a more realistic Operation that reads Kubernetes Ingress resources and
annotates them with certificate expiry information for monitoring tools.
Prerequisites
This guide requires:
- A Kubernetes cluster with at least 2 GB of RAM
- The Crossplane v2 preview [installed on the Kubernetes cluster]({{<ref "install">}}) with Operations enabled
{{<hint "tip">}}
Enable Operations by adding --enable-operations to Crossplane's startup
arguments. If using Helm:
helm upgrade --install crossplane crossplane-stable/crossplane \
--namespace crossplane-system \
--set args='{"--enable-operations"}'
{{}}
Create an operation
Follow these steps to create your first Operation:
- Create a sample Ingress for certificate checking
- Install the function you want to use for the operation
- Create the Operation that checks the
Ingress - Check the Operation as it runs
Create a sample Ingress
Create an Ingress that references a real hostname but doesn't route actual
traffic:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-app
namespace: default
spec:
rules:
- host: google.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nonexistent-service
port:
number: 80
Save as ingress.yaml and apply it:
kubectl apply -f ingress.yaml
Grant Ingress permissions
Operations need permission to access and change Ingresses. Create a ClusterRole
that grants Crossplane access to Ingresses:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: operations-ingress-access
labels:
rbac.crossplane.io/aggregate-to-crossplane: "true"
rules:
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list", "watch", "patch", "update"]
Save as ingress-rbac.yaml and apply it:
kubectl apply -f ingress-rbac.yaml
Install the function
Operations use operation functions to implement their logic. Use the Python function, which supports both composition and operations.
Create this function to install Python support:
apiVersion: pkg.crossplane.io/v1
kind: Function
metadata:
name: crossplane-contrib-function-python
spec:
package: xpkg.crossplane.io/crossplane-contrib/function-python:v0.2.0
Save the function as function.yaml and apply it:
kubectl apply -f function.yaml
Check that Crossplane installed the function:
kubectl get -f function.yaml
NAME INSTALLED HEALTHY PACKAGE AGE
crossplane-contrib-function-python True True xpkg.crossplane.io/crossplane-contrib/function-python:v0.2.0 12s
Create the operation
Create this Operation that monitors the Ingress certificate:
apiVersion: ops.crossplane.io/v1alpha1
kind: Operation
metadata:
name: ingress-cert-monitor
spec:
mode: Pipeline
pipeline:
- step: check-ingress-certificate
functionRef:
name: crossplane-contrib-function-python
requirements:
requiredResources:
- requirementName: ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
name: example-app
namespace: default
input:
apiVersion: python.fn.crossplane.io/v1beta1
kind: Script
script: |
import ssl
import socket
from datetime import datetime
from crossplane.function import request, response
def operate(req, rsp):
# Get the Ingress resource
ingress = request.get_required_resource(req, "ingress")
if not ingress:
response.set_output(rsp, {"error": "No ingress resource found"})
return
# Extract hostname from Ingress rules
hostname = ingress["spec"]["rules"][0]["host"]
port = 443
# Get SSL certificate info
context = ssl.create_default_context()
with socket.create_connection((hostname, port)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
cert = ssock.getpeercert()
# Parse expiration date
expiry_date = datetime.strptime(cert['notAfter'], '%b %d %H:%M:%S %Y %Z')
days_until_expiry = (expiry_date - datetime.now()).days
# Add warning if certificate expires soon
if days_until_expiry < 30:
response.warning(rsp, f"Certificate for {hostname} expires in {days_until_expiry} days")
# Annotate the Ingress with certificate expiry info
rsp.desired.resources["ingress"].resource.update({
"apiVersion": "networking.k8s.io/v1",
"kind": "Ingress",
"metadata": {
"name": ingress["metadata"]["name"],
"namespace": ingress["metadata"]["namespace"],
"annotations": {
"cert-monitor.crossplane.io/expires": cert['notAfter'],
"cert-monitor.crossplane.io/days-until-expiry": str(days_until_expiry),
"cert-monitor.crossplane.io/status": "warning" if days_until_expiry < 30 else "ok"
}
}
})
# Return results in operation output for monitoring
response.set_output(rsp, {
"ingressName": ingress["metadata"]["name"],
"hostname": hostname,
"certificateExpires": cert['notAfter'],
"daysUntilExpiry": days_until_expiry,
"status": "warning" if days_until_expiry < 30 else "ok"
})
Save the operation as operation.yaml and apply it:
kubectl apply -f operation.yaml
Check the operation
Check that the Operation runs successfully:
kubectl get -f operation.yaml
NAME SYNCED SUCCEEDED AGE
ingress-cert-monitor True True 15s
{{<hint "tip">}}
Operations show SUCCEEDED=True when they complete successfully.
{{}}
Check the Operation's detailed status:
kubectl describe operation ingress-cert-monitor
# ... metadata ...
Status:
Conditions:
Last Transition Time: 2024-01-15T10:30:15Z
Reason: PipelineSuccess
Status: True
Type: Succeeded
Last Transition Time: 2024-01-15T10:30:15Z
Reason: ValidPipeline
Status: True
Type: ValidPipeline
Pipeline:
Output:
Certificate Expires: Sep 29 08:34:02 2025 GMT
Days Until Expiry: 54
Hostname: google.com
Ingress Name: example-app
Status: ok
Step: check-ingress-certificate
{{<hint "tip">}}
The status.pipeline field shows the output returned by each function step.
Use this field for tracking what the operation accomplished.
{{}}
Check that the Operation annotated the Ingress with certificate information:
kubectl get ingress example-app -o yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-monitor.crossplane.io/days-until-expiry: "54"
cert-monitor.crossplane.io/expires: Sep 29 08:34:02 2025 GMT
cert-monitor.crossplane.io/status: ok
name: example-app
namespace: default
spec:
# ... ingress spec ...
{{<hint "tip">}}
This pattern shows how Operations can both read and change existing Kubernetes
resources. The Operation annotated the Ingress with certificate expiry
information that other tools can use for monitoring and alerting.
{{}}
Clean up
Delete the resources you created:
kubectl delete -f operation.yaml
kubectl delete -f ingress.yaml
kubectl delete -f ingress-rbac.yaml
kubectl delete -f function.yaml
Next steps
Operations are powerful building blocks for operational workflows. Learn more
about:
- [
Operationconcepts]({{<ref "../operations/operation">}}) - CoreOperationfeatures and best practices - [
CronOperation]({{<ref "../operations/cronoperation">}}) - Schedule operations to run automatically - [
WatchOperation]({{<ref "../operations/watchoperation">}}) - Trigger operations when resources change
Explore the complete [Operations documentation]({{<ref "../operations">}}) for advanced features and examples.