diff --git a/main/library/core/index.html b/main/library/core/index.html index 9161894..22167e6 100644 --- a/main/library/core/index.html +++ b/main/library/core/index.html @@ -1271,7 +1271,7 @@
Welcome to the documentation of the Cloudflight jsonnet library.
This library contains utilities and premade modules to ease working with Kubernets and OpenShift.
To get started, take a look at the guides or the module documentation.
If you know your way around jsonnet already, why not take a look at our complete library?
If you want support for your editor you should use one of the plugins listed on the tools page. We recommend plugins based on the jsonnet-language server.
Info
cloudflight-libsonnet
is inteded to be used with Tanka. Other tools might work, however we do not test for them. If you're using kubecfg
, take a look at our migration guide.
This section contains guides for various usecases concerning our jsonnet library.
If you just want to get going, take a look at the quick start.
"},{"location":"guides/#external-resources","title":"External Resources","text":"To start using this library, first initialize the working directory using tk init
.
This will create a directory structure similar to this:
.\n\u251c\u2500\u2500 environments\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 default\n\u251c\u2500\u2500 jsonnetfile.json\n\u251c\u2500\u2500 jsonnetfile.lock.json\n\u251c\u2500\u2500 lib\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 k.libsonnet\n\u2514\u2500\u2500 vendor\n \u251c\u2500\u2500 1.23 -> github.com/jsonnet-libs/k8s-libsonnet/1.23\n \u251c\u2500\u2500 github.com\n \u2514\u2500\u2500 ksonnet-util -> github.com/grafana/jsonnet-libs/ksonnet-util\n
Next, we need to install the cloudflight-libsonnet
library using jb
:
jb install github.com/cloudflightio/cloudflight-libsonnet@main\n
The last step is to adapt the predefined k.libsonnet
. When initializing, Tanka simply imports the k8s-libsonnet
library here. Since some of our customizations depend on other libraries which have to be imported at this point (such as openshift-libsonnet
or prometheus-libsonnet
), you replace the contents of k.libsonnet
with the following:
import 'github.com/cloudflightio/cloudflight-libsonnet/k.libsonnet'\n
"},{"location":"guides/quickstart/#using-the-library","title":"Using the library","text":"To use the components provided by this library (or other Kubernetes components), import our prelude.libsonnet
.
Let's use the library to deploy a simple java based application, backed by an MariaDB instance.
"},{"location":"guides/quickstart/#creating-the-application","title":"Creating the application","text":"Applications should be defined in the lib
folder. To configure a java application, we create a file called lib/test-java.libsonnet
with the contents below.
local k = (import 'cloudflight-libsonnet/prelude.libsonnet');\n{\n _config+:: {\n myApplication: {\n name: 'my-application',\n image: error '$._config.myApplication.image must be defined',\n },\n },\n myApplication: {\n deployment: k.util.java.deployment.new(\n name=$._config.myApplication.name,\n image=$._config.myApplication.image,\n containerMixin=k.core.v1.container.livenessProbe.withInitialDelaySeconds(60),\n ),\n service: k.util.serviceFor(self.deployment),\n route: k.util.routeFor(self.service, 'hello.example.com'),\n },\n}\n
Now we can import this into our environment file environments/default/main.jsonnet
(import 'test-java.libsonnet')\n+ {\n _config+: {\n myApplication+: {\n image: 'helloworld:latest',\n },\n },\n}\n
Provided your .kube/config
and environments/default/spec.json
are set up correctly, you can deploy this by running tk apply environments/default
.
Most applications want to store data somewhere so let's add a database next. First, we import the database of choice in the main.jsonnet
file.
(import 'cloudflight-libsonnet/databases/mariadb.libsonnet')\n+ (import 'test-java.libsonnet')\n+ {\n _config+: {\n mariadb+: {\n user: 'application-user',\n password: 'hunter2',\n database: 'my-application',\n },\n myApplication+: {\n image: 'helloworld:latest',\n },\n },\n}\n
To connect our application to the database, we need to configure the deployment on a lower level. This is because of the fact, that the plain util.java.deployment
does not make any assumptions about databases.
As documented in the java module, we build the deployment ourselves, but mix in some environment variables.
local k = (import 'cloudflight-libsonnet/prelude.libsonnet');\n{\n _config+:: {\n myApplication: {\n name: 'my-application',\n image: error '$._config.myApplication.image must be defined',\n dbUser: error '$._config.myApplication.dbUser must be defined',\n dbPasswordRef: error '$._config.myApplication.dbPasswordRef must be a valid secretSecretKeyRef',\n dbUrl: error '$._config.myApplication.dbUrl must be defined',\n },\n },\n myApplication: {\n deployment: k.apps.v1.deployment.new(\n name=$._config.myApplication.name,\n replicas=1,\n containers=[\n k.util.java.container.new($._config.myApplication.name, $._config.myApplication.image)\n + k.core.v1.container.withEnvMixin([\n {\n name: 'SPRING_DATASOURCE_PASSWORD',\n valueFrom: { secretKeyRef: $._config.myApplication.dbPasswordRef },\n },\n {\n name: 'SPRING_DATASOURCE_USERNAME',\n value: $._config.myApplication.dbUser,\n },\n {\n name: 'SPRING_DATASOURCE_URL',\n value: $._config.myApplication.dbUrl,\n },\n ]),\n ]\n ),\n service: k.util.serviceFor(self.deployment),\n route: k.util.routeFor(self.service, 'hello.example.com'),\n },\n}\n
In the last step, we fill the new config parameters with values.
(import 'cloudflight-libsonnet/databases/mariadb.libsonnet')\n+ (import 'test-java.libsonnet')\n+ {\n _config+: {\n mariadb+: {\n user: 'application-user',\n password: 'hunter2',\n database: 'my-application',\n },\n myApplication+: {\n image: 'helloworld:latest',\n dbUser: $._config.mariadb.user,\n dbPasswordRef: $.mariadb.passwordSecretKeyRef,\n dbUrl: 'jdbc:mysql://' + $.mariadb.service.metadata.name + '/' + $._config.mariadb.database,\n },\n },\n mariadb2: (import 'cloudflight-libsonnet/databases/mariadb.libsonnet') + {\n _config+: {\n mariadb+: {\n name: 'foo',\n user: 'foo-user',\n password: 'foo-user',\n },\n },\n },\n}\n
And we're done!
To recap: we have configured an application, added a database and connected it to our application. The way we connected the applications is transparent, and we could (as long as the application supports it) change the database entirely in our main.jsonnet
. This way, we can use different database setups across environment, while keeping the application configuration the same.
For more information, check out the documentation of the java utilities and the MariaDB module.
"},{"location":"guides/tanka_migration/","title":"Migrating to Tanka","text":"At Cloudflight we were previously using kubecfg
to deploy our applications. As of 2022-02-21
, tanka is our recommended tool for Kubernetes configurations. Reasoning for this can be found in ADR-0077.
If you're still using kubecfg
you're in Luck! The migration to Tanka is very simple and can be done in under five minutes.
Tip
TL;DR:
Before we can start to migrate to the new setup, we should be confident in the old one to avoid issues further down the line.
As a requirement, you should be able to view your configuration in the yaml format by running
kubecfg show $YOUR_STAGE_FILE\n
"},{"location":"guides/tanka_migration/#restructuring","title":"Restructuring","text":"The main change required for a smooth workflow in Tanka, is a small restructuring of the directory. Our old layout prescribes a flat structure with everything in the root directory. Tanka on the other hand expects a folder per environment. To perform this step, you need to go from this:
.\n\u251c\u2500\u2500 jsonnetfile.json\n\u251c\u2500\u2500 production.jsonnet\n\u251c\u2500\u2500 resources\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 application.jsonnet\n\u2514\u2500\u2500 staging.jsonnet\n
to
.\n\u251c\u2500\u2500 jsonnetfile.json\n\u251c\u2500\u2500 environments\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 production\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 main.jsonnet # (1)\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 staging\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 main.jsonnet # (2)\n\u2514\u2500\u2500 lib\n \u2514\u2500\u2500 application.libsonnet\n
production.jsonnet
staging.jsonnet
Instead of relying on the current Kubernetes context, Tanka needs explicit information on the API Server as well as the namespace.
This information is saved in the spec.json
file, contained in the respective environment. The complete layout can be found in the Tanka documentation
The syntax is as follows:
{\n \"apiVersion\": \"tanka.dev/v1alpha1\",\n \"kind\": \"Environment\",\n \"metadata\": {\n \"name\": \"environments/staging\"\n },\n \"spec\": {\n \"apiServer\": \"openshift-dev.internal.cloudflight.io:6443\", // (1)\n \"namespace\": \"762-example-staging\", // (2)\n \"resourceDefaults\": {},\n \"expectVersions\": {},\n \"injectLabels\": true\n }\n}\n
Now that you moved around the files, you will also need to fix the imports contained within them. For convenience, Tanka automatically includes the lib
and vendor
directory in the jsonnet path. So instead of having to write ../../lib/application.libsonnet
you can simply import application.libsonnet
.
After fixing the imports, you can show the new configuration with the following command:
tk show environments/staging\n
"},{"location":"guides/tanka_migration/#teamcity","title":"TeamCity","text":"Tanka integration from TeamCity is supported from version 3.0.0
of the cloudflight-teamcity-dsl onwards.
Example:
subCloudflightProject {\n name = \"Deployment\"\n tankaApply {\n openShiftConfig {\n serviceAccountToken = \"credentialsJSON:...\"\n }\n contextDir = \".openshift\" // (1)\n }\n}\n
deployment
as is the case with our new configuration skeletonThis library contains various utility modules for use with the jsonnet configuration language To get started, import the provided prelude which will composit the library for you.
local k = import ('cloudflight-libsonnet/prelude.libsonnet');\n
The prelude depends on a file called k.libsonnet
being available for import. Either place it in your lib or environment folder. Using the environment folder allows for library level configuration options to be applied on an environment level.
This works, because import paths are ranked as highlighted in the Tanka documentation.
A pre-populated k.libsonnet
is available in this library so a minimal k.libsonnet
would look like this:
(import 'cloudflight-libsonnet/k.libsonnet')\n
This includes k8s-libsonnet, openshift-libsonnet as well as prometheus-libsonnet
For more information on customization options in k.libsonnet
, take a look at the labeling extension.
Contains extensions related to core kubernetes components
"},{"location":"library/core/#index","title":"Index","text":"obj v1
obj v1.container
fn new(name, image, unprivileged='true')
new(name, image, unprivileged='true')\n
new returns a new container of given name and image. By default it injects an openshift 4.11 compatible securityContext
"},{"location":"library/extensions/","title":"extensions","text":"Extensions available to the standard library
"},{"location":"library/labeling/","title":"labeling","text":"This extension allows you to label core kubernetes resources with useful labels.
"},{"location":"library/labeling/#usage","title":"Usage","text":"To use this labeling function, edit your k.libsonnet
to look something like this
(import 'cloudflight-libsonnet/k.libsonnet')\n+ {\n _config+:: {\n project: 'some-project-name'\n }\n}\n
Afterwards, all resources created (provided they use cloudflight-libsonnet/prelude.libsonnet
), will have the cloudflight.io/project=some-project-name
label attached
If you need to set this on a per-environment basis, move the k.libsonnet
file to your environment folder as described in the Tanka documentation.
Contains extensions related to cert-manager
"},{"location":"library/networking/#index","title":"Index","text":"obj v1
obj v1.ingress
fn withCertMixin(issuer, clusterwide)
withCertMixin(issuer, clusterwide)\n
withCertMixin instructs cert-manager to add an certificate to the ingress-resource.
"},{"location":"library/route/","title":"route","text":"Contains extensions to the default route functions provided by openshift-libsonnet
"},{"location":"library/route/#index","title":"Index","text":"obj v1
obj v1.route
fn new(name, host, path)
new(name, host, path)\n
builds a route with a predefined host and TLS Edge termination
"},{"location":"library/util/","title":"util","text":"The util package contains ease of use functions to simplify working with kubernetes and jsonnet
"},{"location":"library/util/#index","title":"Index","text":"fn ingressFor(service, host='', path='/', port='service.spec.ports[0].port')
fn routeFor(service, host='', path='/', port='service.spec.ports[0].port')
fn serviceFor(deployment, ignored_labels, nameFormat='%(port)s')
fn weightedRouteFor(name, host='', port='', services, path='/')
obj certmanager
obj certmanager.issuer
fn new(emain, ingressClassName='nginx', production=true, clusterwide=true, name='letsencrypt-production || letsencrypt-staging')
obj java
obj java.container
fn new(name, image, port=8080, actuatorPort='port+8080', env={})
obj java.deployment
fn new(name, image, replicas=1, env={}, containerMixin={}, runtime='spring-boot', component='backend')
obj java.livenessProbe
fn new(port=8080, initialDelaySeconds=30)
obj java.readinessProbe
fn new(port=18080, path='/actuator/health')
obj openshiftOAuth
obj openshiftOAuth.container
fn new(upstream, serviceAccount)
obj openshiftOAuth.deployment
fn withProxy(upstream, serviceAccount)
obj openshiftOAuth.serviceAccount
fn new(name, route)
ingressFor(service, host='', path='/', port='service.spec.ports[0].port')\n
ingressFor constructs a ingress object, compatible with the automatic translation to openshift routes. It expects a value for the hostname and defaults to '/' for the path.
"},{"location":"library/util/#fn-routefor","title":"fn routeFor","text":"routeFor(service, host='', path='/', port='service.spec.ports[0].port')\n
routeFor constructs a openshift route to the specified service. It expects a value for the hostname and defaults to '/' for the path.
"},{"location":"library/util/#fn-servicefor","title":"fn serviceFor","text":"serviceFor(deployment, ignored_labels, nameFormat='%(port)s')\n
serviceFor constructs a service for the specified deployment.
Selector labels are taken from the pod spec but can be ignored using the ignored_labels
parameter.
The ports of the service will have the same name as in the container spec to avoid confusion. This can be changed with the nameFormat
parameter.
weightedRouteFor(name, host='', port='', services, path='/')\n
weightedRouteFor constructs a openshift route to the specified services. It expects a value for the name, hostname, port, services and defaults to '/' for the path. services expects an array consisting of objects with the keys name (name of the service) and weight.
"},{"location":"library/util/#obj-certmanager","title":"obj certmanager","text":"certman holds functions related to cert-manager (cert-manager.io)
"},{"location":"library/util/#obj-certmanagerissuer","title":"obj certmanager.issuer","text":""},{"location":"library/util/#fn-certmanagerissuernew","title":"fn certmanager.issuer.new","text":"new(emain, ingressClassName='nginx', production=true, clusterwide=true, name='letsencrypt-production || letsencrypt-staging')\n
constructs a cert-manager issuer resource for letsencrypt with sensible default.
"},{"location":"library/util/#obj-java","title":"obj java","text":"java holds my functions related to java based applications
"},{"location":"library/util/#obj-javacontainer","title":"obj java.container","text":""},{"location":"library/util/#fn-javacontainernew","title":"fn java.container.new","text":"new(name, image, port=8080, actuatorPort='port+8080', env={})\n
constructs a container with reccomended settings for Java/Spring Boot applications. Includes liveness- and readiness probes, activates the kubernetes
spring profile and sets sensible resource defaults.
new(name, image, replicas=1, env={}, containerMixin={}, runtime='spring-boot', component='backend')\n
constructs a deployment using the java container. If you need more control, construct this deployment yourself.
containerMixin
can be used to modify the application container. For example:
deployment.new(/*...*/,\n containerMixin=k.core.v1.container.livenessProbe.withInitialDelaySeconds(60))\n
increases the initial delay seconds of the default liveness probe. The runtime
and component
parameters are used to prefill recommended labels
new(port=8080, initialDelaySeconds=30)\n
new constructs a fresh liveness probe, checking if the tcp port 8080 is open
"},{"location":"library/util/#obj-javareadinessprobe","title":"obj java.readinessProbe","text":""},{"location":"library/util/#fn-javareadinessprobenew","title":"fn java.readinessProbe.new","text":"new(port=18080, path='/actuator/health')\n
new constructs a fresh readiness probe, checking if the application is up. The port and path of the actuator endpoint can be changed using the parameters.
"},{"location":"library/util/#obj-openshiftoauth","title":"obj openshiftOAuth","text":"openshiftOAuth contains utilities to proxy an application using the OpenShift OAuth Proxy
"},{"location":"library/util/#obj-openshiftoauthcontainer","title":"obj openshiftOAuth.container","text":""},{"location":"library/util/#fn-openshiftoauthcontainernew","title":"fn openshiftOAuth.container.new","text":"new(upstream, serviceAccount)\n
constructs a container proxying connections to the upstream
parameter.
withProxy(upstream, serviceAccount)\n
add a proxy sidecar to the container. This also sets the service account used by the pod. The ServiceAccount needs to have the correct redirect reference for the route. See openshiftOAuth.serviceAccount.new
for an easy way to create a compliant service account
new(name, route)\n
constructs a serviceaccount annotated with a oauth-redirectreference pointing to the route parameter
"},{"location":"modules/","title":"What are modules?","text":"Modules are ready-to-use setups of existing applications and services. To use them, import them into your main.libsonnet
like so:
(import 'cloudflight-libsonnet/databases/mariadb.libsonnet') + {\n _config+: {\n mariadb+: {\n user: 'foo',\n password: 'bar',\n }\n }\n}\n
"},{"location":"modules/java_application/","title":"Java Applications","text":"Even though not strictly a module, this library contains a lot of utility functions to help you deploy Java applications. This page contains some ways these functions can be used.
"},{"location":"modules/java_application/#all-in-one","title":"All-in-one","text":"This example contains the deployment of a simple spring boot based application. It should be located somewhere like lib/my-application.libsonnet
.
local k = (import 'cloudflight-libsonnet/prelude.libsonnet');\n{\n _config+:: {\n myApplication: {\n name: 'my-application',\n image: error '$._config.myApplication.image must be defined',\n },\n },\n myApplication: {\n deployment: k.util.java.deployment.new(\n name=$._config.myApplication.name,\n image=$._config.myApplication.image,\n containerMixin=k.core.v1.container.livenessProbe.withInitialDelaySeconds(60),\n ),\n service: k.util.serviceFor(self.deployment),\n route: k.util.routeFor(self.service, 'hello.example.com'),\n },\n}\n
apiVersion: v1\nkind: Service\nmetadata:\nlabels:\n name: my-application\nname: my-application\nnamespace: test-java\nspec:\nports:\n- name: my-application-http\n port: 8080\n targetPort: 8080\n- name: my-application-actuator\n port: 9080\n targetPort: 9080\nselector:\n name: my-application\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\nname: my-application\nnamespace: test-java\nspec:\nminReadySeconds: 10\nreplicas: 1\nrevisionHistoryLimit: 10\nselector:\n matchLabels:\n name: my-application\ntemplate:\n metadata:\n labels:\n name: my-application\n spec:\n containers:\n - env:\n - name: SPRING_PROFILES_ACTIVE\n value: kubernetes\n image: helloworld:latest\n imagePullPolicy: IfNotPresent\n livenessProbe:\n failureThreshold: 5\n initialDelaySeconds: 30\n periodSeconds: 10\n successThreshold: 1\n tcpSocket:\n port: 8080\n timeoutSeconds: 1\n name: my-application\n ports:\n - containerPort: 8080\n name: http\n - containerPort: 9080\n name: actuator\n readinessProbe:\n failureThreshold: 5\n httpGet:\n path: /actuator/health\n port: 18080\n initialDelaySeconds: 30\n periodSeconds: 10\n successThreshold: 1\n timeoutSeconds: 1\n resources:\n limits:\n cpu: 500m\n memory: 1Gi\n requests:\n cpu: 100m\n memory: 1Gi\n---\napiVersion: route.openshift.io/v1\nkind: Route\nmetadata:\nname: my-application\nnamespace: test-java\nspec:\nhost: hello.example.com\npath: /\nport:\n targetPort: 8080\ntls:\n insecureEdgeTerminationPolicy: Redirect\n termination: Edge\nto:\n kind: Service\n name: my-application\n
Switch between the tabs to see the rendered output
"},{"location":"modules/java_application/#diy","title":"DIY","text":"If you have the need for further customization, you can pick and choose parts of the library you would like to use.
In this example, we want to modify the container so we use the util.java.container.new()
to get a base structure and extend it. This way, we still have the defaults set, but are able to customize them to our hearts content.
local k = (import 'cloudflight-libsonnet/prelude.libsonnet');\n{\n _config+:: {\n myApplication: {\n name: 'my-application',\n image: error '$._config.myApplication.image must be defined',\n },\n },\n myApplication: {\n deployment: k.apps.v1.deployment.new(\n name=$._config.myApplication.name,\n replicas=2,\n containers=[\n k.util.java.container.new($._config.myApplication.name, $._config.myApplication.image)\n + k.core.v1.container.withVolumeMounts([\n k.core.v1.volumeMount.new(name='temp', mountPath='/opt/cache'),\n ]),\n ]\n )\n + k.apps.v1.deployment.spec.template.spec.withVolumes([\n k.core.v1.volume.fromEmptyDir(name='temp'),\n ]),\n service: k.util.serviceFor(self.deployment),\n route: k.util.routeFor(self.service, 'hello.example.com'),\n },\n}\n
apiVersion: v1\nkind: Service\nmetadata:\n labels:\n name: my-application\n name: my-application\n namespace: test-java-diy\nspec:\n ports:\n - name: my-application-http\n port: 8080\n targetPort: 8080\n - name: my-application-actuator\n port: 9080\n targetPort: 9080\n selector:\n name: my-application\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: my-application\n namespace: test-java-diy\nspec:\n minReadySeconds: 10\n replicas: 2\n revisionHistoryLimit: 10\n selector:\n matchLabels:\n name: my-application\n template:\n metadata:\n labels:\n name: my-application\n spec:\n containers:\n - env:\n - name: SPRING_PROFILES_ACTIVE\n value: kubernetes\n image: helloworld:latest\n imagePullPolicy: IfNotPresent\n livenessProbe:\n failureThreshold: 5\n initialDelaySeconds: 30\n periodSeconds: 10\n successThreshold: 1\n tcpSocket:\n port: 8080\n timeoutSeconds: 1\n name: my-application\n ports:\n - containerPort: 8080\n name: http\n - containerPort: 9080\n name: actuator\n readinessProbe:\n failureThreshold: 5\n httpGet:\n path: /actuator/health\n port: 18080\n initialDelaySeconds: 30\n periodSeconds: 10\n successThreshold: 1\n timeoutSeconds: 1\n resources:\n limits:\n cpu: 500m\n memory: 1Gi\n requests:\n cpu: 100m\n memory: 1Gi\n volumeMounts:\n - mountPath: /opt/cache\n name: temp\n volumes:\n - emptyDir: {}\n name: temp\n---\napiVersion: route.openshift.io/v1\nkind: Route\nmetadata:\n name: my-application\n namespace: test-java-diy\nspec:\n host: hello.example.com\n path: /\n port:\n targetPort: 8080\n tls:\n insecureEdgeTerminationPolicy: Redirect\n termination: Edge\n to:\n kind: Service\n name: my-application\n
"},{"location":"modules/applications/mailhog/","title":"Mailhog","text":"This module creates an instance of mailhog. Data is stored in memory only so messages will disappear after a pod restart.
The following snippet lists all available configuration options alongside their default values:
(import 'cloudflight-libsonnet/applications/mailhog.libsonnet')\n+ {\n _config+: {\n mailhog: {\n name: 'mailhog',\n image: 'docker.io/anatomicjc/mailhog:1.0.1',\n host: error '$._config.mailhog.host must be defined',\n resources:: {\n limits: {\n cpu: '20m',\n memory: '64Mi',\n },\n requests: {\n cpu: '10m',\n memory: '64Mi',\n },\n },\n },\n\n }\n}\n
"},{"location":"modules/applications/spring-boot-admin/","title":"Spring Boot Admin","text":"This module creates an instance of spring-boot-admin, preconfigured to discover endpoints via Kubernetes.
The following snippets lists all available configuration options alongside their default values:
(import 'cloudflight-libsonnet/applications/spring-boot-admin.libsonnet')\n+ {\n _config+: {\n springBootAdmin: {\n name: 'spring-boot-admin',\n image: 'ghcr.io/cloudflightio/spring-boot-admin-docker:2.7.3',\n host: error '$._config.springBootAdmin.host must be defined',\n serviceAccountName: 'default',\n config: {\n spring: {\n cloud: {\n kubernetes: {\n discovery: {\n enabled: true,\n 'service-labels': {\n '[app.openshift.io/runtime]': 'spring-boot',\n },\n catalogServiceWatchDelay: 300,\n 'primary-port-name': 'actuator',\n },\n },\n },\n },\n },\n resources:: {\n limits: {\n cpu: '500m',\n memory: '512Mi',\n },\n requests: {\n cpu: '10m',\n memory: '512Mi',\n },\n },\n },\n\n }\n}\n
"},{"location":"modules/applications/spring-boot-admin/#integration-and-service-discovery","title":"Integration and Service Discovery","text":"When using our java helpers, spring-boot-admin will automatically discover provided services and their respective actuator endpoints.
To customize the discovery, modify $._config.springBootAdmin.config.spring.cloud.kubernetes.discovery
to match your labels.
This module contains a MariaDB instance, located in the mariadb
key.
The following snippets lists all available configuration options alongside their default values:
(import 'cloudflight-libsonnet/databases/mariadb.libsonnet')\n+ {\n _config+: {\n mariadb: {\n name: 'mariadb',\n storage: '5Gi',\n user: error 'cfg.user must be defined',\n password: error 'cfg.password must be defined',\n database: self.user,\n image: 'registry.redhat.io/rhel9/mariadb-105:1-105',\n datadirAction: 'upgrade-warn', // use 'upgrade-auto' to enable auto-upgrade when going to newer MariaDB version\n exporterImage: 'docker.io/prom/mysqld-exporter:v0.15.1',\n exporter_password: std.md5(self.password),\n resources:: {\n limits: {\n cpu: '500m',\n memory: '1Gi',\n },\n requests: {\n cpu: '200m',\n memory: '1Gi',\n },\n },\n },\n\n }\n}\n
"},{"location":"modules/databases/mariadb/#exposed-values","title":"Exposed values","text":"The following values are exposed, but not exported:
Name Contentsmariadb.passwordSecretKeyRef
A kubernetes secretKeyRef
, referencing the user password"},{"location":"modules/databases/mariadb/#starting-multiple-instances","title":"Starting multiple instances","text":"Another way to use this module, is by calling the newMariaDB
function. This allows you to create multiple instances without polluting the global scope.
{\n _config+:: {\n dbOne: {\n name: 'dbOne',\n user: 'foo',\n password: 'bar',\n },\n dbTwo: {\n name: 'dbTwo',\n user: 'foo',\n password: 'bar',\n }\n }\n dbOne: (import 'cloudflight-libsonnet/databases/mariadb.libsonnet').newMariaDB($._config.dbOne),\n dbTwo: (import 'cloudflight-libsonnet/databases/mariadb.libsonnet').newMariaDB($._config.dbTwo),\n}\n
"},{"location":"modules/databases/mssql/","title":"MSSQL Database Module","text":"This module contains a simple MSSQL instance, located in the mssql
key.
The following snippets lists all available configuration options alongside their default values:
Info
You need to set acceptEula
to true to accept the MSSQL EULA
(import 'cloudflight-libsonnet/databases/mssql.libsonnet')\n+ {\n _config+: {\n mssql: {\n name: 'mssql',\n storage: '5Gi',\n // The password must be at least 8 characters long and contain characters from three of the following four sets: Uppercase letters, Lowercase letters, Base 10 digits, and Symbols\n rootPassword: error 'cfg.rootPassword must be defined',\n productId: 'Developer',\n image: 'mcr.microsoft.com/mssql/rhel/server:2022-latest',\n acceptEula: false,\n resources:: {\n limits: {\n cpu: '500m',\n memory: '2Gi',\n },\n requests: {\n cpu: '200m',\n memory: '2Gi',\n },\n },\n },\n\n }\n}\n
"},{"location":"modules/databases/mssql/#exposed-values","title":"Exposed values","text":"The following values are exposed, but not exported:
Name Contentsmssql.passwordSecretKeyRef
A kubernetes secretKeyRef
, referencing the SA password"},{"location":"modules/databases/redis/","title":"Redis Cache Module","text":"This module contains a Redis Cache, located in the redis
key.
The following snippets lists all available configuration options alongside their default values:
(import 'cloudflight-libsonnet/databases/redis.libsonnet')\n+ {\n _config+: {\n redis: {\n name: 'redis',\n image: 'registry.redhat.io/rhel8/redis-6:1-62',\n exporterImage: 'docker.io/oliver006/redis_exporter:v1.43.0',\n password: error 'cfg.password must either be defined or set to null',\n storage: null,\n resources:: {\n limits: {\n cpu: '100m',\n memory: '1Gi',\n },\n requests: {\n cpu: '50m',\n memory: '1Gi',\n },\n },\n },\n\n }\n}\n
"},{"location":"modules/databases/redis/#starting-multiple-instances","title":"Starting multiple instances","text":"Another way to use this module, is by calling the newRedis
function. This allows you to create multiple instances without polluting the global scope.
{\n _config+:: {\n cacheOne: {\n name: 'cacheOne',\n password: 'foo',\n },\n cacheTwo: {\n name: 'cacheTwo',\n password: 'bar',\n }\n },\n cacheOne: (import 'cloudflight-libsonnet/databases/redis.libsonnet').newRedis($._config.cacheOne),\n cacheTwo: (import 'cloudflight-libsonnet/databases/redis.libsonnet').newRedis($._config.cacheTwo),\n}\n
"},{"location":"modules/databases/redis/#high-availability","title":"High Availability","text":"If required, you can instead import the redis-sentinel
module. This creates an additional sentinel deployment which fails over the master and replicas:
(import 'cloudflight-libsonnet/databases/redis-sentinel.libsonnet')\n+ {\n _config+: {\n redis: {\n name: 'redis',\n replicas: 3,\n sentinels: 3,\n image: 'quay.io/fedora/redis-6:20221012',\n exporterImage: 'docker.io/oliver006/redis_exporter:v1.43.0',\n password: error 'cfg.password must either be defined or set to null',\n topologyKey: 'kubernetes.io/hostname',\n storage: null,\n resources:: {\n limits: {\n cpu: '100m',\n memory: '1Gi',\n },\n requests: {\n cpu: '50m',\n memory: '1Gi',\n },\n },\n },\n\n }\n}\n
"},{"location":"modules/databases/redis/#exposed-values","title":"Exposed values","text":"When using redis-sentinel
, you also have access to the following values. They are exposed, but not exported.
redis.sentinelNodes
Array of sentinel host:port pairs"},{"location":"modules/infrastructure/cert-manager/","title":"Cert-Manager Module","text":"This adds certmanager (see https://cert-manager.io/), located in the certmanager
key.
It helpes you issuing and managing certificated using custom k8s resources only.
The following snippets lists all available configuration options alongside their default values:
(import 'cloudflight-libsonnet/infrastructure/cert-manager/cert-manager.libsonnet')\n+ {\n _config+: {\n certmanager: {\n name: 'cert-manager',\n aks: false,\n },\n\n }\n}\n
"},{"location":"modules/infrastructure/cert-manager/#example","title":"Example","text":"(import 'cloudflight-libsonnet/infrastructure/cert-manager/cert-manager.libsonnet')\n+ {\n _config+: {\n certmanager: {\n name: 'cert-manager',\n namespace: 'cert-manager',\n aks: true,\n },\n },\n}\n
"},{"location":"modules/infrastructure/cert-manager/#addons","title":"Addons","text":"There is also a special set of utilities and extensions that can be used to make the setup process easier.
This example installs cert-manager, adds a lets-encrypt issuer and a ssl-protected ingress-rule:
local k = (import 'k.libsonnet');\nlocal ingress = k.networking.v1.ingress;\n\n(import 'cloudflight-libsonnet/infrastructure/cert-manager/cert-manager.libsonnet')\n+ {\n issuer: k.util.certmanager.issuer.new('admin@example.com'),\n ingress: ingress.new('test.example.com') + ingress.withCertMixin($.issuer),\n}\n
"},{"location":"modules/infrastructure/k8s-digester/","title":"k8s-digester Module","text":"This module installs the k8s-digester in your cluster. It currently does not offer any customization options and is functionally equivalent to applying the digester_manifest.yaml
.
The reason for this module is to have everything you need in one place without relying on manual kubectl apply
steps.
This adds nginx-ingress-controller (see https://github.com/kubernetes/ingress-nginx), located in the nginxingress
key.
This is helpful if no other ingress-controller is deployes (e.g. AKS without API Gateway).
The following snippets lists all available configuration options alongside their default values:
(import 'cloudflight-libsonnet/infrastructure/nginx-ingress/nginx-ingress.libsonnet')\n+ {\n _config+: {\n nginxingress: {\n name: 'nginx-ingress',\n type: 'external',\n loadBalancerIP: error 'you need a static loadbalancer ip (public IP for external, internal IP for internal)',\n internalSubnetAzure: null,\n replicas: 2,\n defaultTlsCertificate: null,\n },\n\n }\n}\n
"}]}
\ No newline at end of file
+{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":"Welcome to the documentation of the Cloudflight jsonnet library.
This library contains utilities and premade modules to ease working with Kubernets and OpenShift.
To get started, take a look at the guides or the module documentation.
If you know your way around jsonnet already, why not take a look at our complete library?
If you want support for your editor you should use one of the plugins listed on the tools page. We recommend plugins based on the jsonnet-language server.
Info
cloudflight-libsonnet
is inteded to be used with Tanka. Other tools might work, however we do not test for them. If you're using kubecfg
, take a look at our migration guide.
This section contains guides for various usecases concerning our jsonnet library.
If you just want to get going, take a look at the quick start.
"},{"location":"guides/#external-resources","title":"External Resources","text":"To start using this library, first initialize the working directory using tk init
.
This will create a directory structure similar to this:
.\n\u251c\u2500\u2500 environments\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 default\n\u251c\u2500\u2500 jsonnetfile.json\n\u251c\u2500\u2500 jsonnetfile.lock.json\n\u251c\u2500\u2500 lib\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 k.libsonnet\n\u2514\u2500\u2500 vendor\n \u251c\u2500\u2500 1.23 -> github.com/jsonnet-libs/k8s-libsonnet/1.23\n \u251c\u2500\u2500 github.com\n \u2514\u2500\u2500 ksonnet-util -> github.com/grafana/jsonnet-libs/ksonnet-util\n
Next, we need to install the cloudflight-libsonnet
library using jb
:
jb install github.com/cloudflightio/cloudflight-libsonnet@main\n
The last step is to adapt the predefined k.libsonnet
. When initializing, Tanka simply imports the k8s-libsonnet
library here. Since some of our customizations depend on other libraries which have to be imported at this point (such as openshift-libsonnet
or prometheus-libsonnet
), you replace the contents of k.libsonnet
with the following:
import 'github.com/cloudflightio/cloudflight-libsonnet/k.libsonnet'\n
"},{"location":"guides/quickstart/#using-the-library","title":"Using the library","text":"To use the components provided by this library (or other Kubernetes components), import our prelude.libsonnet
.
Let's use the library to deploy a simple java based application, backed by an MariaDB instance.
"},{"location":"guides/quickstart/#creating-the-application","title":"Creating the application","text":"Applications should be defined in the lib
folder. To configure a java application, we create a file called lib/test-java.libsonnet
with the contents below.
local k = (import 'cloudflight-libsonnet/prelude.libsonnet');\n{\n _config+:: {\n myApplication: {\n name: 'my-application',\n image: error '$._config.myApplication.image must be defined',\n },\n },\n myApplication: {\n deployment: k.util.java.deployment.new(\n name=$._config.myApplication.name,\n image=$._config.myApplication.image,\n containerMixin=k.core.v1.container.livenessProbe.withInitialDelaySeconds(60),\n ),\n service: k.util.serviceFor(self.deployment),\n route: k.util.routeFor(self.service, 'hello.example.com'),\n },\n}\n
Now we can import this into our environment file environments/default/main.jsonnet
(import 'test-java.libsonnet')\n+ {\n _config+: {\n myApplication+: {\n image: 'helloworld:latest',\n },\n },\n}\n
Provided your .kube/config
and environments/default/spec.json
are set up correctly, you can deploy this by running tk apply environments/default
.
Most applications want to store data somewhere so let's add a database next. First, we import the database of choice in the main.jsonnet
file.
(import 'cloudflight-libsonnet/databases/mariadb.libsonnet')\n+ (import 'test-java.libsonnet')\n+ {\n _config+: {\n mariadb+: {\n user: 'application-user',\n password: 'hunter2',\n database: 'my-application',\n },\n myApplication+: {\n image: 'helloworld:latest',\n },\n },\n}\n
To connect our application to the database, we need to configure the deployment on a lower level. This is because of the fact, that the plain util.java.deployment
does not make any assumptions about databases.
As documented in the java module, we build the deployment ourselves, but mix in some environment variables.
local k = (import 'cloudflight-libsonnet/prelude.libsonnet');\n{\n _config+:: {\n myApplication: {\n name: 'my-application',\n image: error '$._config.myApplication.image must be defined',\n dbUser: error '$._config.myApplication.dbUser must be defined',\n dbPasswordRef: error '$._config.myApplication.dbPasswordRef must be a valid secretSecretKeyRef',\n dbUrl: error '$._config.myApplication.dbUrl must be defined',\n },\n },\n myApplication: {\n deployment: k.apps.v1.deployment.new(\n name=$._config.myApplication.name,\n replicas=1,\n containers=[\n k.util.java.container.new($._config.myApplication.name, $._config.myApplication.image)\n + k.core.v1.container.withEnvMixin([\n {\n name: 'SPRING_DATASOURCE_PASSWORD',\n valueFrom: { secretKeyRef: $._config.myApplication.dbPasswordRef },\n },\n {\n name: 'SPRING_DATASOURCE_USERNAME',\n value: $._config.myApplication.dbUser,\n },\n {\n name: 'SPRING_DATASOURCE_URL',\n value: $._config.myApplication.dbUrl,\n },\n ]),\n ]\n ),\n service: k.util.serviceFor(self.deployment),\n route: k.util.routeFor(self.service, 'hello.example.com'),\n },\n}\n
In the last step, we fill the new config parameters with values.
(import 'cloudflight-libsonnet/databases/mariadb.libsonnet')\n+ (import 'test-java.libsonnet')\n+ {\n _config+: {\n mariadb+: {\n user: 'application-user',\n password: 'hunter2',\n database: 'my-application',\n },\n myApplication+: {\n image: 'helloworld:latest',\n dbUser: $._config.mariadb.user,\n dbPasswordRef: $.mariadb.passwordSecretKeyRef,\n dbUrl: 'jdbc:mysql://' + $.mariadb.service.metadata.name + '/' + $._config.mariadb.database,\n },\n },\n mariadb2: (import 'cloudflight-libsonnet/databases/mariadb.libsonnet') + {\n _config+: {\n mariadb+: {\n name: 'foo',\n user: 'foo-user',\n password: 'foo-user',\n },\n },\n },\n}\n
And we're done!
To recap: we have configured an application, added a database and connected it to our application. The way we connected the applications is transparent, and we could (as long as the application supports it) change the database entirely in our main.jsonnet
. This way, we can use different database setups across environment, while keeping the application configuration the same.
For more information, check out the documentation of the java utilities and the MariaDB module.
"},{"location":"guides/tanka_migration/","title":"Migrating to Tanka","text":"At Cloudflight we were previously using kubecfg
to deploy our applications. As of 2022-02-21
, tanka is our recommended tool for Kubernetes configurations. Reasoning for this can be found in ADR-0077.
If you're still using kubecfg
you're in Luck! The migration to Tanka is very simple and can be done in under five minutes.
Tip
TL;DR:
Before we can start to migrate to the new setup, we should be confident in the old one to avoid issues further down the line.
As a requirement, you should be able to view your configuration in the yaml format by running
kubecfg show $YOUR_STAGE_FILE\n
"},{"location":"guides/tanka_migration/#restructuring","title":"Restructuring","text":"The main change required for a smooth workflow in Tanka, is a small restructuring of the directory. Our old layout prescribes a flat structure with everything in the root directory. Tanka on the other hand expects a folder per environment. To perform this step, you need to go from this:
.\n\u251c\u2500\u2500 jsonnetfile.json\n\u251c\u2500\u2500 production.jsonnet\n\u251c\u2500\u2500 resources\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 application.jsonnet\n\u2514\u2500\u2500 staging.jsonnet\n
to
.\n\u251c\u2500\u2500 jsonnetfile.json\n\u251c\u2500\u2500 environments\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 production\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 main.jsonnet # (1)\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 staging\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 main.jsonnet # (2)\n\u2514\u2500\u2500 lib\n \u2514\u2500\u2500 application.libsonnet\n
production.jsonnet
staging.jsonnet
Instead of relying on the current Kubernetes context, Tanka needs explicit information on the API Server as well as the namespace.
This information is saved in the spec.json
file, contained in the respective environment. The complete layout can be found in the Tanka documentation
The syntax is as follows:
{\n \"apiVersion\": \"tanka.dev/v1alpha1\",\n \"kind\": \"Environment\",\n \"metadata\": {\n \"name\": \"environments/staging\"\n },\n \"spec\": {\n \"apiServer\": \"openshift-dev.internal.cloudflight.io:6443\", // (1)\n \"namespace\": \"762-example-staging\", // (2)\n \"resourceDefaults\": {},\n \"expectVersions\": {},\n \"injectLabels\": true\n }\n}\n
Now that you moved around the files, you will also need to fix the imports contained within them. For convenience, Tanka automatically includes the lib
and vendor
directory in the jsonnet path. So instead of having to write ../../lib/application.libsonnet
you can simply import application.libsonnet
.
After fixing the imports, you can show the new configuration with the following command:
tk show environments/staging\n
"},{"location":"guides/tanka_migration/#teamcity","title":"TeamCity","text":"Tanka integration from TeamCity is supported from version 3.0.0
of the cloudflight-teamcity-dsl onwards.
Example:
subCloudflightProject {\n name = \"Deployment\"\n tankaApply {\n openShiftConfig {\n serviceAccountToken = \"credentialsJSON:...\"\n }\n contextDir = \".openshift\" // (1)\n }\n}\n
deployment
as is the case with our new configuration skeletonThis library contains various utility modules for use with the jsonnet configuration language To get started, import the provided prelude which will composit the library for you.
local k = import ('cloudflight-libsonnet/prelude.libsonnet');\n
The prelude depends on a file called k.libsonnet
being available for import. Either place it in your lib or environment folder. Using the environment folder allows for library level configuration options to be applied on an environment level.
This works, because import paths are ranked as highlighted in the Tanka documentation.
A pre-populated k.libsonnet
is available in this library so a minimal k.libsonnet
would look like this:
(import 'cloudflight-libsonnet/k.libsonnet')\n
This includes k8s-libsonnet, openshift-libsonnet as well as prometheus-libsonnet
For more information on customization options in k.libsonnet
, take a look at the labeling extension.
Contains extensions related to core kubernetes components
"},{"location":"library/core/#index","title":"Index","text":"obj v1
obj v1.container
fn new(name, image, unprivileged='true')
new(name, image, unprivileged='true')\n
new returns a new container of given name and image. By default it injects an openshift 4.11 compatible securityContext
"},{"location":"library/extensions/","title":"extensions","text":"Extensions available to the standard library
"},{"location":"library/labeling/","title":"labeling","text":"This extension allows you to label core kubernetes resources with useful labels.
"},{"location":"library/labeling/#usage","title":"Usage","text":"To use this labeling function, edit your k.libsonnet
to look something like this
(import 'cloudflight-libsonnet/k.libsonnet')\n+ {\n _config+:: {\n project: 'some-project-name'\n }\n}\n
Afterwards, all resources created (provided they use cloudflight-libsonnet/prelude.libsonnet
), will have the cloudflight.io/project=some-project-name
label attached
If you need to set this on a per-environment basis, move the k.libsonnet
file to your environment folder as described in the Tanka documentation.
Contains extensions related to cert-manager
"},{"location":"library/networking/#index","title":"Index","text":"obj v1
obj v1.ingress
fn withCertMixin(issuer, clusterwide)
withCertMixin(issuer, clusterwide)\n
withCertMixin instructs cert-manager to add an certificate to the ingress-resource.
"},{"location":"library/route/","title":"route","text":"Contains extensions to the default route functions provided by openshift-libsonnet
"},{"location":"library/route/#index","title":"Index","text":"obj v1
obj v1.route
fn new(name, host, path)
new(name, host, path)\n
builds a route with a predefined host and TLS Edge termination
"},{"location":"library/util/","title":"util","text":"The util package contains ease of use functions to simplify working with kubernetes and jsonnet
"},{"location":"library/util/#index","title":"Index","text":"fn ingressFor(service, host='', path='/', port='service.spec.ports[0].port')
fn routeFor(service, host='', path='/', port='service.spec.ports[0].port')
fn serviceFor(deployment, ignored_labels, nameFormat='%(port)s')
fn weightedRouteFor(name, host='', port='', services, path='/')
obj certmanager
obj certmanager.issuer
fn new(emain, ingressClassName='nginx', production=true, clusterwide=true, name='letsencrypt-production || letsencrypt-staging')
obj java
obj java.container
fn new(name, image, port=8080, actuatorPort='port+8080', env={})
obj java.deployment
fn new(name, image, replicas=1, env={}, containerMixin={}, runtime='spring-boot', component='backend')
obj java.livenessProbe
fn new(port=8080, initialDelaySeconds=30)
obj java.readinessProbe
fn new(port=18080, path='/actuator/health')
obj openshiftOAuth
obj openshiftOAuth.container
fn new(upstream, serviceAccount)
obj openshiftOAuth.deployment
fn withProxy(upstream, serviceAccount)
obj openshiftOAuth.serviceAccount
fn new(name, route)
ingressFor(service, host='', path='/', port='service.spec.ports[0].port')\n
ingressFor constructs a ingress object, compatible with the automatic translation to openshift routes. It expects a value for the hostname and defaults to '/' for the path.
"},{"location":"library/util/#fn-routefor","title":"fn routeFor","text":"routeFor(service, host='', path='/', port='service.spec.ports[0].port')\n
routeFor constructs a openshift route to the specified service. It expects a value for the hostname and defaults to '/' for the path.
"},{"location":"library/util/#fn-servicefor","title":"fn serviceFor","text":"serviceFor(deployment, ignored_labels, nameFormat='%(port)s')\n
serviceFor constructs a service for the specified deployment.
Selector labels are taken from the pod spec but can be ignored using the ignored_labels
parameter.
The ports of the service will have the same name as in the container spec to avoid confusion. This can be changed with the nameFormat
parameter.
weightedRouteFor(name, host='', port='', services, path='/')\n
weightedRouteFor constructs a openshift route to the specified services. It expects a value for the name, hostname, port, services and defaults to '/' for the path. services expects an array consisting of objects with the keys name (name of the service) and weight.
"},{"location":"library/util/#obj-certmanager","title":"obj certmanager","text":"certman holds functions related to cert-manager (cert-manager.io)
"},{"location":"library/util/#obj-certmanagerissuer","title":"obj certmanager.issuer","text":""},{"location":"library/util/#fn-certmanagerissuernew","title":"fn certmanager.issuer.new","text":"new(emain, ingressClassName='nginx', production=true, clusterwide=true, name='letsencrypt-production || letsencrypt-staging')\n
constructs a cert-manager issuer resource for letsencrypt with sensible default.
"},{"location":"library/util/#obj-java","title":"obj java","text":"java holds my functions related to java based applications
"},{"location":"library/util/#obj-javacontainer","title":"obj java.container","text":""},{"location":"library/util/#fn-javacontainernew","title":"fn java.container.new","text":"new(name, image, port=8080, actuatorPort='port+8080', env={})\n
constructs a container with reccomended settings for Java/Spring Boot applications. Includes liveness- and readiness probes, activates the kubernetes
spring profile and sets sensible resource defaults.
new(name, image, replicas=1, env={}, containerMixin={}, runtime='spring-boot', component='backend')\n
constructs a deployment using the java container. If you need more control, construct this deployment yourself.
containerMixin
can be used to modify the application container. For example:
deployment.new(/*...*/,\n containerMixin=k.core.v1.container.livenessProbe.withInitialDelaySeconds(60))\n
increases the initial delay seconds of the default liveness probe. The runtime
and component
parameters are used to prefill recommended labels
new(port=8080, initialDelaySeconds=30)\n
new constructs a fresh liveness probe, checking if the tcp port 8080 is open
"},{"location":"library/util/#obj-javareadinessprobe","title":"obj java.readinessProbe","text":""},{"location":"library/util/#fn-javareadinessprobenew","title":"fn java.readinessProbe.new","text":"new(port=18080, path='/actuator/health')\n
new constructs a fresh readiness probe, checking if the application is up. The port and path of the actuator endpoint can be changed using the parameters.
"},{"location":"library/util/#obj-openshiftoauth","title":"obj openshiftOAuth","text":"openshiftOAuth contains utilities to proxy an application using the OpenShift OAuth Proxy
"},{"location":"library/util/#obj-openshiftoauthcontainer","title":"obj openshiftOAuth.container","text":""},{"location":"library/util/#fn-openshiftoauthcontainernew","title":"fn openshiftOAuth.container.new","text":"new(upstream, serviceAccount)\n
constructs a container proxying connections to the upstream
parameter.
withProxy(upstream, serviceAccount)\n
add a proxy sidecar to the container. This also sets the service account used by the pod. The ServiceAccount needs to have the correct redirect reference for the route. See openshiftOAuth.serviceAccount.new
for an easy way to create a compliant service account
new(name, route)\n
constructs a serviceaccount annotated with a oauth-redirectreference pointing to the route parameter
"},{"location":"modules/","title":"What are modules?","text":"Modules are ready-to-use setups of existing applications and services. To use them, import them into your main.libsonnet
like so:
(import 'cloudflight-libsonnet/databases/mariadb.libsonnet') + {\n _config+: {\n mariadb+: {\n user: 'foo',\n password: 'bar',\n }\n }\n}\n
"},{"location":"modules/java_application/","title":"Java Applications","text":"Even though not strictly a module, this library contains a lot of utility functions to help you deploy Java applications. This page contains some ways these functions can be used.
"},{"location":"modules/java_application/#all-in-one","title":"All-in-one","text":"This example contains the deployment of a simple spring boot based application. It should be located somewhere like lib/my-application.libsonnet
.
local k = (import 'cloudflight-libsonnet/prelude.libsonnet');\n{\n _config+:: {\n myApplication: {\n name: 'my-application',\n image: error '$._config.myApplication.image must be defined',\n },\n },\n myApplication: {\n deployment: k.util.java.deployment.new(\n name=$._config.myApplication.name,\n image=$._config.myApplication.image,\n containerMixin=k.core.v1.container.livenessProbe.withInitialDelaySeconds(60),\n ),\n service: k.util.serviceFor(self.deployment),\n route: k.util.routeFor(self.service, 'hello.example.com'),\n },\n}\n
apiVersion: v1\nkind: Service\nmetadata:\nlabels:\n name: my-application\nname: my-application\nnamespace: test-java\nspec:\nports:\n- name: my-application-http\n port: 8080\n targetPort: 8080\n- name: my-application-actuator\n port: 9080\n targetPort: 9080\nselector:\n name: my-application\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\nname: my-application\nnamespace: test-java\nspec:\nminReadySeconds: 10\nreplicas: 1\nrevisionHistoryLimit: 10\nselector:\n matchLabels:\n name: my-application\ntemplate:\n metadata:\n labels:\n name: my-application\n spec:\n containers:\n - env:\n - name: SPRING_PROFILES_ACTIVE\n value: kubernetes\n image: helloworld:latest\n imagePullPolicy: IfNotPresent\n livenessProbe:\n failureThreshold: 5\n initialDelaySeconds: 30\n periodSeconds: 10\n successThreshold: 1\n tcpSocket:\n port: 8080\n timeoutSeconds: 1\n name: my-application\n ports:\n - containerPort: 8080\n name: http\n - containerPort: 9080\n name: actuator\n readinessProbe:\n failureThreshold: 5\n httpGet:\n path: /actuator/health\n port: 18080\n initialDelaySeconds: 30\n periodSeconds: 10\n successThreshold: 1\n timeoutSeconds: 1\n resources:\n limits:\n cpu: 500m\n memory: 1Gi\n requests:\n cpu: 100m\n memory: 1Gi\n---\napiVersion: route.openshift.io/v1\nkind: Route\nmetadata:\nname: my-application\nnamespace: test-java\nspec:\nhost: hello.example.com\npath: /\nport:\n targetPort: 8080\ntls:\n insecureEdgeTerminationPolicy: Redirect\n termination: Edge\nto:\n kind: Service\n name: my-application\n
Switch between the tabs to see the rendered output
"},{"location":"modules/java_application/#diy","title":"DIY","text":"If you have the need for further customization, you can pick and choose parts of the library you would like to use.
In this example, we want to modify the container so we use the util.java.container.new()
to get a base structure and extend it. This way, we still have the defaults set, but are able to customize them to our hearts content.
local k = (import 'cloudflight-libsonnet/prelude.libsonnet');\n{\n _config+:: {\n myApplication: {\n name: 'my-application',\n image: error '$._config.myApplication.image must be defined',\n },\n },\n myApplication: {\n deployment: k.apps.v1.deployment.new(\n name=$._config.myApplication.name,\n replicas=2,\n containers=[\n k.util.java.container.new($._config.myApplication.name, $._config.myApplication.image)\n + k.core.v1.container.withVolumeMounts([\n k.core.v1.volumeMount.new(name='temp', mountPath='/opt/cache'),\n ]),\n ]\n )\n + k.apps.v1.deployment.spec.template.spec.withVolumes([\n k.core.v1.volume.fromEmptyDir(name='temp'),\n ]),\n service: k.util.serviceFor(self.deployment),\n route: k.util.routeFor(self.service, 'hello.example.com'),\n },\n}\n
apiVersion: v1\nkind: Service\nmetadata:\n labels:\n name: my-application\n name: my-application\n namespace: test-java-diy\nspec:\n ports:\n - name: my-application-http\n port: 8080\n targetPort: 8080\n - name: my-application-actuator\n port: 9080\n targetPort: 9080\n selector:\n name: my-application\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: my-application\n namespace: test-java-diy\nspec:\n minReadySeconds: 10\n replicas: 2\n revisionHistoryLimit: 10\n selector:\n matchLabels:\n name: my-application\n template:\n metadata:\n labels:\n name: my-application\n spec:\n containers:\n - env:\n - name: SPRING_PROFILES_ACTIVE\n value: kubernetes\n image: helloworld:latest\n imagePullPolicy: IfNotPresent\n livenessProbe:\n failureThreshold: 5\n initialDelaySeconds: 30\n periodSeconds: 10\n successThreshold: 1\n tcpSocket:\n port: 8080\n timeoutSeconds: 1\n name: my-application\n ports:\n - containerPort: 8080\n name: http\n - containerPort: 9080\n name: actuator\n readinessProbe:\n failureThreshold: 5\n httpGet:\n path: /actuator/health\n port: 18080\n initialDelaySeconds: 30\n periodSeconds: 10\n successThreshold: 1\n timeoutSeconds: 1\n resources:\n limits:\n cpu: 500m\n memory: 1Gi\n requests:\n cpu: 100m\n memory: 1Gi\n volumeMounts:\n - mountPath: /opt/cache\n name: temp\n volumes:\n - emptyDir: {}\n name: temp\n---\napiVersion: route.openshift.io/v1\nkind: Route\nmetadata:\n name: my-application\n namespace: test-java-diy\nspec:\n host: hello.example.com\n path: /\n port:\n targetPort: 8080\n tls:\n insecureEdgeTerminationPolicy: Redirect\n termination: Edge\n to:\n kind: Service\n name: my-application\n
"},{"location":"modules/applications/mailhog/","title":"Mailhog","text":"This module creates an instance of mailhog. Data is stored in memory only so messages will disappear after a pod restart.
The following snippet lists all available configuration options alongside their default values:
(import 'cloudflight-libsonnet/applications/mailhog.libsonnet')\n+ {\n _config+: {\n mailhog: {\n name: 'mailhog',\n image: 'docker.io/anatomicjc/mailhog:1.0.1',\n host: error '$._config.mailhog.host must be defined',\n resources:: {\n limits: {\n cpu: '20m',\n memory: '64Mi',\n },\n requests: {\n cpu: '10m',\n memory: '64Mi',\n },\n },\n },\n\n }\n}\n
"},{"location":"modules/applications/spring-boot-admin/","title":"Spring Boot Admin","text":"This module creates an instance of spring-boot-admin, preconfigured to discover endpoints via Kubernetes.
The following snippets lists all available configuration options alongside their default values:
(import 'cloudflight-libsonnet/applications/spring-boot-admin.libsonnet')\n+ {\n _config+: {\n springBootAdmin: {\n name: 'spring-boot-admin',\n image: 'ghcr.io/cloudflightio/spring-boot-admin-docker:2.7.3',\n host: error '$._config.springBootAdmin.host must be defined',\n serviceAccountName: 'default',\n config: {\n spring: {\n cloud: {\n kubernetes: {\n discovery: {\n enabled: true,\n 'service-labels': {\n '[app.openshift.io/runtime]': 'spring-boot',\n },\n catalogServiceWatchDelay: 300,\n 'primary-port-name': 'actuator',\n },\n },\n },\n },\n },\n resources:: {\n limits: {\n cpu: '500m',\n memory: '512Mi',\n },\n requests: {\n cpu: '10m',\n memory: '512Mi',\n },\n },\n },\n\n }\n}\n
"},{"location":"modules/applications/spring-boot-admin/#integration-and-service-discovery","title":"Integration and Service Discovery","text":"When using our java helpers, spring-boot-admin will automatically discover provided services and their respective actuator endpoints.
To customize the discovery, modify $._config.springBootAdmin.config.spring.cloud.kubernetes.discovery
to match your labels.
This module contains a MariaDB instance, located in the mariadb
key.
The following snippets lists all available configuration options alongside their default values:
(import 'cloudflight-libsonnet/databases/mariadb.libsonnet')\n+ {\n _config+: {\n mariadb: {\n name: 'mariadb',\n storage: '5Gi',\n user: error 'cfg.user must be defined',\n password: error 'cfg.password must be defined',\n database: self.user,\n image: 'registry.redhat.io/rhel9/mariadb-105:1-105',\n datadirAction: 'upgrade-warn', // use 'upgrade-auto' to enable auto-upgrade when going to newer MariaDB version\n exporterImage: 'docker.io/prom/mysqld-exporter:v0.15.1',\n exporterPassword: std.md5(self.password),\n resources:: {\n limits: {\n cpu: '500m',\n memory: '1Gi',\n },\n requests: {\n cpu: '200m',\n memory: '1Gi',\n },\n },\n },\n\n }\n}\n
"},{"location":"modules/databases/mariadb/#exposed-values","title":"Exposed values","text":"The following values are exposed, but not exported:
Name Contentsmariadb.passwordSecretKeyRef
A kubernetes secretKeyRef
, referencing the user password"},{"location":"modules/databases/mariadb/#starting-multiple-instances","title":"Starting multiple instances","text":"Another way to use this module, is by calling the newMariaDB
function. This allows you to create multiple instances without polluting the global scope.
{\n _config+:: {\n dbOne: {\n name: 'dbOne',\n user: 'foo',\n password: 'bar',\n },\n dbTwo: {\n name: 'dbTwo',\n user: 'foo',\n password: 'bar',\n }\n }\n dbOne: (import 'cloudflight-libsonnet/databases/mariadb.libsonnet').newMariaDB($._config.dbOne),\n dbTwo: (import 'cloudflight-libsonnet/databases/mariadb.libsonnet').newMariaDB($._config.dbTwo),\n}\n
"},{"location":"modules/databases/mssql/","title":"MSSQL Database Module","text":"This module contains a simple MSSQL instance, located in the mssql
key.
The following snippets lists all available configuration options alongside their default values:
Info
You need to set acceptEula
to true to accept the MSSQL EULA
(import 'cloudflight-libsonnet/databases/mssql.libsonnet')\n+ {\n _config+: {\n mssql: {\n name: 'mssql',\n storage: '5Gi',\n // The password must be at least 8 characters long and contain characters from three of the following four sets: Uppercase letters, Lowercase letters, Base 10 digits, and Symbols\n rootPassword: error 'cfg.rootPassword must be defined',\n productId: 'Developer',\n image: 'mcr.microsoft.com/mssql/rhel/server:2022-latest',\n acceptEula: false,\n resources:: {\n limits: {\n cpu: '500m',\n memory: '2Gi',\n },\n requests: {\n cpu: '200m',\n memory: '2Gi',\n },\n },\n },\n\n }\n}\n
"},{"location":"modules/databases/mssql/#exposed-values","title":"Exposed values","text":"The following values are exposed, but not exported:
Name Contentsmssql.passwordSecretKeyRef
A kubernetes secretKeyRef
, referencing the SA password"},{"location":"modules/databases/redis/","title":"Redis Cache Module","text":"This module contains a Redis Cache, located in the redis
key.
The following snippets lists all available configuration options alongside their default values:
(import 'cloudflight-libsonnet/databases/redis.libsonnet')\n+ {\n _config+: {\n redis: {\n name: 'redis',\n image: 'registry.redhat.io/rhel8/redis-6:1-62',\n exporterImage: 'docker.io/oliver006/redis_exporter:v1.43.0',\n password: error 'cfg.password must either be defined or set to null',\n storage: null,\n resources:: {\n limits: {\n cpu: '100m',\n memory: '1Gi',\n },\n requests: {\n cpu: '50m',\n memory: '1Gi',\n },\n },\n },\n\n }\n}\n
"},{"location":"modules/databases/redis/#starting-multiple-instances","title":"Starting multiple instances","text":"Another way to use this module, is by calling the newRedis
function. This allows you to create multiple instances without polluting the global scope.
{\n _config+:: {\n cacheOne: {\n name: 'cacheOne',\n password: 'foo',\n },\n cacheTwo: {\n name: 'cacheTwo',\n password: 'bar',\n }\n },\n cacheOne: (import 'cloudflight-libsonnet/databases/redis.libsonnet').newRedis($._config.cacheOne),\n cacheTwo: (import 'cloudflight-libsonnet/databases/redis.libsonnet').newRedis($._config.cacheTwo),\n}\n
"},{"location":"modules/databases/redis/#high-availability","title":"High Availability","text":"If required, you can instead import the redis-sentinel
module. This creates an additional sentinel deployment which fails over the master and replicas:
(import 'cloudflight-libsonnet/databases/redis-sentinel.libsonnet')\n+ {\n _config+: {\n redis: {\n name: 'redis',\n replicas: 3,\n sentinels: 3,\n image: 'quay.io/fedora/redis-6:20221012',\n exporterImage: 'docker.io/oliver006/redis_exporter:v1.43.0',\n password: error 'cfg.password must either be defined or set to null',\n topologyKey: 'kubernetes.io/hostname',\n storage: null,\n resources:: {\n limits: {\n cpu: '100m',\n memory: '1Gi',\n },\n requests: {\n cpu: '50m',\n memory: '1Gi',\n },\n },\n },\n\n }\n}\n
"},{"location":"modules/databases/redis/#exposed-values","title":"Exposed values","text":"When using redis-sentinel
, you also have access to the following values. They are exposed, but not exported.
redis.sentinelNodes
Array of sentinel host:port pairs"},{"location":"modules/infrastructure/cert-manager/","title":"Cert-Manager Module","text":"This adds certmanager (see https://cert-manager.io/), located in the certmanager
key.
It helpes you issuing and managing certificated using custom k8s resources only.
The following snippets lists all available configuration options alongside their default values:
(import 'cloudflight-libsonnet/infrastructure/cert-manager/cert-manager.libsonnet')\n+ {\n _config+: {\n certmanager: {\n name: 'cert-manager',\n aks: false,\n },\n\n }\n}\n
"},{"location":"modules/infrastructure/cert-manager/#example","title":"Example","text":"(import 'cloudflight-libsonnet/infrastructure/cert-manager/cert-manager.libsonnet')\n+ {\n _config+: {\n certmanager: {\n name: 'cert-manager',\n namespace: 'cert-manager',\n aks: true,\n },\n },\n}\n
"},{"location":"modules/infrastructure/cert-manager/#addons","title":"Addons","text":"There is also a special set of utilities and extensions that can be used to make the setup process easier.
This example installs cert-manager, adds a lets-encrypt issuer and a ssl-protected ingress-rule:
local k = (import 'k.libsonnet');\nlocal ingress = k.networking.v1.ingress;\n\n(import 'cloudflight-libsonnet/infrastructure/cert-manager/cert-manager.libsonnet')\n+ {\n issuer: k.util.certmanager.issuer.new('admin@example.com'),\n ingress: ingress.new('test.example.com') + ingress.withCertMixin($.issuer),\n}\n
"},{"location":"modules/infrastructure/k8s-digester/","title":"k8s-digester Module","text":"This module installs the k8s-digester in your cluster. It currently does not offer any customization options and is functionally equivalent to applying the digester_manifest.yaml
.
The reason for this module is to have everything you need in one place without relying on manual kubectl apply
steps.
This adds nginx-ingress-controller (see https://github.com/kubernetes/ingress-nginx), located in the nginxingress
key.
This is helpful if no other ingress-controller is deployes (e.g. AKS without API Gateway).
The following snippets lists all available configuration options alongside their default values:
(import 'cloudflight-libsonnet/infrastructure/nginx-ingress/nginx-ingress.libsonnet')\n+ {\n _config+: {\n nginxingress: {\n name: 'nginx-ingress',\n type: 'external',\n loadBalancerIP: error 'you need a static loadbalancer ip (public IP for external, internal IP for internal)',\n internalSubnetAzure: null,\n replicas: 2,\n defaultTlsCertificate: null,\n },\n\n }\n}\n
"}]}
\ No newline at end of file
diff --git a/main/sitemap.xml.gz b/main/sitemap.xml.gz
index a39dacc..3584e9f 100644
Binary files a/main/sitemap.xml.gz and b/main/sitemap.xml.gz differ