Compare commits

..

42 Commits

Author SHA1 Message Date
Jeff McCune
6a47edbc3d guides: Add Change Service Guide (#253)
This patch also adds Organization to the Author API as an example of a
regular expression constraint.
2024-09-23 19:54:46 -07:00
Jeff McCune
67d00f1dd4 website: get rid of What is Holos? on landing page 2024-09-23 14:08:09 -07:00
Jeff McCune
bfa02cd6ed website: introduction (#258) 2024-09-23 13:45:28 -07:00
Jeff McCune
2d8ca474f3 website: Landing Page 3 (#256) 2024-09-23 10:08:25 -07:00
Jeff McCune
c7cd6f5190 website: Landing Page 2 (#256) 2024-09-20 17:14:34 -07:00
Jeff McCune
21e3e6f5e4 website: Landing Page 1 (#256) 2024-09-20 14:57:40 -07:00
Jeff McCune
16a4f89c2f doc: clarify story in the deploy a service guide pass 2
Focus on the migration team and platform team.
2024-09-20 11:12:41 -07:00
Jeff McCune
f15dea5ee7 doc: clarify story in the deploy a service guide
Focus on the migration team and platform team.
2024-09-20 11:02:41 -07:00
Jeff McCune
a3bbadd1f5 doc: apply manifests for deploy a service guide
This gets us through to the end with podinfo deployed.  Need to tell the
story of the migration team a bit better though, working with the
platform team to expose the service.
2024-09-20 09:42:00 -07:00
Jeff McCune
30cbb0d537 doc: add deploy a service guide
Covers wrapping a helm chart with a Holos Component.
2024-09-19 21:31:45 -07:00
Jeff McCune
6041fd4d76 website: fix broken links 2024-09-19 09:51:27 -07:00
Jeff McCune
fec1de0004 website: holistic platform manager social card 2024-09-19 09:49:56 -07:00
Jeff McCune
6ad24a6eec package: rename schema api to author api (#248)
Schema API is unclear, Author API is more clear the API is intended for
component authors.
2024-09-19 08:51:01 -07:00
Jeff McCune
57dedc6450 website: clean up placeholders 2024-09-19 08:30:31 -07:00
Jeff McCune
8d2a9dd659 quickstart: re-focus on core concepts 2024-09-18 17:24:44 -07:00
Jeff McCune
e3c53f5655 website: tweak features on landing page for clarity 2024-09-18 13:44:44 -07:00
Jeff McCune
3b833cdacd website: update landing page to focus on platform management
Instead of package management.
2024-09-18 13:41:36 -07:00
Jeff McCune
31d1086345 render: shorten the component rendered in the output
It's too long for documentation.  Shorten it for clarity.

Result:

```
❯ holos render platform ./platform
rendered bank-accounts-db for cluster workload in 160.7245ms
rendered bank-ledger-db for cluster workload in 162.465625ms
rendered bank-userservice for cluster workload in 166.150417ms
rendered bank-ledger-writer for cluster workload in 168.075459ms
rendered bank-balance-reader for cluster workload in 172.492292ms
rendered bank-backend-config for cluster workload in 198.117916ms
rendered bank-secrets for cluster workload in 223.200042ms
rendered gateway for cluster workload in 124.841917ms
rendered httproutes for cluster workload in 131.86625ms
rendered bank-contacts for cluster workload in 154.463792ms
rendered bank-transaction-history for cluster workload in 159.968208ms
rendered bank-frontend for cluster workload in 325.24425ms
rendered app-projects for cluster workload in 110.577916ms
rendered ztunnel for cluster workload in 137.502792ms
rendered cni for cluster workload in 209.993375ms
rendered cert-manager for cluster workload in 172.933834ms
rendered external-secrets for cluster workload in 135.759792ms
rendered local-ca for cluster workload in 98.026708ms
rendered istiod for cluster workload in 403.050833ms
rendered argocd for cluster workload in 294.663167ms
rendered gateway-api for cluster workload in 228.47875ms
rendered namespaces for cluster workload in 113.586916ms
rendered base for cluster workload in 533.76675ms
rendered external-secrets-crds for cluster workload in 529.053375ms
rendered crds for cluster workload in 931.180458ms
rendered platform in 1.248310167s
```

Previously:

```
❯ holos render platform ./platform
rendered projects/bank-of-holos/backend/components/bank-ledger-db for cluster workload in 158.534875ms
rendered projects/bank-of-holos/backend/components/bank-accounts-db for cluster workload in 159.836166ms
rendered projects/bank-of-holos/backend/components/bank-userservice for cluster workload in 160.360667ms
rendered projects/bank-of-holos/backend/components/bank-balance-reader for cluster workload in 169.478584ms
rendered projects/bank-of-holos/backend/components/bank-ledger-writer for cluster workload in 169.437833ms
rendered projects/bank-of-holos/backend/components/bank-backend-config for cluster workload in 182.089333ms
rendered projects/bank-of-holos/security/components/bank-secrets for cluster workload in 196.502792ms
rendered projects/platform/components/istio/gateway for cluster workload in 122.273083ms
rendered projects/bank-of-holos/frontend/components/bank-frontend for cluster workload in 307.573584ms
rendered projects/platform/components/httproutes for cluster workload in 149.631583ms
rendered projects/bank-of-holos/backend/components/bank-contacts for cluster workload in 153.529708ms
rendered projects/bank-of-holos/backend/components/bank-transaction-history for cluster workload in 165.375667ms
rendered projects/platform/components/app-projects for cluster workload in 107.253958ms
rendered projects/platform/components/istio/ztunnel for cluster workload in 137.22275ms
rendered projects/platform/components/istio/cni for cluster workload in 233.980958ms
rendered projects/platform/components/cert-manager for cluster workload in 171.966958ms
rendered projects/platform/components/external-secrets for cluster workload in 134.207792ms
rendered projects/platform/components/istio/istiod for cluster workload in 403.19ms
rendered projects/platform/components/local-ca for cluster workload in 97.544708ms
rendered projects/platform/components/argocd/argocd for cluster workload in 289.577208ms
rendered projects/platform/components/gateway-api for cluster workload in 218.290458ms
rendered projects/platform/components/namespaces for cluster workload in 109.534125ms
rendered projects/platform/components/istio/base for cluster workload in 526.32525ms
rendered projects/platform/components/external-secrets-crds for cluster workload in 523.7495ms
rendered projects/platform/components/argocd/crds for cluster workload in 1.002546375s
rendered platform in 1.312824333s
```
2024-09-17 11:40:14 -07:00
Jeff McCune
b737543c13 version: 0.95.0 2024-09-17 08:06:38 -07:00
Jeff McCune
8e150ee0d7 generate: fix external-secrets always out of sync in argocd
Without this patch ArgoCD treats the Application as constantly out of
sync.  This is also a good example of how to patch an arbitrary
component, though it patches the core BuildPlan itself now.  If this is
widely used, it would be nice to add this behavior to the schema api
(aka author api).
2024-09-16 21:22:23 -07:00
Jeff McCune
117a2a886d generate: fix istio-base always out of sync in argocd
Without this patch ArgoCD treats the Application as constantly out of
sync.  This is also a good example of how to patch an arbitrary
component, though it patches the core BuildPlan itself now.  If this is
widely used, it would be nice to add this behavior to the schema api
(aka author api).
2024-09-16 20:46:29 -07:00
Jeff McCune
79b41dfbf5 generate: fix istiod always out of sync in argocd
Without this patch ArgoCD treats the Application as constantly out of
sync.  This is also a good example of how to patch an arbitrary
component, though it patches the core BuildPlan itself now.  If this is
widely used, it would be nice to add this behavior to the schema api
(aka author api).
2024-09-16 20:38:35 -07:00
Jeff McCune
55562f9d83 generate: move istio-k3d schematic to projects structure
To match the current layout of the guide platform we're using for the
guides.
2024-09-16 20:02:23 -07:00
Jeff McCune
e0a636f183 generate: move gateway-api schematic to projects structure
To match the current layout of the guide platform we're using for the
guides.
2024-09-16 19:53:28 -07:00
Jeff McCune
1fa74214cf generate: move istio schematic to projects structure
To match the current layout of the guide platform we're using for the
guides.
2024-09-16 19:51:02 -07:00
Jeff McCune
e5851cac57 generate: fix bank of holos connection reset
Without this patch browsing https://bank.holos.localhost frequently gets
connection reset errors.  These errors are caused by the frontend
deployment redirecting the browser to http, which is not enabled on the
Gateway we use in the guides.

This patch sets the scheme to https which corrects the problems.

See https://github.com/GoogleCloudPlatform/bank-of-anthos/issues/478
2024-09-16 19:29:21 -07:00
Jeff McCune
4a26662b92 generate: add bank-contacts
Needed to load the home page of the Bank of Holos demo.
2024-09-16 19:29:02 -07:00
Jeff McCune
6bc6888ffc generate: add bank-transaction-history
Needed to load the home page of the Bank of Holos demo.
2024-09-16 17:00:15 -07:00
Jeff McCune
dab1f305e1 generate: add bank-balance-reader
Needed to load the home page of the Bank of Holos demo.
2024-09-16 16:52:52 -07:00
Jeff McCune
fbe79dd0af generate: add bank-ledger-db and bank-ledger-writer
Needed to load the home page of the Bank of Holos demo.
2024-09-16 16:46:35 -07:00
Jeff McCune
6d6829b149 generate: refactor bank backend config to a component
To fix ArgoCD SharedResourceWarning.
2024-09-16 16:18:31 -07:00
Jeff McCune
971a3fa280 generate: fix accounts-db using wrong service account
Needs to match the bank-of-holos service account name.
2024-09-16 15:58:50 -07:00
Jeff McCune
7632344cd1 generate: add bank-accounts-db needed by userservice
With this patch the frontend, accounts-db, and userservice all start and
become ready.

The user can log in, but on redirecting to home the site can't be
reached.
2024-09-16 15:51:29 -07:00
Jeff McCune
42067748ad generate: add bank userservice to backend 2024-09-16 15:49:25 -07:00
Jeff McCune
340c3484e5 generate: refactor how the bank jwt-key is created
This makes the example more re-usable, reader need only change the
SecretName, the bash script, and replace the #BankOfHolos references.
2024-09-16 15:02:12 -07:00
Jeff McCune
250238c286 generate: add secret store and external secret to bank-of-holos
Rather than commit the jwt private key to version control like upstream
does, we use a SecretStore and ExternalSecret to sync the secret
generated by the security team in the bank-security namespace.

With this patch the SecretStore validates and the ExternalSecret
automatically syncs the secret from the bank-security namespace to the
bank-frontend namespace.

```
❯ k get ss
NAME            AGE   STATUS   CAPABILITIES   READY
bank-security   1s    Valid    ReadWrite      True

❯ k get es
NAME      STORE           REFRESH INTERVAL   STATUS         READY
jwt-key   bank-security   5s                 SecretSynced   True
```

The pod start successfully.

```
❯ k get pods
NAME                        READY   STATUS    RESTARTS   AGE
frontend-646d797d6b-7jhrx   1/1     Running   0          2m39s

❯ k logs frontend-646d797d6b-7jhrx
{"timestamp": "2024-09-16 21:44:47", "message": "info | Starting gunicorn 22.0.0", "severity": "INFO"}
{"timestamp": "2024-09-16 21:44:47", "message": "info | Listening at: http://0.0.0.0:8080 (7)", "severity": "INFO"}
{"timestamp": "2024-09-16 21:44:47", "message": "info | Using worker: gthread", "severity": "INFO"}
{"timestamp": "2024-09-16 21:44:47", "message": "info | Booting worker with pid: 8", "severity": "INFO"}
{"timestamp": "2024-09-16 21:44:57", "message": "create_app | Unable to retrieve cluster name from metadata server metadata.google.internal.", "severity": "WARNING"}
{"timestamp": "2024-09-16 21:44:57", "message": "create_app | Unable to retrieve zone from metadata server metadata.google.internal.", "severity": "WARNING"}
{"timestamp": "2024-09-16 21:44:57", "message": "create_app | Starting frontend service.", "severity": "INFO"}
{"timestamp": "2024-09-16 21:44:57", "message": "create_app | 🚫 Tracing disabled.", "severity": "INFO"}
{"timestamp": "2024-09-16 21:44:57", "message": "create_app | Platform is set to 'local'", "severity": "INFO"}
```
2024-09-16 14:47:33 -07:00
Jeff McCune
a223e2b426 generate: fix duplicate external secrets crds
They're handled outside the helm chart to make upgrades easier.
2024-09-16 13:39:04 -07:00
Jeff McCune
63a7da02e7 generate: add external secrets operator
Need this to sync secrets into the bank-frontend and bank-backend
namespace from the bank-security namespace.
2024-09-16 13:29:03 -07:00
Jeff McCune
569f827e30 speed up argocd crds with raw urls 2024-09-16 13:29:02 -07:00
Jeff McCune
4a656db2ec render: log total render platform time 2024-09-16 13:29:02 -07:00
Jeff McCune
77b0933961 generate: add httproute for bank.holos.localhost
Expose Service frontend in the bank-frontend namespace via httproute
https://bank.holos.localhost

Organize into frontend, backend, security projects to align with three
teams who would each own this work.

remove secret from version control

Google added the secret to version control but we can generate the
secret in-cluster.  Holos makes it easier to manage the ExternalSecret
or RoleBinding necessary to get it in the right place.
2024-09-16 12:46:00 -07:00
Jeff McCune
3b796cfbbd generate: add bank-of-holos frontend
We need a way to demonstrate the value Holos offers in a platform team
managing projects for other teams.  This patch addresses the need by
establishing the bank-of-holos schematic, which is a port of the Bank of
Anthos project to Holos.

This patch adds only the frontend to get the process started.  As of
this patch the frontend pod starts and becomes ready but is not exposed
via HTTPRoute.

Refer to https://github.com/GoogleCloudPlatform/bank-of-anthos/
2024-09-15 22:08:28 -07:00
94 changed files with 5959 additions and 805 deletions

View File

@@ -5,25 +5,34 @@
"mdx"
],
"words": [
"acraccesstokens",
"admissionregistration",
"anthos",
"apiextensions",
"applicationset",
"applicationsets",
"appproject",
"appprojects",
"argoproj",
"authcode",
"authorizationpolicies",
"authpolicy",
"authproxy",
"authroutes",
"balancereader",
"buildplan",
"cainjector",
"CAROOT",
"certificaterequests",
"certificatesigningrequests",
"clsx",
"clusterexternalsecrets",
"clusterissuer",
"clusterissuers",
"clusterrole",
"clusterrolebinding",
"clustersecretstores",
"CNCF",
"configmap",
"cookiesecret",
"coredns",
@@ -40,16 +49,22 @@
"devicecode",
"dnsmasq",
"dscacheutil",
"ecrauthorizationtokens",
"entgo",
"envoyfilters",
"errgroup",
"etcdsnapshotfiles",
"externalsecret",
"externalsecrets",
"fctr",
"fieldmaskpb",
"flushcache",
"gatewayclasses",
"gcraccesstokens",
"gendoc",
"ggnpl",
"ghaction",
"githubaccesstokens",
"gitops",
"godoc",
"golangci",
@@ -57,6 +72,9 @@
"grpcreflect",
"grpcroutes",
"grpcurl",
"healthz",
"helmchartconfigs",
"helmcharts",
"holos",
"holoslogger",
"horizontalpodautoscaler",
@@ -67,8 +85,10 @@
"isatty",
"istiod",
"jbrx",
"jeffmccune",
"jetstack",
"Jsonnet",
"kfbh",
"killall",
"kubeadm",
"kubeconfig",
@@ -78,6 +98,7 @@
"kustomize",
"ldflags",
"leaderelection",
"ledgerwriter",
"libnss",
"loadbalancer",
"mattn",
@@ -101,6 +122,7 @@
"pipefail",
"PKCE",
"platformconnect",
"podcli",
"poddisruptionbudget",
"podinfo",
"portmapping",
@@ -109,9 +131,11 @@
"protojson",
"proxyconfigs",
"Pulumi",
"pushsecrets",
"putenv",
"qjbp",
"quickstart",
"readyz",
"referencegrant",
"referencegrants",
"requestauthentications",
@@ -120,14 +144,17 @@
"ropc",
"seccomp",
"SECRETKEY",
"secretstore",
"secretstores",
"serverlb",
"serverside",
"serviceaccount",
"servicebindings",
"serviceentries",
"spanid",
"spiffe",
"startupapicheck",
"statefulset",
"stefanprodan",
"structpb",
"subjectaccessreviews",
@@ -142,14 +169,18 @@
"Tokener",
"Traceid",
"traefik",
"transactionhistory",
"uibutton",
"unstage",
"untar",
"Upsert",
"urandom",
"usecases",
"userconnect",
"userdata",
"userservice",
"validatingwebhookconfiguration",
"vaultdynamicsecrets",
"virtualservices",
"wasmplugins",
"workloadentries",

View File

@@ -161,3 +161,22 @@ type Platform struct {
// platform operators to define.
Domain string `cue:"string | *\"holos.localhost\""`
}
// Organization represents organizational metadata useful across the platform.
type Organization struct {
Name string
DisplayName string
}
// OrganizationStrict represents organizational metadata useful across the
// platform. This is an example of using CUE regular expressions to constrain
// and validate configuration.
type OrganizationStrict struct {
Organization `json:",inline"`
// Name represents the organization name as a resource name. Must be 63
// characters or less. Must start with a letter. May contain non-repeating
// hyphens, letters, and numbers. Must end with a letter or number.
Name string `cue:"=~ \"^[a-z][0-9a-z-]{1,61}[0-9a-z]$\" & !~ \"--\""`
// DisplayName represents the human readable organization name.
DisplayName string `cue:"=~ \"^[0-9A-Za-z][0-9A-Za-z ]{2,61}[0-9A-Za-z]$\" & !~ \" \""`
}

View File

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

View File

@@ -3,7 +3,7 @@
# v1alpha3
```go
import "github.com/holos-run/holos/api/schema/v1alpha3"
import "github.com/holos-run/holos/api/author/v1alpha3"
```
Package v1alpha3 contains CUE definitions intended as convenience wrappers around the core data types defined in package core. The purpose of these wrappers is to make life easier for platform engineers by reducing boiler plate code and generating component build plans in a consistent manner.
@@ -17,6 +17,8 @@ Package v1alpha3 contains CUE definitions intended as convenience wrappers aroun
- [type Helm](<#Helm>)
- [type Kubernetes](<#Kubernetes>)
- [type Kustomize](<#Kustomize>)
- [type Organization](<#Organization>)
- [type OrganizationStrict](<#OrganizationStrict>)
- [type Platform](<#Platform>)
- [type StandardFleets](<#StandardFleets>)
@@ -172,6 +174,35 @@ type Kustomize struct {
}
```
<a name="Organization"></a>
## type Organization {#Organization}
Organization represents organizational metadata useful across the platform.
```go
type Organization struct {
Name string
DisplayName string
}
```
<a name="OrganizationStrict"></a>
## type OrganizationStrict {#OrganizationStrict}
OrganizationStrict represents organizational metadata useful across the platform. This is an example of using CUE regular expressions to constrain and validate configuration.
```go
type OrganizationStrict struct {
Organization `json:",inline"`
// Name represents the organization name as a resource name. Must be 63
// characters or less. Must start with a letter. May contain non-repeating
// hyphens, letters, and numbers. Must end with a letter or number.
Name string `cue:"=~ \"^[a-z][0-9a-z-]{1,61}[0-9a-z]$\" & !~ \"--\""`
// DisplayName represents the human readable organization name.
DisplayName string `cue:"=~ \"^[0-9A-Za-z][0-9A-Za-z ]{2,61}[0-9A-Za-z]$\" & !~ \" \""`
}
```
<a name="Platform"></a>
## type Platform {#Platform}

View File

@@ -0,0 +1,724 @@
---
description: Try Holos with this quick start guide.
slug: /archive/2024-09-15-quickstart
sidebar_position: 100
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import Admonition from '@theme/Admonition';
# Quickstart
In this guide, you'll experience how Holos makes the process of operating a
Platform safer, easier, and more consistent. We'll use Holos to manage a
vendor-provided Helm chart as a Component. Next, we'll mix in our own custom
resources to manage the Component with GitOps. Finally, you'll see how Holos
makes it safer and easier to maintain software over time by surfacing the exact
changes that will be applied when upgrading the vendor's chart to a new version,
before they are actually made.
The [Concepts](/docs/concepts) page defines capitalized terms such as Platform
and Component.
## What you'll need {#requirements}
You'll need the following tools installed to complete this guide.
1. [holos](/docs/install) - to build the Platform.
2. [helm](https://helm.sh/docs/intro/install/) - to render Holos Components that
wrap upstream Helm charts.
Optionally, if you'd like to apply the rendered manifests to a real Cluster,
first complete the [Local Cluster Guide](/docs/guides/local-cluster).
## Install Holos
Install Holos with the following command or other methods listed on the
[Installation](/docs/install/) page.
```bash
go install github.com/holos-run/holos/cmd/holos@latest
```
## Create a Git Repository
Start by initializing an empty Git repository. Holos operates on local files
stored in a Git repository.
<Tabs groupId="init">
<TabItem value="command" label="Command">
```bash
mkdir holos-quickstart
cd holos-quickstart
git init
```
</TabItem>
<TabItem value="output" label="Output">
```txt
Initialized empty Git repository in /holos-quickstart/.git/
```
</TabItem>
</Tabs>
This guide assumes you will run commands from the root directory of the Git
repository unless stated otherwise.
## Generate the Platform {#Generate-Platform}
Generate the Platform code in the repository root. A Platform refers to the
entire set of software holistically integrated to provide a software development
platform for your organization. In this guide, the Platform will include a
single Component to demonstrate how the concepts fit together.
```bash
holos generate platform quickstart
```
Commit the generated platform config to the repository.
<Tabs groupId="commit-platform">
<TabItem value="command" label="Command">
```bash
git add .
git commit -m "holos generate platform quickstart - $(holos --version)"
```
</TabItem>
<TabItem value="output" label="Output">
```txt
[main (root-commit) 0b17b7f] holos generate platform quickstart
213 files changed, 72349 insertions(+)
...
```
</TabItem>
</Tabs>
## Generate a Component {#generate-component}
The platform you generated is currently empty. Run the following command to
generate the CUE code that defines a Helm Component.
<Tabs groupId="gen-podinfo">
<TabItem value="command" label="Command">
```bash
holos generate component podinfo --component-version 6.6.1
```
</TabItem>
<TabItem value="output" label="Output">
```txt
generated component
```
</TabItem>
</Tabs>
The --component-version 6.6.1 flag intentionally installs an older release.
You'll see how Holos assists with software upgrades later in this guide.
The generate component command creates two files: a leaf file,
`components/podinfo/podinfo.gen.cue`, and a root file, `podinfo.gen.cue`. Holos
leverages the fact that [order is
irrelevant](https://cuelang.org/docs/tour/basics/order-irrelevance/) in CUE to
register the component with the Platform by adding a file to the root of the Git
repository. The second file defines the component in the leaf component
directory.
<Tabs groupId="podinfo-files">
<TabItem value="components/podinfo/podinfo.gen.cue" label="Leaf">
`components/podinfo/podinfo.gen.cue`
```cue showLineNumbers
package holos
// Produce a helm chart build plan.
(#Helm & Chart).Output
let Chart = {
Name: "podinfo"
Version: "6.6.1"
Namespace: "default"
Repo: name: "podinfo"
Repo: url: "https://stefanprodan.github.io/podinfo"
Values: {}
}
```
</TabItem>
<TabItem value="podinfo.gen.cue" label="Root">
`podinfo.gen.cue`
```cue showLineNumbers
package holos
// Manage podinfo on workload clusters only
for Cluster in #Fleets.workload.clusters {
#Platform: Components: "\(Cluster.name)/podinfo": {
path: "components/podinfo"
cluster: Cluster.name
}
}
```
</TabItem>
</Tabs>
In this example, we provide the minimal information needed to manage the Helm
chart: the name, version, Kubernetes namespace for deployment, and the chart
repository location.
This chart deploys cleanly without any values provided, but we include an empty
Values struct to show how Holos improves consistency and safety in Helm by
leveraging the strong type-checking in CUE. You can safely pass shared values,
such as the organizations domain name, to all Components across all clusters in
the Platform by defining them at the root of the configuration.
Commit the generated component config to the repository.
<Tabs groupId="commit-component">
<TabItem value="command" label="Command">
```bash
git add .
git commit -m "holos generate component podinfo - $(holos --version)"
```
</TabItem>
<TabItem value="output" label="Output">
```txt
[main cc0e90c] holos generate component podinfo
2 files changed, 24 insertions(+)
create mode 100644 components/podinfo/podinfo.gen.cue
create mode 100644 podinfo.gen.cue
```
</TabItem>
</Tabs>
## Render the Component
You can render individual components without adding them to a Platform, which is
helpful when developing a new component.
<Tabs groupId="render-podinfo">
<TabItem value="command" label="Command">
```bash
holos render component ./components/podinfo --cluster-name=default
```
</TabItem>
<TabItem value="output" label="Output">
```txt
cached
rendered podinfo
```
</TabItem>
</Tabs>
First, the command caches the Helm chart locally to speed up subsequent
renderings. Then, the command runs Helm to produce the output and writes it into
the deploy directory.
<Tabs groupId="tree-podinfo">
<TabItem value="command" label="Command">
```bash
tree deploy
```
</TabItem>
<TabItem value="output" label="Output">
```txt
deploy
└── clusters
└── default
└── components
└── podinfo
└── podinfo.gen.yaml
5 directories, 1 file
```
</TabItem>
</Tabs>
The component deploys to one cluster named `default`. In practice, the same
component is often deployed to multiple clusters, such as `east` and `west` to
provide redundancy and increase availability.
:::tip
This example is equivalent to running `helm template` on the chart and saving
the output to a file. Holos simplifies this task, making it safer and more
consistent when managing many charts.
:::
## Mix in an ArgoCD Application
We've seen how Holos works with Helm, but we haven't yet explored how Holos
makes it easier to consistently and safely manage all of the software in a
Platform.
Holos allows you to easily mix in resources that differentiate your Platform.
We'll use this feature to mix in an ArgoCD [Application][application] to manage
the podinfo Component with GitOps. We'll define this configuration in a way that
can be automatically and consistently reused across all future Components added
to the Platform.
Create a new file named `argocd.cue` in the root of your Git repository with the
following contents:
<Tabs groupId="argocd-config">
<TabItem value="command" label="argocd.cue">
```cue showLineNumbers
package holos
#ArgoConfig: {
Enabled: true
RepoURL: "https://github.com/holos-run/holos-quickstart-guide"
}
```
</TabItem>
</Tabs>
:::tip
If you plan to apply the rendered output to a real cluster, change the
`example.com` RepoURL to the URL of the Git repository you created in this
guide. You don't need to change the example if you're just exploring Holos by
inspecting the rendered output without applying it to a live cluster.
:::
With this file in place, render the component again.
<Tabs groupId="render-podinfo-argocd">
<TabItem value="command" label="Command">
```bash
holos render component ./components/podinfo --cluster-name=default
```
</TabItem>
<TabItem value="output" label="Output">
```txt
wrote deploy file
rendered gitops/podinfo
rendered podinfo
```
</TabItem>
</Tabs>
Holos uses the locally cached chart to improve performance and reliability. It
then renders the Helm template output along with an ArgoCD Application resource
for GitOps.
:::tip
By defining the ArgoCD configuration at the root, we again take advantage of the
fact that [order is
irrelevant](https://cuelang.org/docs/tour/basics/order-irrelevance/) in CUE.
:::
Defining the configuration at the root ensures all future leaf Components take
the ArgoCD configuration and render an Application manifest for GitOps
management.
<Tabs groupId="tree-podinfo-argocd">
<TabItem value="command" label="Command">
```bash
tree deploy
```
</TabItem>
<TabItem value="output" label="Output">
```txt
deploy
└── clusters
└── default
├── components
│   └── podinfo
│   └── podinfo.gen.yaml
└── gitops
└── podinfo.application.gen.yaml
6 directories, 2 files
```
</TabItem>
</Tabs>
Notice the new `podinfo.application.gen.yaml` file created by enabling ArgoCD in
the Helm component. The Application resource in the file looks like this:
<Tabs groupId="podinfo-application">
<TabItem value="file" label="podinfo.application.gen.yaml">
```yaml showLineNumbers
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: podinfo
namespace: argocd
spec:
destination:
server: https://kubernetes.default.svc
project: default
source:
path: ./deploy/clusters/default/components/podinfo
repoURL: https://example.com/holos-quickstart.git
targetRevision: main
```
</TabItem>
</Tabs>
:::tip
Holos generates a similar Application resource for every additional Component
added to your Platform.
:::
Finally, add and commit the results to your Platform's Git repository.
<Tabs groupId="commit-argo">
<TabItem value="command" label="Command">
```bash
git add .
git commit -m "holos render component ./components/podinfo --cluster-name=default"
```
</TabItem>
<TabItem value="output" label="Output">
```txt
[main f95cef1] holos render component ./components/podinfo --cluster-name=default
3 files changed, 134 insertions(+)
create mode 100644 argocd.cue
create mode 100644 deploy/clusters/default/components/podinfo/podinfo.gen.yaml
create mode 100644 deploy/clusters/default/gitops/podinfo.application.gen.yaml
```
</TabItem>
</Tabs>
In this section, we learned how Holos simplifies mixing resources into
Components, like an ArgoCD Application. Holos ensures consistency by managing an
Application resource for every Component added to the Platform through the
configuration you define in `argocd.cue` at the root of the repository.
## Define Workload Clusters {#workload-clusters}
We've generated a Component to manage podinfo and integrated it with our
Platform, but rendering the Platform doesn't render podinfo. Podinfo isn't
rendered because we haven't assigned any Clusters to the workload Fleet.
Define two new clusters, `east` and `west`, and assign them to the workload
Fleet. Create a new file named `clusters.cue` in the root of your Git repository
with the following contents:
<Tabs groupId="clusters">
<TabItem value="clusters.cue" label="clusters.cue">
```cue showLineNumbers
package holos
// Define two workload clusters for disaster recovery.
#Fleets: workload: clusters: {
// In CUE _ indicates values are defined elsewhere.
east: _
west: _
}
```
</TabItem>
</Tabs>
This example shows how Holos simplifies configuring multiple clusters with
similar configuration by grouping them into a Fleet.
:::tip
Fleets help segment a group of Clusters into one leader and multiple followers
by designating one cluster as the primary. Holos makes it safer, easier, and
more consistent to reconfigure which cluster is the primary. The primary can be
set to automatically restore persistent data from backups, while non-primary
clusters can be configured to automatically replicate from the primary.
Automatic database backup, restore, and streaming replication is an advanced
topic enabled by Cloud Native PG and CUE. Check back for a guide on this and
other Day 2 operations topics.
:::
## Render the Platform {#render-platform}
Render the Platform to render the podinfo Component for each of the workload
clusters.
<Tabs groupId="render-platform">
<TabItem value="command" label="Command">
```bash
holos render platform ./platform
```
</TabItem>
<TabItem value="output" label="Output">
```txt
rendered components/podinfo for cluster west in 99.480792ms
rendered components/podinfo for cluster east in 99.882667ms
```
</TabItem>
</Tabs>
The render platform command iterates over every Cluster in the Fleet and renders
each Component assigned to the Fleet. Notice the two additional subdirectories
created under the deploy directory, one for each cluster: `east` and `west`.
<Tabs groupId="tree-platform">
<TabItem value="command" label="Command">
```bash
tree deploy
```
</TabItem>
<TabItem value="output" label="Output">
```txt
deploy
└── clusters
├── default
│   ├── components
│   │   └── podinfo
│   │   └── podinfo.gen.yaml
│   └── gitops
│   └── podinfo.application.gen.yaml
# highlight-next-line
├── east
│   ├── components
│   │   └── podinfo
│   │   └── podinfo.gen.yaml
│   └── gitops
│   └── podinfo.application.gen.yaml
# highlight-next-line
└── west
├── components
│   └── podinfo
│   └── podinfo.gen.yaml
└── gitops
└── podinfo.application.gen.yaml
14 directories, 6 files
```
</TabItem>
</Tabs>
Holos ensures consistency and safety by defining the ArgoCD Application once,
with strong type checking, at the configuration root.
New Application resources are automatically generated for the `east` and `west`
workload Clusters.
<Tabs groupId="applications">
<TabItem value="east" label="east">
`deploy/clusters/east/gitops/podinfo.application.gen.yaml`
```yaml showLineNumbers
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: podinfo
namespace: argocd
spec:
destination:
server: https://kubernetes.default.svc
project: default
source:
# highlight-next-line
path: ./deploy/clusters/east/components/podinfo
repoURL: https://example.com/holos-quickstart.git
targetRevision: main
```
</TabItem>
<TabItem value="west" label="west">
`deploy/clusters/west/gitops/podinfo.application.gen.yaml`
```yaml showLineNumbers
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: podinfo
namespace: argocd
spec:
destination:
server: https://kubernetes.default.svc
project: default
source:
# highlight-next-line
path: ./deploy/clusters/west/components/podinfo
repoURL: https://example.com/holos-quickstart.git
targetRevision: main
```
</TabItem>
<TabItem value="default" label="default">
`deploy/clusters/default/gitops/podinfo.application.gen.yaml`
```yaml showLineNumbers
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: podinfo
namespace: argocd
spec:
destination:
server: https://kubernetes.default.svc
project: default
source:
# highlight-next-line
path: ./deploy/clusters/default/components/podinfo
repoURL: https://example.com/holos-quickstart.git
targetRevision: main
```
</TabItem>
</Tabs>
Add and commit the rendered Platform and workload Clusters.
<Tabs groupId="commit-render-platform">
<TabItem value="command" label="Command">
```bash
git add .
git commit -m "holos render platform ./platform - $(holos --version)"
```
</TabItem>
<TabItem value="output" label="Output">
```txt
[main 5aebcf5] holos render platform ./platform - 0.93.2
5 files changed, 263 insertions(+)
create mode 100644 clusters.cue
create mode 100644 deploy/clusters/east/components/podinfo/podinfo.gen.yaml
create mode 100644 deploy/clusters/east/gitops/podinfo.application.gen.yaml
create mode 100644 deploy/clusters/west/components/podinfo/podinfo.gen.yaml
create mode 100644 deploy/clusters/west/gitops/podinfo.application.gen.yaml
```
</TabItem>
</Tabs>
## Upgrade a Helm Chart
Holos is designed to ease the burden of Day 2 operations. With Holos, upgrading
software, integrating new software, and making safe platform-wide configuration
changes become easier.
Let's upgrade the podinfo Component to see how this works in practice. First,
update the Component version field to the latest upstream Helm chart version.
<Tabs groupId="gen-podinfo">
<TabItem value="command" label="Command">
```bash
holos generate component podinfo --component-version 6.6.2
```
</TabItem>
<TabItem value="output" label="Output">
```txt
generated component
```
</TabItem>
</Tabs>
Remove the cached chart version.
<Tabs groupId="gen-podinfo">
<TabItem value="command" label="Command">
```bash
rm -rf components/podinfo/vendor
```
</TabItem>
</Tabs>
Now re-render the Platform.
<Tabs groupId="render-platform2">
<TabItem value="command" label="Command">
```bash
holos render platform ./platform
```
</TabItem>
<TabItem value="output" label="Output">
```txt
rendered components/podinfo for cluster east in 327.10475ms
rendered components/podinfo for cluster west in 327.796541ms
```
</TabItem>
</Tabs>
Notice we're still using the upstream chart without modifying it. The Holos
component wraps around the chart to mix in additional resources and integrate
the component with the broader Platform.
## Visualize the Changes
Holos makes it easier to see exactly what changes are made and which resources
will be applied to the API server. By design, Holos operates on local files,
leaving the task of applying them to ecosystem tools like `kubectl` and ArgoCD.
This allows platform operators to inspect changes during code review, or before
committing the change at all.
For example, using `git diff`, we see that the only functional change when
upgrading this Helm chart is the deployment of a new container image tag to each
cluster. Additionally, we can roll out this change gradually by applying it to
the east cluster first, then to the west cluster, limiting the potential blast
radius of a problematic change.
<Tabs groupId="git-diff">
<TabItem value="command" label="Command">
```bash
git diff deploy/clusters/east
```
</TabItem>
<TabItem value="output" label="Output">
```diff showLineNumbers
diff --git a/deploy/clusters/east/components/podinfo/podinfo.gen.yaml b/deploy/clusters/east/components/podinfo/podinfo.gen.yaml
index 7cc3332..8c1647d 100644
--- a/deploy/clusters/east/components/podinfo/podinfo.gen.yaml
+++ b/deploy/clusters/east/components/podinfo/podinfo.gen.yaml
@@ -5,9 +5,9 @@ kind: Service
metadata:
name: podinfo
labels:
- helm.sh/chart: podinfo-6.6.1
+ helm.sh/chart: podinfo-6.6.2
app.kubernetes.io/name: podinfo
- app.kubernetes.io/version: "6.6.1"
+ app.kubernetes.io/version: "6.6.2"
app.kubernetes.io/managed-by: Helm
spec:
type: ClusterIP
@@ -29,9 +29,9 @@ kind: Deployment
metadata:
name: podinfo
labels:
- helm.sh/chart: podinfo-6.6.1
+ helm.sh/chart: podinfo-6.6.2
app.kubernetes.io/name: podinfo
- app.kubernetes.io/version: "6.6.1"
+ app.kubernetes.io/version: "6.6.2"
app.kubernetes.io/managed-by: Helm
spec:
replicas: 1
@@ -53,7 +53,7 @@ spec:
terminationGracePeriodSeconds: 30
containers:
- name: podinfo
# highlight-next-line
- image: "ghcr.io/stefanprodan/podinfo:6.6.1"
# highlight-next-line
+ image: "ghcr.io/stefanprodan/podinfo:6.6.2"
imagePullPolicy: IfNotPresent
command:
- ./podinfo
```
</TabItem>
</Tabs>
:::tip
Holos is designed to surface the _fully rendered_ manifests intended for the
Kubernetes API server, making it easier to see and reason about platform-wide
configuration changes.
:::
## Recap {#recap}
In this quickstart guide, we learned how Holos makes it easier, safer, and more
consistent to manage a Platform composed of multiple Clusters and upstream Helm
charts.
We covered how to:
1. Generate a Git repository for the Platform config.
2. Wrap the unmodified upstream podinfo Helm chart into a Component.
3. Render an individual Component.
4. Mix-in your Platform's unique resources to all Components. For example, ArgoCD Application resources.
5. Define multiple similar, but not identical, workload clusters.
6. Render the manifests for the entire Platform with the `holos render platform` command.
7. Upgrade a Helm chart to the latest version as an important Day 2 task.
8. Visualize and surface the details of planned changes Platform wide.
## Dive Deeper
If you'd like to dive deeper, check out the [Schema API][schema] and [Core
API][core] reference docs. The main difference between the schema and core
packages is that the schema is used by users to write refined CUE, while the
core package is what the schema produces for `holos` to execute. Users rarely
need to interact with the Core API when on the happy path, but can use the core
package as an escape hatch when the happy path doesn't go where you want.
[application]: https://argo-cd.readthedocs.io/en/stable/user-guide/application-specification/
[schema]: /docs/api/author/v1alpha3/
[core]: /docs/api/core/v1alpha3/

View File

@@ -1,7 +1,7 @@
---
description: Self service platform resource management for project teams.
slug: /guides/manage-a-project
sidebar_position: 200
slug: /archive/guides/2024-09-17-manage-a-project
sidebar_position: 250
---
import Tabs from '@theme/Tabs';

View File

@@ -2,4 +2,23 @@ import DocCardList from '@theme/DocCardList';
# Guides
## Start with the [Quickstart] guide
The guides are organized as a progression. We'll use Holos to manage a
fictional bank's platform, the Bank of Holos in each of the guides. In doing so
we'll take the time to explain the foundational concepts of Holos.
1. [Quickstart] covers the foundational concepts of Holos.
2. [Deploy a Service] explains how to deploy a containerized service using an
existing Helm chart. This guide then explains how to deploy a similar service
safely and consistently with CUE instead of Helm.
3. [Change a Service] covers the day two task of making configuration changes to
deployed services safely and consistently.
---
<DocCardList />
[Quickstart]: /docs/quickstart/
[Deploy a Service]: /docs/guides/deploy-a-service/
[Change a Service]: /docs/guides/change-a-service/

View File

@@ -0,0 +1,700 @@
---
description: Change a service on your platform.
slug: /guides/change-a-service
sidebar_position: 300
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import Admonition from '@theme/Admonition';
# Change a Service
In this guide we'll explore how Holos helps the frontend development team at the
[Bank of Holos] reconfigures a service they've already deployed. In doing so,
we'll see how simple configuration configuration changes are safer with type
checking, and how rendering the complete platform provides clear visibility into
changes.
We'll build on the concepts we learned in the [Quickstart] and [Deploy a
Service] guides.
## What you'll need {#requirements}
Like our other guides, this guide is intended to be useful without needing to
run the commands. If you'd like to render the platform and apply the manifests
to a real Cluster, complete the [Local Cluster
Guide](/docs/guides/local-cluster) before this guide.
You'll need the following tools installed to run the commands in this guide.
1. [holos](/docs/install) - to build the Platform.
2. [helm](https://helm.sh/docs/intro/install/) - to render Holos Components that
wrap Helm charts.
3. [kubectl](https://kubernetes.io/docs/tasks/tools/) - to render Holos
Components that render with Kustomize.
If you plan to apply the changes we make, you may delete and re-create your
local platform with the following commands.
```bash
./scripts/reset-cluster
```
Then apply the current manifests with:
```bash
./scripts/apply
```
## Fork the Git Repository
If you haven't already done so, [fork the Bank of
Holos](https://github.com/holos-run/bank-of-holos/fork) then clone the
repository to your local machine.
<Tabs groupId="git-clone">
<TabItem value="command" label="Command">
```bash
# Change YourName
git clone https://github.com/YourName/bank-of-holos
cd bank-of-holos
```
</TabItem>
<TabItem value="output" label="Output">
```txt
Cloning into 'bank-of-holos'...
remote: Enumerating objects: 1177, done.
remote: Counting objects: 100% (1177/1177), done.
remote: Compressing objects: 100% (558/558), done.
remote: Total 1177 (delta 394), reused 1084 (delta 303), pack-reused 0 (from 0)
Receiving objects: 100% (1177/1177), 2.89 MiB | 6.07 MiB/s, done.
Resolving deltas: 100% (394/394), done.
```
</TabItem>
</Tabs>
Run the rest of the commands in this guide from the root of the repository.
## Rename the Bank
Let's imagine the bank recently re-branded from The Bank of Holos to The
Holistic Bank. The software development team responsible for the front end
website needs to update the branding accordingly.
Let's explore how Holos catches errors early, before they land in production,
then guides the team to the correct place to make a change.
The bank front end web service is managed by the
`projects/bank-of-holos/frontend/components/bank-frontend/` component which
refers to the organization display name in `schema.gen.cue`.
<Tabs groupId="F5B546EB-566F-4B83-84C3-C55B40F55555">
<TabItem value="schema.gen.cue" label="schema.gen.cue">
```cue showLineNumbers
package holos
import api "github.com/holos-run/holos/api/author/v1alpha3"
// Define the default organization name
// highlight-next-line
#Organization: DisplayName: string | *"Bank of Holos"
#Organization: Name: string | *"bank-of-holos"
#Organization: api.#OrganizationStrict
#Platform: api.#Platform
#Fleets: api.#StandardFleets
_ComponentConfig: {
Resources: #Resources
ArgoConfig: #ArgoConfig
}
#Helm: api.#Helm & _ComponentConfig
#Kustomize: api.#Kustomize & _ComponentConfig
#Kubernetes: api.#Kubernetes & _ComponentConfig
#ArgoConfig: api.#ArgoConfig & {
ClusterName: _ClusterName
}
```
</TabItem>
<TabItem value="projects/bank-of-holos/frontend/components/bank-frontend/bank-frontend.cue" label="projects/bank-of-holos/frontend/components/bank-frontend/bank-frontend.cue">
```cue showLineNumbers
package holos
// Produce a kubernetes objects build plan.
(#Kubernetes & Objects).BuildPlan
let Objects = {
Name: "bank-frontend"
Namespace: #BankOfHolos.Frontend.Namespace
// Ensure resources go in the correct namespace
Resources: [_]: [_]: metadata: namespace: Namespace
// https://github.com/GoogleCloudPlatform/bank-of-anthos/blob/release/v0.6.5/kubernetes-manifests/frontend.yaml
Resources: {
Service: frontend: {
metadata: name: "frontend"
metadata: labels: {
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
spec: {
selector: {
app: "frontend"
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
_ports: http: {
name: "http"
port: 80
targetPort: 8080
protocol: "TCP"
}
ports: [for x in _ports {x}]
}
}
Deployment: frontend: {
metadata: name: "frontend"
metadata: labels: {
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
spec: {
selector: matchLabels: {
app: "frontend"
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
template: {
metadata: labels: {
app: "frontend"
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
spec: {
securityContext: {
seccompProfile: type: "RuntimeDefault"
fsGroup: 1000
runAsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
}
serviceAccountName: "bank-of-holos"
terminationGracePeriodSeconds: 5
containers: [{
env: [{
name: "BANK_NAME"
// highlight-next-line
value: #Organization.DisplayName
}, {
name: "ENV_PLATFORM"
value: "local"
}, {
name: "VERSION"
value: "v0.6.5"
}, {
name: "PORT"
value: "8080"
}, {
name: "ENABLE_TRACING"
value: "false"
}, {
name: "SCHEME"
value: "https"
}, {
name: "LOG_LEVEL"
value: "info"
}, {
name: "DEFAULT_USERNAME"
valueFrom: configMapKeyRef: {
key: "DEMO_LOGIN_USERNAME"
name: "demo-data-config"
}
}, {
name: "DEFAULT_PASSWORD"
valueFrom: configMapKeyRef: {
key: "DEMO_LOGIN_PASSWORD"
name: "demo-data-config"
}
}, {
name: "REGISTERED_OAUTH_CLIENT_ID"
valueFrom: configMapKeyRef: {
key: "DEMO_OAUTH_CLIENT_ID"
name: "oauth-config"
optional: true
}
}, {
name: "ALLOWED_OAUTH_REDIRECT_URI"
valueFrom: configMapKeyRef: {
key: "DEMO_OAUTH_REDIRECT_URI"
name: "oauth-config"
optional: true
}
}]
envFrom: [{
configMapRef: name: "environment-config"
}, {
configMapRef: name: "service-api-config"
}]
image: "us-central1-docker.pkg.dev/bank-of-anthos-ci/bank-of-anthos/frontend:v0.6.5@sha256:d72050f70d12383e4434ad04d189b681dc625f696087ddf0b5df641645c9dafa"
livenessProbe: {
httpGet: {
path: "/ready"
port: 8080
}
initialDelaySeconds: 60
periodSeconds: 15
timeoutSeconds: 30
}
name: "front"
readinessProbe: {
httpGet: {
path: "/ready"
port: 8080
}
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 10
}
resources: {
limits: {
cpu: "250m"
memory: "128Mi"
}
requests: {
cpu: "100m"
memory: "64Mi"
}
}
securityContext: {
allowPrivilegeEscalation: false
capabilities: drop: ["all"]
privileged: false
readOnlyRootFilesystem: true
}
volumeMounts: [{
mountPath: "/tmp"
name: "tmp"
}, {
mountPath: "/tmp/.ssh"
name: "publickey"
readOnly: true
}]
}]
volumes: [
{
emptyDir: {}
name: "tmp"
},
{
name: "publickey"
secret: {
items: [{key: "jwtRS256.key.pub", path: "publickey"}]
secretName: "jwt-key"
}
},
]
}
}
}
}
// Allow HTTPRoutes in the ingress gateway namespace to reference Services
// in this namespace.
ReferenceGrant: grant: #ReferenceGrant & {
metadata: namespace: Namespace
}
// Include shared resources
#BankOfHolos.Resources
}
}
```
</TabItem>
</Tabs>
Line 6 of the schema cue file defines the _default_ display name by using
`string | *"..."`. In CUE, the asterisk denotes a [default value].
Line 78 of the bank-frontend cue file refers to `#Organization.DisplayName` to
configure the front end web container.
Let's change the name of the bank by defining a new name at the root of the
configuration. Create `projects/organization.cue` with the following content.
<Tabs groupId="B386181F-EBE7-469D-8CB5-37631067669B">
<TabItem value="projects/organization.cue" label="projects/organization.cue">
```cue showLineNumbers
package holos
#Organization: DisplayName: "The Holistic-Bank"
```
</TabItem>
</Tabs>
Let's render the platform and see if this changes the name.
<Tabs groupId="A014333C-3271-4C22-87E6-2B7BF898EA3E">
<TabItem value="command" label="Command">
```bash
holos render platform ./platform
```
</TabItem>
<TabItem value="output" label="Output">
```txt
#Organization.DisplayName: 2 errors in empty disjunction:
#Organization.DisplayName: conflicting values "Bank of Holos" and "The Holistic-Bank":
/bank-of-holos/projects/organization.cue:3:29
/bank-of-holos/schema.gen.cue:6:39
// highlight-next-line
#Organization.DisplayName: invalid value "The Holistic-Bank" (out of bound =~"^[0-9A-Za-z][0-9A-Za-z ]{2,61}[0-9A-Za-z]$"):
/bank-of-holos/cue.mod/gen/github.com/holos-run/holos/api/author/v1alpha3/definitions_go_gen.cue:203:25
/bank-of-holos/cue.mod/gen/github.com/holos-run/holos/api/author/v1alpha3/definitions_go_gen.cue:188:15
/bank-of-holos/cue.mod/gen/github.com/holos-run/holos/api/author/v1alpha3/definitions_go_gen.cue:203:15
/bank-of-holos/projects/organization.cue:3:29
/bank-of-holos/schema.gen.cue:6:29
could not run: could not render component: exit status 1 at internal/render/platform.go:50
```
</TabItem>
</Tabs>
Whoops, the development team defined a value that isn't allowed by the
configuration. Someone else in the organization placed a [constraint] on the
configuration to ensure the display name contains only letters, numbers, and
spaces.
:::tip
CUE provides clear visibility where to start looking to resolve conflicts. Each
file and line number listed is a place the `#Organization.DisplayName` field is
defined.
:::
Let's try again, this time replacing the hyphen with a space.
<Tabs groupId="F93B34FA-C0C6-4793-A32F-DAD094403208">
<TabItem value="projects/organization.cue" label="projects/organization.cue">
```cue showLineNumbers
package holos
#Organization: DisplayName: "The Holistic Bank"
```
</TabItem>
</Tabs>
<Tabs groupId="5FD68778-476A-4F82-8817-71CEE205216E">
<TabItem value="command" label="Command">
```bash
holos render platform ./platform
```
</TabItem>
<TabItem value="output" label="Output">
```txt
rendered bank-ledger-db for cluster workload in 139.863625ms
rendered bank-accounts-db for cluster workload in 151.74875ms
rendered bank-balance-reader for cluster workload in 154.356083ms
rendered bank-ledger-writer for cluster workload in 161.209541ms
rendered bank-userservice for cluster workload in 163.373417ms
rendered bank-backend-config for cluster workload in 179.271208ms
rendered bank-secrets for cluster workload in 204.35625ms
rendered gateway for cluster workload in 118.707583ms
rendered httproutes for cluster workload in 140.981541ms
rendered bank-transaction-history for cluster workload in 156.066875ms
rendered bank-frontend for cluster workload in 300.102292ms
rendered bank-contacts for cluster workload in 159.89625ms
rendered cni for cluster workload in 150.754458ms
rendered istiod for cluster workload in 222.922625ms
rendered app-projects for cluster workload in 118.422792ms
rendered ztunnel for cluster workload in 142.840625ms
rendered cert-manager for cluster workload in 190.938834ms
rendered base for cluster workload in 340.679416ms
rendered local-ca for cluster workload in 107.120334ms
rendered external-secrets for cluster workload in 145.020834ms
rendered argocd for cluster workload in 299.690917ms
rendered namespaces for cluster workload in 115.862334ms
rendered gateway-api for cluster workload in 225.783833ms
rendered external-secrets-crds for cluster workload in 339.741166ms
rendered crds for cluster workload in 421.849041ms
rendered platform in 718.015959ms
```
</TabItem>
</Tabs>
Great, the platform rendered successfully so we know the display name is valid
according to the constraints. Let's see if the new display name value updated
the configuration for the bank frontend.
<Tabs groupId="6C068651-2061-4262-BE1E-7BB3E7EB66CB">
<TabItem value="command" label="Command">
```bash
git status
```
</TabItem>
<TabItem value="output" label="Output">
```txt
On branch main
Your branch and 'jeffmccune/main' have diverged,
and have 2 and 4 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
// highlight-next-line
modified: deploy/clusters/workload/components/app-projects/app-projects.gen.yaml
modified: deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml
Untracked files:
(use "git add <file>..." to include in what will be committed)
projects/organization.cue
no changes added to commit (use "git add" and/or "git commit -a")
```
</TabItem>
</Tabs>
<Tabs groupId="4A20831E-461B-4EDE-8F6E-E73C3AEC12DB">
<TabItem value="command" label="Command">
```bash
git diff
```
</TabItem>
<TabItem value="output" label="Output">
```diff
diff --git a/deploy/clusters/workload/components/app-projects/app-projects.gen.yaml b/deploy/clusters/workload/components/app-projects/app-projects.gen.yaml
index 7914756..250c660 100644
--- a/deploy/clusters/workload/components/app-projects/app-projects.gen.yaml
+++ b/deploy/clusters/workload/components/app-projects/app-projects.gen.yaml
@@ -9,7 +9,7 @@ spec:
clusterResourceWhitelist:
- group: '*'
kind: '*'
- description: Holos managed AppProject for Bank of Holos
+ description: Holos managed AppProject for The Holistic Bank
destinations:
- namespace: '*'
server: '*'
@@ -26,7 +26,7 @@ spec:
clusterResourceWhitelist:
- group: '*'
kind: '*'
- description: Holos managed AppProject for Bank of Holos
+ description: Holos managed AppProject for The Holistic Bank
destinations:
- namespace: '*'
server: '*'
@@ -43,7 +43,7 @@ spec:
clusterResourceWhitelist:
- group: '*'
kind: '*'
- description: Holos managed AppProject for Bank of Holos
+ description: Holos managed AppProject for The Holistic Bank
destinations:
- namespace: '*'
server: '*'
@@ -60,7 +60,7 @@ spec:
clusterResourceWhitelist:
- group: '*'
kind: '*'
- description: Holos managed AppProject for Bank of Holos
+ description: Holos managed AppProject for The Holistic Bank
destinations:
- namespace: '*'
server: '*'
diff --git a/deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml b/deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml
index dae6f93..d41516b 100644
--- a/deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml
+++ b/deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml
@@ -71,7 +71,7 @@ spec:
containers:
- env:
- name: BANK_NAME
- value: Bank of Holos
+ value: The Holistic Bank
- name: ENV_PLATFORM
value: local
- name: VERSION
```
</TabItem>
</Tabs>
The new display name changed the frontend container, but it _also_ affected the
app-projects component. Submitting a pull request would trigger a code review
from the platform engineering team who manages the app-projects component.
Let's see how to narrow the change down to limit the scope to the bank's user
facing services. All of these serves are managed under
`projects/bank-of-holos/` Move the `organization.cue` file we created into this
folder to limit the scope of configuration to the the components contained within.
```bash
mv projects/organization.cue projects/bank-of-holos/
```
Render the platform and review what changed.
<Tabs groupId="0FFEC244-B59B-4136-9C82-837985DC2AB8">
<TabItem value="command" label="Command">
```bash
holos render platform ./platform
```
</TabItem>
<TabItem value="output" label="Output">
```txt
rendered bank-ledger-db for cluster workload in 163.814917ms
rendered bank-accounts-db for cluster workload in 163.960208ms
rendered bank-userservice for cluster workload in 164.1625ms
rendered bank-ledger-writer for cluster workload in 169.185291ms
rendered bank-balance-reader for cluster workload in 174.5455ms
rendered bank-backend-config for cluster workload in 178.092125ms
rendered bank-secrets for cluster workload in 202.305334ms
rendered gateway for cluster workload in 122.81725ms
rendered httproutes for cluster workload in 134.121084ms
rendered bank-contacts for cluster workload in 146.4185ms
rendered bank-frontend for cluster workload in 311.35425ms
rendered bank-transaction-history for cluster workload in 160.103ms
rendered cni for cluster workload in 145.762083ms
rendered istiod for cluster workload in 216.0065ms
rendered app-projects for cluster workload in 117.684333ms
rendered ztunnel for cluster workload in 144.555292ms
rendered cert-manager for cluster workload in 178.247917ms
rendered base for cluster workload in 336.679ms
rendered external-secrets for cluster workload in 142.21825ms
rendered local-ca for cluster workload in 101.249ms
rendered argocd for cluster workload in 280.54525ms
rendered namespaces for cluster workload in 106.822042ms
rendered gateway-api for cluster workload in 200.459791ms
rendered external-secrets-crds for cluster workload in 470.125833ms
rendered crds for cluster workload in 844.388666ms
rendered platform in 1.154937084s
```
</TabItem>
</Tabs>
<Tabs groupId="DE4FEEE5-FC53-48A6-BC6F-D0EA1DBFD00C">
<TabItem value="command" label="Command">
```bash
git diff
```
</TabItem>
<TabItem value="output" label="Output">
```diff
diff --git a/deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml b/deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml
index dae6f93..d41516b 100644
--- a/deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml
+++ b/deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml
@@ -71,7 +71,7 @@ spec:
containers:
- env:
- name: BANK_NAME
- value: Bank of Holos
+ value: The Holistic Bank
- name: ENV_PLATFORM
value: local
- name: VERSION
```
</TabItem>
</Tabs>
Great! This time, the only manifest affected is our `bank-frontend.gen.yaml`.
The `BANK_NAME` environment variable will change as we expected.
Let's commit and push this change and see if it works in the platform.
<Tabs groupId="435D9C60-F841-4CF1-A947-506422E6BAC9">
<TabItem value="command" label="Command">
```bash
git add .
git commit -m 'frontend: rename bank to The Holistic Bank'
git push
```
</TabItem>
<TabItem value="output" label="Output">
```txt
[main fda74ec] frontend: rename bank to The Holistic Bank
2 files changed, 4 insertions(+), 1 deletion(-)
create mode 100644 projects/bank-of-holos/organization.cue
```
</TabItem>
</Tabs>
Now that we've pushed the change, let's apply the change to the platform.
## Apply the Change
Once we've pushed the change, navigate to the [bank-frontend GitOps
Application](https://argocd.holos.localhost/applications/argocd/bank-frontend?view=tree&resource=).
We can see the Deployment needs to sync to the desired state we just pushed.
![bank-frontend out of sync](./img/change-a-service-out-of-sync.png)
Clicking on the frontend Deployment, we see the diff with the change we expect.
![bank-frontend diff](./img/change-a-service-diff.png)
Sync the change, ArgoCD applies the desired configuration state to the cluster
and Kubernetes handles rolling out the updated Deployment resource.
![bank-frontend progressing](./img/change-a-service-progressing.png)
Soon, the deployment finishes and the component is in sync again.
![bank-frontend in sync](./img/change-a-service-in-sync.png)
Finally, let's see if the name actually changed on the website. Navigate to
https://bank.holos.localhost/.
![bank-frontend login page](./img/change-a-service-login-page.png)
Great! We successfully made our change and successfully applied the changed
configuration to the platform.
- We saw how multiple teams are could be impacted by defining configuration at
the `projects/` path.
- We scoped our change to only affect components within the
`projects/bank-of-holos/` path, limiting the impact on other teams.
- We saw how CUE can be used to constrain values in Holos, increasing safety.
- We saw how CUE surfaces the file and line number of _every_ place to look for
where a value is defined, making it faster and easier to troubleshoot problems..
Thanks for taking the time to work through this guide.
[Quickstart]: /docs/quickstart/
[Deploy a Service]: /docs/guides/deploy-a-service/
[Change a Service]: /docs/guides/change-a-service/
[Helm]: /docs/api/author/v1alpha3/#Helm
[Kubernetes]: /docs/api/author/v1alpha3/#Kubernetes
[Kustomize]: /docs/api/author/v1alpha3/#Kustomize
[ComponentFields]: /docs/api/author/v1alpha3/#ComponentFields
[platform-files]: /docs/quickstart/#how-platform-rendering-works
[AppProject]: https://argo-cd.readthedocs.io/en/stable/user-guide/projects/
[unification operator]: https://cuelang.org/docs/reference/spec/#unification
[code-owners]: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
[Kustomization API]: https://github.com/kubernetes-sigs/kustomize/blob/release-kustomize-v5.2/api/types/kustomization.go#L34
[cue import]: https://cuelang.org/docs/reference/command/cue-help-import/
[cue get go]: https://cuelang.org/docs/concept/how-cue-works-with-go/
[timoni-crds]: https://timoni.sh/cue/module/custom-resources/
[HTTPRoute]: https://gateway-api.sigs.k8s.io/api-types/httproute/?h=filter
[Ingress]: https://kubernetes.io/docs/concepts/services-networking/ingress/
[hidden field]: https://cuelang.org/docs/tour/references/hidden/
[comprehension]: https://cuelang.org/docs/reference/spec/#comprehensions
[code owners]: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
[ReferenceGrant]: https://gateway-api.sigs.k8s.io/api-types/referencegrant/
[Local Cluster Guide]: /docs/guides/local-cluster
[Bank of Holos]: https://github.com/holos-run/bank-of-holos
[default value]: https://cuelang.org/docs/tour/types/defaults/
[constraint]: https://cuelang.org/docs/tour/basics/constraints/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,15 @@
---
description: Helm Component
slug: /guides/helm-component
sidebar_position: 400
---
# Helm Component
The [Deploy a Service](/docs/guides/deploy-a-service/) guide is the best guide
we have on wrapping a Helm chart in a Holos Component. The [Helm] section of
the Author API may also be useful.
[Helm]: /docs/api/author/v1alpha3/#Helm
[Kubernetes]: /docs/api/author/v1alpha3/#Kubernetes
[Kustomize]: /docs/api/author/v1alpha3/#Kustomize

Binary file not shown.

After

Width:  |  Height:  |  Size: 690 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 997 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1009 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 617 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 794 KiB

View File

@@ -0,0 +1,20 @@
---
description: Kubernetes Component
slug: /guides/kubernetes-component
sidebar_position: 500
---
# Kubernetes Component
:::warning
TODO
:::
This is a placeholder for a guide for managing Kubernetes resources directly
from a Holos Component with strong type checking.
In the meantime, please refer to the [Kubernetes] section of the Author API.
[Helm]: /docs/api/author/v1alpha3/#Helm
[Kubernetes]: /docs/api/author/v1alpha3/#Kubernetes
[Kustomize]: /docs/api/author/v1alpha3/#Kustomize

View File

@@ -0,0 +1,20 @@
---
description: Wrap a Kustomize Kustomization in a Holos Component.
slug: /guides/kustomize-component
sidebar_position: 600
---
# Kustomize Component
:::warning
TODO
:::
This is a placeholder for a guide on wrapping a Kustomize Kustomization base
with a Holos component.
In the meantime, please refer to the [Kustomize] section of the Author API.
[Helm]: /docs/api/author/v1alpha3/#Helm
[Kubernetes]: /docs/api/author/v1alpha3/#Kubernetes
[Kustomize]: /docs/api/author/v1alpha3/#Kustomize

View File

@@ -1,7 +1,7 @@
---
description: Build a local Cluster to use with these guides.
slug: /guides/local-cluster
sidebar_position: 300
sidebar_position: 999
---
import Tabs from '@theme/Tabs';

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,112 @@ slug: /
# Introduction
:::warning TODO
See [introduction](https://github.com/facebook/docusaurus/blob/main/website/docs/introduction.mdx?plain=1)
:::
Welcome to Holos. Holos is an open source tool to manage software development
platforms safely, easily, and consistently. We built Holos to help engineering
teams work more efficiently together by empowering them to build golden paths
and paved roads for other teams to leverage for quicker delivery.
## Documentation
- [Guides] are organized into example use-cases of how Holos helps engineering
teams at the fictional Bank of Holos deliver business value on the bank's
platform.
- The [API Reference] is a technical reference for when you're writing CUE code to define your platform.
## Backstory
At [Open Infrastructure Services], each of us has helped dozens of companies
build and operate their software development platform over the course of our
career. During the U.S. presidential election just before the pandemic our
second largest client, Twitter, had a global outage lasting the better part of a
day. At the time, we were helping the core infrastructure team by managing
their production configuration management system so the team could focus on
delivering key objectives for the business. In this position, we had a front
row seat into what happened that day.
One of Twitter's employees, a close friend of ours and engineer on the team,
landed a trivial one line change to the firewall configuration. Less than 30
minutes later literally everything was down. The one line change, which passed
code review and seemed harmless, resulted in the host firewall reverting to the
default state on hundreds of thousands of servers. All connections to all
servers globally were blocked and dropped. Except SSH, thankfully. At least
one Presidential candidate complained loudly.
This incident led us to deeply consider a few key problems about Twitter's
software development platform, problems which made their way all the way up to
the board of directors to solve.
1. **Lack of Visibility** - There was no way to see clearly the impact a simple one-line
change could have on the platform. This lack of visibility made it difficult
for engineers to reason about changes they were writing and reviewing.
2. **Large Blast Radius** - All changes, no matter how small or large, affected the
entire global fleet within 30 minutes. Twitter needed a way to cap the
potential blast radius to prevent global outages.
3. **Incomplete Tooling** - Twitter had the correct processes in place, but
their tooling didn't support their process. The one line change was tested and
peer reviewed prior to landing, but the tooling didn't surface the information
they needed when they needed it.
Over the next few years we built features for Twitter's configuration management
system that solved each of these problems. At the same time, I started
exploring my curiosity of what these solutions would look like in the context of
Kubernetes and cloud native software instead of a traditional configuration
management context.
As Google Cloud partners, we had the opportunity to work with Google's largest
customers and learn how they built their software development platforms on
Kubernetes. Over the course of the pandemic, we built a software development
platform made largely in the same way, taking off the shelf CNCF projects like
ArgoCD, the Kubernetes Prometheus Stack, Istio, Cert Manager, External Secrets
Operator, etc... and integrating them into a holistic software development
platform. We started with the packaging recommended by the upstream project.
Helm was and still is the most common distribution method, but many projects
also provided plain yaml, kustomize bases, or sometimes even jsonnet in the case
of the prometheus community. We then wrote scripts to mix-in the resources we
needed to integrate each piece of software with the platform as a whole. For
example, we often passed Helm's output to Kustomize to add common labels or fix
bugs in the upstream chart, like missing namespace fields. We wrote umbrella
charts to mix in Ingress, HTTPRoute, and ExternalSecret resources to the vendor
provided chart.
We viewed these scripts as necessary glue to assemble and fasten the components
together into a platform, but we were never fully satisfied with them. Umbrella
charts became difficult to maintain once there were multiple environments,
regions, and cloud providers in the platform. Nested for loops in yaml
templates created significant friction and were a challenge to troubleshoot
because they obfuscated what was happening. The scripts, too, made it difficult
to see what was happening, when, and fix issues in them that affected all
components in the platform.
Despite the makeshift scripts and umbrella charts, the overall approach had a
significant advantage. The scripts always produced fully rendered manifests
stored in plain text files. We committed these files to version control and
used ArgoCD to apply them. The ability to make a one-line change, render the
whole platform, then see clearly what changed platform-wide resulted in less
time spent troubleshooting and fewer errors making their way to production.
For awhile, we lived with the scripts and charts. I couldn't stop thinking
about the [Why are we templating
YAML?](https://hn.algolia.com/?dateRange=all&page=0&prefix=false&query=https%3A%2F%2Fleebriggs.co.uk%2Fblog%2F2019%2F02%2F07%2Fwhy-are-we-templating-yaml&sort=byDate&type=story)
post on Hacker News though. I was curious what it would look like to replace
our scripts and umbrella charts with something that helped address the 3 main
problems Twitter experienced.
After doing quite a bit of digging and talking with folks, I found
[CUE](https://cuelang.org). I took our scripts and charts and re-wrote the same
functionality we needed from the glue-layer in Go and CUE. The result is a new
tool, `holos`, built to complement Helm, Kustomize, and JSonnet, but not replace
them. Holos leverages CUE to make it easier and safer for teams to define
golden paths and paved roads without having to write bespoke, makeshift scripts
or template text.
Thanks for reading this far, give Holos a try locally with out [Quickstart]
guide.
[Guides]: /docs/guides/
[API Reference]: /docs/api/
[Quickstart]: /docs/quickstart/
[CUE]: https://cuelang.org/
[Author API]: /docs/api/author/
[Core API]: /docs/api/core/
[Open Infrastructure Services]: https://openinfrastructure.co/

View File

@@ -2,4 +2,12 @@ import DocCardList from '@theme/DocCardList';
# Get Started
## Start with the [Quickstart] guide
---
These documents provide additional context to supplement the [Quickstart] guide.
<DocCardList />
[Quickstart]: /docs/quickstart/

View File

@@ -6,65 +6,10 @@ sidebar_position: 300
# Comparison
:::tip
Holos is designed to complement and improve, not replace, existing tools in the
cloud native ecosystem.
:::
## Helm
### Chart Users
Describe how things are different when using an upstream helm chart.
### Chart Authors
Describe how things are different when writing a new helm chart.
## Kustomize
TODO
## ArgoCD
TODO
## Flux
TODO
## Timoni
| Aspect | Timoni | Holos | Comment |
| ---------- | -------------------- | -------------------- | ---------------------------------------------------------------------------------------- |
| Language | CUE | CUE | Like Holos, Timoni is also built on CUE. |
| Artifact | OCI Image | Plain YAML Files | The Holos Authors find plain files easier to work with and reason about than OCI images. |
| Outputs to | OCI Image Repository | Local Git repository | Holos is designed for use with existing GitOps tools. |
| Concept | Module | Component | A Timoni Module is analogous to a Holos Component. |
| Concept | Bundle | Platform | A Timoni Bundle is somewhat similar, but smaller in scope to a Holos Platform. |
:::important
The Holos Authors are deeply grateful to Stefan and Timoni for the capability of
importing Kubernetes custom resource definitions into CUE. Without this
functionality, much of the Kubernetes ecosystem would be more difficult to
manage in CUE and therefore in Holos.
:::
## KubeVela
1. Also built on CUE.
2. Intended to create an Application abstraction.
3. Holos prioritizes composition over abstraction.
4. An abstraction of an Application acts as a filter that removes all but the lowest common denominator functionality. The Holos Authors have found this filtering effect to create excessive friction for software developers.
5. Holos focuses instead on composition to empower developers and platform engineers to leverage the unique features and functionality of their software and platform.
## Pulumi
TODO
## Jsonnet
TODO

View File

@@ -4,7 +4,7 @@ import type * as Preset from '@docusaurus/preset-classic';
const config: Config = {
title: 'Holos',
tagline: 'The Holistic Package Manager for Cloud Native Applications',
tagline: 'Holos helps you manage your software development platform safely and easily.',
favicon: 'img/favicon.ico',
// Set the production url of your site here
@@ -12,6 +12,7 @@ const config: Config = {
// Set the /<baseUrl>/ pathname under which your site is served
// For GitHub pages deployment, it is often '/<projectName>/'
baseUrl: '/',
// trailing slash is necessary for Cloudflare pages.
trailingSlash: true,
// GitHub pages deployment config.
@@ -65,7 +66,7 @@ const config: Config = {
blogSidebarTitle: "All posts",
feedOptions: {
type: 'all',
copyright: `Copyright © ${new Date().getFullYear()}, The Holos Authors.`,
copyright: `Copyright © ${new Date().getFullYear()}, The Holos Authors`,
},
showReadingTime: false,
},

View File

@@ -44,14 +44,14 @@ const sidebars: SidebarsConfig = {
link: { type: 'doc', id: 'api' },
items: [
{
label: 'Schema API',
label: 'Author API',
type: 'category',
link: { type: 'doc', id: 'api/schema' },
link: { type: 'doc', id: 'api/author' },
collapsed: true,
items: [
{
type: 'autogenerated',
dirName: 'api/schema',
dirName: 'api/author',
},
]
},

View File

@@ -8,53 +8,58 @@ type FeatureItem = {
description: JSX.Element;
};
// TODO: Consider focusing on the three pillars of Safe, Easy, Consistent.
// We don't focus on features, but rather problems and solutions.
const FeatureList: FeatureItem[] = [
{
title: 'Kustomize Helm',
Svg: require('@site/static/img/base00/undraw_together_re_a8x4.svg').default,
title: 'For Platform Engineers',
Svg: require('@site/static/img/base00/undraw_software_engineer_re_tnjc.svg').default,
description: (
<>
Super charge your existing Helm charts by providing well defined,
validated input values, post-processing the output with Kustomize,
and mixing in your own custom resources. All without modifying upstream
charts to alleviate the pain of upgrades.
Spend more time building platform features and less time maintaining
scripts and text templates. Add type checking and validation to your
existing Helm charts and manifests. Define golden paths for teams to
safely spin up new projects without interrupting you. Automatically
manage Namespaces, Certificates, Secrets, Roles, and labels with
strongly typed CUE definitions. Take unmodified, upstream software and
mix-in the resources making your platform unique and valuable.
<br />
<a href="/docs/">Learn More</a>
</>
),
},
{
title: 'Unified Data Model',
Svg: require('@site/static/img/base00/undraw_fitting_pieces_re_nss7.svg').default,
title: 'For Software Developers',
Svg: require('@site/static/img/base00/undraw_through_the_park_lxnl.svg').default,
description: (
<>
Unify all of your platform components into one well-defined, strongly
typed data model with CUE. Holos makes it easier and safer to integrate
seamlessly with software distributed with current and future tools that
produce Kubernetes resource manifests.
Move faster along paved roads provided by your platform and security
teams. Quickly spin up new projects and environments without filing
tickets. Develop where it works best for you, locally or in the cloud.
Deploy your existing Helm charts, Kubernetes manifests, or containers
safely and confidently with strong type checking. Reduce the friction of
integrating your services into your organization's platform.
<br />
<a href="/docs/">Learn More</a>
</>
),
},
{
title: 'Deep Insights',
Svg: require('@site/static/img/base00/undraw_code_review_re_woeb.svg').default,
title: 'For Security Teams',
Svg: require('@site/static/img/base00/undraw_security_on_re_e491.svg').default,
description: (
<>
Reduce risk and increase confidence in your configuration changes.
Holos offers clear visibility into complete resource configuration
<i>before</i> being applied.
Express your security policies as reusable, well defined, typed
configuration. Build guard rails making it easy to develop services
securely. Automatically provision and configure SecretStores,
ExternalSecrets, AuthorizationPolicies, RoleBindings, etc... for project
teams. Gain clear visibility into the complete configuration of the
platform to quickly identify risk and audit your security posture.
Integrate your preferred security tools with the platform.
<br />
<a href="/docs/">Learn More</a>
</>
),
},
{
title: 'Interoperable',
Svg: require('@site/static/img/base00/undraw_version_control_re_mg66.svg').default,
description: (
<>
Holos is designed for compatibility with your preferred tools and
processes, for example git diff and code reviews.
</>
),
},
}
];
function Feature({ title, Svg, description }: FeatureItem) {

View File

@@ -10,6 +10,18 @@
overflow-wrap: anywhere;
} */
.hero__title {
text-align: left;
}
.hero__subtitle {
text-align: left;
}
.projectDesc {
text-align: left;
}
/* You can override the default Infima variables here. */
:root {
--ifm-link-color: #268bd2;

View File

@@ -17,10 +17,16 @@ function HomepageHeader() {
</Heading>
<p className="hero__subtitle">{siteConfig.tagline}</p>
<p className="projectDesc">
Holos adds CUE's type safety, unified structure, and strong validation
features to your current software packages, including Helm and
Kustomize. These features make the experience of integrating software
packages into a holistic platform a pleasant journey.
Engineering teams spend considerable time and effort gluing software
projects together into a platform. This integration glue is usually
made with bespoke scripts and error prone text templates. This glue
layer is often makeshift, slowing teams down and inviting outages due
to configuration errors.
</p>
<p className="projectDesc">
Holos helps teams deliver value faster by offering a well defined,
safe, and automated integration layer to manage your platform
holistically.
</p>
<div className={styles.buttons}>
<Link
@@ -31,11 +37,12 @@ function HomepageHeader() {
<span className={styles.divider}></span>
<Link
className="button button--primary button--lg"
to="docs/concepts">
to="docs/">
Learn More
</Link>
<span className={styles.divider}></span>
</div>
</div>
</div >
</header >
);
}
@@ -44,8 +51,8 @@ export default function Home(): JSX.Element {
const { siteConfig } = useDocusaurusContext();
return (
<Layout
title={`${siteConfig.title} Package Manager`}
description="Holos adds CUE's type safety, unified structure, and strong validation features to your current software packages, including Helm and Kustomize.">
title={`${siteConfig.title} Platform Manager`}
description="Holos adds CUE's type safety, unified structure, and strong validation features to your Kubernetes configuration manifests, including Helm and Kustomize.">
<HomepageHeader />
<main>
<HomepageFeatures />

Binary file not shown.

Before

Width:  |  Height:  |  Size: 461 KiB

After

Width:  |  Height:  |  Size: 480 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 KiB

View File

@@ -19,7 +19,11 @@ let Kustomization = ks.#Kustomization & {
// Kustomize the intermediate build plan resources.
BuildPlanResources,
// Mix-in external resources.
"https://github.com/argoproj/argo-cd//manifests/crds/?ref=v\(#ArgoCD.Version)",
"https://raw.githubusercontent.com/argoproj/argo-cd/v\(#ArgoCD.Version)/manifests/crds/application-crd.yaml",
"https://raw.githubusercontent.com/argoproj/argo-cd/v\(#ArgoCD.Version)/manifests/crds/applicationset-crd.yaml",
"https://raw.githubusercontent.com/argoproj/argo-cd/v\(#ArgoCD.Version)/manifests/crds/appproject-crd.yaml",
// This method also works, but takes about 5 seconds longer each build.
// "https://github.com/argoproj/argo-cd//manifests/crds/?ref=v\(#ArgoCD.Version)",
]
}

View File

@@ -0,0 +1,51 @@
package holos
// Manage on workload clusters only
for Cluster in #Fleets.workload.clusters {
// Owned by the security team
#Platform: Components: "\(Cluster.name)/bank-secrets": {
path: "projects/bank-of-holos/security/components/bank-secrets"
cluster: Cluster.name
}
// Owned by the frontend team
#Platform: Components: "\(Cluster.name)/bank-frontend": {
path: "projects/bank-of-holos/frontend/components/bank-frontend"
cluster: Cluster.name
}
// Owned by the backend team
#Platform: Components: "\(Cluster.name)/bank-backend-config": {
path: "projects/bank-of-holos/backend/components/bank-backend-config"
cluster: Cluster.name
}
#Platform: Components: "\(Cluster.name)/bank-accounts-db": {
path: "projects/bank-of-holos/backend/components/bank-accounts-db"
cluster: Cluster.name
}
#Platform: Components: "\(Cluster.name)/bank-userservice": {
path: "projects/bank-of-holos/backend/components/bank-userservice"
cluster: Cluster.name
}
#Platform: Components: "\(Cluster.name)/bank-ledger-db": {
path: "projects/bank-of-holos/backend/components/bank-ledger-db"
cluster: Cluster.name
}
#Platform: Components: "\(Cluster.name)/bank-ledger-writer": {
path: "projects/bank-of-holos/backend/components/bank-ledger-writer"
cluster: Cluster.name
}
#Platform: Components: "\(Cluster.name)/bank-balance-reader": {
path: "projects/bank-of-holos/backend/components/bank-balance-reader"
cluster: Cluster.name
}
#Platform: Components: "\(Cluster.name)/bank-transaction-history": {
path: "projects/bank-of-holos/backend/components/bank-transaction-history"
cluster: Cluster.name
}
#Platform: Components: "\(Cluster.name)/bank-contacts": {
path: "projects/bank-of-holos/backend/components/bank-contacts"
cluster: Cluster.name
}
}

View File

@@ -0,0 +1,26 @@
package holos
// Platform wide definitions
#BankOfHolos: {
Name: "bank-of-holos"
Frontend: Namespace: "bank-frontend"
Backend: Namespace: "bank-backend"
Security: Namespace: "bank-security"
// Resources to manage in each of the namespaces.
Resources: #Resources
}
// Register namespaces
#Namespaces: (#BankOfHolos.Frontend.Namespace): _
#Namespaces: (#BankOfHolos.Backend.Namespace): _
#Namespaces: (#BankOfHolos.Security.Namespace): _
// Register projects
#AppProjects: "bank-frontend": _
#AppProjects: "bank-backend": _
#AppProjects: "bank-security": _
// Register HTTPRoutes.
// bank.example.com routes to Service frontend in the bank-frontend namespace.
#HTTPRoutes: bank: _backendRefs: frontend: namespace: #BankOfHolos.Frontend.Namespace

View File

@@ -0,0 +1,3 @@
package holos
#ArgoConfig: AppProject: #AppProjects["bank-backend"].metadata.name

View File

@@ -0,0 +1,122 @@
package holos
// Produce a kubernetes objects build plan.
(#Kubernetes & Objects).BuildPlan
let BankName = #BankOfHolos.Name
let CommonLabels = {
application: BankName
environment: "development"
team: "accounts"
tier: "db"
}
let Objects = {
Name: "bank-accounts-db"
Namespace: #BankOfHolos.Backend.Namespace
// Ensure resources go in the correct namespace
Resources: [_]: [_]: metadata: namespace: Namespace
// https://github.com/GoogleCloudPlatform/bank-of-anthos/blob/release/v0.6.5/kubernetes-manifests/accounts-db.yaml
Resources: {
ConfigMap: "accounts-db-config": {
apiVersion: "v1"
data: {
ACCOUNTS_DB_URI: "postgresql://accounts-admin:accounts-pwd@accounts-db:5432/accounts-db"
POSTGRES_DB: "accounts-db"
POSTGRES_PASSWORD: "accounts-pwd"
POSTGRES_USER: "accounts-admin"
}
kind: "ConfigMap"
metadata: {
labels: {
app: "accounts-db"
CommonLabels
}
name: "accounts-db-config"
}
}
Service: "accounts-db": {
apiVersion: "v1"
kind: "Service"
metadata: {
name: "accounts-db"
labels: CommonLabels
}
spec: {
ports: [{
name: "tcp"
port: 5432
protocol: "TCP"
targetPort: 5432
}]
selector: {
app: "accounts-db"
CommonLabels
}
type: "ClusterIP"
}
}
StatefulSet: "accounts-db": {
apiVersion: "apps/v1"
kind: "StatefulSet"
metadata: {
name: "accounts-db"
labels: CommonLabels
}
spec: {
replicas: 1
selector: matchLabels: {
app: "accounts-db"
CommonLabels
}
serviceName: "accounts-db"
template: {
metadata: labels: {
app: "accounts-db"
CommonLabels
}
spec: {
containers: [{
envFrom: [{
configMapRef: name: "environment-config"
}, {
configMapRef: name: "accounts-db-config"
}, {
configMapRef: name: "demo-data-config"
}]
image: "us-central1-docker.pkg.dev/bank-of-anthos-ci/bank-of-anthos/accounts-db:v0.6.5@sha256:abb955756a82b115e0fd9c5fa1527ae1a744b398b357fd6d7a26348feccad181"
name: "accounts-db"
ports: [{containerPort: 5432}]
resources: {
limits: {
cpu: "250m"
memory: "512Mi"
}
requests: {
cpu: "100m"
memory: "128Mi"
}
}
volumeMounts: [{
mountPath: "/var/lib/postgresql/data"
name: "postgresdb"
subPath: "postgres"
}]
}]
serviceAccount: BankName
serviceAccountName: BankName
volumes: [{
emptyDir: {}
name: "postgresdb"
}]
}
}
}
}
}
}

View File

@@ -0,0 +1,33 @@
package holos
// Produce a kubernetes objects build plan.
(#Kubernetes & Objects).BuildPlan
let BankName = #BankOfHolos.Name
let CommonLabels = {
application: BankName
environment: "development"
tier: "backend"
}
let Objects = {
Name: "bank-backend-config"
Namespace: #BankOfHolos.Backend.Namespace
// Ensure resources go in the correct namespace
Resources: [_]: [_]: metadata: namespace: Namespace
Resources: [_]: [_]: metadata: labels: CommonLabels
// https://github.com/GoogleCloudPlatform/bank-of-anthos/blob/release/v0.6.5/kubernetes-manifests/userservice.yaml
Resources: {
// Allow HTTPRoutes in the ingress gateway namespace to reference Services
// in this namespace.
ReferenceGrant: grant: #ReferenceGrant & {
metadata: namespace: Namespace
}
// Include shared resources
#BankOfHolos.Resources
}
}

View File

@@ -0,0 +1,179 @@
package holos
// Produce a kubernetes objects build plan.
(#Kubernetes & Objects).BuildPlan
let BankName = #BankOfHolos.Name
let CommonLabels = {
application: BankName
environment: "development"
team: "ledger"
tier: "backend"
}
let Objects = {
Name: "bank-balance-reader"
Namespace: #BankOfHolos.Backend.Namespace
// Ensure resources go in the correct namespace
Resources: [_]: [_]: metadata: namespace: Namespace
Resources: [_]: [_]: metadata: labels: CommonLabels
// https://github.com/GoogleCloudPlatform/bank-of-anthos/blob/release/v0.6.5/kubernetes-manifests
Resources: {
Service: balancereader: {
apiVersion: "v1"
kind: "Service"
metadata: {
name: "balancereader"
labels: CommonLabels
}
spec: {
ports: [{
name: "http"
port: 8080
targetPort: 8080
}]
selector: {
app: "balancereader"
CommonLabels
}
type: "ClusterIP"
}
}
Deployment: balancereader: {
apiVersion: "apps/v1"
kind: "Deployment"
metadata: {
name: "balancereader"
labels: CommonLabels
}
spec: {
selector: matchLabels: {
app: "balancereader"
CommonLabels
}
template: {
metadata: labels: {
app: "balancereader"
CommonLabels
}
spec: {
containers: [{
env: [{
name: "VERSION"
value: "v0.6.5"
}, {
name: "PORT"
value: "8080"
}, {
name: "ENABLE_TRACING"
value: "false"
}, {
name: "ENABLE_METRICS"
value: "false"
}, {
name: "POLL_MS"
value: "100"
}, {
name: "CACHE_SIZE"
value: "1000000"
}, {
name: "JVM_OPTS"
value: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -Xms256m -Xmx512m"
}, {
name: "LOG_LEVEL"
value: "info"
}, {
name: "NAMESPACE"
valueFrom: fieldRef: fieldPath: "metadata.namespace"
}]
envFrom: [{
configMapRef: name: "environment-config"
}, {
configMapRef: name: "ledger-db-config"
}]
image: "us-central1-docker.pkg.dev/bank-of-anthos-ci/bank-of-anthos/balancereader:v0.6.5@sha256:de01f16554ae2d0b49ac85116e6307da8c0f8a35f50a0cf25e1e4a4fe18dca83"
livenessProbe: {
httpGet: {
path: "/healthy"
port: 8080
}
initialDelaySeconds: 120
periodSeconds: 5
timeoutSeconds: 10
}
name: "balancereader"
readinessProbe: {
httpGet: {
path: "/ready"
port: 8080
}
initialDelaySeconds: 60
periodSeconds: 5
timeoutSeconds: 10
}
resources: {
limits: {
cpu: "500m"
"ephemeral-storage": "0.5Gi"
memory: "512Mi"
}
requests: {
cpu: "100m"
"ephemeral-storage": "0.5Gi"
memory: "256Mi"
}
}
securityContext: {
allowPrivilegeEscalation: false
capabilities: drop: ["all"]
privileged: false
readOnlyRootFilesystem: true
}
startupProbe: {
failureThreshold: 30
httpGet: {
path: "/healthy"
port: 8080
}
periodSeconds: 10
}
volumeMounts: [{
mountPath: "/tmp"
name: "tmp"
}, {
mountPath: "/tmp/.ssh"
name: "publickey"
readOnly: true
}]
}]
securityContext: {
fsGroup: 1000
runAsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
}
serviceAccountName: BankName
terminationGracePeriodSeconds: 5
volumes: [{
emptyDir: {}
name: "tmp"
}, {
name: "publickey"
secret: {
items: [{
key: "jwtRS256.key.pub"
path: "publickey"
}]
secretName: "jwt-key"
}
}]
}
}
}
}
}
}

View File

@@ -0,0 +1,143 @@
package holos
// Produce a kubernetes objects build plan.
(#Kubernetes & Objects).BuildPlan
let BankName = #BankOfHolos.Name
let CommonLabels = {
application: BankName
environment: "development"
team: "accounts"
tier: "backend"
}
let Objects = {
Name: "bank-contacts"
Namespace: #BankOfHolos.Backend.Namespace
// Ensure resources go in the correct namespace
Resources: [_]: [_]: metadata: namespace: Namespace
Resources: [_]: [_]: metadata: labels: CommonLabels
// https://github.com/GoogleCloudPlatform/bank-of-anthos/blob/release/v0.6.5/kubernetes-manifests
Resources: {
Service: contacts: {
apiVersion: "v1"
kind: "Service"
metadata: name: "contacts"
spec: {
ports: [{
name: "http"
port: 8080
targetPort: 8080
}]
selector: {
app: "contacts"
CommonLabels
}
type: "ClusterIP"
}
}
Deployment: contacts: {
apiVersion: "apps/v1"
kind: "Deployment"
metadata: name: "contacts"
spec: {
selector: matchLabels: {
app: "contacts"
CommonLabels
}
template: {
metadata: {
labels: {
app: "contacts"
CommonLabels
}
}
spec: {
containers: [{
env: [{
name: "VERSION"
value: "v0.6.5"
}, {
name: "PORT"
value: "8080"
}, {
name: "ENABLE_TRACING"
value: "false"
}, {
name: "LOG_LEVEL"
value: "info"
}]
envFrom: [{
configMapRef: name: "environment-config"
}, {
configMapRef: name: "accounts-db-config"
}]
image: "us-central1-docker.pkg.dev/bank-of-anthos-ci/bank-of-anthos/contacts:v0.6.5@sha256:e451dcac7d34a7bde979c7f02d4c7ebd83a77aff373e1131ce3a2bba2f7fdc1a"
name: "contacts"
readinessProbe: {
httpGet: {
path: "/ready"
port: 8080
}
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 10
}
resources: {
limits: {
cpu: "250m"
"ephemeral-storage": "0.25Gi"
memory: "128Mi"
}
requests: {
cpu: "100m"
"ephemeral-storage": "0.25Gi"
memory: "64Mi"
}
}
securityContext: {
allowPrivilegeEscalation: false
capabilities: drop: ["all"]
privileged: false
readOnlyRootFilesystem: true
}
volumeMounts: [{
mountPath: "/tmp"
name: "tmp"
}, {
mountPath: "/tmp/.ssh"
name: "publickey"
readOnly: true
}]
}]
securityContext: {
fsGroup: 1000
runAsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
}
serviceAccountName: BankName
terminationGracePeriodSeconds: 5
volumes: [{
emptyDir: {}
name: "tmp"
}, {
name: "publickey"
secret: {
items: [{
key: "jwtRS256.key.pub"
path: "publickey"
}]
secretName: "jwt-key"
}
}]
}
}
}
}
}
}

View File

@@ -0,0 +1,121 @@
package holos
// Produce a kubernetes objects build plan.
(#Kubernetes & Objects).BuildPlan
let BankName = #BankOfHolos.Name
let CommonLabels = {
application: BankName
environment: "development"
team: "ledger"
tier: "db"
}
let Objects = {
Name: "bank-ledger-db"
Namespace: #BankOfHolos.Backend.Namespace
// Ensure resources go in the correct namespace
Resources: [_]: [_]: metadata: namespace: Namespace
// https://github.com/GoogleCloudPlatform/bank-of-anthos/blob/release/v0.6.5/kubernetes-manifests
Resources: {
ConfigMap: "ledger-db-config": {
apiVersion: "v1"
metadata: {
name: "ledger-db-config"
labels: {
app: "ledger-db"
CommonLabels
}
}
data: {
POSTGRES_DB: "postgresdb"
POSTGRES_PASSWORD: "password"
POSTGRES_USER: "admin"
SPRING_DATASOURCE_PASSWORD: "password"
SPRING_DATASOURCE_URL: "jdbc:postgresql://ledger-db:5432/postgresdb"
SPRING_DATASOURCE_USERNAME: "admin"
}
}
Service: "ledger-db": {
apiVersion: "v1"
kind: "Service"
metadata: {
name: "ledger-db"
labels: CommonLabels
}
spec: {
ports: [{
name: "tcp"
port: 5432
targetPort: 5432
}]
selector: {
app: "ledger-db"
CommonLabels
}
type: "ClusterIP"
}
}
StatefulSet: "ledger-db": {
apiVersion: "apps/v1"
kind: "StatefulSet"
metadata: {
name: "ledger-db"
labels: CommonLabels
}
spec: {
replicas: 1
selector: matchLabels: {
app: "ledger-db"
CommonLabels
}
serviceName: "ledger-db"
template: {
metadata: labels: {
app: "ledger-db"
CommonLabels
}
spec: {
containers: [{
envFrom: [{
configMapRef: name: "environment-config"
}, {
configMapRef: name: "ledger-db-config"
}, {
configMapRef: name: "demo-data-config"
}]
image: "us-central1-docker.pkg.dev/bank-of-anthos-ci/bank-of-anthos/ledger-db:v0.6.5@sha256:cc4fd25f301ab6d46b1312244d6931babc4c6cb66c5cb6d31d4a1adfa318a321"
name: "postgres"
ports: [{containerPort: 5432}]
resources: {
limits: {
cpu: "250m"
memory: "1Gi"
}
requests: {
cpu: "100m"
memory: "512Mi"
}
}
volumeMounts: [{
mountPath: "/var/lib/postgresql/data"
name: "postgresdb"
subPath: "postgres"
}]
}]
serviceAccountName: BankName
volumes: [{
emptyDir: {}
name: "postgresdb"
}]
}
}
}
}
}
}

View File

@@ -0,0 +1,169 @@
package holos
// Produce a kubernetes objects build plan.
(#Kubernetes & Objects).BuildPlan
let BankName = #BankOfHolos.Name
let CommonLabels = {
application: BankName
environment: "development"
team: "ledger"
tier: "backend"
}
let Objects = {
Name: "bank-ledger-writer"
Namespace: #BankOfHolos.Backend.Namespace
// Ensure resources go in the correct namespace
Resources: [_]: [_]: metadata: namespace: Namespace
Resources: [_]: [_]: metadata: labels: CommonLabels
// https://github.com/GoogleCloudPlatform/bank-of-anthos/blob/release/v0.6.5/kubernetes-manifests
Resources: {
Service: ledgerwriter: {
apiVersion: "v1"
kind: "Service"
metadata: {
name: "ledgerwriter"
labels: CommonLabels
}
spec: {
ports: [{
name: "http"
port: 8080
targetPort: 8080
}]
selector: {
app: "ledgerwriter"
CommonLabels
}
type: "ClusterIP"
}
}
Deployment: ledgerwriter: {
apiVersion: "apps/v1"
kind: "Deployment"
metadata: {
name: "ledgerwriter"
labels: CommonLabels
}
spec: {
selector: matchLabels: {
app: "ledgerwriter"
CommonLabels
}
template: {
metadata: {
labels: {
app: "ledgerwriter"
CommonLabels
}
}
spec: {
containers: [{
env: [{
name: "VERSION"
value: "v0.6.5"
}, {
name: "PORT"
value: "8080"
}, {
name: "ENABLE_TRACING"
value: "false"
}, {
name: "ENABLE_METRICS"
value: "false"
}, {
name: "JVM_OPTS"
value: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -Xms256m -Xmx512m"
}, {
name: "LOG_LEVEL"
value: "info"
}, {
name: "NAMESPACE"
valueFrom: fieldRef: fieldPath: "metadata.namespace"
}]
envFrom: [{
configMapRef: name: "environment-config"
}, {
configMapRef: name: "service-api-config"
}, {
configMapRef: name: "ledger-db-config"
}]
image: "us-central1-docker.pkg.dev/bank-of-anthos-ci/bank-of-anthos/ledgerwriter:v0.6.5@sha256:5b66d6888b87993c8ebe260fe33005c4e4bc2bdae4b5682874e1a078d37ff3b2"
name: "ledgerwriter"
readinessProbe: {
httpGet: {
path: "/ready"
port: 8080
}
initialDelaySeconds: 60
periodSeconds: 5
timeoutSeconds: 10
}
resources: {
limits: {
cpu: "500m"
"ephemeral-storage": "0.5Gi"
memory: "512Mi"
}
requests: {
cpu: "100m"
"ephemeral-storage": "0.5Gi"
memory: "256Mi"
}
}
securityContext: {
allowPrivilegeEscalation: false
capabilities: drop: ["all"]
privileged: false
readOnlyRootFilesystem: true
}
startupProbe: {
failureThreshold: 30
httpGet: {
path: "/ready"
port: 8080
}
periodSeconds: 10
}
volumeMounts: [{
mountPath: "/tmp"
name: "tmp"
}, {
mountPath: "/tmp/.ssh"
name: "publickey"
readOnly: true
}]
}]
securityContext: {
fsGroup: 1000
runAsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
}
serviceAccountName: BankName
terminationGracePeriodSeconds: 5
volumes: [{
emptyDir: {}
name: "tmp"
}, {
name: "publickey"
secret: {
items: [{
key: "jwtRS256.key.pub"
path: "publickey"
}]
secretName: "jwt-key"
}
}]
}
}
}
}
}
}

View File

@@ -0,0 +1,187 @@
package holos
// Produce a kubernetes objects build plan.
(#Kubernetes & Objects).BuildPlan
let BankName = #BankOfHolos.Name
let CommonLabels = {
application: BankName
environment: "development"
team: "ledger"
tier: "backend"
}
let Objects = {
Name: "bank-transaction-history"
Namespace: #BankOfHolos.Backend.Namespace
// Ensure resources go in the correct namespace
Resources: [_]: [_]: metadata: namespace: Namespace
Resources: [_]: [_]: metadata: labels: CommonLabels
// https://github.com/GoogleCloudPlatform/bank-of-anthos/blob/release/v0.6.5/kubernetes-manifests
Resources: {
Service: transactionhistory: {
apiVersion: "v1"
kind: "Service"
metadata: {
labels: CommonLabels
name: "transactionhistory"
}
spec: {
ports: [{
name: "http"
port: 8080
targetPort: 8080
}]
selector: {
app: "transactionhistory"
CommonLabels
}
type: "ClusterIP"
}
}
Deployment: transactionhistory: {
apiVersion: "apps/v1"
kind: "Deployment"
metadata: {
name: "transactionhistory"
labels: CommonLabels
}
spec: {
selector: matchLabels: {
app: "transactionhistory"
CommonLabels
}
template: {
metadata: {
labels: {
app: "transactionhistory"
CommonLabels
}
}
spec: {
containers: [{
env: [{
name: "VERSION"
value: "v0.6.5"
}, {
name: "PORT"
value: "8080"
}, {
name: "ENABLE_TRACING"
value: "false"
}, {
name: "ENABLE_METRICS"
value: "false"
}, {
name: "POLL_MS"
value: "100"
}, {
name: "CACHE_SIZE"
value: "1000"
}, {
name: "CACHE_MINUTES"
value: "60"
}, {
name: "HISTORY_LIMIT"
value: "100"
}, {
name: "JVM_OPTS"
value: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -Xms256m -Xmx512m"
}, {
name: "LOG_LEVEL"
value: "info"
}, {
name: "NAMESPACE"
valueFrom: fieldRef: fieldPath: "metadata.namespace"
}]
envFrom: [{
configMapRef: name: "environment-config"
}, {
configMapRef: name: "ledger-db-config"
}]
image: "us-central1-docker.pkg.dev/bank-of-anthos-ci/bank-of-anthos/transactionhistory:v0.6.5@sha256:54a2b0866df44a50832e71b130f3e069fe8bbce71309fb6cf390b19f64d92c09"
livenessProbe: {
httpGet: {
path: "/healthy"
port: 8080
}
initialDelaySeconds: 120
periodSeconds: 5
timeoutSeconds: 10
}
name: "transactionhistory"
readinessProbe: {
httpGet: {
path: "/ready"
port: 8080
}
initialDelaySeconds: 60
periodSeconds: 5
timeoutSeconds: 10
}
resources: {
limits: {
cpu: "500m"
"ephemeral-storage": "0.5Gi"
memory: "512Mi"
}
requests: {
cpu: "100m"
"ephemeral-storage": "0.5Gi"
memory: "256Mi"
}
}
securityContext: {
allowPrivilegeEscalation: false
capabilities: drop: ["all"]
privileged: false
readOnlyRootFilesystem: true
}
startupProbe: {
failureThreshold: 30
httpGet: {
path: "/healthy"
port: 8080
}
periodSeconds: 10
}
volumeMounts: [{
mountPath: "/tmp"
name: "tmp"
}, {
mountPath: "/tmp/.ssh"
name: "publickey"
readOnly: true
}]
}]
securityContext: {
fsGroup: 1000
runAsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
}
serviceAccountName: BankName
terminationGracePeriodSeconds: 5
volumes: [{
emptyDir: {}
name: "tmp"
}, {
name: "publickey"
secret: {
items: [{
key: "jwtRS256.key.pub"
path: "publickey"
}]
secretName: "jwt-key"
}
}]
}
}
}
}
}
}

View File

@@ -0,0 +1,156 @@
package holos
// Produce a kubernetes objects build plan.
(#Kubernetes & Objects).BuildPlan
let BankName = #BankOfHolos.Name
let CommonLabels = {
application: BankName
environment: "development"
team: "accounts"
tier: "backend"
}
let Objects = {
Name: "bank-userservice"
Namespace: #BankOfHolos.Backend.Namespace
// Ensure resources go in the correct namespace
Resources: [_]: [_]: metadata: namespace: Namespace
// https://github.com/GoogleCloudPlatform/bank-of-anthos/blob/release/v0.6.5/kubernetes-manifests/userservice.yaml
Resources: {
Service: userservice: {
metadata: name: "userservice"
metadata: labels: CommonLabels
spec: {
selector: {
app: "userservice"
CommonLabels
}
_ports: http: {
name: "http"
port: 8080
targetPort: 8080
protocol: "TCP"
}
ports: [for x in _ports {x}]
}
}
Deployment: userservice: {
metadata: name: "userservice"
metadata: labels: CommonLabels
spec: {
selector: matchLabels: {
app: "userservice"
CommonLabels
}
template: {
metadata: labels: {
app: "userservice"
CommonLabels
}
spec: {
serviceAccountName: BankName
terminationGracePeriodSeconds: 5
containers: [{
env: [{
name: "VERSION"
value: "v0.6.5"
}, {
name: "PORT"
value: "8080"
}, {
name: "ENABLE_TRACING"
value: "false"
}, {
name: "LOG_LEVEL"
value: "info"
}, {
name: "TOKEN_EXPIRY_SECONDS"
value: "3600"
}, {
name: "PRIV_KEY_PATH"
value: "/tmp/.ssh/privatekey"
}]
envFrom: [{
configMapRef: name: "environment-config"
}, {
configMapRef: name: "accounts-db-config"
}]
image: "us-central1-docker.pkg.dev/bank-of-anthos-ci/bank-of-anthos/userservice:v0.6.5@sha256:f91e0e5bd6cdb16f6b867b2e3e874b23dd01f11592de006776f1dfb136702941"
name: "userservice"
ports: [{
containerPort: 8080
name: "http-server"
}]
readinessProbe: {
httpGet: {
path: "/ready"
port: 8080
}
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 10
}
resources: {
limits: {
cpu: "500m"
"ephemeral-storage": "0.25Gi"
memory: "256Mi"
}
requests: {
cpu: "260m"
"ephemeral-storage": "0.25Gi"
memory: "128Mi"
}
}
securityContext: {
allowPrivilegeEscalation: false
capabilities: drop: ["all"]
privileged: false
readOnlyRootFilesystem: true
}
volumeMounts: [{
mountPath: "/tmp"
name: "tmp"
}, {
mountPath: "/tmp/.ssh"
name: "keys"
readOnly: true
}]
}]
volumes: [{
emptyDir: {}
name: "tmp"
}, {
name: "keys"
secret: {
secretName: "jwt-key"
items: [
{
key: "jwtRS256.key"
path: "privatekey"
},
{
key: "jwtRS256.key.pub"
path: "publickey"
},
]
}
}]
securityContext: {
seccompProfile: type: "RuntimeDefault"
fsGroup: 1000
runAsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
}
}
}
}
}
}
}

View File

@@ -0,0 +1,88 @@
package holos
import (
core "k8s.io/api/core/v1"
es "external-secrets.io/externalsecret/v1beta1"
ss "external-secrets.io/secretstore/v1beta1"
)
let BankName = #BankOfHolos.Name
#BankOfHolos: {
// Resources to make available in each of the project namespaces.
Resources: {
ServiceAccount: (BankName): core.#ServiceAccount & {
apiVersion: "v1"
kind: "ServiceAccount"
metadata: name: BankName
}
// SecretStore to fetch secrets owned by the security team
SecretStore: (BankName): ss.#SecretStore & {
metadata: name: #BankOfHolos.Security.Namespace
spec: provider: {
kubernetes: {
remoteNamespace: #BankOfHolos.Security.Namespace
auth: serviceAccount: name: ServiceAccount[BankName].metadata.name
server: {
url: "https://kubernetes.default.svc"
caProvider: {
type: "ConfigMap"
name: "kube-root-ca.crt"
key: "ca.crt"
}
}
}
}
}
// We do not check the private key into version control.
// https://github.com/GoogleCloudPlatform/bank-of-anthos/tree/v0.6.5/extras/jwt
ExternalSecret: "jwt-key": es.#ExternalSecret & {
metadata: name: "jwt-key"
spec: {
target: name: metadata.name
dataFrom: [{extract: {key: metadata.name}}]
refreshInterval: "5s"
secretStoreRef: kind: "SecretStore"
secretStoreRef: name: SecretStore[BankName].metadata.name
}
}
// https://github.com/GoogleCloudPlatform/bank-of-anthos/blob/release/v0.6.5/kubernetes-manifests/config.yaml
ConfigMap: "environment-config": core.#ConfigMap & {
apiVersion: "v1"
kind: "ConfigMap"
metadata: name: "environment-config"
data: {
LOCAL_ROUTING_NUM: "883745000"
PUB_KEY_PATH: "/tmp/.ssh/publickey"
}
}
ConfigMap: "service-api-config": core.#ConfigMap & {
apiVersion: "v1"
kind: "ConfigMap"
metadata: name: "service-api-config"
data: {
TRANSACTIONS_API_ADDR: "ledgerwriter.\(#BankOfHolos.Backend.Namespace).svc:8080"
BALANCES_API_ADDR: "balancereader.\(#BankOfHolos.Backend.Namespace).svc:8080"
HISTORY_API_ADDR: "transactionhistory.\(#BankOfHolos.Backend.Namespace).svc:8080"
CONTACTS_API_ADDR: "contacts.\(#BankOfHolos.Backend.Namespace).svc:8080"
USERSERVICE_API_ADDR: "userservice.\(#BankOfHolos.Backend.Namespace).svc:8080"
}
}
ConfigMap: "demo-data-config": core.#ConfigMap & {
apiVersion: "v1"
kind: "ConfigMap"
metadata: name: "demo-data-config"
data: {
USE_DEMO_DATA: "True"
DEMO_LOGIN_USERNAME: "testuser"
// All demo user accounts are hardcoded to use the login password 'bankofanthos'
DEMO_LOGIN_PASSWORD: "bankofanthos"
}
}
}
}

View File

@@ -0,0 +1,201 @@
package holos
// Produce a kubernetes objects build plan.
(#Kubernetes & Objects).BuildPlan
let Objects = {
Name: "bank-frontend"
Namespace: #BankOfHolos.Frontend.Namespace
// Ensure resources go in the correct namespace
Resources: [_]: [_]: metadata: namespace: Namespace
// https://github.com/GoogleCloudPlatform/bank-of-anthos/blob/release/v0.6.5/kubernetes-manifests/frontend.yaml
Resources: {
Service: frontend: {
metadata: name: "frontend"
metadata: labels: {
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
spec: {
selector: {
app: "frontend"
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
_ports: http: {
name: "http"
port: 80
targetPort: 8080
protocol: "TCP"
}
ports: [for x in _ports {x}]
}
}
Deployment: frontend: {
metadata: name: "frontend"
metadata: labels: {
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
spec: {
selector: matchLabels: {
app: "frontend"
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
template: {
metadata: labels: {
app: "frontend"
application: "bank-of-holos"
environment: "development"
team: "frontend"
tier: "web"
}
spec: {
securityContext: {
seccompProfile: type: "RuntimeDefault"
fsGroup: 1000
runAsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
}
serviceAccountName: "bank-of-holos"
terminationGracePeriodSeconds: 5
containers: [{
env: [{
name: "BANK_NAME"
value: "Bank of Holos"
}, {
name: "ENV_PLATFORM"
value: "local"
}, {
name: "VERSION"
value: "v0.6.5"
}, {
name: "PORT"
value: "8080"
}, {
name: "ENABLE_TRACING"
value: "false"
}, {
name: "SCHEME"
value: "https"
}, {
name: "LOG_LEVEL"
value: "info"
}, {
name: "DEFAULT_USERNAME"
valueFrom: configMapKeyRef: {
key: "DEMO_LOGIN_USERNAME"
name: "demo-data-config"
}
}, {
name: "DEFAULT_PASSWORD"
valueFrom: configMapKeyRef: {
key: "DEMO_LOGIN_PASSWORD"
name: "demo-data-config"
}
}, {
name: "REGISTERED_OAUTH_CLIENT_ID"
valueFrom: configMapKeyRef: {
key: "DEMO_OAUTH_CLIENT_ID"
name: "oauth-config"
optional: true
}
}, {
name: "ALLOWED_OAUTH_REDIRECT_URI"
valueFrom: configMapKeyRef: {
key: "DEMO_OAUTH_REDIRECT_URI"
name: "oauth-config"
optional: true
}
}]
envFrom: [{
configMapRef: name: "environment-config"
}, {
configMapRef: name: "service-api-config"
}]
image: "us-central1-docker.pkg.dev/bank-of-anthos-ci/bank-of-anthos/frontend:v0.6.5@sha256:d72050f70d12383e4434ad04d189b681dc625f696087ddf0b5df641645c9dafa"
livenessProbe: {
httpGet: {
path: "/ready"
port: 8080
}
initialDelaySeconds: 60
periodSeconds: 15
timeoutSeconds: 30
}
name: "front"
readinessProbe: {
httpGet: {
path: "/ready"
port: 8080
}
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 10
}
resources: {
limits: {
cpu: "250m"
memory: "128Mi"
}
requests: {
cpu: "100m"
memory: "64Mi"
}
}
securityContext: {
allowPrivilegeEscalation: false
capabilities: drop: ["all"]
privileged: false
readOnlyRootFilesystem: true
}
volumeMounts: [{
mountPath: "/tmp"
name: "tmp"
}, {
mountPath: "/tmp/.ssh"
name: "publickey"
readOnly: true
}]
}]
volumes: [
{
emptyDir: {}
name: "tmp"
},
{
name: "publickey"
secret: {
items: [{key: "jwtRS256.key.pub", path: "publickey"}]
secretName: "jwt-key"
}
},
]
}
}
}
}
// Allow HTTPRoutes in the ingress gateway namespace to reference Services
// in this namespace.
ReferenceGrant: grant: #ReferenceGrant & {
metadata: namespace: Namespace
}
// Include shared resources
#BankOfHolos.Resources
}
}

View File

@@ -0,0 +1,3 @@
package holos
#ArgoConfig: AppProject: #AppProjects["bank-frontend"].metadata.name

View File

@@ -0,0 +1,165 @@
package holos
import (
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
batchv1 "k8s.io/api/batch/v1"
)
// Produce a kubernetes objects build plan.
(#Kubernetes & Objects).BuildPlan
// This may be useful to copy and generate other secrets.
let SecretName = "jwt-key"
// Roles for reading and writing secrets
let Reader = "\(SecretName)-reader"
let Writer = "\(SecretName)-writer"
// AllowedName represents the service account allowed to read the generated
// secret.
let AllowedName = #BankOfHolos.Name
let Objects = {
Name: "bank-secrets"
Namespace: #BankOfHolos.Security.Namespace
Resources: [_]: [_]: metadata: namespace: Namespace
Resources: [_]: [ID=string]: metadata: name: string | *ID
Resources: {
// Kubernetes ServiceAccount used by the secret generator job.
ServiceAccount: (Writer): corev1.#ServiceAccount
// Role to allow the ServiceAccount to update secrets.
Role: (Writer): rbacv1.#Role & {
rules: [{
apiGroups: [""]
resources: ["secrets"]
verbs: ["create", "update", "patch"]
}]
}
// Bind the role to the service account.
RoleBinding: (Writer): rbacv1.#RoleBinding & {
roleRef: {
apiGroup: "rbac.authorization.k8s.io"
kind: "Role"
name: Role[Writer].metadata.name
}
subjects: [{
kind: "ServiceAccount"
name: ServiceAccount[Writer].metadata.name
namespace: Namespace
}]
}
let JobSpec = {
serviceAccountName: Writer
restartPolicy: "OnFailure"
securityContext: {
seccompProfile: type: "RuntimeDefault"
runAsNonRoot: true
runAsUser: 8192 // app
}
containers: [
{
name: "toolkit"
image: "quay.io/holos-run/toolkit:2024-09-16"
securityContext: {
capabilities: drop: ["ALL"]
allowPrivilegeEscalation: false
}
command: ["/bin/bash"]
args: ["/config/entrypoint"]
env: [{
name: "HOME"
value: "/tmp"
}]
volumeMounts: [{
name: "config"
mountPath: "/config"
readOnly: true
}]
},
]
volumes: [{
name: "config"
configMap: name: Writer
}]
}
Job: (Writer): batchv1.#Job & {
spec: template: spec: JobSpec
}
ConfigMap: (Writer): corev1.#ConfigMap & {
data: entrypoint: ENTRYPOINT
}
// Allow the SecretStore in the frontend and backend namespaces to read the
// secret.
Role: (Reader): rbacv1.#Role & {
rules: [{
apiGroups: [""]
resources: ["secrets"]
resourceNames: [SecretName]
verbs: ["get"]
}]
}
// Grant access to the bank-of-holos service account in the frontend and
// backend namespaces.
RoleBinding: (Reader): rbacv1.#RoleBinding & {
roleRef: {
apiGroup: "rbac.authorization.k8s.io"
kind: "Role"
name: Role[Reader].metadata.name
}
subjects: [{
kind: "ServiceAccount"
name: AllowedName
namespace: #BankOfHolos.Frontend.Namespace
}, {
kind: "ServiceAccount"
name: AllowedName
namespace: #BankOfHolos.Backend.Namespace
},
]
}
}
}
let ENTRYPOINT = """
#! /bin/bash
#
tmpdir="$(mktemp -d)"
finish() {
status=$?
rm -rf "${tmpdir}"
return $status
}
trap finish EXIT
set -euo pipefail
cd "$tmpdir"
mkdir secret
cd secret
echo "generating private key" >&2
ssh-keygen -t rsa -b 4096 -m PEM -f jwtRS256.key -q -N "" -C \(AllowedName)
echo "generating public key" >&2
ssh-keygen -e -m PKCS8 -f jwtRS256.key > jwtRS256.key.pub
cd ..
echo "copying secret into kubernetes manifest secret.yaml" >&2
kubectl create secret generic \(SecretName) --from-file=secret --dry-run=client -o yaml > secret.yaml
echo "applying secret.yaml" >&2
kubectl apply --server-side=true -f secret.yaml
echo "cleaning up" >&2
rm -rf secret secret.yaml
echo "ok done" >&2
"""

View File

@@ -0,0 +1,3 @@
package holos
#ArgoConfig: AppProject: #AppProjects["bank-security"].metadata.name

View File

@@ -0,0 +1,5 @@
{
"name": "bank-of-holos",
"short": "demo bank composed of two projects",
"long": "Bank of Holos is a sample HTTP-based web app that simulates a bank's payment processing network, allowing users to create artificial bank accounts and complete transactions."
}

View File

@@ -0,0 +1,15 @@
package holos
// Manage the component on every cluster in the platform
for Fleet in #Fleets {
for Cluster in Fleet.clusters {
#Platform: Components: "\(Cluster.name)/external-secrets-crds": {
path: "projects/platform/components/external-secrets-crds"
cluster: Cluster.name
}
#Platform: Components: "\(Cluster.name)/external-secrets": {
path: "projects/platform/components/external-secrets"
cluster: Cluster.name
}
}
}

View File

@@ -0,0 +1,10 @@
package holos
// Platform wide configuration
#ExternalSecrets: {
Version: "{{ .Version }}"
Namespace: "external-secrets"
}
// Register the namespace
#Namespaces: (#ExternalSecrets.Namespace): _

View File

@@ -0,0 +1,33 @@
package holos
import (
"encoding/yaml"
ks "sigs.k8s.io/kustomize/api/types"
)
(#Kubernetes & {Name: "external-secrets-crds"}).BuildPlan
// Holos stages BuildPlan resources as an intermediate step of the rendering
// pipeline. The purpose is to provide the resources to kustomize for
// post-processing.
let BuildPlanResources = "build-plan-resources.yaml"
_Kustomization: ks.#Kustomization & {
apiVersion: "kustomize.config.k8s.io/v1beta1"
kind: "Kustomization"
resources: [
// Kustomize the intermediate build plan resources.
BuildPlanResources,
// Mix-in external resources.
"https://raw.githubusercontent.com/external-secrets/external-secrets/v\(#ExternalSecrets.Version)/deploy/crds/bundle.yaml",
]
}
// Generate a kustomization.yaml directly from CUE so we can provide the correct
// version.
spec: components: kubernetesObjectsList: [{
// intermediate build plan resources to kustomize. Necessary to activate the
// kustomization post-rendering step in holos.
kustomize: resourcesFile: BuildPlanResources
kustomize: kustomizeFiles: "kustomization.yaml": yaml.Marshal(_Kustomization)
}]

View File

@@ -0,0 +1,50 @@
package holos
import (
"encoding/yaml"
ks "sigs.k8s.io/kustomize/api/types"
)
// Patch the the build plan output.
_Kustomization: patches: [for x in KustomizePatches {x}]
#KustomizePatches: [ArbitraryLabel=string]: ks.#Patch
let KustomizePatches = #KustomizePatches & {
let Patch = [{
op: "replace"
path: "/spec/conversion/webhook/clientConfig/service/name"
value: "external-secrets-webhook"
}, {
op: "replace"
path: "/spec/conversion/webhook/clientConfig/service/namespace"
value: "external-secrets"
}]
clustersecretstores: {
target: {
group: "apiextensions.k8s.io"
version: "v1"
kind: "CustomResourceDefinition"
name: "clustersecretstores.external-secrets.io"
}
patch: yaml.Marshal(Patch)
}
externalsecrets: {
target: {
group: "apiextensions.k8s.io"
version: "v1"
kind: "CustomResourceDefinition"
name: "externalsecrets.external-secrets.io"
}
patch: yaml.Marshal(Patch)
}
secretstores: {
target: {
group: "apiextensions.k8s.io"
version: "v1"
kind: "CustomResourceDefinition"
name: "secretstores.external-secrets.io"
}
patch: yaml.Marshal(Patch)
}
}

View File

@@ -0,0 +1,15 @@
package holos
_Chart: {
Name: "external-secrets"
Version: "0.10.3"
Namespace: "external-secrets"
Repo: name: "external-secrets"
Repo: url: "https://charts.external-secrets.io"
Values: installCRDs: false
}
// Produce a helm chart build plan.
(#Helm & _Chart).BuildPlan

View File

@@ -0,0 +1,6 @@
{
"name": "external-secrets",
"short": "safer secret management",
"long": "https://external-secrets.io",
"version": "0.10.3"
}

View File

@@ -4,7 +4,7 @@ package holos
for Fleet in #Fleets {
for Cluster in Fleet.clusters {
#Platform: Components: "\(Cluster.name)/gateway-api": {
path: "components/gateway-api"
path: "projects/platform/components/gateway-api"
cluster: Cluster.name
}
}

View File

@@ -1,39 +0,0 @@
package holos
// #Istio represents platform wide configuration
#Istio: {
Version: "1.23.1"
System: Namespace: "istio-system"
// Constrain Helm values for safer, easier upgrades and consistency across
// platform components.
Values: global: istioNamespace: System.Namespace
// Configure ambient mode
Values: profile: "ambient"
}
// Register the Namespaces
#Namespaces: (#Istio.System.Namespace): _
// Manage istio on workload clusters
for Cluster in #Fleets.workload.clusters {
#Platform: Components: {
"\(Cluster.name)/istio-base": {
path: "components/istio/base"
cluster: Cluster.name
}
"\(Cluster.name)/istiod": {
path: "components/istio/istiod"
cluster: Cluster.name
}
"\(Cluster.name)/istio-cni": {
path: "components/istio/cni"
cluster: Cluster.name
}
"\(Cluster.name)/istio-ztunnel": {
path: "components/istio/ztunnel"
cluster: Cluster.name
}
}
}

View File

@@ -0,0 +1,24 @@
package holos
// #Istio represents platform wide configuration
// Manage istio on workload clusters
for Cluster in #Fleets.workload.clusters {
#Platform: Components: {
"\(Cluster.name)/istio-base": {
path: "projects/platform/components/istio/base"
cluster: Cluster.name
}
"\(Cluster.name)/istiod": {
path: "projects/platform/components/istio/istiod"
cluster: Cluster.name
}
"\(Cluster.name)/istio-cni": {
path: "projects/platform/components/istio/cni"
cluster: Cluster.name
}
"\(Cluster.name)/istio-ztunnel": {
path: "projects/platform/components/istio/ztunnel"
cluster: Cluster.name
}
}
}

View File

@@ -0,0 +1,17 @@
package holos
// #Istio represents platform wide configuration
#Istio: {
Version: "1.23.1"
System: Namespace: "istio-system"
// Constrain Helm values for safer, easier upgrades and consistency across
// platform components.
Values: global: istioNamespace: System.Namespace
// Configure ambient mode
Values: profile: "ambient"
}
// Register the Namespaces
#Namespaces: (#Istio.System.Namespace): _

View File

@@ -0,0 +1,48 @@
package holos
import (
"encoding/yaml"
ks "sigs.k8s.io/kustomize/api/types"
)
// Holos stages BuildPlan resources as an intermediate step of the rendering
// pipeline. The purpose is to provide the resources to kustomize for
// post-processing.
let BuildPlanOutputManifest = "build-plan-output-manifest.yaml"
// Patch istio so it's not constantly out of sync in ArgoCD
let Kustomization = ks.#Kustomization & {
apiVersion: "kustomize.config.k8s.io/v1beta1"
kind: "Kustomization"
// Kustomize the build plan output.
resources: [BuildPlanOutputManifest]
// Patch the the build plan output.
patches: [for x in KustomizePatches {x}]
}
#KustomizePatches: [ArbitraryLabel=string]: ks.#Patch
let KustomizePatches = #KustomizePatches & {
validator: {
target: {
group: "admissionregistration.k8s.io"
version: "v1"
kind: "ValidatingWebhookConfiguration"
name: "istiod-default-validator"
}
let Patch = [{
op: "replace"
path: "/webhooks/0/failurePolicy"
value: "Fail"
}]
patch: yaml.Marshal(Patch)
}
}
// Generate a kustomization.yaml directly from CUE so we can provide the correct
// version.
spec: components: helmChartList: [{
// intermediate build plan resources to kustomize. Necessary to activate the
// kustomization post-rendering step in holos.
kustomize: resourcesFile: BuildPlanOutputManifest
kustomize: kustomizeFiles: "kustomization.yaml": yaml.Marshal(Kustomization)
}]

View File

@@ -0,0 +1,61 @@
package holos
// Produce a kubernetes objects build plan.
(#Kubernetes & Objects).BuildPlan
let Objects = {
Name: "istio-gateway"
Namespace: #Istio.Gateway.Namespace
Resources: {
// The default gateway with all listeners attached to tls certs.
Gateway: default: {
metadata: namespace: Namespace
let Listeners = {
http: {
name: "http"
protocol: "HTTP"
port: 80
allowedRoutes: namespaces: from: "Same"
}
https: {
name: "https"
protocol: "HTTPS"
port: 443
allowedRoutes: namespaces: from: "Same"
tls: mode: "Terminate"
tls: certificateRefs: [{
kind: "Secret"
name: "gateway-cert"
}]
}
}
spec: listeners: [for x in Listeners {x}]
}
// Manage a simple cert for example.com and *.example.com
Certificate: "gateway-cert": {
metadata: name: "gateway-cert"
metadata: namespace: Namespace
spec: commonName: #Platform.Domain
spec: dnsNames: [spec.commonName, "*.\(spec.commonName)"]
spec: secretName: metadata.name
spec: issuerRef: {
kind: "ClusterIssuer"
name: "local-ca"
}
}
// Manage a service account to prevent ArgoCD from pruning it.
ServiceAccount: "default-istio": {
metadata: namespace: Namespace
metadata: labels: {
"gateway.istio.io/managed": "istio.io-gateway-controller"
"gateway.networking.k8s.io/gateway-name": "default"
"istio.io/gateway-name": "default"
}
}
}
}

View File

@@ -0,0 +1,7 @@
# Gateway API
This component uses the [Gateway API][1] to manage an istio Gateway. This will
become the default method in upstream istio so it is the preferred method in
Holos.
[1]: https://gateway-api.sigs.k8s.io/

View File

@@ -0,0 +1,48 @@
package holos
import (
"encoding/yaml"
ks "sigs.k8s.io/kustomize/api/types"
)
// Holos stages BuildPlan resources as an intermediate step of the rendering
// pipeline. The purpose is to provide the resources to kustomize for
// post-processing.
let BuildPlanOutputManifest = "build-plan-output-manifest.yaml"
// Patch istio so it's not constantly out of sync in ArgoCD
let Kustomization = ks.#Kustomization & {
apiVersion: "kustomize.config.k8s.io/v1beta1"
kind: "Kustomization"
// Kustomize the build plan output.
resources: [BuildPlanOutputManifest]
// Patch the the build plan output.
patches: [for x in KustomizePatches {x}]
}
#KustomizePatches: [ArbitraryLabel=string]: ks.#Patch
let KustomizePatches = #KustomizePatches & {
validator: {
target: {
group: "admissionregistration.k8s.io"
version: "v1"
kind: "ValidatingWebhookConfiguration"
name: "istio-validator-istio-system"
}
let Patch = [{
op: "replace"
path: "/webhooks/0/failurePolicy"
value: "Fail"
}]
patch: yaml.Marshal(Patch)
}
}
// Generate a kustomization.yaml directly from CUE so we can provide the correct
// version.
spec: components: helmChartList: [{
// intermediate build plan resources to kustomize. Necessary to activate the
// kustomization post-rendering step in holos.
kustomize: resourcesFile: BuildPlanOutputManifest
kustomize: kustomizeFiles: "kustomization.yaml": yaml.Marshal(Kustomization)
}]

View File

@@ -1,6 +1,6 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go github.com/holos-run/holos/api/schema/v1alpha3
//cue:generate cue get go github.com/holos-run/holos/api/author/v1alpha3
// Package v1alpha3 contains CUE definitions intended as convenience wrappers
// around the core data types defined in package core. The purpose of these
@@ -181,3 +181,24 @@ import (
// platform operators to define.
Domain: string & (string | *"holos.localhost")
}
// Organization represents organizational metadata useful across the platform.
#Organization: {
Name: string
DisplayName: string
}
// OrganizationStrict represents organizational metadata useful across the
// platform. This is an example of using CUE regular expressions to constrain
// and validate configuration.
#OrganizationStrict: {
#Organization
// Name represents the organization name as a resource name. Must be 63
// characters or less. Must start with a letter. May contain non-repeating
// hyphens, letters, and numbers. Must end with a letter or number.
Name: string & (=~"^[a-z][0-9a-z-]{1,61}[0-9a-z]$" & !~"--")
// DisplayName represents the human readable organization name.
DisplayName: string & (=~"^[0-9A-Za-z][0-9A-Za-z ]{2,61}[0-9A-Za-z]$" & !~" ")
}

View File

@@ -9,8 +9,8 @@ package platforms
//go generate rm -rf cue.mod/gen/github.com/holos-run/holos/api/meta
//go:generate cue get go github.com/holos-run/holos/api/meta/...
//go generate rm -rf cue.mod/gen/github.com/holos-run/holos/api/schema
//go:generate cue get go github.com/holos-run/holos/api/schema/...
//go generate rm -rf cue.mod/gen/github.com/holos-run/holos/api/author
//go:generate cue get go github.com/holos-run/holos/api/author/...
//go generate rm -rf cue.mod/gen/github.com/holos-run/holos/service/gen/holos/object
//go:generate cue import ../../../service/holos/object/v1alpha1/object.proto -o cue.mod/gen/github.com/holos-run/holos/service/gen/holos/object/v1alpha1/object.proto_gen.cue -I ../../../proto -f

View File

@@ -6,3 +6,4 @@
ehthumbs.db
Thumbs.db
vendor/
node_modules/

View File

@@ -12,6 +12,8 @@ import (
hrv1 "gateway.networking.k8s.io/httproute/v1"
gwv1 "gateway.networking.k8s.io/gateway/v1"
ap "argoproj.io/appproject/v1alpha1"
es "external-secrets.io/externalsecret/v1beta1"
ss "external-secrets.io/secretstore/v1beta1"
)
#Resources: {
@@ -28,12 +30,15 @@ import (
ConfigMap: [_]: corev1.#ConfigMap
CronJob: [_]: batchv1.#CronJob
Deployment: [_]: appsv1.#Deployment
ExternalSecret: [_]: es.#ExternalSecret
HTTPRoute: [_]: hrv1.#HTTPRoute
Job: [_]: batchv1.#Job
Namespace: [_]: corev1.#Namespace
ReferenceGrant: [_]: rgv1.#ReferenceGrant
Role: [_]: rbacv1.#Role
RoleBinding: [_]: rbacv1.#RoleBinding
Secret: [_]: corev1.#Secret
SecretStore: [_]: ss.#SecretStore
Service: [_]: corev1.#Service
ServiceAccount: [_]: corev1.#ServiceAccount
StatefulSet: [_]: appsv1.#StatefulSet

View File

@@ -1,19 +1,24 @@
package holos
import schema "github.com/holos-run/holos/api/schema/v1alpha3"
import api "github.com/holos-run/holos/api/author/v1alpha3"
#Platform: schema.#Platform
#Fleets: schema.#StandardFleets
// Define the default organization name
#Organization: DisplayName: string | *"Bank of Holos"
#Organization: Name: string | *"bank-of-holos"
#Organization: api.#OrganizationStrict
#Platform: api.#Platform
#Fleets: api.#StandardFleets
_ComponentConfig: {
Resources: #Resources
ArgoConfig: #ArgoConfig
}
#Helm: schema.#Helm & _ComponentConfig
#Kustomize: schema.#Kustomize & _ComponentConfig
#Kubernetes: schema.#Kubernetes & _ComponentConfig
#Helm: api.#Helm & _ComponentConfig
#Kustomize: api.#Kustomize & _ComponentConfig
#Kubernetes: api.#Kubernetes & _ComponentConfig
#ArgoConfig: schema.#ArgoConfig & {
#ArgoConfig: api.#ArgoConfig & {
ClusterName: _ClusterName
}

View File

@@ -5,8 +5,11 @@ import (
dto "github.com/holos-run/holos/service/gen/holos/object/v1alpha1:object"
)
// Note, tags should have a reasonable default value to easily use cue eval and
// cue export without needing to make a bunch of decisions about tag values.
// _ClusterName is the --cluster-name flag value provided by the holos cli.
_ClusterName: string @tag(cluster, type=string)
_ClusterName: string | *"no-name" @tag(cluster, type=string)
// _PlatformConfig represents all of the data passed from holos to cue, used to
// carry the platform and project models.

View File

@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io"
"path/filepath"
"time"
core "github.com/holos-run/holos/api/core/v1alpha2"
@@ -14,6 +15,7 @@ import (
)
func Platform(ctx context.Context, concurrency int, pf *core.Platform, stderr io.Writer) error {
parentStart := time.Now()
total := len(pf.Spec.Components)
g, ctx := errgroup.WithContext(ctx)
@@ -49,7 +51,7 @@ func Platform(ctx context.Context, concurrency int, pf *core.Platform, stderr io
}
duration := time.Since(start)
msg := fmt.Sprintf("rendered %s for cluster %s in %s", component.Path, component.Cluster, duration)
msg := fmt.Sprintf("rendered %s for cluster %s in %s", filepath.Base(component.Path), component.Cluster, duration)
log.InfoContext(ctx, msg, "duration", duration)
return nil
}
@@ -60,5 +62,12 @@ func Platform(ctx context.Context, concurrency int, pf *core.Platform, stderr io
})
// Wait for completion and return the first error (if any)
return g.Wait()
if err := g.Wait(); err != nil {
return err
}
duration := time.Since(parentStart)
msg := fmt.Sprintf("rendered platform in %s", duration)
logger.FromContext(ctx).InfoContext(ctx, msg, "duration", duration)
return nil
}

View File

@@ -4,5 +4,5 @@ deps:
- remote: buf.build
owner: bufbuild
repository: protovalidate
commit: a6c49f84cc0f4e038680d390392e2ab0
digest: shake256:3deb629c655e469d87c58babcfbed403275a741fb4a269366c4fd6ea9db012cf562a1e64819508d73670c506f96d01f724c43bc97b44e2e02aa6e8bbdd160ab2
commit: 5a7b106cbb87462d9a8c9ffecdbd2e38
digest: shake256:2f7efa5a904668219f039d4f6eeb51e871f8f7f5966055a10663cba335bd65f76cac84da3fa758ab7b5dcb489ec599521390ce3951d119fb56df1fc2def16bb0

View File

@@ -1 +1 @@
94
95

View File

@@ -1 +1 @@
0
3