Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/bin
**/charts
**/docker-compose*
**/compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
44 changes: 44 additions & 0 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: "Security Scan"

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
schedule:
- cron: '0 0 * * 0' # Run weekly

jobs:
security:
name: Security Scan
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Run Gosec Security Scanner
uses: securego/gosec@master
with:
args: ./...

analyze:
name: CodeQL Analysis
runs-on: ubuntu-latest
permissions:
security-events: write
actions: read
contents: read

steps:
- uses: actions/checkout@v3

- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: go

- name: Build Go Code
run: go build ./...

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
46 changes: 46 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Test

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
test:
name: Run Tests
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.20'
check-latest: true

- name: Install dependencies
run: go mod download

- name: Run tests
run: go test -v ./...

- name: Build binary
run: go build -v ./...

- name: Run golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: latest
args: --timeout=5m

- name: Run basic checks
run: |
go vet ./...
if [ -z "$(go fmt ./...)" ]; then
echo "Code is formatted correctly"
else
echo "Code is not formatted correctly"
exit 1
fi
15 changes: 15 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#build stage
FROM golang:alpine AS builder
RUN apk add --no-cache git
WORKDIR /go/src/app
COPY . .
RUN go get -d -v ./...
RUN go build -o /go/bin/app -v ./...

#final stage
FROM alpine:latest
RUN apk --no-cache add ca-certificates
COPY --from=builder /go/bin/app /app
ENTRYPOINT /app
LABEL Name=nodesafedrainer Version=0.0.1
EXPOSE 3000
47 changes: 29 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# Node Safe Drainer

[![Tests](https://github.com/angelabad/node-safe-drainer/actions/workflows/test.yml/badge.svg)](https://github.com/angelabad/node-safe-drainer/actions/workflows/test.yml)
[![Security Scan](https://github.com/angelabad/node-safe-drainer/actions/workflows/security.yml/badge.svg)](https://github.com/angelabad/node-safe-drainer/actions/workflows/security.yml)

# Warning

This repository contains experimental code. Use it at your own risk!

# Node Safe Drainer

Tool to safely drain Kubernetes nodes.

## The problem
Expand Down Expand Up @@ -40,38 +43,46 @@ Download binary from [relases](https://github.com/angelabad/node-safe-drainer/re

### Source code

```bash
git clone git@github.com:angelabad/node-safe-drainer.git
cd node-safe-dainer
go build
```
$ git clone git@github.com:angelabad/node-safe-drainer.git
$ cd node-safe-dainer
$ go build

### Docker (recommended)

```powershell
# Build and run tests
.\build-and-test.ps1

# Run the application (mounts your kubeconfig)
.\run-in-docker.ps1 -ExtraArgs "--kubeconfig /root/.kube/config --max-jobs 5"
```

See [README_DOCKER.md](README_DOCKER.md) for Docker setup details.

## Usage

```
```shell
usage: ./node-safe-drainer [OPTIONS] <COMMA_SEPPARATED_NODE_NAMES>

Simple tool for safe draining nodes, rolling out deployments without downtime.

Options:
-all-nodes
cordon and empty all nodes (use with caution)
-kubeconfig string
abslute path to the kubeconfig file (default "/home/angel/.kube/config")
-max-jobs int
max concurrent rollouts. (default 10)
-timeout duration
deployment rollouts timeout. (default 20m0s)
-all-nodes cordon and empty all nodes (use with caution)
-kubeconfig str absolute path to the kubeconfig file (default "/home/angel/.kube/config")
-max-jobs int max concurrent rollouts (default 10)
-timeout duration deployment rollouts timeout (default 20m0s)
```

### For all nodes on cluster

```
$ ./node-safe-drainer -all-nodes
```shell
./node-safe-drainer -all-nodes
```

### For custom nodes

```
$ ./node-safe-drainer k3d-k3s-default-server-0,k3d-k3s-default-agent-0
```shell
./node-safe-drainer k3d-k3s-default-server-0,k3d-k3s-default-agent-0
```
19 changes: 19 additions & 0 deletions README_DOCKER.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
This repository includes a small Docker setup so you can run tests and the application without installing Go locally.

Quick steps (Windows PowerShell / pwsh):

1. Build the Docker image and run tests:

```powershell
.\build-and-test.ps1
```

2. Run the application and mount your kubeconfig (read-only):

```powershell
.\run-in-docker.ps1 -ExtraArgs "--kubeconfig /root/.kube/config --max-jobs 5"
```

Notes:
- The Docker image uses `golang:1.20-alpine` and will download modules defined in `go.mod`.
- If Docker isn't available on your machine, you can still install Go from https://go.dev/dl/ and run locally.
9 changes: 9 additions & 0 deletions build-and-test.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
param(
[string]$ImageName = "node-safe-drainer:test"
)

Write-Host "Building Docker image $ImageName..."
docker build -t $ImageName .

Write-Host "Running tests inside container..."
docker run --rm $ImageName
8 changes: 8 additions & 0 deletions compose.debug.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
services:
nodesafedrainer:
image: nodesafedrainer
build:
context: .
dockerfile: ./Dockerfile
ports:
- 3000:3000
8 changes: 8 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
services:
nodesafedrainer:
image: nodesafedrainer
build:
context: .
dockerfile: ./Dockerfile
ports:
- 3000:3000
17 changes: 17 additions & 0 deletions run-in-docker.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
param(
[string]$ImageName = "node-safe-drainer:test",
[string]$KubeconfigPath = "$env:USERPROFILE\.kube\config",
[string]$ExtraArgs = ""
)

if (-not (Test-Path $KubeconfigPath)) {
Write-Host "Kubeconfig not found at $KubeconfigPath. You can pass a path with -KubeconfigPath"
}

$mount = ""
if (Test-Path $KubeconfigPath) {
$mount = "-v ${KubeconfigPath}:/root/.kube/config:ro"
}

Write-Host "Running container (will use kubeconfig: $KubeconfigPath)..."
docker run --rm $mount -it $ImageName sh -c "go run main.go $ExtraArgs"