Compare commits

...

32 Commits

Author SHA1 Message Date
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
80 changed files with 3515 additions and 777 deletions

View File

@@ -67,6 +67,7 @@
"isatty",
"istiod",
"jbrx",
"jeffmccune",
"jetstack",
"Jsonnet",
"killall",
@@ -149,6 +150,7 @@
"usecases",
"userconnect",
"userdata",
"userservice",
"validatingwebhookconfiguration",
"virtualservices",
"wasmplugins",

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.

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,11 @@
---
description: Change a service on your platform.
slug: /guides/change-a-service
sidebar_position: 300
---
# Change a Service
:::warning
Under construction.
:::

View File

@@ -0,0 +1,11 @@
---
description: Deploy a service on your platform.
slug: /guides/deploy-a-service
sidebar_position: 200
---
# Deploy a Service
:::warning
Under construction.
:::

Binary file not shown.

After

Width:  |  Height:  |  Size: 690 KiB

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,16 @@ 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.
Our documentation is organized into [Guides] and the [API Reference].
:::tip
Please start with the [Quickstart] guide to learn who Holos is for, what
problems it solves, and if it can solve problems you have.
:::
[Guides]: /docs/guides/
[API Reference]: /docs/api/
[Quickstart]: /docs/quickstart/

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: 'The Holistic Platform Manager',
favicon: 'img/favicon.ico',
// Set the production url of your site here

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

@@ -40,8 +40,8 @@ const FeatureList: FeatureItem[] = [
description: (
<>
Reduce risk and increase confidence in your configuration changes.
Holos offers clear visibility into complete resource configuration
<i>before</i> being applied.
Holos offers clear visibility into platform wide changes before the
change is made.
</>
),
},

View File

@@ -18,22 +18,17 @@ function HomepageHeader() {
<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.
features to your Kubernetes configuration manifests, including Helm
and Kustomize. These features make the experience of integrating
software into a holistic platform a pleasant journey.
</p>
<div className={styles.buttons}>
<Link
className="button button--secondary button--lg"
to="docs/quickstart">
Get Started
</Link>
<span className={styles.divider}></span>
<Link
className="button button--primary button--lg"
to="docs/concepts">
Learn More
</Link>
<span className={styles.divider}></span>
</div>
</div>
</header >
@@ -44,8 +39,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

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,19 @@
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
#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

@@ -1 +1 @@
94
95

View File

@@ -1 +1 @@
0
2