added docs and container (podman + docker) setup

This commit is contained in:
2025-10-13 01:28:52 +02:00
parent 67cca9854f
commit 1cccb4e603
16 changed files with 1918 additions and 5 deletions

36
.containerignore Normal file
View File

@@ -0,0 +1,36 @@
# Git
.git
.gitignore
# Documentation
*.md
!README.md
LICENSE
# Build artifacts
argparse-builder
argparse-builder-*
*.exe
*.dll
*.so
*.dylib
# Test files
*_test.go
test_*.go
# Development
.vscode
.idea
*.swp
*.swo
*~
# OS files
.DS_Store
Thumbs.db
# Temp files
tmp/
temp/
*.tmp

54
Makefile.container Normal file
View File

@@ -0,0 +1,54 @@
.PHONY: help build run docker-build docker-run docker-push clean
BINARY_NAME=argparse-builder
DOCKER_IMAGE=argparse-builder
DOCKER_TAG=latest
PORT=8080
help:
@echo "Available targets:"
@echo " build - Build Go binary"
@echo " run - Run locally"
@echo " docker-build - Build Docker image"
@echo " docker-run - Run Docker container"
@echo " docker-push - Push to registry"
@echo " docker-clean - Remove Docker images"
@echo " clean - Clean all artifacts"
build:
go build -ldflags="-s -w" -o $(BINARY_NAME) .
run: build
./$(BINARY_NAME)
docker-build:
docker build -t $(DOCKER_IMAGE):$(DOCKER_TAG) .
docker-build-alpine:
docker build -f Dockerfile.alpine -t $(DOCKER_IMAGE):alpine .
docker-run:
docker run -d -p $(PORT):8080 --name $(BINARY_NAME) $(DOCKER_IMAGE):$(DOCKER_TAG)
docker-stop:
docker stop $(BINARY_NAME) && docker rm $(BINARY_NAME)
docker-logs:
docker logs -f $(BINARY_NAME)
docker-push:
docker push $(DOCKER_IMAGE):$(DOCKER_TAG)
docker-clean:
docker rmi $(DOCKER_IMAGE):$(DOCKER_TAG) || true
compose-up:
docker-compose up -d
compose-down:
docker-compose down
clean:
rm -f $(BINARY_NAME)
docker-compose down || true
docker rm -f $(BINARY_NAME) || true

View File

@@ -39,8 +39,8 @@ go build -o argparse-builder
./argparse-builder
```
Server starts on port 8080. Open http://localhost:8080 in your browser.
Demo available at: https://pages.git.pynezz.dev/argparse-builder
Server starts on port 8080. Open <http://localhost:8080> in your browser.
Demo available at: <https://pages.git.pynezz.dev/argparse-builder>
## Usage
@@ -89,3 +89,51 @@ Generates a complete bash script with:
- No shell execution
- Template-based HTML generation
- CORS headers not set (localhost only by default)
## Run in container
### File Structure
```
.
├── assets/
│ ├── Containerfile # OCI production (scratch, ~7MB)
│ └── Containerfile.alpine # Development (Alpine, ~15MB)
├── docs/
│ ├── container.md # Primary Podman guide ⭐
│ ├── docker/
│ │ ├── DOCKER_GUIDE.md # Complete Docker reference
│ │ ├── Dockerfile # Docker production
│ │ ├── Dockerfile.alpine # Docker development
│ │ ├── docker-compose.yml
│ │ ├── docker.md # Docker vs Podman
│ │ └── README.md
│ └── README.md # Documentation hub
├── Makefile.container # Podman build targets
├── podman-compose.yml # OCI compose with SELinux
├── CONTAINER_QUICKREF.md # One-page reference
├── PODMAN_SUMMARY.md # This summary
└── k8s-deployment.yaml # Kubernetes manifest (TODO)
```
### Usage
```bash
# Podman (primary)
podman build -f assets/Containerfile -t argparse-builder .
podman run -d -p 8080:8080 --security-opt label=type:container_t argparse-builder
# Docker (compatibility)
docker build -f assets/Containerfile -t argparse-builder .
docker run -d -p 8080:8080 argparse-builder
```
```
```
```
```

43
assets/.compose Normal file
View File

@@ -0,0 +1,43 @@
version: '3.8'
services:
argparse-builder:
build:
context: .
dockerfile: Dockerfile
container_name: argparse-builder
ports:
- "8080:8080"
restart: unless-stopped
# Resource limits
deploy:
resources:
limits:
cpus: '0.5'
memory: 128M
reservations:
cpus: '0.1'
memory: 32M
# Security
read_only: true
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
# Health check
healthcheck:
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:8080/ || exit 1"]
interval: 30s
timeout: 3s
retries: 3
start_period: 5s
# Logging
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"

50
assets/Containerfile Normal file
View File

@@ -0,0 +1,50 @@
# OCI-compliant multi-stage build for Podman
# Handles SELinux contexts and rootless operation
FROM docker.io/library/golang:1.23-alpine AS builder
RUN apk add --no-cache git ca-certificates tzdata
WORKDIR /build
COPY go.mod go.sum* ./
RUN go mod download
COPY . .
# Build static binary with no CGO
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
-ldflags='-w -s -extldflags "-static"' \
-a -installsuffix cgo \
-o argparse-builder \
.
# Minimal runtime with proper labels
FROM scratch
LABEL maintainer="your-email@example.com" \
org.opencontainers.image.title="Argparse Builder" \
org.opencontainers.image.description="Interactive bash argument parser generator" \
org.opencontainers.image.version="1.0.0" \
org.opencontainers.image.authors="pynezz" \
org.opencontainers.image.url="https://git.pynezz.dev/pynezz/argparser" \
org.opencontainers.image.source="https://git.pynezz.dev/pynezz/argparser"
# Copy certificates and timezone data
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
# Copy binary
COPY --from=builder /build/argparse-builder /argparse-builder
# Expose port
EXPOSE 8080
# Run as nobody user
USER 65534:65534
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD ["/argparse-builder", "health"] || exit 1
ENTRYPOINT ["/argparse-builder"]

View File

@@ -0,0 +1,41 @@
# Alpine-based with shell for debugging
# SELinux compatible, rootless ready
FROM docker.io/library/golang:1.23-alpine AS builder
RUN apk add --no-cache git ca-certificates
WORKDIR /build
COPY go.mod go.sum* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build \
-ldflags='-w -s' \
-o argparse-builder \
.
FROM docker.io/library/alpine:3.19
LABEL maintainer="your-email@example.com" \
org.opencontainers.image.title="Argparse Builder (Alpine)" \
org.opencontainers.image.description="Interactive bash argument parser generator" \
org.opencontainers.image.version="1.0.0"
RUN apk add --no-cache ca-certificates tzdata && \
adduser -D -u 1000 -h /app argparse
WORKDIR /app
COPY --from=builder --chown=argparse:argparse /build/argparse-builder .
USER argparse
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
ENTRYPOINT ["/app/argparse-builder"]

48
assets/Dockerfile Normal file
View File

@@ -0,0 +1,48 @@
# Multi-stage build for minimal final image
FROM golang:1.23-alpine AS builder
# Install build dependencies
RUN apk add --no-cache git ca-certificates tzdata
WORKDIR /build
# Copy go mod files
COPY go.mod go.sum* ./
# Download dependencies (cached layer)
RUN go mod download
# Copy source code
COPY . .
# Build with optimizations
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
-ldflags='-w -s -extldflags "-static"' \
-a -installsuffix cgo \
-o argparse-builder \
.
# Final stage - minimal image
FROM scratch
# Copy CA certificates for HTTPS (if needed)
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
# Copy timezone data
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
# Copy binary
COPY --from=builder /build/argparse-builder /argparse-builder
# Expose port
EXPOSE 8080
# Run as non-root (numeric UID for scratch)
USER 65534:65534
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD ["/argparse-builder", "health"] || exit 1
# Run the application
ENTRYPOINT ["/argparse-builder"]

38
assets/Dockerfile.alpine Normal file
View File

@@ -0,0 +1,38 @@
# Alpine-based image for debugging and shell access
FROM golang:1.23-alpine AS builder
RUN apk add --no-cache git ca-certificates
WORKDIR /build
COPY go.mod go.sum* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build \
-ldflags='-w -s' \
-o argparse-builder \
.
# Alpine base for shell access and debugging
FROM alpine:3.19
RUN apk add --no-cache ca-certificates tzdata && \
adduser -D -u 1000 argparse
WORKDIR /app
COPY --from=builder /build/argparse-builder .
# Change ownership
RUN chown argparse:argparse /app/argparse-builder
USER argparse
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/ || exit 1
ENTRYPOINT ["/app/argparse-builder"]

49
compose.yml Normal file
View File

@@ -0,0 +1,49 @@
version: "3"
services:
argparse-builder:
build:
context: .
dockerfile: assets/Containerfile
container_name: argparse-builder
ports:
- "8080:8080"
restart: unless-stopped
# SELinux
security_opt:
- label=type:container_t
- no-new-privileges:true
# Security
read_only: true
cap_drop:
- ALL
# Resources
deploy:
resources:
limits:
cpus: "0.5"
memory: 128M
reservations:
cpus: "0.1"
memory: 32M
# Health
healthcheck:
test:
[
"CMD-SHELL",
"wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1",
]
interval: 30s
timeout: 3s
retries: 3
start_period: 5s
# Logging
logging:
driver: journald
options:
tag: argparse-builder

98
docs/README.md Normal file
View File

@@ -0,0 +1,98 @@
# Documentation
> This project is OCI container (podman)-first. Docker specific documentation is provided in docker/docker.md
# Container Quick Reference (Podman/OCI)
## Structure
```
assets/
├── Containerfile ← OCI production (~7MB)
└── Containerfile.alpine ← Development (~15MB)
docs/
├── container.md ← Main Podman guide ⭐
└── docker/ ← Docker specifics
```
## Quick Commands
```bash
# Build
podman build -t argparse-builder .
# Run rootless
podman run -d -p 8080:8080 argparse-builder
# With SELinux
podman run -d -p 8080:8080 --security-opt label=type:container_t argparse-builder
# Hardened
podman run -d -p 8080:8080 \
--read-only \
--cap-drop=ALL \
--security-opt=no-new-privileges \
--memory=128m \
argparse-builder
```
## SELinux Volumes
```bash
# Private label (recommended)
podman run -v ./data:/data:Z argparse-builder
# Shared label
podman run -v ./shared:/shared:z argparse-builder
```
## Systemd Integration
```bash
# Generate unit
podman generate systemd --new --name argparse-builder > ~/.config/systemd/user/argparse-builder.service
# Enable
systemctl --user enable --now argparse-builder
```
## Key Features
- ✅ Rootless by default
- ✅ SELinux native support
- ✅ Daemonless operation
- ✅ OCI compliant
- ✅ Systemd integration
- ✅ ~7MB image size
## Makefile
```bash
make container-build # Build image
make container-run # Run rootless
make container-run-hardened # Security hardened
make container-systemd # Generate systemd unit
```
See **docs/container.md** for complete guide.
```
```
```
```
```
```
```
```
```
```

478
docs/container.md Normal file
View File

@@ -0,0 +1,478 @@
# Docker Deployment Guide
## Quick Start
```bash
# Build and run
docker build -t argparse-builder .
docker run -d -p 8080:8080 --name argparse-builder argparse-builder
# Or use docker-compose
docker-compose up -d
# Access at http://localhost:8080
```
## Dockerfile Options
### 1. Dockerfile (scratch-based) - RECOMMENDED
**Size: ~7-8 MB**
- Minimal attack surface
- No shell, no package manager
- Best for production
```bash
docker build -t argparse-builder:scratch .
```
### 2. Dockerfile.alpine (Alpine-based)
**Size: ~15 MB**
- Has shell for debugging
- Includes wget for healthchecks
- Better for development
```bash
docker build -f Dockerfile.alpine -t argparse-builder:alpine .
```
## Build Commands
### Standard Build
```bash
docker build -t argparse-builder:latest .
```
### Multi-platform Build
```bash
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t argparse-builder:multi \
--push .
```
### Build with Cache
```bash
docker build \
--cache-from argparse-builder:latest \
-t argparse-builder:latest .
```
### Optimized Build Args
```bash
docker build \
--build-arg GO_VERSION=1.23 \
--build-arg CGO_ENABLED=0 \
-t argparse-builder:optimized .
```
## Run Options
### Basic Run
```bash
docker run -d -p 8080:8080 argparse-builder
```
### With Custom Port
```bash
docker run -d -p 3000:8080 argparse-builder
```
### With Environment Variables
```bash
docker run -d \
-p 8080:8080 \
-e PORT=8080 \
-e LOG_LEVEL=debug \
argparse-builder
```
### With Resource Limits
```bash
docker run -d \
-p 8080:8080 \
--memory="128m" \
--cpus="0.5" \
argparse-builder
```
### With Read-only Root Filesystem
```bash
docker run -d \
-p 8080:8080 \
--read-only \
--cap-drop=ALL \
--security-opt=no-new-privileges:true \
argparse-builder
```
## Docker Compose
### Start Services
```bash
docker-compose up -d
```
### View Logs
```bash
docker-compose logs -f
```
### Stop Services
```bash
docker-compose down
```
### Rebuild and Restart
```bash
docker-compose up -d --build
```
### Scale (if needed)
```bash
docker-compose up -d --scale argparse-builder=3
```
## Health Checks
### Check Container Health
```bash
docker ps --filter "name=argparse-builder"
```
### Manual Health Check
```bash
# For Alpine image
docker exec argparse-builder wget -qO- http://localhost:8080/
# For scratch image (no shell)
curl http://localhost:8080/
```
### View Health Status
```bash
docker inspect --format='{{json .State.Health}}' argparse-builder | jq
```
## Image Management
### List Images
```bash
docker images | grep argparse-builder
```
### Tag Image
```bash
docker tag argparse-builder:latest registry.example.com/argparse-builder:v1.0
```
### Push to Registry
```bash
docker push registry.example.com/argparse-builder:v1.0
```
### Clean Up
```bash
# Remove stopped containers
docker container prune
# Remove unused images
docker image prune -a
# Remove everything
docker system prune -a
```
## Kubernetes Deployment
### Basic Deployment
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: argparse-builder
spec:
replicas: 2
selector:
matchLabels:
app: argparse-builder
template:
metadata:
labels:
app: argparse-builder
spec:
containers:
- name: argparse-builder
image: argparse-builder:latest
ports:
- containerPort: 8080
resources:
limits:
memory: "128Mi"
cpu: "500m"
requests:
memory: "32Mi"
cpu: "100m"
livenessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 3
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: argparse-builder
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 8080
selector:
app: argparse-builder
```
### Deploy to Kubernetes
```bash
kubectl apply -f k8s-deployment.yaml
kubectl get pods -l app=argparse-builder
kubectl get svc argparse-builder
```
## Security Best Practices
### 1. Use Specific Version Tags
```dockerfile
FROM golang:1.23-alpine AS builder
```
### 2. Run as Non-root User
```dockerfile
USER 65534:65534
```
### 3. Drop All Capabilities
```bash
docker run --cap-drop=ALL argparse-builder
```
### 4. Use Read-only Root Filesystem
```bash
docker run --read-only argparse-builder
```
### 5. Scan for Vulnerabilities
```bash
docker scan argparse-builder:latest
```
## Performance Tuning
### Build-time Optimizations
```dockerfile
# Static linking
-ldflags='-w -s -extldflags "-static"'
# No CGO
CGO_ENABLED=0
# Strip debug info
-w -s
```
### Runtime Optimizations
```bash
# Set GOMAXPROCS (if multi-core)
docker run -e GOMAXPROCS=2 argparse-builder
# Adjust memory limits
docker run --memory="64m" --memory-swap="128m" argparse-builder
```
## Monitoring
### Container Stats
```bash
docker stats argparse-builder
```
### Logs
```bash
docker logs -f --tail 100 argparse-builder
```
### Resource Usage
```bash
docker container inspect argparse-builder | jq '.[0].HostConfig.Memory'
```
## Troubleshooting
### Container Won't Start
```bash
# Check logs
docker logs argparse-builder
# Inspect container
docker inspect argparse-builder
# Try running interactively (Alpine image)
docker run -it --rm argparse-builder:alpine sh
```
### Port Already in Use
```bash
# Find process using port
lsof -i :8080
# Use different port
docker run -p 3000:8080 argparse-builder
```
### Permission Denied
```bash
# Check file permissions
ls -la argparse-builder
# Ensure binary is executable
chmod +x argparse-builder
```
### Out of Memory
```bash
# Increase memory limit
docker run --memory="256m" argparse-builder
# Check current limits
docker inspect argparse-builder | jq '.[0].HostConfig'
```
## CI/CD Integration
### GitHub Actions
```yaml
name: Docker Build and Push
on:
push:
branches: [main]
release:
types: [created]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ghcr.io/${{ github.repository }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max
```
### GitLab CI
```yaml
build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
```
## Image Size Comparison
| Dockerfile | Base Image | Size | Use Case |
| ----------------- | ----------- | ------- | --------------- |
| Dockerfile | scratch | ~7 MB | Production |
| Dockerfile.alpine | alpine:3.19 | ~15 MB | Development |
| (no optimization) | golang:1.23 | ~900 MB | Not recommended |
## Registry Options
### GitHub Container Registry
```bash
docker tag argparse-builder:latest ghcr.io/username/argparse-builder:latest
docker push ghcr.io/username/argparse-builder:latest
```
### Docker Hub
```bash
docker tag argparse-builder:latest username/argparse-builder:latest
docker push username/argparse-builder:latest
```
### Private Registry
```bash
docker tag argparse-builder:latest registry.example.com/argparse-builder:latest
docker push registry.example.com/argparse-builder:latest
```

12
docs/docker/README.md Normal file
View File

@@ -0,0 +1,12 @@
# Docker quick start
```zsh
# Build
docker build -t argparse-builder .
# Run
docker run -d -p 8080:8080 argparse-builder
# Or use compose
docker-compose up -d
```

View File

@@ -0,0 +1,86 @@
# Docker-Specific Guide
## Docker vs Podman
This project prioritizes **Podman** (OCI-compliant, rootless, daemonless). For Docker, convert commands:
```bash
# Podman → Docker
podman build -t name . → docker build -t name .
podman run -d name → docker run -d name
```
## Key Differences
### SELinux
**Podman**: Native support, use `:Z` or `:z` for volumes
```bash
podman run -v ./data:/data:Z name
```
**Docker**: Requires `selinux` mount option
```bash
docker run -v ./data:/data:Z name # May not work
docker run --security-opt label=type:container_t name
```
### Rootless
**Podman**: Default rootless operation
```bash
podman run -d -p 8080:8080 name # Works as user
```
**Docker**: Requires rootless daemon setup
```bash
dockerd-rootless-setuptool.sh install
```
### Systemd
**Podman**: Native integration
```bash
podman generate systemd --new name
```
**Docker**: Use third-party solutions
## Docker Files
Use `Dockerfile` instead of `Containerfile`:
```bash
docker build -f assets/Dockerfile.alpine -t argparse-builder .
```
## Docker Compose
Standard `docker-compose.yml` works, but note SELinux limitations:
```yaml
services:
app:
volumes:
- ./data:/data # No :Z support in Docker Compose
```
Workaround:
```bash
chcon -Rt container_file_t ./data # Pre-label directory
```
## Migration to Podman
1. Replace `docker` with `podman` in commands
2. Add `:Z` to volume mounts for SELinux
3. Use rootless by default
4. Generate systemd units with Podman
See `docs/container.md` for full Podman guide.

181
docs/docker/docker.md Normal file
View File

@@ -0,0 +1,181 @@
# Docker Quick Reference
## 🚀 Quick Start
```bash
# Build and run (one command)
docker build -t argparse-builder . && docker run -d -p 8080:8080 argparse-builder
# Or with docker-compose
docker-compose up -d
```
## 📦 Files Included
```
Dockerfile ← Production (scratch-based, ~7MB)
Dockerfile.alpine ← Development (Alpine, ~15MB)
docker-compose.yml ← Easy deployment
.dockerignore ← Build optimization
k8s-deployment.yaml ← Kubernetes manifest
DOCKER_GUIDE.md ← Complete documentation
Makefile.docker ← Build automation
main_enhancements.go ← Health check & config code
```
## 🔨 Build Options
```bash
# Production (minimal)
docker build -t argparse-builder .
# Development (with shell)
docker build -f Dockerfile.alpine -t argparse-builder:alpine .
# Multi-platform
docker buildx build --platform linux/amd64,linux/arm64 -t argparse-builder .
```
## ▶️ Run Options
```bash
# Basic
docker run -d -p 8080:8080 argparse-builder
# With limits
docker run -d -p 8080:8080 --memory=128m --cpus=0.5 argparse-builder
# Secure
docker run -d -p 8080:8080 --read-only --cap-drop=ALL argparse-builder
```
## 🎯 Image Sizes
| Image | Size | Use |
| ------- | ------- | ------------ |
| scratch | ~7 MB | Production |
| alpine | ~15 MB | Development |
| no-opt | ~900 MB | ❌ Don't use |
## 🔍 Health Check
```bash
# Check health
curl http://localhost:8080/health
# Docker health status
docker ps --filter "health=healthy"
```
## 📊 Monitoring
```bash
# Logs
docker logs -f argparse-builder
# Stats
docker stats argparse-builder
# Inspect
docker inspect argparse-builder
```
## 🎪 Kubernetes
```bash
# Deploy
kubectl apply -f k8s-deployment.yaml
# Check status
kubectl get pods -n argparse-builder
kubectl get svc -n argparse-builder
# Logs
kubectl logs -f deployment/argparse-builder -n argparse-builder
```
## 🛠️ Makefile Commands
```bash
make docker-build # Build image
make docker-run # Run container
make docker-logs # View logs
make compose-up # Start with compose
make clean # Clean everything
```
## 🔒 Security Features
- Non-root user (UID 65534)
- Read-only filesystem
- No capabilities
- Static binary
- Minimal attack surface
## 📝 Key Points
✅ Dockerfile uses multi-stage build (builder + scratch)
✅ Healthcheck endpoint at /health
✅ Environment vars: PORT, LOG_LEVEL
✅ Graceful shutdown support
✅ Resource limits configured
✅ Security hardened by default
## 🌐 Registry Push
```bash
# GitHub Container Registry
docker tag argparse-builder ghcr.io/username/argparse-builder
docker push ghcr.io/username/argparse-builder
# Docker Hub
docker tag argparse-builder username/argparse-builder
docker push username/argparse-builder
```
## 🔄 CI/CD Ready
GitHub Actions example included in DOCKER_GUIDE.md for:
- Automated builds on push
- Multi-platform support
- Registry push
- Cache optimization
See DOCKER_GUIDE.md for complete instructions.
```
```
```
```
```
```
```
```
```
```
```
```
```
```
```
```
```
```

620
docs/podman.md Normal file
View File

@@ -0,0 +1,620 @@
# Podman (OCI Container) Guide
## Quick Start
```bash
# Build
podman build -t argparse-builder .
# Run rootless
podman run -d -p 8080:8080 argparse-builder
# Run with SELinux
podman run -d -p 8080:8080 --security-opt label=type:container_t argparse-builder
```
## Podman vs Docker
| Feature | Podman | Docker |
| ------- | ------------------- | ----------------- |
| Daemon | Daemonless | Requires daemon |
| Root | Rootless by default | Needs root/group |
| SELinux | Native support | Additional config |
| Systemd | Native integration | Third-party |
| OCI | Full compliance | Mostly compliant |
## Build Commands
### Standard Build
```bash
podman build -t argparse-builder .
```
### Using Containerfile
```bash
podman build -f Containerfile -t argparse-builder .
```
### Multi-architecture
```bash
podman build --platform linux/amd64,linux/arm64 -t argparse-builder --manifest argparse-builder .
```
### Build with cache
```bash
podman build --layers -t argparse-builder .
```
## Rootless Operation
### Setup Rootless Podman
```bash
# Install
sudo dnf install podman
# Configure subuid/subgid (automatic on most systems)
grep $(whoami) /etc/subuid
grep $(whoami) /etc/subgid
# Run rootless
podman run -d -p 8080:8080 argparse-builder
# Verify
podman ps
```
### Port Binding < 1024 (Rootless)
```bash
# Option 1: Use high port and forward
podman run -d -p 8080:8080 argparse-builder
sudo firewall-cmd --add-forward-port=port=80:proto=tcp:toport=8080
# Option 2: Set sysctl
sudo sysctl net.ipv4.ip_unprivileged_port_start=80
# Option 3: Use systemd socket activation
# See systemd section below
```
## SELinux Configuration
### Run with SELinux
```bash
# Default (uses process label)
podman run -d -p 8080:8080 argparse-builder
# Specific label
podman run -d -p 8080:8080 --security-opt label=type:container_t argparse-builder
# Disable SELinux for container (not recommended)
podman run -d -p 8080:8080 --security-opt label=disable argparse-builder
```
### Volume Mounts with SELinux
```bash
# Auto-label volume (recommended)
podman run -d -p 8080:8080 -v ./data:/data:Z argparse-builder
# Shared label (multiple containers)
podman run -d -p 8080:8080 -v ./data:/data:z argparse-builder
# Private label (single container)
podman run -d -p 8080:8080 -v ./data:/data:Z argparse-builder
```
### Check SELinux Context
```bash
# Container process
podman top <container> label
# Volume labels
ls -Z ./data
```
### SELinux Troubleshooting
```bash
# Check denials
sudo ausearch -m avc -ts recent
# Generate policy
sudo ausearch -m avc | audit2allow -M my-argparse
sudo semodule -i my-argparse.pp
# Check booleans
getsebool -a | grep container
```
## Systemd Integration
### Generate Systemd Unit
```bash
# Create container
podman run -d --name argparse-builder -p 8080:8080 argparse-builder
# Generate unit file
podman generate systemd --new --name argparse-builder > ~/.config/systemd/user/argparse-builder.service
# Enable and start
systemctl --user daemon-reload
systemctl --user enable --now argparse-builder
```
### Systemd Unit (Manual)
```ini
# ~/.config/systemd/user/argparse-builder.service
[Unit]
Description=Argparse Builder Container
Wants=network-online.target
After=network-online.target
[Service]
Restart=always
ExecStartPre=/usr/bin/podman pull argparse-builder:latest
ExecStart=/usr/bin/podman run \
--rm \
--name argparse-builder \
-p 8080:8080 \
--security-opt label=type:container_t \
argparse-builder:latest
ExecStop=/usr/bin/podman stop -t 10 argparse-builder
ExecStopPost=/usr/bin/podman rm -f argparse-builder
[Install]
WantedBy=default.target
```
### System-wide Service (requires root)
```bash
# Generate for system
sudo podman generate systemd --new --name argparse-builder > /etc/systemd/system/argparse-builder.service
# Enable and start
sudo systemctl daemon-reload
sudo systemctl enable --now argparse-builder
```
## Pod Management
### Create Pod
```bash
# Create pod with port mapping
podman pod create --name argparse-pod -p 8080:8080
# Run container in pod
podman run -d --pod argparse-pod argparse-builder
# List pods
podman pod ps
# Inspect pod
podman pod inspect argparse-pod
```
### Pod with Multiple Containers
```bash
podman pod create --name argparse-stack -p 8080:8080 -p 9090:9090
# Application
podman run -d --pod argparse-stack argparse-builder
# Monitoring (example)
podman run -d --pod argparse-stack prom/prometheus
```
### Pod Systemd Service
```bash
podman generate systemd --new --name argparse-pod > argparse-pod.service
```
## Security Hardening
### Read-only Root
```bash
podman run -d -p 8080:8080 --read-only argparse-builder
```
### No New Privileges
```bash
podman run -d -p 8080:8080 --security-opt=no-new-privileges argparse-builder
```
### Drop Capabilities
```bash
podman run -d -p 8080:8080 --cap-drop=ALL argparse-builder
```
### Resource Limits
```bash
podman run -d -p 8080:8080 \
--memory=128m \
--cpus=0.5 \
--pids-limit=100 \
argparse-builder
```
### Combined Hardening
```bash
podman run -d -p 8080:8080 \
--read-only \
--security-opt=no-new-privileges \
--cap-drop=ALL \
--security-opt label=type:container_t \
--memory=128m \
--cpus=0.5 \
argparse-builder
```
## Networking
### Port Mapping
```bash
# Basic
podman run -d -p 8080:8080 argparse-builder
# Different host port
podman run -d -p 3000:8080 argparse-builder
# Specific interface
podman run -d -p 127.0.0.1:8080:8080 argparse-builder
```
### Custom Network
```bash
# Create network
podman network create argparse-net
# Run with network
podman run -d --network argparse-net -p 8080:8080 argparse-builder
# Inspect network
podman network inspect argparse-net
```
### DNS
```bash
# Custom DNS
podman run -d -p 8080:8080 --dns=8.8.8.8 argparse-builder
# Add hosts
podman run -d -p 8080:8080 --add-host=api.local:192.168.1.100 argparse-builder
```
## Storage and Volumes
### Named Volume
```bash
# Create volume
podman volume create argparse-data
# Use volume with SELinux
podman run -d -p 8080:8080 -v argparse-data:/data:Z argparse-builder
# Inspect volume
podman volume inspect argparse-data
```
### Bind Mount
```bash
# Auto-label (Z)
podman run -d -p 8080:8080 -v ./logs:/app/logs:Z argparse-builder
# Shared label (z) - multiple containers
podman run -d -p 8080:8080 -v ./shared:/shared:z argparse-builder
```
### tmpfs Mount
```bash
podman run -d -p 8080:8080 --tmpfs /tmp:rw,size=64m,mode=1777 argparse-builder
```
## Health and Monitoring
### Health Check
```bash
# Check health status
podman healthcheck run argparse-builder
# View logs
podman logs argparse-builder
# Stats
podman stats argparse-builder
# Top processes
podman top argparse-builder
```
### Inspect Container
```bash
# Full inspect
podman inspect argparse-builder
# Specific field
podman inspect --format='{{.State.Health.Status}}' argparse-builder
```
## Registry Operations
### Login
```bash
# Docker Hub
podman login docker.io
# GitHub Container Registry
podman login ghcr.io
# Private registry
podman login registry.example.com
```
### Tag and Push
```bash
# Tag
podman tag argparse-builder ghcr.io/username/argparse-builder:latest
# Push
podman push ghcr.io/username/argparse-builder:latest
```
### Pull
```bash
# Pull image
podman pull ghcr.io/username/argparse-builder:latest
# Pull specific platform
podman pull --platform linux/arm64 ghcr.io/username/argparse-builder:latest
```
## Podman Compose
### Install
```bash
pip3 install podman-compose
```
### podman-compose.yml
```yaml
version: "3"
services:
argparse-builder:
build: .
ports:
- "8080:8080"
restart: unless-stopped
security_opt:
- label=type:container_t
- no-new-privileges
read_only: true
cap_drop:
- ALL
resources:
limits:
cpus: "0.5"
memory: 128M
```
### Usage
```bash
podman-compose up -d
podman-compose logs -f
podman-compose down
```
## Kubernetes with Podman
### Generate K8s YAML
```bash
# From container
podman generate kube argparse-builder > argparse-k8s.yaml
# From pod
podman generate kube argparse-pod > argparse-pod-k8s.yaml
```
### Play Kubernetes YAML
```bash
# Create from YAML
podman play kube argparse-k8s.yaml
# Remove
podman play kube --down argparse-k8s.yaml
```
## Migration from Docker
### Pull Docker Images
```bash
podman pull docker.io/library/nginx
```
### Docker Compatibility
```bash
# Use docker command (alias)
alias docker=podman
# Docker socket emulation
podman system service --time=0 unix:///tmp/podman.sock
export DOCKER_HOST=unix:///tmp/podman.sock
```
### Convert docker-compose
```bash
# Most docker-compose files work with podman-compose
podman-compose -f docker-compose.yml up
```
## Troubleshooting
### Permission Denied (Rootless)
```bash
# Check subuid/subgid
grep $(whoami) /etc/subuid /etc/subgid
# Verify user namespaces
podman unshare cat /proc/self/uid_map
# Reset storage
podman system reset
```
### SELinux Denials
```bash
# Check denials
sudo ausearch -m avc -ts recent | grep podman
# Temporary permissive mode (troubleshooting)
sudo setenforce 0
# Re-enable
sudo setenforce 1
```
### Port Already in Use
```bash
# Find what's using port
ss -tulpn | grep 8080
# Use different port
podman run -d -p 8081:8080 argparse-builder
```
### Storage Issues
```bash
# Check storage
podman system df
# Clean up
podman system prune -a
# Reset storage
podman system reset
```
## Performance Tuning
### Storage Driver
```bash
# Check current driver
podman info --format '{{.Store.GraphDriverName}}'
# Use overlay (default, best performance)
# Already configured in /etc/containers/storage.conf
```
### Network Performance
```bash
# Use host network (best performance, less isolation)
podman run -d --network host argparse-builder
```
### Build Cache
```bash
# Use buildah cache
podman build --layers -t argparse-builder .
```
## CI/CD Integration
### GitLab CI
```yaml
build:
image: quay.io/podman/stable
services:
- podman:dind
script:
- podman build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- podman push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
```
### GitHub Actions
```yaml
- name: Build with Podman
run: |
podman build -t argparse-builder .
podman tag argparse-builder ghcr.io/${{ github.repository }}:latest
podman push ghcr.io/${{ github.repository }}:latest
```
## Best Practices
1. **Use Rootless** - Run as regular user by default
2. **SELinux** - Keep enabled, use :Z/:z for volumes
3. **Systemd** - Use `podman generate systemd` for services
4. **Security** - Use `--read-only`, `--cap-drop=ALL`, labels
5. **OCI** - Use Containerfile (compatible with Dockerfile)
6. **Pods** - Group related containers in pods
7. **Health Checks** - Include in Containerfile
8. **Resources** - Set limits with `--memory`, `--cpus`
## Quick Reference
```bash
# Build
podman build -t name .
# Run
podman run -d -p 8080:8080 name
# SELinux volume
podman run -v ./data:/data:Z name
# Systemd
podman generate systemd --new name
# Rootless
podman run --userns=keep-id name
# Pod
podman pod create -p 8080:8080
podman run --pod podname name
```

37
main.go
View File

@@ -6,13 +6,18 @@ import (
"io/fs"
"log"
"net/http"
"os"
"strings"
"text/template"
)
//go:embed static/* templates/*
var content embed.FS
var content embed.FS // Environment configuration
type Config struct {
Port string
LogLevel string
}
type Argument struct {
Params string `json:"params"`
Command string `json:"command"`
@@ -36,11 +41,34 @@ type GenerateRequestV2 struct {
Subcommands []Subcommand `json:"subcommands"`
}
func loadConfig() Config {
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
return Config{
Port: port,
LogLevel: os.Getenv("LOG_LEVEL"),
}
}
// Add health check endpoint
func healthHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{
"status": "healthy",
"version": "1.0.0",
})
}
func main() {
staticFS, err := fs.Sub(content, "static")
if err != nil {
log.Fatal(err)
}
config := loadConfig()
templatesFS, err := fs.Sub(content, "templates")
if err != nil {
@@ -49,6 +77,7 @@ func main() {
tmpl := template.Must(template.ParseFS(templatesFS, "*.html"))
http.HandleFunc("/health", healthHandler)
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(staticFS))))
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
@@ -97,8 +126,9 @@ func main() {
w.Write([]byte(bashCode))
})
log.Println("Server starting on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
addr := ":" + config.Port
log.Printf("Server starting on %s", addr)
log.Fatal(http.ListenAndServe(addr, nil))
}
func generateBashScript(req GenerateRequest) string {
@@ -222,6 +252,7 @@ func generateBashScript(req GenerateRequest) string {
return sb.String()
}
func generateBashScriptV2(req GenerateRequestV2) string {
// If no subcommands, use flat generation
if len(req.Subcommands) == 0 {