Skip to content

Commit d49add3

Browse files
first commit, me and Copilot was very productive
0 parents  commit d49add3

11 files changed

Lines changed: 1264 additions & 0 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*~
2+
/deployment-tracker

Dockerfile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# 1.25.5-alpine3.23
2+
FROM golang@sha256:26111811bc967321e7b6f852e914d14bede324cd1accb7f81811929a6a57fea9 AS builder
3+
4+
WORKDIR /app
5+
COPY go.mod go.sum ./
6+
RUN go mod download
7+
COPY . .
8+
RUN CGO_ENABLED=0 GOOS=linux go build -o deployment-tracker cmd/deployment-tracker/main.go
9+
10+
# v3.23
11+
FROM alpine@sha256:51183f2cfa6320055da30872f211093f9ff1d3cf06f39a0bdb212314c5dc7375
12+
RUN apk --no-cache add ca-certificates
13+
COPY --from=builder /app/deployment-tracker /deployment-tracker
14+
ENTRYPOINT ["/deployment-tracker"]

Makefile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
REPOSITORY ?= deployment-tracker
2+
TAG ?= latest
3+
IMG := $(REPOSITORY):$(TAG)
4+
CLUSTER = kind
5+
6+
.PHONY: build
7+
build:
8+
go build -o deployment-tracker cmd/deployment-tracker/main.go
9+
10+
.PHONY: docker
11+
docker:
12+
docker build --platform linux/arm64 -t ${IMG} .
13+
14+
.PHONY: kind-load-image
15+
kind-load-image:
16+
kind load docker-image ${IMG} --name ${CLUSTER}
17+
18+
fmt:
19+
go fmt ./...
20+
21+
test:
22+
go test ./...

README.md

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
# Deployment Tracker
2+
3+
A Kubernetes controller that monitors pod lifecycles and uploads
4+
deployment records to GitHub's artifact metadata API.
5+
6+
## Features
7+
8+
- **Informer-based controller**: Uses Kubernetes SharedInformers for
9+
efficient, reliable pod watching
10+
- **Work queue with retries**: Rate-limited work queue with automatic
11+
retries on failure
12+
- **Real-time tracking**: Sends deployment records when pods are
13+
created or deleted
14+
- **Graceful shutdown**: Properly drains work queue before terminating
15+
16+
## How It Works
17+
18+
1. The controller watches for pod events using a Kubernetes
19+
SharedInformer
20+
2. When a pod becomes Running, a `CREATED` event is queued
21+
3. When a pod is deleted, a `DELETED` event is queued
22+
4. Worker goroutines process events and POST deployment records to the
23+
API
24+
5. Failed requests are automatically retried with exponential backoff
25+
26+
## Building
27+
28+
```bash
29+
go build -o deployment-tracker .
30+
```
31+
32+
## Usage
33+
34+
### Local Development (with kubeconfig)
35+
36+
```bash
37+
# Monitor all namespaces
38+
./deployment-tracker -kubeconfig ~/.kube/config
39+
40+
# Monitor specific namespace
41+
./deployment-tracker -kubeconfig ~/.kube/config -namespace default
42+
43+
# Use more workers
44+
./deployment-tracker -kubeconfig ~/.kube/config -workers 4
45+
```
46+
47+
### In-Cluster Deployment
48+
49+
When running inside Kubernetes, the controller automatically uses
50+
in-cluster configuration:
51+
52+
```bash
53+
./deployment-tracker
54+
```
55+
56+
## Command Line Options
57+
58+
| Flag | Description | Default |
59+
|---------------|--------------------------------------|--------------------------------------------|
60+
| `-kubeconfig` | Path to kubeconfig file | Uses in-cluster config or `~/.kube/config` |
61+
| `-namespace` | Namespace to monitor (empty for all) | `""` (all namespaces) |
62+
| `-workers` | Number of worker goroutines | `2` |
63+
64+
## Environment Variables
65+
66+
| Variable | Description | Default |
67+
|------------------------|---------------------------|------------------------------------------------------|
68+
| `ORG` | GitHub organization name | (required) |
69+
| `BASE_URL` | API base URL | `api.github.com` |
70+
| `DN_TEMPLATE` | Deployment name template | `{{namespace}}/{{deploymentName}}/{{containerName}}` |
71+
| `LOGICAL_ENVIRONMENT` | Logical environment name | `""` |
72+
| `PHYSICAL_ENVIRONMENT` | Physical environment name | `""` |
73+
| `CLUSTER` | Cluster name | `""` |
74+
| `API_TOKEN` | API authentication token | `""` |
75+
76+
### Template Variables
77+
78+
The `DN_TEMPLATE` supports the following placeholders:
79+
- `{{namespace}}` - Pod namespace
80+
- `{{deploymentName}}` - Name of the owning Deployment
81+
- `{{containerName}}` - Container name
82+
83+
## Output Format
84+
85+
```
86+
[2024-01-15T10:30:00Z] OK CREATED name=nginx deployment_name=default/nginx/nginx digest=sha256:abc123... status=deployed
87+
[2024-01-15T10:30:10Z] OK DELETED name=nginx deployment_name=default/nginx/nginx digest=sha256:abc123... status=decommissioned
88+
[2024-01-15T10:30:15Z] FAILED CREATED name=myapp deployment_name=default/myapp/app error=connection refused
89+
```
90+
91+
## Kubernetes Deployment
92+
93+
A complete deployment manifest is provided in `deploy/manifest.yaml`
94+
which includes:
95+
96+
- **Namespace**: `deployment-tracker`
97+
- **ServiceAccount**: Identity for the controller pod
98+
- **ClusterRole**: Minimal permissions (`get`, `list`, `watch` on pods)
99+
- **ClusterRoleBinding**: Binds the ServiceAccount to the ClusterRole
100+
- **Deployment**: Runs the controller with security hardening
101+
102+
### Deploy to Kubernetes
103+
104+
```bash
105+
# Build and push the container image
106+
docker build -t your-registry/deployment-tracker:latest .
107+
docker push your-registry/deployment-tracker:latest
108+
109+
# Update the image in the manifest, then apply
110+
kubectl apply -f deploy/manifest.yaml
111+
```
112+
113+
### View Logs
114+
115+
```bash
116+
# Follow logs from the controller
117+
kubectl logs -f -n deployment-tracker deployment/deployment-tracker
118+
119+
# View recent logs
120+
kubectl logs -n deployment-tracker deployment/deployment-tracker --tail=100
121+
```
122+
123+
### Verify Deployment
124+
125+
```bash
126+
# Check the deployment status
127+
kubectl get deployment -n deployment-tracker
128+
129+
# Check the pod is running
130+
kubectl get pods -n deployment-tracker
131+
132+
# Verify RBAC permissions
133+
kubectl auth can-i list pods --as=system:serviceaccount:deployment-tracker:deployment-tracker
134+
```
135+
136+
### Uninstall
137+
138+
```bash
139+
kubectl delete -f deploy/manifest.yaml
140+
```
141+
142+
## RBAC Permissions
143+
144+
The controller requires the following minimum permissions:
145+
146+
| API Group | Resource | Verbs |
147+
|-----------|----------|-------|
148+
| `""` (core) | `pods` | `get`, `list`, `watch` |
149+
150+
If you only need to monitor a single namespace, you can modify the manifest to use a `Role` and `RoleBinding` instead of `ClusterRole` and `ClusterRoleBinding` for more restricted permissions.
151+
152+
## Architecture
153+
154+
```
155+
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
156+
│ Kubernetes │ │ Controller │ │ GitHub API │
157+
│ API Server │────▶│ │────▶│ │
158+
│ │ │ ┌───────────┐ │ │ /orgs/{org}/ │
159+
│ Pod Events │ │ │ Informer │ │ │ artifacts/ │
160+
│ - Add │ │ └─────┬─────┘ │ │ metadata/ │
161+
│ - Update │ │ │ │ │ deployment- │
162+
│ - Delete │ │ ┌─────▼─────┐ │ │ record │
163+
│ │ │ │ Workqueue │ │ │ │
164+
│ │ │ └─────┬─────┘ │ │ │
165+
│ │ │ │ │ │ │
166+
│ │ │ ┌─────▼─────┐ │ │ │
167+
│ │ │ │ Workers │──┼────▶│ │
168+
│ │ │ └───────────┘ │ │ │
169+
└─────────────────┘ └─────────────────┘ └─────────────────┘
170+
```
171+
172+
## API Payload
173+
174+
The controller POSTs JSON payloads to `{BASE_URL}/orgs/{ORG}/artifacts/metadata/deployment-record`:
175+
176+
```json
177+
{
178+
"name": "nginx",
179+
"digest": "sha256:abc123...",
180+
"version": "1.21",
181+
"logical_environment": "staging",
182+
"physical_environment": "us-east-1",
183+
"cluster": "prod-cluster",
184+
"status": "deployed",
185+
"deployment_name": "default/nginx/nginx"
186+
}
187+
```
188+
189+
The `status` field is either `deployed` (for pod creation) or `decommissioned` (for pod deletion).

0 commit comments

Comments
 (0)