Skip to content

Commit ab99014

Browse files
committed
feat: helm standards
1 parent d0f4e83 commit ab99014

8 files changed

Lines changed: 164 additions & 64 deletions

README.md

Lines changed: 76 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -9,70 +9,75 @@ The Better Stack Operator keeps Better Stack monitors in sync with Kubernetes by
99
- **Lifecycle management** – Finalizers ensure remote monitors are removed when their CRs are deleted, preventing orphaned resources.
1010
- **Status you can trust**`Ready`, `CredentialsAvailable`, and `Synced` conditions expose reconciliation health.
1111

12-
## Helm Install
12+
## Install with Helm
1313

14-
Once a release is tagged (`vX.Y.Z`), the publish workflow builds and pushes a chart to:
14+
Published charts live at `oci://ghcr.io/loks0n/betterstack-operator/helm/betterstack-operator`.
1515

16-
```
17-
oci://ghcr.io/loks0n/betterstack-operator/helm/betterstack-operator
18-
```
16+
### 1. Provide Better Stack credentials
1917

20-
Install/update the operator with:
18+
Choose how the controller should access the API token:
2119

22-
```bash
23-
helm upgrade --install betterstack-operator \
24-
oci://ghcr.io/loks0n/betterstack-operator/helm/betterstack-operator \
25-
--namespace betterstack-operator --create-namespace \
26-
--wait
27-
```
20+
- **Chart-managed secret** – let the release create the secret in its namespace (default `betterstack-operator`).
2821

29-
Create the `betterstack-credentials` secret before running the chart (see Quick Start step 2).
22+
```bash
23+
helm upgrade --install betterstack-operator \
24+
oci://ghcr.io/loks0n/betterstack-operator/helm/betterstack-operator \
25+
--namespace betterstack-operator --create-namespace \
26+
--set credentials.secret.create=true \
27+
--set-file credentials.secret.value=./betterstack-token.txt \
28+
--wait
29+
```
3030

31-
## Quick Start
31+
Swap `--set-file` for `--set credentials.secret.value=$TOKEN` if you prefer piping the token directly from an environment variable or secret store.
3232

33-
1. **Fetch dependencies and (optionally) build**
33+
- **Bring-your-own secret** – pre-create it and point the chart at it:
3434

35-
```bash
36-
go mod tidy
37-
go build ./...
38-
```
35+
```bash
36+
kubectl create secret generic betterstack-operator-credentials \
37+
--from-literal=api-key=REPLACE_ME \
38+
-n betterstack-operator
39+
40+
helm upgrade --install betterstack-operator \
41+
oci://ghcr.io/loks0n/betterstack-operator/helm/betterstack-operator \
42+
--namespace betterstack-operator --create-namespace \
43+
--set credentials.existingSecret=betterstack-operator-credentials \
44+
--wait
45+
```
3946

40-
2. **Create an API token secret**
47+
The chart-generated secret defaults to `betterstack-operator-credentials`. Whichever path you choose, the secret must exist in every namespace where you define `BetterStackMonitor` objects.
4148

42-
```bash
43-
kubectl create secret generic betterstack-credentials \
44-
--from-literal=api-key=REPLACE_ME \
45-
-n default
46-
```
49+
### 2. Create monitors
4750

48-
3. **Install CRD, RBAC, and controller**
51+
Apply one of the sample CRs to verify the install:
4952

50-
```bash
51-
kubectl apply -f config/crd/bases/monitoring.betterstack.io_betterstackmonitors.yaml
52-
kubectl apply -f config/rbac/service_account.yaml
53-
kubectl apply -f config/rbac/role.yaml
54-
kubectl apply -f config/rbac/role_binding.yaml
55-
kubectl apply -k config/manager
56-
```
53+
```bash
54+
kubectl apply -f config/samples/monitoring_v1alpha1_betterstackmonitor_https.yaml
55+
kubectl apply -f config/samples/monitoring_v1alpha1_betterstackmonitor_keyword.yaml
56+
kubectl apply -f config/samples/monitoring_v1alpha1_betterstackmonitor_tcp.yaml
57+
```
5758

58-
4. **Create a monitor resource**
59+
Check reconciliation status and debug events with:
5960

60-
Choose one (or more) of the sample manifests:
61+
```bash
62+
kubectl get betterstackmonitors.monitoring.betterstack.io -A
63+
kubectl describe betterstackmonitor demo-monitor
64+
```
6165

62-
```bash
63-
kubectl apply -f config/samples/monitoring_v1alpha1_betterstackmonitor_https.yaml
64-
kubectl apply -f config/samples/monitoring_v1alpha1_betterstackmonitor_keyword.yaml
65-
kubectl apply -f config/samples/monitoring_v1alpha1_betterstackmonitor_tcp.yaml
66-
```
66+
Deleting a `BetterStackMonitor` automatically deletes the remote Better Stack monitor thanks to controller finalizers.
6767

68-
5. **Inspect status**
68+
### Configuration highlights
6969

70-
```bash
71-
kubectl get betterstackmonitors.monitoring.betterstack.io -A
72-
kubectl describe betterstackmonitor demo-monitor
73-
```
70+
See `helm/betterstack-operator/values.yaml` for the full list. Frequently tuned values include:
7471

75-
Deleting the `BetterStackMonitor` automatically deletes the remote Better Stack monitor.
72+
- `credentials.existingSecret` – reference a pre-created secret instead of letting the chart manage one.
73+
- `credentials.secret.*` – control chart-managed secret creation (name override, key, annotations, inline value).
74+
- `imagePullSecrets` – add registry credentials when pulling the operator image.
75+
- `podAnnotations`, `podLabels`, `podSecurityContext`, `containerSecurityContext` – attach metadata or adjust pod/container security posture.
76+
- `nodeSelector`, `tolerations`, `affinity` – steer the operator onto matching nodes.
77+
- `namespace` – pin all resources to a specific namespace (defaults to the release namespace).
78+
- `manager.*` – adjust controller ports, enable/disable leader election, and pass extra arguments.
79+
- `rbac.create` – disable default RBAC when running with pre-provisioned roles.
80+
- `crds.install` – set to `false` when CRDs are installed out-of-band (e.g., via GitOps).
7681

7782
## Spec Reference (excerpt)
7883

@@ -99,13 +104,34 @@ See `api/v1alpha1/betterstackmonitor_types.go` for the full schema and commentar
99104

100105
## Troubleshooting
101106

102-
- `CredentialsAvailable=False`Confirm the referenced secret exists and contains the API key.
103-
- `Synced=False`The Better Stack API rejected the payload; inspect the condition message for validation errors.
104-
- `Ready=True`The latest spec was successfully applied.
107+
- `CredentialsAvailable=False`confirm the referenced secret exists and contains the API key in the expected key.
108+
- `Synced=False`the Better Stack API rejected the payload; inspect the condition message for validation errors.
109+
- `Ready=True`the latest spec was successfully applied.
105110

106111
Enable verbose logging with `--zap-log-level=debug` in the manager deployment for extra context.
107112

108-
## Testing
113+
## Manual installation (development)
114+
115+
The manifests under `config/` are primarily for hacking on the controller:
116+
117+
```bash
118+
kubectl apply -f config/crd/bases/monitoring.betterstack.io_betterstackmonitors.yaml
119+
kubectl apply -f config/rbac/service_account.yaml
120+
kubectl apply -f config/rbac/role.yaml
121+
kubectl apply -f config/rbac/role_binding.yaml
122+
kubectl apply -k config/manager
123+
```
124+
125+
You still need to create a matching secret in the target namespace before running the manager locally or via these raw manifests.
126+
127+
## Development
128+
129+
- Module path: `loks0n/betterstack-operator`.
130+
- API types live under `api/v1alpha1`; controller logic is in `controllers/betterstackmonitor_controller.go`.
131+
- The Better Stack API client lives in `pkg/betterstack`.
132+
- E2E helpers are in `test/e2e`, relying on `kind`, `kubectl`, and a Better Stack test token.
133+
134+
### Testing
109135

110136
- **Unit tests**
111137

@@ -122,11 +148,4 @@ Enable verbose logging with `--zap-log-level=debug` in the manager deployment fo
122148

123149
The e2e test boots a Kind cluster, installs the CRD and controller, applies a richly populated `BetterStackMonitor`, and asserts (via the Better Stack API) that create/update/delete operations are reflected remotely. The test cleans up the remote monitor, but run it only against non-production credentials.
124150

125-
## Development Notes
126-
127-
- Module path: `loks0n/betterstack-operator`.
128-
- API types live under `api/v1alpha1`; controller logic is in `controllers/betterstackmonitor_controller.go`.
129-
- The Better Stack API client (create/update/get/list/delete) resides in `pkg/betterstack`.
130-
- E2E helpers are in `test/e2e`, relying on `kind`, `kubectl`, and genuine Better Stack credentials.
131-
132151
Contributions, issues, and ideas are welcome!

config/samples/monitoring_v1alpha1_betterstackmonitor_https.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,5 @@ spec:
3535
- name: X-Monitor-Source
3636
value: betterstack-operator
3737
apiTokenSecretRef:
38-
name: betterstack-credentials
38+
name: betterstack-operator-credentials
3939
key: api-key

config/samples/monitoring_v1alpha1_betterstackmonitor_keyword.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,5 @@ spec:
2727
maintenanceTo: "01:00:00"
2828
maintenanceTimezone: Europe/London
2929
apiTokenSecretRef:
30-
name: betterstack-credentials
30+
name: betterstack-operator-credentials
3131
key: api-key

config/samples/monitoring_v1alpha1_betterstackmonitor_tcp.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,5 @@ spec:
2424
maintenanceTo: "04:00:00"
2525
maintenanceTimezone: America/New_York
2626
apiTokenSecretRef:
27-
name: betterstack-credentials
27+
name: betterstack-operator-credentials
2828
key: api-key

helm/betterstack-operator/templates/deployment.yaml

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,29 @@ spec:
1818
labels:
1919
app.kubernetes.io/name: {{ include "betterstack-operator.name" . }}
2020
app.kubernetes.io/instance: {{ .Release.Name }}
21+
{{- with .Values.podLabels }}{{ toYaml . | nindent 8 }}{{- end }}
22+
{{- with .Values.podAnnotations }}
23+
annotations:
24+
{{ toYaml . | nindent 8 }}
25+
{{- end }}
2126
spec:
27+
{{- with .Values.imagePullSecrets }}
28+
imagePullSecrets:
29+
{{ toYaml . | nindent 8 }}
30+
{{- end }}
31+
{{- with .Values.podSecurityContext }}
32+
securityContext:
33+
{{ toYaml . | nindent 8 }}
34+
{{- end }}
2235
serviceAccountName: {{ default (include "betterstack-operator.fullname" .) .Values.serviceAccount.name }}
2336
containers:
2437
- name: manager
2538
image: "{{ .Values.image.repository }}:{{ default .Chart.AppVersion .Values.image.tag }}"
2639
imagePullPolicy: {{ .Values.image.pullPolicy }}
2740
args:
2841
- "--leader-elect={{ .Values.manager.leaderElection }}"
42+
- "--metrics-bind-address=:{{ .Values.manager.metricsPort }}"
43+
- "--health-probe-bind-address=:{{ .Values.manager.healthProbePort }}"
2944
{{- range $arg := .Values.manager.extraArgs }}
3045
- {{ $arg | quote }}
3146
{{- end }}
@@ -42,9 +57,21 @@ spec:
4257
httpGet:
4358
path: /healthz
4459
port: healthz
60+
{{- with .Values.containerSecurityContext }}
4561
securityContext:
46-
allowPrivilegeEscalation: false
47-
runAsNonRoot: true
48-
runAsUser: 65532
62+
{{ toYaml . | nindent 12 }}
63+
{{- end }}
4964
resources:
5065
{{ toYaml .Values.resources | indent 12 }}
66+
{{- with .Values.nodeSelector }}
67+
nodeSelector:
68+
{{ toYaml . | nindent 8 }}
69+
{{- end }}
70+
{{- with .Values.affinity }}
71+
affinity:
72+
{{ toYaml . | nindent 8 }}
73+
{{- end }}
74+
{{- with .Values.tolerations }}
75+
tolerations:
76+
{{ toYaml . | nindent 8 }}
77+
{{- end }}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{{- $existing := .Values.credentials.existingSecret -}}
2+
{{- if and (not $existing) .Values.credentials.secret.create }}
3+
{{- $name := default (printf "%s-credentials" (include "betterstack-operator.fullname" .)) .Values.credentials.secret.name -}}
4+
{{- $key := default "api-key" .Values.credentials.secret.key -}}
5+
{{- $value := required "credentials.secret.value must be set when credentials.secret.create is true" .Values.credentials.secret.value -}}
6+
apiVersion: v1
7+
kind: Secret
8+
metadata:
9+
name: {{ $name }}
10+
namespace: {{ include "betterstack-operator.namespace" . }}
11+
labels:
12+
app.kubernetes.io/name: {{ include "betterstack-operator.name" . }}
13+
app.kubernetes.io/instance: {{ .Release.Name }}
14+
app.kubernetes.io/managed-by: {{ .Release.Service }}
15+
{{- with .Values.credentials.secret.annotations }}
16+
annotations:
17+
{{ toYaml . | nindent 4 }}
18+
{{- end }}
19+
type: Opaque
20+
stringData:
21+
{{ $key }}: {{ $value | quote }}
22+
{{- end }}

helm/betterstack-operator/templates/serviceaccount.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,8 @@ metadata:
88
app.kubernetes.io/name: {{ include "betterstack-operator.name" . }}
99
app.kubernetes.io/instance: {{ .Release.Name }}
1010
app.kubernetes.io/managed-by: {{ .Release.Service }}
11+
{{- with .Values.serviceAccount.annotations }}
12+
annotations:
13+
{{ toYaml . | nindent 4 }}
14+
{{- end }}
1115
{{- end }}

helm/betterstack-operator/values.yaml

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,22 @@ image:
33
tag: ""
44
pullPolicy: IfNotPresent
55

6+
imagePullSecrets: []
7+
68
nameOverride: ""
79
fullnameOverride: ""
810

911
namespace: ""
1012

1113
replicaCount: 1
1214

15+
podAnnotations: {}
16+
podLabels: {}
17+
1318
serviceAccount:
1419
create: true
1520
name: ""
21+
annotations: {}
1622

1723
resources:
1824
requests:
@@ -22,9 +28,22 @@ resources:
2228
cpu: 300m
2329
memory: 256Mi
2430

31+
podSecurityContext: {}
32+
33+
containerSecurityContext:
34+
allowPrivilegeEscalation: false
35+
runAsNonRoot: true
36+
runAsUser: 65532
37+
38+
nodeSelector: {}
39+
40+
tolerations: []
41+
42+
affinity: {}
43+
2544
manager:
2645
leaderElection: true
27-
metricsPort: 8443
46+
metricsPort: 8080
2847
healthProbePort: 8081
2948
extraArgs: []
3049

@@ -33,3 +52,12 @@ rbac:
3352

3453
crds:
3554
install: true
55+
56+
credentials:
57+
existingSecret: ""
58+
secret:
59+
create: false
60+
name: ""
61+
key: api-key
62+
value: ""
63+
annotations: {}

0 commit comments

Comments
 (0)