Compare commits

..

22 Commits

Author SHA1 Message Date
Gary Larizza
488f7ae985 Start Hello Holos
This is a very, very minimal framework using the Tokyo docs as a guide.
This code is going to have to change when `v1alpha5` is published, so
I'm just dropping it in here as a placeholder.

Like the Tokyo docs, I was intening to setup the code and commands at the
start, and then have a "Breaking it down" section later explaining all
the moving parts.
2024-11-05 16:27:10 -08:00
Gary Larizza
4817491aab Update groupId for uniqueness 2024-11-05 16:26:40 -08:00
Gary Larizza
30ce72a9b7 Add the Local Cluster guide 2024-11-05 14:50:16 -08:00
Gary Larizza
958f65ddcf Setup page first draft 2024-11-05 14:47:12 -08:00
Gary Larizza
a1c9111a05 Overview initial draft 2024-11-05 13:30:35 -08:00
Jeff McCune
ee30c52673 docs: generate version specific api docs (#303)
Without this patch each version of the core and author schemas are
duplicated into each docs version.  This is unnecessary and difficult to
maintain now that we have docusaurus versioned docs enabled.

This patch updates the schema generation script to check if the docs
version has been released, and if so write into a markdown file in the
versioned docs folder.  If not, the version is written into the next
version folder.

This patch also updates some, but not all, document links to the md or
mdx relative file paths.  This is necessary to generate the correct
versioned links.

A nice outcome of this change is that technical docs no longer need to
link to version specific pages.  For example, `[Core Schema]:
./api/core.md` will always refer to the correct auto generated docs
associated with the docs version.
2024-11-05 07:20:53 -08:00
Jeff McCune
117a00334f docs: restructure docs into tutorial and topics (#301)
The docs for v1alpha4 have the right information, but in the wrong
places.  The most important bits are tucked away in the Core API docs.
One of our first users entirely missed the `holos generate platform`
command mentioned in the Helm guide.

We'll fix this by organizing the docs into two distinct categories.
First, a tutorial written as a series progressively building up the
minimum knowledge to use holos effectively and gain the benefits.  Think
of it as a tour of the essential bits.

The second category are focused topics which stand alone.  They're the
things most people using holos will need to know eventually, but aren't
essential for everyone to know.  For example, Clusters and Fleets will
move from the Author API to stand alone examples of how to implement
these features if necessary.

Then there's a Glossary which serves as the place to describe our
concepts and domain specific language.

Finally there's the API documentation which should be cut down to the
specific version.  The next release version will be v1alpha5.

Attribution: We're copying the Tokio docs structure, it's concise and a
similar size and complexity to our own project.

The Go docs are also an inspiration, but the project is much larger so
not directly comparable.  The organization of https://go.dev/doc/ feels
complete at first glance, despite the size and age of the project.  The
site also makes clear who each section is for without needing to come
right out and say it. Getting started, Using and understanding Go,
Writing modules, using databases, etc...
2024-11-04 20:25:04 -08:00
Jeff McCune
1e03debfac tests: add make unity target
For https://cuelabs.dev/unity/
2024-11-04 19:08:44 -08:00
Jeff McCune
72137b2fa9 docs: upgrade docusaurus to 3.6.0
npm i @docusaurus/core@latest @docusaurus/plugin-client-redirects@latest \
  @docusaurus/preset-classic@latest @docusaurus/theme-mermaid@latest \
  @docusaurus/module-type-aliases@latest @docusaurus/tsconfig@latest \
  @docusaurus/types@latest
2024-11-04 06:47:48 -08:00
Jeff McCune
5abf967116 docs: npm run docusaurus docs:version v1alpha4 (#299)
Tag version v1alpha4 so we can start working on v1alpha5 as the next
version in main.
2024-11-04 06:43:15 -08:00
Jeff McCune
5d882f465d website: fix resources.yaml tab in helm guide (#293)
We switched from using a kustomize remote base to a local file so the
tests don't need to make a network round trip to github.  It's also
better practice to use local files for this sort of thing.

In doing so I botched the location of the file, putting it in the
platform registration section.  This patch claifies how `resources.yaml`
is linked to `httpbin.cue` through the `KustomizeConfig: Files:
"resources.yaml": _` field.
2024-11-03 10:57:52 -08:00
Jeff McCune
45bdaac833 main: cue v0.10.1 and add e2e test for helm guide (#293)
Previously there was no test coverage of the
https://holos.run/docs/guides/helm/ guide.  This patch uses Roger's
testscript package, which the CUE folks also use to add comprehensive
test coverage of each step in the guide.  Ideally we would execute these
commands directly from the guide itself, but for now we'll duplicate the
commands into the test script.  This could be enhanced by generating the
test script from the document itself in some way.

When updating the script, use the `holos txtar` command to embed entire
helm charts into the test script.  It's not super fast, but it's better
than network access and it's not terribly slow either.  A few seconds to
unpack.

---

txtar: quote files for testscript unquote

For the helm guide test script we want to include the entire helm chart
which may have files that need to be quoted.  This patch changes the
default behavior of the holos txtar command to quote files if necessary
and list them in an unquote script command in the comment of the
archive.

The purpose is for testscript authors to copy and paste the entire thing
into a test script and include the unquote command at the top.

---

This change also updates CUE to v0.10.1
2024-11-03 10:27:46 -08:00
Jeff McCune
7ae1f990ef website: update quickstart diagram to match helm
Avoid confusion, got a question about this in discord.
2024-11-03 08:53:43 -08:00
Jeff McCune
b526fd1669 testdata: clean up old v1alpha1 tests (#292)
No longer necessary now that we're on v1alpha4.  Test coverage for
v1alpha4 and the user facing guides will be added back soon for use both
in the holos repo and in Unity.
2024-11-01 15:22:13 -07:00
Jeff McCune
5e07655f35 website: fix port in helm guide
Should be 9115 not 6115.
2024-11-01 06:39:48 -07:00
Jeff McCune
6fb6afe8d5 v0.97.3 2024-10-31 21:04:22 -07:00
Jeff McCune
d6f89052d9 website: update helm guide to apply patches (#291)
Updated the helm guide to apply patches while still showing the diff in
the documentation markdown.  The only gotcha is it creates orig files.
2024-10-31 20:54:57 -07:00
Jeff McCune
e4aa7f5994 website: update change-a-service to use hidden fields (#291)
Use _Foo instead of #Foo to hold concrete values.
2024-10-31 20:25:40 -07:00
Jeff McCune
6e4c65cb6c website: update deploy-a-service to use hidden fields (#291)
Use _Foo instead of #Foo to hold concrete values.
2024-10-31 20:13:17 -07:00
Jeff McCune
4f091677e2 website: update quickstart for v1alpha4 hidden fields (#291) 2024-10-31 16:35:41 -07:00
Jeff McCune
0c05df1162 website: update technical overview with consistent fields (#291) 2024-10-31 11:30:20 -07:00
Jeff McCune
64a745fd34 v1alpha4: use hidden fields consistently (#291)
Previously it wasn't clear for users if platform wide structs should be
definitions or hidden fields in CUE.  They should be hidden fields when
they contain data and definitions when they define a schema.

This patch updates the generate platform v1alpha4 subcommand to use the
correct field names consistently for clarity.
2024-10-31 10:45:47 -07:00
205 changed files with 33013 additions and 2805 deletions

View File

@@ -5,6 +5,7 @@
"mdx"
],
"words": [
"acmesolver",
"acraccesstokens",
"admissionregistration",
"alertmanager",
@@ -33,12 +34,14 @@
"blackbox",
"buildplan",
"builtinpluginloadingoptions",
"cachedir",
"cadvisor",
"cainjector",
"CAROOT",
"certificaterequest",
"certificaterequests",
"certificatesigningrequests",
"clientset",
"clsx",
"clusterexternalsecret",
"clusterexternalsecrets",
@@ -49,8 +52,10 @@
"clustersecretstore",
"clustersecretstores",
"clusterwide",
"Cmds",
"CNCF",
"CODEOWNERS",
"configdir",
"configmap",
"configmapargs",
"connectrpc",
@@ -100,6 +105,7 @@
"ghaction",
"githubaccesstokens",
"gitops",
"GOBIN",
"godoc",
"golangci",
"gomarkdoc",
@@ -169,6 +175,7 @@
"Multicluster",
"mutatingwebhookconfiguration",
"mutatingwebhookconfigurations",
"mvdan",
"mxcl",
"myhostname",
"myRegistrKeySecretName",
@@ -186,6 +193,7 @@
"organizationconnect",
"orgid",
"otelconnect",
"outfile",
"overriden",
"Parentspanid",
"patchstrategicmerge",
@@ -207,6 +215,7 @@
"poddisruptionbudget",
"poddisruptionbudgets",
"podinfo",
"podmonitor",
"portmapping",
"postgrescluster",
"privs",
@@ -236,6 +245,7 @@
"requestauthentications",
"resourcequotas",
"retryable",
"rogpeppe",
"rolebinding",
"rootfs",
"ropc",
@@ -272,6 +282,7 @@
"systemconnect",
"tablewriter",
"templatable",
"testscript",
"thanos",
"Tiltfile",
"timestamppb",
@@ -304,6 +315,7 @@
"volumeattachments",
"wasmplugin",
"wasmplugins",
"workdir",
"workloadentries",
"workloadentry",
"workloadgroup",

View File

@@ -13,7 +13,7 @@ permissions:
jobs:
test:
runs-on: gha-rs
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
@@ -35,7 +35,7 @@ jobs:
uses: azure/setup-helm@v4
- name: Set up Kubectl
uses: azure/setup-kubectl@v3
uses: azure/setup-kubectl@v4
- name: Install Tools
run: |

View File

@@ -150,6 +150,10 @@ dev-deploy: install image ## deploy to dev
website: ## Build website
./hack/build-website
.PHONY: unity
unity: ## https://cuelabs.dev/unity/
./scripts/unity
.PHONY: help
help: ## Display this help menu.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)

View File

@@ -1,4 +1,4 @@
---
description: Core v1alpha2 schema for advanced use cases.
sidebar_position: 996
description: Core schema for holos to render a component BuildPlan.
sidebar_position: 100
---

View File

@@ -2,8 +2,10 @@ package main
import (
"os"
"path/filepath"
"testing"
cue "cuelang.org/go/cmd/cue/cmd"
"github.com/holos-run/holos/internal/cli"
"github.com/rogpeppe/go-internal/testscript"
)
@@ -11,11 +13,29 @@ import (
func TestMain(m *testing.M) {
os.Exit(testscript.RunMain(m, map[string]func() int{
"holos": cli.MakeMain(),
"cue": cue.Main,
}))
}
func TestGetSecrets(t *testing.T) {
testscript.Run(t, testscript.Params{
Dir: "testdata",
})
func TestGuides(t *testing.T) {
testscript.Run(t, params(filepath.Join("v1alpha4", "guides")))
}
func TestCLI(t *testing.T) {
testscript.Run(t, params("cli"))
}
func params(dir string) testscript.Params {
return testscript.Params{
Dir: filepath.Join("tests", dir),
RequireExplicitExec: true,
RequireUniqueNames: true,
Setup: func(env *testscript.Env) error {
// Just like cmd/cue/cmd.TestScript, set up separate cache and config dirs per test.
env.Setenv("CUE_CACHE_DIR", filepath.Join(env.WorkDir, "tmp/cachedir"))
configDir := filepath.Join(env.WorkDir, "tmp/configdir")
env.Setenv("CUE_CONFIG_DIR", configDir)
return nil
},
}
}

View File

@@ -1,34 +0,0 @@
# Want support for intermediary constraints
exec holos build ./foo/... --log-level debug
stdout '^bf2bc7f9-9ba0-4f9e-9bd2-9a205627eb0b$'
-- platform.config.json --
{}
-- cue.mod --
package holos
-- foo/constraints.cue --
package holos
metadata: name: "jeff"
-- foo/bar/bar.cue --
package holos
spec: components: KubernetesObjectsList: [
#KubernetesObjects & {
apiObjectMap: foo: bar: "bf2bc7f9-9ba0-4f9e-9bd2-9a205627eb0b"
}
]
-- schema.cue --
package holos
_cluster: string @tag(cluster, string)
_platform_config: string @tag(platform_config, string)
#KubernetesObjects: {
apiVersion: "holos.run/v1alpha1"
kind: "KubernetesObjects"
apiObjectMap: {...}
}
apiVersion: "holos.run/v1alpha1"
kind: "BuildPlan"

View File

@@ -1,20 +0,0 @@
# Want cue errors to show files and lines
! exec holos build .
stderr 'apiObjectMap.foo.bar: cannot convert incomplete value'
stderr '/component.cue:\d+:\d+$'
-- platform.config.json --
{}
-- cue.mod --
package holos
-- component.cue --
package holos
_cluster: string @tag(cluster, string)
_platform_config: string @tag(platform_config, string)
apiVersion: "holos.run/v1alpha1"
kind: "BuildPlan"
spec: components: KubernetesObjectsList: [{apiObjectMap: foo: bar: _baz}]
_baz: string

View File

@@ -1,61 +0,0 @@
# Want kube api objects in the apiObjects output.
exec holos build .
stdout '^kind: SecretStore$'
stdout '# Source: CUE apiObjects.SecretStore.default'
-- platform.config.json --
{}
-- cue.mod --
package holos
-- component.cue --
package holos
apiVersion: "holos.run/v1alpha1"
kind: "BuildPlan"
spec: components: KubernetesObjectsList: [{apiObjectMap: #APIObjects.apiObjectMap}]
_cluster: string @tag(cluster, string)
_platform_config: string @tag(platform_config, string)
#SecretStore: {
kind: string
metadata: name: string
}
#APIObjects: {
apiObjects: {
SecretStore: {
default: #SecretStore & { metadata: name: "default" }
}
}
}
-- schema.cue --
package holos
// #APIObjects is the output type for api objects produced by cue. A map is used to aid debugging and clarity.
import "encoding/yaml"
#APIObjects: {
// apiObjects holds each the api objects produced by cue.
apiObjects: {
[Kind=_]: {
[Name=_]: {
kind: Kind
metadata: name: Name
}
}
}
// apiObjectsContent holds the marshalled representation of apiObjects
apiObjectMap: {
for kind, v in apiObjects {
"\(kind)": {
for name, obj in v {
"\(name)": yaml.Marshal(obj)
}
}
}
}
}

View File

@@ -1,62 +0,0 @@
# Want kube api objects in the apiObjects output.
exec holos build .
stdout '^kind: SecretStore$'
stdout '# Source: CUE apiObjects.SecretStore.default'
stderr 'skipping helm: no chart name specified'
-- platform.config.json --
{}
-- cue.mod --
package holos
-- component.cue --
package holos
apiVersion: "holos.run/v1alpha1"
kind: "BuildPlan"
spec: components: HelmChartList: [{apiObjectMap: #APIObjects.apiObjectMap}]
_cluster: string @tag(cluster, string)
_platform_config: string @tag(platform_config, string)
#SecretStore: {
kind: string
metadata: name: string
}
#APIObjects: {
apiObjects: {
SecretStore: {
default: #SecretStore & { metadata: name: "default" }
}
}
}
-- schema.cue --
package holos
// #APIObjects is the output type for api objects produced by cue. A map is used to aid debugging and clarity.
import "encoding/yaml"
#APIObjects: {
// apiObjects holds each the api objects produced by cue.
apiObjects: {
[Kind=_]: {
[Name=_]: {
kind: Kind
metadata: name: Name
}
}
}
// apiObjectsContent holds the marshalled representation of apiObjects
apiObjectMap: {
for kind, v in apiObjects {
"\(kind)": {
for name, obj in v {
"\(name)": yaml.Marshal(obj)
}
}
}
}
}

View File

@@ -1,25 +0,0 @@
# Want api object kind and name in errors
! exec holos build .
stderr 'apiObjects.secretstore.default.foo: field not allowed'
-- platform.config.json --
{}
-- cue.mod --
package holos
-- component.cue --
package holos
apiVersion: "holos.run/v1alpha1"
kind: "KubernetesObjects"
cluster: string @tag(cluster, string)
_platform_config: string @tag(platform_config, string)
#SecretStore: {
metadata: name: string
}
apiObjects: {
secretstore: {
default: #SecretStore & { foo: "not allowed" }
}
}

View File

@@ -1,289 +0,0 @@
# Want helm errors to show up
! exec holos build .
stderr 'Error: execution error at \(zitadel/templates/secret_zitadel-masterkey.yaml:2:4\): Either set .Values.zitadel.masterkey xor .Values.zitadel.masterkeySecretName'
-- platform.config.json --
{}
-- cue.mod --
package holos
-- zitadel.cue --
package holos
apiVersion: "holos.run/v1alpha1"
kind: "BuildPlan"
spec: components: HelmChartList: [_HelmChart]
_cluster: string @tag(cluster, string)
_platform_config: string @tag(platform_config, string)
_HelmChart: {
apiVersion: "holos.run/v1alpha1"
kind: "HelmChart"
metadata: name: "zitadel"
namespace: "zitadel"
chart: {
name: "zitadel"
version: "7.9.0"
release: name
repository: {
name: "zitadel"
url: "https://charts.zitadel.com"
}
}
}
-- vendor/zitadel/templates/secret_zitadel-masterkey.yaml --
{{- if (or (and .Values.zitadel.masterkey .Values.zitadel.masterkeySecretName) (and (not .Values.zitadel.masterkey) (not .Values.zitadel.masterkeySecretName)) ) }}
{{- fail "Either set .Values.zitadel.masterkey xor .Values.zitadel.masterkeySecretName" }}
{{- end }}
{{- if .Values.zitadel.masterkey -}}
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: zitadel-masterkey
{{- with .Values.zitadel.masterkeyAnnotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
labels:
{{- include "zitadel.labels" . | nindent 4 }}
stringData:
masterkey: {{ .Values.zitadel.masterkey }}
{{- end -}}
-- vendor/zitadel/Chart.yaml --
apiVersion: v2
appVersion: v2.46.0
description: A Helm chart for ZITADEL
icon: https://zitadel.com/zitadel-logo-dark.svg
kubeVersion: '>= 1.21.0-0'
maintainers:
- email: support@zitadel.com
name: zitadel
url: https://zitadel.com
name: zitadel
type: application
version: 7.9.0
-- vendor/zitadel/values.yaml --
# Default values for zitadel.
zitadel:
# The ZITADEL config under configmapConfig is written to a Kubernetes ConfigMap
# See all defaults here:
# https://github.com/zitadel/zitadel/blob/main/cmd/defaults.yaml
configmapConfig:
ExternalSecure: true
Machine:
Identification:
Hostname:
Enabled: true
Webhook:
Enabled: false
# The ZITADEL config under secretConfig is written to a Kubernetes Secret
# See all defaults here:
# https://github.com/zitadel/zitadel/blob/main/cmd/defaults.yaml
secretConfig:
# Annotations set on secretConfig secret
secretConfigAnnotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-delete-policy: before-hook-creation
helm.sh/hook-weight: "0"
# Reference the name of a secret that contains ZITADEL configuration.
configSecretName:
# The key under which the ZITADEL configuration is located in the secret.
configSecretKey: config-yaml
# ZITADEL uses the masterkey for symmetric encryption.
# You can generate it for example with tr -dc A-Za-z0-9 </dev/urandom | head -c 32
masterkey: ""
# Reference the name of the secret that contains the masterkey. The key should be named "masterkey".
# Note: Either zitadel.masterkey or zitadel.masterkeySecretName must be set
masterkeySecretName: ""
# Annotations set on masterkey secret
masterkeyAnnotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-delete-policy: before-hook-creation
helm.sh/hook-weight: "0"
# The CA Certificate needed for establishing secure database connections
dbSslCaCrt: ""
# The Secret containing the CA certificate at key ca.crt needed for establishing secure database connections
dbSslCaCrtSecret: ""
# The db admins secret containing the client certificate and key at tls.crt and tls.key needed for establishing secure database connections
dbSslAdminCrtSecret: ""
# The db users secret containing the client certificate and key at tls.crt and tls.key needed for establishing secure database connections
dbSslUserCrtSecret: ""
# Generate a self-signed certificate using an init container
# This will also mount the generated files to /etc/tls/ so that you can reference them in the pod.
# E.G. KeyPath: /etc/tls/tls.key CertPath: /etc/tls/tls.crt
# By default, the SAN DNS names include, localhost, the POD IP address and the POD name. You may include one more by using additionalDnsName like "my.zitadel.fqdn".
selfSignedCert:
enabled: false
additionalDnsName:
replicaCount: 3
image:
repository: ghcr.io/zitadel/zitadel
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""
chownImage:
repository: alpine
pullPolicy: IfNotPresent
tag: "3.19"
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
# Annotations to add to the deployment
annotations: {}
# Annotations to add to the configMap
configMap:
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-delete-policy: before-hook-creation
helm.sh/hook-weight: "0"
serviceAccount:
# Specifies whether a service account should be created
create: true
# Annotations to add to the service account
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-delete-policy: before-hook-creation
helm.sh/hook-weight: "0"
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
podAnnotations: {}
podAdditionalLabels: {}
podSecurityContext:
runAsNonRoot: true
runAsUser: 1000
securityContext: {}
# Additional environment variables
env:
[]
# - name: ZITADEL_DATABASE_POSTGRES_HOST
# valueFrom:
# secretKeyRef:
# name: postgres-pguser-postgres
# key: host
service:
type: ClusterIP
# If service type is "ClusterIP", this can optionally be set to a fixed IP address.
clusterIP: ""
port: 8080
protocol: http2
annotations: {}
scheme: HTTP
ingress:
enabled: false
className: ""
annotations: {}
hosts:
- host: localhost
paths:
- path: /
pathType: Prefix
tls: []
resources: {}
nodeSelector: {}
tolerations: []
affinity: {}
topologySpreadConstraints: []
initJob:
# Once ZITADEL is installed, the initJob can be disabled.
enabled: true
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-delete-policy: before-hook-creation
helm.sh/hook-weight: "1"
resources: {}
backoffLimit: 5
activeDeadlineSeconds: 300
extraContainers: []
podAnnotations: {}
# Available init commands :
# "": initialize ZITADEL instance (without skip anything)
# database: initialize only the database
# grant: set ALL grant to user
# user: initialize only the database user
# zitadel: initialize ZITADEL internals (skip "create user" and "create database")
command: ""
setupJob:
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-delete-policy: before-hook-creation
helm.sh/hook-weight: "2"
resources: {}
activeDeadlineSeconds: 300
extraContainers: []
podAnnotations: {}
additionalArgs:
- "--init-projections=true"
machinekeyWriter:
image:
repository: bitnami/kubectl
tag: ""
resources: {}
readinessProbe:
enabled: true
initialDelaySeconds: 0
periodSeconds: 5
failureThreshold: 3
livenessProbe:
enabled: true
initialDelaySeconds: 0
periodSeconds: 5
failureThreshold: 3
startupProbe:
enabled: true
periodSeconds: 1
failureThreshold: 30
metrics:
enabled: false
serviceMonitor:
# If true, the chart creates a ServiceMonitor that is compatible with Prometheus Operator
# https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#monitoring.coreos.com/v1.ServiceMonitor.
# The Prometheus community Helm chart installs this operator
# https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack#kube-prometheus-stack
enabled: false
honorLabels: false
honorTimestamps: true
pdb:
enabled: false
# these values are used for the PDB and are mutally exclusive
minAvailable: 1
# maxUnavailable: 1
annotations: {}

View File

@@ -1,39 +0,0 @@
# Kustomize is a supported holos component kind
exec holos render component --cluster-name=mycluster . --log-level=debug
# Want generated output
cmp want.yaml deploy/clusters/mycluster/components/kstest/kstest.gen.yaml
-- platform.config.json --
{}
-- cue.mod --
package holos
-- component.cue --
package holos
_cluster: string @tag(cluster, string)
_platform_config: string @tag(platform_config, string)
apiVersion: "holos.run/v1alpha1"
kind: "BuildPlan"
spec: components: KustomizeBuildList: [{metadata: name: "kstest"}]
-- kustomization.yaml --
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: mynamespace
resources:
- serviceaccount.yaml
-- serviceaccount.yaml --
apiVersion: v1
kind: ServiceAccount
metadata:
name: test
-- want.yaml --
apiVersion: v1
kind: ServiceAccount
metadata:
name: test
namespace: mynamespace

View File

@@ -1,17 +0,0 @@
# https://github.com/holos-run/holos/issues/72
# Want holos to fail on unknown fields to catch typos and aid refactors
! exec holos build .
stderr 'unknown field \\"TypoKubernetesObjectsList\\"'
-- platform.config.json --
{}
-- cue.mod --
package holos
-- component.cue --
package holos
_cluster: string @tag(cluster, string)
_platform_config: string @tag(platform_config, string)
apiVersion: "holos.run/v1alpha1"
kind: "BuildPlan"
spec: components: TypoKubernetesObjectsList: []

File diff suppressed because it is too large Load Diff

View File

@@ -80,33 +80,62 @@ The bank front end web service is managed by the
refers to the organization display name in `schema.gen.cue`.
<Tabs groupId="F5B546EB-566F-4B83-84C3-C55B40F55555">
<TabItem value="schema.gen.cue" label="schema.gen.cue">
<TabItem value="schema.cue" label="schema.cue">
```cue showLineNumbers
package holos
import api "github.com/holos-run/holos/api/author/v1alpha3"
import api "github.com/holos-run/holos/api/author/v1alpha4"
// Define the default organization name
// highlight-next-line
#Organization: DisplayName: string | *"Bank of Holos"
#Organization: Name: string | *"bank-of-holos"
#Organization: api.#OrganizationStrict
#Platform: api.#Platform
#Fleets: api.#StandardFleets
_ComponentConfig: {
Resources: #Resources
ArgoConfig: #ArgoConfig
// Define the default organization name.
_Organization: api.#OrganizationStrict & {
DisplayName: string | *"Bank of Holos"
Name: string | *"bank-of-holos"
Domain: string | *"holos.localhost"
}
#Helm: api.#Helm & _ComponentConfig
#Kustomize: api.#Kustomize & _ComponentConfig
#Kubernetes: api.#Kubernetes & _ComponentConfig
// Projects represents a way to organize components into projects with owners.
// https://holos.run/docs/api/author/v1alpha4/#Projects
_Projects: api.#Projects
#ArgoConfig: api.#ArgoConfig & {
ClusterName: _ClusterName
// ArgoConfig represents the configuration of ArgoCD Application resources for
// each component.
// https://holos.run/docs/api/author/v1alpha4/#ArgoConfig
_ArgoConfig: api.#ArgoConfig
#ComponentConfig: api.#ComponentConfig & {
Name: _Tags.name
Component: _Tags.component
Cluster: _Tags.cluster
ArgoConfig: _ArgoConfig & {
if _Tags.project != "no-project" {
AppProject: _Tags.project
}
}
Resources: #Resources
// Mix in project labels if the project is defined by the platform.
if _Tags.project != "no-project" {
CommonLabels: _Projects[_Tags.project].CommonLabels
}
}
// https://holos.run/docs/api/author/v1alpha4/#Kubernetes
#Kubernetes: close({
#ComponentConfig
api.#Kubernetes
})
// https://holos.run/docs/api/author/v1alpha4/#Kustomize
#Kustomize: close({
#ComponentConfig
api.#Kustomize
})
// https://holos.run/docs/api/author/v1alpha4/#Helm
#Helm: close({
#ComponentConfig
api.#Helm
})
```
</TabItem>
<TabItem value="projects/bank-of-holos/frontend/components/bank-frontend/bank-frontend.cue" label="projects/bank-of-holos/frontend/components/bank-frontend/bank-frontend.cue">
@@ -117,215 +146,214 @@ package holos
(#Kubernetes & Objects).BuildPlan
let Objects = {
Name: "bank-frontend"
Namespace: #BankOfHolos.Frontend.Namespace
Name: "bank-frontend"
Namespace: _BankOfHolos.Frontend.Namespace
// Ensure resources go in the correct namespace
Resources: [_]: [_]: metadata: namespace: Namespace
// Ensure resources go in the correct namespace
Resources: [_]: [_]: metadata: namespace: Namespace
// https://github.com/GoogleCloudPlatform/bank-of-anthos/blob/release/v0.6.5/kubernetes-manifests/frontend.yaml
Resources: {
Service: frontend: {
metadata: name: "frontend"
metadata: labels: {
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
spec: {
selector: {
app: "frontend"
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
_ports: http: {
name: "http"
port: 80
targetPort: 8080
protocol: "TCP"
}
ports: [for x in _ports {x}]
}
}
// https://github.com/GoogleCloudPlatform/bank-of-anthos/blob/release/v0.6.5/kubernetes-manifests/frontend.yaml
Resources: {
Service: frontend: {
metadata: name: "frontend"
metadata: labels: {
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
spec: {
selector: {
app: "frontend"
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
_ports: http: {
name: "http"
port: 80
targetPort: 8080
protocol: "TCP"
}
ports: [for x in _ports {x}]
}
}
Deployment: frontend: {
metadata: name: "frontend"
metadata: labels: {
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
spec: {
selector: matchLabels: {
app: "frontend"
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
template: {
metadata: labels: {
app: "frontend"
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
spec: {
securityContext: {
seccompProfile: type: "RuntimeDefault"
fsGroup: 1000
runAsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
}
serviceAccountName: "bank-of-holos"
terminationGracePeriodSeconds: 5
containers: [{
env: [{
name: "BANK_NAME"
// highlight-next-line
value: #Organization.DisplayName
}, {
name: "ENV_PLATFORM"
value: "local"
}, {
name: "VERSION"
value: "v0.6.5"
}, {
name: "PORT"
value: "8080"
}, {
name: "ENABLE_TRACING"
value: "false"
}, {
name: "SCHEME"
value: "https"
}, {
name: "LOG_LEVEL"
value: "info"
}, {
name: "DEFAULT_USERNAME"
valueFrom: configMapKeyRef: {
key: "DEMO_LOGIN_USERNAME"
name: "demo-data-config"
}
}, {
name: "DEFAULT_PASSWORD"
valueFrom: configMapKeyRef: {
key: "DEMO_LOGIN_PASSWORD"
name: "demo-data-config"
}
}, {
name: "REGISTERED_OAUTH_CLIENT_ID"
valueFrom: configMapKeyRef: {
key: "DEMO_OAUTH_CLIENT_ID"
name: "oauth-config"
optional: true
}
}, {
name: "ALLOWED_OAUTH_REDIRECT_URI"
valueFrom: configMapKeyRef: {
key: "DEMO_OAUTH_REDIRECT_URI"
name: "oauth-config"
optional: true
}
}]
envFrom: [{
configMapRef: name: "environment-config"
}, {
configMapRef: name: "service-api-config"
}]
image: "us-central1-docker.pkg.dev/bank-of-anthos-ci/bank-of-anthos/frontend:v0.6.5@sha256:d72050f70d12383e4434ad04d189b681dc625f696087ddf0b5df641645c9dafa"
livenessProbe: {
httpGet: {
path: "/ready"
port: 8080
}
initialDelaySeconds: 60
periodSeconds: 15
timeoutSeconds: 30
}
name: "front"
readinessProbe: {
httpGet: {
path: "/ready"
port: 8080
}
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 10
}
resources: {
limits: {
cpu: "250m"
memory: "128Mi"
}
requests: {
cpu: "100m"
memory: "64Mi"
}
}
securityContext: {
allowPrivilegeEscalation: false
capabilities: drop: ["all"]
privileged: false
readOnlyRootFilesystem: true
}
volumeMounts: [{
mountPath: "/tmp"
name: "tmp"
}, {
mountPath: "/tmp/.ssh"
name: "publickey"
readOnly: true
}]
}]
volumes: [
{
emptyDir: {}
name: "tmp"
},
{
name: "publickey"
secret: {
items: [{key: "jwtRS256.key.pub", path: "publickey"}]
secretName: "jwt-key"
}
},
]
}
}
}
}
Deployment: frontend: {
metadata: name: "frontend"
metadata: labels: {
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
spec: {
selector: matchLabels: {
app: "frontend"
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
template: {
metadata: labels: {
app: "frontend"
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
spec: {
securityContext: {
seccompProfile: type: "RuntimeDefault"
fsGroup: 1000
runAsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
}
serviceAccountName: "bank-of-holos"
terminationGracePeriodSeconds: 5
containers: [{
env: [{
name: "BANK_NAME"
value: _Organization.DisplayName
}, {
name: "ENV_PLATFORM"
value: "local"
}, {
name: "VERSION"
value: "v0.6.5"
}, {
name: "PORT"
value: "8080"
}, {
name: "ENABLE_TRACING"
value: "false"
}, {
name: "SCHEME"
value: "https"
}, {
name: "LOG_LEVEL"
value: "info"
}, {
name: "DEFAULT_USERNAME"
valueFrom: configMapKeyRef: {
key: "DEMO_LOGIN_USERNAME"
name: "demo-data-config"
}
}, {
name: "DEFAULT_PASSWORD"
valueFrom: configMapKeyRef: {
key: "DEMO_LOGIN_PASSWORD"
name: "demo-data-config"
}
}, {
name: "REGISTERED_OAUTH_CLIENT_ID"
valueFrom: configMapKeyRef: {
key: "DEMO_OAUTH_CLIENT_ID"
name: "oauth-config"
optional: true
}
}, {
name: "ALLOWED_OAUTH_REDIRECT_URI"
valueFrom: configMapKeyRef: {
key: "DEMO_OAUTH_REDIRECT_URI"
name: "oauth-config"
optional: true
}
}]
envFrom: [{
configMapRef: name: "environment-config"
}, {
configMapRef: name: "service-api-config"
}]
image: "us-central1-docker.pkg.dev/bank-of-anthos-ci/bank-of-anthos/frontend:v0.6.5@sha256:d72050f70d12383e4434ad04d189b681dc625f696087ddf0b5df641645c9dafa"
livenessProbe: {
httpGet: {
path: "/ready"
port: 8080
}
initialDelaySeconds: 60
periodSeconds: 15
timeoutSeconds: 30
}
name: "front"
readinessProbe: {
httpGet: {
path: "/ready"
port: 8080
}
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 10
}
resources: {
limits: {
cpu: "250m"
memory: "128Mi"
}
requests: {
cpu: "100m"
memory: "64Mi"
}
}
securityContext: {
allowPrivilegeEscalation: false
capabilities: drop: ["all"]
privileged: false
readOnlyRootFilesystem: true
}
volumeMounts: [{
mountPath: "/tmp"
name: "tmp"
}, {
mountPath: "/tmp/.ssh"
name: "publickey"
readOnly: true
}]
}]
volumes: [
{
emptyDir: {}
name: "tmp"
},
{
name: "publickey"
secret: {
items: [{key: "jwtRS256.key.pub", path: "publickey"}]
secretName: "jwt-key"
}
},
]
}
}
}
}
// Allow HTTPRoutes in the ingress gateway namespace to reference Services
// in this namespace.
ReferenceGrant: grant: #ReferenceGrant & {
metadata: namespace: Namespace
}
// Allow HTTPRoutes in the ingress gateway namespace to reference Services
// in this namespace.
ReferenceGrant: grant: _ReferenceGrant & {
metadata: namespace: Namespace
}
// Include shared resources
#BankOfHolos.Resources
}
// Include shared resources
_BankOfHolos.Resources
}
}
```
</TabItem>
</Tabs>
Line 6 of the `schema.gen.cue` file defines the _default_ value for
`#Organization.DisplayName` by using `string | *"..."`. In CUE, the `*`
Line 7 of the `schema.cue` file defines the _default_ value for
`_Organization.DisplayName` by using `string | *"..."`. In CUE, the `*`
asterisk character denotes a [default value].
Line 78 of the `bank-frontend.cue` file refers to `#Organization.DisplayName` to
Line 78 of the `bank-frontend.cue` file refers to `_Organization.DisplayName` to
configure the front end web container.
Let's change the name of the bank by defining a new value for
`#Organization.DisplayName` at the root of the configuration. Create
`_Organization.DisplayName` at the root of the configuration. Create
`projects/organization.cue` with the following content.
<Tabs groupId="B386181F-EBE7-469D-8CB5-37631067669B">
@@ -333,7 +361,7 @@ Let's change the name of the bank by defining a new value for
```cue showLineNumbers
package holos
#Organization: DisplayName: "The Holistic-Bank"
_Organization: DisplayName: "The Holistic-Bank"
```
</TabItem>
</Tabs>
@@ -348,18 +376,11 @@ holos render platform ./platform
</TabItem>
<TabItem value="output" label="Output">
```txt
#Organization.DisplayName: 2 errors in empty disjunction:
#Organization.DisplayName: conflicting values "Bank of Holos" and "The Holistic-Bank":
/bank-of-holos/projects/organization.cue:3:29
/bank-of-holos/schema.gen.cue:6:39
// highlight-next-line
#Organization.DisplayName: invalid value "The Holistic-Bank" (out of bound =~"^[0-9A-Za-z][0-9A-Za-z ]{2,61}[0-9A-Za-z]$"):
/bank-of-holos/cue.mod/gen/github.com/holos-run/holos/api/author/v1alpha3/definitions_go_gen.cue:203:25
/bank-of-holos/cue.mod/gen/github.com/holos-run/holos/api/author/v1alpha3/definitions_go_gen.cue:188:15
/bank-of-holos/cue.mod/gen/github.com/holos-run/holos/api/author/v1alpha3/definitions_go_gen.cue:203:15
/bank-of-holos/projects/organization.cue:3:29
/bank-of-holos/schema.gen.cue:6:29
could not run: could not render component: exit status 1 at internal/render/platform.go:50
could not run: could not marshal json projects/platform/components/istio/cni: cue: marshal error: _Organization.DisplayName: 2 errors in empty disjunction: (and 2 more errors) at internal/builder/builder.go:63
_Organization.DisplayName: _Organization.DisplayName: 2 errors in empty disjunction: (and 2 more errors)
could not run: could not marshal json projects/platform/components/argocd/crds: cue: marshal error: _Organization.DisplayName: 2 errors in empty disjunction: (and 2 more errors) at internal/builder/builder.go:63
_Organization.DisplayName: _Organization.DisplayName: 2 errors in empty disjunction: (and 2 more errors)
could not run: could not render component: exit status 1 at builder/v1alpha4/builder.go:95
```
</TabItem>
</Tabs>
@@ -386,7 +407,7 @@ Let's try again, this time replacing the hyphen with a space.
```cue showLineNumbers
package holos
#Organization: DisplayName: "The Holistic Bank"
_Organization: DisplayName: "The Holistic Bank"
```
</TabItem>
</Tabs>

View File

@@ -130,23 +130,23 @@ package holos
// Platform wide definitions
// highlight-next-line
#Migration: Namespace: "migration"
_Migration: Namespace: "migration"
// Register namespaces
// highlight-next-line
#Namespaces: (#Migration.Namespace): _
_Namespaces: (_Migration.Namespace): _
// Register projects
// highlight-next-line
#AppProjects: migration: _
_AppProjects: migration: _
```
</TabItem>
</Tabs>
Each of the highlighted lines has a specific purpose.
- Line 4 defines the `#Migration` CUE struct. The team that currently owns the
migration project defines this struct.
- Line 4 defines the `_Migration` hidden field. The team owning the migration
project manages this struct.
- Line 7 registers the namespace with the `namespaces` component owned by the
platform team. The `_` value indicates the value is defined elsewhere in CUE.
In this case, the platform team defines what a Namespace is.
@@ -208,9 +208,9 @@ Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
// highlight-next-line
modified: deploy/clusters/workload/components/app-projects/app-projects.gen.yaml
modified: deploy/clusters/local/components/app-projects/app-projects.gen.yaml
// highlight-next-line
modified: deploy/clusters/workload/components/namespaces/namespaces.gen.yaml
modified: deploy/clusters/local/components/namespaces/namespaces.gen.yaml
Untracked files:
(use "git add <file>..." to include in what will be committed)
@@ -230,15 +230,14 @@ git diff deploy
</TabItem>
<TabItem value="output" label="Output">
```diff
diff --git a/deploy/clusters/workload/components/app-projects/app-projects.gen.yaml b/deploy/clusters/workload/components/app-projects/app-projects.gen.yaml
diff --git a/deploy/clusters/local/components/app-projects/app-projects.gen.yaml b/deploy/clusters/local/components/app-projects/app-projects.gen.yaml
index bdc8371..42cb01a 100644
--- a/deploy/clusters/workload/components/app-projects/app-projects.gen.yaml
+++ b/deploy/clusters/workload/components/app-projects/app-projects.gen.yaml
--- a/deploy/clusters/local/components/app-projects/app-projects.gen.yaml
+++ b/deploy/clusters/local/components/app-projects/app-projects.gen.yaml
@@ -50,6 +50,23 @@ spec:
sourceRepos:
- '*'
---
+# Source: CUE apiObjects.AppProject.migration
+apiVersion: argoproj.io/v1alpha1
+kind: AppProject
+metadata:
@@ -255,19 +254,17 @@ index bdc8371..42cb01a 100644
+ sourceRepos:
+ - '*'
+---
# Source: CUE apiObjects.AppProject.platform
apiVersion: argoproj.io/v1alpha1
kind: AppProject
diff --git a/deploy/clusters/workload/components/namespaces/namespaces.gen.yaml b/deploy/clusters/workload/components/namespaces/namespaces.gen.yaml
diff --git a/deploy/clusters/local/components/namespaces/namespaces.gen.yaml b/deploy/clusters/local/components/namespaces/namespaces.gen.yaml
index de96ab9..7ddd870 100644
--- a/deploy/clusters/workload/components/namespaces/namespaces.gen.yaml
+++ b/deploy/clusters/workload/components/namespaces/namespaces.gen.yaml
--- a/deploy/clusters/local/components/namespaces/namespaces.gen.yaml
+++ b/deploy/clusters/local/components/namespaces/namespaces.gen.yaml
@@ -62,3 +62,11 @@ metadata:
kubernetes.io/metadata.name: istio-system
kind: Namespace
apiVersion: v1
+---
+# Source: CUE apiObjects.Namespace.migration
+metadata:
+ name: migration
+ labels:
@@ -351,37 +348,33 @@ import ks "sigs.k8s.io/kustomize/api/types"
// Produce a helm chart build plan.
// highlight-next-line
(#Helm & Chart).BuildPlan
_Helm.BuildPlan
let Chart = {
// highlight-next-line
Name: "podinfo"
// highlight-next-line
Namespace: #Migration.Namespace
_Helm: #Helm & {
// highlight-next-line
Name: "podinfo"
// highlight-next-line
Namespace: _Migration.Namespace
Chart: {
version: "6.6.2"
repository: {
name: "podinfo"
url: "https://stefanprodan.github.io/podinfo"
}
}
Chart: {
version: "6.6.2"
repository: {
name: "podinfo"
url: "https://stefanprodan.github.io/podinfo"
}
}
// Necessary to ensure the resources go to the correct namespace.
// highlight-next-line
EnableKustomizePostProcessor: true
// highlight-next-line
KustomizeFiles: "kustomization.yaml": ks.#Kustomization & {
namespace: Namespace
}
KustomizeConfig: Kustomization: ks.#Kustomization & {
// highlight-next-line
namespace: Namespace
}
// Allow the platform team to route traffic into our namespace.
// highlight-next-line
Resources: ReferenceGrant: grant: #ReferenceGrant & {
metadata: namespace: Namespace
}
// Allow the platform team to route traffic into our namespace.
Resources: ReferenceGrant: grant: _ReferenceGrant & {
// highlight-next-line
metadata: namespace: Namespace
}
}
```
</TabItem>
</Tabs>
@@ -403,16 +396,16 @@ component, `podinfo/podinfo.cue`, but `holos` doesn't enforce this convention.
**Line 10**: We use the same namespace we registered with the `namespaces`
component as the value we pass to Helm. This is a good example of Holos
offering safety and consistency with CUE, if we change the value of
`#Migration.Namespace`, multiple components stay consistent.
`_Migration.Namespace`, multiple components stay consistent.
**Lines 20-21**: Unfortunately, the Helm chart doesn't set the
**Lines 21**: Unfortunately, the Helm chart doesn't set the
`metadata.namespace` field for the resources it generates, which creates a
security problem. The resources will be created in the wrong namespace. We
don't want to modify the upstream chart because it creates a maintenance burden.
We solve the problem by having Holos post-process the Helm output with
Kustomize. This ensures all resources go into the correct namespace.
**Lines 27**: The migration team grants the platform team permission to route
**Lines 26**: The migration team grants the platform team permission to route
traffic into the `migration` Namespace using a [ReferenceGrant].
:::note
@@ -463,11 +456,12 @@ following content.
package holos
// Manage on workload clusters only
for Cluster in #Fleets.workload.clusters {
#Platform: Components: "\(Cluster.name)/podinfo": {
path: "projects/migration/components/podinfo"
cluster: Cluster.name
}
for Cluster in _Fleets.workload.clusters {
_Platform: Components: "\(Cluster.name)/podinfo": {
name: "podinfo"
component: "projects/migration/components/podinfo"
cluster: Cluster.name
}
}
```
</TabItem>
@@ -492,7 +486,7 @@ package holos
// Assign ArgoCD Applications to the migration AppProject
// highlight-next-line
#ArgoConfig: AppProject: #AppProjects.migration.metadata.name
_ArgoConfig: AppProject: _AppProjects.migration.metadata.name
```
</TabItem>
</Tabs>
@@ -501,7 +495,7 @@ This file provides consistency and safety in a number of ways:
1. All components under `projects/migration/` will automatically have their
ArgoCD Application assigned to the migration `AppProject`.
2. `holos render platform` errors out if `#AppProjects.migration` is not
2. `holos render platform` errors out if `_AppProjects.migration` is not
defined, we defined it in `projects/migration.cue`
3. The platform team is responsible for managing the `AppProject` resource
itself, the team doing the migration refers to the `metadata.name` field defined
@@ -561,14 +555,14 @@ git status
</TabItem>
<TabItem value="output" label="Output">
```txt
On branch main
On branch jeff/291-consistent-fields
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: deploy/clusters/workload/components/podinfo/podinfo.gen.yaml
new file: deploy/clusters/workload/gitops/podinfo.application.gen.yaml
new file: platform/migration-podinfo.cue
new file: projects/migration/app-project.cue
new file: projects/migration/components/podinfo/podinfo.cue
new file: deploy/clusters/local/components/podinfo/podinfo.gen.yaml
new file: deploy/clusters/local/gitops/podinfo.gen.yaml
new file: platform/migration-podinfo.cue
new file: projects/migration/app-project.cue
new file: projects/migration/components/podinfo/podinfo.cue
```
</TabItem>
</Tabs>
@@ -578,25 +572,26 @@ in a new manifest for the Helm output along with an ArgoCD Application for
GitOps. Here's what they look like:
<Tabs groupId="0F2B3066-B57F-466E-A27F-A603C1803E11">
<TabItem value="deploy/clusters/workload/gitops/podinfo.application.gen.yaml" label="podinfo.application.gen.yaml">
<TabItem value="deploy/clusters/local/gitops/podinfo.gen.yaml" label="podinfo.gen.yaml">
```yaml showLineNumbers
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
labels:
holos.run/component.name: podinfo
name: podinfo
namespace: argocd
spec:
destination:
server: https://kubernetes.default.svc
# highlight-next-line
project: migration
source:
path: ./deploy/clusters/workload/components/podinfo
path: deploy/clusters/local/components/podinfo
repoURL: https://github.com/holos-run/bank-of-holos
targetRevision: main
```
</TabItem>
<TabItem value="deploy/clusters/workload/components/podinfo/podinfo.gen.yaml" label="podinfo.gen.yaml">
<TabItem value="deploy/clusters/local/components/podinfo/podinfo.gen.yaml" label="podinfo.gen.yaml">
```yaml showLineNumbers
apiVersion: v1
kind: Service
@@ -605,9 +600,10 @@ metadata:
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: podinfo
app.kubernetes.io/version: 6.6.2
argocd.argoproj.io/instance: podinfo
helm.sh/chart: podinfo-6.6.2
holos.run/component.name: podinfo
name: podinfo
# highlight-next-line
namespace: migration
spec:
ports:
@@ -621,6 +617,8 @@ spec:
targetPort: grpc
selector:
app.kubernetes.io/name: podinfo
argocd.argoproj.io/instance: podinfo
holos.run/component.name: podinfo
type: ClusterIP
---
apiVersion: apps/v1
@@ -630,15 +628,18 @@ metadata:
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: podinfo
app.kubernetes.io/version: 6.6.2
argocd.argoproj.io/instance: podinfo
helm.sh/chart: podinfo-6.6.2
holos.run/component.name: podinfo
name: podinfo
# highlight-next-line
namespace: migration
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: podinfo
argocd.argoproj.io/instance: podinfo
holos.run/component.name: podinfo
strategy:
rollingUpdate:
maxUnavailable: 1
@@ -650,6 +651,8 @@ spec:
prometheus.io/scrape: "true"
labels:
app.kubernetes.io/name: podinfo
argocd.argoproj.io/instance: podinfo
holos.run/component.name: podinfo
spec:
containers:
- command:
@@ -714,6 +717,23 @@ spec:
volumes:
- emptyDir: {}
name: data
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
labels:
argocd.argoproj.io/instance: podinfo
holos.run/component.name: podinfo
name: istio-ingress
namespace: migration
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: istio-ingress
to:
- group: ""
kind: Service
```
</TabItem>
</Tabs>
@@ -730,10 +750,10 @@ git commit -m 'register the migration project podinfo component with the platfor
</TabItem>
<TabItem value="output" label="Output">
```txt
[main] register the migration project podinfo component with the platform
5 files changed, 167 insertions(+)
create mode 100644 deploy/clusters/workload/components/podinfo/podinfo.gen.yaml
create mode 100644 deploy/clusters/workload/gitops/podinfo.application.gen.yaml
[main 31197e2] register the migration project podinfo component with the platform
5 files changed, 205 insertions(+)
create mode 100644 deploy/clusters/local/components/podinfo/podinfo.gen.yaml
create mode 100644 deploy/clusters/local/gitops/podinfo.gen.yaml
create mode 100644 platform/migration-podinfo.cue
create mode 100644 projects/migration/app-project.cue
create mode 100644 projects/migration/components/podinfo/podinfo.cue
@@ -777,9 +797,9 @@ platform as a whole. Bank of Holos uses [HTTPRoute] routes from the new Gateway
API. The company the bank acquired uses older Ingress resources from earlier
Kubernetes versions.
The platform team at the bank defines a `#HTTPRoutes` struct for other teams at
the bank to register with. The `#HTTPRoutes` struct is similar to the
`#Namespaces` and `#AppProjects` structs we've already seen.
The platform team at the bank defines a `_HTTPRoutes` struct for other teams at
the bank to register with. The `_HTTPRoutes` struct is similar to the
`_Namespaces` and `_AppProjects` structs we've already seen.
As a member of the migration team, we'll add the file
`projects/migration-routes.cue` to expose the service we're migrating.
@@ -791,17 +811,15 @@ Go ahead and create this file (if it hasn't been created previously) with the fo
```cue showLineNumbers
package holos
let Podinfo = {
podinfo: {
port: 9898
namespace: #Migration.Namespace
}
}
// Route migration-podinfo.example.com to port 9898 of Service podinfo in the
// migration namespace.
// highlight-next-line
#HTTPRoutes: "migration-podinfo": _backendRefs: Podinfo
_HTTPRoutes: "migration-podinfo": _backendRefs: {
podinfo: {
port: 9898
namespace: _Migration.Namespace
}
}
```
</TabItem>
<TabItem value="projects/httproutes.cue" label="projects/httproutes.cue">
@@ -810,44 +828,45 @@ package holos
import v1 "gateway.networking.k8s.io/httproute/v1"
// #HTTPRoutes defines managed HTTPRoute resources for the platform. These
// resources are managed in the istio-ingress namespace. Other components
// define the routes they need close to the root of configuration.
// Struct containing HTTPRoute configurations. These resources are managed in
// the istio-ingress namespace. Other components define the routes they need
// close to the root of configuration.
_HTTPRoutes: #HTTPRoutes
// #HTTPRoutes defines the schema of managed HTTPRoute resources for the
// platform.
#HTTPRoutes: {
// For the guides, we simplify this down to a flat namespace.
// highlight-next-line
[Name=string]: v1.#HTTPRoute & {
let HOST = Name + "." + #Organization.Domain
// For the guides, we simplify this down to a flat namespace.
[Name=string]: v1.#HTTPRoute & {
let HOST = Name + "." + _Organization.Domain
// highlight-next-line
_backendRefs: [NAME=string]: {
name: NAME
namespace: string
port: number | *80
}
_backendRefs: [NAME=string]: {
name: NAME
namespace: string
port: number | *80
}
metadata: name: Name
metadata: namespace: #Istio.Gateway.Namespace
metadata: labels: app: Name
spec: hostnames: [HOST]
spec: parentRefs: [{
name: "default"
namespace: metadata.namespace
}]
spec: rules: [
{
matches: [{path: {type: "PathPrefix", value: "/"}}]
// highlight-next-line
backendRefs: [for x in _backendRefs {x}]
},
]
}
metadata: name: Name
metadata: namespace: _Istio.Gateway.Namespace
metadata: labels: app: Name
spec: hostnames: [HOST]
spec: parentRefs: [{
name: "default"
namespace: metadata.namespace
}]
spec: rules: [
{
matches: [{path: {type: "PathPrefix", value: "/"}}]
backendRefs: [for x in _backendRefs {x}]
},
]
}
}
```
</TabItem>
</Tabs>
In this file we're adding a field to the `#HTTPRoutes` struct the platform team
In this file we're adding a field to the `_HTTPRoutes` struct the platform team
defined for us.
You might be wondering how we knew all of these fields to put into this file.
@@ -861,8 +880,9 @@ The most important things the migration team takes away from this file are:
1. The platform team requires a `gateway.networking.k8s.io/httproute/v1`
`HTTPRoute`.
2. Line 13 uses a [hidden field] so we can provide backend references as a struct instead of a list.
3. Line 30 uses a [comprehension] to convert the struct to a list.
2. Line 17 uses a [hidden field] so we can provide backend references as a
struct instead of a list.
3. Line 34 uses a [comprehension] to convert the struct to a list.
We can look up the spec for the fields we need to provide in the Gateway API
reference documentation for [HTTPRoute].
@@ -928,10 +948,10 @@ git diff
</TabItem>
<TabItem value="output" label="Output">
```diff
diff --git a/deploy/clusters/workload/components/httproutes/httproutes.gen.yaml b/deploy/clusters/workload/components/httproutes/httproutes.gen.yaml
diff --git a/deploy/clusters/local/components/httproutes/httproutes.gen.yaml b/deploy/clusters/local/components/httproutes/httproutes.gen.yaml
index 06f7c91..349e070 100644
--- a/deploy/clusters/workload/components/httproutes/httproutes.gen.yaml
+++ b/deploy/clusters/workload/components/httproutes/httproutes.gen.yaml
--- a/deploy/clusters/local/components/httproutes/httproutes.gen.yaml
+++ b/deploy/clusters/local/components/httproutes/httproutes.gen.yaml
@@ -47,3 +47,28 @@ spec:
- path:
type: PathPrefix
@@ -961,7 +981,6 @@ index 06f7c91..349e070 100644
+ - path:
+ type: PathPrefix
+ value: /
```
</TabItem>
</Tabs>
@@ -1044,7 +1063,7 @@ in the `bank-of-holos` repository after resetting your cluster following the
</TabItem>
<TabItem value="output" label="Output">
```txt
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/namespaces/namespaces.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/namespaces/namespaces.gen.yaml
namespace/argocd serverside-applied
namespace/bank-backend serverside-applied
namespace/bank-frontend serverside-applied
@@ -1054,17 +1073,17 @@ namespace/external-secrets serverside-applied
namespace/istio-ingress serverside-applied
namespace/istio-system serverside-applied
namespace/migration serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/argocd-crds/argocd-crds.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/argocd-crds/argocd-crds.gen.yaml
customresourcedefinition.apiextensions.k8s.io/applications.argoproj.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/applicationsets.argoproj.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/appprojects.argoproj.io serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/gateway-api/gateway-api.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/gateway-api/gateway-api.gen.yaml
customresourcedefinition.apiextensions.k8s.io/gatewayclasses.gateway.networking.k8s.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/gateways.gateway.networking.k8s.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/grpcroutes.gateway.networking.k8s.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/httproutes.gateway.networking.k8s.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/referencegrants.gateway.networking.k8s.io serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/external-secrets-crds/external-secrets-crds.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/external-secrets-crds/external-secrets-crds.gen.yaml
customresourcedefinition.apiextensions.k8s.io/acraccesstokens.generators.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/clusterexternalsecrets.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/clustersecretstores.external-secrets.io serverside-applied
@@ -1126,7 +1145,7 @@ customresourcedefinition.apiextensions.k8s.io/wasmplugins.extensions.istio.io co
customresourcedefinition.apiextensions.k8s.io/webhooks.generators.external-secrets.io condition met
customresourcedefinition.apiextensions.k8s.io/workloadentries.networking.istio.io condition met
customresourcedefinition.apiextensions.k8s.io/workloadgroups.networking.istio.io condition met
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/external-secrets/external-secrets.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/external-secrets/external-secrets.gen.yaml
serviceaccount/external-secrets-cert-controller serverside-applied
serviceaccount/external-secrets serverside-applied
serviceaccount/external-secrets-webhook serverside-applied
@@ -1146,7 +1165,7 @@ deployment.apps/external-secrets serverside-applied
deployment.apps/external-secrets-webhook serverside-applied
validatingwebhookconfiguration.admissionregistration.k8s.io/secretstore-validate serverside-applied
validatingwebhookconfiguration.admissionregistration.k8s.io/externalsecret-validate serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/cert-manager/cert-manager.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/cert-manager/cert-manager.gen.yaml
serviceaccount/cert-manager-cainjector serverside-applied
serviceaccount/cert-manager serverside-applied
serviceaccount/cert-manager-webhook serverside-applied
@@ -1192,11 +1211,11 @@ deployment.apps/cert-manager serverside-applied
deployment.apps/cert-manager-webhook serverside-applied
mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook serverside-applied
validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/local-ca/local-ca.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/local-ca/local-ca.gen.yaml
clusterissuer.cert-manager.io/local-ca serverside-applied
+ kubectl wait --for=condition=Ready clusterissuer/local-ca --timeout=30s
clusterissuer.cert-manager.io/local-ca condition met
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/argocd/argocd.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/argocd/argocd.gen.yaml
serviceaccount/argocd-application-controller serverside-applied
serviceaccount/argocd-applicationset-controller serverside-applied
serviceaccount/argocd-notifications-controller serverside-applied
@@ -1243,13 +1262,13 @@ deployment.apps/argocd-server serverside-applied
statefulset.apps/argocd-application-controller serverside-applied
job.batch/argocd-redis-secret-init serverside-applied
referencegrant.gateway.networking.k8s.io/istio-ingress serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/app-projects/app-projects.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/app-projects/app-projects.gen.yaml
appproject.argoproj.io/bank-backend serverside-applied
appproject.argoproj.io/bank-frontend serverside-applied
appproject.argoproj.io/bank-security serverside-applied
appproject.argoproj.io/migration serverside-applied
appproject.argoproj.io/platform serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/istio-base/istio-base.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/istio-base/istio-base.gen.yaml
customresourcedefinition.apiextensions.k8s.io/authorizationpolicies.security.istio.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/destinationrules.networking.istio.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/envoyfilters.networking.istio.io serverside-applied
@@ -1266,7 +1285,7 @@ customresourcedefinition.apiextensions.k8s.io/workloadentries.networking.istio.i
customresourcedefinition.apiextensions.k8s.io/workloadgroups.networking.istio.io serverside-applied
serviceaccount/istio-reader-service-account serverside-applied
validatingwebhookconfiguration.admissionregistration.k8s.io/istiod-default-validator serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/istiod/istiod.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/istiod/istiod.gen.yaml
serviceaccount/istiod serverside-applied
role.rbac.authorization.k8s.io/istiod serverside-applied
clusterrole.rbac.authorization.k8s.io/istio-reader-clusterrole-istio-system serverside-applied
@@ -1284,7 +1303,7 @@ poddisruptionbudget.policy/istiod serverside-applied
horizontalpodautoscaler.autoscaling/istiod serverside-applied
mutatingwebhookconfiguration.admissionregistration.k8s.io/istio-sidecar-injector serverside-applied
validatingwebhookconfiguration.admissionregistration.k8s.io/istio-validator-istio-system serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/istio-cni/istio-cni.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/istio-cni/istio-cni.gen.yaml
serviceaccount/istio-cni serverside-applied
configmap/istio-cni-config serverside-applied
clusterrole.rbac.authorization.k8s.io/istio-cni serverside-applied
@@ -1296,20 +1315,20 @@ clusterrolebinding.rbac.authorization.k8s.io/istio-cni-ambient serverside-applie
daemonset.apps/istio-cni-node serverside-applied
+ kubectl wait --for=condition=Ready pod -l k8s-app=istio-cni-node --timeout=300s -n istio-system
pod/istio-cni-node-7kfbh condition met
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/istio-ztunnel/istio-ztunnel.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/istio-ztunnel/istio-ztunnel.gen.yaml
serviceaccount/ztunnel serverside-applied
daemonset.apps/ztunnel serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/istio-gateway/istio-gateway.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/istio-gateway/istio-gateway.gen.yaml
certificate.cert-manager.io/gateway-cert serverside-applied
gateway.gateway.networking.k8s.io/default serverside-applied
serviceaccount/default-istio serverside-applied
+ kubectl wait --for=condition=Ready pod -l istio.io/gateway-name=default --timeout=300s -n istio-ingress
pod/default-istio-54598d985b-69wmr condition met
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/httproutes/httproutes.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/httproutes/httproutes.gen.yaml
httproute.gateway.networking.k8s.io/argocd serverside-applied
httproute.gateway.networking.k8s.io/bank serverside-applied
httproute.gateway.networking.k8s.io/migration-podinfo serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-secrets/bank-secrets.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-secrets/bank-secrets.gen.yaml
configmap/jwt-key-writer serverside-applied
job.batch/jwt-key-writer serverside-applied
role.rbac.authorization.k8s.io/jwt-key-reader serverside-applied
@@ -1319,7 +1338,7 @@ rolebinding.rbac.authorization.k8s.io/jwt-key-writer serverside-applied
serviceaccount/jwt-key-writer serverside-applied
+ kubectl wait --for=condition=complete job.batch/jwt-key-writer -n bank-security --timeout=300s
job.batch/jwt-key-writer condition met
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-backend-config/bank-backend-config.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-backend-config/bank-backend-config.gen.yaml
configmap/demo-data-config serverside-applied
configmap/environment-config serverside-applied
configmap/service-api-config serverside-applied
@@ -1327,30 +1346,30 @@ externalsecret.external-secrets.io/jwt-key serverside-applied
referencegrant.gateway.networking.k8s.io/istio-ingress serverside-applied
secretstore.external-secrets.io/bank-security serverside-applied
serviceaccount/bank-of-holos serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-accounts-db/bank-accounts-db.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-accounts-db/bank-accounts-db.gen.yaml
configmap/accounts-db-config serverside-applied
service/accounts-db serverside-applied
statefulset.apps/accounts-db serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-ledger-db/bank-ledger-db.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-ledger-db/bank-ledger-db.gen.yaml
configmap/ledger-db-config serverside-applied
service/ledger-db serverside-applied
statefulset.apps/ledger-db serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-contacts/bank-contacts.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-contacts/bank-contacts.gen.yaml
deployment.apps/contacts serverside-applied
service/contacts serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-balance-reader/bank-balance-reader.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-balance-reader/bank-balance-reader.gen.yaml
deployment.apps/balancereader serverside-applied
service/balancereader serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-userservice/bank-userservice.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-userservice/bank-userservice.gen.yaml
deployment.apps/userservice serverside-applied
service/userservice serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-ledger-writer/bank-ledger-writer.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-ledger-writer/bank-ledger-writer.gen.yaml
deployment.apps/ledgerwriter serverside-applied
service/ledgerwriter serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-transaction-history/bank-transaction-history.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-transaction-history/bank-transaction-history.gen.yaml
deployment.apps/transactionhistory serverside-applied
service/transactionhistory serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-frontend/bank-frontend.gen.yaml
configmap/demo-data-config serverside-applied
configmap/environment-config serverside-applied
configmap/service-api-config serverside-applied
@@ -1360,7 +1379,7 @@ referencegrant.gateway.networking.k8s.io/istio-ingress serverside-applied
secretstore.external-secrets.io/bank-security serverside-applied
service/frontend serverside-applied
serviceaccount/bank-of-holos serverside-applied
+ kubectl apply --server-side=true -f deploy/clusters/workload/gitops
+ kubectl apply --server-side=true -f deploy/clusters/local/gitops
application.argoproj.io/app-projects serverside-applied
application.argoproj.io/argocd-crds serverside-applied
application.argoproj.io/argocd serverside-applied

View File

@@ -461,8 +461,9 @@ values into both charts to configure them in lock step.
<Tabs groupId="740ABBEB-7A03-4B53-9CD5-4B8C5680172F">
<TabItem value="projects/blackbox.schema.cue" label="Blackbox Schema">
```txt
projects/blackbox.schema.cue
```bash
mkdir -p projects
touch projects/blackbox.schema.cue
```
```cue showLineNumbers
package holos
@@ -498,9 +499,7 @@ Add the CUE configuration to manage the prometheus Helm Chart component.
```bash
mkdir -p projects/platform/components/prometheus
```
```txt
projects/platform/components/prometheus/prometheus.cue
touch projects/platform/components/prometheus/prometheus.cue
```
```cue showLineNumbers
package holos
@@ -527,8 +526,9 @@ the platform directory.
<Tabs groupId="FF5FF6C6-181D-4071-8BCF-5C8E0663C028">
<TabItem value="platform/prometheus.cue" label="Platform">
```txt
platform/prometheus.cue
```bash
mkdir -p platform
touch platform/prometheus.cue
```
```cue showLineNumbers
package holos
@@ -553,8 +553,8 @@ holos render platform ./platform
<TabItem value="output" label="Output">
```txt
cached prometheus 25.27.0
rendered prometheus for cluster local in 1.900449291s
rendered platform in 1.900581125s
rendered prometheus for cluster local in 1.600449291s
rendered platform in 1.600581125s
```
</TabItem>
<TabItem value="deploy/clusters/local/components/prometheus/prometheus.gen.yaml" label="prometheus.gen.yaml">
@@ -2041,9 +2041,7 @@ Add the CUE configuration to manage the blackbox Helm Chart component.
```bash
mkdir -p projects/platform/components/blackbox
```
```txt
projects/platform/components/blackbox/blackbox.cue
touch projects/platform/components/blackbox/blackbox.cue
```
```cue showLineNumbers
package holos
@@ -2070,8 +2068,9 @@ _Helm: #Helm & {
Register the blackbox chart with the platform by adding the following file to
the platform directory.
```txt
platform/blackbox.cue
```bash
mkdir -p platform
touch platform/blackbox.cue
```
```cue showLineNumbers
package holos
@@ -2292,9 +2291,10 @@ First for prometheus.
<Tabs groupId="5062EB93-F5AA-4038-9CF8-67A5ECA085FD">
<TabItem value="command" label="Command">
```bash
cue import -p holos -o- -l '_Helm: Values:' \
projects/platform/components/prometheus/vendor/25.27.0/prometheus/values.yaml \
> projects/platform/components/prometheus/values.cue
cue import --package holos \
--path '_Helm: Values:' \
--outfile projects/platform/components/prometheus/values.cue \
projects/platform/components/prometheus/vendor/25.27.0/prometheus/values.yaml
```
</TabItem>
<TabItem value="output" label="values.cue">
@@ -3648,9 +3648,10 @@ Then for blackbox.
<Tabs groupId="843D706B-5BE0-46FE-978F-EA17BC1AD932">
<TabItem value="command" label="Command">
```bash
cue import -p holos -o- -l '_Helm: Values:' \
projects/platform/components/blackbox/vendor/9.0.1/prometheus-blackbox-exporter/values.yaml \
> projects/platform/components/blackbox/values.cue
cue import --package holos \
--path '_Helm: Values:' \
--outfile projects/platform/components/blackbox/values.cue
projects/platform/components/blackbox/vendor/9.0.1/prometheus-blackbox-exporter/values.yaml
```
</TabItem>
<TabItem value="output" label="values.cue">
@@ -4168,12 +4169,8 @@ lock step.
<Tabs groupId="B3A011D0-2D13-4DA8-B963-92115E734085">
<TabItem value="command" label="Command">
```bash
git diff
```
</TabItem>
<TabItem value="output" label="Output" default>
```diff
patch -p1 <<EOF
--- a/projects/platform/components/blackbox/values.cue
+++ b/projects/platform/components/blackbox/values.cue
@@ -2,6 +2,9 @@ package holos
@@ -4186,15 +4183,15 @@ git diff
global: {
//# Global image registry to use if it needs to be overriden for some specific use cases (e.g local registries, custom images, ...)
//#
@@ -196,7 +196,7 @@ _Helm: {
annotations: {}
labels: {}
type: "ClusterIP"
- port: 9115
+ port: _blackbox.port
ipDualStack: {
enabled: false
ipFamilies: ["IPv6", "IPv4"]
@@ -193,7 +196,7 @@ _Helm: {
annotations: {}
labels: {}
type: "ClusterIP"
- port: 9115
+ port: _blackbox.port
ipDualStack: {
enabled: false
ipFamilies: ["IPv6", "IPv4"]
--- a/projects/platform/components/prometheus/values.cue
+++ b/projects/platform/components/prometheus/values.cue
@@ -1084,7 +1084,7 @@ _Helm: {
@@ -4206,6 +4203,13 @@ git diff
}, {
source_labels: ["__param_target"]
target_label: "instance"
EOF
```
</TabItem>
<TabItem value="output" label="Output" default>
```txt
patching file 'projects/platform/components/blackbox/values.cue'
patching file 'projects/platform/components/prometheus/values.cue'
```
</TabItem>
</Tabs>
@@ -4308,11 +4312,10 @@ git diff
- __address__
target_label: __param_target
- - replacement: blackbox
+ - replacement: blackbox:6115
+ - replacement: blackbox:9115
target_label: __address__
- source_labels:
- __param_target
```
</TabItem>
</Tabs>
@@ -4498,12 +4501,8 @@ render platform` command fails immediately with a clear validation error.
<Tabs groupId="BFCF4FCA-33EB-45D8-8D36-CDD80E54C819">
<TabItem value="command" label="Command">
```bash
git diff
```
</TabItem>
<TabItem value="output" label="Output">
```diff
patch -p1 <<EOF
--- a/projects/blackbox.schema.cue
+++ b/projects/blackbox.schema.cue
@@ -10,6 +10,6 @@ package holos
@@ -4514,7 +4513,12 @@ git diff
+ host: "this is not valid"
port: 6115
}
EOF
```
</TabItem>
<TabItem value="output" label="Output">
```txt
patching file 'projects/blackbox.schema.cue'
```
</TabItem>
</Tabs>
@@ -4539,6 +4543,13 @@ could not run: could not render component: exit status 1 at builder/v1alpha4/bui
![VS Code out of bound error](img/helm-editor-constraints.png)
Undo the invalid change.
```bash
git restore projects/blackbox.schema.cue
rm -f projects/blackbox.schema.cue.orig
```
### Httpbin Kustomization
We need to manage [httpbin] so we can achieve the goal of probing a simple
@@ -4556,10 +4567,7 @@ components.
<TabItem value="projects/platform/components/httpbin/httpbin.cue" label="Component">
```bash
mkdir -p projects/platform/components/httpbin
```
```txt
projects/platform/components/httpbin/httpbin.cue
touch projects/platform/components/httpbin/httpbin.cue
```
```cue showLineNumbers
package holos
@@ -4571,9 +4579,10 @@ _Kustomize.BuildPlan
// https://github.com/mccutchen/go-httpbin/blob/v2.15.0/kustomize/README.md
_Kustomize: #Kustomize & {
KustomizeConfig: Resources: "github.com/mccutchen/go-httpbin/kustomize": _
KustomizeConfig: Files: "resources.yaml": _
KustomizeConfig: Kustomization: {
commonLabels: "app.kubernetes.io/name": "httpbin"
images: [{name: "mccutchen/go-httpbin"}]
_patches: probe: {
target: kind: "Service"
target: name: "httpbin"
@@ -4586,6 +4595,55 @@ _Kustomize: #Kustomize & {
patches: [for x in _patches {x}]
}
}
```
</TabItem>
<TabItem value="projects/platform/components/httpbin/resources.yaml" label="resources.yaml">
Add a plain `resources.yaml` file containing resources for kustomize to process.
:::important
Holos knows this file is part of the BuildPlan from the `KustomizeConfig:
Files: "resources.yaml": _` line in the Component.
:::
```bash
mkdir -p projects/platform/components/httpbin
touch projects/platform/components/httpbin/resources.yaml
```
```yaml showLineNumbers
# https://github.com/mccutchen/go-httpbin/blob/v2.15.0/kustomize/resources.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
spec:
template:
spec:
containers:
- name: httpbin
image: mccutchen/go-httpbin
ports:
- name: http
containerPort: 8080
protocol: TCP
livenessProbe:
httpGet:
path: /status/200
port: http
readinessProbe:
httpGet:
path: /status/200
port: http
resources: {}
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
spec:
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
appProtocol: http
```
</TabItem>
</Tabs>
@@ -4595,7 +4653,8 @@ Register the component with the platform.
<Tabs groupId="CBD42BC2-38C3-46E2-9F4D-B21D8E909BAC">
<TabItem value="platform/httpbin.cue" label="Platform">
```txt
platform/httpbin.cue
mkdir -p platform
touch platform/httpbin.cue
```
```cue showLineNumbers
package holos
@@ -4765,6 +4824,7 @@ deployment.apps/httpbin created
Port forward to the prometheus web interface.
```bash
kubectl wait --for=condition=Available deployment/prometheus-server --timeout=300s
kubectl -n default port-forward svc/prometheus-server 8081:80
```

View File

Before

Width:  |  Height:  |  Size: 690 KiB

After

Width:  |  Height:  |  Size: 690 KiB

View File

Before

Width:  |  Height:  |  Size: 997 KiB

After

Width:  |  Height:  |  Size: 997 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

Before

Width:  |  Height:  |  Size: 287 KiB

After

Width:  |  Height:  |  Size: 287 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

Before

Width:  |  Height:  |  Size: 1009 KiB

After

Width:  |  Height:  |  Size: 1009 KiB

View File

Before

Width:  |  Height:  |  Size: 617 KiB

After

Width:  |  Height:  |  Size: 617 KiB

View File

Before

Width:  |  Height:  |  Size: 706 KiB

After

Width:  |  Height:  |  Size: 706 KiB

View File

Before

Width:  |  Height:  |  Size: 794 KiB

After

Width:  |  Height:  |  Size: 794 KiB

View File

Before

Width:  |  Height:  |  Size: 248 KiB

After

Width:  |  Height:  |  Size: 248 KiB

View File

Before

Width:  |  Height:  |  Size: 206 KiB

After

Width:  |  Height:  |  Size: 206 KiB

View File

@@ -72,7 +72,7 @@ go install github.com/holos-run/holos/cmd/holos@latest
</TabItem>
<TabItem value="output" label="Output">
```txt
go: downloading github.com/holos-run/holos v0.95.1
go: downloading github.com/holos-run/holos v0.97.2
```
</TabItem>
</Tabs>
@@ -138,12 +138,10 @@ workflow.
```cue showLineNumbers
package holos
#ArgoConfig: {
Enabled: true
// highlight-next-line
RepoURL: "https://github.com/holos-run/bank-of-holos"
_ArgoConfig: {
Enabled: true
RepoURL: "https://github.com/jeffmccune/bank-of-holos"
}
```
</TabItem>
</Tabs>
@@ -154,16 +152,17 @@ Change the RepoURL to the URL of your fork. For example:
<TabItem value="command" label="projects/argocd-config.cue">
```diff showLineNumbers
diff --git a/projects/argocd-config.cue b/projects/argocd-config.cue
index 5264f48..0214e99 100644
index 1291a31..ff3bbfb 100644
--- a/projects/argocd-config.cue
+++ b/projects/argocd-config.cue
@@ -2,5 +2,5 @@ package holos
#ArgoConfig: {
Enabled: true
- RepoURL: "https://github.com/holos-run/bank-of-holos"
+ RepoURL: "https://github.com/jeffmccune/bank-of-holos"
_ArgoConfig: {
Enabled: true
- RepoURL: "https://github.com/holos-run/bank-of-holos"
+ RepoURL: "https://github.com/jeffmccune/bank-of-holos"
}
```
</TabItem>
</Tabs>
@@ -228,38 +227,36 @@ git status
</TabItem>
<TabItem value="output" label="Output">
```txt
On branch main
Your branch is up to date with 'origin/main'.
On branch jeff/291-consistent-fields
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: deploy/clusters/workload/gitops/app-projects.gen.yaml
modified: deploy/clusters/workload/gitops/argocd-crds.gen.yaml
modified: deploy/clusters/workload/gitops/argocd.gen.yaml
modified: deploy/clusters/workload/gitops/bank-accounts-db.gen.yaml
modified: deploy/clusters/workload/gitops/bank-backend-config.gen.yaml
modified: deploy/clusters/workload/gitops/bank-balance-reader.gen.yaml
modified: deploy/clusters/workload/gitops/bank-contacts.gen.yaml
modified: deploy/clusters/workload/gitops/bank-frontend.gen.yaml
modified: deploy/clusters/workload/gitops/bank-ledger-db.gen.yaml
modified: deploy/clusters/workload/gitops/bank-ledger-writer.gen.yaml
modified: deploy/clusters/workload/gitops/bank-secrets.gen.yaml
modified: deploy/clusters/workload/gitops/bank-transaction-history.gen.yaml
modified: deploy/clusters/workload/gitops/bank-userservice.gen.yaml
modified: deploy/clusters/workload/gitops/cert-manager.gen.yaml
modified: deploy/clusters/workload/gitops/external-secrets-crds.gen.yaml
modified: deploy/clusters/workload/gitops/external-secrets.gen.yaml
modified: deploy/clusters/workload/gitops/gateway-api.gen.yaml
modified: deploy/clusters/workload/gitops/httproutes.gen.yaml
modified: deploy/clusters/workload/gitops/istio-base.gen.yaml
modified: deploy/clusters/workload/gitops/istio-cni.gen.yaml
modified: deploy/clusters/workload/gitops/istio-gateway.gen.yaml
modified: deploy/clusters/workload/gitops/istio-ztunnel.gen.yaml
modified: deploy/clusters/workload/gitops/istiod.gen.yaml
modified: deploy/clusters/workload/gitops/local-ca.gen.yaml
modified: deploy/clusters/workload/gitops/namespaces.gen.yaml
modified: projects/argocd-config.cue
modified: deploy/clusters/local/gitops/app-projects.gen.yaml
modified: deploy/clusters/local/gitops/argocd-crds.gen.yaml
modified: deploy/clusters/local/gitops/argocd.gen.yaml
modified: deploy/clusters/local/gitops/bank-accounts-db.gen.yaml
modified: deploy/clusters/local/gitops/bank-backend-config.gen.yaml
modified: deploy/clusters/local/gitops/bank-balance-reader.gen.yaml
modified: deploy/clusters/local/gitops/bank-contacts.gen.yaml
modified: deploy/clusters/local/gitops/bank-frontend.gen.yaml
modified: deploy/clusters/local/gitops/bank-ledger-db.gen.yaml
modified: deploy/clusters/local/gitops/bank-ledger-writer.gen.yaml
modified: deploy/clusters/local/gitops/bank-secrets.gen.yaml
modified: deploy/clusters/local/gitops/bank-transaction-history.gen.yaml
modified: deploy/clusters/local/gitops/bank-userservice.gen.yaml
modified: deploy/clusters/local/gitops/cert-manager.gen.yaml
modified: deploy/clusters/local/gitops/external-secrets-crds.gen.yaml
modified: deploy/clusters/local/gitops/external-secrets.gen.yaml
modified: deploy/clusters/local/gitops/gateway-api.gen.yaml
modified: deploy/clusters/local/gitops/httproutes.gen.yaml
modified: deploy/clusters/local/gitops/istio-base.gen.yaml
modified: deploy/clusters/local/gitops/istio-cni.gen.yaml
modified: deploy/clusters/local/gitops/istio-gateway.gen.yaml
modified: deploy/clusters/local/gitops/istio-ztunnel.gen.yaml
modified: deploy/clusters/local/gitops/istiod.gen.yaml
modified: deploy/clusters/local/gitops/local-ca.gen.yaml
modified: deploy/clusters/local/gitops/namespaces.gen.yaml
modified: projects/argocd-config.cue
no changes added to commit (use "git add" and/or "git commit -a")
```
@@ -272,22 +269,23 @@ the changed `spec.source.repoURL` field.
<Tabs groupId="665E5402-FB42-4975-B654-3922EE73EE07">
<TabItem value="command" label="Command">
```bash
git diff deploy/clusters/workload/gitops/bank-frontend.gen.yaml
git diff deploy/clusters/local/gitops/bank-frontend.gen.yaml
```
</TabItem>
<TabItem value="output" label="Output">
```diff showLineNumbers
diff --git a/deploy/clusters/workload/gitops/bank-frontend.gen.yaml b/deploy/clusters/workload/gitops/bank-frontend.gen.yaml
index 3a3dec0..22e21bb 100644
--- a/deploy/clusters/workload/gitops/bank-frontend.gen.yaml
+++ b/deploy/clusters/workload/gitops/bank-frontend.gen.yaml
diff --git a/deploy/clusters/local/gitops/bank-frontend.gen.yaml b/deploy/clusters/local/gitops/bank-frontend.gen.yaml
index e07d5ea..14cc71c 100644
--- a/deploy/clusters/local/gitops/bank-frontend.gen.yaml
+++ b/deploy/clusters/local/gitops/bank-frontend.gen.yaml
@@ -11,5 +11,5 @@ spec:
project: default
project: bank-frontend
source:
path: deploy/clusters/workload/components/bank-frontend
path: deploy/clusters/local/components/bank-frontend
- repoURL: https://github.com/holos-run/bank-of-holos
+ repoURL: https://github.com/jeffmccune/bank-of-holos
targetRevision: main
```
</TabItem>
</Tabs>
@@ -328,35 +326,34 @@ like this.
```mermaid
---
title: Figure 1 - Render Pipeline
title: Figure 1 - v1alpha4 Rendered Manifest Pipeline
---
graph LR
PS[<a href="/docs/api/author/v1alpha3/#Platform">Platform</a>]
HC[<a href="/docs/api/author/v1alpha3/#ComponentFields">Components</a>]
BP[<a href="/docs/api/core/v1alpha3#BuildPlan">BuildPlan</a>]
Platform[<a href="/docs/api/author/v1alpha4/#Platform">Platform</a>]
Component[<a href="/docs/api/author/v1alpha4/#ComponentConfig">Components</a>]
H[<a href="/docs/api/author/v1alpha3/#Helm">Helm</a>]
K[<a href="/docs/api/author/v1alpha3/#Kustomize">Kustomize</a>]
O[<a href="/docs/api/author/v1alpha3/#Kubernetes">Kubernetes</a>]
Helm[<a href="/docs/api/author/v1alpha4/#Helm">Helm</a>]
Kustomize[<a href="/docs/api/author/v1alpha4/#Kustomize">Kustomize</a>]
Kubernetes[<a href="/docs/api/author/v1alpha4/#Kubernetes">Kubernetes</a>]
P[<a href="/docs/api/core/v1alpha3#Kustomize">Kustomize</a>]
Y[Kubernetes <br/>Resources]
G[GitOps <br/>Resource]
FS[Local Files]
BuildPlan[<a href="/docs/api/core/v1alpha4/#buildplan">BuildPlan</a>]
C[Kube API Server]
ResourcesArtifact[<a href="/docs/api/core/v1alpha4/#artifact">Resources<br/>Artifact</a>]
GitOpsArtifact[<a href="/docs/api/core/v1alpha4/#artifact">GitOps<br/>Artifact</a>]
PS --> HC --> BP
BP --> H --> P
BP --> K --> P
BP --> O --> P
Generators[<a href="/docs/api/core/v1alpha4/#generators">Generators</a>]
Transformers[<a href="/docs/api/core/v1alpha4/#transformer">Transformers</a>]
Files[Manifest<br/>Files]
P --> Y --> FS
P --> G --> FS
Platform --> Component
Component --> Helm --> BuildPlan
Component --> Kubernetes --> BuildPlan
Component --> Kustomize --> BuildPlan
FS --> ArgoCD --> C
FS --> Flux --> C
FS --> kubectl --> C
BuildPlan --> ResourcesArtifact --> Generators
BuildPlan --> GitOpsArtifact --> Generators
Generators --> Transformers --> Files
```
### Why do we render the platform? {#why-render-the-platform}
@@ -407,14 +404,14 @@ files for now, they behave the same as these two.
package holos
// Manage the Component on every Cluster in the Platform
for Fleet in #Fleets {
for Fleet in _Fleets {
for Cluster in Fleet.clusters {
#Platform: Components: "\(Cluster.name):argocd-crds": {
_Platform: Components: "\(Cluster.name):argocd-crds": {
name: "argocd-crds"
component: "projects/platform/components/argocd/crds"
cluster: Cluster.name
}
#Platform: Components: "\(Cluster.name):argocd": {
_Platform: Components: "\(Cluster.name):argocd": {
name: "argocd"
component: "projects/platform/components/argocd/argocd"
cluster: Cluster.name
@@ -428,14 +425,14 @@ for Fleet in #Fleets {
package holos
// Manage the component on every cluster in the platform
for Fleet in #Fleets {
for Fleet in _Fleets {
for Cluster in Fleet.clusters {
#Platform: Components: "\(Cluster.name):external-secrets-crds": {
_Platform: Components: "\(Cluster.name):external-secrets-crds": {
name: "external-secrets-crds"
component: "projects/platform/components/external-secrets-crds"
cluster: Cluster.name
}
#Platform: Components: "\(Cluster.name):external-secrets": {
_Platform: Components: "\(Cluster.name):external-secrets": {
name: "external-secrets"
component: "projects/platform/components/external-secrets"
cluster: Cluster.name
@@ -488,7 +485,7 @@ understand how the rest of the CUE files in the platform directory behave.
:::tip
Each CUE file in the platform directory adds components to the
`#Platform.Components` struct.
`_Platform.Components` struct.
:::
The final file in the directory is responsible for producing the Platform spec.
@@ -501,17 +498,17 @@ package holos
import api "github.com/holos-run/holos/api/author/v1alpha4"
#Platform: api.#Platform & {
Name: "guide"
_Platform: api.#Platform & {
Name: "default"
}
// Render a Platform resource for holos to process
#Platform.Resource
_Platform.Resource
```
</TabItem>
</Tabs>
This file provides the value of the `#Platform.Resource` field, the platform
This file provides the value of the `_Platform.Resource` field, the platform
spec, to `holos`.
Let's take a look at that Output value:
@@ -527,29 +524,84 @@ cue export --out yaml ./platform
kind: Platform
apiVersion: v1alpha4
metadata:
name: guide
name: default
spec:
components: # This is a trimmed list for readability.
components:
- name: httproutes
component: projects/platform/components/httproutes
cluster: local
- name: istio-gateway
component: projects/platform/components/istio/gateway
cluster: local
- name: istio-base
component: projects/platform/components/istio/base
cluster: local
- name: istiod
component: projects/platform/components/istio/istiod
cluster: local
- name: istio-cni
component: projects/platform/components/istio/cni
cluster: local
- name: istio-ztunnel
component: projects/platform/components/istio/ztunnel
cluster: local
- name: app-projects
component: projects/platform/components/app-projects
cluster: local
- name: argocd-crds
component: projects/platform/components/argocd/crds
cluster: local
- name: argocd
component: projects/platform/components/argocd/argocd
cluster: local
- name: bank-secrets
component: projects/bank-of-holos/security/components/bank-secrets
cluster: workload
model: {}
cluster: local
- name: bank-frontend
component: projects/bank-of-holos/frontend/components/bank-frontend
cluster: workload
model: {}
cluster: local
- name: bank-backend-config
component: projects/bank-of-holos/backend/components/bank-backend-config
cluster: workload
model: {}
cluster: local
- name: bank-accounts-db
component: projects/bank-of-holos/backend/components/bank-accounts-db
cluster: workload
model: {}
cluster: local
- name: bank-userservice
component: projects/bank-of-holos/backend/components/bank-userservice
cluster: workload
model: {}
cluster: local
- name: bank-ledger-db
component: projects/bank-of-holos/backend/components/bank-ledger-db
cluster: local
- name: bank-ledger-writer
component: projects/bank-of-holos/backend/components/bank-ledger-writer
cluster: local
- name: bank-balance-reader
component: projects/bank-of-holos/backend/components/bank-balance-reader
cluster: local
- name: bank-transaction-history
component: projects/bank-of-holos/backend/components/bank-transaction-history
cluster: local
- name: bank-contacts
component: projects/bank-of-holos/backend/components/bank-contacts
cluster: local
- name: cert-manager
component: projects/platform/components/cert-manager
cluster: local
- name: external-secrets-crds
component: projects/platform/components/external-secrets-crds
cluster: local
- name: external-secrets
component: projects/platform/components/external-secrets
cluster: local
- name: gateway-api
component: projects/platform/components/gateway-api
cluster: local
- name: local-ca
component: projects/platform/components/local-ca
cluster: local
- name: namespaces
component: projects/platform/components/namespaces
cluster: local
```
</TabItem>
</Tabs>
@@ -600,23 +652,26 @@ start working with the cert-manager component.
package holos
// Produce a helm chart build plan.
(#Helm & Chart).BuildPlan
_HelmChart.BuildPlan
let Chart = {
_HelmChart: #Helm & {
Name: "cert-manager"
Namespace: #CertManager.Namespace
Namespace: _CertManager.Namespace
Chart: {
version: #CertManager.Version
version: _CertManager.Version
repository: {
name: "jetstack"
url: "https://charts.jetstack.io"
}
}
EnableHooks: true
Values: {
installCRDs: true
Values: #Values & {
crds: enabled: true
startupapicheck: enabled: false
// https://github.com/cert-manager/cert-manager/issues/6716
global: leaderElection: namespace: Namespace
}
}
```
@@ -625,14 +680,19 @@ let Chart = {
```cue showLineNumbers
package holos
// Platform wide configuration
#CertManager: {
Version: "1.15.3"
Version: string
Namespace: string
}
// Platform wide configuration
_CertManager: {
Version: "v1.16.1"
Namespace: "cert-manager"
}
// Register the namespace
#Namespaces: (#CertManager.Namespace): _
_Namespaces: (_CertManager.Namespace): _
```
</TabItem>
</Tabs>
@@ -640,15 +700,13 @@ package holos
This file introduces a few new concepts.
1. Line 4 indicates this component produces a BuildPlan that wraps a Helm Chart.
2. On line 6 `let` binds a name to an expression for the current scope. The
current file in this case.
3. Notice Chart is referenced on line 4 before it's bound on line 6. **Order is
irrelevant in CUE**. Complex changes are simpler and easier when we don't have
to think about order.
4. The chart version and namespace are defined in a different file closer to the
root, `projects/cert-manager.cue`
5. We define Helm values in CUE to take advantage of strong type checking and
manage multiple Helm charts consistently with platform wide values.
2. Notice `_HelmChart` is referenced on line 4 before it's defined on line 6.
**Order is irrelevant in CUE**. Complex changes are simpler and easier when we
don't have to think about order.
3. Line 8 and 11: The chart version and namespace are defined in a different
file closer to the root, `projects/cert-manager.cue`
4. Line 19: Helm values are defined in CUE to take advantage of strong type
checking and manage multiple Helm charts consistently with the same values.
Let's take a look at the BuildPlan that results from the CUE configuration
described above.
@@ -675,16 +733,280 @@ spec:
helm:
chart:
name: cert-manager
version: 1.15.3
version: v1.16.1
release: cert-manager
repository:
name: jetstack
url: https://charts.jetstack.io
values:
installCRDs: true
global:
imagePullSecrets: []
commonLabels: {}
priorityClassName: ""
rbac:
create: true
aggregateClusterRoles: true
podSecurityPolicy:
enabled: false
useAppArmor: true
logLevel: 2
leaderElection:
namespace: cert-manager
installCRDs: false
crds:
enabled: true
keep: true
replicaCount: 1
strategy: {}
podDisruptionBudget:
enabled: false
featureGates: ""
maxConcurrentChallenges: 60
image:
repository: quay.io/jetstack/cert-manager-controller
pullPolicy: IfNotPresent
clusterResourceNamespace: ""
namespace: ""
serviceAccount:
create: true
automountServiceAccountToken: true
enableCertificateOwnerRef: false
config: {}
dns01RecursiveNameservers: ""
dns01RecursiveNameserversOnly: false
disableAutoApproval: false
approveSignerNames:
- issuers.cert-manager.io/*
- clusterissuers.cert-manager.io/*
extraArgs: []
extraEnv: []
resources: {}
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containerSecurityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
volumes: []
volumeMounts: []
podLabels: {}
hostAliases: []
nodeSelector:
kubernetes.io/os: linux
ingressShim: {}
affinity: {}
tolerations: []
topologySpreadConstraints: []
livenessProbe:
enabled: true
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 15
successThreshold: 1
failureThreshold: 8
enableServiceLinks: false
prometheus:
enabled: true
servicemonitor:
enabled: false
prometheusInstance: default
targetPort: 9402
path: /metrics
interval: 60s
scrapeTimeout: 30s
labels: {}
annotations: {}
honorLabels: false
endpointAdditionalProperties: {}
podmonitor:
enabled: false
prometheusInstance: default
path: /metrics
interval: 60s
scrapeTimeout: 30s
labels: {}
annotations: {}
honorLabels: false
endpointAdditionalProperties: {}
webhook:
replicaCount: 1
timeoutSeconds: 30
config: {}
strategy: {}
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containerSecurityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
podDisruptionBudget:
enabled: false
validatingWebhookConfiguration:
namespaceSelector:
matchExpressions:
- key: cert-manager.io/disable-validation
operator: NotIn
values:
- "true"
mutatingWebhookConfiguration:
namespaceSelector: {}
extraArgs: []
extraEnv: []
featureGates: ""
resources: {}
livenessProbe:
failureThreshold: 3
initialDelaySeconds: 60
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
readinessProbe:
failureThreshold: 3
initialDelaySeconds: 5
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 1
nodeSelector:
kubernetes.io/os: linux
affinity: {}
tolerations: []
topologySpreadConstraints: []
podLabels: {}
serviceLabels: {}
serviceIPFamilyPolicy: ""
serviceIPFamilies: []
image:
repository: quay.io/jetstack/cert-manager-webhook
pullPolicy: IfNotPresent
serviceAccount:
create: true
automountServiceAccountToken: true
securePort: 10250
hostNetwork: false
serviceType: ClusterIP
url: {}
networkPolicy:
enabled: false
ingress:
- from:
- ipBlock:
cidr: 0.0.0.0/0
egress:
- ports:
- port: 80
protocol: TCP
- port: 443
protocol: TCP
- port: 53
protocol: TCP
- port: 53
protocol: UDP
- port: 6443
protocol: TCP
to:
- ipBlock:
cidr: 0.0.0.0/0
volumes: []
volumeMounts: []
enableServiceLinks: false
cainjector:
enabled: true
replicaCount: 1
config: {}
strategy: {}
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containerSecurityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
podDisruptionBudget:
enabled: false
extraArgs: []
extraEnv: []
featureGates: ""
resources: {}
nodeSelector:
kubernetes.io/os: linux
affinity: {}
tolerations: []
topologySpreadConstraints: []
podLabels: {}
serviceLabels: {}
image:
repository: quay.io/jetstack/cert-manager-cainjector
pullPolicy: IfNotPresent
serviceAccount:
create: true
automountServiceAccountToken: true
volumes: []
volumeMounts: []
enableServiceLinks: false
acmesolver:
image:
repository: quay.io/jetstack/cert-manager-acmesolver
pullPolicy: IfNotPresent
startupapicheck:
enabled: false
enableHooks: false
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containerSecurityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
timeout: 1m
backoffLimit: 4
jobAnnotations:
helm.sh/hook: post-install
helm.sh/hook-weight: "1"
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
extraArgs:
- -v
extraEnv: []
resources: {}
nodeSelector:
kubernetes.io/os: linux
affinity: {}
tolerations: []
podLabels: {}
image:
repository: quay.io/jetstack/cert-manager-startupapicheck
pullPolicy: IfNotPresent
rbac:
annotations:
helm.sh/hook: post-install
helm.sh/hook-weight: "-5"
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
serviceAccount:
create: true
annotations:
helm.sh/hook: post-install
helm.sh/hook-weight: "-5"
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
automountServiceAccountToken: true
volumes: []
volumeMounts: []
enableServiceLinks: false
extraObjects: []
creator: helm
enabled: true
enableHooks: true
namespace: cert-manager
- kind: Resources
output: resources.gen.yaml
@@ -711,6 +1033,7 @@ spec:
namespace: cert-manager
commonLabels:
holos.run/component.name: cert-manager
argocd.argoproj.io/instance: cert-manager
resources:
- combined.gen.yaml
- artifact: clusters/no-cluster/gitops/cert-manager.gen.yaml
@@ -728,7 +1051,7 @@ spec:
spec:
destination:
server: https://kubernetes.default.svc
project: default
project: platform
source:
path: deploy/clusters/no-cluster/components/cert-manager
repoURL: https://github.com/jeffmccune/bank-of-holos

View File

Before

Width:  |  Height:  |  Size: 934 KiB

After

Width:  |  Height:  |  Size: 934 KiB

View File

Before

Width:  |  Height:  |  Size: 703 KiB

After

Width:  |  Height:  |  Size: 703 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

Before

Width:  |  Height:  |  Size: 1014 KiB

After

Width:  |  Height:  |  Size: 1014 KiB

View File

Before

Width:  |  Height:  |  Size: 728 KiB

After

Width:  |  Height:  |  Size: 728 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

Before

Width:  |  Height:  |  Size: 1014 KiB

After

Width:  |  Height:  |  Size: 1014 KiB

View File

Before

Width:  |  Height:  |  Size: 854 KiB

After

Width:  |  Height:  |  Size: 854 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

Before

Width:  |  Height:  |  Size: 624 KiB

After

Width:  |  Height:  |  Size: 624 KiB

View File

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 116 KiB

View File

@@ -0,0 +1,52 @@
---
description: Introduction
---
# Introduction
Welcome to Holos. Holos is an open source tool to manage software development
platforms safely, easily, and consistently. We built Holos to help engineering
teams work more efficiently together by empowering them to build golden paths
and paved roads for other teams to leverage for quicker delivery.
## Documentation
- [Guides] are organized into example use-cases of how Holos helps engineering
teams at the fictional Bank of Holos deliver business value on the bank's
platform.
- The [API Reference] is a technical reference for when you're writing CUE code to define your platform.
## Backstory
At [Open Infrastructure Services], we've each helped dozens of companies build and operate their software development platforms. During the U.S. presidential election just before the pandemic, our second-largest client, Twitter, experienced a global outage that lasted nearly a full day. We were managing their production configuration system, allowing the core infrastructure team to focus on business-critical objectives. This gave us a front-row seat to the incident.
A close friend and engineer on the team made a trivial one-line change to the firewall configuration. Less than 30 minutes later, everything was down. That change, which passed code review, caused the host firewall to revert to its default state on hundreds of thousands of servers, blocking all connections globally—except for SSH, thankfully. Even a Presidential candidate complained loudly.
This incident forced us to reconsider key issues with Twitter's platform:
1. **Lack of Visibility** - Engineers couldn't foresee the impact of even a small change, making it difficult to assess risks.
2. **Large Blast Radius** - Small changes affected the entire global fleet in under 30 minutes. There was no way to limit the impact of a single change.
3. **Incomplete Tooling** - The right processes were in place, but the tooling didn't fully support them. The change was tested and reviewed, but critical information wasn't surfaced in time.
Over the next few years, we built features to address these issues. Meanwhile, I began exploring how these solutions could work in the Kubernetes and cloud-native space.
As Google Cloud partners, we worked with large customers to understand how they built their platforms on Kubernetes. During the pandemic, we built a platform using CNCF projects like ArgoCD, Prometheus Stack, Istio, Cert Manager, and External Secrets Operator, integrating them into a cohesive platform. We started with upstream recommendations—primarily Helm charts—and wrote scripts to integrate each piece into the platform. For example, we passed Helm outputs to Kustomize to add labels or fix bugs, and wrote umbrella charts to add Ingress, HTTPRoute, and ExternalSecret resources.
These scripts served as necessary glue to hold everything together but became difficult to manage across multiple environments, regions, and cloud providers. YAML templates and nested loops created friction, making them hard to troubleshoot. The scripts themselves made it difficult to see what was happening and to fix issues affecting the entire platform.
Still, the scripts had a key advantage: they produced fully rendered manifests in plain text, committed to version control, and applied via ArgoCD. This clarity made troubleshooting easier and reduced errors in production.
Despite the makeshift nature of the scripts, I kept thinking about the "[Why are we templating YAML]?" post on Hacker News. I wanted to replace our scripts and charts with something more robust and easier to maintain—something that addressed Twitter's issues head-on.
I rewrote our scripts and charts using CUE and Go, replacing the glue layer. The result is **Holos**—a tool designed to complement Helm, Kustomize, and Jsonnet, making it easier and safer to define golden paths and paved roads without bespoke scripts or templates.
Thanks for reading. Take Holos for a spin on your local machine with our [Quickstart] guide.
[Guides]: /docs/guides/
[API Reference]: /docs/api/
[Quickstart]: /docs/quickstart/
[CUE]: https://cuelang.org/
[Author API]: /docs/api/author/
[Core API]: /docs/api/core/
[Open Infrastructure Services]: https://openinfrastructure.co/
[Why are we templating YAML]: https://hn.algolia.com/?dateRange=all&page=0&prefix=false&query=https%3A%2F%2Fleebriggs.co.uk%2Fblog%2F2019%2F02%2F07%2Fwhy-are-we-templating-yaml&sort=byDate&type=story

View File

@@ -0,0 +1,690 @@
---
slug: technical-overview
title: Technical Overview
description: Learn how Holos makes it easier for platform teams to integrate software into their platform.
---
<head>
<meta property="og:title" content="Technical Overview | Holos" />
<meta property="og:image" content="/img/cards/technical-overview.png" />
</head>
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import Admonition from '@theme/Admonition';
## Overview
Holos makes it easier for platform teams to integrate software into their
platform. Existing tools in the Kubernetes ecosystem are narrowly focused on
application management. Holos takes a holistic approach, focusing on the broad
integration layer where applications are joined into the platform. Holos
improves cross team collaboration through well defined, typed structures at the
integration layer. These definitions provide golden paths for other teams to
easily integrate their own services into the platform.
<!-- truncate -->
## The Problem
Platform teams need to develop and maintain significant glue code to integrate
Helm charts and YAML manifests into a platform built on Kubernetes. This glue
code is often implemented with home grown umbrella charts and scripts.
Maintaining these charts and scripts takes time and effort that could otherwise
be spent improving the platform. The need for each organization to develop and
maintain this glue code indicates a gap in the Kubernetes ecosystem. Holos is a
Go command line tool leveraging [CUE] to fill this gap.
## Key Features
1. Holos enables teams to provide simple definitions for other teams to use as golden paths.
2. Define integrations in [CUE] with strong type checking. No more text templates or bash scripts.
3. Simplify complex integration. Order does not matter. Validation is early and quick.
4. Reuse your existing Helm charts and Kustomize bases.
5. Implement the [rendered manifests pattern]. Changes are clearly visible platform-wide.
6. Fully render manifests to plain files. Use your existing GitOps tools and processes.
7. Post-process with Kustomize from CUE instead of plain text files. Customize your Kustomizations.
8. Mix in resources to Helm charts and Kustomize bases, for example ExternalSecrets.
9. Render all of Helm, Kustomize, CUE, JSON, and YAML consistently with the same process.
## Rendering Pipeline
```mermaid
---
title: Figure 1 - v1alpha4 Rendered Manifest Pipeline
---
graph LR
Platform[<a href="/docs/api/author/v1alpha4/#Platform">Platform</a>]
Component[<a href="/docs/api/author/v1alpha4/#ComponentConfig">Components</a>]
Helm[<a href="/docs/api/author/v1alpha4/#Helm">Helm</a>]
Kustomize[<a href="/docs/api/author/v1alpha4/#Kustomize">Kustomize</a>]
Kubernetes[<a href="/docs/api/author/v1alpha4/#Kubernetes">Kubernetes</a>]
BuildPlan[<a href="/docs/api/core/v1alpha4/#buildplan">BuildPlan</a>]
ResourcesArtifact[<a href="/docs/api/core/v1alpha4/#artifact">Resources<br/>Artifact</a>]
GitOpsArtifact[<a href="/docs/api/core/v1alpha4/#artifact">GitOps<br/>Artifact</a>]
Generators[<a href="/docs/api/core/v1alpha4/#generators">Generators</a>]
Transformers[<a href="/docs/api/core/v1alpha4/#transformer">Transformers</a>]
Files[Manifest<br/>Files]
Platform --> Component
Component --> Helm --> BuildPlan
Component --> Kubernetes --> BuildPlan
Component --> Kustomize --> BuildPlan
BuildPlan --> ResourcesArtifact --> Generators
BuildPlan --> GitOpsArtifact --> Generators
Generators --> Transformers --> Files
```
## Use Case
One of the development teams at the fictional Bank of Holos wants to deploy a
simple web app for an experimental project they're working on.
The platform team at the bank wants to build a simple golden path for teams to
provision projects consistently and easily in compliance with the bank's
policies.
### Platform Team
The platform team builds a golden path for development teams to register their
project with the platform. In compliance with bank policy, the platform team
needs to manage important security resources for each new project. All of these
resources can be derived from only 3 pieces of information.
1. The name of the project the dev team is working on.
2. The name of the team who currently owns the project.
3. The services, if any, the project is exposing.
The platform team defines a structure for the dev team to register this
information. This structure provides the golden path for the dev team.
The development team registers their experimental project, creatively named
"experiment" by submitting a pull request that contains this information.
<Tabs groupId="EB9C9AF1-F1AA-4189-B746-A5B8E3043F87">
<TabItem value="projects/experiment.cue" label="projects/experiment.cue">
```cue showLineNumbers
package holos
// The development team registers a project name.
_Projects: experiment: {
// The project owner must be named.
Owner: Name: "dev-team"
// Expose Service podinfo at https://podinfo.example.com
Hostnames: podinfo: Port: 9898
}
```
</TabItem>
</Tabs>
The platform team uses these three pieces of information to derive all of the
platform resources necessary to support the development team.
1. **Namespace** for the project resources.
2. **RoleBinding** to grant the dev team access to the project namespace.
3. **SecretStore** which implements the secret management policy for the bank.
4. **ReferenceGrant** to expose the project services through the Gateway API.
5. **HTTPRoutes** to expose the project services, if any.
6. **AppProject** to deploy and manage the project Applications with ArgoCD.
7. **Common Labels** to ensure every resource is labeled for resource accounting.
Rendering the platform generates fully rendered manifests for all of these
resources. These manifests are derived from the three pieces of information the
dev team provided.
Note the platform team must manage these resources across multiple namespaces.
The first four reside in the project namespace owned by the dev team. The
HTTPRoute and AppProject go into two namespaces managed by the platform team.
Holos makes it easier for the platform team to organize these resources into
different components with different owners.
:::important
Holos supports [CODEOWNERS] by clearly defining the teams responsible for each
platform component.
:::
<Tabs groupId="2E46EA1C-B118-44BF-AE20-752E8D1CE131">
<TabItem value="command" label="Command">
```bash
holos render platform ./platform
```
</TabItem>
<TabItem value="output" label="Output">
```txt
rendered httproutes for cluster overview in 177.823625ms
rendered app-projects for cluster overview in 180.946834ms
rendered projects for cluster overview in 181.98725ms
rendered namespaces for cluster overview in 182.30725ms
rendered platform in 182.31075ms
```
:::tip
If you'd like to try this for yourself, `cd` into [examples/tech-overview] and
render the platform.
:::
</TabItem>
</Tabs>
The fully rendered manifests are written into the `deploy/` directory organized
by cluster and component for GitOps.
<Tabs groupId="07FBE14E-E9EA-437B-9FA1-C6D8806524AD">
<TabItem value="deploy/clusters/local/components/namespaces/namespaces.gen.yaml" label="namespaces">
```
cat deploy/clusters/local/components/namespaces/namespaces.gen.yaml
```
```yaml showLineNumbers
apiVersion: v1
kind: Namespace
metadata:
labels:
argocd.argoproj.io/instance: namespaces
example.com/owner.email: sg-dev-team@example.com
example.com/owner.name: dev-team
example.com/project.name: experiment
holos.run/component.name: namespaces
kubernetes.io/metadata.name: experiment
name: experiment
```
</TabItem>
<TabItem value="deploy/clusters/local/components/projects/projects.gen.yaml" label="projects">
```
cat deploy/clusters/local/components/projects/projects.gen.yaml
```
```yaml showLineNumbers
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
argocd.argoproj.io/instance: projects
example.com/owner.email: sg-dev-team@example.com
example.com/owner.name: dev-team
example.com/project.name: experiment
holos.run/component.name: projects
name: admin
namespace: experiment
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: oidc:sg-dev-team@example.com
---
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
labels:
argocd.argoproj.io/instance: projects
example.com/owner.email: sg-dev-team@example.com
example.com/owner.name: dev-team
example.com/project.name: experiment
holos.run/component.name: projects
name: default
namespace: experiment
spec:
provider:
kubernetes:
auth:
token:
bearerToken:
key: token
name: eso-reader
remoteNamespace: experiment
server:
caBundle: LS0tLS1CRUd...QVRFLS0tLS0K
url: https://management.example.com:6443
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
labels:
argocd.argoproj.io/instance: projects
example.com/owner.email: sg-dev-team@example.com
example.com/owner.name: dev-team
example.com/project.name: experiment
holos.run/component.name: projects
name: istio-ingress
namespace: experiment
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: istio-ingress
to:
- group: ""
kind: Service
```
</TabItem>
<TabItem value="deploy/clusters/local/components/httproutes/httproutes.gen.yaml" label="httproutes">
```
cat deploy/clusters/local/components/httproutes/httproutes.gen.yaml
```
```yaml showLineNumbers
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
labels:
argocd.argoproj.io/instance: httproutes
example.com/owner.email: sg-dev-team@example.com
example.com/owner.name: dev-team
example.com/project.name: experiment
holos.run/component.name: httproutes
name: podinfo.example.com
namespace: istio-ingress
spec:
hostnames:
- podinfo.example.com
parentRefs:
- name: default
namespace: istio-ingress
rules:
- backendRefs:
- name: podinfo
namespace: experiment
port: 9898
matches:
- path:
type: PathPrefix
value: /
```
</TabItem>
</Tabs>
The rendered manifests are derived from the project registration information by
definitions implemented by the platform team. The [Author API] provides a
[Project] schema, but does not define an implementation. The platform team
implements the [Project] schema by adding a `_Projects` struct to manage
resources according to bank policies.
:::important
The Author API is intended as a convenient, ergonomic reference for component
authors. Definitions **are not** confined to the Author API.
:::
The following example shows how the platform team wrote the `_Projects`
definition to derive the Namespace from the project registration provided by the
dev team.
<Tabs groupId="5732727B-295E-46E1-B851-F8A1C5D7DF88">
<TabItem value="projects/platform/components/namespaces/namespaces.cue" label="Namespaces Component">
```txt
projects/platform/components/namespaces/namespaces.cue
```
```cue showLineNumbers
package holos
_Kubernetes: #Kubernetes & {
Name: "namespaces"
Resources: Namespace: _Namespaces
}
// Produce a kubernetes objects build plan.
_Kubernetes.BuildPlan
```
1. This is the namespaces component which manages a collection of Namespace resources derived from the project registration data shown in the second tab.
2. Line 5 manages a Namespace for each value of the `#Namespaces` struct. See the second tab for how the platform team defines this structure.
</TabItem>
<TabItem value="projects/projects.cue" label="Projects Definition">
```txt
projects/projects.cue
```
```cue showLineNumbers
package holos
import api "github.com/holos-run/holos/api/author/v1alpha4"
// Projects defines the structure other teams register with to manage project
// resources. The platform team defines the schema, development teams provide
// the values.
_Projects: api.#Projects & {
[NAME=string]: {
Name: NAME
// The platform team requires the development teams to indicate an owner of
// the project.
Owner: Name: string
// The default value for the owner email address is derived from the owner
// name, but development teams can provide a different email address if
// needed.
Owner: Email: string | *"sg-\(Owner.Name)@\(_Organization.Domain)"
// The platform team constrains the project to a single namespace.
Namespaces: close({(NAME): Name: NAME})
// The platform team constrains the exposed services to the project
// namespace.
Hostnames: [HOST=string]: {
Name: HOST
Namespace: Namespaces[NAME].Name
Service: HOST
Port: number | *80
}
CommonLabels: {
"\(_Organization.Domain)/project.name": Name
"\(_Organization.Domain)/owner.name": Owner.Name
"\(_Organization.Domain)/owner.email": Owner.Email
}
}
}
for Project in _Projects {
// Register project namespaces with the namespaces component.
_Namespaces: {
for Namespace in Project.Namespaces {
(Namespace.Name): metadata: labels: Project.CommonLabels
}
}
}
```
1. On lines 8-35 the platform team derives most fields from the project name (line 9), and the owner name (line 13). The purpose is to fill in the remaining fields defined by the Author API.
2. Line 13 The dev team is expected to provide a concrete owner name, indicated by the `string` value.
3. Line 17 The platform team provides a default value for the email address. The project team may define a different value.
4. Line 19 The Author API allows a project to have many namespaces. The platform team constrains this down to one namespace per project by closing the struct. The namespace name must be the same as the project name.
5. Lines 22-27 The platform team derives values for a Gateway API [BackendObjectReference] from the hostname provided by the project team. These values are used later to build HTTPRoutes to expose their service.
6. Lines 30-32 Common labels are derived to mix into resources associated with this project.
7. Lines 37-44 The platform team adds a namespace with common labels for each project to the struct we saw in the first tab.
</TabItem>
</Tabs>
The RoleBinding, SecretScore, and ReferenceGrant are managed in the
[projects](https://github.com/holos-run/bank-of-holos/blob/v0.4.1/examples/tech-overview/projects/platform/components/projects/projects.cue)
component, similar to the previous namespaces example.
The HTTPRoute is managed separately in the
[httproutes](https://github.com/holos-run/bank-of-holos/blob/v0.4.1/examples/tech-overview/projects/platform/components/httproutes/httproutes.cue)
component.
All components are registered with the platform in the
[platform](https://github.com/holos-run/bank-of-holos/tree/v0.4.1/examples/tech-overview/platform)
directory.
:::important
Multiple components, potentially owned by different teams, derive fully rendered
resources from the same three project values. The dev team added these three
values to the `_Projects` struct. The platform team wrote the definition to
integrate software according to bank policies. CUE powers this _unified_
platform configuration model.
:::
:::tip
Components map 1:1 to ArgoCD Applications or Flux Kustomizations.
:::
### Development Team
The development team has the platform resources they need, but they still need
to deploy their container. The development team submits a pull request adding
the following two files to deploy their existing Helm chart.
<Tabs groupId="7AD1DDA9-8001-462B-8BE0-D9410EB51233">
<TabItem value="projects/experiment/components/podinfo/podinfo.cue" label="Helm Component">
```txt
projects/experiment/components/podinfo/podinfo.cue
```
```cue showLineNumbers
package holos
// Produce a helm chart build plan.
_HelmChart.BuildPlan
_HelmChart: #Helm & {
Name: "podinfo"
Chart: {
version: "6.6.2"
repository: {
name: "podinfo"
url: "https://stefanprodan.github.io/podinfo"
}
}
}
```
This file represents a Helm chart component to add to the platform. The second
tab registers this component with the platform.
</TabItem>
<TabItem value="platform/podinfo.cue" label="Component Registration">
```
platform/podinfo.cue
```
```cue showLineNumbers
package holos
// Manage the component on every workload Cluster, but not management clusters.
for Cluster in _Fleets.workload.clusters {
_Platform: Components: "\(Cluster.name):podinfo": {
name: "podinfo"
component: "projects/experiment/components/podinfo"
cluster: Cluster.name
tags: project: "experiment"
}
}
```
This file registers the component with the platform. When the platform is
rendered the dev team's Helm chart will be rendered on all workload clusters
across the platform.
</TabItem>
</Tabs>
The project tag links the component to the same field of the `_Projects` struct.
:::important
You can add your own key=value tags in your platform specification to inject
values into components. This feature is useful to reuse one component path for
several environments or customers.
:::
Once the dev team's component is registered, rendering the platform will render
their component.
<Tabs groupId="1BAF7AD2-BBCD-4797-A3A6-55A626732845">
<TabItem value="command" label="Command">
```bash
holos render platform ./platform
```
</TabItem>
<TabItem value="output" label="Output">
```txt
rendered namespaces for cluster overview in 185.64075ms
rendered app-projects for cluster overview in 186.729292ms
rendered httproutes for cluster overview in 195.222833ms
rendered projects for cluster overview in 195.217125ms
// highlight-next-line
rendered podinfo for cluster overview in 195.830042ms
rendered platform in 195.90275ms
```
</TabItem>
</Tabs>
<Tabs groupId="77BF500B-105A-4AB4-A615-DEC19F501AE1">
<TabItem value="command" label="Command">
```bash
cat deploy/clusters/local/components/podinfo/podinfo.gen.yaml
```
</TabItem>
<TabItem value="output" label="Output">
```yaml showLineNumbers
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: podinfo
app.kubernetes.io/version: 6.6.2
argocd.argoproj.io/instance: podinfo
example.com/owner.email: sg-dev-team@example.com
example.com/owner.name: dev-team
example.com/project.name: experiment
helm.sh/chart: podinfo-6.6.2
holos.run/component.name: podinfo
name: podinfo
spec:
ports:
- name: http
port: 9898
protocol: TCP
targetPort: http
- name: grpc
port: 9999
protocol: TCP
targetPort: grpc
selector:
app.kubernetes.io/name: podinfo
argocd.argoproj.io/instance: podinfo
example.com/owner.email: sg-dev-team@example.com
example.com/owner.name: dev-team
example.com/project.name: experiment
holos.run/component.name: podinfo
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: podinfo
app.kubernetes.io/version: 6.6.2
argocd.argoproj.io/instance: podinfo
example.com/owner.email: sg-dev-team@example.com
example.com/owner.name: dev-team
example.com/project.name: experiment
helm.sh/chart: podinfo-6.6.2
holos.run/component.name: podinfo
name: podinfo
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: podinfo
argocd.argoproj.io/instance: podinfo
example.com/owner.email: sg-dev-team@example.com
example.com/owner.name: dev-team
example.com/project.name: experiment
holos.run/component.name: podinfo
strategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
annotations:
prometheus.io/port: "9898"
prometheus.io/scrape: "true"
labels:
app.kubernetes.io/name: podinfo
argocd.argoproj.io/instance: podinfo
example.com/owner.email: sg-dev-team@example.com
example.com/owner.name: dev-team
example.com/project.name: experiment
holos.run/component.name: podinfo
spec:
containers:
- command:
- ./podinfo
- --port=9898
- --cert-path=/data/cert
- --port-metrics=9797
- --grpc-port=9999
- --grpc-service-name=podinfo
- --level=info
- --random-delay=false
- --random-error=false
env:
- name: PODINFO_UI_COLOR
value: '#34577c'
image: ghcr.io/stefanprodan/podinfo:6.6.2
imagePullPolicy: IfNotPresent
livenessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/healthz
failureThreshold: 3
initialDelaySeconds: 1
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
name: podinfo
ports:
- containerPort: 9898
name: http
protocol: TCP
- containerPort: 9797
name: http-metrics
protocol: TCP
- containerPort: 9999
name: grpc
protocol: TCP
readinessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/readyz
failureThreshold: 3
initialDelaySeconds: 1
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
resources:
limits: null
requests:
cpu: 1m
memory: 16Mi
volumeMounts:
- mountPath: /data
name: data
terminationGracePeriodSeconds: 30
volumes:
- emptyDir: {}
name: data
```
</TabItem>
</Tabs>
Note the rendered Helm chart resources have consistent project labels. The
platform team added a constraint to the project so all Helm charts are post
processed with Kustomize to add these common labels. The platform team
accomplishes this by adding a constraint in the project directory. This can be
seen in
[schema.cue](https://github.com/holos-run/bank-of-holos/blob/v0.4.1/schema.cue#L35-L38)
where the platform team configures all component kinds for the platform.
We've covered how the platform team provides a golden path for development teams
to register their projects by defining a Projects structure. We've also covered
how the development team deploys their existing Helm chart onto the platform.
## Support & Resources
1. See our [Quickstart] guide to get started with Holos.
2. Check out our other [Guides] which cover specific topics.
3. Refer to the [Author API] when writing components.
4. Consider the [Core API] if you need to do something more advanced than the Author API supports.
5. Community and commercial [Support] is available.
6. [Discussions Forum](https://github.com/holos-run/holos/discussions)
[Support]: /docs/support/
[Guides]: /docs/guides/
[API Reference]: /docs/api/
[Quickstart]: /docs/quickstart/
[CUE]: https://cuelang.org/
[Author API]: /docs/api/author/
[Core API]: /docs/api/core/
[Open Infrastructure Services]: https://openinfrastructure.co/
[Why are we templating YAML]: https://hn.algolia.com/?dateRange=all&page=0&prefix=false&query=https%3A%2F%2Fleebriggs.co.uk%2Fblog%2F2019%2F02%2F07%2Fwhy-are-we-templating-yaml&sort=byDate&type=story
[Holos]: https://holos.run/
[Quickstart]: /docs/quickstart/
[rendered manifests pattern]: https://akuity.io/blog/the-rendered-manifests-pattern/
[examples/tech-overview]: https://github.com/holos-run/bank-of-holos/tree/v0.2.0/examples/tech-overview
[BackendObjectReference]: https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io%2fv1.BackendObjectReference
[CODEOWNERS]: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
[Project]: /docs/api/author/v1alpha3/#Project

View File

@@ -1,5 +1,3 @@
import DocCardList from '@theme/DocCardList';
# Author Schema
# Author API
<DocCardList />
v1alpha5

View File

@@ -1,5 +1,3 @@
import DocCardList from '@theme/DocCardList';
# Core Schema
# Core API
<DocCardList />
v1alpha5

15
doc/md/topics.mdx Normal file
View File

@@ -0,0 +1,15 @@
---
slug: /topics
title: Topics
description: Stand alone topics that often come up when using Holos.
---
import DocCardList from '@theme/DocCardList';
# Topics
This section has self-contained articles related to various topics that come up
when writing platform configuration code with Holos.
---
<DocCardList />

View File

@@ -0,0 +1 @@
# Multi Cluster

View File

View File

View File

@@ -0,0 +1,272 @@
---
description: Build a local Cluster to use with these guides.
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import Admonition from '@theme/Admonition';
# Local Cluster
In this guide we'll set up a local k3d cluster to apply and explore the
configuration described in our other guides. After completing this guide you'll
have a standard Kubernetes API server with proper DNS and TLS certificates.
You'll be able to easily reset the cluster to a known good state to iterate on
your own Platform.
## Reset the Cluster
If you've already followed this guide, reset the cluster by running the
following commands. Skip this section if you're creating a cluster for the
first time.
First, delete the cluster.
<Tabs groupId="k3d-cluster-delete">
<TabItem value="command" label="Command">
```bash
k3d cluster delete workload
```
</TabItem>
<TabItem value="output" label="Output">
```txt showLineNumbers
INFO[0000] Deleting cluster 'workload'
INFO[0000] Deleting cluster network 'k3d-workload'
INFO[0000] Deleting 1 attached volumes...
INFO[0000] Removing cluster details from default kubeconfig...
INFO[0000] Removing standalone kubeconfig file (if there is one)...
INFO[0000] Successfully deleted cluster workload!
```
</TabItem>
</Tabs>
Then create the cluster again.
<Tabs groupId="k3d-cluster-create">
<TabItem value="command" label="Command">
```bash
k3d cluster create workload \
--registry-use k3d-registry.holos.localhost:5100 \
--port "443:443@loadbalancer" \
--k3s-arg "--disable=traefik@server:0"
```
</TabItem>
<TabItem value="output" label="Output">
```txt showLineNumbers
INFO[0000] portmapping '443:443' targets the loadbalancer: defaulting to [servers:*:proxy agents:*:proxy]
INFO[0000] Prep: Network
INFO[0000] Created network 'k3d-workload'
INFO[0000] Created image volume k3d-workload-images
INFO[0000] Starting new tools node...
INFO[0000] Starting node 'k3d-workload-tools'
INFO[0001] Creating node 'k3d-workload-server-0'
INFO[0001] Creating LoadBalancer 'k3d-workload-serverlb'
INFO[0001] Using the k3d-tools node to gather environment information
INFO[0001] HostIP: using network gateway 172.17.0.1 address
INFO[0001] Starting cluster 'workload'
INFO[0001] Starting servers...
INFO[0001] Starting node 'k3d-workload-server-0'
INFO[0003] All agents already running.
INFO[0003] Starting helpers...
INFO[0003] Starting node 'k3d-workload-serverlb'
INFO[0009] Injecting records for hostAliases (incl. host.k3d.internal) and for 3 network members into CoreDNS configmap...
INFO[0012] Cluster 'workload' created successfully!
INFO[0012] You can now use it like this:
kubectl cluster-info
```
</TabItem>
</Tabs>
Finally, add your trusted certificate authority.
<Tabs groupId="apply-local-ca">
<TabItem value="command" label="Command">
```bash
kubectl apply --server-side=true -f "$(mkcert -CAROOT)/namespace.yaml"
kubectl apply --server-side=true -n cert-manager -f "$(mkcert -CAROOT)/local-ca.yaml"
```
</TabItem>
<TabItem value="output" label="Output">
```txt showLineNumbers
namespace/cert-manager serverside-applied
secret/local-ca serverside-applied
```
</TabItem>
</Tabs>
You're back to the same state as the first time you completed this guide.
## What you'll need {#requirements}
You'll need the following tools installed to complete this guide.
1. [holos](/docs/install) - to build the platform.
2. [helm](https://helm.sh/docs/intro/install/) - to render Holos components that wrap upstream Helm charts.
3. [k3d](https://k3d.io/#installation) - to provide a k8s api server.
4. [OrbStack](https://docs.orbstack.dev/install) or [Docker](https://docs.docker.com/get-docker/) - to use k3d.
5. [kubectl](https://kubernetes.io/docs/tasks/tools/) - to interact with the k8s api server.
6. [mkcert](https://github.com/FiloSottile/mkcert?tab=readme-ov-file#installation) - to make trusted TLS certificates.
7. [jq](https://jqlang.github.io/jq/download/) - to fiddle with JSON output.
## Configure DNS {#configure-dns}
Configure your machine to resolve `*.holos.localhost` to your loopback
interface. This is necessary for requests to reach the workload cluster. Save
this script to a file and execute it.
```bash showLineNumbers
#! /bin/bash
#
set -euo pipefail
tmpdir="$(mktemp -d)"
finish() {
[[ -d "$tmpdir" ]] && rm -rf "$tmpdir"
}
trap finish EXIT
cd "$tmpdir"
brew install dnsmasq
cat <<EOF >"$(brew --prefix)/etc/dnsmasq.d/holos.localhost.conf"
# Refer to https://holos.run/docs/tutorial/local/k3d/
address=/holos.localhost/127.0.0.1
EOF
if [[ -r /Library/LaunchDaemons/homebrew.mxcl.dnsmasq.plist ]]; then
echo "dnsmasq already configured"
else
sudo cp "$(brew list dnsmasq | grep 'dnsmasq.plist$')" \
/Library/LaunchDaemons/homebrew.mxcl.dnsmasq.plist
sudo launchctl unload /Library/LaunchDaemons/homebrew.mxcl.dnsmasq.plist
sudo launchctl load /Library/LaunchDaemons/homebrew.mxcl.dnsmasq.plist
dscacheutil -flushcache
echo "dnsmasq configured"
fi
sudo mkdir -p /etc/resolver
sudo tee /etc/resolver/holos.localhost <<EOF
domain holos.localhost
nameserver 127.0.0.1
EOF
sudo killall -HUP mDNSResponder
echo "all done."
```
## Create the Cluster {#create-the-cluster}
The Workload Cluster is where your applications and services will be deployed.
In production this is usually an EKS, GKE, or AKS cluster.
:::tip
Holos supports all compliant Kubernetes clusters. Holos was developed and tested
on GKE, EKS, Talos, k3s, and Kubeadm clusters.
:::
Create a local registry to speed up image builds and pulls.
```bash
k3d registry create registry.holos.localhost --port 5100
```
Create the workload cluster configured to use the local registry.
```bash
k3d cluster create workload \
--registry-use k3d-registry.holos.localhost:5100 \
--port "443:443@loadbalancer" \
--k3s-arg "--disable=traefik@server:0"
```
Traefik is disabled because Istio provides the same functionality.
## Setup Root CA {#setup-root-ca}
Platforms most often use cert-manager to issue tls certificates. The browser
and tools we're using need to trust these certificates to work together.
Generate a local, trusted root certificate authority with the following script.
Admin access is necessary for `mkcert` to manage the certificate into your trust
stores.
```bash
sudo -v
```
Manage the local CA and copy the CA key to the workload cluster so that cert
manager can manage trusted certificates.
Save this script to a file and execute it to configure a trusted certificate
authority.
```bash showLineNumbers
#! /bin/bash
#
set -euo pipefail
mkcert --install
tmpdir="$(mktemp -d)"
finish() {
[[ -d "$tmpdir" ]] && rm -rf "$tmpdir"
}
trap finish EXIT
cd "$tmpdir"
# Create the local CA Secret with ca.crt, tls.crt, tls.key
mkdir local-ca
cd local-ca
CAROOT="$(mkcert -CAROOT)"
cp -p "${CAROOT}/rootCA.pem" ca.crt
cp -p "${CAROOT}/rootCA.pem" tls.crt
cp -p "${CAROOT}/rootCA-key.pem" tls.key
kubectl create secret generic --from-file=. --dry-run=client -o yaml local-ca > ../local-ca.yaml
echo 'type: kubernetes.io/tls' >> ../local-ca.yaml
cd ..
cat <<EOF > namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
labels:
kubernetes.io/metadata.name: cert-manager
name: cert-manager
spec:
finalizers:
- kubernetes
EOF
kubectl apply --server-side=true -f namespace.yaml
kubectl apply -n cert-manager --server-side=true -f local-ca.yaml
# Save the Secret to easily reset the cluster later.
install -m 0644 namespace.yaml "${CAROOT}/namespace.yaml"
install -m 0600 local-ca.yaml "${CAROOT}/local-ca.yaml"
```
:::warning
Take care to run the local-ca script each time you create the workload cluster
so that Certificates are issued correctly.
:::
## Clean Up {#clean-up}
If you'd like to clean up the resources you created in this guide, remove them
with:
```bash
k3d cluster delete workload
```
## Next Steps
Now that you have a real cluster, continue your Holos journey by following the
[Tutorial](../tutorial/1-overview.mdx) and setting up your own Platform.

17
doc/md/tutorial.mdx Normal file
View File

@@ -0,0 +1,17 @@
---
slug: /
title: Tutorial
description: Take a guided tour of Holos features with our tutorial.
---
import DocCardList from '@theme/DocCardList';
# Tutorial
Our tutorial starts with a technical overview of Holos and then progresses
through each of the main features and concepts. Upon completing the tutorial
you'll have a solid understanding of the primary features and advantages of
Holos.
---
<DocCardList />

View File

@@ -0,0 +1,94 @@
# Overview
Holos is an open-source tool that simplifies software integration for platform
teams. While most Kubernetes tools focus on application management, Holos takes
a holistic infrastructure-as-code (IaC) approach, targeting the integration
layer where applications and organizational data converge. By providing
well-defined, typed structures for consistent validation, Holos reduces errors,
streamlines integration, and creates clear pathways for teams to easily
integrate their services.
# How Holos works
Holos implements the [rendered manifests pattern][rmp], generating fully
rendered Kubernetes manifests from [CUE language][CUE] abstractions called
Components. These Components can model [Helm charts][Helm], [Kustomize
bases][Kustomize], or native Kubernetes resources. A Holos Platform consists of
one or more Components and is applied to one or more Kubernetes clusters.
```mermaid
graph BT
Platform[Platform]
Cluster[Cluster]
Component[Component]
Helm[Helm]
Kustomize[Kustomize]
CUE[CUE]
Platform --> Cluster
Component --> Platform
Helm --> Component
Kustomize --> Component
CUE --> Component
```
# Holos' role in your workflow
Holos generates, but does not apply, rendered manifests, allowing teams to use
`git diff` to clearly see changes and assess the impact on clusters and services
before deploying. Instead, Holos manages the GitOps configuration for tools like
ArgoCD and Flux CD, enabling continuous deployment of resource changes with the
full visibility and control that these tools provide. As a result, expect Holos
to sit at the very end of a CI pipeline.
# Advantages of using Holos
### Safety
* CUE constraints on Holos Components surface validation errors early in the
development process, reducing the number of failed deployments and the time
spent troubleshooting them.
* Holos natively provides a "blast radius" to code
changes by identifying the rendered manifests across your fleet of Kubernetes
clusters that will be affected by the change.
* CUE's unification strategy allows multiples teams to contribute to the desired
state of a service:
* The Platform team provides definitions for shared resources.
* Engineering teams populate definitions with service-specific data.
* The Security team provides concrete values that cannot be changed to harden the company's security posture.
### Flexibility
* CUE is adept at modeling variation and organizational complexity at scale,
while Holos enables seamless integration of CUE data with native Kubernetes
tools such as [Helm][Helm] and [Kustomize][Kustomize].
* Holos is extensible, allowing Holos Components to be modeled from any tool that
generates (e.g. `helm`) or transforms (e.g. `kustomize`) manifest data.
### Consistency
* Holos manages the execution context for Helm and Kustomize, ensuring that
rendered manifests are consistently and reliably reproducible, no matter where
Holos is run.
* CUE constraints ensure that data abstractions include the required information
in the expected format, triggering early failures if any required data is
missing.
# When not to use Holos
Holos excels at configuration management and is most effective when integrated
into a broader Kubernetes deployment strategy. If you need a single tool to
manage the entire lifecycle of a Kubernetes cluster, Holos may not fully meet
your needs on its own.
# Next Steps
Now that you have a base understanding of how Holos works, continue
to the [Setup page](./2-setup.mdx) that guides you through installing Holos and
initializing your first Platform.
[rmp]: https://akuity.io/blog/the-rendered-manifests-pattern
[Helm]: https://helm.sh/
[Kustomize]: https://kustomize.io/
[CUE]: https://cuelang.org/

View File

@@ -0,0 +1,85 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# Setup
This tutorial will guide you through the installation of Holos and its
dependencies, as well as the initialization of a minimal Platform that you can
extend to meet your specific needs.
# Prerequisites
Holos integrates with the following tools that should be installed to enable
their functionality.
* [Helm][helm] to fetch and render Helm chart Components
* [Kubectl][kubectl] to [kustomize][kustomize] components.
# Install Holos
Holos is distributed as a single file executable that can be installed in a couple of ways.
### Releases
Download `holos` from the [releases](https://github.com/holos-run/holos/releases) page and place the executable into your shell path.
### Go install
Alternatively, install directly into your go bin path using:
```shell
go install github.com/holos-run/holos/cmd/holos@latest
```
# Do I need a Kubernetes cluster?
Holos only generates rendered Kubernetes manifests, so you don't need a
Kubernetes cluster to start using the tool or understand its workflow. However,
you will need a cluster eventually to apply the rendered manifests and verify
that they achieve the desired end state.
We recommend using [k3d](https://k3d.io/) to set up a minimal Kubernetes cluster with
[Orbstack](https://docs.orbstack.dev/install) or
[Docker](https://docs.docker.com/get-started/get-docker/). To simplify this,
we've created [the Local Cluster guide](../topics/4-local-cluster.mdx) which
automates the process, ensuring proper DNS and TLS certificates, and includes a
script to reset the cluster to a known good state.
When you're ready to experiment with a live Kubernetes cluster, refer to [the
Local Cluster guide](../topics/4-local-cluster.mdx).
# Initialize a new Platform
Use Holos to generate a minimal platform using the recommended directory structure
by creating an empty directory and then using the `holos generate platform` subcommand:
<Tabs groupId="tutorial-setup-generate-platform">
<TabItem value="command" label="Command">
```bash
mkdir holos_platform
cd holos_platform
holos generate platform v1alpha4
```
</TabItem>
<TabItem value="output" label="Output">
```txt
no output
```
</TabItem>
</Tabs>
Holos creates a `platform` directory with a `platform.gen.cue` file that serves
as the foundation for your newly initialized Holos Platform. For each Holos
Component you model, you'll add a new CUE file to the platform directory,
mapping it to the location of the Component's CUE code, and extending the
capabilities of your platform.
# Next Steps
Now that you've got Holos and its prerequisites installed, continue on to the
[Hello Holos page](./3-hello-holos.mdx) where we will guide you through the
process of creating your first Component and modeling a Helm chart.
[helm]: https://github.com/helm/helm/releases
[kubectl]: https://kubernetes.io/docs/tasks/tools/
[kustomize]: https://kustomize.io/

View File

@@ -0,0 +1,74 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# Hello Holos
One of the first exercises you perform when learning a new programming language
is to print out the "Hello World!" greeting. For Holos, our "Hello Holos"
exercise involves modeling the [podinfo Helm chart][podinfo] that produces a
similar greeting message from a Kubernetes Pod.
By the end of this tutorial you will gain the understanding of how to model
an individual Holos Component using a Helm chart as its source.
# The code
### Podinfo Helm Chart
Let's start by creating a directory for `podinfo`, touching an empty CUE file,
and then populating it with the CUE code below:
<Tabs groupId="tutorial-hello-podinfo-helm-cue-code">
<TabItem value="projects/tutorial/components/podinfo/podinfo.cue" label="Podinfo Helm Chart">
```bash
mkdir -p projects/tutorial/components/podinfo
touch projects/tutorial/components/podinfo/podinfo.cue
```
```cue showLineNumbers
package holos
// Produce a helm chart build plan.
_HelmChart.BuildPlan
_HelmChart: #Helm & {
Name: "podinfo"
Chart: {
version: "6.6.2"
repository: {
name: "podinfo"
url: "https://stefanprodan.github.io/podinfo"
}
}
}
```
</TabItem>
</Tabs>
### Register the podinfo component
Now let's register the code modeling the `podinfo` Helm chart as a Holos
Component and assign it to a cluser. For this we will need a create new file in
the `platform` directory with the following contents:
<Tabs groupId="tutorial-hello-register-podinfo-component">
<TabItem value="platform/podinfo.cue" label="Register Podinfo">
```bash
touch plaform/podinfo.cue
```
```cue showLineNumbers
_Platform: Components: podinfo: {
name: "podinfo"
component: "projects/tutorial/components/podinfo"
cluster: "local"
}
```
</TabItem>
</Tabs>
[podinfo]: https://github.com/stefanprodan/podinfo

View File

@@ -0,0 +1 @@
# Helm

View File

@@ -0,0 +1 @@
# Kustomize

Some files were not shown because too many files have changed in this diff Show More