Replace Docker with Podman throughout
- builder/build.sh: all docker commands → podman (build, run, stop, rm, network create, images, rmi, inspect) - server/src/routes/apps.rs: docker stop/restart → podman - server/src/routes/ui.rs: docker inspect → podman - infra/Dockerfile.server: install podman instead of docker.io - infra/docker-compose.yml: rename docker-proxy → podman-proxy, mount /run/podman/podman.sock (rootful Podman socket), update DOCKER_HOST - infra/Makefile: docker compose → podman compose Podman is daemonless and rootless by default; OCI images are identical so no build-pipeline changes are needed beyond renaming the CLI. https://claude.ai/code/session_01FKCW3FDjNFj6jve4niMFXH
This commit is contained in:
parent
0569252edf
commit
4319b99102
6 changed files with 33 additions and 29 deletions
|
|
@ -35,7 +35,7 @@ CONTAINER_NAME="hiy-${APP_ID}"
|
||||||
|
|
||||||
if [ -f "Dockerfile" ]; then
|
if [ -f "Dockerfile" ]; then
|
||||||
log "Strategy: Dockerfile"
|
log "Strategy: Dockerfile"
|
||||||
docker build --tag "$IMAGE_TAG" .
|
podman build --tag "$IMAGE_TAG" .
|
||||||
|
|
||||||
elif [ -f "package.json" ] || [ -f "yarn.lock" ]; then
|
elif [ -f "package.json" ] || [ -f "yarn.lock" ]; then
|
||||||
log "Strategy: Node.js (Cloud Native Buildpack)"
|
log "Strategy: Node.js (Cloud Native Buildpack)"
|
||||||
|
|
@ -69,7 +69,7 @@ elif [ -d "static" ] || [ -d "public" ]; then
|
||||||
FROM caddy:2-alpine
|
FROM caddy:2-alpine
|
||||||
COPY $STATIC_DIR /srv
|
COPY $STATIC_DIR /srv
|
||||||
EOF
|
EOF
|
||||||
docker build --file Dockerfile.hiy --tag "$IMAGE_TAG" .
|
podman build --file Dockerfile.hiy --tag "$IMAGE_TAG" .
|
||||||
rm -f Dockerfile.hiy
|
rm -f Dockerfile.hiy
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
@ -78,14 +78,14 @@ else
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── 3. Ensure Docker network ───────────────────────────────────────────────────
|
# ── 3. Ensure Podman network ───────────────────────────────────────────────────
|
||||||
docker network create hiy-net 2>/dev/null || true
|
podman network create hiy-net 2>/dev/null || true
|
||||||
|
|
||||||
# ── 4. Stop & remove previous container ───────────────────────────────────────
|
# ── 4. Stop & remove previous container ───────────────────────────────────────
|
||||||
if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
if podman ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
||||||
log "Stopping old container…"
|
log "Stopping old container…"
|
||||||
docker stop "$CONTAINER_NAME" >/dev/null 2>&1 || true
|
podman stop "$CONTAINER_NAME" >/dev/null 2>&1 || true
|
||||||
docker rm "$CONTAINER_NAME" >/dev/null 2>&1 || true
|
podman rm "$CONTAINER_NAME" >/dev/null 2>&1 || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── 5. Start new container ────────────────────────────────────────────────────
|
# ── 5. Start new container ────────────────────────────────────────────────────
|
||||||
|
|
@ -96,7 +96,7 @@ if [ -n "${ENV_FILE:-}" ] && [ -f "$ENV_FILE" ]; then
|
||||||
else
|
else
|
||||||
log "No env file found at '${ENV_FILE:-}'; starting without one."
|
log "No env file found at '${ENV_FILE:-}'; starting without one."
|
||||||
fi
|
fi
|
||||||
docker run --detach \
|
podman run --detach \
|
||||||
--name "$CONTAINER_NAME" \
|
--name "$CONTAINER_NAME" \
|
||||||
--network hiy-net \
|
--network hiy-net \
|
||||||
"${ENV_FILE_ARG[@]+"${ENV_FILE_ARG[@]}"}" \
|
"${ENV_FILE_ARG[@]+"${ENV_FILE_ARG[@]}"}" \
|
||||||
|
|
@ -114,7 +114,7 @@ CADDY_API="${CADDY_API_URL:-http://localhost:2019}"
|
||||||
DOMAIN_SUFFIX="${DOMAIN_SUFFIX:-localhost}"
|
DOMAIN_SUFFIX="${DOMAIN_SUFFIX:-localhost}"
|
||||||
|
|
||||||
if curl --silent --fail "${CADDY_API}/config/" >/dev/null 2>&1; then
|
if curl --silent --fail "${CADDY_API}/config/" >/dev/null 2>&1; then
|
||||||
CONTAINER_IP=$(docker inspect "$CONTAINER_NAME" \
|
CONTAINER_IP=$(podman inspect "$CONTAINER_NAME" \
|
||||||
--format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}')
|
--format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}')
|
||||||
UPSTREAM="${CONTAINER_IP}:${PORT}"
|
UPSTREAM="${CONTAINER_IP}:${PORT}"
|
||||||
log "Updating Caddy: ${APP_ID}.${DOMAIN_SUFFIX} → ${UPSTREAM}"
|
log "Updating Caddy: ${APP_ID}.${DOMAIN_SUFFIX} → ${UPSTREAM}"
|
||||||
|
|
@ -209,17 +209,17 @@ else
|
||||||
log "Caddy admin API not reachable; skipping route update."
|
log "Caddy admin API not reachable; skipping route update."
|
||||||
log "Container ${CONTAINER_NAME} is running on port ${PORT} but not publicly routed."
|
log "Container ${CONTAINER_NAME} is running on port ${PORT} but not publicly routed."
|
||||||
log "To reach it directly, re-run the container with a published port:"
|
log "To reach it directly, re-run the container with a published port:"
|
||||||
log " docker rm -f ${CONTAINER_NAME}"
|
log " podman rm -f ${CONTAINER_NAME}"
|
||||||
log " docker run -d --name ${CONTAINER_NAME} -p ${PORT}:${PORT} ${IMAGE_TAG}"
|
log " podman run -d --name ${CONTAINER_NAME} -p ${PORT}:${PORT} ${IMAGE_TAG}"
|
||||||
log "Or point any reverse proxy at: \$(docker inspect ${CONTAINER_NAME} --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'):${PORT}"
|
log "Or point any reverse proxy at: \$(podman inspect ${CONTAINER_NAME} --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'):${PORT}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── 7. Prune old images ───────────────────────────────────────────────────────
|
# ── 7. Prune old images ───────────────────────────────────────────────────────
|
||||||
log "Pruning old images (keeping last 3)…"
|
log "Pruning old images (keeping last 3)…"
|
||||||
docker images "hiy/${APP_ID}" --format "{{.ID}}\t{{.CreatedAt}}" \
|
podman images "hiy/${APP_ID}" --format "{{.ID}}\t{{.CreatedAt}}" \
|
||||||
| sort --reverse --key=2 \
|
| sort --reverse --key=2 \
|
||||||
| tail -n +4 \
|
| tail -n +4 \
|
||||||
| awk '{print $1}' \
|
| awk '{print $1}' \
|
||||||
| xargs --no-run-if-empty docker rmi 2>/dev/null || true
|
| xargs --no-run-if-empty podman rmi 2>/dev/null || true
|
||||||
|
|
||||||
log "=== Build complete: $APP_NAME @ $ACTUAL_SHA ==="
|
log "=== Build complete: $APP_NAME @ $ACTUAL_SHA ==="
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ RUN apt-get update && apt-get install -y \
|
||||||
curl \
|
curl \
|
||||||
bash \
|
bash \
|
||||||
python3 \
|
python3 \
|
||||||
docker.io \
|
podman \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
COPY --from=builder /usr/local/bin/hiy-server /usr/local/bin/hiy-server
|
COPY --from=builder /usr/local/bin/hiy-server /usr/local/bin/hiy-server
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
# HIY — docker compose helpers
|
# HIY — podman compose helpers
|
||||||
# Usage: make <target>
|
# Usage: make <target>
|
||||||
#
|
#
|
||||||
|
# Requires: podman + podman-compose (or Docker with compose plugin as fallback)
|
||||||
|
#
|
||||||
# Default (make up) — auto-detects the host platform.
|
# Default (make up) — auto-detects the host platform.
|
||||||
#
|
#
|
||||||
# Explicit cross-compile targets:
|
# Explicit cross-compile targets:
|
||||||
|
|
@ -9,7 +11,7 @@
|
||||||
# up-armv7 — linux/arm/v7 (Pi 2/3/4 32-bit OS)
|
# up-armv7 — linux/arm/v7 (Pi 2/3/4 32-bit OS)
|
||||||
# up-armv6 — linux/arm/v6 (Pi Zero, Pi 1)
|
# up-armv6 — linux/arm/v6 (Pi Zero, Pi 1)
|
||||||
|
|
||||||
COMPOSE = docker compose
|
COMPOSE = podman compose
|
||||||
BUILD = $(COMPOSE) build
|
BUILD = $(COMPOSE) build
|
||||||
UP = $(COMPOSE) up --build
|
UP = $(COMPOSE) up --build
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,20 @@
|
||||||
# HIY — local development stack
|
# HIY — local development stack
|
||||||
# Run with: docker compose up --build
|
# Run with: podman compose up --build (or: docker compose up --build)
|
||||||
#
|
#
|
||||||
# On a real Pi you would run Caddy as a systemd service; here it runs in Compose
|
# On a real Pi you would run Caddy as a systemd service; here it runs in Compose
|
||||||
# so you can develop without changing the host.
|
# so you can develop without changing the host.
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
|
||||||
# ── Docker socket proxy (unix → TCP) ──────────────────────────────────────
|
# ── Podman socket proxy (unix → TCP) ──────────────────────────────────────
|
||||||
docker-proxy:
|
# Rootful Podman socket: /run/podman/podman.sock
|
||||||
|
# Rootless Podman socket: /run/user/<UID>/podman/podman.sock
|
||||||
|
podman-proxy:
|
||||||
image: alpine/socat
|
image: alpine/socat
|
||||||
command: tcp-listen:2375,fork,reuseaddr unix-connect:/var/run/docker.sock
|
command: tcp-listen:2375,fork,reuseaddr unix-connect:/run/podman/podman.sock
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /run/podman/podman.sock:/run/podman/podman.sock
|
||||||
networks:
|
networks:
|
||||||
- hiy-net
|
- hiy-net
|
||||||
|
|
||||||
|
|
@ -36,12 +38,12 @@ services:
|
||||||
HIY_ADDR: 0.0.0.0:3000
|
HIY_ADDR: 0.0.0.0:3000
|
||||||
HIY_BUILD_SCRIPT: /app/builder/build.sh
|
HIY_BUILD_SCRIPT: /app/builder/build.sh
|
||||||
CADDY_API_URL: http://caddy:2019
|
CADDY_API_URL: http://caddy:2019
|
||||||
DOCKER_HOST: tcp://docker-proxy:2375
|
DOCKER_HOST: tcp://podman-proxy:2375
|
||||||
RUST_LOG: hiy_server=debug,tower_http=info
|
RUST_LOG: hiy_server=debug,tower_http=info
|
||||||
depends_on:
|
depends_on:
|
||||||
caddy:
|
caddy:
|
||||||
condition: service_started
|
condition: service_started
|
||||||
docker-proxy:
|
podman-proxy:
|
||||||
condition: service_started
|
condition: service_started
|
||||||
networks:
|
networks:
|
||||||
- hiy-net
|
- hiy-net
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ pub async fn stop(
|
||||||
Path(id): Path<String>,
|
Path(id): Path<String>,
|
||||||
) -> Result<StatusCode, StatusCode> {
|
) -> Result<StatusCode, StatusCode> {
|
||||||
let name = format!("hiy-{}", id);
|
let name = format!("hiy-{}", id);
|
||||||
let out = tokio::process::Command::new("docker")
|
let out = tokio::process::Command::new("podman")
|
||||||
.args(["stop", &name])
|
.args(["stop", &name])
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
|
|
@ -116,7 +116,7 @@ pub async fn stop(
|
||||||
if out.status.success() {
|
if out.status.success() {
|
||||||
Ok(StatusCode::NO_CONTENT)
|
Ok(StatusCode::NO_CONTENT)
|
||||||
} else {
|
} else {
|
||||||
tracing::warn!("docker stop {}: {}", name, String::from_utf8_lossy(&out.stderr));
|
tracing::warn!("podman stop {}: {}", name, String::from_utf8_lossy(&out.stderr));
|
||||||
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -126,7 +126,7 @@ pub async fn restart(
|
||||||
Path(id): Path<String>,
|
Path(id): Path<String>,
|
||||||
) -> Result<StatusCode, StatusCode> {
|
) -> Result<StatusCode, StatusCode> {
|
||||||
let name = format!("hiy-{}", id);
|
let name = format!("hiy-{}", id);
|
||||||
let out = tokio::process::Command::new("docker")
|
let out = tokio::process::Command::new("podman")
|
||||||
.args(["restart", &name])
|
.args(["restart", &name])
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
|
|
@ -134,7 +134,7 @@ pub async fn restart(
|
||||||
if out.status.success() {
|
if out.status.success() {
|
||||||
Ok(StatusCode::NO_CONTENT)
|
Ok(StatusCode::NO_CONTENT)
|
||||||
} else {
|
} else {
|
||||||
tracing::warn!("docker restart {}: {}", name, String::from_utf8_lossy(&out.stderr));
|
tracing::warn!("podman restart {}: {}", name, String::from_utf8_lossy(&out.stderr));
|
||||||
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ async fn read_sys_stats() -> SysStats {
|
||||||
|
|
||||||
async fn get_container_status(app_id: &str) -> String {
|
async fn get_container_status(app_id: &str) -> String {
|
||||||
let name = format!("hiy-{}", app_id);
|
let name = format!("hiy-{}", app_id);
|
||||||
match tokio::process::Command::new("docker")
|
match tokio::process::Command::new("podman")
|
||||||
.args(["inspect", "--format", "{{.State.Status}}", &name])
|
.args(["inspect", "--format", "{{.State.Status}}", &name])
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue