summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhc <hc@email.ch>2025-05-30 22:51:55 +0800
committerhc <hc@email.ch>2025-05-30 22:51:55 +0800
commit7b94af70555aab814f964a08098d0fb123171f7e (patch)
tree2b8cf5793a7ecee85122133b4a59cad824e0c912
dev_env
-rw-r--r--.claude/settings.local.json9
-rw-r--r--docker_build/Dockerfile50
-rw-r--r--docker_build/vimrc77
-rw-r--r--docs48
-rwxr-xr-xpodman_launch_devenv.py49
-rw-r--r--rocky-ssh-deployment.yaml48
-rw-r--r--ssh-keys/macm4-resident.pub1
7 files changed, 282 insertions, 0 deletions
diff --git a/.claude/settings.local.json b/.claude/settings.local.json
new file mode 100644
index 0000000..f689325
--- /dev/null
+++ b/.claude/settings.local.json
@@ -0,0 +1,9 @@
+{
+ "permissions": {
+ "allow": [
+ "Bash(rm:*)",
+ "Bash(chmod:*)"
+ ],
+ "deny": []
+ }
+} \ No newline at end of file
diff --git a/docker_build/Dockerfile b/docker_build/Dockerfile
new file mode 100644
index 0000000..644b18f
--- /dev/null
+++ b/docker_build/Dockerfile
@@ -0,0 +1,50 @@
+FROM rockylinux:9
+
+# Install required packages, resolving curl conflict
+RUN dnf install -y epel-release
+RUN dnf install -y --allowerasing openssh-server sudo procps-ng \
+ gcc gcc-c++ make cmake pkg-config openssl-devel libicu-devel perl python3-devel \
+ nc openssl bat autossh tmux htop tar bmon gzip tree wget \
+ nano vim unzip net-tools git python3 python3-pip make wireguard-tools usbutils yum xclip \
+ && dnf clean all
+
+# Configure SSH
+RUN mkdir -p /var/run/sshd && \
+ ssh-keygen -A && \
+ sed -i 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config && \
+ sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config && \
+ sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
+
+# Setup SSH directory for root and ensure root has valid shell
+RUN mkdir -p /root/.ssh && \
+ chmod 700 /root/.ssh && \
+ usermod -s /bin/bash root
+
+# Copy SSH public keys from ssh-keys directory into the image
+COPY ssh-keys/*.pub /tmp/ssh-keys/
+RUN cat /tmp/ssh-keys/*.pub > /root/.ssh/authorized_keys && \
+ chmod 600 /root/.ssh/authorized_keys && \
+ rm -rf /tmp/ssh-keys
+
+# Configure vim
+COPY docker_build/vimrc /etc/vimrc
+
+# Configure bash prompt and colors
+RUN echo 'LS_COLORS=$LS_COLORS:"di=38;5;135:ex=00;32:" ; export LS_COLORS' >> /etc/bashrc && \
+ echo 'PS1="[\[\033[01;32m\]\u\[\033[00m\]@\h \[\033[38;5;135m\]\W\[\033[00m\]]\$ "' >> /etc/bashrc && \
+ echo 'export PATH=$PATH:/root/.cargo/bin' >> /root/.bashrc
+
+# Install Rust and tools for root
+RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && \
+ echo '[ -f "$HOME/.cargo/env" ] && source "$HOME/.cargo/env"' >> ~/.bashrc && \
+ source "$HOME/.cargo/env" && \
+ cargo install cargo-clone-crate cargo-edit cargo-info evcxr_jupyter bacon du-dust
+
+# Set working directory
+WORKDIR /root
+
+# Expose SSH port
+EXPOSE 22
+
+# Start SSH daemon
+CMD ["/usr/sbin/sshd", "-D", "-e"] \ No newline at end of file
diff --git a/docker_build/vimrc b/docker_build/vimrc
new file mode 100644
index 0000000..36583bc
--- /dev/null
+++ b/docker_build/vimrc
@@ -0,0 +1,77 @@
+" Basic vim configuration for development environment
+
+" Enable syntax highlighting
+syntax on
+
+" Enable line numbers
+set number
+
+" Enable relative line numbers for easier navigation
+set relativenumber
+
+" Set tab width to 4 spaces
+set tabstop=4
+set shiftwidth=4
+set expandtab
+
+" Enable auto-indentation
+set autoindent
+set smartindent
+
+" Enable incremental search
+set incsearch
+
+" Highlight search results
+set hlsearch
+
+" Case-insensitive search unless uppercase is used
+set ignorecase
+set smartcase
+
+" Show matching brackets
+set showmatch
+
+" Enable mouse support
+set mouse=a
+
+" Set backspace behavior
+set backspace=indent,eol,start
+
+" Show current line and column
+set ruler
+
+" Enable file type detection
+filetype on
+filetype plugin on
+filetype indent on
+
+" Set color scheme (if available)
+colorscheme default
+
+" Enable visual bell instead of beep
+set visualbell
+
+" Set encoding
+set encoding=utf-8
+
+" Show command in status line
+set showcmd
+
+" Enable wildmenu for command completion
+set wildmenu
+
+" Set status line
+set laststatus=2
+set statusline=%F%m%r%h%w\ [%l,%c]\ [%L\ lines]
+
+" Rust specific settings
+autocmd FileType rust setlocal tabstop=4 shiftwidth=4 expandtab
+
+" Python specific settings
+autocmd FileType python setlocal tabstop=4 shiftwidth=4 expandtab
+
+" JavaScript/TypeScript settings
+autocmd FileType javascript,typescript setlocal tabstop=2 shiftwidth=2 expandtab
+
+" YAML settings
+autocmd FileType yaml setlocal tabstop=2 shiftwidth=2 expandtab \ No newline at end of file
diff --git a/docs b/docs
new file mode 100644
index 0000000..50aca64
--- /dev/null
+++ b/docs
@@ -0,0 +1,48 @@
+# Rocky SSH Container
+Rocky Linux development environment with SSH access for Podman and Kubernetes.
+
+## Launcher Commands
+```bash
+# Check image status and show build commands
+python3 launcher.py
+python3 launcher.py run
+python3 launcher.py run -p 2222
+python3 launcher.py list
+python3 launcher.py cleanup
+```
+
+## Kubernetes Commands
+```bash
+kubectl apply -f rocky-ssh-deployment.yaml
+# Check pods with IPs
+kubectl get pods -l app=rocky-dev-deploy -o wide
+# Check services (networking), get deployment is for stateless (not this)
+kubectl get svc rocky-dev-deploy-svc
+# Delete specific pod (auto-recreates)
+kubectl delete pod rocky-dev-deploy-0
+# Scale replicas
+kubectl scale statefulset rocky-dev-deploy --replicas=10
+kubectl delete -f rocky-ssh-deployment.yaml
+```
+
+## Local Registry (for Kubernetes)
+```bash
+# Run a local registry
+podman run -d -p 5000:5000 --name registry registry:2
+# Tag and push to local registry
+podman tag localhost/rocky_dev:latest localhost:5000/rocky_dev:latest
+podman push localhost:5000/rocky_dev:latest --tls-verify=false
+# Update image in rocky-ssh-deployment.yaml to: localhost:5000/rocky_dev:latest
+```
+
+## SSH Access
+```bash
+# Podman (launcher shows connection command)
+ssh root@<host> -p <port>
+# Kubernetes (port forward - localhost only)
+kubectl port-forward <pod-name> 2222:22
+ssh root@localhost -p 2222
+# Kubernetes (port forward - external access)
+kubectl port-forward --address 0.0.0.0 <pod-name> 9999:22
+ssh root@<host> -p 9999
+```
diff --git a/podman_launch_devenv.py b/podman_launch_devenv.py
new file mode 100755
index 0000000..a155b8f
--- /dev/null
+++ b/podman_launch_devenv.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+"""
+Rocky SSH Container Launcher
+
+Manual build command:
+ podman build -f docker-build/Dockerfile -t rocky_dev:latest .
+
+Usage:
+ python3 launcher.py # Build and launch container
+ python3 launcher.py --list # List running rocky-dev containers
+ python3 launcher.py --cleanup # Stop and remove all containers
+"""
+import subprocess, argparse, os, glob
+
+def run(cmd): return subprocess.run(cmd, shell=True, capture_output=True, text=True)
+
+def build():
+ if not glob.glob("ssh-keys/*.pub"): os.makedirs("ssh-keys", exist_ok=True); open("ssh-keys/dummy.pub", "w").write("# dummy")
+ result = run("podman build -f docker_build/Dockerfile -t rocky_dev:latest .")
+ if os.path.exists("ssh-keys/dummy.pub"): os.remove("ssh-keys/dummy.pub")
+ return result.returncode == 0
+
+def launch():
+ port = str(args.port) if args.port else run("shuf -i 10000-65000 -n 1").stdout.strip()
+ result = run(f"podman run -d -p {port}:22 --privileged --name rocky_dev-{port} rocky_dev:latest")
+ if result.returncode == 0:
+ ip = run("hostname -I | awk '{print $1}'").stdout.strip() or "localhost"
+ print(f"🐳 SSH: ssh root@{ip} -p {port}")
+ return result.returncode == 0
+
+parser = argparse.ArgumentParser(epilog="""
+Manual build commands:
+ Build: podman build -f docker_build/Dockerfile -t rocky_dev:latest .
+ Rebuild: podman rmi rocky_dev:latest && podman build -f docker_build/Dockerfile -t rocky_dev:latest .
+""", formatter_class=argparse.RawDescriptionHelpFormatter)
+parser.add_argument("command", nargs="?", choices=["run", "list", "cleanup"], help="Command to execute")
+parser.add_argument("-p", "--port", type=int)
+args = parser.parse_args()
+
+if args.command == "list": print(run("podman ps --filter name=rocky_dev").stdout or "No containers")
+elif args.command == "cleanup": [run(f"podman stop {c} && podman rm {c}") for c in run("podman ps -a --filter name=rocky_dev --format '{{.Names}}'").stdout.split()]
+elif args.command == "run":
+ if run("podman images -q rocky_dev").stdout:
+ print("found rocky_dev container! starting with a random public port to ssh... ")
+ launch()
+ else:
+ print("❌ Image rocky_dev:latest not found")
+else:
+ print("Usage: python3 launcher.py {run|list|cleanup} [-p PORT]")
diff --git a/rocky-ssh-deployment.yaml b/rocky-ssh-deployment.yaml
new file mode 100644
index 0000000..61e0dc9
--- /dev/null
+++ b/rocky-ssh-deployment.yaml
@@ -0,0 +1,48 @@
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: rocky-dev-deploy
+ labels:
+ app: rocky-dev-deploy
+spec:
+ serviceName: rocky-dev-deploy-svc
+ replicas: 3
+ selector:
+ matchLabels:
+ app: rocky-dev-deploy
+ template:
+ metadata:
+ labels:
+ app: rocky-dev-deploy
+ spec:
+ containers:
+ - name: rocky-dev-deploy
+ image: localhost:5000/rocky_dev:latest
+ imagePullPolicy: IfNotPresent # Use local image
+ ports:
+ - containerPort: 22
+ name: ssh
+ securityContext:
+ privileged: true
+ livenessProbe:
+ tcpSocket:
+ port: 22
+ initialDelaySeconds: 30
+ periodSeconds: 30
+ readinessProbe:
+ tcpSocket:
+ port: 22
+ initialDelaySeconds: 5
+ periodSeconds: 10
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: rocky-dev-deploy-svc
+spec:
+ clusterIP: None
+ selector:
+ app: rocky-dev-deploy
+ ports:
+ - port: 22
+ targetPort: 22
diff --git a/ssh-keys/macm4-resident.pub b/ssh-keys/macm4-resident.pub
new file mode 100644
index 0000000..fbccb4f
--- /dev/null
+++ b/ssh-keys/macm4-resident.pub
@@ -0,0 +1 @@
+sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIFdHP8n64jOV6Ok7U9TDnGW+LUkXP6V7cvXH6xqN0zcNAAAAEnNzaDptYWNtNC1yZXNpZGVudA== ssh:macm4-resident