mirror of
https://github.com/holos-run/holos.git
synced 2026-03-19 16:54:58 +00:00
Compare commits
7 Commits
jeff/406-u
...
v0.104.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7e0470c48 | ||
|
|
d5c7b82684 | ||
|
|
7d0392e596 | ||
|
|
410b882d1d | ||
|
|
e2648202dc | ||
|
|
8fbee1cbd9 | ||
|
|
982db2cccc |
@@ -0,0 +1,7 @@
|
||||
exec bash -c 'bash -euo pipefail $WORK/command.sh 2>&1'
|
||||
cmp stdout $WORK/output.txt
|
||||
|
||||
-- command.sh --
|
||||
holos --version
|
||||
-- output.txt --
|
||||
0.103.0
|
||||
126
doc/md/tutorial/_hello-holos/examples/02-hello-holos.txt
Normal file
126
doc/md/tutorial/_hello-holos/examples/02-hello-holos.txt
Normal file
@@ -0,0 +1,126 @@
|
||||
# Set $HOME because:
|
||||
# - Helm uses it for temporary files
|
||||
# - Git requires it for setting author name/email globally
|
||||
env HOME=$WORK/.tmp
|
||||
chmod 0755 $WORK/update.sh
|
||||
|
||||
# Configure git author for testscript execution
|
||||
exec git config --global user.name 'Holos Docs'
|
||||
exec git config --global user.email 'hello@holos.run'
|
||||
exec git config --global init.defaultBranch main
|
||||
|
||||
# Remove the tutorial directory if it already exists
|
||||
exec rm -rf holos-tutorial
|
||||
|
||||
# Create and change to the tutorial directory, and then initialize the Holos platform
|
||||
exec bash -c 'bash -euo pipefail $WORK/mkdir-and-init.sh'
|
||||
cd holos-tutorial
|
||||
|
||||
# Create the components directory
|
||||
exec bash -c 'bash -euo pipefail $WORK/mkdir-components.sh'
|
||||
|
||||
# Combine and execute the multiline podinfo component header/body/trailer files
|
||||
exec cat $WORK/podinfo-component-header.sh ../podinfo-component-body.cue ../eof-trailer.sh
|
||||
stdin stdout
|
||||
exec bash -xeuo pipefail
|
||||
|
||||
# Combine and execute the multiline platform registration header/body/trailer files
|
||||
exec cat $WORK/register-podinfo-header.sh ../register-podinfo-body.cue ../eof-trailer.sh
|
||||
stdin stdout
|
||||
exec bash -xeuo pipefail
|
||||
|
||||
# Render the platform, capture stdout, and use update.sh to gate whether the
|
||||
# output file should be updated.
|
||||
#
|
||||
# NOTE: The [net] condition will test whether external network access is available
|
||||
[net] exec bash -c 'bash -euo pipefail $WORK/render.sh 2>&1'
|
||||
[net] stdin stdout
|
||||
exec $WORK/update.sh $WORK/register-components-output.txt
|
||||
|
||||
# Generate and update the tree of the tutorial directory (omitting the cue.mod directory)
|
||||
exec bash -c 'bash -euo pipefail $WORK/tree.sh'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/tree.txt
|
||||
|
||||
# Split the rendered manifest into two separate files to display separately
|
||||
exec bash -c 'bash -euo pipefail $WORK/split-rendered-manifest.sh $WORK/holos-tutorial/deploy/components/podinfo/podinfo.gen.yaml $WORK'
|
||||
|
||||
# Grep for the Hello Holos message and write the output file
|
||||
exec bash -c 'bash -euo pipefail $WORK/grep-for-message.sh'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/grepped-output.txt
|
||||
|
||||
# Clean up the tutorial directory and tmp $HOME directory
|
||||
cd $WORK
|
||||
exec rm -rf holos-tutorial
|
||||
exec rm -rf $HOME
|
||||
|
||||
-- update.sh --
|
||||
#! /bin/bash
|
||||
set -euo pipefail
|
||||
[[ -s "$1" ]] && [[ -z "${HOLOS_UPDATE_SCRIPTS:-}" ]] && exit 0
|
||||
cat > "$1"
|
||||
-- mkdir-and-init.sh --
|
||||
mkdir holos-tutorial && cd holos-tutorial
|
||||
holos init platform v1alpha5
|
||||
-- tree.sh --
|
||||
tree -L 3 -I cue.mod .
|
||||
-- mkdir-components.sh --
|
||||
mkdir -p components/podinfo
|
||||
-- podinfo-component-header.sh --
|
||||
cat <<EOF > components/podinfo/podinfo.cue
|
||||
-- podinfo-component-body.cue --
|
||||
package holos
|
||||
|
||||
// Produce a helm chart build plan.
|
||||
holos: HelmChart.BuildPlan
|
||||
|
||||
HelmChart: #Helm & {
|
||||
Name: "podinfo"
|
||||
Chart: {
|
||||
version: "6.6.2"
|
||||
repository: {
|
||||
name: "podinfo"
|
||||
url: "https://stefanprodan.github.io/podinfo"
|
||||
}
|
||||
}
|
||||
// Holos marshals Values into values.yaml for Helm.
|
||||
Values: {
|
||||
// message is a string with a default value. @tag indicates a value may
|
||||
// be injected from the platform spec component parameters.
|
||||
ui: {
|
||||
message: string | *"Hello World" @tag(greeting, type=string)
|
||||
}
|
||||
}
|
||||
}
|
||||
-- eof-trailer.sh --
|
||||
EOF
|
||||
-- register-podinfo-header.sh --
|
||||
cat <<EOF > platform/podinfo.cue
|
||||
-- register-podinfo-body.cue --
|
||||
package holos
|
||||
|
||||
Platform: Components: podinfo: {
|
||||
name: "podinfo"
|
||||
path: "components/podinfo"
|
||||
// Inject a value into the component.
|
||||
parameters: greeting: "Hello Holos!"
|
||||
}
|
||||
-- render.sh --
|
||||
holos render platform
|
||||
-- register-components-output.txt --
|
||||
cached podinfo 6.6.2
|
||||
rendered podinfo in 1.938665041s
|
||||
rendered platform in 1.938759417s
|
||||
-- podinfo-rendered-path.sh --
|
||||
deploy/components/podinfo/podinfo.gen.yaml
|
||||
-- split-rendered-manifest.sh --
|
||||
awk 'BEGIN {RS="---"} NR==1 {print > "service.yaml"} NR==2 {print > "deployment.yaml"}' $1
|
||||
mv service.yaml $2/rendered-service.yaml
|
||||
mv deployment.yaml $2/rendered-deployment.yaml
|
||||
-- grep-for-message.sh --
|
||||
grep -B2 Hello deploy/components/podinfo/podinfo.gen.yaml
|
||||
-- grepped-output.txt --
|
||||
env:
|
||||
- name: PODINFO_UI_MESSAGE
|
||||
value: Hello Holos!
|
||||
@@ -0,0 +1 @@
|
||||
holos --version
|
||||
@@ -0,0 +1 @@
|
||||
0.103.0
|
||||
@@ -0,0 +1 @@
|
||||
grep -B2 Hello deploy/components/podinfo/podinfo.gen.yaml
|
||||
@@ -0,0 +1,3 @@
|
||||
env:
|
||||
- name: PODINFO_UI_MESSAGE
|
||||
value: Hello Holos!
|
||||
@@ -0,0 +1,2 @@
|
||||
mkdir holos-tutorial && cd holos-tutorial
|
||||
holos init platform v1alpha5
|
||||
@@ -0,0 +1 @@
|
||||
mkdir -p components/podinfo
|
||||
@@ -0,0 +1,23 @@
|
||||
package holos
|
||||
|
||||
// Produce a helm chart build plan.
|
||||
holos: HelmChart.BuildPlan
|
||||
|
||||
HelmChart: #Helm & {
|
||||
Name: "podinfo"
|
||||
Chart: {
|
||||
version: "6.6.2"
|
||||
repository: {
|
||||
name: "podinfo"
|
||||
url: "https://stefanprodan.github.io/podinfo"
|
||||
}
|
||||
}
|
||||
// Holos marshals Values into values.yaml for Helm.
|
||||
Values: {
|
||||
// message is a string with a default value. @tag indicates a value may
|
||||
// be injected from the platform spec component parameters.
|
||||
ui: {
|
||||
message: string | *"Hello World" @tag(greeting, type=string)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
cat <<EOF > components/podinfo/podinfo.cue
|
||||
@@ -0,0 +1 @@
|
||||
deploy/components/podinfo/podinfo.gen.yaml
|
||||
@@ -0,0 +1,2 @@
|
||||
rendered podinfo in 544.501875ms
|
||||
rendered platform in 544.608125ms
|
||||
@@ -0,0 +1,8 @@
|
||||
package holos
|
||||
|
||||
Platform: Components: podinfo: {
|
||||
name: "podinfo"
|
||||
path: "components/podinfo"
|
||||
// Inject a value into the component.
|
||||
parameters: greeting: "Hello Holos!"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
cat <<EOF > platform/podinfo.cue
|
||||
@@ -1,2 +1 @@
|
||||
rm -rf deploy
|
||||
holos render platform
|
||||
@@ -0,0 +1,93 @@
|
||||
|
||||
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
|
||||
helm.sh/chart: podinfo-6.6.2
|
||||
name: podinfo
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/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
|
||||
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_MESSAGE
|
||||
value: Hello Holos!
|
||||
- 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
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
app.kubernetes.io/name: podinfo
|
||||
app.kubernetes.io/version: 6.6.2
|
||||
helm.sh/chart: podinfo-6.6.2
|
||||
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
|
||||
type: ClusterIP
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
awk 'BEGIN {RS="---"} NR==1 {print > "service.yaml"} NR==2 {print > "deployment.yaml"}' $1
|
||||
mv service.yaml $2/rendered-service.yaml
|
||||
mv deployment.yaml $2/rendered-deployment.yaml
|
||||
@@ -0,0 +1 @@
|
||||
tree -L 3 -I cue.mod .
|
||||
17
doc/md/tutorial/_hello-holos/script-02-hello-holos/tree.txt
Normal file
17
doc/md/tutorial/_hello-holos/script-02-hello-holos/tree.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
.
|
||||
|-- components
|
||||
| `-- podinfo
|
||||
| |-- podinfo.cue
|
||||
| `-- vendor
|
||||
|-- deploy
|
||||
| `-- components
|
||||
| `-- podinfo
|
||||
|-- platform
|
||||
| |-- platform.gen.cue
|
||||
| `-- podinfo.cue
|
||||
|-- platform.metadata.json
|
||||
|-- resources.cue
|
||||
|-- schema.cue
|
||||
`-- tags.cue
|
||||
|
||||
8 directories, 7 files
|
||||
7
doc/md/tutorial/_kustomize/examples/01-holos-version.txt
Normal file
7
doc/md/tutorial/_kustomize/examples/01-holos-version.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
exec bash -c 'bash -euo pipefail $WORK/command.sh 2>&1'
|
||||
cmp stdout $WORK/output.txt
|
||||
|
||||
-- command.sh --
|
||||
holos --version
|
||||
-- output.txt --
|
||||
0.103.0
|
||||
226
doc/md/tutorial/_kustomize/examples/02-kustomize.txt
Normal file
226
doc/md/tutorial/_kustomize/examples/02-kustomize.txt
Normal file
@@ -0,0 +1,226 @@
|
||||
# Set $HOME because:
|
||||
# - Helm uses it for temporary files
|
||||
# - Git requires it for setting author name/email globally
|
||||
env HOME=$WORK/.tmp
|
||||
chmod 0755 $WORK/update.sh
|
||||
|
||||
# Configure git author for testscript execution
|
||||
exec git config --global user.name 'Holos Docs'
|
||||
exec git config --global user.email 'hello@holos.run'
|
||||
exec git config --global init.defaultBranch main
|
||||
|
||||
# Remove the tutorial directory if it already exists
|
||||
exec rm -rf holos-kustomize-tutorial
|
||||
|
||||
# Create and change to the tutorial directory, and then initialize the Holos platform
|
||||
exec bash -c 'bash -euo pipefail $WORK/mkdir-and-init.sh'
|
||||
cd holos-kustomize-tutorial
|
||||
|
||||
# Initialize git
|
||||
exec bash -c 'bash -euo pipefail $WORK/git-init.sh'
|
||||
|
||||
# Create the component directory
|
||||
exec bash -c 'bash -euo pipefail $WORK/mkdir-component.sh'
|
||||
|
||||
# Combine and execute the multiline httpbin component header/body/trailer files
|
||||
exec cat $WORK/httpbin-component-header.sh $WORK/httpbin-component-body.cue $WORK/eof-trailer.sh
|
||||
stdin stdout
|
||||
exec bash -xeuo pipefail
|
||||
|
||||
# Combine and execute the multiline httpbin yaml header/body/trailer files
|
||||
exec cat $WORK/httpbin-yaml-header.sh $WORK/httpbin-yaml-body.yaml $WORK/eof-trailer.sh
|
||||
stdin stdout
|
||||
exec bash -xeuo pipefail
|
||||
|
||||
# Combine and execute the multiline registration header/body/trailer files
|
||||
exec cat $WORK/register-component-header.sh $WORK/register-component-body.cue $WORK/eof-trailer.sh
|
||||
stdin stdout
|
||||
exec bash -xeuo pipefail
|
||||
|
||||
# Render the platform, capture stdout, and use update.sh to gate whether the
|
||||
# output file should be updated.
|
||||
#
|
||||
# NOTE: The [net] condition will test whether external network access is available
|
||||
[net] exec bash -c 'bash -euo pipefail $WORK/render.sh 2>&1'
|
||||
[net] stdin stdout
|
||||
exec $WORK/update.sh $WORK/register-component-output.txt
|
||||
|
||||
# Git commit and capture output
|
||||
exec bash -c 'bash -euo pipefail $WORK/git-commit-component.sh'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/git-commit-component-output.txt
|
||||
|
||||
# Export Build Plan and capture output
|
||||
exec bash -c 'bash -euo pipefail $WORK/cue-export.sh'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/buildplan-output.cue
|
||||
|
||||
# Combine and execute the multiline kustomize patch header/body/trailer files
|
||||
exec cat $WORK/httpbin-patch-header.sh $WORK/httpbin-patch-body.cue $WORK/eof-trailer.sh
|
||||
stdin stdout
|
||||
exec bash -xeuo pipefail
|
||||
|
||||
# Render the platform and capture output
|
||||
[net] exec bash -c 'bash -euo pipefail $WORK/render.sh 2>&1'
|
||||
[net] stdin stdout
|
||||
exec $WORK/update.sh $WORK/kustomize-patch-render-output.txt
|
||||
|
||||
# Git diff and capture output
|
||||
exec bash -c 'bash -euo pipefail $WORK/git-diff.sh'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/git.diff
|
||||
|
||||
# Git commit and capture output
|
||||
exec bash -c 'bash -euo pipefail $WORK/git-commit-final.sh'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/git-commit-final-output.txt
|
||||
|
||||
# Clean up the tutorial directory and tmp $HOME directory
|
||||
cd $WORK
|
||||
exec rm -rf holos-kustomize-tutorial
|
||||
exec rm -rf $HOME
|
||||
|
||||
-- update.sh --
|
||||
#! /bin/bash
|
||||
set -euo pipefail
|
||||
[[ -s "$1" ]] && [[ -z "${HOLOS_UPDATE_SCRIPTS:-}" ]] && exit 0
|
||||
cat > "$1"
|
||||
-- mkdir-and-init.sh --
|
||||
mkdir holos-kustomize-tutorial
|
||||
cd holos-kustomize-tutorial
|
||||
holos init platform v1alpha5
|
||||
-- git-init.sh --
|
||||
git init . && git add . && git commit -m initial
|
||||
-- mkdir-component.sh --
|
||||
mkdir -p components/httpbin
|
||||
-- httpbin-component-header.sh --
|
||||
cat <<EOF > components/httpbin/httpbin.cue
|
||||
-- httpbin-component-body.cue --
|
||||
package holos
|
||||
|
||||
// Produce a Kustomize BuildPlan for Holos
|
||||
holos: Kustomize.BuildPlan
|
||||
|
||||
// https://github.com/mccutchen/go-httpbin/blob/v2.15.0/kustomize/README.md
|
||||
Kustomize: #Kustomize & {
|
||||
KustomizeConfig: {
|
||||
// Files tells Holos to copy the file from the component path to the
|
||||
// temporary directory Holos uses for BuildPlan execution.
|
||||
Files: {
|
||||
"httpbin.yaml": _
|
||||
}
|
||||
CommonLabels: {
|
||||
"app.kubernetes.io/name": "httpbin"
|
||||
}
|
||||
// Kustomization represents a kustomization.yaml file in CUE. Holos
|
||||
// marshals this field into a `kustomization.yaml` while processing a
|
||||
// BuildPlan. See
|
||||
// https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/
|
||||
Kustomization: {
|
||||
images: [{name: "mccutchen/go-httpbin"}]
|
||||
// Use a hidden field to compose patches easily with a struct. Hidden
|
||||
// fields are not included in exported structures.
|
||||
_patches: {}
|
||||
// Convert the hidden struct to a list.
|
||||
patches: [for x in _patches {x}]
|
||||
}
|
||||
}
|
||||
}
|
||||
-- eof-trailer.sh --
|
||||
EOF
|
||||
-- httpbin-yaml-header.sh --
|
||||
cat <<EOF > components/httpbin/httpbin.yaml
|
||||
-- httpbin-yaml-body.yaml --
|
||||
# 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
|
||||
-- register-component-header.sh --
|
||||
cat <<EOF > platform/httpbin.cue
|
||||
-- register-component-body.cue --
|
||||
package holos
|
||||
|
||||
Platform: Components: {
|
||||
httpbin: {
|
||||
name: "httpbin"
|
||||
path: "components/httpbin"
|
||||
}
|
||||
}
|
||||
-- git-commit-component.sh --
|
||||
git add . && git commit -m 'add httpbin'
|
||||
-- cue-export.sh --
|
||||
holos cue export --expression holos --out=yaml ./components/httpbin
|
||||
-- httpbin-patch-header.sh --
|
||||
cat <<EOF > components/httpbin/patches.cue
|
||||
-- httpbin-patch-body.cue --
|
||||
package holos
|
||||
|
||||
import "encoding/yaml"
|
||||
|
||||
// Mix in a Kustomize patch to the configuration.
|
||||
Kustomize: KustomizeConfig: Kustomization: _patches: {
|
||||
probe: {
|
||||
target: kind: "Service"
|
||||
target: name: "httpbin"
|
||||
patch: yaml.Marshal([{
|
||||
op: "add"
|
||||
path: "/metadata/annotations/prometheus.io~1probe"
|
||||
value: "true"
|
||||
}])
|
||||
}
|
||||
}
|
||||
-- httpbin-component-output.txt --
|
||||
rendered httpbin in 197.030208ms
|
||||
rendered platform in 197.416416ms
|
||||
-- render.sh --
|
||||
holos render platform
|
||||
-- git-diff.sh --
|
||||
git diff
|
||||
-- git.diff --
|
||||
diff --git a/deploy/components/httpbin/httpbin.gen.yaml b/deploy/components/httpbin/httpbin.gen.yaml
|
||||
index 298b9a8..a16bd1a 100644
|
||||
--- a/deploy/components/httpbin/httpbin.gen.yaml
|
||||
+++ b/deploy/components/httpbin/httpbin.gen.yaml
|
||||
@@ -1,6 +1,8 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
+ annotations:
|
||||
+ prometheus.io/probe: "true"
|
||||
labels:
|
||||
app.kubernetes.io/name: httpbin
|
||||
name: httpbin
|
||||
-- git-commit-final.sh --
|
||||
git add . && git commit -m 'annotate httpbin for prometheus probes'
|
||||
@@ -0,0 +1 @@
|
||||
holos --version
|
||||
@@ -0,0 +1 @@
|
||||
0.103.0
|
||||
@@ -0,0 +1,36 @@
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: no-name
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: components/no-name/no-name.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
resources: {}
|
||||
- kind: File
|
||||
output: httpbin.yaml
|
||||
file:
|
||||
source: httpbin.yaml
|
||||
validators: []
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- resources.gen.yaml
|
||||
- httpbin.yaml
|
||||
output: components/no-name/no-name.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
labels:
|
||||
- includeSelectors: false
|
||||
pairs:
|
||||
app.kubernetes.io/name: httpbin
|
||||
patches: []
|
||||
images:
|
||||
- name: mccutchen/go-httpbin
|
||||
resources:
|
||||
- resources.gen.yaml
|
||||
- httpbin.yaml
|
||||
kind: Kustomization
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
@@ -0,0 +1 @@
|
||||
holos cue export --expression holos --out=yaml ./components/httpbin
|
||||
@@ -0,0 +1,6 @@
|
||||
[main f0dd632] add httpbin
|
||||
4 files changed, 113 insertions(+)
|
||||
create mode 100644 components/httpbin/httpbin.cue
|
||||
create mode 100644 components/httpbin/httpbin.yaml
|
||||
create mode 100644 deploy/components/httpbin/httpbin.gen.yaml
|
||||
create mode 100644 platform/httpbin.cue
|
||||
@@ -0,0 +1 @@
|
||||
git add . && git commit -m 'add httpbin'
|
||||
@@ -0,0 +1,3 @@
|
||||
[main b120712] annotate httpbin for prometheus probes
|
||||
2 files changed, 18 insertions(+)
|
||||
create mode 100644 components/httpbin/patches.cue
|
||||
@@ -0,0 +1 @@
|
||||
git add . && git commit -m 'annotate httpbin for prometheus probes'
|
||||
@@ -0,0 +1 @@
|
||||
git diff
|
||||
@@ -0,0 +1 @@
|
||||
git init . && git add . && git commit -m initial
|
||||
13
doc/md/tutorial/_kustomize/script-02-kustomize/git.diff
Normal file
13
doc/md/tutorial/_kustomize/script-02-kustomize/git.diff
Normal file
@@ -0,0 +1,13 @@
|
||||
diff --git a/deploy/components/httpbin/httpbin.gen.yaml b/deploy/components/httpbin/httpbin.gen.yaml
|
||||
index 298b9a8..a16bd1a 100644
|
||||
--- a/deploy/components/httpbin/httpbin.gen.yaml
|
||||
+++ b/deploy/components/httpbin/httpbin.gen.yaml
|
||||
@@ -1,6 +1,8 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
+ annotations:
|
||||
+ prometheus.io/probe: "true"
|
||||
labels:
|
||||
app.kubernetes.io/name: httpbin
|
||||
name: httpbin
|
||||
@@ -0,0 +1,30 @@
|
||||
package holos
|
||||
|
||||
// Produce a Kustomize BuildPlan for Holos
|
||||
holos: Kustomize.BuildPlan
|
||||
|
||||
// https://github.com/mccutchen/go-httpbin/blob/v2.15.0/kustomize/README.md
|
||||
Kustomize: #Kustomize & {
|
||||
KustomizeConfig: {
|
||||
// Files tells Holos to copy the file from the component path to the
|
||||
// temporary directory Holos uses for BuildPlan execution.
|
||||
Files: {
|
||||
"httpbin.yaml": _
|
||||
}
|
||||
CommonLabels: {
|
||||
"app.kubernetes.io/name": "httpbin"
|
||||
}
|
||||
// Kustomization represents a kustomization.yaml file in CUE. Holos
|
||||
// marshals this field into a `kustomization.yaml` while processing a
|
||||
// BuildPlan. See
|
||||
// https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/
|
||||
Kustomization: {
|
||||
images: [{name: "mccutchen/go-httpbin"}]
|
||||
// Use a hidden field to compose patches easily with a struct. Hidden
|
||||
// fields are not included in exported structures.
|
||||
_patches: {}
|
||||
// Convert the hidden struct to a list.
|
||||
patches: [for x in _patches {x}]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
cat <<EOF > components/httpbin/httpbin.cue
|
||||
@@ -0,0 +1,2 @@
|
||||
rendered httpbin in 197.030208ms
|
||||
rendered platform in 197.416416ms
|
||||
@@ -0,0 +1,16 @@
|
||||
package holos
|
||||
|
||||
import "encoding/yaml"
|
||||
|
||||
// Mix in a Kustomize patch to the configuration.
|
||||
Kustomize: KustomizeConfig: Kustomization: _patches: {
|
||||
probe: {
|
||||
target: kind: "Service"
|
||||
target: name: "httpbin"
|
||||
patch: yaml.Marshal([{
|
||||
op: "add"
|
||||
path: "/metadata/annotations/prometheus.io~1probe"
|
||||
value: "true"
|
||||
}])
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
cat <<EOF > components/httpbin/patches.cue
|
||||
@@ -0,0 +1,36 @@
|
||||
# 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
|
||||
@@ -0,0 +1 @@
|
||||
cat <<EOF > components/httpbin/httpbin.yaml
|
||||
@@ -0,0 +1,2 @@
|
||||
rendered httpbin in 132.00525ms
|
||||
rendered platform in 132.124042ms
|
||||
@@ -0,0 +1,3 @@
|
||||
mkdir holos-kustomize-tutorial
|
||||
cd holos-kustomize-tutorial
|
||||
holos init platform v1alpha5
|
||||
@@ -0,0 +1 @@
|
||||
mkdir -p components/httpbin
|
||||
@@ -0,0 +1,8 @@
|
||||
package holos
|
||||
|
||||
Platform: Components: {
|
||||
httpbin: {
|
||||
name: "httpbin"
|
||||
path: "components/httpbin"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
cat <<EOF > platform/httpbin.cue
|
||||
@@ -0,0 +1,2 @@
|
||||
rendered httpbin in 175.057083ms
|
||||
rendered platform in 175.145292ms
|
||||
@@ -1,2 +1 @@
|
||||
rm -rf deploy
|
||||
holos render platform
|
||||
@@ -10,6 +10,7 @@ import TabItem from '@theme/TabItem';
|
||||
import RenderingOverview from '@site/src/diagrams/rendering-overview.mdx';
|
||||
import PlatformSequence from '@site/src/diagrams/render-platform-sequence.mdx';
|
||||
import ComponentSequence from '@site/src/diagrams/render-component-sequence.mdx';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
# Hello Holos
|
||||
|
||||
@@ -21,49 +22,37 @@ This introduces the core concept of wrapping Helm charts as Holos Components.
|
||||
|
||||
## Implementation
|
||||
|
||||
### Holos Version
|
||||
|
||||
Ensure you have a current version of `holos` installed. This document was
|
||||
tested with the following version.
|
||||
|
||||
import HolosVersionCommand from '!!raw-loader!./_hello-holos/script-01-holos-version/command.sh';
|
||||
import HolosVersionOutput from '!!raw-loader!./_hello-holos/script-01-holos-version/output.txt';
|
||||
|
||||
<CodeBlock language="bash">{HolosVersionCommand}</CodeBlock>
|
||||
<CodeBlock language="txt">{HolosVersionOutput}</CodeBlock>
|
||||
|
||||
### Initialize Platform Structure
|
||||
|
||||
Create and initialize a minimal platform:
|
||||
|
||||
```shell
|
||||
mkdir holos-tutorial && cd holos-tutorial
|
||||
holos init platform v1alpha5
|
||||
```
|
||||
import MkdirAndInit from '!!raw-loader!./_hello-holos/script-02-hello-holos/mkdir-and-init.sh';
|
||||
import TreeOutput from '!!raw-loader!./_hello-holos/script-02-hello-holos/tree.txt';
|
||||
|
||||
The resulting directory structure:
|
||||
<CodeBlock language="bash">{MkdirAndInit}</CodeBlock>
|
||||
|
||||
For reference, the directory structure you will attain by the end of this tutorial
|
||||
is listed below (NOTE: we have omitted the `cue.mod` directory for brevity):
|
||||
|
||||
<Tabs groupId="80D04C6A-BC83-44D0-95CC-CE01B439B159">
|
||||
<TabItem value="tree" label="Tree">
|
||||
```text showLineNumbers
|
||||
holos-tutorial/
|
||||
├── components/
|
||||
│ └── podinfo/
|
||||
│ └── podinfo.cue
|
||||
├── cue.mod/
|
||||
├── platform/
|
||||
│ ├── platform.gen.cue
|
||||
│ └── podinfo.cue
|
||||
├── resources.cue
|
||||
├── schema.cue
|
||||
└── tags.cue
|
||||
```
|
||||
<CodeBlock language="txt" showLineNumbers>{TreeOutput}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="details" label="Details">
|
||||
<div style={{display: "flex"}}>
|
||||
<div>
|
||||
```text showLineNumbers
|
||||
holos-tutorial/
|
||||
├── components/
|
||||
│ └── podinfo/
|
||||
│ └── podinfo.cue
|
||||
├── cue.mod/
|
||||
├── platform/
|
||||
│ ├── platform.gen.cue
|
||||
│ └── podinfo.cue
|
||||
├── resources.cue
|
||||
├── schema.cue
|
||||
└── tags.cue
|
||||
```
|
||||
<CodeBlock language="txt" showLineNumbers>{TreeOutput}</CodeBlock>
|
||||
</div>
|
||||
<div>
|
||||
- **Line 1** The platform root is the `holos-tutorial` directory we created.
|
||||
@@ -72,22 +61,24 @@ anywhere.
|
||||
- **Line 3** A component is a collection of `*.cue` files at a path.
|
||||
- **Line 4** We'll create this file and configure the podinfo helm chart in the
|
||||
next section.
|
||||
- **Line 5** The CUE module directory. Schema definitions for Kubernetes and
|
||||
Holos resources reside within the `cue.mod` directory.
|
||||
- **Line 6** The platform directory is the **main entrypoint** for the `holos
|
||||
- **Line 5** The `vendor` directory contains a cached copy of the Helm chart that
|
||||
was fetched for the component.
|
||||
- **Line 6** Rendered manifests are placed within the `deploy` directory following
|
||||
the structure of the `components/` directory.
|
||||
- **Line 9** The platform directory is the **main entrypoint** for the `holos
|
||||
render platform` command.
|
||||
- **Line 7** `platform.gen.cue` is initialized by `holos init platform` and
|
||||
- **Line 10** `platform.gen.cue` is initialized by `holos init platform` and
|
||||
contains the Platform spec.
|
||||
- **Line 8** `podinfo.cue` integrates podinfo with the platform by adding the
|
||||
- **Line 11** `podinfo.cue` integrates podinfo with the platform by adding the
|
||||
component to the platform spec. We'll add ths file after the next section.
|
||||
- **Line 9** `resources.cue` Defines the Kubernetes resources available to
|
||||
- **Line 13** `resources.cue` Defines the Kubernetes resources available to
|
||||
manage in CUE.
|
||||
- **Line 10** `schema.cue` Defines the configuration common to all component
|
||||
- **Line 14** `schema.cue` Defines the configuration common to all component
|
||||
kinds.
|
||||
- **Line 11** `tags.cue` Defines where component parameter values are injected
|
||||
- **Line 15** `tags.cue` Defines where component parameter values are injected
|
||||
into the overall platform configuration. We don't need to be concerned with
|
||||
this file until we cover component parameters.
|
||||
- **Lines 9-11** Initialized by `holos init platform`, user editable after
|
||||
- **Lines 9-15** Initialized by `holos init platform`, user editable after
|
||||
initialization.
|
||||
</div>
|
||||
</div>
|
||||
@@ -98,40 +89,15 @@ initialization.
|
||||
|
||||
Configure the `podinfo` component:
|
||||
|
||||
```bash
|
||||
mkdir -p components/podinfo
|
||||
```
|
||||
```bash
|
||||
cat <<EOF > components/podinfo/podinfo.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
import MkdirComponents from '!!raw-loader!./_hello-holos/script-02-hello-holos/mkdir-components.sh';
|
||||
import PodinfoHeader from '!!raw-loader!./_hello-holos/script-02-hello-holos/podinfo-component-header.sh';
|
||||
import PodinfoBody from '!!raw-loader!./_hello-holos/script-02-hello-holos/podinfo-component-body.cue';
|
||||
import EofTrailer from '!!raw-loader!./_hello-holos/script-02-hello-holos/eof-trailer.sh';
|
||||
|
||||
// Produce a helm chart build plan.
|
||||
holos: HelmChart.BuildPlan
|
||||
|
||||
HelmChart: #Helm & {
|
||||
Name: "podinfo"
|
||||
Chart: {
|
||||
version: "6.6.2"
|
||||
repository: {
|
||||
name: "podinfo"
|
||||
url: "https://stefanprodan.github.io/podinfo"
|
||||
}
|
||||
}
|
||||
// Holos marshals Values into values.yaml for Helm.
|
||||
Values: {
|
||||
// message is a string with a default value. @tag indicates a value may
|
||||
// be injected from the platform spec component parameters.
|
||||
ui: {
|
||||
message: string | *"Hello World" @tag(greeting, type=string)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
<CodeBlock language="bash">{MkdirComponents}</CodeBlock>
|
||||
<CodeBlock language="bash">{PodinfoHeader}</CodeBlock>
|
||||
<CodeBlock language="cue" showLineNumbers>{PodinfoBody}</CodeBlock>
|
||||
<CodeBlock language="bash">{EofTrailer}</CodeBlock>
|
||||
|
||||
:::important
|
||||
Like Go packages, CUE loads all `*.cue` files in the component directory to
|
||||
@@ -148,22 +114,12 @@ root-level `schema.cue`.
|
||||
|
||||
Register the `podinfo` component in `platform/podinfo.cue`:
|
||||
|
||||
```bash
|
||||
cat <<EOF > platform/podinfo.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
import RegisterPodinfoHeader from '!!raw-loader!./_hello-holos/script-02-hello-holos/register-podinfo-header.sh';
|
||||
import RegisterPodinfoBody from '!!raw-loader!./_hello-holos/script-02-hello-holos/register-podinfo-body.cue';
|
||||
|
||||
Platform: Components: podinfo: {
|
||||
name: "podinfo"
|
||||
path: "components/podinfo"
|
||||
// Inject a value into the component.
|
||||
parameters: greeting: "Hello Holos!"
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
<CodeBlock language="bash">{RegisterPodinfoHeader}</CodeBlock>
|
||||
<CodeBlock language="cue" showLineNumbers>{RegisterPodinfoBody}</CodeBlock>
|
||||
<CodeBlock language="bash">{EofTrailer}</CodeBlock>
|
||||
|
||||
:::tip
|
||||
Parameter names are unrestricted, except for the reserved `holos_` prefix.
|
||||
@@ -173,161 +129,42 @@ Parameter names are unrestricted, except for the reserved `holos_` prefix.
|
||||
|
||||
Render the `podinfo` configuration:
|
||||
|
||||
import RenderCommand from '!!raw-loader!./_hello-holos/script-02-hello-holos/render.sh';
|
||||
import RegisterComponentsOutput from '!!raw-loader!./_hello-holos/script-02-hello-holos/register-components-output.txt';
|
||||
|
||||
<Tabs groupId="E150C802-7162-4FBF-82A7-77D9ADAEE847">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
holos render platform
|
||||
```
|
||||
<CodeBlock language="bash">{RenderCommand}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```
|
||||
cached podinfo 6.6.2
|
||||
rendered podinfo in 1.938665041s
|
||||
rendered platform in 1.938759417s
|
||||
```
|
||||
<CodeBlock language="txt">{RegisterComponentsOutput}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Holos executes `helm template` with locally cached charts to generate:
|
||||
|
||||
```txt
|
||||
deploy/components/podinfo/podinfo.gen.yaml
|
||||
```
|
||||
import PodinfoRenderedPath from '!!raw-loader!./_hello-holos/script-02-hello-holos/podinfo-rendered-path.sh';
|
||||
import RenderedService from '!!raw-loader!./_hello-holos/script-02-hello-holos/rendered-service.yaml';
|
||||
import RenderedDeployment from '!!raw-loader!./_hello-holos/script-02-hello-holos/rendered-deployment.yaml';
|
||||
|
||||
<CodeBlock language="txt">{PodinfoRenderedPath}</CodeBlock>
|
||||
|
||||
<Tabs groupId="0E9C231D-D0E8-410A-A4A0-601842A086A6">
|
||||
<TabItem value="service" label="Service">
|
||||
```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
|
||||
helm.sh/chart: podinfo-6.6.2
|
||||
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
|
||||
type: ClusterIP
|
||||
```
|
||||
<CodeBlock language="yaml" showLineNumbers>{RenderedService}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="deployment" label="Deployment">
|
||||
```yaml showLineNumbers
|
||||
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
|
||||
helm.sh/chart: podinfo-6.6.2
|
||||
name: podinfo
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/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
|
||||
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_MESSAGE
|
||||
value: Hello Holos!
|
||||
- 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
|
||||
```
|
||||
<CodeBlock language="yaml" showLineNumbers>{RenderedDeployment}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Holos renders the component with the greeting injected from the platform spec.
|
||||
|
||||
```shell
|
||||
grep -B2 Hello deploy/components/podinfo/podinfo.gen.yaml
|
||||
```
|
||||
```yaml
|
||||
env:
|
||||
- name: PODINFO_UI_MESSAGE
|
||||
value: Hello Holos!
|
||||
```
|
||||
import GrepForMessage from '!!raw-loader!./_hello-holos/script-02-hello-holos/grep-for-message.sh';
|
||||
import GreppedOutput from '!!raw-loader!./_hello-holos/script-02-hello-holos/grepped-output.txt';
|
||||
|
||||
<CodeBlock language="bash">{GrepForMessage}</CodeBlock>
|
||||
<CodeBlock language="yaml">{GreppedOutput}</CodeBlock>
|
||||
|
||||
## Breaking it down
|
||||
|
||||
|
||||
19
doc/md/tutorial/hello-holos_test.go
Normal file
19
doc/md/tutorial/hello-holos_test.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Run these with go test -v to see the verbose names
|
||||
func TestHelloHolos(t *testing.T) {
|
||||
t.Run("TestHelloHolos", func(t *testing.T) {
|
||||
// Get an ordered list of test script files.
|
||||
dir := "_hello-holos"
|
||||
for _, file := range sortedTestScripts(t, filepath.Join(dir, "examples")) {
|
||||
t.Run("examples", func(t *testing.T) {
|
||||
runOneScript(t, dir, file)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -7,6 +7,7 @@ sidebar_position: 45
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
# Kustomize
|
||||
|
||||
@@ -24,6 +25,17 @@ covered in the [Helm Values] tutorial.
|
||||
|
||||
## The Code
|
||||
|
||||
### Holos Version
|
||||
|
||||
Ensure you have a current version of `holos` installed. This document was
|
||||
tested with the following version.
|
||||
|
||||
import HolosVersionCommand from '!!raw-loader!./_kustomize/script-01-holos-version/command.sh';
|
||||
import HolosVersionOutput from '!!raw-loader!./_kustomize/script-01-holos-version/output.txt';
|
||||
|
||||
<CodeBlock language="bash">{HolosVersionCommand}</CodeBlock>
|
||||
<CodeBlock language="txt">{HolosVersionOutput}</CodeBlock>
|
||||
|
||||
### Generating the structure
|
||||
|
||||
<Tabs>
|
||||
@@ -39,18 +51,14 @@ Use `holos` to generate a minimal platform directory structure. First, create
|
||||
and navigate into a blank directory. Then, run the `holos init platform`
|
||||
command.
|
||||
|
||||
```shell
|
||||
mkdir holos-kustomize-tutorial
|
||||
cd holos-kustomize-tutorial
|
||||
holos init platform v1alpha5
|
||||
```
|
||||
import MkdirAndInit from '!!raw-loader!./_kustomize/script-02-kustomize/mkdir-and-init.sh';
|
||||
import GitInit from '!!raw-loader!./_kustomize/script-02-kustomize/git-init.sh';
|
||||
|
||||
<CodeBlock language="bash">{MkdirAndInit}</CodeBlock>
|
||||
|
||||
Make a commit to track changes.
|
||||
|
||||
```bash
|
||||
git init . && git add . && git commit -m initial
|
||||
```
|
||||
|
||||
<CodeBlock language="bash">{GitInit}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
@@ -59,97 +67,26 @@ git init . && git add . && git commit -m initial
|
||||
Create the `httpbin` component directory, and add the `httpbin.cue` and
|
||||
`httpbin.yaml` files to it for configuration and setup.
|
||||
|
||||
import MkdirComponent from '!!raw-loader!./_kustomize/script-02-kustomize/mkdir-component.sh';
|
||||
import HttpbinComponentHeader from '!!raw-loader!./_kustomize/script-02-kustomize/httpbin-component-header.sh';
|
||||
import HttpbinComponentBody from '!!raw-loader!./_kustomize/script-02-kustomize/httpbin-component-body.cue';
|
||||
import EofTrailer from '!!raw-loader!./_kustomize/script-02-kustomize/eof-trailer.sh';
|
||||
import HttpbinYamlHeader from '!!raw-loader!./_kustomize/script-02-kustomize/httpbin-yaml-header.sh';
|
||||
import HttpbinYamlBody from '!!raw-loader!./_kustomize/script-02-kustomize/httpbin-yaml-body.yaml';
|
||||
|
||||
<Tabs groupId="800C3AE7-E7F8-4AFC-ABF1-6AFECD945958">
|
||||
<TabItem value="setup" label="Setup">
|
||||
```bash
|
||||
mkdir -p components/httpbin
|
||||
```
|
||||
<CodeBlock language="bash">{MkdirComponent}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="components/httpbin/httpbin.cue" label="httpbin.cue">
|
||||
```bash
|
||||
cat <<EOF > components/httpbin/httpbin.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
// Produce a Kustomize BuildPlan for Holos
|
||||
holos: Kustomize.BuildPlan
|
||||
|
||||
// https://github.com/mccutchen/go-httpbin/blob/v2.15.0/kustomize/README.md
|
||||
Kustomize: #Kustomize & {
|
||||
KustomizeConfig: {
|
||||
// Files tells Holos to copy the file from the component path to the
|
||||
// temporary directory Holos uses for BuildPlan execution.
|
||||
Files: {
|
||||
"httpbin.yaml": _
|
||||
}
|
||||
CommonLabels: {
|
||||
"app.kubernetes.io/name": "httpbin"
|
||||
}
|
||||
// Kustomization represents a kustomization.yaml file in CUE. Holos
|
||||
// marshals this field into a `kustomization.yaml` while processing a
|
||||
// BuildPlan. See
|
||||
// https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/
|
||||
Kustomization: {
|
||||
images: [{name: "mccutchen/go-httpbin"}]
|
||||
// Use a hidden field to compose patches easily with a struct. Hidden
|
||||
// fields are not included in exported structures.
|
||||
_patches: {}
|
||||
// Convert the hidden struct to a list.
|
||||
patches: [for x in _patches {x}]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
<CodeBlock language="bash">{HttpbinComponentHeader}</CodeBlock>
|
||||
<CodeBlock language="cue" showLineNumbers>{HttpbinComponentBody}</CodeBlock>
|
||||
<CodeBlock language="bash">{EofTrailer}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="components/httpbin/httpbin.yaml" label="httpbin.yaml">
|
||||
```bash
|
||||
cat <<EOF > components/httpbin/httpbin.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
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
<CodeBlock language="bash">{HttpbinYamlHeader}</CodeBlock>
|
||||
<CodeBlock language="yaml" showLineNumbers>{HttpbinYamlBody}</CodeBlock>
|
||||
<CodeBlock language="bash">{EofTrailer}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
@@ -161,56 +98,38 @@ Holos knows the `httpbin.yaml` file is part of the BuildPlan because of the
|
||||
Register `httpbin` with the platform by adding the following file to the
|
||||
platform directory.
|
||||
|
||||
```bash
|
||||
cat <<EOF > platform/httpbin.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
import RegisterComponentHeader from '!!raw-loader!./_kustomize/script-02-kustomize/register-component-header.sh';
|
||||
import RegisterComponentBody from '!!raw-loader!./_kustomize/script-02-kustomize/register-component-body.cue';
|
||||
|
||||
Platform: Components: {
|
||||
httpbin: {
|
||||
name: "httpbin"
|
||||
path: "components/httpbin"
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
<CodeBlock language="bash">{RegisterComponentHeader}</CodeBlock>
|
||||
<CodeBlock language="cue">{RegisterComponentBody}</CodeBlock>
|
||||
<CodeBlock language="bash">{EofTrailer}</CodeBlock>
|
||||
|
||||
Render the platform.
|
||||
|
||||
import RenderCommand from '!!raw-loader!./_kustomize/script-02-kustomize/render.sh';
|
||||
import RegisterComponentOutput from '!!raw-loader!./_kustomize/script-02-kustomize/register-component-output.txt';
|
||||
|
||||
<Tabs groupId="B120D5D1-0EAB-41E0-AD21-15526EBDD53D">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
holos render platform
|
||||
```
|
||||
<CodeBlock language="bash">{RenderCommand}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```txt
|
||||
rendered httpbin in 707.554666ms
|
||||
rendered platform in 707.9845ms
|
||||
```
|
||||
<CodeBlock language="txt">{RegisterComponentOutput}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Commit the results.
|
||||
|
||||
import GitCommitComponent from '!!raw-loader!./_kustomize/script-02-kustomize/git-commit-component.sh';
|
||||
import GitCommitComponentOutput from '!!raw-loader!./_kustomize/script-02-kustomize/git-commit-component-output.txt';
|
||||
|
||||
<Tabs groupId="446CC550-A634-45C0-BEC7-992E5C56D4FA">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
git add . && git commit -m 'add httpbin'
|
||||
```
|
||||
<CodeBlock language="bash">{GitCommitComponent}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```txt
|
||||
[main c05f9ef] add httpbin
|
||||
4 files changed, 118 insertions(+)
|
||||
create mode 100644 components/httpbin/httpbin.cue
|
||||
create mode 100644 components/httpbin/httpbin.yaml
|
||||
create mode 100644 deploy/components/httpbin/httpbin.gen.yaml
|
||||
create mode 100644 platform/httpbin.cue
|
||||
```
|
||||
<CodeBlock language="txt">{GitCommitComponentOutput}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
@@ -220,55 +139,15 @@ We can see the [BuildPlan] exported to `holos` by the `holos:
|
||||
Kustomize.BuildPlan` line in `httpbin.cue`. Holos processes this build plan to
|
||||
produce the fully rendered manifests.
|
||||
|
||||
import CueExport from '!!raw-loader!./_kustomize/script-02-kustomize/cue-export.sh';
|
||||
import BuildplanOutput from '!!raw-loader!./_kustomize/script-02-kustomize/buildplan-output.cue';
|
||||
|
||||
<Tabs groupId="DD697D65-5BEC-4B92-BB33-59BE4FEC112F">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
holos cue export --expression holos --out=yaml ./components/httpbin
|
||||
```
|
||||
<CodeBlock language="bash">{CueExport}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```yaml showLineNumbers
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: no-name
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: components/no-name/no-name.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
resources: {}
|
||||
- kind: File
|
||||
output: httpbin.yaml
|
||||
file:
|
||||
source: httpbin.yaml
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- resources.gen.yaml
|
||||
- httpbin.yaml
|
||||
output: components/no-name/no-name.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
labels:
|
||||
- includeSelectors: false
|
||||
pairs:
|
||||
app.kubernetes.io/name: httpbin
|
||||
patches: []
|
||||
images:
|
||||
- name: mccutchen/go-httpbin
|
||||
resources:
|
||||
- resources.gen.yaml
|
||||
- httpbin.yaml
|
||||
kind: Kustomization
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
source:
|
||||
component:
|
||||
name: no-name
|
||||
path: no-path
|
||||
parameters: {}
|
||||
```
|
||||
<CodeBlock language="yaml">{BuildplanOutput}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
@@ -291,30 +170,12 @@ need to edit any YAML files manually.
|
||||
Add a new `patches.cue` file to the `httpbin` component with the following
|
||||
content.
|
||||
|
||||
```bash
|
||||
cat <<EOF > components/httpbin/patches.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
import HttpbinPatchHeader from '!!raw-loader!./_kustomize/script-02-kustomize/httpbin-patch-header.sh';
|
||||
import HttpbinPatchBody from '!!raw-loader!./_kustomize/script-02-kustomize/httpbin-patch-body.cue';
|
||||
|
||||
import "encoding/yaml"
|
||||
|
||||
// Mix in a Kustomize patch to the configuration.
|
||||
Kustomize: KustomizeConfig: Kustomization: _patches: {
|
||||
probe: {
|
||||
target: kind: "Service"
|
||||
target: name: "httpbin"
|
||||
patch: yaml.Marshal([{
|
||||
op: "add"
|
||||
path: "/metadata/annotations/prometheus.io~1probe"
|
||||
value: "true"
|
||||
}])
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
<CodeBlock language="bash">{HttpbinPatchHeader}</CodeBlock>
|
||||
<CodeBlock language="bash" showLineNumbers>{HttpbinPatchBody}</CodeBlock>
|
||||
<CodeBlock language="bash">{EofTrailer}</CodeBlock>
|
||||
|
||||
:::note
|
||||
We use a hidden `_patches` field to easily unify data into a struct, then
|
||||
@@ -325,62 +186,43 @@ convert the struct into a list for export.
|
||||
|
||||
Render the platform to see the result of the kustomization patch.
|
||||
|
||||
import KustomizePatchRenderOutput from '!!raw-loader!./_kustomize/script-02-kustomize/kustomize-patch-render-output.txt';
|
||||
|
||||
<Tabs groupId="5D1812DD-8E7B-4F97-B349-275214F38B6E">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
holos render platform
|
||||
```
|
||||
<CodeBlock language="bash">{RenderCommand}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```txt
|
||||
rendered httpbin in 197.030208ms
|
||||
rendered platform in 197.416416ms
|
||||
```
|
||||
<CodeBlock language="txt">{KustomizePatchRenderOutput}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Holos is configuring Kustomize to patch the plain `httpbin.yaml` file with the
|
||||
annotation.
|
||||
|
||||
import GitDiff from '!!raw-loader!./_kustomize/script-02-kustomize/git-diff.sh';
|
||||
import GitDiffOutput from '!!raw-loader!./_kustomize/script-02-kustomize/git.diff';
|
||||
|
||||
<Tabs groupId="3D80279E-8EDE-4B3E-9269-50F5D1C1CA42">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
git diff
|
||||
```
|
||||
<CodeBlock language="bash">{GitDiff}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```diff
|
||||
diff --git a/deploy/components/httpbin/httpbin.gen.yaml b/deploy/components/httpbin/httpbin.gen.yaml
|
||||
index 298b9a8..a16bd1a 100644
|
||||
--- a/deploy/components/httpbin/httpbin.gen.yaml
|
||||
+++ b/deploy/components/httpbin/httpbin.gen.yaml
|
||||
@@ -1,6 +1,8 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
+ annotations:
|
||||
+ prometheus.io/probe: "true"
|
||||
labels:
|
||||
app.kubernetes.io/name: httpbin
|
||||
name: httpbin
|
||||
|
||||
```
|
||||
<CodeBlock language="diff">{GitDiffOutput}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Add and commit the final changes.
|
||||
|
||||
import GitCommitFinal from '!!raw-loader!./_kustomize/script-02-kustomize/git-commit-final.sh';
|
||||
import GitCommitFinalOutput from '!!raw-loader!./_kustomize/script-02-kustomize/git-commit-final-output.txt';
|
||||
|
||||
<Tabs groupId="54C335C8-B382-4277-AE87-0D6556921955">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
git add . && git commit -m 'annotate httpbin for prometheus probes'
|
||||
```
|
||||
<CodeBlock language="bash">{GitCommitFinal}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```txt
|
||||
[main 6eeeadb] annotate httpbin for prometheus probes
|
||||
2 files changed, 3 insertions(+), 1 deletion(-)
|
||||
```
|
||||
<CodeBlock language="txt">{GitCommitFinalOutput}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
|
||||
19
doc/md/tutorial/kustomize_test.go
Normal file
19
doc/md/tutorial/kustomize_test.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Run these with go test -v to see the verbose names
|
||||
func TestKustomize(t *testing.T) {
|
||||
t.Run("TestKustomize", func(t *testing.T) {
|
||||
// Get an ordered list of test script files.
|
||||
dir := "_kustomize"
|
||||
for _, file := range sortedTestScripts(t, filepath.Join(dir, "examples")) {
|
||||
t.Run("examples", func(t *testing.T) {
|
||||
runOneScript(t, dir, file)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,752 +0,0 @@
|
||||
---
|
||||
unlisted: true
|
||||
slug: simplify-helm-value-files-with-unification
|
||||
title: Simplify Helm Value Files with Unification
|
||||
authors: [jeff]
|
||||
tags: [holos, helm, gitops]
|
||||
# image: /img/cards/validators.png
|
||||
description: Migrate an ApplicationSet to the rendered manifest pattern with Holos, removing unnecessary complexity.
|
||||
keywords:
|
||||
- Holos
|
||||
- CUE
|
||||
- Configuration
|
||||
- Kubernetes
|
||||
- Hydrated
|
||||
- Rendered
|
||||
- Manifest
|
||||
- Pattern
|
||||
- Rendered Manifest Pattern
|
||||
- Unification
|
||||
- ArgoCD
|
||||
- ApplicationSet
|
||||
- Application
|
||||
- Multi Source
|
||||
- Values
|
||||
- Hierarchy
|
||||
- Merge
|
||||
- Override
|
||||
- GitOps
|
||||
- Complexity
|
||||
---
|
||||
|
||||
## Simplifying a Hierarchy
|
||||
|
||||
In [Part 1] of our series on migrating a complex multi environment
|
||||
ApplicationSet to Holos we reduced complexity by replacing the ApplicationSet Go
|
||||
template generator with an Application resource exported from CUE. We completed
|
||||
the migration to implement the rendered manifest pattern, but complexity remains
|
||||
in the 5 layers of Helm value file overrides.
|
||||
|
||||
We'll continue eliminating accidental complexity by refactoring the Helm value
|
||||
file hierarchy into one unified layer. The data will be visible and within
|
||||
reach through the command line. Any future changes will either unify
|
||||
successfully or produce an immediate error, significantly reducing the
|
||||
complexity of managing Kubernetes by eliminating the accidental complexity of a
|
||||
Helm value hierarchy.
|
||||
|
||||
[Part 1]: ./2025-01-13-replace-an-applicationset-with-the-rendered-manifest-pattern.mdx
|
||||
|
||||
{/* truncate */}
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
### Why are overrides a problem?
|
||||
|
||||
Consider this snippet form the [original ApplicationSet] we migrated:
|
||||
|
||||
```yaml
|
||||
helm:
|
||||
valueFiles:
|
||||
- $values/my-values/common-values.yaml
|
||||
- $values/my-values/app-version/{{.version}}-values.yaml
|
||||
- $values/my-values/env-type/{{.type}}-values.yaml
|
||||
- $values/my-values/regions/{{.region}}-values.yaml
|
||||
- $values/my-values/envs/{{.env}}-values.yaml
|
||||
```
|
||||
|
||||
Both Holos and ArgoCD pass these value files to Helm in order, resulting in the
|
||||
following Helm command:
|
||||
|
||||
```bash
|
||||
helm template my-chart \
|
||||
-f my-values/common-values.yaml \
|
||||
-f my-values/app-version/prod-values.yaml \
|
||||
-f my-values/env-type/prod-values.yaml \
|
||||
-f my-values/regions/us-values.yaml \
|
||||
-f my-values/envs/prod-us-values.yaml \
|
||||
...
|
||||
```
|
||||
|
||||
Helm merges each of the value files on top of one another in a last in first out
|
||||
manner. Imagine we're troubleshooting an issue where the Deployment in the live
|
||||
system has `replicas: 3` but it should have `replicas: 5`. We need to
|
||||
reconfigure the replicas.
|
||||
|
||||
1. **It's unclear where the `replicas: 3` value came from** when looking at the live system.
|
||||
2. **It's unclear if or where `replicaCount` is used** when looking at each value file.
|
||||
3. **It's unclear where we need to set a value of `5` to fix the problem.** Common
|
||||
values would probably affect too many deployments. Prod-us values would likely
|
||||
be too specific, missing other prod environments.
|
||||
4. **Complexity accumulates over time.** Each time we make a change we're invited
|
||||
to add a new level of overrides. If we're adding a value that's not broad
|
||||
enough at one level, but too broad at the next level, then we have no choice but
|
||||
to add one more level in between.
|
||||
5. **It's difficult to see the actual values passed to Helm.** We have to implement
|
||||
the last in first out merge algorithm in our head as we page through each file,
|
||||
an extremely error prone chore.
|
||||
|
||||
For example, `common-values.yaml` has `replicaCount: 1`. Is that value actually
|
||||
used anywhere? The only way to know is to walk through all permutations and
|
||||
determine if it's overridden or not. Spoiler, `common-values.yaml` is _always_
|
||||
overridden in the original ApplicationSet we migrated. It serves no purpose,
|
||||
yet it lays a hidden trap for us to trip over in the future. If we remove a
|
||||
value overriding common-values.yaml then we don't know if the freshly uncovered
|
||||
value had an important purpose relevant now or if it no longer serves a purpose.
|
||||
|
||||
This particular form of override hierarchy is similar to inheritance, suffering
|
||||
from the same problems. The central concept of unification in CUE elegantly
|
||||
solves these problems.
|
||||
|
||||
> Like with other configuration languages, CUE can add complexity if values are organized to come from multiple places. However, as CUE disallows overrides, deep layerings are naturally prevented. More importantly, CUE can also enhance readability. A definition in one file may apply to values in many other files. Where one would usually have to open all these files to verify validity; with CUE one can see it at a glance.
|
||||
|
||||
Attribution: [Simplicity at Scale](https://cuelang.org/docs/concept/configuration-use-case/#simplicity-at-scale)
|
||||
|
||||
> Inheritance is not commutative and idempotent in the general case. In other words, order matters. This makes it hard to track where values are coming from. This is not only true for humans, but also machines. It makes it very complicated, if not impossible, to do any kind of automation.
|
||||
>
|
||||
> The basic operation of CUE is commutative, associative and idempotent. This order independence helps both humans and machines. The resulting model is much less complex.
|
||||
|
||||
Attribution: [Inheritance-based configuration languages](https://cuelang.org/docs/concept/configuration-use-case/#inheritance-based-configuration-languages)
|
||||
|
||||
In CUE, **order is irrelevant**. This property greatly simplifies configuration
|
||||
as we'll see by unifying these value files.
|
||||
|
||||
### What's the desired outcome?
|
||||
|
||||
For this refactoring, we'd like to achieve the following goals:
|
||||
|
||||
1. Prune unused values.
|
||||
2. Reduce the five layers of abstraction down to one.
|
||||
3. Gain insight into the values passed into Helm.
|
||||
4. Fail fast if a future change creates a conflict.
|
||||
5. Fail fast if a necessary value is not provided.
|
||||
6. Prevent complex layers of abstraction from accumulating.
|
||||
7. Add type checks, schema validation, and constraints to Helm values.
|
||||
|
||||
### Starting Context
|
||||
|
||||
If you didn't work through [Part 1] the final results are available in the
|
||||
[end-of-part-1] branch for your reference.
|
||||
|
||||
### Pruning Unused Values
|
||||
|
||||
We need a way to identify which values are used so we can prune the unused ones.
|
||||
Holos simplifies this task by rendering all of the manifests to the local
|
||||
filesystem. We can simply grep the deploy directory to see what values are
|
||||
actually used.
|
||||
|
||||
import GrepReplicasCmd from '!!raw-loader!./_migrate_appset/script-06-unification/grep.sh';
|
||||
import GrepReplicasOut from '!!raw-loader!./_migrate_appset/script-06-unification/grep.txt';
|
||||
|
||||
<Tabs groupId="grep-replicas">
|
||||
<TabItem value="Command" label="Command">
|
||||
<CodeBlock language="bash">{GrepReplicasCmd}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Output" label="Output">
|
||||
<CodeBlock language="txt">{GrepReplicasOut}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
The `grep` output indicates **3, 8 and 10** are the only values used, yet
|
||||
`common-values.yaml` configures a value of 1.
|
||||
|
||||
import CommonPath from '!!raw-loader!./_migrate_appset/script-06-unification/common.path';
|
||||
import CommonYAML from '!!raw-loader!./_migrate_appset/script-06-unification/common.yaml';
|
||||
|
||||
<CodeBlock language="txt">{CommonPath}</CodeBlock>
|
||||
<CodeBlock language="yaml" showLineNumbers>{CommonYAML}</CodeBlock>
|
||||
|
||||
The `common-values.yaml` file is therefore useless. Let's remove it.
|
||||
|
||||
import RemoveHead from '!!raw-loader!./_migrate_appset/script-06-unification/remove.head';
|
||||
import RemoveBody from '!!raw-loader!./_migrate_appset/script-06-unification/remove.body';
|
||||
import RemoveTail from '!!raw-loader!./_migrate_appset/script-06-unification/remove.tail';
|
||||
import RemoveOut from '!!raw-loader!./_migrate_appset/script-06-unification/remove.out';
|
||||
|
||||
<Tabs groupId="remove-common-values">
|
||||
<TabItem value="Command" label="Command">
|
||||
<CodeBlock language="bash">{RemoveHead}</CodeBlock>
|
||||
<CodeBlock language="diff" showLineNumbers>{RemoveBody}</CodeBlock>
|
||||
<CodeBlock language="bash">{RemoveTail}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Output" label="Output">
|
||||
<CodeBlock language="txt">{RemoveOut}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
We double check by rendering the platform. There should be no changes to the
|
||||
deploy directory even though we removed `common-values.yaml` from the Helm
|
||||
hierarchy.
|
||||
|
||||
import RenderCmd from '!!raw-loader!./_migrate_appset/script-06-unification/render.sh';
|
||||
import RenderOut from '!!raw-loader!./_migrate_appset/script-06-unification/render.txt';
|
||||
|
||||
<Tabs groupId="render-command">
|
||||
<TabItem value="Command" label="Command">
|
||||
<CodeBlock language="bash">{RenderCmd}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Output" label="Output">
|
||||
<CodeBlock language="txt">{RenderOut}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
import CheckCmd from '!!raw-loader!./_migrate_appset/script-06-unification/check.sh';
|
||||
import CheckOut from '!!raw-loader!./_migrate_appset/script-06-unification/check.txt';
|
||||
|
||||
<Tabs groupId="git-status">
|
||||
<TabItem value="Command" label="Command">
|
||||
<CodeBlock language="bash">{CheckCmd}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Output" label="Output">
|
||||
<CodeBlock language="txt">{CheckOut}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::tip
|
||||
Holos makes it easier to confidently remove values which are never used.
|
||||
:::
|
||||
|
||||
If we didn't have the rendered manifests in hand this would be a much more
|
||||
difficult task.
|
||||
|
||||
### Eliminating Complexity
|
||||
|
||||
Let's unify all the levels of the value hierarchy into one layer and see where
|
||||
the conflicts are. This is straight forward with `holos`.
|
||||
|
||||
:::important
|
||||
One unified layer is significantly less complicated than a hierarchy of
|
||||
overrides.
|
||||
:::
|
||||
|
||||
import UnifyHead from '!!raw-loader!./_migrate_appset/script-06-unification/unify.head';
|
||||
import UnifyBody from '!!raw-loader!./_migrate_appset/script-06-unification/unify.body';
|
||||
import UnifyTail from '!!raw-loader!./_migrate_appset/script-06-unification/unify.tail';
|
||||
import UnifyOut from '!!raw-loader!./_migrate_appset/script-06-unification/unify.out';
|
||||
|
||||
<Tabs groupId="unify-values">
|
||||
<TabItem value="Command" label="Command">
|
||||
<CodeBlock language="bash">{UnifyHead}</CodeBlock>
|
||||
<CodeBlock language="diff" showLineNumbers>{UnifyBody}</CodeBlock>
|
||||
<CodeBlock language="bash">{UnifyTail}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Output" label="Output">
|
||||
<CodeBlock language="txt">{UnifyOut}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::important
|
||||
The 4 ordered list elements convert into one unified struct.
|
||||
:::
|
||||
|
||||
Render all components to see conflicting values. We use concurrency 1 to return
|
||||
the first error encountered.
|
||||
|
||||
import Render2Cmd from '!!raw-loader!./_migrate_appset/script-06-unification/render2.sh';
|
||||
import Render2Out from '!!raw-loader!./_migrate_appset/script-06-unification/render2.txt';
|
||||
|
||||
<Tabs groupId="render2-command">
|
||||
<TabItem value="Command" label="Command">
|
||||
<CodeBlock language="bash">{Render2Cmd}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Output" label="Output">
|
||||
<CodeBlock language="txt">{Render2Out}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
The `prod-eu` environment has a conflict:
|
||||
|
||||
```txt
|
||||
values.replicaCount: conflicting values 8 and 5
|
||||
```
|
||||
|
||||
The error is detailed, helpfully listing all of the potential locations the
|
||||
conflict may arise from. We can hone in on the yaml files in the `my-values`
|
||||
directory:
|
||||
|
||||
1. my-values/env-type/prod-values.yaml:2:15
|
||||
2. my-values/envs/prod-eu-values.yaml:2:15
|
||||
|
||||
These files we originally migrated without modifying them are:
|
||||
|
||||
import ConflictA from '!!raw-loader!./_migrate_appset/script-06-unification/conflict/prod-values.yaml';
|
||||
import ConflictB from '!!raw-loader!./_migrate_appset/script-06-unification/conflict/prod-eu-values.yaml';
|
||||
|
||||
<Tabs groupId="conflict-files">
|
||||
<TabItem value="prod-values.yaml" label="prod-values.yaml">
|
||||
<CodeBlock language="yaml" showLineNumbers>{ConflictA}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="prod-eu-values.yaml" label="prod-eu-values.yaml">
|
||||
<CodeBlock language="yaml" showLineNumbers>{ConflictB}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::important
|
||||
The conflict arises from the original article specifying a value for the same
|
||||
field along two different aspects of our configuration: specific environments
|
||||
(envs) and broad types of environments (env-types).
|
||||
:::
|
||||
|
||||
### Resolving Conflicts
|
||||
|
||||
In Holos and CUE we resolve these conflicts by picking one aspect to specify a
|
||||
given field value. We'll pick specific environments in this case because it's
|
||||
not too broad and not too specific.
|
||||
|
||||
We previously determined **3, 8 and 10** are the only values actually used in
|
||||
the final configurations, so we already know `replicaCount: 5` in the
|
||||
`my-values/env-type/prod-values.yaml` file is useless.
|
||||
|
||||
Let's remove it.
|
||||
|
||||
import Unify2Head from '!!raw-loader!./_migrate_appset/script-06-unification/unify2.head';
|
||||
import Unify2Body from '!!raw-loader!./_migrate_appset/script-06-unification/unify2.body';
|
||||
import Unify2Tail from '!!raw-loader!./_migrate_appset/script-06-unification/unify2.tail';
|
||||
import Unify2Out from '!!raw-loader!./_migrate_appset/script-06-unification/unify2.out';
|
||||
|
||||
<Tabs groupId="unify2-values">
|
||||
<TabItem value="Command" label="Command">
|
||||
<CodeBlock language="bash">{Unify2Head}</CodeBlock>
|
||||
<CodeBlock language="diff" showLineNumbers>{Unify2Body}</CodeBlock>
|
||||
<CodeBlock language="bash">{Unify2Tail}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Output" label="Output">
|
||||
<CodeBlock language="txt">{Unify2Out}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Now we can render the platform again and verify there are no changes to the
|
||||
rendered manifests in the `deploy` directory.
|
||||
|
||||
import Render3Cmd from '!!raw-loader!./_migrate_appset/script-06-unification/render3.sh';
|
||||
import Render3Out from '!!raw-loader!./_migrate_appset/script-06-unification/render3.txt';
|
||||
|
||||
<Tabs groupId="render3-command">
|
||||
<TabItem value="Command" label="Command">
|
||||
<CodeBlock language="bash">{Render3Cmd}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Output" label="Output">
|
||||
<CodeBlock language="txt">{Render3Out}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
import Status3Cmd from '!!raw-loader!./_migrate_appset/script-06-unification/status3.sh';
|
||||
import Status3Out from '!!raw-loader!./_migrate_appset/script-06-unification/status3.txt';
|
||||
|
||||
<Tabs groupId="status3-command">
|
||||
<TabItem value="Command" label="Command">
|
||||
<CodeBlock language="bash">{Status3Cmd}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Output" label="Output">
|
||||
<CodeBlock language="txt">{Status3Out}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Voila! We've successfully refactored all of the value files for Helm into a
|
||||
single unified data structure. We know we're done because unification succeeds
|
||||
and there are no changes to the deploy directory.
|
||||
|
||||
## Simplifying a Complex Hierarchy
|
||||
|
||||
We've removed the complexity of the Go template in the ApplicationSet, and 5
|
||||
more layers of complexity in the Helm value files, but the original data didn't
|
||||
have many overrides. It was the best case scenario, flattening the hierarchy by
|
||||
trial and error was straight forward.
|
||||
|
||||
What about a complex hierarchy with lots of overrides? This same trial and
|
||||
error approach would take too long. Holos offers a solution in this scenario.
|
||||
In this section we'll use `holos` to create a flattened value file for each of
|
||||
the config.json deployment configs without using trial and error.
|
||||
|
||||
The layout of the deployment configs is a key aspect of this method. The
|
||||
deployment config inputs always map 1:1 to the rendered manifests and associated
|
||||
Application resource. Therefore, any intermediate layers of overrides are not
|
||||
strictly necessary, an opportunity to reduce complexity significantly.
|
||||
|
||||
In this example the deployment configs are organized by customer and cluster, so
|
||||
we'll work to flatten the unnecessary levels of the hierarchy while also
|
||||
organizing the output around customers and clusters to get everything lined up
|
||||
nicely.
|
||||
|
||||
Using the same deployment configs at each step, we'll:
|
||||
|
||||
1. Render my-app using the helm values hierarchy to get a reference point.
|
||||
2. Render a special chart, render-values, to flatten the value files hierarchy into one file.
|
||||
3. Render my-app using the flattened values file.
|
||||
4. Verify there are no changes to the deploy artifacts.
|
||||
|
||||
We'll be able to quickly locate and read the configuration given a customer and
|
||||
a cluster.
|
||||
|
||||
### What's the worst case scenario?
|
||||
|
||||
In the worst case scenario there is little rhyme or reason to how values are set
|
||||
and overridden in a hierarchy. We'll start with this worst case scenario,
|
||||
spraying data across clusters and override layers. This starting point looks
|
||||
like the following, with the highest precedence values at the top of the table.
|
||||
|
||||
| Num | Layer | Description |
|
||||
| - | - | - |
|
||||
| 1 | Customer | customer-zzsbbmfc, customer-xxxxxxx, ... |
|
||||
| 2 | Namespace | prod-myapp, dev-myapp, ... |
|
||||
| 3 | Application | myapp, yourapp, ... |
|
||||
| 4 | Cluster | prod1-customer, dev2-internal, uat3-management, ... |
|
||||
| 5 | Environment | prod, uat, test, dev |
|
||||
| 6 | Tier | prod, nonprod |
|
||||
| 7 | Scope | customer, internal, management |
|
||||
| 8 | Zone | us-east1-a, us-east1-b, ... |
|
||||
| 9 | Region | us-east1, us-west1, ... |
|
||||
| 10 | Location | us, eu, ap, ... |
|
||||
| 11 | Common | Base layer |
|
||||
|
||||
Across these layers the following fields may be set:
|
||||
|
||||
| Field | Type | Description |
|
||||
| - | - | - |
|
||||
| enabled | bool | Feature flag |
|
||||
| image | string | Container image URI, e.g. "oci://example.com/myservice" |
|
||||
| version | string | Version string, e.g. "v0.1.0" |
|
||||
| domain | string | DNS domain, e.g. "example.com" |
|
||||
| replicas | int | number of replicas |
|
||||
| clientID | string | OAuth 2.0 client ID |
|
||||
| issuer | string | OIDC issuer uri, e.g. `https://login.example.com` |
|
||||
| projectID | string | cloud project id, e.g. "my-project-123456" |
|
||||
| accountID | int | cloud account id, e.g. 012345678901 |
|
||||
| arn | string | resource name, e.g. "arn:partition:service:region:account-id:resource-type:resource-id" |
|
||||
| cores | float | cpu cores, e.g. 2.0 |
|
||||
| memory | int | memory in MiB, e.g. 2048 |
|
||||
| labels | map[string]string | resource labels |
|
||||
|
||||
### Generating complexity
|
||||
|
||||
Generate the deployment configs and the value files. The RNG is seeded with
|
||||
constant values so the output is deterministic. If you'd like truly random data
|
||||
set `RANDOMIZE=1` in the environment before running this command..
|
||||
|
||||
import GeneratorCmd from '!!raw-loader!./_migrate_appset/script-08-complex-unification/generator.sh';
|
||||
|
||||
<CodeBlock language="bash">{GeneratorCmd}</CodeBlock>
|
||||
|
||||
{/* Show the generated structure */}
|
||||
|
||||
Deployment configs are generated in the following directory. The `config`
|
||||
directory contains concrete values by convention, organized in packages.
|
||||
|
||||
import ShowDeploymentConfigsCmd from '!!raw-loader!./_migrate_appset/script-08-complex-unification/show-deployment-configs.sh';
|
||||
import ShowDeploymentConfigsOut from '!!raw-loader!./_migrate_appset/script-08-complex-unification/show-deployment-configs.txt';
|
||||
|
||||
<CodeBlock language="bash">{ShowDeploymentConfigsCmd}</CodeBlock>
|
||||
<CodeBlock language="txt">{ShowDeploymentConfigsOut}</CodeBlock>
|
||||
|
||||
Each of these {ShowDeploymentConfigsOut} deployment config files map 1:1 to a
|
||||
`holos` `BuildPlan` and an ArgoCD `Application`.
|
||||
|
||||
The Helm value files hierarchy files are written into the `my-app` component
|
||||
directory. By convention values reside in the component directory so they're
|
||||
closely associated with the helm chart using them.
|
||||
|
||||
import ShowValueFilesCmd from '!!raw-loader!./_migrate_appset/script-08-complex-unification/show-value-files.sh';
|
||||
import ShowValueFilesOut from '!!raw-loader!./_migrate_appset/script-08-complex-unification/show-value-files.txt';
|
||||
|
||||
<Tabs groupId="show-value-files">
|
||||
<TabItem value="Command" label="Command">
|
||||
<CodeBlock language="bash">{ShowValueFilesCmd}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Output" label="Output">
|
||||
<CodeBlock language="txt">{ShowValueFilesOut}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### Flattening Step 1
|
||||
|
||||
We'll use CUE build tags to render `my-app` instead of `my-chart` for this
|
||||
example. Build tags alow us to exclude files used in the previous example, like
|
||||
`platform/my-chart.cue`, and include files for this example like
|
||||
`platform/my-app.cue`.
|
||||
|
||||
This example is about flattening the helm values file, so we use `-t flatten`.
|
||||
There are three steps to flatten the hierarchy, so we'll use `-t stepX` for each
|
||||
step along the way.
|
||||
|
||||
Finally, we'll use selectors to focus on one customer specifically. It takes a
|
||||
few minutes (about 4 on my machine) to render all {ShowDeploymentConfigsOut}
|
||||
deployments for all customers, so we can develop and test the migration process
|
||||
quickly with one customer, then roll the change out to all customers once we're
|
||||
ready.
|
||||
|
||||
Let's take a look at one `BuildPlan` for one customer. Take note of the
|
||||
valueFiles hierarchy in the output. Our goal is to reduce complexity by
|
||||
collapsing this down to one layer with at most one override of a default value.
|
||||
|
||||
First, set the customer as a variable:
|
||||
|
||||
```bash
|
||||
export CUSTOMER="customer-zzsbbmfc"
|
||||
```
|
||||
|
||||
import ShowOneBuildPlanCmd from '!!raw-loader!./_migrate_appset/script-08-complex-unification/show-one-buildplan.sh';
|
||||
import ShowOneBuildPlanOut from '!!raw-loader!./_migrate_appset/script-08-complex-unification/show-one-buildplan.txt';
|
||||
|
||||
<Tabs groupId="show-one-buildplan">
|
||||
<TabItem value="Command" label="Command">
|
||||
<CodeBlock language="bash">{ShowOneBuildPlanCmd}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Output" label="Output">
|
||||
<CodeBlock language="yaml" showLineNumbers>{ShowOneBuildPlanOut}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
The other `BuildPlan` specifications are similar. Values are randomly
|
||||
distributed through the hierarchy making it a challenge to comprehend which
|
||||
value is used in the final configuration.
|
||||
|
||||
Render the final manifests for this customer so we have a reference point for
|
||||
the rest of the migration.
|
||||
|
||||
import RenderOneCustomerCmd from '!!raw-loader!./_migrate_appset/script-08-complex-unification/render-one-customer.sh';
|
||||
import RenderOneCustomerOut from '!!raw-loader!./_migrate_appset/script-08-complex-unification/render-one-customer.txt';
|
||||
|
||||
<Tabs groupId="render-one-customer">
|
||||
<TabItem value="Command" label="Command">
|
||||
<CodeBlock language="bash">{RenderOneCustomerCmd}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Output" label="Output">
|
||||
<CodeBlock language="txt">{RenderOneCustomerOut}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Add and commit these changes so we can easily see any future changes. For the
|
||||
rest of the migration there should be no changes to the final configuration.
|
||||
|
||||
import AddCommitStep1Cmd from '!!raw-loader!./_migrate_appset/script-08-complex-unification/add-and-commit-step1.sh';
|
||||
import AddCommitStep1Out from '!!raw-loader!./_migrate_appset/script-08-complex-unification/add-and-commit-step1.txt';
|
||||
|
||||
<Tabs groupId="add-commit-step1">
|
||||
<TabItem value="Command" label="Command">
|
||||
<CodeBlock language="bash">{AddCommitStep1Cmd}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Output" label="Output">
|
||||
<CodeBlock language="txt">{AddCommitStep1Out}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### Flattening Step 2
|
||||
|
||||
Now that we have a reference point we can use `holos` to flatten the hierarchy.
|
||||
We'll pass the same value files to a special `render-values` chart that simply
|
||||
echos back the final merged values. Holos writes the value files to
|
||||
`deploy/values` organized by customer and cluster to match the organization of
|
||||
the source deployment configs, the `config.json` files.
|
||||
|
||||
import RenderStep2Cmd from '!!raw-loader!./_migrate_appset/script-08-complex-unification/render-step2.sh';
|
||||
import RenderStep2Out from '!!raw-loader!./_migrate_appset/script-08-complex-unification/render-step2.txt';
|
||||
|
||||
<Tabs groupId="render-step2">
|
||||
<TabItem value="Command" label="Command">
|
||||
<CodeBlock language="bash">{RenderStep2Cmd}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Output" label="Output">
|
||||
<CodeBlock language="txt">{RenderStep2Out}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This command produces flattened `values.yaml` files for each one of the input
|
||||
deployment configs.
|
||||
|
||||
import ShowFlattenedValuesCmd from '!!raw-loader!./_migrate_appset/script-08-complex-unification/show-flattened-values.sh';
|
||||
import ShowFlattenedValuesOut from '!!raw-loader!./_migrate_appset/script-08-complex-unification/show-flattened-values.txt';
|
||||
|
||||
<Tabs groupId="show-flattened-values">
|
||||
<TabItem value="Command" label="Command">
|
||||
<CodeBlock language="bash">{ShowFlattenedValuesCmd}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Output" label="Output">
|
||||
<CodeBlock language="txt">{ShowFlattenedValuesOut}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Now we can proceed to change the `my-app` Holos component to use these flattened
|
||||
values in place of the value files hierarchy.
|
||||
|
||||
### Flattening Step 3
|
||||
|
||||
The final step of the migration is to use the flattened values in place of the
|
||||
complex hierarchy. In the component definition we replace the use of
|
||||
`valueFiles` with one `values` struct.
|
||||
|
||||
Normally we'd move the `deploy/values` directory into `components/my-app`, but
|
||||
for the article we use a symlink instead: `components/my-app/flattened-values ->
|
||||
../../deploy/values`
|
||||
|
||||
Here's how the final `BuildPlan` looks. Note how the values are flattened and
|
||||
the complexity of the override layers are gone.
|
||||
|
||||
import Step3ShowOneBuildPlanCmd from '!!raw-loader!./_migrate_appset/script-09-step3/show-one-buildplan.sh';
|
||||
import Step3ShowOneBuildPlanOut from '!!raw-loader!./_migrate_appset/script-09-step3/show-one-buildplan.txt';
|
||||
|
||||
<Tabs groupId="step3-show-one-buildplan">
|
||||
<TabItem value="Command" label="Command">
|
||||
<CodeBlock language="bash">{Step3ShowOneBuildPlanCmd}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Output" label="Output">
|
||||
<CodeBlock language="yaml" showLineNumbers>{Step3ShowOneBuildPlanOut}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Step 1" label="Step 1 Comparison">
|
||||
This is the previous BuildPlan from Step 1 for comparison.
|
||||
<CodeBlock language="yaml" showLineNumbers>{ShowOneBuildPlanOut}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Render the platform to ensure we're producing the same output as we did when we
|
||||
started in step 1.
|
||||
|
||||
import RenderStep3Cmd from '!!raw-loader!./_migrate_appset/script-09-step3/render-one-customer.sh';
|
||||
import RenderStep3Out from '!!raw-loader!./_migrate_appset/script-09-step3/render-one-customer.txt';
|
||||
|
||||
<Tabs groupId="render-step3">
|
||||
<TabItem value="Command" label="Command">
|
||||
<CodeBlock language="bash">{RenderStep3Cmd}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Output" label="Output">
|
||||
<CodeBlock language="txt">{RenderStep3Out}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
The manifests rendered with the flattened values are identical to those rendered
|
||||
with the more complex hierarchy of overrides.
|
||||
|
||||
import GitStatusStep3Cmd from '!!raw-loader!./_migrate_appset/script-09-step3/git-status.sh';
|
||||
import GitStatusStep3Out from '!!raw-loader!./_migrate_appset/script-09-step3/git-status.txt';
|
||||
|
||||
<Tabs groupId="git-status-step3">
|
||||
<TabItem value="Command" label="Command">
|
||||
<CodeBlock language="bash">{GitStatusStep3Cmd}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Output" label="Output">
|
||||
<CodeBlock language="txt">{GitStatusStep3Out}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### Going deeper
|
||||
|
||||
If you'd like to dive deeper into these steps, take a look at the following
|
||||
files which are the entrypoints for the `holos render platform` command at each
|
||||
step. From there, take a look at the component definitions in
|
||||
`components/my-app/*.cue` and `components/render-values/*.cue`
|
||||
|
||||
#### Entrypoints
|
||||
|
||||
import S2PlatformMyApp from '!!raw-loader!./_migrate_appset/script-08-complex-unification/files/platform-my-app.cue';
|
||||
import S2PlatformRenderValues from '!!raw-loader!./_migrate_appset/script-08-complex-unification/files/platform-render-values.cue';
|
||||
|
||||
<Tabs groupId="review">
|
||||
<TabItem value="Step 1" label="Step 1">
|
||||
```
|
||||
platform/my-app.cue
|
||||
```
|
||||
<CodeBlock language="cue" showLineNumbers>{S2PlatformMyApp}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Step 2" label="Step 2">
|
||||
```
|
||||
platform/render-values.cue
|
||||
```
|
||||
<CodeBlock language="cue" showLineNumbers>{S2PlatformRenderValues}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Step 3" label="Step 3">
|
||||
:::note
|
||||
Step 3 uses the same entrypoint as Step 1, completing the migration. The
|
||||
main difference is in `components/my-app/step3.cue` where the flattened
|
||||
values are used.
|
||||
:::
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
#### Component Definition
|
||||
|
||||
The `my-app` component definition starts off in step 1, is not used in step 2,
|
||||
and changes to a flattened values structure in step3. Here are the changes at
|
||||
each step.
|
||||
|
||||
import ComponentDefMyAppXMain from '!!raw-loader!./_migrate_appset/script-09-step3/files/my-app.cue';
|
||||
import ComponentDefMyAppStep1 from '!!raw-loader!./_migrate_appset/script-09-step3/files/step1.cue';
|
||||
import ComponentDefMyAppStep3 from '!!raw-loader!./_migrate_appset/script-09-step3/files/step3.cue';
|
||||
|
||||
<Tabs groupId="review-component-definition">
|
||||
<TabItem value="Component Definition" label="Component Definition">
|
||||
```
|
||||
components/my-app/my-app.cue
|
||||
```
|
||||
<CodeBlock language="cue" showLineNumbers>{ComponentDefMyAppXMain}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Step 1" label="Step 1">
|
||||
```
|
||||
components/my-app/step1.cue
|
||||
```
|
||||
<CodeBlock language="cue" showLineNumbers>{ComponentDefMyAppStep1}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Step 3" label="Step 3">
|
||||
```
|
||||
components/my-app/step3.cue
|
||||
```
|
||||
<CodeBlock language="cue" showLineNumbers>{ComponentDefMyAppStep3}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Concluding Remarks
|
||||
|
||||
The original article used 5 layers of Helm value files. Migrating the
|
||||
configuration to Holos uncovered issues and solved problems.
|
||||
|
||||
1. `replicaCount: 1` in common-values.yaml was unnecessary, it was always overridden.
|
||||
2. `replicaCount: 5` in prod-values.yaml was _also_ unnecessary, it was never used.
|
||||
3. Removing these two values allowed unification to succeed, which indicates
|
||||
there was no need for a Helm value hierarchy at all.
|
||||
|
||||
The Helm value hierarchy added significant accidental complexity, accidental
|
||||
because it was not necessary and complex because the layers of override made it
|
||||
difficult to reason about the system.
|
||||
|
||||
Migrating to Holos achieves the same result, the deploy directory remains
|
||||
unchanged, while leaving us with a much simpler solution.
|
||||
|
||||
1. **Complexity remains constant over time.** New aspects can be added, for
|
||||
example specifying values by customer without introducing a new layer of
|
||||
overrides. With the previous approach of Helm value overrides _each additional
|
||||
layer accidentally increased complexity_.
|
||||
2. **Conflicts are clear and immediate** indicating the exact files and line
|
||||
numbers where we need to resolve the conflict.
|
||||
3. **Data is within our reach** we no longer need to rely on ArgoCD running in a
|
||||
remote cluster to see the desired state. We can inspect the intermediate state
|
||||
with `holos show buildplans` and the final manifests with `holos render
|
||||
platform`. We can use simple tools like `grep` to make well informed decisions
|
||||
about the platform wide configuration.
|
||||
|
||||
For example, here's the `holos` `BuildPlan` for prod-us where we see the actual
|
||||
unified values provided to `helm`.
|
||||
|
||||
import ShowBuildPlansCmd from '!!raw-loader!./_migrate_appset/script-06-unification/buildplan.sh';
|
||||
import ShowBuildPlansOut from '!!raw-loader!./_migrate_appset/script-06-unification/buildplan.txt';
|
||||
|
||||
<Tabs groupId="show-buildplans-command">
|
||||
<TabItem value="Command" label="Command">
|
||||
<CodeBlock language="bash">{ShowBuildPlansCmd}</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="Output" label="Output">
|
||||
<CodeBlock language="yaml" showLineNumbers>{ShowBuildPlansOut}</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
[Part 1]: ./2025-01-13-replace-an-applicationset-with-the-rendered-manifest-pattern.mdx
|
||||
[original ApplicationSet]: https://github.com/holos-run/multi-sources-example/blob/v0.1.0/appsets/4-final/all-my-envs-appset-with-version.yaml#L27-L32
|
||||
[end-of-part-1]: https://github.com/holos-run/multi-sources-example/tree/end-of-part-1
|
||||
@@ -30,7 +30,6 @@ exec $WORK/update.sh $WORK/manifest.yaml
|
||||
# Make a commit
|
||||
exec git add .
|
||||
exec git commit -m '05-application.txtar'
|
||||
exec git branch end-of-part-1
|
||||
|
||||
-- manifest.path --
|
||||
deploy/environments/prod-us/components/my-chart/my-chart.gen.yaml
|
||||
|
||||
@@ -1,198 +0,0 @@
|
||||
# Work in the root of the example repo
|
||||
cd ../script-01-clone/multi-sources-example
|
||||
chmod 0755 $WORK/update.sh
|
||||
|
||||
# Grep for replicas: to see what's used
|
||||
exec bash -c 'bash -euo pipefail $WORK/grep.sh 2>&1'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/grep.txt
|
||||
|
||||
# Common values
|
||||
exec bash -c 'cp $(<$WORK/common.path) $WORK/common.yaml'
|
||||
|
||||
# Remove common values
|
||||
exec cat $WORK/remove.head $WORK/remove.body $WORK/remove.tail
|
||||
stdin stdout
|
||||
exec bash -xeuo pipefail
|
||||
cp stdout $WORK/remove.out
|
||||
|
||||
# Render platform
|
||||
exec bash -c 'bash -euo pipefail $WORK/render.sh 2>&1'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/render.txt
|
||||
|
||||
# Check results
|
||||
exec bash -c 'bash -euo pipefail $WORK/check.sh 2>&1'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/check.txt
|
||||
|
||||
# Commit 1
|
||||
exec bash -c 'bash -euo pipefail $WORK/commit1.sh 2>&1'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/commit1.txt
|
||||
|
||||
# Unification Section
|
||||
# Unify Values
|
||||
exec cat $WORK/unify.head $WORK/unify.body $WORK/unify.tail
|
||||
stdin stdout
|
||||
exec bash -xeuo pipefail
|
||||
cp stdout $WORK/unify.out
|
||||
|
||||
# Render the platform to see the conflicts
|
||||
! exec bash -euo pipefail -c 'bash -euo pipefail $WORK/render2.sh 2>&1 | sed s,$(pwd)/,,g'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/render2.txt
|
||||
|
||||
# Copy the value files to show the conflict
|
||||
mkdir $WORK/conflict
|
||||
cp components/my-chart/my-values/env-type/prod-values.yaml $WORK/conflict/prod-values.yaml
|
||||
cp components/my-chart/my-values/envs/prod-eu-values.yaml $WORK/conflict/prod-eu-values.yaml
|
||||
|
||||
# Commit 2
|
||||
exec bash -c 'bash -euo pipefail $WORK/commit2.sh 2>&1'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/commit2.txt
|
||||
|
||||
# Remove replicaCount: 5 from env-type/prod-values.yaml
|
||||
exec cat $WORK/unify2.head $WORK/unify2.body $WORK/unify2.tail
|
||||
stdin stdout
|
||||
exec bash -xeuo pipefail
|
||||
cp stdout $WORK/unify2.out
|
||||
|
||||
# Render the platform again: no conflicts
|
||||
exec bash -euo pipefail -c 'bash -euo pipefail $WORK/render3.sh 2>&1'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/render3.txt
|
||||
|
||||
# Verify there are no changes to the deploy directory
|
||||
exec bash -c 'bash -euo pipefail $WORK/status3.sh 2>&1'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/status3.txt
|
||||
|
||||
# Commit 3
|
||||
exec bash -c 'bash -euo pipefail $WORK/commit3.sh 2>&1'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/commit3.txt
|
||||
|
||||
# Final wrap up - show build plan
|
||||
exec bash -c 'bash -euo pipefail $WORK/buildplan.sh 2>&1'
|
||||
cp stdout $WORK/buildplan.txt
|
||||
|
||||
-- buildplan.sh --
|
||||
holos show buildplans --selector env=prod-us
|
||||
-- status3.sh --
|
||||
git status deploy
|
||||
-- render3.sh --
|
||||
rm -rf deploy
|
||||
holos render platform
|
||||
-- unify2.head --
|
||||
patch -p1 <<'EOF'
|
||||
-- unify2.tail --
|
||||
EOF
|
||||
-- unify2.body --
|
||||
diff --git a/components/my-chart/my-values/env-type/prod-values.yaml b/components/my-chart/my-values/env-type/prod-values.yaml
|
||||
index fef58f4..a3cce4a 100644
|
||||
--- a/components/my-chart/my-values/env-type/prod-values.yaml
|
||||
+++ b/components/my-chart/my-values/env-type/prod-values.yaml
|
||||
@@ -1,11 +1,5 @@
|
||||
-# Kubernetes settings
|
||||
-replicaCount: 5
|
||||
-
|
||||
# Environment settings
|
||||
environmentType: production
|
||||
paypalUrl: "production.paypal.com"
|
||||
dbUser: "prod_username"
|
||||
dbPassword: "prod_password"
|
||||
-
|
||||
-
|
||||
-
|
||||
-- render2.sh --
|
||||
holos render platform --concurrency 1
|
||||
-- unify.head --
|
||||
patch -p1 <<'EOF'
|
||||
-- unify.tail --
|
||||
EOF
|
||||
-- unify.body --
|
||||
diff --git a/components/my-chart/my-chart.cue b/components/my-chart/my-chart.cue
|
||||
index cf1dae4..4f01828 100644
|
||||
--- a/components/my-chart/my-chart.cue
|
||||
+++ b/components/my-chart/my-chart.cue
|
||||
@@ -31,23 +31,14 @@ component: #Helm & {
|
||||
// article uses the ApplicationSet template to specify the namespace.
|
||||
KustomizeConfig: Kustomization: namespace: parameters.env
|
||||
|
||||
- // Migrate the Helm Hierarchy preserving the behavior of over writing values.
|
||||
- // Migrated from [valueFiles]. Later files win.
|
||||
+ // Migrate the Helm Hierarchy to CUE. Conflicts are errors.
|
||||
+ // Migrated from [valueFiles].
|
||||
//
|
||||
// [valueFiles]: https://github.com/holos-run/multi-sources-example/blob/v0.1.0/appsets/4-final/all-my-envs-appset-with-version.yaml#L27-L32
|
||||
- ValueFiles: [{
|
||||
- name: "version-values.yaml"
|
||||
- values: valueFiles["my-values/app-version/\(parameters.version)-values.yaml"]
|
||||
- }, {
|
||||
- name: "type-values.yaml"
|
||||
- values: valueFiles["my-values/env-type/\(parameters.type)-values.yaml"]
|
||||
- }, {
|
||||
- name: "region-values.yaml"
|
||||
- values: valueFiles["my-values/regions/\(parameters.region)-values.yaml"]
|
||||
- }, {
|
||||
- name: "env-values.yaml"
|
||||
- values: valueFiles["my-values/envs/\(parameters.env)-values.yaml"]
|
||||
- }]
|
||||
+ Values: valueFiles["my-values/app-version/\(parameters.version)-values.yaml"]
|
||||
+ Values: valueFiles["my-values/env-type/\(parameters.type)-values.yaml"]
|
||||
+ Values: valueFiles["my-values/regions/\(parameters.region)-values.yaml"]
|
||||
+ Values: valueFiles["my-values/envs/\(parameters.env)-values.yaml"]
|
||||
}
|
||||
|
||||
// holos represents the output for the holos command line to process. The holos
|
||||
-- commit3.sh --
|
||||
git add .
|
||||
git commit -m '06-unification step 3'
|
||||
-- commit2.sh --
|
||||
git add .
|
||||
git commit -m '06-unification step 2'
|
||||
-- commit1.sh --
|
||||
git add .
|
||||
git commit -m '06-unification step 1'
|
||||
-- render.sh --
|
||||
rm -rf deploy
|
||||
holos render platform
|
||||
-- check.sh --
|
||||
git status deploy
|
||||
-- remove.head --
|
||||
git rm -f components/my-chart/my-values/common-values.yaml
|
||||
patch -p1 <<'EOF'
|
||||
-- remove.tail --
|
||||
EOF
|
||||
-- remove.body --
|
||||
diff --git a/components/my-chart/my-chart.cue b/components/my-chart/my-chart.cue
|
||||
index 2809d1a..cf1dae4 100644
|
||||
--- a/components/my-chart/my-chart.cue
|
||||
+++ b/components/my-chart/my-chart.cue
|
||||
@@ -36,9 +36,6 @@ component: #Helm & {
|
||||
//
|
||||
// [valueFiles]: https://github.com/holos-run/multi-sources-example/blob/v0.1.0/appsets/4-final/all-my-envs-appset-with-version.yaml#L27-L32
|
||||
ValueFiles: [{
|
||||
- name: "common-values.yaml"
|
||||
- values: valueFiles["my-values/common-values.yaml"]
|
||||
- }, {
|
||||
name: "version-values.yaml"
|
||||
values: valueFiles["my-values/app-version/\(parameters.version)-values.yaml"]
|
||||
}, {
|
||||
@@ -61,5 +58,4 @@ component: #Helm & {
|
||||
holos: component.BuildPlan
|
||||
|
||||
// Migrated from https://github.com/holos-run/multi-sources-example/blob/v0.1.0/appsets/4-final/all-my-envs-appset-with-version.yaml#L27-L32
|
||||
-valueFiles: _ @embed(glob=my-values/*.yaml)
|
||||
valueFiles: _ @embed(glob=my-values/*/*-values.yaml)
|
||||
-- common.path --
|
||||
components/my-chart/my-values/common-values.yaml
|
||||
-- grep.sh --
|
||||
grep -r replicas: deploy
|
||||
-- update.sh --
|
||||
#! /bin/bash
|
||||
set -euo pipefail
|
||||
[[ -s "$1" ]] && [[ -z "${HOLOS_UPDATE_SCRIPTS:-}" ]] && exit 0
|
||||
cat > "$1"
|
||||
@@ -1,5 +0,0 @@
|
||||
# Work in the root of the example repo
|
||||
cd ../script-01-clone/multi-sources-example
|
||||
|
||||
# Checkout the v0.4.x branch
|
||||
exec git checkout v0.4.x
|
||||
@@ -1,77 +0,0 @@
|
||||
# Work in the root of the example repo
|
||||
cd ../script-01-clone/multi-sources-example
|
||||
env HOME=$WORK/.tmp
|
||||
env CUSTOMER=customer-zzsbbmfc
|
||||
chmod 0755 $WORK/update.sh
|
||||
|
||||
mkdir $WORK/files
|
||||
|
||||
# Reset
|
||||
exec git reset --hard origin/v0.4.x
|
||||
|
||||
# Values Generator
|
||||
exec bash -c 'bash -euo pipefail $WORK/generator.sh 2>&1'
|
||||
# Show the generated structure
|
||||
exec bash -c 'bash -eu $WORK/show-deployment-configs.sh 2>&1'
|
||||
cp stdout $WORK/show-deployment-configs.txt
|
||||
exec bash -c 'bash -euo pipefail $WORK/show-value-files.sh 2>&1'
|
||||
cp stdout $WORK/show-value-files.txt
|
||||
|
||||
# Show one buildplan
|
||||
exec bash -c 'bash -euo pipefail $WORK/show-one-buildplan.sh 2>&1'
|
||||
cp stdout $WORK/show-one-buildplan.txt
|
||||
|
||||
# Render one customer
|
||||
exec bash -c 'bash -euo pipefail $WORK/render-one-customer.sh 2>&1'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/render-one-customer.txt
|
||||
|
||||
# Add and commit
|
||||
exec bash -c 'bash -euo pipefail $WORK/add-and-commit-step1.sh 2>&1'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/add-and-commit-step1.txt
|
||||
|
||||
# Flattening Values
|
||||
exec bash -c 'bash -euo pipefail $WORK/render-step2.sh 2>&1'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/render-step2.txt
|
||||
|
||||
# Show the flattened values
|
||||
exec bash -c 'bash -euo pipefail $WORK/show-flattened-values.sh 2>&1'
|
||||
cp stdout $WORK/show-flattened-values.txt
|
||||
|
||||
# Step 2 - Take a look at the following files
|
||||
cp platform/my-app.cue $WORK/files/platform-my-app.cue
|
||||
cp platform/render-values.cue $WORK/files/platform-render-values.cue
|
||||
|
||||
-- show-flattened-values.sh --
|
||||
# Flattened values written here
|
||||
tree deploy/values/customers/$CUSTOMER
|
||||
# Note how the input deployment configs now map 1:1 to values files.
|
||||
tree config/my-app/deployment/customers/$CUSTOMER
|
||||
-- render-step2.sh --
|
||||
holos render platform -t flatten -t step2 \
|
||||
--selector customer=$CUSTOMER
|
||||
-- add-and-commit-step1.sh --
|
||||
git add deploy
|
||||
git commit -m 'render step1 with helm value file overrides'
|
||||
-- render-one-customer.sh --
|
||||
holos render platform -t flatten -t step1 \
|
||||
--selector customer=$CUSTOMER
|
||||
-- show-one-buildplan.sh --
|
||||
holos show buildplans -t flatten -t step1 \
|
||||
--selector customer=$CUSTOMER,cluster=prod9-management
|
||||
-- show-deployment-configs.sh --
|
||||
ls config/my-app/deployment/customers/*/clusters/*/config.json | wc -l
|
||||
-- show-value-files.sh --
|
||||
tree -d components/my-app/values/
|
||||
tree components/my-app/values/05-environments
|
||||
tree components/my-app/values/06-tiers
|
||||
tree components/my-app/values/07-scopes
|
||||
-- generator.sh --
|
||||
go run ./generator
|
||||
-- update.sh --
|
||||
#! /bin/bash
|
||||
set -euo pipefail
|
||||
[[ -s "$1" ]] && [[ -z "${HOLOS_UPDATE_SCRIPTS:-}" ]] && exit 0
|
||||
cat > "$1"
|
||||
@@ -1,38 +0,0 @@
|
||||
# Work in the root of the example repo
|
||||
cd ../script-01-clone/multi-sources-example
|
||||
env CUSTOMER=customer-zzsbbmfc
|
||||
chmod 0755 $WORK/update.sh
|
||||
|
||||
# Show one buildplan
|
||||
exec bash -c 'bash -euo pipefail $WORK/show-one-buildplan.sh 2>&1'
|
||||
cp stdout $WORK/show-one-buildplan.txt
|
||||
|
||||
# Render one customer
|
||||
exec bash -c 'bash -euo pipefail $WORK/render-one-customer.sh 2>&1'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/render-one-customer.txt
|
||||
|
||||
# Git status
|
||||
exec bash -c 'bash -euo pipefail $WORK/git-status.sh 2>&1'
|
||||
cp stdout $WORK/git-status.txt
|
||||
|
||||
# Component definitions
|
||||
mkdir $WORK/files
|
||||
cp components/my-app/my-app.cue $WORK/files/my-app.cue
|
||||
cp components/my-app/step1.cue $WORK/files/step1.cue
|
||||
cp components/my-app/step3.cue $WORK/files/step3.cue
|
||||
|
||||
-- git-status.sh --
|
||||
git status
|
||||
-- render-one-customer.sh --
|
||||
find deploy/clusters -name $CUSTOMER -print0 | xargs -0 rm -rf
|
||||
holos render platform -t flatten -t step3 \
|
||||
--selector customer=$CUSTOMER
|
||||
-- show-one-buildplan.sh --
|
||||
holos show buildplans -t flatten -t step3 \
|
||||
--selector customer=$CUSTOMER,cluster=prod9-management
|
||||
-- update.sh --
|
||||
#! /bin/bash
|
||||
set -euo pipefail
|
||||
[[ -s "$1" ]] && [[ -z "${HOLOS_UPDATE_SCRIPTS:-}" ]] && exit 0
|
||||
cat > "$1"
|
||||
@@ -1 +1 @@
|
||||
6a882ac5aee7241e0130a59737cc46db5f636a21
|
||||
f35da50452b346d4eea3f3e59ff5ae6b8c221218
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
rendered my-chart 0.1.0 for environment integration-gpu in 451.061ms
|
||||
rendered my-chart 0.1.0 for environment prod-eu in 451.063834ms
|
||||
rendered my-chart 0.1.0 for environment prod-us in 451.098417ms
|
||||
rendered my-chart 0.2.0 for environment staging-eu in 451.417625ms
|
||||
rendered my-chart 0.2.0 for environment staging-us in 471.239083ms
|
||||
rendered my-chart 0.2.0 for environment integration-non-gpu in 471.789667ms
|
||||
rendered my-chart 0.2.0 for environment qa in 471.892041ms
|
||||
rendered platform in 471.935667ms
|
||||
rendered my-chart 0.1.0 for environment integration-gpu in 428.168708ms
|
||||
rendered my-chart 0.1.0 for environment prod-us in 428.221333ms
|
||||
rendered my-chart 0.1.0 for environment prod-eu in 428.148834ms
|
||||
rendered my-chart 0.2.0 for environment qa in 433.4605ms
|
||||
rendered my-chart 0.2.0 for environment staging-us in 493.320625ms
|
||||
rendered my-chart 0.2.0 for environment integration-non-gpu in 493.343917ms
|
||||
rendered my-chart 0.2.0 for environment staging-eu in 493.325917ms
|
||||
rendered platform in 493.432542ms
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
rendered my-chart 0.2.0 for environment integration-non-gpu in 189.944ms
|
||||
rendered my-chart 0.1.0 for environment prod-eu in 198.639375ms
|
||||
rendered my-chart 0.1.0 for environment prod-us in 199.318375ms
|
||||
rendered my-chart 0.2.0 for environment staging-us in 202.999667ms
|
||||
rendered my-chart 0.2.0 for environment qa in 203.460125ms
|
||||
rendered my-chart 0.1.0 for environment integration-gpu in 204.000958ms
|
||||
rendered my-chart 0.2.0 for environment staging-eu in 204.434791ms
|
||||
rendered platform in 204.515917ms
|
||||
rendered my-chart 0.2.0 for environment integration-non-gpu in 204.149958ms
|
||||
rendered my-chart 0.1.0 for environment prod-us in 205.34475ms
|
||||
rendered my-chart 0.2.0 for environment staging-eu in 206.376291ms
|
||||
rendered my-chart 0.1.0 for environment prod-eu in 207.298833ms
|
||||
rendered my-chart 0.1.0 for environment integration-gpu in 207.896ms
|
||||
rendered my-chart 0.2.0 for environment staging-us in 210.70825ms
|
||||
rendered my-chart 0.2.0 for environment qa in 210.695667ms
|
||||
rendered platform in 210.776584ms
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
holos show buildplans --selector env=prod-us
|
||||
@@ -1,86 +0,0 @@
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: my-chart
|
||||
labels:
|
||||
env: prod-us
|
||||
annotations:
|
||||
app.holos.run/description: my-chart 0.1.0 for environment prod-us
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: environments/prod-us/components/my-chart/my-chart.gen.yaml
|
||||
generators:
|
||||
- kind: Helm
|
||||
output: helm.gen.yaml
|
||||
helm:
|
||||
chart:
|
||||
name: my-chart
|
||||
version: 0.1.0
|
||||
release: my-chart
|
||||
repository:
|
||||
name: multi-sources-example
|
||||
url: https://kostis-codefresh.github.io/multi-sources-example
|
||||
values:
|
||||
cacheSize: 1024kb
|
||||
dbPassword: prod_password
|
||||
dbUser: prod_username
|
||||
environment: prod-us
|
||||
environmentType: production
|
||||
gpuEnabled: "1"
|
||||
imageVersion: "1.0"
|
||||
nBuckets: "42"
|
||||
pageLimit: "25"
|
||||
paypalUrl: production.paypal.com
|
||||
region: us
|
||||
replicaCount: 10
|
||||
sorting: Ascending
|
||||
userInterfaceTheme: dark
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- helm.gen.yaml
|
||||
- resources.gen.yaml
|
||||
output: environments/prod-us/components/my-chart/my-chart.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
labels:
|
||||
- includeSelectors: false
|
||||
pairs:
|
||||
argocd.argoproj.io/instance: prod-us-my-chart
|
||||
namespace: prod-us
|
||||
resources:
|
||||
- helm.gen.yaml
|
||||
- resources.gen.yaml
|
||||
- artifact: gitops/prod-us-my-chart-application.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: gitops/prod-us-my-chart-application.gen.yaml
|
||||
resources:
|
||||
Application:
|
||||
prod-us-my-chart:
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
labels:
|
||||
env: prod-us
|
||||
name: prod-us-my-chart
|
||||
namespace: argocd
|
||||
spec:
|
||||
destination:
|
||||
namespace: prod-us
|
||||
server: https://kubernetes.default.svc
|
||||
project: default
|
||||
source:
|
||||
path: deploy/environments/prod-us/components/my-chart
|
||||
repoURL: https://github.com/holos-run/multi-sources-example
|
||||
targetRevision: main
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
@@ -1 +0,0 @@
|
||||
git status deploy
|
||||
@@ -1,2 +0,0 @@
|
||||
On branch work
|
||||
nothing to commit, working tree clean
|
||||
@@ -1,2 +0,0 @@
|
||||
git add .
|
||||
git commit -m '06-unification step 1'
|
||||
@@ -1,3 +0,0 @@
|
||||
[work ba3701f] 06-unification step 1
|
||||
2 files changed, 6 deletions(-)
|
||||
delete mode 100644 components/my-chart/my-values/common-values.yaml
|
||||
@@ -1,2 +0,0 @@
|
||||
git add .
|
||||
git commit -m '06-unification step 2'
|
||||
@@ -1,2 +0,0 @@
|
||||
[work cd67fc5] 06-unification step 2
|
||||
1 file changed, 6 insertions(+), 15 deletions(-)
|
||||
@@ -1,2 +0,0 @@
|
||||
git add .
|
||||
git commit -m '06-unification step 3'
|
||||
@@ -1,2 +0,0 @@
|
||||
[work 44027c3] 06-unification step 3
|
||||
1 file changed, 6 deletions(-)
|
||||
@@ -1 +0,0 @@
|
||||
components/my-chart/my-values/common-values.yaml
|
||||
@@ -1,2 +0,0 @@
|
||||
# Kubernetes settings
|
||||
replicaCount: 1
|
||||
@@ -1,13 +0,0 @@
|
||||
# Kubernetes settings
|
||||
replicaCount: 8
|
||||
|
||||
# Environment settings
|
||||
environment: prod-eu
|
||||
|
||||
# Application settings
|
||||
userInterfaceTheme: "dark"
|
||||
cacheSize: "1024kb"
|
||||
gpuEnabled: "1"
|
||||
pageLimit: "25"
|
||||
sorting: "Ascending"
|
||||
nBuckets: "42"
|
||||
@@ -1,11 +0,0 @@
|
||||
# Kubernetes settings
|
||||
replicaCount: 5
|
||||
|
||||
# Environment settings
|
||||
environmentType: production
|
||||
paypalUrl: "production.paypal.com"
|
||||
dbUser: "prod_username"
|
||||
dbPassword: "prod_password"
|
||||
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
grep -r replicas: deploy
|
||||
@@ -1,7 +0,0 @@
|
||||
deploy/environments/integration-gpu/components/my-chart/my-chart.gen.yaml: replicas: 3
|
||||
deploy/environments/prod-eu/components/my-chart/my-chart.gen.yaml: replicas: 8
|
||||
deploy/environments/integration-non-gpu/components/my-chart/my-chart.gen.yaml: replicas: 3
|
||||
deploy/environments/qa/components/my-chart/my-chart.gen.yaml: replicas: 3
|
||||
deploy/environments/staging-eu/components/my-chart/my-chart.gen.yaml: replicas: 3
|
||||
deploy/environments/prod-us/components/my-chart/my-chart.gen.yaml: replicas: 10
|
||||
deploy/environments/staging-us/components/my-chart/my-chart.gen.yaml: replicas: 3
|
||||
@@ -1,20 +0,0 @@
|
||||
diff --git a/components/my-chart/my-chart.cue b/components/my-chart/my-chart.cue
|
||||
index 2809d1a..cf1dae4 100644
|
||||
--- a/components/my-chart/my-chart.cue
|
||||
+++ b/components/my-chart/my-chart.cue
|
||||
@@ -36,9 +36,6 @@ component: #Helm & {
|
||||
//
|
||||
// [valueFiles]: https://github.com/holos-run/multi-sources-example/blob/v0.1.0/appsets/4-final/all-my-envs-appset-with-version.yaml#L27-L32
|
||||
ValueFiles: [{
|
||||
- name: "common-values.yaml"
|
||||
- values: valueFiles["my-values/common-values.yaml"]
|
||||
- }, {
|
||||
name: "version-values.yaml"
|
||||
values: valueFiles["my-values/app-version/\(parameters.version)-values.yaml"]
|
||||
}, {
|
||||
@@ -61,5 +58,4 @@ component: #Helm & {
|
||||
holos: component.BuildPlan
|
||||
|
||||
// Migrated from https://github.com/holos-run/multi-sources-example/blob/v0.1.0/appsets/4-final/all-my-envs-appset-with-version.yaml#L27-L32
|
||||
-valueFiles: _ @embed(glob=my-values/*.yaml)
|
||||
valueFiles: _ @embed(glob=my-values/*/*-values.yaml)
|
||||
@@ -1,2 +0,0 @@
|
||||
git rm -f components/my-chart/my-values/common-values.yaml
|
||||
patch -p1 <<'EOF'
|
||||
@@ -1,2 +0,0 @@
|
||||
rm 'components/my-chart/my-values/common-values.yaml'
|
||||
patching file 'components/my-chart/my-chart.cue'
|
||||
@@ -1,8 +0,0 @@
|
||||
rendered my-chart 0.2.0 for environment staging-eu in 247.658792ms
|
||||
rendered my-chart 0.1.0 for environment integration-gpu in 272.017ms
|
||||
rendered my-chart 0.2.0 for environment qa in 279.942875ms
|
||||
rendered my-chart 0.1.0 for environment prod-us in 285.04225ms
|
||||
rendered my-chart 0.2.0 for environment integration-non-gpu in 285.188667ms
|
||||
rendered my-chart 0.1.0 for environment prod-eu in 285.855333ms
|
||||
rendered my-chart 0.2.0 for environment staging-us in 286.05975ms
|
||||
rendered platform in 286.136375ms
|
||||
@@ -1 +0,0 @@
|
||||
holos render platform --concurrency 1
|
||||
@@ -1,15 +0,0 @@
|
||||
rendered my-chart 0.2.0 for environment qa in 167.755583ms
|
||||
rendered my-chart 0.2.0 for environment staging-eu in 183.818166ms
|
||||
rendered my-chart 0.2.0 for environment staging-us in 205.0915ms
|
||||
could not run: component.Artifacts.HolosComponent.generators.0.helm.values.replicaCount: conflicting values 8 and 5 at internal/builder/instance.go:129
|
||||
component.Artifacts.HolosComponent.generators.0.helm.values.replicaCount: conflicting values 8 and 5:
|
||||
components/my-chart/my-chart.cue:18:12
|
||||
components/my-chart/my-chart.cue:39:10
|
||||
components/my-chart/my-chart.cue:41:10
|
||||
components/schema.cue:36:2
|
||||
cue.mod/pkg/github.com/holos-run/holos/api/author/v1alpha5/definitions.cue:115:15
|
||||
my-values/env-type/prod-values.yaml:2:15
|
||||
my-values/envs/prod-eu-values.yaml:2:15
|
||||
could not run: could not render component: could not run command:
|
||||
holos '--log-level' 'info' '--log-format' 'console' 'render' 'component' '--inject' 'version=prod' '--inject' 'outputBaseDir=environments/prod-eu' '--inject' 'chart=0.1.0' '--inject' 'env=prod-eu' '--inject' 'region=eu' '--inject' 'type=prod' '--inject' 'holos_component_name=my-chart' '--inject' 'holos_component_path=components/my-chart' '--inject' 'holos_component_labels={"env":"prod-eu"}' '--inject' 'holos_component_annotations={"app.holos.run/description":"my-chart 0.1.0 for environment prod-eu"}' './components/my-chart'
|
||||
exit status 1 at cli/render/render.go:171
|
||||
@@ -1,8 +0,0 @@
|
||||
rendered my-chart 0.2.0 for environment staging-eu in 263.07275ms
|
||||
rendered my-chart 0.1.0 for environment prod-eu in 268.438375ms
|
||||
rendered my-chart 0.2.0 for environment staging-us in 269.214167ms
|
||||
rendered my-chart 0.2.0 for environment integration-non-gpu in 272.854334ms
|
||||
rendered my-chart 0.2.0 for environment qa in 273.286416ms
|
||||
rendered my-chart 0.1.0 for environment integration-gpu in 273.956417ms
|
||||
rendered my-chart 0.1.0 for environment prod-us in 274.647041ms
|
||||
rendered platform in 274.712875ms
|
||||
@@ -1 +0,0 @@
|
||||
git status deploy
|
||||
@@ -1,2 +0,0 @@
|
||||
On branch work
|
||||
nothing to commit, working tree clean
|
||||
@@ -1,34 +0,0 @@
|
||||
diff --git a/components/my-chart/my-chart.cue b/components/my-chart/my-chart.cue
|
||||
index cf1dae4..4f01828 100644
|
||||
--- a/components/my-chart/my-chart.cue
|
||||
+++ b/components/my-chart/my-chart.cue
|
||||
@@ -31,23 +31,14 @@ component: #Helm & {
|
||||
// article uses the ApplicationSet template to specify the namespace.
|
||||
KustomizeConfig: Kustomization: namespace: parameters.env
|
||||
|
||||
- // Migrate the Helm Hierarchy preserving the behavior of over writing values.
|
||||
- // Migrated from [valueFiles]. Later files win.
|
||||
+ // Migrate the Helm Hierarchy to CUE. Conflicts are errors.
|
||||
+ // Migrated from [valueFiles].
|
||||
//
|
||||
// [valueFiles]: https://github.com/holos-run/multi-sources-example/blob/v0.1.0/appsets/4-final/all-my-envs-appset-with-version.yaml#L27-L32
|
||||
- ValueFiles: [{
|
||||
- name: "version-values.yaml"
|
||||
- values: valueFiles["my-values/app-version/\(parameters.version)-values.yaml"]
|
||||
- }, {
|
||||
- name: "type-values.yaml"
|
||||
- values: valueFiles["my-values/env-type/\(parameters.type)-values.yaml"]
|
||||
- }, {
|
||||
- name: "region-values.yaml"
|
||||
- values: valueFiles["my-values/regions/\(parameters.region)-values.yaml"]
|
||||
- }, {
|
||||
- name: "env-values.yaml"
|
||||
- values: valueFiles["my-values/envs/\(parameters.env)-values.yaml"]
|
||||
- }]
|
||||
+ Values: valueFiles["my-values/app-version/\(parameters.version)-values.yaml"]
|
||||
+ Values: valueFiles["my-values/env-type/\(parameters.type)-values.yaml"]
|
||||
+ Values: valueFiles["my-values/regions/\(parameters.region)-values.yaml"]
|
||||
+ Values: valueFiles["my-values/envs/\(parameters.env)-values.yaml"]
|
||||
}
|
||||
|
||||
// holos represents the output for the holos command line to process. The holos
|
||||
@@ -1 +0,0 @@
|
||||
patch -p1 <<'EOF'
|
||||
@@ -1 +0,0 @@
|
||||
patching file 'components/my-chart/my-chart.cue'
|
||||
@@ -1,16 +0,0 @@
|
||||
diff --git a/components/my-chart/my-values/env-type/prod-values.yaml b/components/my-chart/my-values/env-type/prod-values.yaml
|
||||
index fef58f4..a3cce4a 100644
|
||||
--- a/components/my-chart/my-values/env-type/prod-values.yaml
|
||||
+++ b/components/my-chart/my-values/env-type/prod-values.yaml
|
||||
@@ -1,11 +1,5 @@
|
||||
-# Kubernetes settings
|
||||
-replicaCount: 5
|
||||
-
|
||||
# Environment settings
|
||||
environmentType: production
|
||||
paypalUrl: "production.paypal.com"
|
||||
dbUser: "prod_username"
|
||||
dbPassword: "prod_password"
|
||||
-
|
||||
-
|
||||
-
|
||||
@@ -1 +0,0 @@
|
||||
patch -p1 <<'EOF'
|
||||
@@ -1 +0,0 @@
|
||||
patching file 'components/my-chart/my-values/env-type/prod-values.yaml'
|
||||
@@ -1 +0,0 @@
|
||||
EOF
|
||||
@@ -1,2 +0,0 @@
|
||||
git add deploy
|
||||
git commit -m 'render step1 with helm value file overrides'
|
||||
@@ -1,18 +0,0 @@
|
||||
[v0.4.x fa82933] render step1 with helm value file overrides
|
||||
16 files changed, 512 insertions(+)
|
||||
create mode 100644 deploy/apps/customer-zzsbbmfc-myapp137-dev14-management-application.gen.yaml
|
||||
create mode 100644 deploy/apps/customer-zzsbbmfc-myapp137-prod9-management-application.gen.yaml
|
||||
create mode 100644 deploy/apps/customer-zzsbbmfc-myapp137-test8-management-application.gen.yaml
|
||||
create mode 100644 deploy/apps/customer-zzsbbmfc-myapp137-uat10-management-application.gen.yaml
|
||||
create mode 100644 deploy/apps/customer-zzsbbmfc-myapp306-dev12-internal-application.gen.yaml
|
||||
create mode 100644 deploy/apps/customer-zzsbbmfc-myapp306-prod10-internal-application.gen.yaml
|
||||
create mode 100644 deploy/apps/customer-zzsbbmfc-myapp306-test7-internal-application.gen.yaml
|
||||
create mode 100644 deploy/apps/customer-zzsbbmfc-myapp306-uat9-internal-application.gen.yaml
|
||||
create mode 100644 deploy/clusters/dev12-internal/customers/customer-zzsbbmfc/components/my-app/my-app.gen.yaml
|
||||
create mode 100644 deploy/clusters/dev14-management/customers/customer-zzsbbmfc/components/my-app/my-app.gen.yaml
|
||||
create mode 100644 deploy/clusters/prod10-internal/customers/customer-zzsbbmfc/components/my-app/my-app.gen.yaml
|
||||
create mode 100644 deploy/clusters/prod9-management/customers/customer-zzsbbmfc/components/my-app/my-app.gen.yaml
|
||||
create mode 100644 deploy/clusters/test7-internal/customers/customer-zzsbbmfc/components/my-app/my-app.gen.yaml
|
||||
create mode 100644 deploy/clusters/test8-management/customers/customer-zzsbbmfc/components/my-app/my-app.gen.yaml
|
||||
create mode 100644 deploy/clusters/uat10-management/customers/customer-zzsbbmfc/components/my-app/my-app.gen.yaml
|
||||
create mode 100644 deploy/clusters/uat9-internal/customers/customer-zzsbbmfc/components/my-app/my-app.gen.yaml
|
||||
@@ -1,52 +0,0 @@
|
||||
@if(flatten && step1 || step2 || step3)
|
||||
package holos
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
// The deployment config.json configs reside in this package.
|
||||
"holos.example/config/my-app/deployment"
|
||||
)
|
||||
|
||||
// #MyApp defines a re-usable way to manage my-app for each deployment config.
|
||||
#MyApp: {
|
||||
// _config represents the concrete values from the deployment config.json
|
||||
_config: _
|
||||
|
||||
// Render components/my-app by default. See render-values.cue for where this
|
||||
// gets overridden in subsequent steps of the migration.
|
||||
name: string | *"my-app"
|
||||
path: "components/\(name)"
|
||||
|
||||
// CUE supports constraints, here we constrain environment to one of three
|
||||
// possible values.
|
||||
parameters: {
|
||||
// For use in components/my-app and components/render-values
|
||||
config: json.Marshal(_config)
|
||||
|
||||
// For use in components/componentconfig-gitops.cue
|
||||
env: _config.env
|
||||
|
||||
// The output is the reverse of the deployment config filesystem structure,
|
||||
// cluster then customer instead of customer then cluster, reflecting the
|
||||
// perspective of the platform team compared with the perspective of the app
|
||||
// team. It could be either way.
|
||||
outputBaseDir: "clusters/\(_config.cluster)/customers/\(_config.customer)"
|
||||
}
|
||||
// The app.holos.run/description annotation configures holos render platform
|
||||
// log messages.
|
||||
annotations: "app.holos.run/description": string | *"\(name) for \(_config.customer) cluster \(_config.cluster)"
|
||||
// Selector labels, useful to quickly render combinations of customer,
|
||||
// cluster, and app
|
||||
labels: customer: _config.customer
|
||||
labels: cluster: _config.cluster
|
||||
labels: app: _config.application
|
||||
}
|
||||
|
||||
// Add one holos component for each config.json file to the
|
||||
// Platform.spec.components list.
|
||||
for KEY, CONFIG in deployment.config {
|
||||
Platform: Components: (KEY): #MyApp & {
|
||||
_config: CONFIG
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
@if(flatten && step2)
|
||||
package holos
|
||||
|
||||
#MyApp: {
|
||||
// Renders components/render-values instead of the default components/my-app
|
||||
// configured in my-app.cue
|
||||
name: "render-values"
|
||||
|
||||
// Bring the config.json values into scope so we can reference them.
|
||||
_config: _
|
||||
|
||||
// Adjust the output of holos render platform so it's clear we're flatting
|
||||
// values in step 2.
|
||||
annotations: "app.holos.run/description": "flattened values for \(_config.customer) \(_config.cluster)"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user