Packaging an Operator
This guide extends on Packaging an Application, with the goal to package and deploy an Kubernetes Operator using the Package Operator - ClusterPackage API.
During this guide you will:
- Create a
manifest.yaml
file - Use multiple PKO phases
- Build and Validate the Package Operator package
To complete this guide you will need:
- A Kubernetes cluster with Package Operator installed
- The
kubectl-package
CLI plugin - Access to a container registry where you can push your images
All files used during this guide are available in the package-operator/examples repository.
1. Start
Please refer to the files in /2_operators/1_start
for this step.
Writing a PackageManifest
Operators are always installed for the whole cluster, so the package is also scoped for the cluster.
spec:
scopes:
- Cluster
Operators require distinct order-of-operations to successfully install.
The phases list represents these steps.
CustomResourceDefinitions
have no pre-requisites, so they come first.Namespaces
also has no dependencies.ServiceAccount
andRoleBinding
need theNamespace
Deployment
needs all of the above.
spec:
phases:
- name: crds
- name: namespace
- name: rbac
- name: deploy
Probes define how Package Operator interrogates objects under management for status.
For this operator we want to add a new probe to ensure the CRDs have been established.
spec:
availabilityProbes:
- probes:
- condition:
type: Available
status: "True"
- fieldsEqual:
fieldA: .status.updatedReplicas
fieldB: .status.replicas
selector:
kind:
group: apps
kind: Deployment
- probes:
- condition:
type: Established
status: "True"
selector:
kind:
group: apiextensions.k8s.io
kind: CustomResourceDefinition
Assigning objects to phases
Package Operators needs to know in which phase objects belong.
To assign an object to a phase, simply add an annotation:
metadata:
annotations:
package-operator.run/phase: crds|namespace|rbac|deploy
Build & Validate
To inspect the parsed hierarchy of your package, use:
$ kubectl package tree --cluster 2_operators/1_start
# example:
example-operator
ClusterPackage /name
└── Phase crds
│ ├── apiextensions.k8s.io/v1, Kind=CustomResourceDefinition /nginxes.example.thetechnick.ninja
└── Phase namespace
│ ├── /v1, Kind=Namespace /example-operator
└── Phase rbac
│ ├── /v1, Kind=ServiceAccount example-operator/example-operator
│ ├── rbac.authorization.k8s.io/v1, Kind=Role example-operator/example-operator
│ ├── rbac.authorization.k8s.io/v1, Kind=RoleBinding example-operator/example-operator
│ ├── rbac.authorization.k8s.io/v1, Kind=ClusterRole /example-operator
│ ├── rbac.authorization.k8s.io/v1, Kind=ClusterRoleBinding /example-operator
└── Phase deploy
└── apps/v1, Kind=Deployment example-operator/example-operator
And finally to build your package as a container image use:
# Push images directly to a registry.
# Assumes you are already logged into a registry via `podman/docker login`
$ kubectl package build -t <your-image-url-goes-here> --push 2_operators/1_start
Deploy
Now that you have build your first Package Operator package, we can deploy it!
You will find the Package
-object template in the examples checkout under 2_operators/clusterpackage.yaml.
apiVersion: package-operator.run/v1alpha1
kind: ClusterPackage
metadata:
name: example-operator
spec:
image: <your-image-url-goes-here>
$ kubectl create -f 2_operators/clusterpackage.yaml
clusterpackage.package-operator.run/example-operator created
# wait for package to be loaded and installed:
$ kubectl get clusterpackage -w
NAME STATUS AGE
example-operator Progressing 10s
example-operator Available 22s
# success!
$ kubectl get po -n example-operator
NAME READY STATUS RESTARTS AGE
example-operator-5d86f95b4f-z4wfz 1/1 Running 0 17m