做了一个启动脚本,原来那个不合适
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
#!/bin/bash
|
||||
# Docker/Podman entrypoint: bootstrap config files into the mounted volume, then run hermes.
|
||||
set -e
|
||||
|
||||
HERMES_HOME="${HERMES_HOME:-/opt/data}"
|
||||
INSTALL_DIR="/opt/hermes"
|
||||
|
||||
# 这个脚本太烂了,我重新写一个逻辑好了
|
||||
# 原本的脚本根本没有考虑用户可以自行修改目录属主的问题
|
||||
if [ "$(id -u)" = "0" ]; then
|
||||
groupadd -g ${HERMES_UID} runner
|
||||
useradd -u ${HERMES_UID} -g ${HERMES_UID} -d ${HERMES_HOME} runner
|
||||
echo "!!! Changing ${INSTALL_DIR}/.venv to ${HERMES_UID}:${HERMES_GID}"
|
||||
chown -R ${HERMES_UID}:${HERMES_GID} "${INSTALL_DIR}/.venv" || exit 1
|
||||
# Drop root privilege
|
||||
|
||||
echo "Dropping root privileges"
|
||||
exec gosu ${HERMES_UID} "$0" "$@"
|
||||
fi
|
||||
|
||||
# --- Running as hermes from here ---
|
||||
source "${INSTALL_DIR}/.venv/bin/activate"
|
||||
|
||||
# 这狗*的环境变量!
|
||||
export PATH=${HERMES_HOME}/home/.local/bin:${HERMES_HOME}/.local/bin:${INSTALL_DIR}/bin:${PATH}
|
||||
|
||||
# Create essential directory structure. Cache and platform directories
|
||||
# (cache/images, cache/audio, platforms/whatsapp, etc.) are created on
|
||||
# demand by the application — don't pre-create them here so new installs
|
||||
# get the consolidated layout from get_hermes_dir().
|
||||
# The "home/" subdirectory is a per-profile HOME for subprocesses (git,
|
||||
# ssh, gh, npm …). Without it those tools write to /root which is
|
||||
# ephemeral and shared across profiles. See issue #4426.
|
||||
mkdir -p "$HERMES_HOME"/{cron,sessions,logs,hooks,memories,skills,skins,plans,workspace,home}
|
||||
|
||||
# .env
|
||||
if [ ! -f "$HERMES_HOME/.env" ]; then
|
||||
cp "$INSTALL_DIR/.env.example" "$HERMES_HOME/.env"
|
||||
fi
|
||||
|
||||
# config.yaml
|
||||
if [ ! -f "$HERMES_HOME/config.yaml" ]; then
|
||||
cp "$INSTALL_DIR/cli-config.yaml.example" "$HERMES_HOME/config.yaml"
|
||||
fi
|
||||
|
||||
# SOUL.md
|
||||
if [ ! -f "$HERMES_HOME/SOUL.md" ]; then
|
||||
cp "$INSTALL_DIR/docker/SOUL.md" "$HERMES_HOME/SOUL.md"
|
||||
fi
|
||||
|
||||
# auth.json: bootstrap from env on first boot only. Used by orchestrators
|
||||
# (e.g. provisioning a Hermes VPS from an account-management service) that
|
||||
# need to seed the OAuth refresh credential non-interactively, instead of
|
||||
# walking the user through `hermes setup` + the device-flow login dance.
|
||||
# Subsequent token rotations write back to the same file, which lives on a
|
||||
# persistent volume — so this env var is consumed exactly once at first
|
||||
# boot. The `[ ! -f ... ]` guard is critical: without it, a container
|
||||
# restart would clobber a rotated refresh token with the now-stale value
|
||||
# the orchestrator originally seeded.
|
||||
if [ ! -f "$HERMES_HOME/auth.json" ] && [ -n "$HERMES_AUTH_JSON_BOOTSTRAP" ]; then
|
||||
printf '%s' "$HERMES_AUTH_JSON_BOOTSTRAP" > "$HERMES_HOME/auth.json"
|
||||
chmod 600 "$HERMES_HOME/auth.json"
|
||||
fi
|
||||
|
||||
# Sync bundled skills (manifest-based so user edits are preserved)
|
||||
if [ -d "$INSTALL_DIR/skills" ]; then
|
||||
python3 "$INSTALL_DIR/tools/skills_sync.py"
|
||||
fi
|
||||
|
||||
# Optionally start `hermes dashboard` as a side-process.
|
||||
#
|
||||
# Toggled by HERMES_DASHBOARD=1 (also accepts "true"/"yes", case-insensitive).
|
||||
# Host/port/TUI can be overridden via:
|
||||
# HERMES_DASHBOARD_HOST (default 0.0.0.0 — exposed outside the container)
|
||||
# HERMES_DASHBOARD_PORT (default 9119, matches `hermes dashboard` default)
|
||||
# HERMES_DASHBOARD_TUI (already honored by `hermes dashboard` itself)
|
||||
#
|
||||
# The dashboard is a long-lived server. We background it *before* the final
|
||||
# `exec hermes "$@"` so the user's chosen foreground command (chat, gateway,
|
||||
# sleep infinity, …) remains PID-of-interest for the container runtime. When
|
||||
# the container stops the whole process tree is torn down, so no explicit
|
||||
# cleanup is needed.
|
||||
case "${HERMES_DASHBOARD:-}" in
|
||||
1|true|TRUE|True|yes|YES|Yes)
|
||||
dash_host="${HERMES_DASHBOARD_HOST:-0.0.0.0}"
|
||||
dash_port="${HERMES_DASHBOARD_PORT:-9119}"
|
||||
dash_args=(--host "$dash_host" --port "$dash_port" --no-open)
|
||||
# Binding to anything other than localhost requires --insecure — the
|
||||
# dashboard refuses otherwise because it exposes API keys. Inside a
|
||||
# container this is the expected deployment (host reaches it via
|
||||
# published port), so opt in automatically.
|
||||
if [ "$dash_host" != "127.0.0.1" ] && [ "$dash_host" != "localhost" ]; then
|
||||
dash_args+=(--insecure)
|
||||
fi
|
||||
echo "Starting hermes dashboard on ${dash_host}:${dash_port} (background)"
|
||||
# Prefix dashboard output so it's distinguishable from the main
|
||||
# process in `docker logs`. stdbuf keeps the pipe line-buffered.
|
||||
(
|
||||
stdbuf -oL -eL hermes dashboard "${dash_args[@]}" 2>&1 \
|
||||
| sed -u 's/^/[dashboard] /'
|
||||
) &
|
||||
;;
|
||||
esac
|
||||
|
||||
# Final exec: two supported invocation patterns.
|
||||
#
|
||||
# docker run <image> -> exec `hermes` with no args (legacy default)
|
||||
# docker run <image> chat -q "..." -> exec `hermes chat -q "..."` (legacy wrap)
|
||||
# docker run <image> sleep infinity -> exec `sleep infinity` directly
|
||||
# docker run <image> bash -> exec `bash` directly
|
||||
#
|
||||
# If the first positional arg resolves to an executable on PATH, we assume the
|
||||
# caller wants to run it directly (needed by the launcher which runs long-lived
|
||||
# `sleep infinity` sandbox containers — see tools/environments/docker.py).
|
||||
# Otherwise we treat the args as a hermes subcommand and wrap with `hermes`,
|
||||
# preserving the documented `docker run <image> <subcommand>` behavior.
|
||||
if [ $# -gt 0 ] && command -v "$1" >/dev/null 2>&1; then
|
||||
exec "$@"
|
||||
fi
|
||||
exec hermes "$@"
|
||||
+20
-40
@@ -4,7 +4,6 @@ metadata:
|
||||
name: hermes
|
||||
namespace: hermes
|
||||
spec:
|
||||
|
||||
strategy:
|
||||
type: Recreate
|
||||
replicas: 1
|
||||
@@ -16,10 +15,6 @@ spec:
|
||||
labels:
|
||||
app: hermes
|
||||
spec:
|
||||
securityContext:
|
||||
runAsUser: 10000
|
||||
supplementalGroups:
|
||||
- 1000
|
||||
volumes:
|
||||
- name: data
|
||||
hostPath:
|
||||
@@ -35,6 +30,10 @@ spec:
|
||||
type: DirectoryOrCreate
|
||||
- name: tmp
|
||||
emptyDir: {}
|
||||
- name: start-sh
|
||||
configMap:
|
||||
name: hermes-start
|
||||
defaultMode: 0555
|
||||
containers:
|
||||
- name: gateway
|
||||
#image: cr.wetofu.me/nousresearch/hermes-agent:v2026.5.16
|
||||
@@ -43,7 +42,7 @@ spec:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8642
|
||||
initialDelaySeconds: 30
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 10
|
||||
successThreshold: 1
|
||||
failureThreshold: 3
|
||||
@@ -58,6 +57,8 @@ spec:
|
||||
ports:
|
||||
- containerPort: 8642
|
||||
name: gateway
|
||||
- containerPort: 9119
|
||||
name: dashboard
|
||||
args:
|
||||
- gateway
|
||||
- run
|
||||
@@ -70,6 +71,16 @@ spec:
|
||||
value: "0.0.0.0"
|
||||
- name: API_SERVER_CORS_ORIGINS
|
||||
value: '*'
|
||||
- name: HERMES_UID
|
||||
value: '1000'
|
||||
- name: HERMES_GID
|
||||
value: '1000'
|
||||
- name: HERMES_DASHBOARD
|
||||
value: 'true'
|
||||
- name: HERMES_DASHBOARD_HOST
|
||||
value: '::'
|
||||
- name: HERMES_DASHBOARD_HOST
|
||||
value: '9119'
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: hermes
|
||||
@@ -89,6 +100,9 @@ spec:
|
||||
mountPath: /opt/data/workspace/Projects
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
- name: start-sh
|
||||
mountPath: /opt/hermes/docker/entrypoint.sh
|
||||
subPath: entrypoint.sh
|
||||
resources:
|
||||
requests:
|
||||
memory: "1Gi"
|
||||
@@ -96,37 +110,3 @@ spec:
|
||||
limits:
|
||||
memory: "4Gi"
|
||||
cpu: "2"
|
||||
- name: dashboard
|
||||
image: image
|
||||
args:
|
||||
- dashboard
|
||||
ports:
|
||||
- containerPort: 9119
|
||||
name: dashboard
|
||||
env:
|
||||
- name: TZ
|
||||
value: Asia/Shanghai
|
||||
- name: GATEWAY_HEALTH_URL
|
||||
value: localhost:8642
|
||||
- name: GATEWAY_HEALTH_TIMEOUT
|
||||
value: "3"
|
||||
- name: HERMES_DASHBOARD_HOST
|
||||
value: "::"
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: hermes
|
||||
optional: true
|
||||
- configMapRef:
|
||||
name: hermes
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /opt/data
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "512Mi"
|
||||
cpu: "500m"
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# yaml-language-server: $schema=https://json.schemastore.org/kustomization.json
|
||||
kind: Kustomization
|
||||
namespace: hermes
|
||||
replicas:
|
||||
- name: hermes
|
||||
count: 1
|
||||
resources:
|
||||
- deploy.yaml
|
||||
- services.yaml
|
||||
@@ -25,3 +28,7 @@ configMapGenerator:
|
||||
- config/TELEGRAM_OBSERVE_UNMENTIONED_GROUP_MESSAGES
|
||||
- config/TELEGRAM_REQUIRE_MENTION
|
||||
- config/SIYUAN_URL
|
||||
- config/PATH
|
||||
- name: hermes-start
|
||||
files:
|
||||
- config/entrypoint.sh
|
||||
Reference in New Issue
Block a user