Add Gitea container image workflow
Some checks failed
Container Image / build-and-push (push) Failing after 12s
Some checks failed
Container Image / build-and-push (push) Failing after 12s
This commit is contained in:
@@ -13,6 +13,8 @@ build/
|
|||||||
/data/
|
/data/
|
||||||
/logs/
|
/logs/
|
||||||
.git/
|
.git/
|
||||||
|
.gitea/
|
||||||
|
.github/
|
||||||
.claude/
|
.claude/
|
||||||
.playwright-mcp/
|
.playwright-mcp/
|
||||||
.pytest_cache/
|
.pytest_cache/
|
||||||
|
|||||||
71
.gitea/workflows/container-image.yml
Normal file
71
.gitea/workflows/container-image.yml
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
name: Container Image
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: container-image-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-push:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
REGISTRY: git.wilkensxl.de
|
||||||
|
IMAGE_NAME: odysseus
|
||||||
|
FALLBACK_OWNER: mrsphay
|
||||||
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
||||||
|
|
||||||
|
- name: Check Docker
|
||||||
|
run: docker version
|
||||||
|
|
||||||
|
- name: Build and push image
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
registry_token="${REGISTRY_TOKEN:-${GITEA_TOKEN:-}}"
|
||||||
|
if [ -z "${registry_token}" ]; then
|
||||||
|
echo "REGISTRY_TOKEN or GITEA_TOKEN is required to publish ${REGISTRY}/${FALLBACK_OWNER}/${IMAGE_NAME}."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
owner="${GITHUB_REPOSITORY_OWNER:-${FALLBACK_OWNER}}"
|
||||||
|
owner="$(printf '%s' "${owner}" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
registry_user="${GITHUB_ACTOR:-${owner}}"
|
||||||
|
image="${REGISTRY}/${owner}/${IMAGE_NAME}"
|
||||||
|
short_sha="$(printf '%s' "${GITHUB_SHA}" | cut -c1-7)"
|
||||||
|
ref_name="${GITHUB_REF_NAME:-dev}"
|
||||||
|
ref_tag="$(printf '%s' "${ref_name}" | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9._-' '-' | sed 's/^-//; s/-$//')"
|
||||||
|
|
||||||
|
echo "${registry_token}" | docker login "${REGISTRY}" --username "${registry_user}" --password-stdin
|
||||||
|
|
||||||
|
docker build --pull \
|
||||||
|
--tag "${image}:sha-${short_sha}" \
|
||||||
|
--tag "${image}:${ref_tag}" \
|
||||||
|
--tag "${image}:latest" \
|
||||||
|
.
|
||||||
|
|
||||||
|
docker push "${image}:sha-${short_sha}"
|
||||||
|
docker push "${image}:${ref_tag}"
|
||||||
|
docker push "${image}:latest"
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "Published image tags:"
|
||||||
|
echo "- ${image}:latest"
|
||||||
|
echo "- ${image}:${ref_tag}"
|
||||||
|
echo "- ${image}:sha-${short_sha}"
|
||||||
|
} >> "${GITHUB_STEP_SUMMARY}"
|
||||||
145
docker-compose.dockge.yml
Normal file
145
docker-compose.dockge.yml
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
services:
|
||||||
|
odysseus:
|
||||||
|
image: ${ODYSSEUS_IMAGE:-git.wilkensxl.de/mrsphay/odysseus:latest}
|
||||||
|
ports:
|
||||||
|
- "${APP_BIND:-127.0.0.1}:${APP_PORT:-7000}:7000"
|
||||||
|
volumes:
|
||||||
|
- ./data:/app/data:z
|
||||||
|
- ./logs:/app/logs:z
|
||||||
|
# Cookbook remote-server SSH identity. Odysseus can generate a key here;
|
||||||
|
# add the shown public key to each remote server's authorized_keys.
|
||||||
|
- ./data/ssh:/app/.ssh:z
|
||||||
|
# Cookbook local model cache. Inside Docker, "Local" means the Odysseus
|
||||||
|
# container, so persist its HuggingFace cache under ./data/huggingface.
|
||||||
|
- ./data/huggingface:/app/.cache/huggingface:z
|
||||||
|
# Cookbook-installed Python CLIs/packages (vLLM, llama-cpp-python, etc.)
|
||||||
|
# land under /app/.local for the odysseus user. Persist them so a
|
||||||
|
# container recreate does not silently remove installed serve engines.
|
||||||
|
- ./data/local:/app/.local:z
|
||||||
|
extra_hosts:
|
||||||
|
# Lets the container reach local services on the Docker host, including
|
||||||
|
# Ollama at http://host.docker.internal:11434.
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
|
environment:
|
||||||
|
- LLM_HOST=${LLM_HOST:-localhost}
|
||||||
|
- LLM_HOSTS=${LLM_HOSTS:-}
|
||||||
|
- OPENAI_API_KEY=${OPENAI_API_KEY:-}
|
||||||
|
- OLLAMA_BASE_URL=${OLLAMA_BASE_URL:-}
|
||||||
|
- RESEARCH_LLM_ENDPOINT=${RESEARCH_LLM_ENDPOINT:-}
|
||||||
|
- HF_TOKEN=${HF_TOKEN:-}
|
||||||
|
- HUGGING_FACE_HUB_TOKEN=${HUGGING_FACE_HUB_TOKEN:-}
|
||||||
|
- SEARXNG_INSTANCE=http://searxng:8080
|
||||||
|
- CHROMADB_HOST=chromadb
|
||||||
|
- CHROMADB_PORT=8000
|
||||||
|
- DATABASE_URL=${DATABASE_URL:-sqlite:///./data/app.db}
|
||||||
|
- AUTH_ENABLED=${AUTH_ENABLED:-true}
|
||||||
|
- LOCALHOST_BYPASS=${LOCALHOST_BYPASS:-false}
|
||||||
|
- ODYSSEUS_ADMIN_USER=${ODYSSEUS_ADMIN_USER:-admin}
|
||||||
|
- ODYSSEUS_ADMIN_PASSWORD=${ODYSSEUS_ADMIN_PASSWORD:-}
|
||||||
|
- ALLOWED_ORIGINS=${ALLOWED_ORIGINS:-http://localhost,http://127.0.0.1}
|
||||||
|
- SECURE_COOKIES=${SECURE_COOKIES:-false}
|
||||||
|
- EMBEDDING_URL=${EMBEDDING_URL:-}
|
||||||
|
- EMBEDDING_MODEL=${EMBEDDING_MODEL:-}
|
||||||
|
- FASTEMBED_MODEL=${FASTEMBED_MODEL:-sentence-transformers/all-MiniLM-L6-v2}
|
||||||
|
- FASTEMBED_CACHE_PATH=${FASTEMBED_CACHE_PATH:-}
|
||||||
|
- CLEANUP_INTERVAL_HOURS=${CLEANUP_INTERVAL_HOURS:-24}
|
||||||
|
- ODYSSEUS_INPROCESS_POLLERS=${ODYSSEUS_INPROCESS_POLLERS:-1}
|
||||||
|
- ODYSSEUS_INPROCESS_TASKS=${ODYSSEUS_INPROCESS_TASKS:-1}
|
||||||
|
- ODYSSEUS_SCRIPT_HOST=${ODYSSEUS_SCRIPT_HOST:-localhost}
|
||||||
|
- DATA_BRAVE_API_KEY=${DATA_BRAVE_API_KEY:-}
|
||||||
|
- GOOGLE_API_KEY=${GOOGLE_API_KEY:-}
|
||||||
|
- GOOGLE_PSE_CX=${GOOGLE_PSE_CX:-}
|
||||||
|
- TAVILY_API_KEY=${TAVILY_API_KEY:-}
|
||||||
|
- SERPER_API_KEY=${SERPER_API_KEY:-}
|
||||||
|
# PUID / PGID — the user/group the container drops to before
|
||||||
|
# running uvicorn (entrypoint also chowns /app/data + /app/logs
|
||||||
|
# to match, so bind-mounted files stay editable from the host).
|
||||||
|
# 1000 is the default first user on most Linux installs. If your
|
||||||
|
# host user has a different id, override here or via .env, e.g.:
|
||||||
|
# PUID=1001
|
||||||
|
# PGID=1001
|
||||||
|
# Find yours with: id -u / id -g
|
||||||
|
- PUID=${PUID:-1000}
|
||||||
|
- PGID=${PGID:-1000}
|
||||||
|
depends_on:
|
||||||
|
searxng:
|
||||||
|
condition: service_healthy
|
||||||
|
chromadb:
|
||||||
|
condition: service_started
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
chromadb:
|
||||||
|
image: docker.io/chromadb/chroma:latest
|
||||||
|
ports:
|
||||||
|
- "${CHROMADB_BIND:-127.0.0.1}:8100:8000"
|
||||||
|
volumes:
|
||||||
|
- chromadb-data:/chroma/chroma
|
||||||
|
environment:
|
||||||
|
- ANONYMIZED_TELEMETRY=FALSE
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
searxng:
|
||||||
|
# Pinned, not :latest — odysseus waits on searxng's healthcheck
|
||||||
|
# (depends_on: condition: service_healthy), so a broken upstream `latest`
|
||||||
|
# tag blocks the whole app from starting. 2026.6.2 crashes on boot with
|
||||||
|
# `KeyError: 'default_doi_resolver'`, failing the healthcheck (issue #1414).
|
||||||
|
# Bump this deliberately after verifying a newer tag boots clean.
|
||||||
|
image: docker.io/searxng/searxng:2026.5.31-7159b8aed
|
||||||
|
entrypoint:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
set -eu
|
||||||
|
if [ ! -s /etc/searxng/settings.yml ] || grep -q 'odysseus-local-searxng-json-2026-05-30\|__SEARXNG_SECRET__' /etc/searxng/settings.yml; then
|
||||||
|
secret="$${SEARXNG_SECRET:-}"
|
||||||
|
if [ -z "$$secret" ]; then
|
||||||
|
secret="$$(python -c 'import secrets; print(secrets.token_urlsafe(48))')"
|
||||||
|
fi
|
||||||
|
sed "s|__SEARXNG_SECRET__|$$secret|g" /tmp/searxng-settings.yml.template > /etc/searxng/settings.yml
|
||||||
|
fi
|
||||||
|
exec /usr/local/searxng/entrypoint.sh
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:8080:8080"
|
||||||
|
volumes:
|
||||||
|
- searxng-data:/etc/searxng
|
||||||
|
- ./config/searxng/settings.yml:/tmp/searxng-settings.yml.template:ro,z
|
||||||
|
environment:
|
||||||
|
- SEARXNG_BASE_URL=http://localhost:8080/
|
||||||
|
- SEARXNG_SECRET=${SEARXNG_SECRET:-}
|
||||||
|
# The official searxng image runs as the non-root `searxng` user, but its
|
||||||
|
# entrypoint still needs to chown /etc/searxng on first boot, drop privs via
|
||||||
|
# su-exec, and (with our wrapper above) write settings.yml into the named
|
||||||
|
# volume. Without these capabilities the wrapper aborts at the redirection
|
||||||
|
# with EACCES and the container fails its healthcheck with permission
|
||||||
|
# errors during setup. Mirrors the cap set recommended by the upstream
|
||||||
|
# searxng-docker compose file. See issue #721.
|
||||||
|
cap_drop:
|
||||||
|
- ALL
|
||||||
|
cap_add:
|
||||||
|
- CHOWN
|
||||||
|
- SETGID
|
||||||
|
- SETUID
|
||||||
|
- DAC_OVERRIDE
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "python -c \"import urllib.request; urllib.request.urlopen('http://localhost:8080/', timeout=5).read(1)\""]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 6s
|
||||||
|
retries: 20
|
||||||
|
start_period: 10s
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
ntfy:
|
||||||
|
image: docker.io/binwiederhier/ntfy
|
||||||
|
command: serve
|
||||||
|
ports:
|
||||||
|
- "${NTFY_BIND:-127.0.0.1}:8091:80"
|
||||||
|
volumes:
|
||||||
|
- ntfy-cache:/var/cache/ntfy
|
||||||
|
environment:
|
||||||
|
- NTFY_BASE_URL=${NTFY_BASE_URL:-http://localhost:8091}
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
searxng-data:
|
||||||
|
chromadb-data:
|
||||||
|
ntfy-cache:
|
||||||
Reference in New Issue
Block a user