Getting Started
Note
Cezanne implementation is yet intended a full Yupiik BundleBee replacement and you can refer to Yupiik Bundlebee documentation.
Defining your recipes
Note
Cezanne uses recipe naming where Yupiik BundleBee uses alveolus. It is exactly the same concept of an entry point of a deployment set of descriptors (with or without transitive dependencies).
A recipe defines a set of descriptors to deploy to Kubernetes.
The convention of Cezanne is to start from a manifest.json
file set under bundlebee
folder (or anywhere actually but it is generally better to respect this convention).
The manifest defines the list of recipes:
{
"recipes": [ ... ]
}
Tip
Since Cezanne tries to be as compatible as possible with Yupiik BundleBee, you can also use:
{
"alveoli": [ ... ]
}
Then every recipe defines its name (identifier) and (optionally) a set of descriptors/dependencies to install.
{
"recipes": [
{
"name": "my-recipe",
"descriptors": [
{ "name": "my-descriptor.json" }
]
}
]
}
A descriptor is a Kubernetes descriptor located in bundlebee/kubernetes/
folder (this is why it is better to put the manifest.json
in bundlebee
folder).
Its name
is actually a path related to kubernetes
folder so it is common to use some subtree there (deployments
, cronjobs
, ...).
The descriptor can be in json
, yaml
, handlebars
or even cs
(CSharp Script - in this case the script must return the descriptor as a string
).
Tip
It is always better to use json
format since it is the easiest one to get generated but also parsed in any language (so pipeline/tooling).
Here is a sample JSON descriptor to install a ConfigMap
- but any type of Kubernetes resource will work:
{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": {
"name": "my-cm",
"namespace": "default"
},
"data": {
"SAMPLE": "true"
}
}
Interpolate your descriptors
To go further, the descriptor can be marked as interpolated:
{
"name": "my-recipe",
"descriptors": [
{
"name": "my-descriptor.json",
"interpolate": true
}
]
}
Then you can use placeholders to populate the values marked with {{xxx}}
in the descriptor.
Warning
It looks like mustache/handlebars templates but this interpolation - when extension is not hb
or handlebars
- is just using a simple templating engine, don't try to do too advanced things except setting default ({{key:-default}}
and nesting placeholders if needed).
Now the descriptor can use the interpolation syntax to get value interpolated either from environment variables or the cezanne.json
file (Microsoft configuration/settings):
{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": {
"name": "my-cm",
"namespace": "{{my.namespace}}"
},
"data": {
"SAMPLE": "{{my.sample:-true}}"
}
}
Tip
To keep things easy, the placeholder keys are converted to UNIx like environment variables so my.placeholder
will become MY_PLACEHOLDER
- dot are replaced with underscores and case is uppercased.
You can also scope the placeholder values using placeholders
map of string
in any recipe.
This enables to define custom recipes which are templates to share common practise accross deployments and set variables when important them.
Important
The descriptor name
must be an identifier accross all recipes.
Other descriptor formats
The descriptors can use these formats (take care it must match the extension of the descriptor - and its name
to be enabled):
json
- as seen, it is the recommended format.
yaml
- since it is very common in Kubernetes ecosystem it is supported but not recommended since it is very error prone (indentation).
hb
orhandlebars
- enables to use a Handlebars template where
recipe
(JSON recipe as inmanifest.json
),descriptor
(defines descriptor extension, content, ...),executionId
(execution identifier - GID) andbundlebee
(enables to accesskubernetes.base
- API - andkubernetes.namespace
- default namespace if set) variables are defined. cs
- enables to use a CSharp script (Roselyn) template where the script must return a string which will be the descriptor. The variables
K8s
,Id
,Substitutor
,Desc
andRecipe
are available globally (not in nested class but in the root script scope). They globally match the Handlebars case exceptSubstitutor
which has aReplace(Manifest.Recipe? recipe, LoadedDescriptor? desc, string source, string? id)
method (default values being the global variables) which enables to have some more advanced placeholders (see next part).
Built-in placeholders
Important
This part is only relevant for JSON and Yaml formats enabling interpolation.
Normally, Cezanne supports all Yupiik BundleBee placeholders except jsr223
one which is Java specific:
alveolus.name
: name of the alveolus the descriptor comes from,descriptor.name
: name of the descriptor,bundlebee-strip:<value>
: strips the provided value,bundlebee-strip-leading:<value>
: strips the provided value at the beginning,bundlebee-strip-trailing:<value>
: strips the provided value at the end,bundlebee-indent:<indent size>:<value>
: indents a value with the provided space size, it is generally combined with another interpolation (file ones in particular) as value, ex{{bundlebee-indent:8:{{bundlebee-inline-file:myfile.txt}}}}
,bundlebee-inline-file:<file path>
: load the file content as value,bundlebee-base64-file:<file path>
: converts the file in base64 (useful to writedata:xxxx,<base64>
values for ex keeping the raw file in the filesystem, very helpful for images),bundlebee-base64-decode-file:<file path>
: decode the file from a base64 content,bundlebee-base64:<text>
: encodes in base64 the text,bundlebee-base64-decode:<text>
: decode from base64 to text the valuetext
,bundlebee-digest:BASE64|HEX,<algorithm>,<text>
: computes the digest of the text encoded in base64 or hexa format (useful to read files likeConfigMap
orSecret
and inject their digest value in aDeployment
annotations to force its reload for example),bundlebee-quote-escaped-inline-file:<file path>
: load the file content as a quoted value,bundlebee-json-inline-file:<file path>
: load the file content as a JSON string value - without quotes,bundlebee-json-string:content
: escapes a string to be a JSON string (useful when you inject withbundlebee-json-inline-file
a string in another string like in JSONConfigMap
in a JSON configuration),bundlebee-maven-server-username:<server id>
: extract from your mavensettings.xml
a server username (see configuration for a custom settings.xml location),bundlebee-maven-server-password:<server id>
: extract from your mavensettings.xml
a server password (potentially deciphered),bundlebee-decipher
: use Maven ciphering logic (AES/CBC/PKCS5Padding
) to read a clear value. Syntax is as follow{{bundlebee-decipher:$masterKey,$cipheredValue}}
withmasterKey
another placeholder name which contains the master key andcipheredValue
the value to decipher. Indeed we recommend to reference the master key with another shared placeholder if you use a single one ({{bundlebee-decipher:{{myMasyterKey}},$cipheredValue}}
). Last, since the value will be surrounded by{
and}
, we tolerate spaces before/after to avoid any confusion with the mustable like syntax we use for placeholders:{{bundlebee-decipher:{{my.master.key}}, {...base64....} }}
,bundlebee-kubernetes-namespace
: the Kubernetes namespace defined in the HttpKubeClient,kubeconfig.cluster.<cluster name>.ip
: extract cluster IP from your kubeconfig,timestamp
: current time in milliseconds (since epoch),timestampSec
: current time in seconds (since epoch),now
:OffsetDateTime.now()
value,date:<pattern>
: formatOffsetDateTime.now()
value using the provided pattern,nowUTC
:OffsetDateTime.now()
value with UTCZoneId
,kubernetes.<namespace>.serviceaccount.<account name>.secrets.<secret name prefix>.data.<entry name>[.<timeout in seconds>]
: secret value looked up through Kubernetes API.bundlebee-directory-json-key-value-pairs:/path/to/dir
: creates a JSON object from a directory. The path can be either a directory path of a directory path with a glob pattern at the end (/path/to/dir/*.txt
for example). The keys are the filenames (simple) and____
are converted to/
. The values are the content of the files, filtered. Note it only works with exploded folders, not jar resources as of today.bundlebee-directory-json-key-value-pairs-content:/path/to/dir
: same asbundlebee-directory-json-key-value-pairs
but dropping enclosing brackets to be able to embed the content in an existing object (likeannotations
). Ex:{{bundlebee-directory-json-key-value-pairs-content:resources/app/annotations/*.txt}}
.
Patching dependencies/descriptors
Since sometimes we import dependencies and they don't 100% do what we want, we can patch descriptors either directly from the recipe (useful when combined with next part) or from a HoR (Higer order Recipe - a recipe importing another recipe).
You just have to fill the patches
array of the recipe which will contain a list of descriptor name associated with a JSON-Patch:
{
"name": "root-recipe",
"descriptors": [
{
"name": "root/descriptor.json"
}
],
"patches": [
{
"descriptorName": "root/descriptor.json",
"includeIf": {
"conditions": [
{
"type": "ENV",
"key": "PATCH_ROOT_DESCRIPTOR",
"value": "true"
}
]
},
"patch": [
{
"op": "add",
"path": "/metadata/labels/patched",
"value": "true"
}
]
}
]
}
This recipe will install root/descriptor.json
and if the environment variable PATCH_ROOT_DESCRIPTOR
is set to true
then the label patched
will be set to true
in the descriptor.
Indeed you can use any JSON-Patch operation including replace
or remove
.
Tip
You can patch a descriptor without any condition as well - it is common for transitive dependencies.
Conditions
We saw a bit in previous part but it can make sense to have some conditions on patches but also on deploying descriptors or dependencies.
This is why descriptor and dependency definitions can have an includeIf
object as well.
It works exactly as for patches but either on descriptors or for dependencies installation.
More on manifest.json documentation.
Bundling and sharing your recipes
The recipes can be written in an exploded folder when passing the manifest location explicitly - it is often the case for final deployable recipes but more rarely for dependencies.
However, if you want to bundle your recipes you can do it in a zip and expose it in an Apache Maven repository (plain http server) or NuGet server.
Learn more about it visiting the packaging documentation.
Going further
Now you can move to commands documentation to see how to deploy (apply
your application).