Skip to content

Commit ab063ab

Browse files
docs: readme (#206)
* docs: ai generated readme * fix(drive-by): update rust version for docker build
1 parent 7affb0b commit ab063ab

2 files changed

Lines changed: 209 additions & 3 deletions

File tree

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Leveraging the pre-built Docker images with
22
# cargo-chef and the Rust toolchain
3-
FROM lukemathwalker/cargo-chef:latest-rust-1.81-bookworm AS chef
3+
FROM lukemathwalker/cargo-chef:latest-rust-1.85-bookworm AS chef
44
WORKDIR app
55

66
FROM chef AS planner

README.md

Lines changed: 208 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,209 @@
1-
# sinker
1+
# Sinker
22

3-
Copy k8s resources (or parts thereof) across clusters.
3+
Sinker is a Kubernetes controller that keeps resources in sync across clusters. It watches `ResourceSync` custom
4+
resources (CRs), reads a source object, then projects it onto a target object—optionally in a different cluster—while
5+
preserving the fields you care about. Sinker keeps watching both ends so that drifts introduced by other actors are
6+
reconciled automatically.
7+
8+
## Features
9+
10+
- Cross-cluster or in-cluster synchronization for any Kubernetes API resource using a single declarative CR.
11+
- JSONPath-based field mappings that let you clone entire objects or copy specific subtrees into the target.
12+
- Safe lifecycle management through finalizers plus explicit per-resource annotations to control deletion behavior
13+
during outages.
14+
- Remote watchers that observe both source and target objects and trigger reconciliations whenever something changes.
15+
- Admin HTTP server exposing readiness and liveness probes (and, via the `kubert` runtime, metrics) so the controller
16+
integrates cleanly with cluster operations tooling.
17+
18+
## Getting Started
19+
20+
### Prerequisites
21+
22+
- Rust toolchain 1.85 or later (see `rust-toolchain.toml`) if you plan to build from source.
23+
- Docker or another OCI-compatible builder to produce a controller image.
24+
- Access to at least one Kubernetes cluster (1.33+) with `kubectl` and the ability to create CRDs, roles, and service
25+
accounts.
26+
- Optional: access credentials for any remote clusters you want Sinker to read from or write to. These must be stored as
27+
Kubernetes secrets containing kubeconfigs such as those created by [CAPI](https://cluster-api.sigs.k8s.io/).
28+
29+
### Build the controller
30+
31+
```bash
32+
git clone https://github.com/influxdata/sinker.git
33+
cd sinker
34+
cargo build --release
35+
```
36+
37+
The compiled binary lives at `target/release/sinker`. To build a container image:
38+
39+
```bash
40+
docker build -t <registry>/<repo>/sinker:<tag> .
41+
docker push <registry>/<repo>/sinker:<tag>
42+
```
43+
44+
### Deploy to Kubernetes
45+
46+
1. **Create an image pull secret** (if needed) in the namespace where Sinker will run, for example:
47+
```bash
48+
kubectl create secret docker-registry gar-auth-sinker \
49+
--docker-server=<registry> \
50+
--docker-username=<username> \
51+
--docker-password=<password> \
52+
--namespace sinker
53+
```
54+
2. **Update the controller image** in `manifests/deployment.yml` (or overlay with Kustomize) to point at the image you
55+
pushed.
56+
3. **Apply the bundled manifests** (CRDs, RBAC, Deployment, ServiceAccount, etc.):
57+
```bash
58+
kubectl apply -k manifests
59+
```
60+
4. **Verify deployment**:
61+
```bash
62+
kubectl -n sinker get pods
63+
kubectl -n sinker logs deploy/sinker
64+
```
65+
5. When the pod is ready, the controller listens on port `8080` for `/live`, `/ready`, and `/metrics` (Prometheus
66+
format) endpoints exposed by the admin server.
67+
68+
### Running locally against a cluster
69+
70+
You can also run the controller directly from your workstation:
71+
72+
```bash
73+
cargo run -- --kubeconfig /path/to/kubeconfig --context my-context
74+
```
75+
76+
Key CLI flags:
77+
78+
- `--log-level` (or `SINKER_LOG`) controls tracing filters (default `sinker=info,warn`).
79+
- `--log-format` selects `plain` or `json`.
80+
- `--kubeconfig`, `--context`, `--cluster`, and `--user` mirror the standard `kubectl` flags for choosing credentials.
81+
- `--as` and `--as-group` let you impersonate another Kubernetes user or group.
82+
- `--kube-api-response-headers-timeout` configures the Kubernetes client timeout (default `9s`).
83+
- `--admin-addr` sets the admin HTTP server bind address (default `0.0.0.0:8080`).
84+
85+
## Defining resource syncs
86+
87+
Sinker ships two custom resources:
88+
89+
### ResourceSync
90+
91+
`ResourceSync` objects describe how to mirror a Kubernetes resource.
92+
93+
| Field | Required | Description |
94+
|---------------------------|----------|-------------------------------------------------------------------------------------------------------------------------------------|
95+
| `spec.source.resourceRef` || API reference (`apiVersion`, `kind`, `name`) pointing to the object you want to copy. |
96+
| `spec.source.cluster` | | Optional remote cluster reference. When omitted, Sinker reads the source from the same cluster and namespace as the `ResourceSync`. |
97+
| `spec.target.resourceRef` || API reference for the target object. |
98+
| `spec.target.cluster` | | Optional remote cluster reference. When omitted, the target lives in the same cluster as the `ResourceSync`. |
99+
| `spec.mappings[]` | | Optional list of field mapping rules. See below. |
100+
101+
#### Cluster references
102+
103+
When you provide `spec.{source|target}.cluster`, Sinker reads a kubeconfig from a secret to talk to the remote cluster:
104+
105+
```yaml
106+
cluster:
107+
namespace: other-namespace # optional override; defaults to the Remote kubeconfig's namespace
108+
kubeConfig:
109+
secretRef:
110+
name: remote-kubeconfig
111+
key: value
112+
```
113+
114+
Create the secret by embedding a standard kubeconfig:
115+
116+
```bash
117+
kubectl -n <ns> create secret generic remote-kubeconfig \
118+
--from-file=value=/path/to/kubeconfig
119+
```
120+
121+
Within the remote cluster, RBAC for the kubeconfig user limits what Sinker can access. For local clusters, Sinker uses
122+
its in-cluster credentials.
123+
124+
#### Mappings
125+
126+
- When `spec.mappings` is empty, Sinker clones the entire source object, copying annotations and labels while cleaning
127+
the `kubectl.kubernetes.io/last-applied-configuration` annotation.
128+
- When mappings are supplied, each mapping entry has `fromFieldPath` and/or `toFieldPath`:
129+
- `fromFieldPath` is a JSONPath evaluated against the source. Use `spec.data.someField` to copy a nested field, or
130+
leave it blank/omit it to select the entire object.
131+
- `toFieldPath` is a JSONPath-like dotted path inside the target (`metadata.*` and `spec|status|data` are
132+
supported). Omit `toFieldPath` to replace the entire target with the selected subtree.
133+
- Sinker enforces that at least one of the fields is present per mapping. If `toFieldPath` targets `metadata`, the
134+
controller keeps metadata in sync using server-side apply.
135+
136+
Example `ResourceSync`:
137+
138+
```yaml
139+
apiVersion: sinker.influxdata.io/v1alpha1
140+
kind: ResourceSync
141+
metadata:
142+
name: demo
143+
namespace: default
144+
spec:
145+
source:
146+
resourceRef:
147+
apiVersion: v1
148+
kind: ConfigMap
149+
name: remote-demo
150+
cluster:
151+
namespace: default
152+
kubeConfig:
153+
secretRef:
154+
name: k3-test-27-kubeconfig
155+
key: value
156+
target:
157+
resourceRef:
158+
apiVersion: v1
159+
kind: ConfigMap
160+
name: demo
161+
mappings:
162+
- fromFieldPath: data.remote
163+
toFieldPath: data.remote
164+
- fromFieldPath: data.foo
165+
toFieldPath: data.bar
166+
```
167+
168+
### SinkerContainer
169+
170+
`SinkerContainer` is a lightweight CRD that stores arbitrary structured data under `.spec`. Use it as either a source or
171+
target when you want Sinker to materialize generated configuration into a typed CR (for example, to copy an inner spec
172+
from one object into another).
173+
174+
## Annotations and finalizers
175+
176+
Sinker adds a finalizer (`sinker.influxdata.io/target`) to each `ResourceSync` so it can clean up target objects when
177+
the CR is deleted. Two optional annotations modify that behavior:
178+
179+
- `sinker.influxdata.io/force-delete: "true"` – if set and the controller cannot contact a remote cluster while
180+
deleting, Sinker removes its finalizer so the `ResourceSync` can be garbage-collected.
181+
- `sinker.influxdata.io/disable-target-deletion: "true"` – skip deleting the target object when the `ResourceSync` is
182+
removed. Useful when you want to manage the target lifecycle manually.
183+
184+
## Status and observability
185+
186+
- Sinker publishes a `ResourceSyncFailing` condition in `.status.conditions[]` with timestamps, reasons, and messages if
187+
reconciliation fails.
188+
- Logs use the standard `tracing` crate; adjust verbosity with `SINKER_LOG`.
189+
- The admin server exposes `/live`, `/ready`, and `/metrics` on port 8080. Wire these into your cluster’s probes and
190+
monitoring.
191+
- Remote watchers reconcile whenever the source or target resource changes, even on remote clusters, which keeps
192+
synchronized objects fresh with minimal polling.
193+
194+
## Generating CRDs programmatically
195+
196+
To print the latest CRDs (e.g., for Helm packaging), use the built-in command:
197+
198+
```bash
199+
cargo run -- manifests > out.yml
200+
```
201+
202+
The output includes both `ResourceSync` and `SinkerContainer` definitions.
203+
204+
## Development notes
205+
206+
- Format and lint with `cargo fmt` and `cargo clippy --all-targets --all-features`.
207+
- Run tests with `cargo test`.
208+
- When developing new features, update `manifests` or regenerate CRDs via `sinker manifests` before deploying.
209+
- The project uses MIT licensing; see `LICENSE` for details.

0 commit comments

Comments
 (0)