Merge pull request 'fix: feat: publish versioned agent images — compose should use image: not build: (#429)' (#775) from fix/issue-429 into main
This commit is contained in:
commit
250788952f
6 changed files with 100 additions and 18 deletions
64
.woodpecker/publish-images.yml
Normal file
64
.woodpecker/publish-images.yml
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
# .woodpecker/publish-images.yml — Build and push versioned container images
|
||||||
|
# Triggered on tag pushes (e.g. v1.2.3). Builds and pushes:
|
||||||
|
# - ghcr.io/disinto/agents:<tag>
|
||||||
|
# - ghcr.io/disinto/reproduce:<tag>
|
||||||
|
# - ghcr.io/disinto/edge:<tag>
|
||||||
|
#
|
||||||
|
# Requires GHCR_TOKEN secret configured in Woodpecker with push access
|
||||||
|
# to ghcr.io/disinto.
|
||||||
|
|
||||||
|
when:
|
||||||
|
event: tag
|
||||||
|
ref: refs/tags/v*
|
||||||
|
|
||||||
|
clone:
|
||||||
|
git:
|
||||||
|
image: alpine/git
|
||||||
|
commands:
|
||||||
|
- AUTH_URL=$(printf '%s' "$CI_REPO_CLONE_URL" | sed "s|://|://token:$FORGE_TOKEN@|")
|
||||||
|
- git clone --depth 1 "$AUTH_URL" .
|
||||||
|
- git fetch --depth 1 origin "$CI_COMMIT_REF"
|
||||||
|
- git checkout FETCH_HEAD
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: build-and-push-agents
|
||||||
|
image: plugins/docker
|
||||||
|
settings:
|
||||||
|
repo: ghcr.io/disinto/agents
|
||||||
|
registry: ghcr.io
|
||||||
|
dockerfile: docker/agents/Dockerfile
|
||||||
|
context: .
|
||||||
|
tags:
|
||||||
|
- ${CI_COMMIT_TAG}
|
||||||
|
- latest
|
||||||
|
username: disinto
|
||||||
|
password:
|
||||||
|
from_secret: GHCR_TOKEN
|
||||||
|
|
||||||
|
- name: build-and-push-reproduce
|
||||||
|
image: plugins/docker
|
||||||
|
settings:
|
||||||
|
repo: ghcr.io/disinto/reproduce
|
||||||
|
registry: ghcr.io
|
||||||
|
dockerfile: docker/reproduce/Dockerfile
|
||||||
|
context: .
|
||||||
|
tags:
|
||||||
|
- ${CI_COMMIT_TAG}
|
||||||
|
- latest
|
||||||
|
username: disinto
|
||||||
|
password:
|
||||||
|
from_secret: GHCR_TOKEN
|
||||||
|
|
||||||
|
- name: build-and-push-edge
|
||||||
|
image: plugins/docker
|
||||||
|
settings:
|
||||||
|
repo: ghcr.io/disinto/edge
|
||||||
|
registry: ghcr.io
|
||||||
|
dockerfile: docker/edge/Dockerfile
|
||||||
|
context: docker/edge
|
||||||
|
tags:
|
||||||
|
- ${CI_COMMIT_TAG}
|
||||||
|
- latest
|
||||||
|
username: disinto
|
||||||
|
password:
|
||||||
|
from_secret: GHCR_TOKEN
|
||||||
10
bin/disinto
10
bin/disinto
|
|
@ -82,6 +82,7 @@ Init options:
|
||||||
--ci-id <n> Woodpecker CI repo ID (default: 0 = no CI)
|
--ci-id <n> Woodpecker CI repo ID (default: 0 = no CI)
|
||||||
--forge-url <url> Forge base URL (default: http://localhost:3000)
|
--forge-url <url> Forge base URL (default: http://localhost:3000)
|
||||||
--bare Skip compose generation (bare-metal setup)
|
--bare Skip compose generation (bare-metal setup)
|
||||||
|
--build Use local docker build instead of registry images (dev mode)
|
||||||
--yes Skip confirmation prompts
|
--yes Skip confirmation prompts
|
||||||
--rotate-tokens Force regeneration of all bot tokens/passwords (idempotent by default)
|
--rotate-tokens Force regeneration of all bot tokens/passwords (idempotent by default)
|
||||||
|
|
||||||
|
|
@ -652,7 +653,7 @@ disinto_init() {
|
||||||
shift
|
shift
|
||||||
|
|
||||||
# Parse flags
|
# Parse flags
|
||||||
local branch="" repo_root="" ci_id="0" auto_yes=false forge_url_flag="" bare=false rotate_tokens=false
|
local branch="" repo_root="" ci_id="0" auto_yes=false forge_url_flag="" bare=false rotate_tokens=false use_build=false
|
||||||
while [ $# -gt 0 ]; do
|
while [ $# -gt 0 ]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--branch) branch="$2"; shift 2 ;;
|
--branch) branch="$2"; shift 2 ;;
|
||||||
|
|
@ -660,6 +661,7 @@ disinto_init() {
|
||||||
--ci-id) ci_id="$2"; shift 2 ;;
|
--ci-id) ci_id="$2"; shift 2 ;;
|
||||||
--forge-url) forge_url_flag="$2"; shift 2 ;;
|
--forge-url) forge_url_flag="$2"; shift 2 ;;
|
||||||
--bare) bare=true; shift ;;
|
--bare) bare=true; shift ;;
|
||||||
|
--build) use_build=true; shift ;;
|
||||||
--yes) auto_yes=true; shift ;;
|
--yes) auto_yes=true; shift ;;
|
||||||
--rotate-tokens) rotate_tokens=true; shift ;;
|
--rotate-tokens) rotate_tokens=true; shift ;;
|
||||||
*) echo "Unknown option: $1" >&2; exit 1 ;;
|
*) echo "Unknown option: $1" >&2; exit 1 ;;
|
||||||
|
|
@ -743,7 +745,7 @@ p.write_text(text)
|
||||||
local forge_port
|
local forge_port
|
||||||
forge_port=$(printf '%s' "$forge_url" | sed -E 's|.*:([0-9]+)/?$|\1|')
|
forge_port=$(printf '%s' "$forge_url" | sed -E 's|.*:([0-9]+)/?$|\1|')
|
||||||
forge_port="${forge_port:-3000}"
|
forge_port="${forge_port:-3000}"
|
||||||
generate_compose "$forge_port"
|
generate_compose "$forge_port" "$use_build"
|
||||||
generate_agent_docker
|
generate_agent_docker
|
||||||
generate_caddyfile
|
generate_caddyfile
|
||||||
generate_staging_index
|
generate_staging_index
|
||||||
|
|
@ -1412,13 +1414,15 @@ disinto_up() {
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Pre-build: download binaries to docker/agents/bin/ to avoid network calls during docker build
|
# Pre-build: download binaries only when compose uses local build
|
||||||
|
if grep -q '^\s*build:' "$compose_file"; then
|
||||||
echo "── Pre-build: downloading agent binaries ────────────────────────"
|
echo "── Pre-build: downloading agent binaries ────────────────────────"
|
||||||
if ! download_agent_binaries; then
|
if ! download_agent_binaries; then
|
||||||
echo "Error: failed to download agent binaries" >&2
|
echo "Error: failed to download agent binaries" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
# Decrypt secrets to temp .env if SOPS available and .env.enc exists
|
# Decrypt secrets to temp .env if SOPS available and .env.enc exists
|
||||||
local tmp_env=""
|
local tmp_env=""
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,9 @@ RUN chmod +x /entrypoint.sh
|
||||||
|
|
||||||
# Entrypoint runs polling loop directly, dropping to agent user via gosu.
|
# Entrypoint runs polling loop directly, dropping to agent user via gosu.
|
||||||
# All scripts execute as the agent user (UID 1000) while preserving env vars.
|
# All scripts execute as the agent user (UID 1000) while preserving env vars.
|
||||||
|
VOLUME /home/agent/data
|
||||||
|
VOLUME /home/agent/repos
|
||||||
|
|
||||||
WORKDIR /home/agent/disinto
|
WORKDIR /home/agent/disinto
|
||||||
|
|
||||||
ENTRYPOINT ["/entrypoint.sh"]
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
FROM caddy:latest
|
FROM caddy:latest
|
||||||
RUN apk add --no-cache bash jq curl git docker-cli python3 openssh-client autossh
|
RUN apk add --no-cache bash jq curl git docker-cli python3 openssh-client autossh
|
||||||
COPY entrypoint-edge.sh /usr/local/bin/entrypoint-edge.sh
|
COPY entrypoint-edge.sh /usr/local/bin/entrypoint-edge.sh
|
||||||
|
|
||||||
|
VOLUME /data
|
||||||
|
|
||||||
ENTRYPOINT ["bash", "/usr/local/bin/entrypoint-edge.sh"]
|
ENTRYPOINT ["bash", "/usr/local/bin/entrypoint-edge.sh"]
|
||||||
|
|
|
||||||
|
|
@ -7,5 +7,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
RUN useradd -m -u 1000 -s /bin/bash agent
|
RUN useradd -m -u 1000 -s /bin/bash agent
|
||||||
COPY docker/reproduce/entrypoint-reproduce.sh /entrypoint-reproduce.sh
|
COPY docker/reproduce/entrypoint-reproduce.sh /entrypoint-reproduce.sh
|
||||||
RUN chmod +x /entrypoint-reproduce.sh
|
RUN chmod +x /entrypoint-reproduce.sh
|
||||||
|
VOLUME /home/agent/data
|
||||||
|
VOLUME /home/agent/repos
|
||||||
|
|
||||||
WORKDIR /home/agent
|
WORKDIR /home/agent
|
||||||
ENTRYPOINT ["/entrypoint-reproduce.sh"]
|
ENTRYPOINT ["/entrypoint-reproduce.sh"]
|
||||||
|
|
|
||||||
|
|
@ -100,9 +100,7 @@ _generate_local_model_services() {
|
||||||
cat >> "$temp_file" <<EOF
|
cat >> "$temp_file" <<EOF
|
||||||
|
|
||||||
agents-${service_name}:
|
agents-${service_name}:
|
||||||
build:
|
image: ghcr.io/disinto/agents:\${DISINTO_IMAGE_TAG:-latest}
|
||||||
context: .
|
|
||||||
dockerfile: docker/agents/Dockerfile
|
|
||||||
container_name: disinto-agents-${service_name}
|
container_name: disinto-agents-${service_name}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
security_opt:
|
security_opt:
|
||||||
|
|
@ -233,6 +231,7 @@ for name, config in agents.items():
|
||||||
# to materialize a working stack on a fresh checkout.
|
# to materialize a working stack on a fresh checkout.
|
||||||
_generate_compose_impl() {
|
_generate_compose_impl() {
|
||||||
local forge_port="${1:-3000}"
|
local forge_port="${1:-3000}"
|
||||||
|
local use_build="${2:-false}"
|
||||||
local compose_file="${FACTORY_ROOT}/docker-compose.yml"
|
local compose_file="${FACTORY_ROOT}/docker-compose.yml"
|
||||||
|
|
||||||
# Check if compose file already exists
|
# Check if compose file already exists
|
||||||
|
|
@ -324,9 +323,7 @@ services:
|
||||||
- woodpecker
|
- woodpecker
|
||||||
|
|
||||||
agents:
|
agents:
|
||||||
build:
|
image: ghcr.io/disinto/agents:${DISINTO_IMAGE_TAG:-latest}
|
||||||
context: .
|
|
||||||
dockerfile: docker/agents/Dockerfile
|
|
||||||
container_name: disinto-agents
|
container_name: disinto-agents
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
security_opt:
|
security_opt:
|
||||||
|
|
@ -340,6 +337,9 @@ services:
|
||||||
- ${HOME}/.ssh:/home/agent/.ssh:ro
|
- ${HOME}/.ssh:/home/agent/.ssh:ro
|
||||||
- ${HOME}/.config/sops/age:/home/agent/.config/sops/age:ro
|
- ${HOME}/.config/sops/age:/home/agent/.config/sops/age:ro
|
||||||
- woodpecker-data:/woodpecker-data:ro
|
- woodpecker-data:/woodpecker-data:ro
|
||||||
|
- ./projects:/home/agent/disinto/projects:ro
|
||||||
|
- ./.env:/home/agent/disinto/.env:ro
|
||||||
|
- ./state:/home/agent/disinto/state
|
||||||
environment:
|
environment:
|
||||||
FORGE_URL: http://forgejo:3000
|
FORGE_URL: http://forgejo:3000
|
||||||
FORGE_REPO: ${FORGE_REPO:-disinto-admin/disinto}
|
FORGE_REPO: ${FORGE_REPO:-disinto-admin/disinto}
|
||||||
|
|
@ -382,9 +382,7 @@ services:
|
||||||
- disinto-net
|
- disinto-net
|
||||||
|
|
||||||
runner:
|
runner:
|
||||||
build:
|
image: ghcr.io/disinto/agents:${DISINTO_IMAGE_TAG:-latest}
|
||||||
context: .
|
|
||||||
dockerfile: docker/agents/Dockerfile
|
|
||||||
profiles: ["vault"]
|
profiles: ["vault"]
|
||||||
security_opt:
|
security_opt:
|
||||||
- apparmor=unconfined
|
- apparmor=unconfined
|
||||||
|
|
@ -405,7 +403,7 @@ services:
|
||||||
# Edge proxy — reverse proxy to Forgejo, Woodpecker, and staging
|
# Edge proxy — reverse proxy to Forgejo, Woodpecker, and staging
|
||||||
# Serves on ports 80/443, routes based on path
|
# Serves on ports 80/443, routes based on path
|
||||||
edge:
|
edge:
|
||||||
build: ./docker/edge
|
image: ghcr.io/disinto/edge:${DISINTO_IMAGE_TAG:-latest}
|
||||||
container_name: disinto-edge
|
container_name: disinto-edge
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
security_opt:
|
security_opt:
|
||||||
|
|
@ -573,6 +571,13 @@ COMPOSEEOF
|
||||||
sed -i "s|CLAUDE_BIN_PLACEHOLDER|/usr/local/bin/claude|g" "$compose_file"
|
sed -i "s|CLAUDE_BIN_PLACEHOLDER|/usr/local/bin/claude|g" "$compose_file"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# In build mode, replace image: with build: for locally-built images
|
||||||
|
if [ "$use_build" = true ]; then
|
||||||
|
sed -i 's|^\( agents:\)|\1|' "$compose_file"
|
||||||
|
sed -i '/^ image: ghcr\.io\/disinto\/agents:/{s|image: ghcr\.io/disinto/agents:.*|build:\n context: .\n dockerfile: docker/agents/Dockerfile|}' "$compose_file"
|
||||||
|
sed -i '/^ image: ghcr\.io\/disinto\/edge:/{s|image: ghcr\.io/disinto/edge:.*|build: ./docker/edge|}' "$compose_file"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Created: ${compose_file}"
|
echo "Created: ${compose_file}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue