Create a new module and learn its structure and development workflow.
This guide will walk you through the process of creating a new Timoni module.
We’ll explore the structure of the created module, and the various development
commands that Timoni provides to aid module development.Furthermore, this guide provides an overview of the templating system,
including the module configuration values, the Kubernetes templates,
and how to generate Kubernetes objects from these templates.
Timoni comes with a set of commands that help with module development.At most times, after making changes, you’ll be using the
timoni mod vet command to verify that
the module config and the Kubernetes templates are valid.
To build a module instance, run the following command:
timoni -n test build nginx .
The build command generates a Kubernetes Deployment and Service,
and prints the Kubernetes resources to stdout in YAML format.If you inspect the output, you’ll notice that the Kubernetes metadata
matches the instance name and namespace specified in the build command:
By convention, Timoni uses the app.kubernetes.io/name label to set the
Deployment selector and the Service selector.The app.kubernetes.io/version label is used to track the module version
from the container registry, and it’s set to 0.0.0-devel by default, when
building a module locally.To create the module instance on a Kubernetes cluster:
timoni -n test apply nginx .
The apply command will create the Kubernetes resources and will wait for the
Deployment and Service to become ready. If the test namespace doesn’t exist,
Timoni will create it.
Diff changesWhen making changes to the module, you can use the timoni apply --diff
flag to see the differences between the in-cluster resources
and the newly generated ones.
The values of the Kubernetes Secrets data entries are masked in the diff. To mask them in the
timoni build output as well, use the --mask-secrets flag.
To delete the module instance:
timoni -n test delete nginx .
The delete command will remove the Kubernetes Deployment and Service from the cluster,
but will leave the test namespace intact, because the namespace resource
is not part of the module.
For debugging purposes, the blueprint contains a debug_values.cue file
that can be used to test the module with custom values.To build a module instance with the debug values, run the following command:
timoni -n test build nginx . --values debug_values.cue
If you inspect the output, you’ll notice that the Deployment container image
has changed from docker.io/nginxinc/nginx-unprivileged:1-alpine to
docker.io/nginxinc/nginx-unprivileged:1-alpine-slim,
as specified in the debug_values.cue file.
Ignore rulesNote that the debug_values.cue file is listed in timoni.ignore,
and will be excluded when publishing the module to a container registry.
The debug values are meant to be used only for local testing while developing
the module.
The vet command is your best friend when developing modules.
It verifies that the module structure is compliant with the Timoni specification,
then it builds the module and validates the generated Kubernetes
resources against their CUE schemas.To vet the module with default values, run the following command:
The vet command will print the list of Kubernetes resources and their validation status,
along with the container images referenced in the module.It is also possible to verify the module using the debug values:
command
output
timoni mod vet --debug --name nginx --namespace test
In CI, timoni fmt --diff prints the pending changes and exits with an error if
any file needs formating.For editors, timoni fmt - reads CUE from standard input and writes the formatted
result to standard output, so it can be wired up as a format-on-save command.
To ensure that the Kubernetes resources defined in a module
are in conformance with their OpenAPI schema, Timoni offers a command for
vendoring CUE definitions generated from the Kubernetes builtin APIs.To update the schemas to the latest Kubernetes stable release, run the following command:
timoni mod vendor k8s
The vendor command will download the Kubernetes schemas from GitHub
container registry,
and will update the CUE definitions from the cue.mod/gen/k8s.io directory.
Timoni comes with a set of CUE definitions (schemas and generators), that are used to reduce the
boilerplate code when developing modules. These definitions are included in the modules generated
with timoni mod init, and are vendored in the cue.mod/pkg/timoni directory.To update the Timoni schemas to the latest version,
run the following command from within the module root:
Schemas versioningThe schemas are published with every Timoni release, each Timoni version has
a corresponding schemas artifact tag. While the Timoni API is in alpha,
the schemas may change between releases in a non-backwards compatible way.
The config.cue file contains a schema definition
called #Config that is used to specify which input fields can be configured by end-users
when applying a module instance.For each input field, the #Config definition can specify the field type, if it is
required or optional, if it has a default value,
and which validation rules should be applied.For example, the #Config contains a replicas field defined like this:
#Config: { replicas: *1 | int & >0}
This means that the replicas field defaults to the value of 1, and when specified,
the user-supplied value must be an integer greater than zero.The replicas value is used in the deployment.cue template to set the
spec.replicas field of the Kubernetes Deployment:
The config.cue file contains a definition called #Instance that is used to specify
the list of Kubernetes objects that will be generated from templates when
building and applying a module instance.For example, the #Instance definition takes as input a #Config object
and returns the list of objects with the #Deployment and #Service types:
The #Instance definition is used in by the Timoni entry point,
defined in timoni.cue file from the root directory,
which injects the instance name, namespace and user-supplied config
values and then applies the generated objects on the cluster.
The timoni: apply: field holds one or more named lists of Kubernetes objects:
timoni: { apply: app: [for obj in instance.objects {obj}] apply: test: [for obj in instance.tests {obj}]}
The set names are chosen by the module author. When installing or upgrading
an instance, Timoni applies the sets in the order they are defined. When
waiting is enabled, Timoni waits for the objects in the current set to become
ready before applying the next set.Every object in an apply set must have the apiVersion, kind and
metadata.name fields set. The object’s name, namespace, labels and
annotations are validated at build time with the Kubernetes API server rules.
When an object fails validation, Timoni reports an error containing the
CUE path of the invalid object.Null values in apply sets are skipped, and Kubernetes List objects are
expanded to their items.
The deployment.cue and service.cue files contain the
CUE definitions
used to generate the Deployment and Service Kubernetes objects.Let’s take a look at the service.cue file:
The package directive specifies the CUE package name,
the package name should match the directory name.The import directive is used to import packages from the cue.mod directory,
in this case the k8s.io/api/core/v1 package is imported as corev1. We need this
package to generate any Kubernetes object that is part of the v1 API group, like
ConfigMap, Secret, ServiceAccount, Service, etc.With #Service: corev1.#Service & {...} we specify that our #Service definition
is a Kubernetes Service object, and that it should inherit all the fields from the
corev1.#Service type. This ensures that the generated object will be validated
against the Kubernetes API schema.Inside the #Service definition, we have a #config field of type #Config.
The #config field is used as an input parameter for the user-supplied values.The rest of the #Service definition is used to set the Kubernetes object fields
to the #config values.Optional config fields, like the service.annotations, should be set only if the user
supplied a value for them. To verify if a field has a value, we can use an if statement
and map the config field inside:
if #config.service.annotations != _|_ { metadata: annotations: #config.service.annotations}
Besides mapping the config fields to the Kubernetes object fields, we can also
set fixed values, like the port protocol and name fields.
Assuming that you want to allow users to expose the NGINX service outside the cluster
as a NodePort or LoadBalancer type. To do this, you can add a field called type
to the service section of the #Config definition, then map the type value to the
Kubernetes Service spec.type field.
With the * operator we specify that the type field has a default value of ClusterIP.With the | operator we enumerate the allowed values for the type field.
DocumentationNote that you should document newly added fields in the module’s README.md file.
The readme contains a table with the module configuration fields, their type,
default value and description.
Finally, we can test the validation rules by setting an
invalid value, e.g. service: type: "foo".Running the build or vet command with the debug values
should print a validation error:
timoni mod vet --debug
Was this page helpful?
{"docsConfig":{"theme":"aspen","$schema":"https://mintlify.com/docs.json","name":"Timoni","description":"Timoni is a package manager for Kubernetes powered by CUE lang.","colors":{"primary":"#7e56c2","light":"#a98be0","dark":"#6500b0"},"logo":{"light":"https://mintcdn.com/timoni/8xOqj2ulwazG1u2D/images/logo_text_black.svg?fit=max\u0026auto=format\u0026n=8xOqj2ulwazG1u2D\u0026q=85\u0026s=85ffbf62ec541a621a19255513199222","dark":"https://mintcdn.com/timoni/8xOqj2ulwazG1u2D/images/logo_text_white.svg?fit=max\u0026auto=format\u0026n=8xOqj2ulwazG1u2D\u0026q=85\u0026s=89788f7e520a7c81896a693804eb502d","href":"/"},"favicon":"https://mintcdn.com/timoni/8xOqj2ulwazG1u2D/images/favicon.png?fit=max\u0026auto=format\u0026n=8xOqj2ulwazG1u2D\u0026q=85\u0026s=214f9ea61f808abf055c6211a83d221c","appearance":{"default":"system"},"background":{"decoration":"gradient"},"navbar":{"links":[{"icon":"download","href":"/install","label":"Install"},{"icon":"github-alt","href":"https://github.com/stefanprodan/timoni","label":"GitHub"}]},"footer":{"socials":{"github":"https://github.com/stefanprodan/timoni","slack":"https://cloud-native.slack.com/team/ULPRMFH38","x":"https://x.com/stefanprodan","linkedin":"https://linkedin.com/in/stefanprodan"}},"seo":{"metatags":{"twitter:site":"@stefanprodan","twitter:creator":"@stefanprodan","twitter:card":"summary_large_image"},"indexing":"navigable"},"styling":{"eyebrows":"breadcrumbs","codeblocks":"system","latex":false},"errors":{"404":{"redirect":false,"title":"Page not found","description":"The page you are looking for does not exist or has moved.\n\n\u003cCardGroup cols={2}>\n \u003cCard title=\"Quickstart\" icon=\"rocket\" href=\"/quickstart\">Deploy your first module in minutes.\u003c/Card>\n \u003cCard title=\"Installation\" icon=\"download\" href=\"/install\">Get the Timoni CLI for your OS.\u003c/Card>\n \u003cCard title=\"CUE Reference\" icon=\"code\" href=\"/cue/module/initialization\">Author Timoni modules with CUE.\u003c/Card>\n \u003cCard title=\"CLI Reference\" icon=\"terminal\" href=\"/cmd/timoni\">Every timoni command and flag.\u003c/Card>\n\u003c/CardGroup>\n\nFollowed a broken link? [Open an issue](https://github.com/stefanprodan/timoni/issues) so we can fix it."}},"contextual":{"options":["copy","mcp","view","cursor","vscode"],"display":"header"},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"timoni","hasAudioNarration":false,"actualSubdomain":"timoni","customDomains":["timoni.sh"],"gitSource":{"type":"github","owner":"stefanprodan","repo":"timoni","deployBranch":"website","contentDirectory":"","isPrivate":true,"mountPath":"","label":""},"chroma":{"latestBuiltDeploymentHistoryId":"6ae489bca3eed560d7e508f5","collectionId":"c8a53a18-8419-4450-b32a-35cdecb6ffb2","liveDeploymentHistoryId":"6ae489bca3eed560d7e508f5","schemaVersion":"v3"},"feedback":{"thumbs":true},"entitlements":{"AI_CHAT":{"status":"ENABLED"},"WEB_MCP":{"status":"ENABLED"},"NARRATION":{"status":"ENABLED"}},"buildId":"6ae489bca3eed560d7e508f5","clientVersion":"0.0.4076","searchFilterCounts":[{"language":"default","tag":"CLI Reference","count":49},{"language":"default","tag":"Documentation","count":16},{"language":"default","tag":"CUE Reference","count":14},{"language":"default","tag":"Module","count":13},{"language":"default","tag":"Instance","count":9},{"language":"default","tag":"Module Development","count":9},{"language":"default","tag":"Artifact","count":7},{"language":"default","tag":"Bundle","count":7},{"language":"default","tag":"App Delivery","count":6},{"language":"default","tag":"Integrations","count":5}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true,"deflection":{"enabled":true,"email":"[email protected]"}},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":true,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"comment-mode","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[{"filePath":"style.css","content":"body:has(#timoni-home) #navbar div:has(>.nav-tabs){display:none}#body-content,#navbar>div.mx-auto{max-width:100rem!important}@media (min-width: 1024px){#content-container{max-width:none!important;padding-left:3rem!important}}#header>.text-lg.prose{display:none}body:has(#timoni-home) #body-content{max-width:none!important}.tm-gradient{background:linear-gradient(135deg, #7e56c2 0%, #6500b0 60%, #2b1a4a 100%)}.tm-on-gradient{color:rgba(255, 255, 255, 0.8)}.tm-outline-light{color:#fff;border:1px solid rgba(255, 255, 255, 0.5)}.tm-outline-light:hover{border-color:#fff;background:rgba(255, 255, 255, 0.1)}.tm-band{background:#faf8fd;border-top:1px solid #ebe6f4;border-bottom:1px solid #ebe6f4}html.dark .tm-band{background:rgba(255, 255, 255, 0.025);border-color:rgba(255, 255, 255, 0.07)}.tm-check{display:inline-flex;flex:none;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;margin-top:0.1rem;border-radius:9999px;background:rgba(126, 86, 194, 0.12);color:#7e56c2}.tm-check svg{width:0.65rem!important;height:0.65rem!important}html.dark .tm-check{background:rgba(169, 139, 224, 0.18);color:#a98be0}.tm-diagram-frame{padding:1.25rem;border:1px solid #ebe6f4;border-radius:1rem;background:#fff}html.dark .tm-diagram-frame{border-color:rgba(255, 255, 255, 0.08);background:rgba(255, 255, 255, 0.02)}.tm-footer{border-top:1px solid #ebe6f4}html.dark .tm-footer{border-color:rgba(255, 255, 255, 0.07)}.tm-footer ul a{color:#4b5563}html.dark .tm-footer ul a{color:#9ca3af}.tm-footer ul a:hover{color:#7e56c2}html.dark .tm-footer ul a:hover{color:#a98be0}.tm-footer-bottom{border-top:1px solid #ebe6f4}html.dark .tm-footer-bottom{border-color:rgba(255, 255, 255, 0.07)}.tm-footer-socials{display:inline-flex;gap:1rem}.tm-footer-socials a{color:#6b7280}.tm-footer-socials a:hover{color:#7e56c2}.tm-footer-socials svg{width:1.1rem!important;height:1.1rem!important}#navbar .navbar-link>a{width:30px;height:30px;padding:0;justify-content:center;border-radius:9999px;background:rgba(31, 41, 55, 0.04)}html.dark #navbar .navbar-link>a{background:rgba(255, 255, 255, 0.1)}#navbar .navbar-link>a>span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap}#navbar .navbar-link>a>svg{width:1rem;height:1rem;background-color:#4b5563}#navbar .navbar-link>a:hover>svg{background-color:#1f2937}html.dark #navbar .navbar-link>a>svg{background-color:#d1d5db}html.dark #navbar .navbar-link>a:hover>svg{background-color:#f3f4f6}.not-found-container{max-width:44rem!important;padding-top:8rem!important}.not-found-description .card-group{width:100%;text-align:left}.not-found-description .card-group .card{text-align:left}#navbar img.nav-logo{height:30px}[data-component-part=\"card-icon\"] img[src*=\"/images/icons/\"]{object-fit:none;object-position:-9999px -9999px;background-color:rgb(var(--primary));mask-repeat:no-repeat;mask-position:center;mask-size:contain}html.dark [data-component-part=\"card-icon\"] img[src*=\"/images/icons/\"]{background-color:rgb(var(--primary-light))}[data-component-part=\"card-icon\"] img[src*=\"/images/icons/kubernetes.svg\"]{mask-image:url(\"/images/icons/kubernetes.svg\")}[data-component-part=\"card-icon\"] img[src*=\"/images/icons/helm.svg\"]{mask-image:url(\"/images/icons/helm.svg\")}[data-component-part=\"card-icon\"] img[src*=\"/images/icons/cue.svg\"]{mask-image:url(\"/images/icons/cue.svg\")}[data-component-part=\"card-icon\"] img[src*=\"/images/icons/flux.svg\"]{mask-image:url(\"/images/icons/flux.svg\")}img.tm-hero-logo{object-fit:none;object-position:-9999px -9999px;background-color:#111827;mask-image:url(\"/images/logo_icons.svg\");mask-repeat:no-repeat;mask-position:center;mask-size:contain}html.dark img.tm-hero-logo{background-color:#fff}"}],"page":{"pagePath":"cue/module/initialization","slug":"/cue/module/initialization","pageMetadata":{"title":"Get Started with Timoni Modules","sidebarTitle":"Get started with modules","description":"Create a new module and learn its structure and development workflow.","href":"/cue/module/initialization"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Create a new module and learn its structure and development workflow.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,p:`p`,pre:`pre`,span:`span`,strong:`strong`,..._provideComponents(),...props.components},{CodeBlock,Heading,Tab,Tabs,Tip}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Tab)_missingMdxReference(`Tab`,true);if(!Tabs)_missingMdxReference(`Tabs`,true);if(!Tip)_missingMdxReference(`Tip`,true);return _jsxs(_Fragment,{children:[_jsx(_components.p,{children:`This guide will walk you through the process of creating a new Timoni module.\nWe’ll explore the structure of the created module, and the various development\ncommands that Timoni provides to aid module development.`}),`\n`,_jsx(_components.p,{children:`Furthermore, this guide provides an overview of the templating system,\nincluding the module configuration values, the Kubernetes templates,\nand how to generate Kubernetes objects from these templates.`}),`\n`,_jsx(Heading,{level:`2`,id:`initialize-a-module`,children:`Initialize a module`}),`\n`,_jsx(_components.p,{children:`To create a module in the current directory, run the following command:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`2`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`2`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`timoni`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` mod`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` init`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` myapp`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`--blueprint `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`oci://ghcr.io/stefanprodan/timoni/blueprints/starter`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`The starter blueprint will create a simple module that deploys a NGINX web server.`}),`\n`,_jsx(Heading,{level:`2`,id:`module-structure`,children:`Module structure`}),`\n`,_jsxs(_components.p,{children:[`The init command creates a directory named `,_jsx(_components.code,{children:`myapp`}),` with the following structure:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`15`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`15`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`myapp`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`├──`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` cue.mod`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`│\\xA0\\xA0`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` ├──`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` gen`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # Kubernetes APIs and CRDs schemas`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`│\\xA0\\xA0`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` ├──`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` pkg`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # Timoni APIs schemas`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`│\\xA0\\xA0`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` └──`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` module.cue`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # Module metadata`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`├──`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` templates`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`│\\xA0\\xA0`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` ├──`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` config.cue`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # Config schema and default values`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`│\\xA0\\xA0`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` ├──`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` deployment.cue`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # Kubernetes Deployment template`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`│\\xA0\\xA0`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` └──`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` service.cue`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # Kubernetes Service template`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`├──`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` images.cue`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # Container images defaults`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`├──`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` timoni.cue`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # Timoni entry point`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`├──`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` timoni.ignore`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # Timoni ignore rules`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`├──`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` values.cue`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # Timoni values placeholder `})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`├──`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` LICENSE`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # Module license`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`└──`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` README.md`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # Module documentation`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Navigate to the root directory of the new module with `,_jsx(_components.code,{children:`cd myapp`}),`,\nthis is where we’ll be working from now on.`]}),`\n`,_jsx(Heading,{level:`2`,id:`development-commands`,children:`Development commands`}),`\n`,_jsx(_components.p,{children:`Timoni comes with a set of commands that help with module development.`}),`\n`,_jsxs(_components.p,{children:[`At most times, after making changes, you’ll be using the\n`,_jsx(_components.a,{href:`#vetting-the-module`,children:_jsx(_components.code,{children:`timoni mod vet`})}),` command to verify that\nthe module config and the Kubernetes templates are valid.`]}),`\n`,_jsx(Heading,{level:`3`,id:`build-and-apply-the-module`,children:`Build and apply the module`}),`\n`,_jsx(_components.p,{children:`To build a module instance, run the following command:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`timoni`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -n`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` test`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` build`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` nginx`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` .`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`The build command generates a Kubernetes Deployment and Service,\nand prints the Kubernetes resources to stdout in YAML format.`}),`\n`,_jsxs(_components.p,{children:[`If you inspect the output, you’ll notice that the Kubernetes `,_jsx(_components.code,{children:`metadata`}),`\nmatches the instance name and namespace specified in the build command:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`9`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`9`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`apiVersion`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`apps/v1`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`kind`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Deployment`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`metadata`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` labels`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` app.kubernetes.io/managed-by`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`timoni`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` app.kubernetes.io/name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`nginx`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` app.kubernetes.io/version`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`0.0.0-devel`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`nginx`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` namespace`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`test`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`By convention, Timoni uses the `,_jsx(_components.code,{children:`app.kubernetes.io/name`}),` label to set the\nDeployment selector and the Service selector.`]}),`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`app.kubernetes.io/version`}),` label is used to track the module version\nfrom the container registry, and it’s set to `,_jsx(_components.code,{children:`0.0.0-devel`}),` by default, when\nbuilding a module locally.`]}),`\n`,_jsx(_components.p,{children:`To create the module instance on a Kubernetes cluster:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`timoni`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -n`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` test`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` apply`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` nginx`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` .`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`The apply command will create the Kubernetes resources and will wait for the\nDeployment and Service to become ready. If the `,_jsx(_components.code,{children:`test`}),` namespace doesn’t exist,\nTimoni will create it.`]}),`\n`,_jsxs(Tip,{children:[_jsx(_components.p,{children:_jsx(_components.strong,{children:`Diff changes`})}),_jsxs(_components.p,{children:[`When making changes to the module, you can use the `,_jsx(_components.code,{children:`timoni apply --diff`}),`\nflag to see the differences between the in-cluster resources\nand the newly generated ones.\nThe values of the Kubernetes Secrets data entries are masked in the diff. To mask them in the\n`,_jsx(_components.code,{children:`timoni build`}),` output as well, use the `,_jsx(_components.code,{children:`--mask-secrets`}),` flag.`]})]}),`\n`,_jsx(_components.p,{children:`To delete the module instance:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`timoni`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -n`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` test`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` delete`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` nginx`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` .`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`The delete command will remove the Kubernetes Deployment and Service from the cluster,\nbut will leave the `,_jsx(_components.code,{children:`test`}),` namespace intact, because the namespace resource\nis not part of the module.`]}),`\n`,_jsx(Heading,{level:`3`,id:`build-with-custom-values`,children:`Build with custom values`}),`\n`,_jsxs(_components.p,{children:[`For debugging purposes, the blueprint contains a `,_jsx(_components.code,{children:`debug_values.cue`}),` file\nthat can be used to test the module with custom values.`]}),`\n`,_jsx(_components.p,{children:`To build a module instance with the debug values, run the following command:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`timoni`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -n`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` test`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` build`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` nginx`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` .`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --values`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` debug_values.cue`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`If you inspect the output, you’ll notice that the Deployment container image\nhas changed from `,_jsx(_components.code,{children:`docker.io/nginxinc/nginx-unprivileged:1-alpine`}),` to\n`,_jsx(_components.code,{children:`docker.io/nginxinc/nginx-unprivileged:1-alpine-slim`}),`,\nas specified in the `,_jsx(_components.code,{children:`debug_values.cue`}),` file.`]}),`\n`,_jsxs(Tip,{children:[_jsx(_components.p,{children:_jsx(_components.strong,{children:`Ignore rules`})}),_jsxs(_components.p,{children:[`Note that the `,_jsx(_components.code,{children:`debug_values.cue`}),` file is listed in `,_jsx(_components.code,{children:`timoni.ignore`}),`,\nand will be excluded when publishing the module to a container registry.\nThe debug values are meant to be used only for local testing while developing\nthe module.`]})]}),`\n`,_jsx(Heading,{level:`3`,id:`vetting-the-module`,children:`Vetting the module`}),`\n`,_jsx(_components.p,{children:`The vet command is your best friend when developing modules.\nIt verifies that the module structure is compliant with the Timoni specification,\nthen it builds the module and validates the generated Kubernetes\nresources against their CUE schemas.`}),`\n`,_jsx(_components.p,{children:`To vet the module with default values, run the following command:`}),`\n`,_jsxs(Tabs,{sync:false,children:[_jsx(Tab,{title:`command`,id:`command`,children:_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`timoni`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` mod`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` vet`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --name`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` nginx`})]}),`\n`]})})})}),_jsx(Tab,{title:`output`,id:`output`,children:_jsx(CodeBlock,{filename:``,numberOfLines:`6`,language:`text`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`text`,children:_jsxs(_components.code,{language:`text`,numberOfLines:`6`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`INF vetting with default values`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`INF Deployment/default/nginx valid resource`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`INF Service/default/nginx valid resource`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`INF docker.io/nginxinc/nginx-unprivileged:1-alpine valid image (digest missing)`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`INF timoni.sh/myapp valid module`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{})})]})})})})]}),`\n`,_jsx(_components.p,{children:`The vet command will print the list of Kubernetes resources and their validation status,\nalong with the container images referenced in the module.`}),`\n`,_jsx(_components.p,{children:`It is also possible to verify the module using the debug values:`}),`\n`,_jsxs(Tabs,{sync:false,children:[_jsx(Tab,{title:`command`,id:`command-2`,children:_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`timoni`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` mod`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` vet`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --debug`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --name`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` nginx`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --namespace`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` test`})]}),`\n`]})})})}),_jsx(Tab,{title:`output`,id:`output-2`,children:_jsx(CodeBlock,{filename:``,numberOfLines:`6`,language:`text`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`text`,children:_jsxs(_components.code,{language:`text`,numberOfLines:`6`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`INF vetting with debug values`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`INF Deployment/test/nginx valid resource`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`INF Service/test/nginx valid resource`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`INF docker.io/nginxinc/nginx-unprivileged:1-alpine-slim valid image (digest missing)`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`INF timoni.sh/myapp valid module`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{})})]})})})})]}),`\n`,_jsx(_components.p,{children:`If the vet command encounters an invalid definition, it will print the error message,\nthe file and line number where the error occurred.`}),`\n`,_jsx(Heading,{level:`3`,id:`format-the-module-files`,children:`Format the module files`}),`\n`,_jsx(_components.p,{children:`To format all files in a module:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`timoni`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` fmt`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`In CI, `,_jsx(_components.code,{children:`timoni fmt --diff`}),` prints the pending changes and exits with an error if\nany file needs formating.`]}),`\n`,_jsxs(_components.p,{children:[`For editors, `,_jsx(_components.code,{children:`timoni fmt -`}),` reads CUE from standard input and writes the formatted\nresult to standard output, so it can be wired up as a format-on-save command.`]}),`\n`,_jsx(Heading,{level:`3`,id:`update-the-kubernetes-schemas`,children:`Update the Kubernetes schemas`}),`\n`,_jsx(_components.p,{children:`To ensure that the Kubernetes resources defined in a module\nare in conformance with their OpenAPI schema, Timoni offers a command for\nvendoring CUE definitions generated from the Kubernetes builtin APIs.`}),`\n`,_jsx(_components.p,{children:`To update the schemas to the latest Kubernetes stable release, run the following command:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`timoni`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` mod`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` vendor`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` k8s`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`The vendor command will download the Kubernetes schemas from GitHub\n`,_jsx(_components.a,{href:`https://github.com/stefanprodan/kubernetes-cue-schema/pkgs/container/timoni%2Fkubernetes-schema`,children:`container registry`}),`,\nand will update the CUE definitions from the `,_jsx(_components.code,{children:`cue.mod/gen/k8s.io`}),` directory.`]}),`\n`,_jsx(Heading,{level:`3`,id:`update-the-timoni-schemas`,children:`Update the Timoni schemas`}),`\n`,_jsxs(_components.p,{children:[`Timoni comes with a set of CUE definitions (schemas and generators), that are used to reduce the\nboilerplate code when developing modules. These definitions are included in the modules generated\nwith `,_jsx(_components.code,{children:`timoni mod init`}),`, and are vendored in the `,_jsx(_components.code,{children:`cue.mod/pkg/timoni`}),` directory.`]}),`\n`,_jsx(_components.p,{children:`To update the Timoni schemas to the latest version,\nrun the following command from within the module root:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`timoni`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` artifact`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` pull`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` oci://ghcr.io/stefanprodan/timoni/schemas`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -o`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` cue.mod/pkg`})]}),`\n`]})})}),`\n`,_jsxs(Tip,{children:[_jsx(_components.p,{children:_jsx(_components.strong,{children:`Schemas versioning`})}),_jsx(_components.p,{children:`The schemas are published with every Timoni release, each Timoni version has\na corresponding schemas artifact tag. While the Timoni API is in alpha,\nthe schemas may change between releases in a non-backwards compatible way.`})]}),`\n`,_jsx(Heading,{level:`2`,id:`templates-overview`,children:`Templates overview`}),`\n`,_jsx(_components.p,{children:`The templates directory contains the module configuration schema\nand the Kubernetes resources templates.`}),`\n`,_jsx(Heading,{level:`3`,id:`config-definition`,children:`Config definition`}),`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`config.cue`}),` file contains a `,_jsx(_components.a,{href:`/cue/walkthrough#schema-definitions`,children:`schema definition`}),`\ncalled `,_jsx(_components.code,{children:`#Config`}),` that is used to specify which input fields can be configured by end-users\nwhen applying a module instance.`]}),`\n`,_jsxs(_components.p,{children:[`For each input field, the `,_jsx(_components.code,{children:`#Config`}),` definition can specify the field type, if it is\nrequired or optional, if it has a `,_jsx(_components.a,{href:`/cue/walkthrough#default-values`,children:`default value`}),`,\nand which `,_jsx(_components.a,{href:`/cue/walkthrough#field-constraints`,children:`validation rules`}),` should be applied.`]}),`\n`,_jsxs(_components.p,{children:[`For example, the `,_jsx(_components.code,{children:`#Config`}),` contains a `,_jsx(_components.code,{children:`replicas`}),` field defined like this:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`4`,language:`cue`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`cue`,children:_jsxs(_components.code,{language:`cue`,numberOfLines:`4`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#Config`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\treplicas`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`*`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`1`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` |`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4EC9B0`},children:` int`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u0026`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` >`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`0`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`This means that the `,_jsx(_components.code,{children:`replicas`}),` field defaults to the value of `,_jsx(_components.code,{children:`1`}),`, and when specified,\nthe user-supplied value must be an integer greater than zero.`]}),`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`replicas`}),` value is used in the `,_jsx(_components.code,{children:`deployment.cue`}),` template to set the\n`,_jsx(_components.code,{children:`spec.replicas`}),` field of the Kubernetes Deployment:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`7`,language:`cue`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`cue`,children:_jsxs(_components.code,{language:`cue`,numberOfLines:`7`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#Deployment`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`appsv1`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#Deployment`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u0026`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t#config`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#Config`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\tspec`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t\treplicas`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#config`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`replicas`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\t}`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`]})})}),`\n`,_jsx(Heading,{level:`3`,id:`instance-definition`,children:`Instance definition`}),`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`config.cue`}),` file contains a definition called `,_jsx(_components.code,{children:`#Instance`}),` that is used to specify\nthe list of Kubernetes objects that will be generated from templates when\nbuilding and applying a module instance.`]}),`\n`,_jsxs(_components.p,{children:[`For example, the `,_jsx(_components.code,{children:`#Instance`}),` definition takes as input a `,_jsx(_components.code,{children:`#Config`}),` object\nand returns the list of objects with the `,_jsx(_components.code,{children:`#Deployment`}),` and `,_jsx(_components.code,{children:`#Service`}),` types:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`9`,language:`cue`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`cue`,children:_jsxs(_components.code,{language:`cue`,numberOfLines:`9`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#Instance`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\tconfig`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#Config`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\tobjects`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t\tdeploy`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#Deployment`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u0026`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#config`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`config`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t\tservice`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#Service`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u0026`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#config`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`config`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\t}`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`#Instance`}),` definition is used in by the Timoni entry point,\ndefined in `,_jsx(_components.code,{children:`timoni.cue`}),` file from the root directory,\nwhich injects the instance name, namespace and user-supplied config\nvalues and then applies the generated objects on the cluster.`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`12`,language:`cue`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`cue`,children:_jsxs(_components.code,{language:`cue`,numberOfLines:`12`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`timoni`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\tinstance`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`templates`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#Instance`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u0026`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t\tconfig`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`values`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t\tconfig`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`metadata`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t\t\tname`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4EC9B0`},children:`string`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` @`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#9CDCFE`},children:`tag`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`)`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t\t\tnamespace`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4EC9B0`},children:`string`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` @`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#9CDCFE`},children:`tag`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`namespace`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`)`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\t\t}`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\t}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\tapply`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`app`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`for`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` obj`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:` in`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` instance`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`objects`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`obj`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}]`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`]})})}),`\n`,_jsx(Heading,{level:`3`,id:`apply-sets`,children:`Apply sets`}),`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`timoni: apply:`}),` field holds one or more named lists of Kubernetes objects:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`4`,language:`cue`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`cue`,children:_jsxs(_components.code,{language:`cue`,numberOfLines:`4`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`timoni`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\tapply`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`app`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`for`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` obj`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:` in`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` instance`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`objects`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`obj`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}]`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\tapply`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`test`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`for`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` obj`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:` in`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` instance`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`tests`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`obj`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}]`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`The set names are chosen by the module author. When installing or upgrading\nan instance, Timoni applies the sets in the order they are defined. When\nwaiting is enabled, Timoni waits for the objects in the current set to become\nready before applying the next set.`}),`\n`,_jsxs(_components.p,{children:[`Every object in an apply set must have the `,_jsx(_components.code,{children:`apiVersion`}),`, `,_jsx(_components.code,{children:`kind`}),` and\n`,_jsx(_components.code,{children:`metadata.name`}),` fields set. The object’s name, namespace, labels and\nannotations are validated at build time with the Kubernetes API server rules.\nWhen an object fails validation, Timoni reports an error containing the\nCUE path of the invalid object.`]}),`\n`,_jsxs(_components.p,{children:[`Null values in apply sets are skipped, and Kubernetes `,_jsx(_components.code,{children:`List`}),` objects are\nexpanded to their items.`]}),`\n`,_jsx(Heading,{level:`3`,id:`kubernetes-definitions`,children:`Kubernetes definitions`}),`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`deployment.cue`}),` and `,_jsx(_components.code,{children:`service.cue`}),` files contain the\n`,_jsx(_components.a,{href:`/cue/walkthrough#schema-definitions`,children:`CUE definitions`}),`\nused to generate the Deployment and Service Kubernetes objects.`]}),`\n`,_jsxs(_components.p,{children:[`Let’s take a look at the `,_jsx(_components.code,{children:`service.cue`}),` file:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`26`,language:`cue`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`cue`,children:_jsxs(_components.code,{language:`cue`,numberOfLines:`26`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`package`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#4EC9B0`},children:` templates`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`import`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` (`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#4EC9B0`},children:`\tcorev1`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` \"`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`k8s.io/api/core/v1`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`)`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#Service`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`corev1`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#Service`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u0026`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t#config`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#Config`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\tapiVersion`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`v1`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\tkind`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Service`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\tmetadata`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#config`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`metadata`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`\tif`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` #config`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`service`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`annotations`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` !=`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` _|_`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t\tmetadata`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`annotations`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#config`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`service`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`annotations`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\t}`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\tspec`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`corev1`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#ServiceSpec`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u0026`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t\tselector`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#config`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`selector`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`labels`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t\tports`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\t\t\t{`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t\t\t\tport`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#config`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`service`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`port`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t\t\t\tprotocol`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`TCP`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t\t\t\tname`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`http`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t\t\t\ttargetPort`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`name`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\t\t\t},`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\t\t]`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\t}`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`package`}),` directive specifies the CUE package name,\nthe package name should match the directory name.`]}),`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`import`}),` directive is used to import packages from the `,_jsx(_components.code,{children:`cue.mod`}),` directory,\nin this case the `,_jsx(_components.code,{children:`k8s.io/api/core/v1`}),` package is imported as `,_jsx(_components.code,{children:`corev1`}),`. We need this\npackage to generate any Kubernetes object that is part of the `,_jsx(_components.code,{children:`v1`}),` API group, like\nConfigMap, Secret, ServiceAccount, Service, etc.`]}),`\n`,_jsxs(_components.p,{children:[`With `,_jsx(_components.code,{children:`#Service: corev1.#Service \u0026 {...}`}),` we specify that our `,_jsx(_components.code,{children:`#Service`}),` definition\nis a Kubernetes Service object, and that it should inherit all the fields from the\n`,_jsx(_components.code,{children:`corev1.#Service`}),` type. This ensures that the generated object will be validated\nagainst the Kubernetes API schema.`]}),`\n`,_jsxs(_components.p,{children:[`Inside the `,_jsx(_components.code,{children:`#Service`}),` definition, we have a `,_jsx(_components.code,{children:`#config`}),` field of type `,_jsx(_components.code,{children:`#Config`}),`.\nThe `,_jsx(_components.code,{children:`#config`}),` field is used as an input parameter for the user-supplied values.`]}),`\n`,_jsxs(_components.p,{children:[`The rest of the `,_jsx(_components.code,{children:`#Service`}),` definition is used to set the Kubernetes object fields\nto the `,_jsx(_components.code,{children:`#config`}),` values.`]}),`\n`,_jsxs(_components.p,{children:[`Optional config fields, like the `,_jsx(_components.code,{children:`service.annotations`}),`, should be set only if the user\nsupplied a value for them. To verify if a field has a value, we can use an if statement\nand map the config field inside:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`3`,language:`cue`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`cue`,children:_jsxs(_components.code,{language:`cue`,numberOfLines:`3`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`if`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` #config`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`service`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`annotations`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` !=`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` _|_`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` metadata`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`annotations`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#config`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`service`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`annotations`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Besides mapping the config fields to the Kubernetes object fields, we can also\nset fixed values, like the port `,_jsx(_components.code,{children:`protocol`}),` and `,_jsx(_components.code,{children:`name`}),` fields.`]}),`\n`,_jsx(Heading,{level:`3`,id:`container-images`,children:`Container images`}),`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`images.cue`}),` file from the module root holds the default\nrepository, tag and digest of the container images used by the module:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`11`,language:`cue`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`cue`,children:_jsxs(_components.code,{language:`cue`,numberOfLines:`11`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`package`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#4EC9B0`},children:` main`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`// The container images tracked from the upstream releases.`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`values`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\timage`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t\trepository`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`*`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`docker.io/nginxinc/nginx-unprivileged`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` |`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4EC9B0`},children:` string`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t\ttag`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`*`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`1-alpine`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` |`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4EC9B0`},children:` string`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t\tdigest`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`*`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"\"`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` |`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4EC9B0`},children:` string`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\t}`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`image`}),` field is declared as required in the `,_jsx(_components.code,{children:`#Config`}),` definition,\nand its default values come from `,_jsx(_components.code,{children:`images.cue`}),`:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`4`,language:`cue`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`cue`,children:_jsxs(_components.code,{language:`cue`,numberOfLines:`4`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#Config`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\timage`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`!`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`timoniv1`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#Image`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Users can override the image repository, tag or digest with their own values.\nTo update the images to a new version, edit the defaults in `,_jsx(_components.code,{children:`images.cue`}),`.`]}),`\n`,_jsx(Heading,{level:`2`,id:`extend-the-module-config`,children:`Extend the module config`}),`\n`,_jsxs(_components.p,{children:[`Assuming that you want to allow users to expose the NGINX service outside the cluster\nas a NodePort or LoadBalancer type. To do this, you can add a field called `,_jsx(_components.code,{children:`type`}),`\nto the `,_jsx(_components.code,{children:`service`}),` section of the `,_jsx(_components.code,{children:`#Config`}),` definition, then map the `,_jsx(_components.code,{children:`type`}),` value to the\nKubernetes Service `,_jsx(_components.code,{children:`spec.type`}),` field.`]}),`\n`,_jsx(Heading,{level:`3`,id:`add-the-config-field`,children:`Add the config field`}),`\n`,_jsxs(_components.p,{children:[`Open the `,_jsx(_components.code,{children:`config.cue`}),` file and add the `,_jsx(_components.code,{children:`type`}),` field to the `,_jsx(_components.code,{children:`service`}),` section:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`6`,language:`cue`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`cue`,children:_jsxs(_components.code,{language:`cue`,numberOfLines:`6`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#Config`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\tservice`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t\ttype`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`*`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`ClusterIP`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` |`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` \"`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`NodePort`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` |`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` \"`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`LoadBalancer`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\t}`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`With the `,_jsx(_components.code,{children:`*`}),` operator we specify that the `,_jsx(_components.code,{children:`type`}),` field has a default value of `,_jsx(_components.code,{children:`ClusterIP`}),`.`]}),`\n`,_jsxs(_components.p,{children:[`With the `,_jsx(_components.code,{children:`|`}),` operator we enumerate the allowed values for the `,_jsx(_components.code,{children:`type`}),` field.`]}),`\n`,_jsxs(Tip,{children:[_jsx(_components.p,{children:_jsx(_components.strong,{children:`Documentation`})}),_jsxs(_components.p,{children:[`Note that you should document newly added fields in the module’s `,_jsx(_components.code,{children:`README.md`}),` file.\nThe readme contains a table with the module configuration fields, their type,\ndefault value and description.`]})]}),`\n`,_jsx(Heading,{level:`3`,id:`map-the-field-in-the-template`,children:`Map the field in the template`}),`\n`,_jsxs(_components.p,{children:[`Open the `,_jsx(_components.code,{children:`service.cue`}),` file and set the `,_jsx(_components.code,{children:`spec.type`}),` field to the `,_jsx(_components.code,{children:`#config.service.type`}),` value:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`8`,language:`cue`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`cue`,children:_jsxs(_components.code,{language:`cue`,numberOfLines:`8`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#Service`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`corev1`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#Service`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u0026`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t#config`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#Config`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\tspec`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\t\ttype`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`#config`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`service`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`type`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\t}`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`]})})}),`\n`,_jsx(Heading,{level:`3`,id:`test-the-config`,children:`Test the config`}),`\n`,_jsx(_components.p,{children:`To test the new config field, we can build the module with the default values,\nand check the generated Service:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`timoni`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` build`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` nginx`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` .`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` |`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:` grep`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` ClusterIP`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`To test if we can change the Service type,\nwe can use the `,_jsx(_components.code,{children:`debug_values.cue`}),` file:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`3`,language:`cue`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`cue`,children:_jsxs(_components.code,{language:`cue`,numberOfLines:`3`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`values`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`\tservice`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`type`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`NodePort`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`\"`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`And build the module with the debug values:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`timoni`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` build`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` nginx`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` .`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -f`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` debug_values.cue`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` |`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:` grep`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` NodePort`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Finally, we can test the validation rules by setting an\ninvalid value, e.g. `,_jsx(_components.code,{children:`service: type: \"foo\"`}),`.`]}),`\n`,_jsx(_components.p,{children:`Running the build or vet command with the debug values\nshould print a validation error:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`timoni`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` mod`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` vet`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --debug`})]}),`\n`]})})})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"codeStyling":"system","config":{},"pageMetadata":{"title":"Get Started with Timoni Modules","sidebarTitle":"Get started with modules","description":"Create a new module and learn its structure and development workflow.","href":"/cue/module/initialization"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Initialize a module","slug":"initialize-a-module","depth":2,"children":[]},{"title":"Module structure","slug":"module-structure","depth":2,"children":[]},{"title":"Development commands","slug":"development-commands","depth":2,"children":[{"title":"Build and apply the module","slug":"build-and-apply-the-module","depth":3,"children":[]},{"title":"Build with custom values","slug":"build-with-custom-values","depth":3,"children":[]},{"title":"Vetting the module","slug":"vetting-the-module","depth":3,"children":[]},{"title":"Format the module files","slug":"format-the-module-files","depth":3,"children":[]},{"title":"Update the Kubernetes schemas","slug":"update-the-kubernetes-schemas","depth":3,"children":[]},{"title":"Update the Timoni schemas","slug":"update-the-timoni-schemas","depth":3,"children":[]}]},{"title":"Templates overview","slug":"templates-overview","depth":2,"children":[{"title":"Config definition","slug":"config-definition","depth":3,"children":[]},{"title":"Instance definition","slug":"instance-definition","depth":3,"children":[]},{"title":"Apply sets","slug":"apply-sets","depth":3,"children":[]},{"title":"Kubernetes definitions","slug":"kubernetes-definitions","depth":3,"children":[]},{"title":"Container images","slug":"container-images","depth":3,"children":[]}]},{"title":"Extend the module config","slug":"extend-the-module-config","depth":2,"children":[{"title":"Add the config field","slug":"add-the-config-field","depth":3,"children":[]},{"title":"Map the field in the template","slug":"map-the-field-in-the-template","depth":3,"children":[]},{"title":"Test the config","slug":"test-the-config","depth":3,"children":[]}]}],"codeExamples":{}},"jsLinks":[],"subdomain":"timoni","siteName":"Timoni","title":"Get Started with Timoni Modules - Timoni","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-08-22T15:38:16.820Z","originalFileLocation":"cue/module/initialization.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Create a new module and learn its structure and development workflow.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Timoni\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/timoni/wBHd5XBsu-JLPEJB/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/timoni/wBHd5XBsu-JLPEJB/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/timoni/wBHd5XBsu-JLPEJB/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/timoni/wBHd5XBsu-JLPEJB/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/timoni/wBHd5XBsu-JLPEJB/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/timoni/wBHd5XBsu-JLPEJB/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/timoni/wBHd5XBsu-JLPEJB/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/timoni/wBHd5XBsu-JLPEJB/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/timoni/wBHd5XBsu-JLPEJB/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Get Started with Timoni Modules - Timoni\">\u003cmeta data-mint-head property=\"og:description\" content=\"Create a new module and learn its structure and development workflow.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Timoni\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://timoni.sh/cue/module/initialization\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://timoni.mintlify.site/_mintlify/api/og/v2?division=Module+Development\u0026amp;title=Get+Started+with+Timoni+Modules\u0026amp;description=Create+a+new+module+and+learn+its+structure+and+development+workflow.\u0026amp;theme=d31bdd9b74b0932292c26bd2\u0026amp;signature=aafbf624cf7f0942243f3ebefb9c633271a48746164db851616ea76e0c434e3c\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Get Started with Timoni Modules - Timoni\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Create a new module and learn its structure and development workflow.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://timoni.mintlify.site/_mintlify/api/og/v2?division=Module+Development\u0026amp;title=Get+Started+with+Timoni+Modules\u0026amp;description=Create+a+new+module+and+learn+its+structure+and+development+workflow.\u0026amp;theme=d31bdd9b74b0932292c26bd2\u0026amp;signature=aafbf624cf7f0942243f3ebefb9c633271a48746164db851616ea76e0c434e3c\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/timoni/wBHd5XBsu-JLPEJB/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Timoni\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#7e56c2\">\u003cmeta data-mint-head name=\"twitter:creator\" content=\"@stefanprodan\">\u003clink data-mint-head rel=\"canonical\" href=\"https://timoni.sh/cue/module/initialization\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/cue/module/initialization.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://timoni.sh/#organization\",\"name\":\"Timoni\",\"url\":\"https://timoni.sh\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/timoni/8xOqj2ulwazG1u2D/images/logo_text_black.svg?fit=max\u0026auto=format\u0026n=8xOqj2ulwazG1u2D\u0026q=85\u0026s=85ffbf62ec541a621a19255513199222\"}},{\"@type\":\"WebSite\",\"@id\":\"https://timoni.sh#website\",\"name\":\"Timoni\",\"url\":\"https://timoni.sh\",\"publisher\":{\"@id\":\"https://timoni.sh/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://timoni.sh/cue/module/initialization#webpage\",\"url\":\"https://timoni.sh/cue/module/initialization\",\"name\":\"Get Started with Timoni Modules\",\"description\":\"Create a new module and learn its structure and development workflow.\",\"dateModified\":\"2026-08-22T15:38:16.820Z\",\"isPartOf\":{\"@id\":\"https://timoni.sh#website\"},\"breadcrumb\":{\"@id\":\"https://timoni.sh/cue/module/initialization#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://timoni.sh/cue/module/initialization#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Timoni\",\"item\":\"https://timoni.sh\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Get Started with Timoni Modules\",\"item\":\"https://timoni.sh/cue/module/initialization\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://timoni.sh/cue/module/initialization#article\",\"headline\":\"Get Started with Timoni Modules\",\"name\":\"Get Started with Timoni Modules\",\"description\":\"Create a new module and learn its structure and development workflow.\",\"url\":\"https://timoni.sh/cue/module/initialization\",\"mainEntityOfPage\":{\"@id\":\"https://timoni.sh/cue/module/initialization#webpage\"},\"dateModified\":\"2026-08-22T15:38:16.820Z\",\"publisher\":{\"@id\":\"https://timoni.sh/#organization\"},\"isPartOf\":{\"@id\":\"https://timoni.sh#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Timoni\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Timoni","nav":{"global":null,"tabs":[{"tab":"Documentation","icon":"book-open","pages":[{"title":"Documentation","href":"/quickstart"}]},{"tab":"CUE Reference","icon":"code","groups":[{"group":"CUE Language","pages":[{"title":"CUE Language","sidebarTitle":"Introduction","href":"/cue/introduction"},{"title":"CUE Features Walkthrough","sidebarTitle":"CUE Walkthrough","description":"Learn the core CUE features used to generate Kubernetes objects.","href":"/cue/walkthrough"}]},{"group":"Module Development","pages":[{"title":"Get Started with Timoni Modules","sidebarTitle":"Get started with modules","href":"/cue/module/initialization"},{"title":"Immutable ConfigMaps and Secrets","description":"Generate immutable ConfigMaps and Secrets that roll out on change.","href":"/cue/module/immutable-config"},{"title":"Embedding files","href":"/cue/module/embedding-files"},{"title":"Kubernetes Custom Resources","sidebarTitle":"Add custom resources","href":"/cue/module/custom-resources"},{"title":"Kubernetes Version Constraints","sidebarTitle":"Cluster version constraints","href":"/cue/module/semver-constraints"},{"title":"Control the Apply Behavior","sidebarTitle":"Control the apply behavior","href":"/cue/module/apply-behavior"},{"title":"Custom Health Checks","sidebarTitle":"Custom health checks","href":"/cue/module/health-checks"},{"title":"Run tests with Kubernetes Jobs","href":"/cue/module/test-jobs"},{"title":"Import Kubernetes Resources from YAML","sidebarTitle":"Import resources from YAML","href":"/cue/module/import-resources"}]},{"group":"Module Distribution","pages":[{"title":"Module Publishing","sidebarTitle":"Publishing module versions","href":"/cue/module/publishing"},{"title":"Module Signing and Verification","sidebarTitle":"Signing and Verification","href":"/cue/module/signing"},{"title":"Module Distribution with GitHub Actions","sidebarTitle":"GitHub Actions","href":"/cue/module/github-actions"}]}]},{"tab":"CLI Reference","icon":"terminal","pages":[{"title":"CLI Reference","href":"/cmd/timoni"}]}]},"basePath":"","title":"Get Started with Timoni Modules - Timoni","buildId":"dpl_8LJbrAiZvr1K98WQNZXCyY5AvT34","deploymentId":"dpl_8LJbrAiZvr1K98WQNZXCyY5AvT34","dynamics":[],"chunks":[]}