Skip to content
Kubernetes Operator simplifying the development of microservices on k8s !
Go Shell Makefile Dockerfile
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.
.circleci Use v${VERSION} as the docker tag Aug 28, 2019
build Fix #121. Rename component-operator to halkyon-operator. Create compr… Aug 29, 2019
cmd/manager feat: use for the API instead of embedding it Aug 26, 2019
demo chore: Exclude from the uber jar file io.sundr too Sep 6, 2019
deploy fix: improper JSONPath for type, also improve description Sep 5, 2019
e2e feat: use for the API instead of embedding it Aug 26, 2019
examples Remove env var Aug 20, 2019
img Update image of the operator bundle Apr 5, 2019
pkg fix: Define default values for the contextPath or ModuleDirName when … Sep 11, 2019
scripts Fix #121. Rename component-operator to halkyon-operator. Create compr… Aug 29, 2019
test feat: use for the API instead of embedding it Aug 26, 2019
.gitignore Update gitignore Aug 20, 2019 Update the TOC. Set a VERSION field for the docker instructions. Remo… Aug 30, 2019
LICENSE Add Apache License Aug 27, 2019
Makefile Remove wrong bash file --> #121 Aug 29, 2019 chore: Replace the image with a new one where we include exposed serv… Sep 12, 2019 fix: typos Jun 6, 2019
go.mod fix: improper check for capability category/type by updating API Sep 5, 2019
go.sum fix: improper check for capability category/type by updating API Sep 5, 2019
halkyon-operator-demo.png chore: Replace the image with a new one where we include exposed serv… Sep 12, 2019

Halkyon Operator: get back to the halcyon days of local development in a modern kubernetes setting!

CircleCI GitHub release Licensed under Apache License version 2.0

Table of Contents


Deploying modern micro-services applications that comply with the 12-factor guidelines to Kubernetes is difficult, mainly due to the host of different and complex Kubernetes Resources involved. In such scenarios developer experience becomes very important.

This projects aims to tackle said complexity and vastly simplify the process of deploying micro-service applications to Kubernetes and get back to the halcyon days of local development! 😎

By providing several, easy-to-use Kubernetes Custom Resources (CRs) and an Operator to handle them, the Halkyon project provides the following features:

  • Install micro-services (components in Halkyon's parlance) utilizing runtimes such as Spring Boot, Vert.x, Thorntail, Quarkus or Nodejs, serving as base building blocks for your application
  • Manage the relations between the different components using link CR allowing one micro-service for example to consume a REST endpoint provided by another
  • Deploy various infrastructure services like a database which are bound to a component via the capability CR.

The Halkyon Operator requires Kubernetes >= 1.13 or OpenShift >= 3.11.

Key concepts

An example of a simple, modern application, defined as a collection of micro-services is depicted hereafter


Such an application, though simple, will require several Kubernetes resources in order to be deployed on a Kubernetes cluster. Furthermore several development iterations are usually required to make the application production ready.

The entry point to the application is the fruit-client-sb application. It connects to a backend REST endpoint implemented by the fruit-backend-sb application. This application, in turns, uses the services of a PostgreSQL database.

In Halkyon parlance, both fruit-client-sb and fruit-backend-sb are components of our application. The PostgreSQL database is a capability used by the fruit-backend-sb component. Components and capabilities are "glued" together using links. Halkyon links provides the components or capabilities they link together with the information the respective applications need to materialize the connection within the remote cluster.

For example, we use a link between fruit-client-sb and fruit-backend-sb to provide fruit-client-sb with the cluster URL of the fruit-backend-sb so that the client can access the backend endpoint. Similarly, we create a link between the fruit-backend-sb component and the PostgreSQL database capability, thus providing the component with the database connection information.

Information about components, links and capabilities are materialized by custom resources in Halkyon. We can create the manifests for these custom resources which, once processed by the remote cluster, will be handled by the Halkyon operator to create the appropriate Kubernetes/OpenShift resources for you, so you can focus on your application architecture as opposed to wondering how it might translate to Kubernetes pods or deployments.

Remark: you can view the full description of the CRs and their API under the project


A component represents a micro-service, i.e. part of an application to be deployed. The Component custom resource provides a simpler to fathom abstraction over what's actually required at the Kubernetes level to deploy and optionally expose the micro-service outside of the cluster. In fact, when a component is deployed to a Halkyon-enabled cluster, the Halkyon operator will create these resources:

  • Deployment,
  • Service,
  • PersistentVolumeClaim,
  • Ingress or Route on OpenShift if the component is exposed.

You can already see how Halkyon reduces the cognitive load on developers since there is no need to worry about the low-level details by focusing on the salient aspects of your component: what runtime does it need to run, does it need to be exposed outside of the cluster and on what port. Theses aspects are captured along with less important ones in the custom resource fields: runtime (and version), exposeService and port. The runtime name will condition which container image will be used to run the application. For example, an OpenJDK image will be used for Java runtimes such as Spring Boot or Eclipse Vert.x. If you want to expose your application, you will need to set exposeService to true and specify which port needs to be exposed.

Of note, Halkyon offers two deployment modes, controlled by the deploymentMode field of the custom resource: dev (for "development") and build, dev being the default mode if none is specified explicitly.

The dev mode sets the environment in such a way that the pod where your application is deployed doesn't need to be restarted when the code changes. On the contrary, the pod contains an init container exposing a server that can listen to commands so that your application executable can be restarted or re-compiled after updates without needing to restart the whole pod or generate a new container image which allows for faster turn-around.

The build mode uses the Tekton Pipeline Operator in order to build of a new image for your application. How the image is built is controlled by the buildConfig field of the component custom resource where you need to minimally specify the url of the git repository to be used as basis for the code (url field). You can also specify the precise git reference to use (ref field) or where to find the actual code to build within the repository using the contextPath and moduleDirName fields.

For more details on the fields of the Component custom resource, please refer to its API.


DeploymentMode: dev

kind: Component
  name: spring-boot-demo
  deploymentMode: dev
  runtime: spring-boot
  version: 2.1.16
  exposeService: true
  port: 8080
    value: openshift-catalog

DeploymentMode: build

apiVersion: ""
kind: "Component"
    app: "fruit-backend-sb"
  name: "fruit-backend-sb"
  deploymentMode: "build"
  runtime: "spring-boot"
  version: "2.1.6.RELEASE"
  exposeService: true
    type: "s2i"
    url: ""
    ref: "master"
    contextPath: "demo/"
    moduleDirName: "fruit-backend-sb"
  port: 8080


As explained in the introduction, links explicit how components are tied together to create a composite application. This is done by injecting information in the target component (as identified by the componentName field of the link custom resource). Under the hood, the Halkyon operator modifies the Deployment associated with the target component to either add environment variables or secret reference, depending on the type of link. This is controlled, as you might have guessed 😏, using the type field of the link CR. This fields currently accepts two possible values: Secret or Env. A Secret link will use the ref field value to look up a Kubernetes secret while an Env link will use the envs field. This information will then be used to enrich the container associated with the Deployment according to its type (EnvFrom for secret injection, Env for environment variable injection).

For more details on the fields of the Link custom resource, please refer to its API.



apiVersion: ""
kind: "Link"
  name: "link-to-database"
  componentName: "fruit-backend-sb"
  type: "Secret"
  ref: "postgres-db-config" 


apiVersion: ""
kind: "Link"
  name: "link-to-fruit-backend"
  componentName: "fruit-client-sb"
  type: "Env"
  ref: ""
    value: "http://fruit-backend-sb:8080/api/fruits"


A capability corresponds to a service that the micro-service will consume on the platform. The Halkyon operator then uses this information to configure the service. Capabilities are identified by the combination of its category which represents the general class of configurable services, further identified by a more specific type (which could be construed as a sub-category) and a version for the category/type combination. The service is then configured using a list of name/value parameters.

We currently only support the database/PostgreSQL category/type combination but are planning to expand to other categories and types. Halkyon uses the [KubeDB]( operator to handle the database category.

For more details on the fields of the Capability custom resource, please refer to its API.


PostgreSQL Database

apiVersion: ""
  kind: "Capability"
    name: "postgres-db"
    category: "database"
    type: "postgres"
    version: "10"
    - name: "DB_USER"
      value: "admin"
    - name: "DB_PASSWORD"
      value: "admin"
    - name: "DB_NAME"
      value: "sample-db"


In order to use the Halkyon Operator and the CRs, the Tekton Pipelines and KubeDB Operators need to be installed on the cluster. We assume that you have installed a cluster with Kubernetes version equals to 1.13 or newer.

Local cluster using minikube

Install using Homebrew on macOS the following software:

brew cask install minikube
brew install kubernetes-cli
brew install kubernetes-helm

Next, create a Kubernetes cluster where ingress and dashboard addons are enabled

minikube config set cpus 4
minikube config set kubernetes-version v1.14.0
minikube config set memory 8000
minikube addons enable ingress
minikube addons enable dashboard
minikube addons enable registry
minikube start

When minikube has started, initialize Helm to install Tiller on the cluster:

helm init
until kubectl get pods -n kube-system -l name=tiller | grep 1/1; do sleep 1; done
kubectl create clusterrolebinding tiller-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:default

Install Tekton Pipelines:

kubectl apply -f

Install the KubeDB operator and its PostgreSQL catalog supporting different database versions:

helm repo add appscode
helm repo update
helm install appscode/kubedb --name kubedb-operator --version ${KUBEDB_VERSION} \
  --namespace kubedb --set apiserver.enableValidatingWebhook=true,apiserver.enableMutatingWebhook=true

Wait until the Operator has started before installing the catalog:

until kubectl get crd || [[ ${TIMER} -eq 60 ]]; do
  sleep 5
  TIMER=$((TIMER + 1))

Install the PostgreSQL catalog:

helm install appscode/kubedb-catalog --name kubedb-catalog --version ${KUBEDB_VERSION} \
  --namespace kubedb --set catalog.postgres=true,catalog.elasticsearch=false,catalog.etcd=false,catalog.memcached=false,catalog.mongo=false,catalog.mysql=false,catalog.redis=false

Installing the Halkyon Operator

Deploy the ClusterRole, RoleBinding, CRDs, ServiceAccount and Operator resources within the operators namespace:

kubectl create ns operators
kubectl apply -n operators -f deploy/sa.yaml
kubectl apply -f deploy/cluster-role.yaml
kubectl apply -f deploy/user-rbac.yaml
kubectl apply -f deploy/cluster-role-binding.yaml
kubectl apply -f deploy/crds/capability.yaml
kubectl apply -f deploy/crds/component.yaml
kubectl apply -f deploy/crds/link.yaml
kubectl apply -n operators -f deploy/operator.yaml

Wait until the Operator's pod is ready and running before continuing:

until kubectl get pods -n operators -l name=halkyon-operator | grep 1/1; do sleep 1; done

Control if the operator is running correctly:

pod_id=$(kubectl get pods -n operators -l name=halkyon-operator -o=name)
kubectl logs $pod_id -n operators

Enjoy the Halkyon Operator!

How to play with it

Deploy the operator as defined within the Operator Doc or use the operator bundle promoted on

First create a demo namespace:

kubectl create ns demo

Next, create a component yml file with the following information within your maven java project:

kind: Component
  name: spring-boot
  runtime: spring-boot
  version: 2.1.6.RELEASE
  deploymentMode: dev
  port: 8080

Deploy it:

kubectl apply -n demo -f my-component.yml

Verify if the component has been deployed properly:

kubectl get components -n demo
NAME          RUNTIME       VERSION        AGE   MODE   STATUS    MESSAGE                                                            REVISION
spring-boot   spring-boot   2.1.6.RELEASE  14s   dev    Pending   pod is not ready for component 'spring-boot' in namespace 'demo'                        

Remark Don't worry about the initial status as downloading the needed images from an external docker registry could take time!

kubectl get components -n demo   
spring-boot   spring-boot             2m19s   dev    Ready              

The Halkyon operator will then use the content of the component custom resource to create the Kubernetes resources needed to materialize your application on the cluster. You can see all these resources by executing the following command:

kubectl get pods,services,deployments,pvc -n demo
NAME                              READY   STATUS    RESTARTS   AGE
pod/spring-boot-6d9475f4c-c9w2z   1/1     Running   0          4m18s

NAME                  TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/spring-boot   ClusterIP   <none>        8080/TCP   4m18s

NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/spring-boot   1/1     1            1           4m18s

NAME                                        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/m2-data-spring-boot   Bound    pvc-dab00dfe-a2f6-11e9-98d1-08002798bb5f   1Gi        RWO            standard       4m18s

Package your Java Application mvn package and push the uber java file.

kubectl cp target/my-component-1.0-SNAPSHOT.jar POD_NAME:/deployments/my-component-1.0-SNAPSHOT -n demo

Start your application within the pod

kubectl exec POD_NAME -n demo /var/lib/supervisord/bin/supervisord ctl start run-cmd

Enrich your application with additional Component, Link them or deploy a Capability database using the supported CRs for your different microservices. To simplify your life even more when developing Java applications, add Dekorate to your project to automatically generate the YAML resources for your favorite runtime !

You can now cleanup the project:

kubectl delete component --all -n demo 

A Real demo

To play with a more real-world example and discover the different features currently supported, we have implemented the application we took as an example in the Key Concepts section. You can find it in the demo directory.

So jump here to see in action how Halkyon enhances the Developer Experience on Kubernetes 😉

Cleanup the operator resources

To remove the operator from your favorite Kubernetes cluster, then execute the following kubectl commands:

kubectl delete -n operators -f deploy/sa.yaml
kubectl delete -f deploy/cluster-role.yaml
kubectl delete -f deploy/user-rbac.yaml
kubectl delete -f deploy/cluster-role-binding.yaml
kubectl delete -f deploy/crds/capability.yaml
kubectl delete -f deploy/crds/component.yaml
kubectl delete -f deploy/crds/link.yaml
kubectl delete -n operators -f deploy/operator.yaml

Compatibility matrix

Kubernetes >= 1.13 OpenShift 3.x OpenShift 4.x KubeDB 0.12 Tekton v0.5.x
halkyon v0.1.x


If you need support, reach out to us via zulip.

If you run into issues or if you have questions, don't hesitate to raise an issue.

Follow us on twitter.

You can’t perform that action at this time.