Go to file
Nikolai Rodionov 439e735203
Refactor the reconciler and add Woodpecker CI
Now controller looks a bit better and its parts can be tested with
integration tests, that are going to be implemented later.
2024-01-06 09:02:23 +01:00
.woodpecker Refactor the reconciler and add Woodpecker CI 2024-01-06 09:02:23 +01:00
src Refactor the reconciler and add Woodpecker CI 2024-01-06 09:02:23 +01:00
tests Refactor the reconciler and add Woodpecker CI 2024-01-06 09:02:23 +01:00
.containerignore First Commit 2023-11-24 18:49:06 +01:00
.gitignore First Commit 2023-11-24 18:49:06 +01:00
Cargo.lock First Commit 2023-11-24 18:49:06 +01:00
Cargo.toml First Commit 2023-11-24 18:49:06 +01:00
Containerfile First Commit 2023-11-24 18:49:06 +01:00
README.md First Commit 2023-11-24 18:49:06 +01:00

Shoebill

!! Be careful !!

The code is not ready for real use, it can only create secrets, but a lot of errors are not handled, so they are making the controller die, and there is no clean-up at all. Also, reconciliation doesn't work as I would like to work yet. I hope that I'll release the first prod-ready version soon

What's that?

It's a Kubernetes operator that lets you build new Secrets and ConfigMaps using ones that exist already as inputs for templates.

Why does that exist?

I'm one of maintainers of db-operator, and there we have implemented a feature that we call templated credentials, it lets user define templates that should be used for creating new entries to Secrets and ConfigMaps that are managed by the operator. Because sometimes you need to have more than just credentials, cause your application may require a custom connection string. But since this feature doesn't exist in any operator, I've created another operator for exactly that.

Let's say you have an operator some-operator that should run something that is required for your application to run, and when you apply the CR, the operator is creating something that results in a Secret like that:

kind: Secret
metadata:
  name: some-secret
stringData:
  password: really-strong-one

and a ConfigMap:

kind: ConfigMap
metadata:
  name: some-configmap
data:
  username: application-user
  hostname: some.app.rocks

But to use that something, your application require an environment variable in a format like this:

SOME_CONNECTION_STRING=${USERNAME}:${PASSWORD}@{$HOSTNAME}

What are your options?

  • You can get the data from the Secret and ConfigMap to build a new Secret manually and add it as an env var to your application Deployment
  • You can write an initContainer that will get the data from those sources, and create a formatted connection string, that later might be somehow set as an environment var for you main workload
  • You can have a watcher that is checking those sources and modifies you workload object, setting the desired env
  • Or maybe you can use something that exists already, but I wanted to try writing an operator in Rust, so I don't care too much

With this operator, you can create a Custom Resource called ConfigSet, that in our case should look like that:

kind: ConfigSet
spec:
  inputs:
    - name: PASSWORD
      from:
        kind: Secret
        name: some-secret
        key: password
    - name: USERNAME
      from:
        kind: ConfigMap
        name: some-configmap
        key: username
    - name: HOSTNAME
      from:
        kind: ConfigMap
        name: somet-configmap
        key: hostname
  targets:
    - name: app-some-creds
      target:
        kind: Secret
        name: app-some-creds
  templates:
    - name: SOME_CONNECTION_STRING
      template: "{{USERNAME}}:{{PASSWORD}}@{{HOSTNAME}}"

And after you apply it, there will be a new secret created (or the existing one will be modified), and it will contain

kind: Secret
metadata:
  name: app-some-creds
stringData:
  SOME_CONNECTION_STRING: application-user:really-strong-one@some.app.rocks

Now you can simply mount that newly created secret to your workload, and that's it.

How can I start using it?

Once it's production ready, I'll start distributing it as a helm chart. Currently, since it's should only be used by those one who are developing it, it looks like that

  • build an image
  • import that image to you K8s
  • build the tool locally (or use the image too)
  • run shoebill manifests > /tmp/manifests.yaml, it will generate all the required manifests for the quick start
  • apply those manifests, and check if the controller is up
  • prepare you secrets and configmaps (or go to ./yaml/example folder and use manifests from there
  • create you ConfigSet manifests and apply it too. Example also can be found in ./yaml/example dir

Why Shoebill?

There is no real connection between the project and the name, I just always wanted to have a project called Shoebill because I really like those birds