added docs and container (podman + docker) setup
This commit is contained in:
36
.containerignore
Normal file
36
.containerignore
Normal 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
54
Makefile.container
Normal 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
|
52
README.md
52
README.md
@@ -39,8 +39,8 @@ go build -o argparse-builder
|
|||||||
./argparse-builder
|
./argparse-builder
|
||||||
```
|
```
|
||||||
|
|
||||||
Server starts on port 8080. Open http://localhost:8080 in your browser.
|
Server starts on port 8080. Open <http://localhost:8080> in your browser.
|
||||||
Demo available at: https://pages.git.pynezz.dev/argparse-builder
|
Demo available at: <https://pages.git.pynezz.dev/argparse-builder>
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -89,3 +89,51 @@ Generates a complete bash script with:
|
|||||||
- No shell execution
|
- No shell execution
|
||||||
- Template-based HTML generation
|
- Template-based HTML generation
|
||||||
- CORS headers not set (localhost only by default)
|
- 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
43
assets/.compose
Normal 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
50
assets/Containerfile
Normal 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"]
|
41
assets/Containerfile.alpine
Normal file
41
assets/Containerfile.alpine
Normal 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
48
assets/Dockerfile
Normal 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
38
assets/Dockerfile.alpine
Normal 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
49
compose.yml
Normal 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
98
docs/README.md
Normal 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
478
docs/container.md
Normal 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
12
docs/docker/README.md
Normal 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
|
||||||
|
```
|
86
docs/docker/docker-revised.md
Normal file
86
docs/docker/docker-revised.md
Normal 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
181
docs/docker/docker.md
Normal 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
620
docs/podman.md
Normal 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
37
main.go
@@ -6,13 +6,18 @@ import (
|
|||||||
"io/fs"
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed static/* templates/*
|
//go:embed static/* templates/*
|
||||||
var content embed.FS
|
var content embed.FS // Environment configuration
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Port string
|
||||||
|
LogLevel string
|
||||||
|
}
|
||||||
type Argument struct {
|
type Argument struct {
|
||||||
Params string `json:"params"`
|
Params string `json:"params"`
|
||||||
Command string `json:"command"`
|
Command string `json:"command"`
|
||||||
@@ -36,11 +41,34 @@ type GenerateRequestV2 struct {
|
|||||||
Subcommands []Subcommand `json:"subcommands"`
|
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() {
|
func main() {
|
||||||
staticFS, err := fs.Sub(content, "static")
|
staticFS, err := fs.Sub(content, "static")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
config := loadConfig()
|
||||||
|
|
||||||
templatesFS, err := fs.Sub(content, "templates")
|
templatesFS, err := fs.Sub(content, "templates")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -49,6 +77,7 @@ func main() {
|
|||||||
|
|
||||||
tmpl := template.Must(template.ParseFS(templatesFS, "*.html"))
|
tmpl := template.Must(template.ParseFS(templatesFS, "*.html"))
|
||||||
|
|
||||||
|
http.HandleFunc("/health", healthHandler)
|
||||||
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(staticFS))))
|
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(staticFS))))
|
||||||
|
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -97,8 +126,9 @@ func main() {
|
|||||||
w.Write([]byte(bashCode))
|
w.Write([]byte(bashCode))
|
||||||
})
|
})
|
||||||
|
|
||||||
log.Println("Server starting on :8080")
|
addr := ":" + config.Port
|
||||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
log.Printf("Server starting on %s", addr)
|
||||||
|
log.Fatal(http.ListenAndServe(addr, nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateBashScript(req GenerateRequest) string {
|
func generateBashScript(req GenerateRequest) string {
|
||||||
@@ -222,6 +252,7 @@ func generateBashScript(req GenerateRequest) string {
|
|||||||
|
|
||||||
return sb.String()
|
return sb.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateBashScriptV2(req GenerateRequestV2) string {
|
func generateBashScriptV2(req GenerateRequestV2) string {
|
||||||
// If no subcommands, use flat generation
|
// If no subcommands, use flat generation
|
||||||
if len(req.Subcommands) == 0 {
|
if len(req.Subcommands) == 0 {
|
||||||
|
Reference in New Issue
Block a user