diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index c06c026..3b7ff56 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -1,26 +1,18 @@ name: Docker build and push + on: push: tags: - "v*" branches: + - "master" - "release/*" + pull_request: + branches: + - "master" jobs: - cache: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Cache Docker layers - uses: actions/cache@v2 - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-docker-${{ hashFiles('**/Dockerfile') }} - docker: - needs: cache runs-on: ubuntu-latest environment: ci permissions: @@ -31,13 +23,34 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 + - name: Docker metadata setup + id: meta + uses: docker/metadata-action@v4 + with: + images: | + ghcr.io/donkeyx/cluster-utils + docker.io/donkeyx/cluster-utils + tags: | + type=sha + type=ref,event=branch + type=semver,pattern={{version}} + type=semver,pattern={{major}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=latest,enable={{is_default_branch}} + - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 + # with: + # driver-opts: | + # image=moby/buildkit:v0.15.0 + # buildkitd-flags: --debug + - name: Login to Docker Hub + if: github.event_name != 'pull_request' && vars.DOCKERHUB_USERNAME != '' uses: docker/login-action@v3 with: username: ${{ vars.DOCKERHUB_USERNAME }} @@ -50,38 +63,24 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Docker meta (GHCR) - id: meta - uses: docker/metadata-action@v4 - with: - images: | - ghcr.io/donkeyx/cluster-utils - docker.io/donkeyx/cluster-utils - tags: | - type=sha - type=ref,event=branch - type=semver,pattern={{version}} - type=semver,pattern={{major}} - type=semver,pattern={{major}}.{{minor}} - branches: | - release/* - - - name: Debug Metadata Outputs - run: | - echo "Tags: ${{ steps.meta.outputs.tags }}" - echo "Labels: ${{ steps.meta.outputs.labels }}" - echo "Images: ${{ steps.meta.outputs.images }}" - echo "Meta Outputs: ${{ toJson(steps.meta.outputs) }}" - - - name: Build and push - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . platforms: linux/amd64,linux/arm64 push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} - build-args: VERSION=${{ env.VERSION }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache + cache-from: type=gha + cache-to: type=gha,mode=max + provenance: false + sbom: false + + - name: Update DockerHub README + if: github.event_name != 'pull_request' && vars.DOCKERHUB_USERNAME != '' + uses: peter-evans/dockerhub-description@v4 + with: + username: ${{ vars.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + repository: donkeyx/cluster-utils + readme-filepath: ./README.md \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c0d8b49..f83a313 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,12 +1,6 @@ name: Release on: - workflow_run: - workflows: ["Docker build and push"] - tags: [ 'v*.*.*' ] - types: - - completed - push: tags: [ 'v*.*.*' ] @@ -28,11 +22,15 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # ################################ - # create release and push assets - # ################################ + # create release and push assets + # ################################ + - name: Verify Docker build + if: startsWith(github.ref, 'refs/tags/') + run: | + docker build -t cluster-utils:release-test . - name: Release to github with Notes uses: softprops/action-gh-release@v1 diff --git a/Changelog.md b/Changelog.md new file mode 100644 index 0000000..76efee6 --- /dev/null +++ b/Changelog.md @@ -0,0 +1,19 @@ +# Changelog + +## [3.0.0] - 2025-10-08 +### Added +- 🐴 ASCII donkey mascot with colorized welcome message +- Auto-updating k6 load testing tool (fetches latest version) +- Zsh as default shell with Oh My Zsh configuration +- Multi-shell auto-switching capability + +### Changed +- **BREAKING**: Converted from Job to Deployment for continuous operation +- Replaced vegeta with k6 for modern load testing +- Optimized Docker layers for smaller image size (~220MB) +- Enhanced README with comprehensive usage examples + +### Removed +- All timeout configurations (RUNTIME env, ttlSecondsAfterFinished) +- MongoDB tools (reduced bloat) +- Separate kickstart.sh script (consolidated into Dockerfile) \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 0f6a84f..a3eb593 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,31 +1,58 @@ -FROM debian:bookworm-slim - -# Metadata -ARG VERSION=latest -LABEL maintainer="David Binney " -LABEL version=$VERSION -LABEL description="This is a utility for testing within cluster or networks and not needing to install tooling" +FROM alpine:latest ENV TZ="Australia/Adelaide" WORKDIR /app -COPY ./*.sh /app/ - -# Update and install all required tools in one RUN command to minimize layers -RUN apt-get update && apt-get install -y --no-install-recommends \ - dnsutils netcat-openbsd curl wget tar gnupg vim tmux zsh \ - postgresql-client redis-tools git golang nodejs npm && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* - -# Uncomment and modify the MongoDB tools installation if needed -# RUN curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | gpg --dearmor -o /usr/share/keyrings/mongodb-server-7.0.gpg && \ -# echo "deb [signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg] http://repo.mongodb.org/apt/debian bookworm/mongodb-org/7.0 main" | tee /etc/apt/sources.list.d/mongodb-org-7.0.list && \ -# apt-get update && apt-get install -y --no-install-recommends mongodb-org-tools && \ -# apt-get clean && \ -# rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* - -RUN ./kickstart.sh +# Copy scripts +COPY sleeper.sh /app/runner.sh +COPY welcome.sh /app/welcome.sh + +# Install packages, setup tools, and cleanup in a single layer +RUN set -eux && \ + # Install system packages + apk add --no-cache \ + bind-tools \ + netcat-openbsd \ + curl \ + wget \ + git \ + jq \ + vim \ + tmux \ + zsh \ + postgresql-client \ + redis \ + npm \ + tar && \ + # Install oh-my-zsh + sh -c "$(wget -O- https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)" && \ + # Install k6 (lighter than vegeta) - always get the latest version + K6_VERSION=$(curl -s https://api.github.com/repos/grafana/k6/releases/latest | jq -r '.tag_name') && \ + curl -sS -L https://github.com/grafana/k6/releases/download/${K6_VERSION}/k6-${K6_VERSION}-linux-amd64.tar.gz | tar -xz --strip-components=1 && \ + mv k6 /usr/local/bin/ && \ + # Make scripts executable and configure welcome message + chmod +x /app/runner.sh /app/welcome.sh && \ + echo "# Show welcome message on interactive shell login" >> /root/.zshrc && \ + echo "if [[ \$- == *i* ]] && [[ -z \$WELCOME_SHOWN ]]; then" >> /root/.zshrc && \ + echo " export WELCOME_SHOWN=1" >> /root/.zshrc && \ + echo " /app/welcome.sh" >> /root/.zshrc && \ + echo "fi" >> /root/.zshrc && \ + # Set zsh as the default shell for root user in multiple ways for compatibility + sed -i 's|root:.*:/bin/.*sh|root:x:0:0:root:/root:/bin/zsh|g' /etc/passwd && \ + # Also set SHELL environment variable as fallback + echo 'export SHELL=/bin/zsh' >> /root/.profile && \ + echo 'export SHELL=/bin/zsh' >> /root/.zshrc && \ + # Create a .profile that auto-switches to zsh if we're in an interactive session with sh/ash + echo '# Auto-switch to zsh if in interactive mode and not already in zsh' >> /root/.profile && \ + echo 'if [ -t 0 ] && [ "$0" != "/bin/zsh" ] && [ "$0" != "zsh" ] && [ -z "$ZSH_SWITCHED" ]; then' >> /root/.profile && \ + echo ' export ZSH_SWITCHED=1' >> /root/.profile && \ + echo ' exec /bin/zsh' >> /root/.profile && \ + echo 'fi' >> /root/.profile && \ + # Make sure .profile is sourced by ash/sh + ln -sf /root/.profile /root/.ashrc && \ + # Cleanup to reduce image size + rm -rf /var/cache/apk/* /tmp/* /root/.oh-my-zsh/.git + +ENTRYPOINT ["sh", "/app/runner.sh"] -ENTRYPOINT ["zsh", "/app/sleeper.sh"] diff --git a/README.md b/README.md index f8b19c7..3598735 100644 --- a/README.md +++ b/README.md @@ -1,120 +1,232 @@ -# cluster-utils +# 🐴 DonkeyX's Cluster Utils + +``` +╭────────────────────────────────────────╮ +| 🐴 DonkeyX's Cluster Utils │ +╰────────────────────────────────────────╯ + + //\\ + (/oo\) .----. + (____) | K8s | + /||\ '----' + //||\\ 🐛 Debug Mode + ^^ ^^ ^^ + "Lets break some Shit!" +``` ## Description -Sample docker image to give you a bash session into your cluster, with lots of tools for testing -network routes etc. I find it super handy when i am testing istio routes/dns and security group -access. +A modern, lightweight Docker container designed for Kubernetes cluster debugging and network troubleshooting. Built on Alpine Linux with a comprehensive toolkit for testing network routes, DNS resolution, database connections, and service mesh configurations. + +**Key Features:** +- 🚀 **Runs Continuously** - No timeouts, persistent debugging environment +- 🎨 **Beautiful Welcome** - Colorized interface with tool inventory +- 🐚 **Modern Shell** - Zsh with Oh My Zsh for enhanced productivity +- 🔧 **Latest Tools** - Automatically fetches latest versions (k6, etc.) +- 📦 **Optimized Size** - Single-layer build, minimal footprint (~220MB) + +* **Container Registry**: `donkeyx/cluster-utils:latest` (DockerHub) or `ghcr.io/donkeyx/cluster-utils:latest` (GitHub) + +## 🚀 Usage + +### Quick Interactive Access (Local) + +For immediate interactive shell access without deployment: + +```bash +# Interactive shell (with explicit zsh entry) +docker run -it --rm --entrypoint=/bin/zsh donkeyx/cluster-utils:latest + +# Alternative: Let auto-shell switching handle it (sh → zsh automatically) +docker run -it --rm --entrypoint=/bin/sh donkeyx/cluster-utils:latest -This container will by default run for 30mins before exiting. You can override this behavior -by modifying the env param ```RUNTIME=1234```. This can be done in the kubes pod definition or -passed to docker at runtime. +# GitHub Container Registry alternative: ghcr.io/donkeyx/cluster-utils:latest +# Note: Replace 'docker' with 'podman' if using Podman instead +``` -* dockerhub : https://hub.docker.com/r/donkeyx/cluster-utils +**What you get:** +- ✅ Immediate zsh shell with Oh My Zsh +- ✅ Welcome screen with ASCII donkey and tool inventory +- ✅ All debugging tools ready to use +- ✅ Auto-cleanup when you exit (`--rm`) -## Usage +### Deploy to Kubernetes Cluster -### run image in k8 cluster: +Deploy as a **Deployment** (runs continuously, no timeouts): -You can run the pod in your cluster with the commands below, this will start the container -in the default namespace and timeout in 30mins. ```bash -# apply pod config with default 30min timeout -kubectl -n default \ - apply -f https://raw.githubusercontent.com/donkeyx/cluster-utils/master/k8s-cluster-utils.yml - -# list the pod -$ kubectl get pods -n default -NAME READY STATUS RESTARTS AGE -cluster-utils 1/1 Running 0 2m18s +# Deploy the cluster utilities as a persistent deployment +kubectl apply -f https://raw.githubusercontent.com/donkeyx/cluster-utils/master/k8s-cluster-utils.yml + +# Check the deployment and service +kubectl get deployments,services -l app=cluster-utils +NAME READY UP-TO-DATE AVAILABLE AGE +deployment.apps/cluster-utils 1/1 1 1 30s + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +service/cluster-utils ClusterIP 10.96.45.123 8080/TCP 30s ``` -Now the pod is running, you can exec into it and.. do whatever you need within the context of -your cluster/namespace. +### Connect to Deployed Container + +**Easy connection via service (no need to know pod name!):** + ```bash -$ kubectl exec -it cluster-utils -- zsh - -awk: cannot open /proc/fb (No such file or directory) - _,met$$$$$gg. root@c8b5eabe6232 - ,g$$$$$$$$$$$$$$$P. OS: Debian 10 buster - ,g$$P"" """Y$$.". Kernel: x86_64 Linux 5.15.153.1-microsoft-standard-WSL2 - ,$$P' `$$$. Uptime: 14h 13m - ',$$P ,ggs. `$$b: Packages: 546 - `d$$' ,$P"' . $$$ Shell: sh - $$P d$' , $$P CPU: AMD Ryzen 5 3600 6-Core @ 12x 3.6GHz - $$: $$. - ,d$$' GPU: - $$\; Y$b._ _,d$P' RAM: 1957MiB / 15959MiB - Y$$. `.`"Y$$$$P"' - `$$b "-.__ - `Y$$ - `Y$$. - `$$b. - `Y$$b. - `"Y$b._ - `"""" - -This container is useful for cluster and network testing with many tools. - -database connection tools: -- psql, redis-cli, mongo -network testing tools: -- curl, wget, ping, traceroute, mtr, nmap, tcpdump, netcat -performance testing tools: -- vegeta, k6 -programming languages: -- golang, python, nodejs -shell: -- zsh with oh-my-zsh +# Connect using the service - simplest method: +kubectl exec -it service/cluster-utils -- sh +kubectl exec -it service/cluster-utils -- zsh + +# Alternative: Connect via deployment: +kubectl exec -it deployment/cluster-utils -- sh +kubectl exec -it deployment/cluster-utils -- zsh + +# You'll see the welcome screen: +╭────────────────────────────────────────╮ +| 🐴 DonkeyX's Cluster Utils │ +╰────────────────────────────────────────╯ + + //\\ + (/oo\) .----. + (____) | K8s | + /||\ '----' + //||\\ 🐛 Debug Mode + ^^ ^^ ^^ + "Braying at broken clusters!" + +🚀 Welcome to the Kubernetes Cluster Utilities! 🚀 +===================================================== + +📦 Available Tools: + +🌐 Network & DNS: + • dig, nslookup, host (bind-tools) + • nc (netcat-openbsd) + • curl, wget + +🗄️ Database Clients: + • psql (PostgreSQL client v17.6) + • redis-cli (Redis client) + +🛠️ Development & Utilities: + • git (version control) + • jq (JSON processor) + • vim (text editor) + • tmux (terminal multiplexer) + • npm/node (JavaScript runtime) + +⚡ Load Testing: + • k6 (latest version - auto-updated) + +🐚 Shell Environment: + • zsh with Oh My Zsh + • Custom prompt and completions +``` + +## 🎯 **Two Usage Modes** + +| Mode | Use Case | Command Pattern | +|------|----------|-----------------| +| **Interactive** | Quick local debugging, testing tools | `docker run -it --rm --entrypoint=/bin/zsh ...` | +| **Deployment** | Persistent cluster pod, team access | `kubectl apply -f k8s-cluster-utils.yml` | + +### Deploy to Kubernetes Cluster ``` -### Build image locally: +## 🔨 Local Development -You can build the image locally if you like and then push to your own repo for testing +### Build Image Locally ```bash -# clone repo -git@github.com:donkeyx/cluster-utils.git +# Clone the repository +git clone https://github.com/donkeyx/cluster-utils.git cd cluster-utils -# build and tag -docker build . -t donkeyx/cluster-utils +# Build the image +docker build -t cluster-utils:local . + +# Run locally for testing +docker run -d --name cluster-utils-test cluster-utils:local -# push -docker push YOUR_REPO.../cluster-utils:latest +# Connect to test container (automatically switches to zsh!) +docker exec -it cluster-utils-test sh + +# Note: All commands work with Podman by replacing 'docker' with 'podman' ``` -### Start container: +### Container Runtime Options -Follow the build process above ```bash +# Run with Docker (DockerHub - recommended) +docker run -d --rm --name cluster-utils donkeyx/cluster-utils:latest -$ docker run -e RUNTIME=60 -d --rm --name cluster-utils donkeyx/cluster-utils -1a3b19d75ab9a536ff531935e9da9f9c549d288cb0cab0d6bbdda2249b4ea680 +# Alternative: GitHub Container Registry +docker run -d --rm --name cluster-utils ghcr.io/donkeyx/cluster-utils:latest -$ docker ps -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -1a3b19d75ab9 donkeyx/cluster-utils "sh /tmp/sleeper.sh" 3 seconds ago Up 3 seconds cluster-utils +# Connect to running container (any shell command gives you zsh): +docker exec -it cluster-utils sh +docker exec -it cluster-utils zsh -$ docker exec -it cluster-utils zsh -➜ /tmp +# Kubernetes connections (easiest with service): +kubectl exec -it service/cluster-utils -- sh +kubectl exec -it deployment/cluster-utils -- sh +# Note: Podman users can replace 'docker' with 'podman' in all commands ``` -### Some useful command and packages available +## 🧰 Available Tools & Commands +### Network Diagnostics ```bash - -# check port is open +# Check if port is open nc -z -v -w5 10.1.1.51 8080 -# check dns +# DNS resolution dig google.com +nslookup my-service.default.svc.cluster.local + +# HTTP testing +curl -v https://api.example.com +wget --spider https://my-service/health +``` + +### Database Testing +```bash +# PostgreSQL connection +psql -h postgres-host -U username -d database -# curl your internal service -curl my-internal-service.default.cluster.local | jq +# Redis testing +redis-cli -h redis-host ping +redis-cli -h redis-host info server +``` -# traceroute path for request -traceroute my-internal-service.default.cluster.local +### Load Testing +```bash +# k6 load testing (latest version auto-installed) +k6 run --vus 10 --duration 30s script.js +k6 run --http-debug https://api.example.com +``` + +### Container & Kubernetes Debugging +```bash +# Check container environment +env | grep KUBERNETES +cat /var/run/secrets/kubernetes.io/serviceaccount/namespace +# Network troubleshooting within cluster +nc -z -v service-name 80 +dig service-name.namespace.svc.cluster.local ``` + +## 🎯 Key Improvements + +- **No Timeouts**: Container runs continuously until manually stopped +- **Modern Tools**: Latest k6, PostgreSQL 17.6, npm instead of full Node.js +- **Optimized Size**: ~220MB (removed MongoDB tools, optimized layers) +- **Better UX**: Auto-switches to zsh, colorized welcome, tool inventory +- **Deployment Ready**: Kubernetes Deployment (not Job) for persistence +- **Multi-Shell Support**: Works with `sh`, `zsh`, or `bash` connections + +## 🐴 Why "Braying at Broken Clusters"? + +Because sometimes your clusters are stubborn as a mule, and you need the right tools to debug them! This container gives you everything you need to troubleshoot network issues, test services, and get your Kubernetes clusters working smoothly again. 🎯 diff --git a/k8s-cluster-utils.yml b/k8s-cluster-utils.yml index 8c3e144..d87a782 100644 --- a/k8s-cluster-utils.yml +++ b/k8s-cluster-utils.yml @@ -1,18 +1,40 @@ -apiVersion: batch/v1 -kind: Job +apiVersion: apps/v1 +kind: Deployment metadata: name: cluster-utils labels: app: cluster-utils purpose: testing spec: + replicas: 1 + selector: + matchLabels: + app: cluster-utils template: + metadata: + labels: + app: cluster-utils spec: containers: - name: cluster-utils - image: donkeyx/cluster-utils:latest - env: - - name: RUNTIME - value: "1800" - restartPolicy: Never - ttlSecondsAfterFinished: 1800 + image: ghcr.io/donkeyx/cluster-utils:latest + # Alternative: donkeyx/cluster-utils:latest (DockerHub) + # Remove RUNTIME env if it was only for timeout + restartPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + name: cluster-utils + labels: + app: cluster-utils + purpose: testing +spec: + selector: + app: cluster-utils + ports: + - name: dummy + port: 8080 + targetPort: 8080 + protocol: TCP + type: ClusterIP diff --git a/kickstart.sh b/kickstart.sh deleted file mode 100755 index bbd7dfd..0000000 --- a/kickstart.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env sh -set -eu pipefail - -# # decent prompt -echo "--- prompt setup zsh ---" - -sh -c "$(wget https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -)" - -curl -sS -L https://github.com/tsenart/vegeta/releases/download/v12.8.3/vegeta-12.8.3-linux-amd64.tar.gz | tar -xz -mv vegeta /usr/local/bin - -# Create a new script that runs screenfetch and then prints the additional information -cat < ~/customfetch -#!/usr/bin/env sh -screenfetch -cat <> ~/.zshrc -echo "export PATH=$HOME/go/bin:$PATH" >> ~/.zshrc - -echo "--- cleanup ---" -apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* \ No newline at end of file diff --git a/sleeper.sh b/sleeper.sh index 21390f6..0736433 100755 --- a/sleeper.sh +++ b/sleeper.sh @@ -2,10 +2,10 @@ set -eu -# run for 30mins before ending -runtime=${RUNTIME:-1800} +echo "Container running continuously - ready for cluster utilities work" +echo "Use kubectl exec to connect and run commands interactively" +echo "Container will keep running until manually stopped" -echo "will run for $runtime seconds, before exiting container" -echo "-- you can override this by passing RUNTIME=33 to the container" - -sleep $runtime +# Keep container running indefinitely +# Using tail -f /dev/null is a common pattern for keeping containers alive +tail -f /dev/null diff --git a/welcome.sh b/welcome.sh new file mode 100644 index 0000000..974c5fd --- /dev/null +++ b/welcome.sh @@ -0,0 +1,80 @@ +#!/bin/sh + +# Welcome message and tool inventory for cluster-utils container +# Colors for better readability +if [ -t 1 ]; then + BOLD='\033[1m' + GREEN='\033[0;32m' + BLUE='\033[0;34m' + YELLOW='\033[1;33m' + CYAN='\033[0;36m' + NC='\033[0m' # No Color +else + BOLD='' GREEN='' BLUE='' YELLOW='' CYAN='' NC='' +fi + +echo "" +printf "${BOLD}${CYAN}" +cat << 'EOF' +╭────────────────────────────────────────╮ +| 🐴 DonkeyX's Cluster Utils │ +╰────────────────────────────────────────╯ + + //\\ + (/oo\) .----. + (____) | K8s | + /||\ '----' + //||\\ 🐛 Debug Mode + ^^ ^^ ^^ + "Braying at broken clusters!" + +EOF +printf "${NC}" +printf "${BOLD}${GREEN}🚀 Welcome to the Networking Cluster Utilities! 🚀${NC}\n" +printf "${BOLD}=====================================================${NC}\n" +echo "" +printf "${BOLD}${BLUE}📦 Available Tools:${NC}\n" +echo "" + +# Network & DNS tools +printf "${CYAN}🌐 Network & DNS:${NC}\n" +echo " • dig, nslookup, host (bind-tools)" +echo " • nc (netcat-openbsd)" +echo " • curl, wget" +echo "" + +# Database clients +printf "${CYAN}🗄️ Database Clients:${NC}\n" +PG_VERSION=$(psql --version 2>/dev/null | cut -d' ' -f3 | cut -d'.' -f1-2 || echo 'N/A') +echo " • psql (PostgreSQL client v${PG_VERSION})" +echo " • redis-cli (Redis client)" +echo "" + +# Development & utilities +printf "${CYAN}🛠️ Development & Utilities:${NC}\n" +echo " • git (version control)" +echo " • jq (JSON processor)" +echo " • vim (text editor)" +echo " • tmux (terminal multiplexer)" +echo " • npm/node (JavaScript runtime)" +echo "" + +# Load testing +printf "${CYAN}⚡ Load Testing:${NC}\n" +K6_VERSION=$(k6 version 2>/dev/null | head -1 || echo 'load testing tool') +echo " • k6 (${K6_VERSION})" +echo "" + +# Shell +printf "${CYAN}🐚 Shell Environment:${NC}\n" +echo " • zsh with Oh My Zsh" +echo " • Custom prompt and completions" +echo "" + +printf "${BOLD}${YELLOW}💡 Tips:${NC}\n" +echo " • Use 'kubectl exec -it -- zsh' for interactive shell" +echo " • All tools are in PATH and ready to use" +echo " • Container runs continuously - no timeouts!" +echo "" +printf "${BOLD}${GREEN}Happy cluster debugging! 🎯${NC}\n" +echo "" \ No newline at end of file