A batteries-included CLI toolkit for day-to-day Kubernetes / OpenShift operations: image mirroring, pod balancing, CNPG database backup & restore, and ImagePullBackOff remediation.
| Command | Description |
|---|---|
shed mirror |
Mirror a container image from any registry to your private registry |
shed backoff |
Detect and scale down deployments stuck in ImagePullBackOff |
shed dump |
Backup all PostgreSQL databases from a CloudNativePG cluster |
shed import |
Restore the latest (or a specific) backup to a CNPG cluster |
shed eq |
Evenly rebalance pod distribution across cluster nodes |
bash≥ 4.xkubectl/oc(OpenShift CLI)docker(formirror)jqbase64
git clone https://github.com/dweis163/shed.git
cd shed
cp config/shed.conf.example config/shed.conf
# Edit config/shed.conf with your valuesOptionally add shed to your PATH:
export PATH="$PATH:/path/to/shed"All project-specific values live in config/shed.conf (gitignored). Copy the example and fill it in:
cp config/shed.conf.example config/shed.conf| Variable | Used by | Description |
|---|---|---|
REGISTRY_HOST |
mirror | Target registry hostname |
REGISTRY_DEFAULT_ORG |
mirror | Default target organization |
OC_API_BASE / OC_API_SLOT / OC_API_SUFFIX |
dump, import | OpenShift API URL template |
K8S_NS_BASE / K8S_NS_SUFFIX |
dump, import | Namespace template |
BACKUP_ROOT |
dump, import | Root directory for database backups |
CNPG_CLUSTER_NAME |
dump, import | Default CNPG cluster name |
CNPG_SECRET_SUFFIX |
dump, import | Suffix for the CNPG app secret |
EQ_TOLERANCE |
eq | Acceptable pod gap between nodes |
EQ_MAX_ITERATIONS |
eq | Max rebalancing cycles |
EQ_SYSTEM_NAMESPACES |
eq | Namespaces excluded from balancing |
Environments are overlays in config/environments/<name>.env. Each file sets ENV_NAME and ENV_LETTER, which are used to derive the API URL and namespace at runtime.
# config/environments/staging.env
ENV_NAME="staging"
ENV_LETTER="s"Adding a new environment is just creating a new .env file — no code changes needed.
shed [--env <name>] [--debug] <command> [command options]shed mirror <source_image> [organization]
shed mirror --dry-run ghcr.io/upstream/app:1.2.3
shed mirror ghcr.io/upstream/app:1.2.3 my-orgshed backoff
shed backoff --namespace my-namespace
shed backoff --dry-run
shed backoff --yes # skip confirmationshed --env prod dump
shed --env test dump --cluster my-cluster
shed --env prod dump --debugBackups are written to $BACKUP_ROOT/<env>/<timestamp>/<database>.sql.
shed --env test import
shed --env test import --yes # skip confirmation
shed --env test import --backup /path/to/backup/dir # specific backup
shed --env prod import --cluster my-clustershed eq
shed eq --dry-run
shed eq --tolerance 2 --max-iterations 5
shed eq --namespace my-appshed/
├── shed # Main CLI entry point
├── lib/
│ ├── colors.sh # ANSI color constants
│ ├── log.sh # log_info/warn/error/debug/step, die, confirm
│ ├── config.sh # config_load, config_load_env, list_environments
│ └── k8s.sh # k8s_login, k8s_cnpg_check, k8s_cnpg_credentials, exec_cmd
├── scripts/
│ ├── mirror.sh
│ ├── backoff.sh
│ ├── dump.sh
│ ├── import.sh
│ └── eq.sh
└── config/
├── shed.conf.example # Template — copy to shed.conf
├── shed.conf # Your config (gitignored)
└── environments/
├── prod.env
└── test.env
Add a new environment: create config/environments/<name>.env with ENV_NAME and ENV_LETTER.
Add a new script: create scripts/<name>.sh, source the libs you need, then add a one-liner case in shed.
Add a new config variable: declare it in config/shed.conf.example with a comment, then reference it in the relevant script.