做了一个启动脚本,原来那个不合适
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
|
name: hermes
|
||||||
namespace: hermes
|
namespace: hermes
|
||||||
spec:
|
spec:
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
type: Recreate
|
type: Recreate
|
||||||
replicas: 1
|
replicas: 1
|
||||||
@@ -16,10 +15,6 @@ spec:
|
|||||||
labels:
|
labels:
|
||||||
app: hermes
|
app: hermes
|
||||||
spec:
|
spec:
|
||||||
securityContext:
|
|
||||||
runAsUser: 10000
|
|
||||||
supplementalGroups:
|
|
||||||
- 1000
|
|
||||||
volumes:
|
volumes:
|
||||||
- name: data
|
- name: data
|
||||||
hostPath:
|
hostPath:
|
||||||
@@ -35,6 +30,10 @@ spec:
|
|||||||
type: DirectoryOrCreate
|
type: DirectoryOrCreate
|
||||||
- name: tmp
|
- name: tmp
|
||||||
emptyDir: {}
|
emptyDir: {}
|
||||||
|
- name: start-sh
|
||||||
|
configMap:
|
||||||
|
name: hermes-start
|
||||||
|
defaultMode: 0555
|
||||||
containers:
|
containers:
|
||||||
- name: gateway
|
- name: gateway
|
||||||
#image: cr.wetofu.me/nousresearch/hermes-agent:v2026.5.16
|
#image: cr.wetofu.me/nousresearch/hermes-agent:v2026.5.16
|
||||||
@@ -43,7 +42,7 @@ spec:
|
|||||||
httpGet:
|
httpGet:
|
||||||
path: /health
|
path: /health
|
||||||
port: 8642
|
port: 8642
|
||||||
initialDelaySeconds: 30
|
initialDelaySeconds: 60
|
||||||
periodSeconds: 10
|
periodSeconds: 10
|
||||||
successThreshold: 1
|
successThreshold: 1
|
||||||
failureThreshold: 3
|
failureThreshold: 3
|
||||||
@@ -58,6 +57,8 @@ spec:
|
|||||||
ports:
|
ports:
|
||||||
- containerPort: 8642
|
- containerPort: 8642
|
||||||
name: gateway
|
name: gateway
|
||||||
|
- containerPort: 9119
|
||||||
|
name: dashboard
|
||||||
args:
|
args:
|
||||||
- gateway
|
- gateway
|
||||||
- run
|
- run
|
||||||
@@ -70,6 +71,16 @@ spec:
|
|||||||
value: "0.0.0.0"
|
value: "0.0.0.0"
|
||||||
- name: API_SERVER_CORS_ORIGINS
|
- name: API_SERVER_CORS_ORIGINS
|
||||||
value: '*'
|
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:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
name: hermes
|
name: hermes
|
||||||
@@ -89,6 +100,9 @@ spec:
|
|||||||
mountPath: /opt/data/workspace/Projects
|
mountPath: /opt/data/workspace/Projects
|
||||||
- name: tmp
|
- name: tmp
|
||||||
mountPath: /tmp
|
mountPath: /tmp
|
||||||
|
- name: start-sh
|
||||||
|
mountPath: /opt/hermes/docker/entrypoint.sh
|
||||||
|
subPath: entrypoint.sh
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
memory: "1Gi"
|
memory: "1Gi"
|
||||||
@@ -96,37 +110,3 @@ spec:
|
|||||||
limits:
|
limits:
|
||||||
memory: "4Gi"
|
memory: "4Gi"
|
||||||
cpu: "2"
|
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
|
# yaml-language-server: $schema=https://json.schemastore.org/kustomization.json
|
||||||
kind: Kustomization
|
kind: Kustomization
|
||||||
namespace: hermes
|
namespace: hermes
|
||||||
|
replicas:
|
||||||
|
- name: hermes
|
||||||
|
count: 1
|
||||||
resources:
|
resources:
|
||||||
- deploy.yaml
|
- deploy.yaml
|
||||||
- services.yaml
|
- services.yaml
|
||||||
@@ -25,3 +28,7 @@ configMapGenerator:
|
|||||||
- config/TELEGRAM_OBSERVE_UNMENTIONED_GROUP_MESSAGES
|
- config/TELEGRAM_OBSERVE_UNMENTIONED_GROUP_MESSAGES
|
||||||
- config/TELEGRAM_REQUIRE_MENTION
|
- config/TELEGRAM_REQUIRE_MENTION
|
||||||
- config/SIYUAN_URL
|
- config/SIYUAN_URL
|
||||||
|
- config/PATH
|
||||||
|
- name: hermes-start
|
||||||
|
files:
|
||||||
|
- config/entrypoint.sh
|
||||||
Reference in New Issue
Block a user