Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ jobs:
registry-server: ghcr.io
registry-username: ${{ github.actor }}
image: ${{ github.repository }}
version: 0.10.0-RC2
version: 0.10.0-RC3
secrets:
pull-request-token: ${{ secrets.GH_ORG_PAT }}
11 changes: 11 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,14 @@ jobs:
permissions:
contents: read
uses: kadras-io/github-reusable-workflows/.github/workflows/carvel-package-test-config.yml@main

test-integration:
name: Integration Tests
strategy:
matrix:
k8s_version: [v1.25, v1.26, v1.27]
permissions:
contents: read
uses: kadras-io/github-reusable-workflows/.github/workflows/carvel-package-test-integration.yml@main
with:
k8s_version: ${{ matrix.k8s_version }}
14 changes: 11 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
K8S_VERSION=v1.26
K8S_VERSION=v1.27

# Build package configuration
build: package
Expand All @@ -20,12 +20,20 @@ clean:

# Process the configuration manifests with ytt
ytt:
ytt --file package/config
ytt -f package/config --data-values-file test/unit/config/values.yml

# Use ytt to generate an OpenAPI specification
schema:
ytt -f package/config/values-schema.yml --data-values-schema-inspect -o openapi-v3 > schema-openapi.yml

# Use kbld to resolve the OCI images referenced within the manifests
kbld:
rm -f package/.imgpkg/images.yml && mkdir -p package/.imgpkg && kbld --file package/config --imgpkg-lock-output package/.imgpkg/images.yml 1>> /dev/null

# Check the ytt-annotated Kubernetes configuration and its validation
test-config:
ytt -f package/config | kubeconform -ignore-missing-schemas -summary
ytt -f package/config --data-values-file test/unit/config/values.yml | kubeconform -ignore-missing-schemas -summary

# Run package integration tests
test-integration: test/integration
kubectl kuttl test --config test/integration/kuttl-test.yml --kind-config test/setup/kind/$(K8S_VERSION)/kind-config.yml
28 changes: 14 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

![Test Workflow](https://github.com/kadras-io/engineering-platform/actions/workflows/test.yml/badge.svg)
![Release Workflow](https://github.com/kadras-io/engineering-platform/actions/workflows/release.yml/badge.svg)
[![The SLSA Level 3 badge](https://slsa.dev/images/gh-badge-level3.svg)](https://slsa.dev/spec/v0.1/levels)
[![The SLSA Level 3 badge](https://slsa.dev/images/gh-badge-level3.svg)](https://slsa.dev/spec/v1.0/levels)
[![The Apache 2.0 license badge](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Follow us on Twitter](https://img.shields.io/static/v1?label=Twitter&message=Follow&color=1DA1F2)](https://twitter.com/kadrasIO)

Expand All @@ -26,10 +26,9 @@ A curated set of Carvel packages to build an engineering platform supporting app
Add the Kadras [package repository](https://github.com/kadras-io/kadras-packages) to your Kubernetes cluster:

```shell
kubectl create namespace kadras-packages
kctrl package repository add -r kadras-packages \
--url ghcr.io/kadras-io/kadras-packages \
-n kadras-packages
-n kadras-packages --create-namespace
```

<details><summary>Installation without package repository</summary>
Expand Down Expand Up @@ -75,11 +74,10 @@ The Engineering Platform package can be customized via a `values.yml` file.

```yaml
platform:
platform:
profile: serving
ingress:
domain: thomasvitale.com
oci_registry:
server: ghcr.io
repository: thomasvitale
```

Reference the `values.yml` file from the `kctrl` command when installing or upgrading the package.
Expand All @@ -100,19 +98,24 @@ The Engineering Platform package has the following configurable properties.

| Config | Default | Description |
|-------|-------------------|-------------|
| `platform.profile` | `full` | The platform profile to install. Options: `full`, `serving`. |
| `platform.namespace` | `kadras-packages` | The namespace where to install the platform. |
| `platform.excluded_packages` | `[]` | A list of packages to exclude from being installed. |
| `platform.ca_cert_data` | `""` | PEM-encoded certificate data to trust TLS connections with a custom CA. |
| `platform.ingress.domain.issuer.type` | `private` | The type of ClusterIssuer the platform will use to enable TLS communications. Options: `private`, `letsencrypt_staging`, `letsencrypt`, `custom`. |
| `platform.ingress.domain.issuer.name` | `""` | A reference to a custom ClusterIssuer previously created on the cluster where the platform will be installed. Required when the type is `custom`. |
| `platform.infrastructure_provider` | `""` | The underlying infrastructure provider. Options are `local` and `vsphere`. This field is not required, but it enables better validation and defaulting if provided. |
| `platform.ingress.domain` | `""` | The base domain name the platform will use to configure the Ingress controller. It must be a valid DNS name. |
| `platform.ingress.issuer.type` | `private` | The type of ClusterIssuer the platform will use to enable TLS communications. Options: `private`, `letsencrypt_staging`, `letsencrypt`, `custom`. |
| `platform.ingress.issuer.name` | `""` | A reference to a custom ClusterIssuer previously created on the cluster where the platform will be installed. Required when the type is `custom`. |
| `platform.ingress.issuer.email` | `""` | The email address that Let's Encrypt will use to send info on expiring certificates or other issues. Required when the type is `letsencrypt_staging` or `letsencrypt`. |
| `platform.oci_registry.server` | `""` | The server of the OCI Registry where the platform will publish and consume OCI images. |
| `platform.oci_registry.repository` | `""` | The repository in the OCI Registry where the platform will publish and consume OCI images. |
| `platform.oci_registry.credentials.username` | `""` | Username to access the OCI registry. Note: Use `_json_key` for GCR. |
| `platform.oci_registry.credentials.password` | `""` | Token to access the OCI registry. Note: Use contents of service account key json for GCR. |
| `platform.oci_registry.secret.name` | `supply-chain-registry-credentials` | The name of the Secret holding the credentials to access the OCI registry. |
| `platform.oci_registry.secret.namespace` | `kadras-packages` | The namespace of the Secret holding the credentials to access the OCI registry. |
| `platform.cosign.secret.name` | `supply-chain-cosign-key-pair` | The name of the Secret holding the Cosign key pair. |
| `platform.cosign.secret.namespace` | `kadras-packages` | The namespace of the Secret holding the Cosign key pair. |
| `platform.git.server` | `https://github.com` | The server hosting the Git repositories used by the plaform. |
| `platform.git.secret.name` | `supply-chain-git-credentials` | The name of the Secret holding the credentials to access the Git server. |
| `platform.git.secret.namespace` | `kadras-packages` | The namespace of the Secret holding the credentials to access the Git server. |

Each Kadras package included in the platform can be configured independently.

Expand Down Expand Up @@ -148,7 +151,4 @@ This project is licensed under the **Apache License 2.0**. See [LICENSE](LICENSE

## 🙏&nbsp; Acknowledgments

This package is inspired by:

* the App Toolkit package used in [Tanzu Community Edition](https://github.com/vmware-tanzu/community-edition) before its retirement;
* the [OSS Stack](https://github.com/vrabbi/tap-oss) example of [Tanzu Application Platform](https://tanzu.vmware.com/application-platform).
This package is inspired by the App Toolkit package used in [Tanzu Community Edition](https://github.com/vmware-tanzu/community-edition) before its retirement and the [open-source example](https://github.com/vrabbi/tap-oss) of [Tanzu Application Platform](https://tanzu.vmware.com/application-platform) by [Scott Rosenberg](https://vrabbi.cloud).
43 changes: 23 additions & 20 deletions docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## 1. Prerequisites

* Kubernetes 1.24+
* Kubernetes 1.25+
* Carvel [`kctrl`](https://carvel.dev/kapp-controller/docs/latest/install/#installing-kapp-controller-cli-kctrl) CLI.
* Sigstore [`cosign`](https://docs.sigstore.dev/cosign/installation/) CLI.
* Carvel [kapp-controller](https://carvel.dev/kapp-controller) deployed in your Kubernetes cluster. You can install it with Carvel [`kapp`](https://carvel.dev/kapp/docs/latest/install) (recommended choice) or `kubectl`.
Expand All @@ -14,13 +14,12 @@

## 2. Add the Kadras Repository

Add the Kadras repository to make all Kadras packages available to the cluster.
Add the Kadras repository to make all the platform packages available to the cluster.

```shell
kubectl create namespace kadras-packages
kctrl package repository add -r kadras-packages \
--url ghcr.io/kadras-io/kadras-packages \
-n kadras-packages
-n kadras-packages --create-namespace
```

You can check the full list of available packages as follows.
Expand Down Expand Up @@ -61,7 +60,26 @@ Next, use Cosign to generate a key-pair that will be used by the platform to sig

The previous command will create a cosign.pub file in the current directory. That's the public key you can use the verify OCI artifacts built and signed by the platform.

## 5. Configure the Platform
## 5. Create Secret for Git server

Then, create a Secret with the credentials to access your Git server in read/write mode. It will be used by the platform to work with Git repositories.

```shell
export SUPPLY_CHAIN_GIT_USERNAME=<username>
export SUPPLY_CHAIN_GIT_TOKEN=<token>
```

* `<username>` is the username to access the Git server.
* `<token>` is a token with read/write permissions to access the Git server.

```shell
kubectl create secret generic supply-chain-git-credentials \
--from-literal=username"${SUPPLY_CHAIN_REGISTRY_USERNAME}" \
--from-literal=password="${SUPPLY_CHAIN_REGISTRY_TOKEN}" \
--namespace=kadras-packages
```

## 6. Configure the Platform

The installation of the Kadras Engineering Platform can be configured via YAML. Create a `values.yml` file with any configuration you need for the platform. The following is a minimal configuration example.

Expand All @@ -73,26 +91,11 @@ platform:
oci_registry:
server: <oci-server>
repository: <oci-repository>

cosign:
secret:
name: supply-chain-cosign-key-pair
namespace: kadras-packages

workspace_provisioner:
namespaces:
- name: default
git:
credentials:
username: <github-username>
password: <github-token>
```

* `<domain>` is the base domain name the platform will use to configure the Ingress controller. It must be a valid DNS name. For example, `lab.thomasvitale.com`.
* `<oci-server>` is the server of the OCI registry where the platform will publish and consume OCI images. It must be the same used in step 3 when creating a Secret with the OCI registry credentials. For example, `ghcr.io`, `gcr.io`, `quay.io`, `index.docker.io`.
* `<oci-repository>` is the repository in the OCI registry where the platform will publish and consume OCI images. It must be the same used in step 3 when creating a Secret with the OCI registry credentials. For example, it might be your username or organization name depending on which OCI server you're using.
* `<github-username>` is your username to access your Git repositories on GitHub. It's not needed if you won't use the GitOps workflows offered by the platform and only use public Git repositories.
* `<github-token>` is a token with read/write permissions to access your Git repositories on GitHub. It's not needed if you won't use the GitOps workflows offered by the platform and only use public Git repositories.

## 6. Install the Platform

Expand Down
23 changes: 11 additions & 12 deletions package/config/buildpacks-catalog.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
#@ load("@ytt:data", "data")
#@ load("@ytt:struct", "struct")
#@ load("@ytt:yaml", "yaml")
#@ load("/helpers.star", "is_package_enabled")
#@ load("/helpers.star", "is_any_profile_enabled", "is_package_enabled", "profiles")

#@ if is_package_enabled("buildpacks-catalog"):
#@ if is_package_enabled("buildpacks-catalog") and is_any_profile_enabled([profiles.full]):

#@ def build_package_values():
#@ values = {
#@ "kp_default_repository": {}
#@ }
#@ def compute_package_values():
#@ values = struct.decode(data.values.buildpacks.catalog)
#@
#@ if data.values.buildpacks.catalog:
#@ values.update(struct.decode(data.values.buildpacks.catalog))
#@ end
#@ if data.values.platform.oci_registry.server and data.values.platform.oci_registry.repository and (not hasattr(data.values.buildpacks.catalog, "kp_default_repository") or not hasattr(data.values.buildpacks.catalog.kp_default_repository, "name") or not data.values.buildpacks.catalog.kp_default_repository.name):
#@ values["kp_default_repository"]["name"] = data.values.platform.oci_registry.server.rstrip("/") + "/" + data.values.platform.oci_registry.repository.rstrip("/") + "/buildpacks"
#@ #! Compute values for OCI Registry server
#@ if data.values.platform.oci_registry.server and data.values.platform.oci_registry.repository:
#@ if not hasattr(data.values.buildpacks.catalog, "kp_default_repository") or not hasattr(data.values.buildpacks.catalog.kp_default_repository, "name") or not data.values.buildpacks.catalog.kp_default_repository.name:
#@ values["kp_default_repository"] = {}
#@ values["kp_default_repository"]["name"] = data.values.platform.oci_registry.server.rstrip("/") + "/" + data.values.platform.oci_registry.repository.rstrip("/") + "/buildpacks"
#@ end
#@ end
#@
#@ return struct.encode(values)
Expand Down Expand Up @@ -47,6 +46,6 @@ metadata:
name: buildpacks-catalog-values
namespace: #@ data.values.platform.namespace
stringData:
values.yaml: #@ yaml.encode(build_package_values())
values.yaml: #@ yaml.encode(compute_package_values())

#@ end
16 changes: 5 additions & 11 deletions package/config/cartographer-blueprints.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
#@ load("@ytt:data", "data")
#@ load("@ytt:struct", "struct")
#@ load("@ytt:yaml", "yaml")
#@ load("/helpers.star", "is_package_enabled")
#@ load("/helpers.star", "is_any_profile_enabled", "is_package_enabled", "profiles")

#@ if is_package_enabled("cartographer-blueprints"):
#@ if is_package_enabled("cartographer-blueprints") and is_any_profile_enabled([profiles.full]):

#@ def build_package_values():
#@ values = {}
#@
#@ if data.values.cartographer.blueprints:
#@ values.update(struct.decode(data.values.cartographer.blueprints))
#@ end
#@
#@ return struct.encode(values)
#@ def compute_package_values():
#@ return data.values.cartographer.blueprints
#@ end

---
Expand Down Expand Up @@ -44,6 +38,6 @@ metadata:
name: cartographer-blueprints-values
namespace: #@ data.values.platform.namespace
stringData:
values.yaml: #@ yaml.encode(build_package_values())
values.yaml: #@ yaml.encode(compute_package_values())

#@ end
16 changes: 5 additions & 11 deletions package/config/cartographer-delivery.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
#@ load("@ytt:data", "data")
#@ load("@ytt:struct", "struct")
#@ load("@ytt:yaml", "yaml")
#@ load("/helpers.star", "is_package_enabled")
#@ load("/helpers.star", "is_any_profile_enabled", "is_package_enabled", "profiles")

#@ if is_package_enabled("cartographer-delivery"):
#@ if is_package_enabled("cartographer-delivery") and is_any_profile_enabled([profiles.full]):

#@ def build_package_values():
#@ values = {}
#@
#@ if data.values.cartographer.delivery:
#@ values.update(struct.decode(data.values.cartographer.delivery))
#@ end
#@
#@ return struct.encode(values)
#@ def compute_package_values():
#@ return data.values.cartographer.delivery
#@ end

---
Expand Down Expand Up @@ -43,6 +37,6 @@ metadata:
name: cartographer-delivery-values
namespace: #@ data.values.platform.namespace
stringData:
values.yaml: #@ yaml.encode(build_package_values())
values.yaml: #@ yaml.encode(compute_package_values())

#@ end
25 changes: 12 additions & 13 deletions package/config/cartographer-supply-chains.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
#@ load("@ytt:data", "data")
#@ load("@ytt:struct", "struct")
#@ load("@ytt:yaml", "yaml")
#@ load("/helpers.star", "is_package_enabled")
#@ load("/helpers.star", "is_any_profile_enabled", "is_package_enabled", "profiles")

#@ if is_package_enabled("cartographer-supply-chains"):
#@ if is_package_enabled("cartographer-supply-chains") and is_any_profile_enabled([profiles.full]):

#@ def build_package_values():
#@ values = {
#@ "registry": {}
#@ }
#@ def compute_package_values():
#@ values = struct.decode(data.values.cartographer.supply_chains)
#@
#@ if data.values.cartographer.supply_chains:
#@ values.update(struct.decode(data.values.cartographer.supply_chains))
#@ end
#@ if data.values.platform.oci_registry.server and data.values.platform.oci_registry.repository and (not hasattr(data.values.cartographer.supply_chains, "registry") or not hasattr(data.values.cartographer.supply_chains.registry, "server") or not hasattr(data.values.cartographer.supply_chains.registry, "repository") or not data.values.cartographer.supply_chains.registry.server or not data.values.cartographer.supply_chains.registry.repository):
#@ values["registry"]["server"] = data.values.platform.oci_registry.server.rstrip("/")
#@ values["registry"]["repository"] = data.values.platform.oci_registry.repository.rstrip("/") + "/workloads"
#@ #! Compute values for OCI Registry server
#@ if data.values.platform.oci_registry.server and data.values.platform.oci_registry.repository:
#@ if not hasattr(data.values.cartographer.supply_chains, "registry") or not hasattr(data.values.cartographer.supply_chains.registry, "server") or not hasattr(data.values.cartographer.supply_chains.registry, "repository") or not data.values.cartographer.supply_chains.registry.server or not data.values.cartographer.supply_chains.registry.repository:
#@ values["registry"] = {}
#@ values["registry"]["server"] = data.values.platform.oci_registry.server.rstrip("/")
#@ values["registry"]["repository"] = data.values.platform.oci_registry.repository.rstrip("/") + "/workloads"
#@ end
#@ end
#@
#@ return struct.encode(values)
Expand Down Expand Up @@ -49,6 +48,6 @@ metadata:
name: cartographer-supply-chains-values
namespace: #@ data.values.platform.namespace
stringData:
values.yaml: #@ yaml.encode(build_package_values())
values.yaml: #@ yaml.encode(compute_package_values())

#@ end
20 changes: 8 additions & 12 deletions package/config/cartographer.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
#@ load("@ytt:data", "data")
#@ load("@ytt:struct", "struct")
#@ load("@ytt:yaml", "yaml")
#@ load("/helpers.star", "is_package_enabled")
#@ load("/helpers.star", "is_any_profile_enabled", "is_package_enabled", "profiles")

#@ if is_package_enabled("cartographer"):
#@ if is_package_enabled("cartographer") and is_any_profile_enabled([profiles.full]):

#@ def build_package_values():
#@ values = {
#@ "ca_cert_data": ""
#@ }
#@ def compute_package_values():
#@ values = struct.decode(data.values.cartographer.core)
#@
#@ if data.values.cartographer.core:
#@ values.update(struct.decode(data.values.cartographer.core))
#@ end
#@ if data.values.platform.ca_cert_data and (not hasattr(data.values.cartographer.core, "ca_cert_data") or not data.values.cartographer.core.ca_cert_data):
#@ values["ca_cert_data"] = data.values.platform.ca_cert_data
#@ #! Compute values for CA Certificates
#@ if data.values.platform.ca_cert_data:
#@ values["ca_cert_data"] = values["ca_cert_data"] + data.values.platform.ca_cert_data
#@ end
#@
#@ return struct.encode(values)
Expand Down Expand Up @@ -47,6 +43,6 @@ metadata:
name: cartographer-values
namespace: #@ data.values.platform.namespace
stringData:
values.yaml: #@ yaml.encode(build_package_values())
values.yaml: #@ yaml.encode(compute_package_values())

#@ end
Loading