feat: Split ngrok-operators CRDs into their own chart (#732)

Signed-off-by: Jonathan Stacks <jonstacks@users.noreply.github.com>
This commit is contained in:
Jonathan Stacks
2025-12-16 15:58:31 -06:00
committed by GitHub
parent ea488a0d10
commit 36b119329d
40 changed files with 243 additions and 36 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ PROJECT linguist-generated=true
api/**/zz_generated*go linguist-generated=true
# These files are generated by kubebuilder. See Makefile for details.
helm/ngrok-operator/templates/crds/** linguist-generated=true
helm/ngrok-crds/templates/*.yaml linguist-generated=true
helm/ngrok-operator/templates/rbac/role.yaml linguist-generated=true
manifest-bundle.yaml linguist-generated=true
+2
View File
@@ -37,8 +37,10 @@ runs:
- '.github/actions/**'
chartyaml:
- 'helm/ngrok-operator/Chart.yaml'
- 'helm/ngrok-crds/Chart.yaml'
charts:
- 'helm/ngrok-operator/**'
- 'helm/ngrok-crds/**'
- 'scripts/e2e.sh'
go:
- '**.go'
+30 -7
View File
@@ -5,6 +5,7 @@ on:
branches:
- main
paths:
- 'helm/ngrok-crds/Chart.yaml'
- 'helm/ngrok-operator/Chart.yaml'
jobs:
@@ -13,7 +14,8 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
outputs:
charts: ${{ steps.filter.outputs.charts }}
ngrok-operator: ${{ steps.filter.outputs.ngrok-operator }}
ngrok-crds: ${{ steps.filter.outputs.ngrok-crds }}
permissions:
contents: read
pull-requests: read
@@ -26,11 +28,13 @@ jobs:
uses: dorny/paths-filter@v2.11.1
with:
filters: |
charts:
ngrok-operator:
- 'helm/ngrok-operator/Chart.yaml'
ngrok-crds:
- 'helm/ngrok-crds/Chart.yaml'
chart:
name: Release Chart
name: Release Charts
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
@@ -38,7 +42,10 @@ jobs:
needs: [changes]
if: |
(github.repository == 'ngrok/ngrok-operator') &&
(needs.changes.outputs.charts == 'true')
(
(needs.changes.outputs.ngrok-operator == 'true') ||
(needs.changes.outputs.ngrok-crds == 'true')
)
steps:
- name: Checkout repo
uses: actions/checkout@v6
@@ -69,7 +76,7 @@ jobs:
uses: helm/chart-releaser-action@v1.5.0
env:
CR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CR_RELEASE_NAME_TEMPLATE: "helm-chart-{{ .Version }}" # Publishes a new release. Ex: helm-chart-0.1.0
CR_RELEASE_NAME_TEMPLATE: "helm-chart-{{ .Name }}-{{ .Version }}" # Publishes a new release. Ex: helm-chart-ngrok-operator-0.1.0
CR_SKIP_EXISTING: "true"
CR_KEY: "Team Eng Infra (ngrok.com) (Key for signing ngrok-operator Helm chart) <team-infra@ngrok.com>" # full key name
CR_KEYRING: keyring.gpg
@@ -80,9 +87,25 @@ jobs:
- run: ls -alth .
working-directory: ./.cr-release-packages
shell: bash
- name: Push to charts.ngrok.com
- name: Push ngrok-crds to charts.ngrok.com
if: needs.changes.outputs.ngrok-crds == 'true'
working-directory: ./.cr-release-packages
env:
CHART_PUSH_AUTH: ${{ secrets.CHART_PUSH_AUTH }}
run: |
for chart in ngrok-crds-*.tgz; do
if [ -f "${chart}.prov" ]; then
echo "Uploading ${chart} and ${chart}.prov"
curl -H "Authorization: Basic ${CHART_PUSH_AUTH}" -F "chart=@${chart}" -F "prov=@${chart}.prov" "https://charts.ngrok.com/api/charts"
else
echo "Uploading ${chart}"
curl -H "Authorization: Basic ${CHART_PUSH_AUTH}" -F "chart=@${chart}" "https://charts.ngrok.com/api/charts"
fi
done
- name: Push ngrok-operator to charts.ngrok.com
if: needs.changes.outputs.ngrok-operator == 'true'
working-directory: ./.cr-release-packages
env:
CHART_PUSH_AUTH: ${{ secrets.CHART_PUSH_AUTH }}
+3 -1
View File
@@ -28,8 +28,10 @@ jobs:
filters: |
chartyaml:
- 'helm/ngrok-operator/Chart.yaml'
- 'helm/ngrok-crds/Chart.yaml'
charts:
- 'helm/ngrok-operator/**'
- 'helm/ngrok-crds/**'
- 'scripts/e2e.sh'
go:
- '**.go'
@@ -63,7 +65,7 @@ jobs:
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: ":wave: Looks like there are changes in the Helm Chart's Chart.yaml file. Upon merge, a new release of the helm chart will be created if the Chart's version was changed."
body: ":wave: Looks like there are changes in a Helm Chart's Chart.yaml file. Upon merge, a new release of the helm chart will be created if the Chart's version was changed."
})
- if: needs.changes.outputs.tag == 'true'
name: Notify about version change
+21 -2
View File
@@ -3,10 +3,12 @@
- [Artifacts](#artifacts)
- [Docker Image](#docker-image)
- [Helm Chart](#helm-chart)
- [CRDs Helm Chart](#crds-helm-chart)
- [Semantic Versioning](#semantic-versioning)
- [Release Process](#release-process)
- [Tagging](#tagging)
- [Helm Chart](#helm-chart-1)
- [CRDs Helm Chart](#crds-helm-chart-1)
- [Controller](#controller)
# Release Steps
@@ -55,6 +57,13 @@ support `amd64` and `arm64` architectures, with future plans to build for other
The helm chart is packaged and published to its own [helm repository](https://charts.ngrok.com/index.yaml)
and can be installed by following the instructions in the chart's [README](../helm/ingress-operator/README.md).
### CRDs Helm Chart
The `ngrok-crds` helm chart contains the Custom Resource Definitions (CRDs) for the ngrok operator.
This chart is published to the same [helm repository](https://charts.ngrok.com/index.yaml) as the
main operator chart. It allows users to manage CRD lifecycle separately from the operator, which
is useful for GitOps workflows and when multiple operators share the same CRDs.
## Semantic Versioning
This project uses [semantic versioning](https://semver.org/) for both the the docker image
@@ -79,8 +88,8 @@ There is a different git tag pattern for each artifact.
#### Helm Chart
Releases of the helm chart will be tagged with a prefix of `helm-chart-`. For example, version `1.2.0`
of the helm chart will have a git tag of `helm-chart-1.2.0` which contains the code used to package
and publish version `1.2.0` of the helm chart.
of the helm chart will have a git tag of `helm-chart-1.2.0` or `helm-chart-ngrok-operator-1.2.0` which
contains the code used to package and publish version `1.2.0` of the helm chart.
When changes are made to the helm chart's `Chart.yaml` file, a github workflow will trigger upon
merging the PR to the `main` branch. The workflow will package and publish the helm chart for
@@ -89,6 +98,16 @@ consumption. The workflow will also create a git tag as described above.
When changing `version` in the helm chart's `Chart.yaml` file, the version should be bumped according
to the semantic versioning spec as described above.
#### CRDs Helm Chart
Releases of the CRDs helm chart will be tagged with a prefix of `helm-chart-`. For example, version `0.1.0`
of the CRDs helm chart will have a git tag of `helm-chart-ngrok-crds-0.1.0` which contains the code used to package
and publish version `0.1.0` of the CRDs helm chart.
When changes are made to the CRDs helm chart's `Chart.yaml` file in `helm/ngrok-crds/`, a github workflow
will trigger upon merging the PR to the `main` branch. The workflow will package and publish the CRDs
helm chart for consumption. The workflow will also create a git tag as described above.
#### Controller
Releases of the controller will be tagged with a prefix of `ngrok-operator-`. For example,
+28
View File
@@ -0,0 +1,28 @@
# Source: https://github.com/helm/helm/blob/main/pkg/repo/repotest/testdata/examplechart/.helmignore
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
# helmtest plugin tests
tests
# Makefile used in development
Makefile
+15
View File
@@ -0,0 +1,15 @@
apiVersion: v2
name: ngrok-crds
description: ngrok Custom Resource Definitions for Kubernetes.
version: 0.1.0
appVersion: 0.1.0
keywords:
- ngrok
- networking
- ingress
- edge
- api gateway
home: https://ngrok.com
sources:
- https://github.com/ngrok/ngrok-operator
icon: https://charts.ngrok.com/assets/ngrok-favicon.svg
+36
View File
@@ -0,0 +1,36 @@
# ngrok Custom Resource Definitions
This Helm chart installs the ngrok Custom Resource Definitions (CRDs) for Kubernetes.
## Usage
### Prerequisites
[Helm](https://helm.sh) must be installed to use the charts.
Please refer to Helm's [documentation](https://helm.sh/docs) to get started.
### Installation
Once Helm has been set up correctly, add the repo as follows:
`helm repo add ngrok https://charts.ngrok.com`
If you had already added this repo earlier, run `helm repo update` to retrieve the latest versions of the packages.
You can then run `helm search repo ngrok` to see the charts.
To install the ngrok-crds chart:
`helm install ngrok-crds ngrok/ngrok-crds`
To uninstall the chart:
`helm delete ngrok-crds`
### Using with ngrok-operator
The `ngrok-operator` chart can install these CRDs automatically via the `installCRDs` value (enabled by default).
You only need to install this chart separately if you want to manage CRD lifecycle independently from the operator.
## More Information
For more information about the ngrok Kubernetes Operator, see https://github.com/ngrok/ngrok-operator
View File
+2
View File
@@ -0,0 +1,2 @@
# Default values for ngrok-crds.
# This is a CRD-only chart with minimal configuration options.
+5 -2
View File
@@ -2,5 +2,8 @@ dependencies:
- name: common
repository: oci://registry-1.docker.io/bitnamicharts
version: 2.31.4
digest: sha256:fc442e77200e1914dd46fe26490dcf62f44caa51db673c2f8e67d5319cd4c163
generated: "2025-09-16T12:41:24.213248873-05:00"
- name: ngrok-crds
repository: file://../ngrok-crds
version: 0.1.0
digest: sha256:9c480e82a22999fc545c25743c8d3b77424110e41301d32fdf1638fa77b77b1a
generated: "2025-12-04T13:58:23.841927339-06:00"
+7 -1
View File
@@ -1,7 +1,7 @@
apiVersion: v2
name: ngrok-operator
description: The official ngrok Kubernetes Operator.
version: 0.21.1
version: 0.22.0-rc.1
appVersion: 0.19.1
keywords:
- ngrok
@@ -19,3 +19,9 @@ dependencies:
tags:
- bitnami-common
version: 2.x.x
- name: ngrok-crds
repository: file://../ngrok-crds
version: 0.1.0
condition: installCRDs
tags:
- install-crds
+31
View File
@@ -30,6 +30,31 @@ To uninstall the chart:
`helm delete my-ngrok-operator`
## Multi-Instance Installations
To run multiple ngrok-operator instances in the same cluster (e.g., in different namespaces), install the CRDs once and disable CRD installation for each operator instance:
1. Install CRDs once per cluster:
```bash
helm install ngrok-crds ngrok/ngrok-crds
```
2. Install operator instances with `installCRDs=false`:
```bash
helm install ngrok-operator-ns1 ngrok/ngrok-operator \
--namespace ns1 \
--set installCRDs=false
helm install ngrok-operator-ns2 ngrok/ngrok-operator \
--namespace ns2 \
--set installCRDs=false
```
> **Important:** Do not set `installCRDs=true` if CRDs are already managed by another Helm release. Helm will fail with ownership conflicts if multiple releases attempt to manage the same CRDs.
<!-- Parameters are auto generated via @bitnami/readme-generator-for-helm -->
## Parameters
@@ -176,3 +201,9 @@ To uninstall the chart:
| `bindings.forwarder.tolerations` | Tolerations for the bindings forwarder pod(s) | `[]` |
| `bindings.forwarder.nodeSelector` | Node labels for the bindings forwarder pod(s) | `{}` |
| `bindings.forwarder.topologySpreadConstraints` | Topology Spread Constraints for the bindings forwarder pod(s) | `[]` |
### Custom Resource Definitions installation
| Name | Description | Value |
| ------------- | ------------------------------------------------------------------ | ------ |
| `installCRDs` | When true, the ngrok CRDs will be installed alongside the operator | `true` |
@@ -13,7 +13,7 @@ Should match all-options snapshot:
app.kubernetes.io/name: ngrok-operator
app.kubernetes.io/part-of: ngrok-operator
app.kubernetes.io/version: 0.19.1
helm.sh/chart: ngrok-operator-0.21.1
helm.sh/chart: ngrok-operator-0.22.0-rc.1
name: RELEASE-NAME-ngrok-operator-manager
namespace: NAMESPACE
spec:
@@ -430,7 +430,7 @@ Should match default snapshot:
app.kubernetes.io/name: ngrok-operator
app.kubernetes.io/part-of: ngrok-operator
app.kubernetes.io/version: 0.19.1
helm.sh/chart: ngrok-operator-0.21.1
helm.sh/chart: ngrok-operator-0.22.0-rc.1
name: RELEASE-NAME-ngrok-operator-manager
namespace: NAMESPACE
spec:
@@ -10,7 +10,7 @@ should match snapshot:
app.kubernetes.io/name: ngrok-operator
app.kubernetes.io/part-of: ngrok-operator
app.kubernetes.io/version: 0.19.1
helm.sh/chart: ngrok-operator-0.21.1
helm.sh/chart: ngrok-operator-0.22.0-rc.1
name: test-release-ngrok-operator-controller-pdb
namespace: test-namespace
spec:
@@ -10,6 +10,6 @@ Should match the snapshot:
app.kubernetes.io/name: ngrok-operator
app.kubernetes.io/part-of: ngrok-operator
app.kubernetes.io/version: 0.19.1
helm.sh/chart: ngrok-operator-0.21.1
helm.sh/chart: ngrok-operator-0.22.0-rc.1
name: test-release-ngrok-operator
namespace: test-namespace
@@ -10,7 +10,7 @@ Should match snapshot:
app.kubernetes.io/name: ngrok-operator
app.kubernetes.io/part-of: ngrok-operator
app.kubernetes.io/version: 0.19.1
helm.sh/chart: ngrok-operator-0.21.1
helm.sh/chart: ngrok-operator-0.22.0-rc.1
name: ngrok
spec:
controller: k8s.ngrok.com/ingress-controller
@@ -12,7 +12,7 @@ Should match snapshot:
app.kubernetes.io/name: ngrok-operator
app.kubernetes.io/part-of: ngrok-operator
app.kubernetes.io/version: 0.19.1
helm.sh/chart: ngrok-operator-0.21.1
helm.sh/chart: ngrok-operator-0.22.0-rc.1
name: RELEASE-NAME-ngrok-operator-agent
namespace: NAMESPACE
spec:
@@ -10,6 +10,6 @@ Should match snapshot:
app.kubernetes.io/name: ngrok-operator
app.kubernetes.io/part-of: ngrok-operator
app.kubernetes.io/version: 0.19.1
helm.sh/chart: ngrok-operator-0.21.1
helm.sh/chart: ngrok-operator-0.22.0-rc.1
name: test-release-ngrok-operator-agent
namespace: test-namespace
@@ -12,7 +12,7 @@ Should match snapshot:
app.kubernetes.io/name: ngrok-operator
app.kubernetes.io/part-of: ngrok-operator
app.kubernetes.io/version: 0.19.1
helm.sh/chart: ngrok-operator-0.21.1
helm.sh/chart: ngrok-operator-0.22.0-rc.1
name: RELEASE-NAME-ngrok-operator-bindings-forwarder
namespace: NAMESPACE
spec:
@@ -10,6 +10,6 @@ Should match snapshot:
app.kubernetes.io/name: ngrok-operator
app.kubernetes.io/part-of: ngrok-operator
app.kubernetes.io/version: 0.19.1
helm.sh/chart: ngrok-operator-0.21.1
helm.sh/chart: ngrok-operator-0.22.0-rc.1
name: test-release-ngrok-operator-bindings-forwarder
namespace: test-namespace
+5
View File
@@ -551,6 +551,11 @@
}
}
}
},
"installCRDs": {
"type": "boolean",
"description": "When true, the ngrok CRDs will be installed alongside the operator",
"default": true
}
}
}
+6
View File
@@ -415,3 +415,9 @@ bindings:
## @param bindings.forwarder.topologySpreadConstraints Topology Spread Constraints for the bindings forwarder pod(s)
topologySpreadConstraints: []
## @section Custom Resource Definitions installation
##
## @param installCRDs When true, the ngrok CRDs will be installed alongside the operator
installCRDs: true
+4 -2
View File
@@ -2,12 +2,12 @@ package agent
import (
"context"
"path/filepath"
"testing"
"time"
ingressv1alpha1 "github.com/ngrok/ngrok-operator/api/ingress/v1alpha1"
ngrokv1alpha1 "github.com/ngrok/ngrok-operator/api/ngrok/v1alpha1"
"github.com/ngrok/ngrok-operator/internal/testutils"
"github.com/ngrok/ngrok-operator/pkg/agent"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
@@ -41,7 +41,9 @@ var _ = BeforeSuite(func() {
By("bootstrapping test environment")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "helm", "ngrok-operator", "templates", "crds")},
CRDDirectoryPaths: []string{
testutils.OperatorCRDPath("..", "..", ".."),
},
ErrorIfCRDPathMissing: true,
}
+3 -2
View File
@@ -26,7 +26,6 @@ package bindings
import (
"context"
"path/filepath"
"testing"
"time"
@@ -80,7 +79,9 @@ var _ = BeforeSuite(func() {
By("bootstrapping test environment")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "helm", "ngrok-operator", "templates", "crds")},
CRDDirectoryPaths: []string{
testutils.OperatorCRDPath("..", "..", ".."),
},
ErrorIfCRDPathMissing: true,
}
+4 -2
View File
@@ -90,10 +90,12 @@ var _ = BeforeSuite(func() {
ctx, cancel = context.WithCancel(GinkgoT().Context())
By("bootstrapping test environment")
operatorAPIs := filepath.Join("..", "..", "..", "helm", "ngrok-operator", "templates", "crds")
gwAPIs := filepath.Join(".", "testdata", "gatewayapi-crds.yaml")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{operatorAPIs, gwAPIs},
CRDDirectoryPaths: []string{
testutils.OperatorCRDPath("..", "..", ".."),
gwAPIs,
},
}
var err error
+4 -2
View File
@@ -83,10 +83,12 @@ var _ = BeforeSuite(func() {
ctx, cancel = context.WithCancel(GinkgoT().Context())
By("bootstrapping test environment")
operatorAPIs := filepath.Join("..", "..", "..", "helm", "ngrok-operator", "templates", "crds")
gwAPIs := filepath.Join(".", "testdata", "gatewayapi-crds.yaml")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{operatorAPIs, gwAPIs},
CRDDirectoryPaths: []string{
testutils.OperatorCRDPath("..", "..", ".."),
gwAPIs,
},
}
var err error
+4 -2
View File
@@ -26,12 +26,12 @@ package ngrok
import (
"context"
"path/filepath"
"testing"
ingressv1alpha1 "github.com/ngrok/ngrok-operator/api/ingress/v1alpha1"
ngrokv1alpha1 "github.com/ngrok/ngrok-operator/api/ngrok/v1alpha1"
"github.com/ngrok/ngrok-operator/internal/mocks/nmockapi"
"github.com/ngrok/ngrok-operator/internal/testutils"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"k8s.io/client-go/kubernetes/scheme"
@@ -68,7 +68,9 @@ var _ = BeforeSuite(func() {
By("bootstrapping test environment")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "helm", "ngrok-operator", "templates", "crds")},
CRDDirectoryPaths: []string{
testutils.OperatorCRDPath("..", "..", ".."),
},
ErrorIfCRDPathMissing: true,
}
+1 -1
View File
@@ -79,7 +79,7 @@ var _ = BeforeSuite(func() {
ctx, cancel = context.WithCancel(GinkgoT().Context())
By("bootstrapping test environment")
operatorAPIs := filepath.Join("..", "..", "..", "helm", "ngrok-operator", "templates", "crds")
operatorAPIs := filepath.Join("..", "..", "..", "helm", "ngrok-crds", "templates")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{operatorAPIs},
}
+16
View File
@@ -0,0 +1,16 @@
package testutils
import (
"path/filepath"
)
// OperatorCRDPath returns the relative path to the operator CRD templates
// used in envtest setups. The path is relative to the repository root.
//
// Example:
//
// testutils.OperatorCRDPath() // returns "helm/ngrok-crds/templates"
// testutils.OperatorCRDPath("..", "..") // returns "../../helm/ngrok-crds/templates"
func OperatorCRDPath(relPathParts ...string) string {
return filepath.Join(append(relPathParts, "helm", "ngrok-crds", "templates")...)
}
+2 -1
View File
@@ -48,8 +48,9 @@ KIND_CLUSTER_NAME ?= ngrok-operator
HELM_RELEASE_NAME ?= ngrok-operator
HELM_CHART_DIR = ./helm/ngrok-operator
CRD_CHART_DIR = ./helm/ngrok-crds
HELM_TEMPLATES_DIR = $(HELM_CHART_DIR)/templates
CRD_TEMPLATES_DIR = $(CRD_CHART_DIR)/templates
## Tool Versions
+3
View File
@@ -84,6 +84,9 @@ deploy_for_e2e: _deploy-check-env-vars docker-build manifests _helm_setup kind-l
--set bindings.serviceAnnotations.annotation2="val2" \
--set bindings.serviceLabels.label1="val1"
.PHONY: deploy_multi_namespace
deploy_multi_namespace: _deploy-check-env-vars docker-build manifests _helm_setup kind-load-image ## Deploy multiple copies of the controller to the K8s cluster specified in ~/.kube/config.
.PHONY: kind-load-image
kind-load-image: ## Load the locally built image into the kind cluster.
kind load docker-image $(IMG) --name $(KIND_CLUSTER_NAME)
+1 -1
View File
@@ -11,7 +11,7 @@ generate-mocks:
.PHONY: manifests
manifests: ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
controller-gen rbac:roleName=ngrok-operator-manager-role crd webhook paths="$(CONTROLLER_GEN_PATHS)" \
output:crd:artifacts:config=$(HELM_TEMPLATES_DIR)/crds \
output:crd:artifacts:config=$(CRD_TEMPLATES_DIR) \
output:rbac:artifacts:config=$(HELM_TEMPLATES_DIR)/rbac