Skip to content

Commit 70cbf3d

Browse files
committed
Initial commit
0 parents  commit 70cbf3d

12 files changed

Lines changed: 1319 additions & 0 deletions

File tree

.github/workflows/ci.yaml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
push:
7+
branches: [main]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v6
14+
15+
- name: Set up Go
16+
uses: actions/setup-go@v6
17+
with:
18+
go-version-file: go.mod
19+
20+
- name: Vet
21+
run: make vet
22+
23+
- name: Test
24+
run: make test
25+
26+
- name: Build
27+
run: make build
28+
29+
docker:
30+
runs-on: ubuntu-latest
31+
steps:
32+
- uses: actions/checkout@v6
33+
34+
- name: Build Docker image
35+
run: docker build -t node-taint-controller:ci .

.github/workflows/release.yaml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v[0-9]+.[0-9]+.[0-9]+'
7+
8+
env:
9+
REGISTRY: ghcr.io
10+
IMAGE_NAME: ${{ github.repository }}
11+
12+
jobs:
13+
release:
14+
runs-on: ubuntu-latest
15+
permissions:
16+
contents: write
17+
packages: write
18+
19+
steps:
20+
- uses: actions/checkout@v6
21+
22+
- name: Set up Go
23+
uses: actions/setup-go@v6
24+
with:
25+
go-version-file: go.mod
26+
27+
- name: Run tests
28+
run: go test -v ./...
29+
30+
- name: Log in to GitHub Container Registry
31+
uses: docker/login-action@v3
32+
with:
33+
registry: ${{ env.REGISTRY }}
34+
username: ${{ github.actor }}
35+
password: ${{ secrets.GITHUB_TOKEN }}
36+
37+
- name: Extract metadata for Docker
38+
id: meta
39+
uses: docker/metadata-action@v5
40+
with:
41+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
42+
tags: |
43+
type=semver,pattern={{version}}
44+
type=semver,pattern={{major}}.{{minor}}
45+
type=semver,pattern={{major}}
46+
47+
- name: Build and push Docker image
48+
uses: docker/build-push-action@v6
49+
with:
50+
context: .
51+
push: true
52+
tags: ${{ steps.meta.outputs.tags }}
53+
labels: ${{ steps.meta.outputs.labels }}
54+
55+
- name: Create GitHub Release
56+
uses: softprops/action-gh-release@v2
57+
with:
58+
generate_release_notes: true

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/controller
2+
/manifest.yaml
3+
/.idea

Dockerfile

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
FROM golang:1.25-alpine AS builder
2+
3+
WORKDIR /app
4+
COPY go.mod go.sum ./
5+
RUN go mod download
6+
7+
COPY *.go ./
8+
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o controller .
9+
10+
FROM gcr.io/distroless/static:nonroot
11+
WORKDIR /
12+
COPY --from=builder /app/controller .
13+
USER 65532:65532
14+
15+
ENTRYPOINT ["/controller"]

Makefile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
build:
2+
go build -o controller
3+
4+
test:
5+
go test -race -v ./...
6+
7+
vet:
8+
go vet ./...
9+
10+
.PHONY: build test vet

README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# node-taint-controller
2+
3+
A Kubernetes controller that applies the `node.kubernetes.io/out-of-service` taint to nodes that have been `NotReady` for a specified duration.
4+
5+
Useful when a node suddenly goes offline due to power outage etc. and needs to be quickly identified and removed from the cluster to prevent pods from being stuck in `Terminating` state.
6+
7+
## Installation
8+
9+
Images are available at `ghcr.io/dcelasun/node-taint-controller`.
10+
11+
Copy the manifest and customize it to your needs:
12+
```sh
13+
$ cp manifest.example.yaml manifest.yaml
14+
# Edit manifest.yaml to adjust thresholds, replicas, etc.
15+
$ kubectl apply -f manifest.yaml
16+
```
17+
18+
## Configuration
19+
20+
```sh
21+
$ make build
22+
$ ./controller --help
23+
Usage of ./controller:
24+
-health-probe-bind-address string
25+
The address the probe endpoint binds to. (default ":8081")
26+
-kubeconfig string
27+
Paths to a kubeconfig. Only required if out-of-cluster.
28+
-leader-election-id string
29+
The ID of the leader election. (default "node-taint-controller.example.com")
30+
-metrics-bind-address string
31+
The address the metric endpoint binds to. (default ":8080")
32+
-not-ready-threshold duration
33+
Duration a node must be NotReady before tainting. (default 5m0s)
34+
-reconcile-interval duration
35+
How often to re-check node status. (default 30s)
36+
-zap-devel
37+
Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn). Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error)
38+
-zap-encoder value
39+
Zap log encoding (one of 'json' or 'console')
40+
-zap-log-level value
41+
Zap Level to configure the verbosity of logging. Can be one of 'debug', 'info', 'error', 'panic'or any integer value > 0 which corresponds to custom debug levels of increasing verbosity
42+
-zap-stacktrace-level value
43+
Zap Level at and above which stacktraces are captured (one of 'info', 'error', 'panic').
44+
-zap-time-encoding value
45+
Zap time encoding (one of 'epoch', 'millis', 'nano', 'iso8601', 'rfc3339' or 'rfc3339nano'). Defaults to 'epoch'.
46+
47+
```

go.mod

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
module github.com/dcelasun/node-taint-controller
2+
3+
go 1.25.6
4+
5+
require (
6+
k8s.io/api v0.35.0
7+
k8s.io/apimachinery v0.35.0
8+
k8s.io/client-go v0.35.0
9+
sigs.k8s.io/controller-runtime v0.22.4
10+
)
11+
12+
require (
13+
github.com/beorn7/perks v1.0.1 // indirect
14+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
15+
github.com/davecgh/go-spew v1.1.1 // indirect
16+
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
17+
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
18+
github.com/fsnotify/fsnotify v1.9.0 // indirect
19+
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
20+
github.com/go-logr/logr v1.4.3 // indirect
21+
github.com/go-logr/zapr v1.3.0 // indirect
22+
github.com/go-openapi/jsonpointer v0.22.4 // indirect
23+
github.com/go-openapi/jsonreference v0.21.4 // indirect
24+
github.com/go-openapi/swag v0.25.4 // indirect
25+
github.com/go-openapi/swag/cmdutils v0.25.4 // indirect
26+
github.com/go-openapi/swag/conv v0.25.4 // indirect
27+
github.com/go-openapi/swag/fileutils v0.25.4 // indirect
28+
github.com/go-openapi/swag/jsonname v0.25.4 // indirect
29+
github.com/go-openapi/swag/jsonutils v0.25.4 // indirect
30+
github.com/go-openapi/swag/loading v0.25.4 // indirect
31+
github.com/go-openapi/swag/mangling v0.25.4 // indirect
32+
github.com/go-openapi/swag/netutils v0.25.4 // indirect
33+
github.com/go-openapi/swag/stringutils v0.25.4 // indirect
34+
github.com/go-openapi/swag/typeutils v0.25.4 // indirect
35+
github.com/go-openapi/swag/yamlutils v0.25.4 // indirect
36+
github.com/gogo/protobuf v1.3.2 // indirect
37+
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
38+
github.com/golang/protobuf v1.5.4 // indirect
39+
github.com/google/btree v1.1.3 // indirect
40+
github.com/google/gnostic-models v0.7.1 // indirect
41+
github.com/google/go-cmp v0.7.0 // indirect
42+
github.com/google/gofuzz v1.2.0 // indirect
43+
github.com/google/uuid v1.6.0 // indirect
44+
github.com/imdario/mergo v0.3.16 // indirect
45+
github.com/josharian/intern v1.0.0 // indirect
46+
github.com/json-iterator/go v1.1.12 // indirect
47+
github.com/mailru/easyjson v0.9.1 // indirect
48+
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
49+
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
50+
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
51+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
52+
github.com/pkg/errors v0.9.1 // indirect
53+
github.com/pmezard/go-difflib v1.0.0 // indirect
54+
github.com/prometheus/client_golang v1.23.2 // indirect
55+
github.com/prometheus/client_model v0.6.2 // indirect
56+
github.com/prometheus/common v0.67.5 // indirect
57+
github.com/prometheus/procfs v0.19.2 // indirect
58+
github.com/spf13/pflag v1.0.10 // indirect
59+
github.com/x448/float16 v0.8.4 // indirect
60+
go.uber.org/multierr v1.11.0 // indirect
61+
go.uber.org/zap v1.27.1 // indirect
62+
go.yaml.in/yaml/v2 v2.4.3 // indirect
63+
go.yaml.in/yaml/v3 v3.0.4 // indirect
64+
golang.org/x/exp v0.0.0-20260112195511-716be5621a96 // indirect
65+
golang.org/x/net v0.49.0 // indirect
66+
golang.org/x/oauth2 v0.34.0 // indirect
67+
golang.org/x/sync v0.19.0 // indirect
68+
golang.org/x/sys v0.40.0 // indirect
69+
golang.org/x/term v0.39.0 // indirect
70+
golang.org/x/text v0.33.0 // indirect
71+
golang.org/x/time v0.14.0 // indirect
72+
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
73+
google.golang.org/appengine v1.6.8 // indirect
74+
google.golang.org/protobuf v1.36.11 // indirect
75+
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
76+
gopkg.in/inf.v0 v0.9.1 // indirect
77+
gopkg.in/yaml.v2 v2.4.0 // indirect
78+
gopkg.in/yaml.v3 v3.0.1 // indirect
79+
k8s.io/apiextensions-apiserver v0.35.0 // indirect
80+
k8s.io/component-base v0.35.0 // indirect
81+
k8s.io/klog/v2 v2.130.1 // indirect
82+
k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e // indirect
83+
k8s.io/utils v0.0.0-20260108192941-914a6e750570 // indirect
84+
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
85+
sigs.k8s.io/randfill v1.0.0 // indirect
86+
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
87+
sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect
88+
sigs.k8s.io/yaml v1.6.0 // indirect
89+
)

0 commit comments

Comments
 (0)