feat: deploy-node.sh also deploys the Backend and migrates old probe.json [CI SKIP]
This commit is contained in:
1 parent
a9f562441f
commit
b4b50c636f
2 files changed
+69
-11
No files matched your search
+3
-1
@@ -213,7 +213,9 @@ OpenWrt 默认不带 OpenSSL:`opkg install libopenssl3`(较新的快照和 2
|
|||||||
# 首次部署(需要 root;脚本和 packaging/ 里的 systemd/、update/ 放在一起)
|
# 首次部署(需要 root;脚本和 packaging/ 里的 systemd/、update/ 放在一起)
|
||||||
sudo sh deploy-node.sh agent --image-repo registry.oeo.one/moshiro/moshiro-agent --server https://<backend> --join <token> --name <name>
|
sudo sh deploy-node.sh agent --image-repo registry.oeo.one/moshiro/moshiro-agent --server https://<backend> --join <token> --name <name>
|
||||||
sudo sh deploy-node.sh probe --image-repo registry.oeo.one/moshiro/moshiro-probe --server https://<backend> --join <probe 令牌> --name <name>
|
sudo sh deploy-node.sh probe --image-repo registry.oeo.one/moshiro/moshiro-probe --server https://<backend> --join <probe 令牌> --name <name>
|
||||||
# 之后更新节点:不带参数
|
# Backend(只支持 Podman,更新策略固定为管理端确认;--port 默认 29181,环境文件写在 /etc/moshiro/backend.env,已有的不覆盖)
|
||||||
|
sudo sh deploy-node.sh backend --channel dev --admin-password '<密码>' --public-url https://<面板域名>
|
||||||
|
# 之后更新:不带参数(旧版 Probe 的 probe.json 没有 fleet 段,加上 --server --join --name 重新运行即可,旧文件备份为 probe.json.old)
|
||||||
sudo sh deploy-node.sh agent
|
sudo sh deploy-node.sh agent
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,28 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# 部署或更新容器节点(Agent、Probe)。可以重复运行:每次都会拉取镜像、把配置迁移到当前版本需要的样子、
|
# 部署或更新容器服务(Backend、Agent、Probe)。可以重复运行:每次都会拉取镜像、把配置迁移到当前版本需要的样子、
|
||||||
# 重新安装单元和更新器,然后重启节点;已有的身份和配置不会被覆盖。
|
# 重新安装单元和更新器,然后重启节点;已有的身份和配置不会被覆盖。
|
||||||
#
|
#
|
||||||
# 首次部署 Agent:sudo sh deploy-node.sh agent --image-repo REPO --server https://panel --join jt_xxx --name hk-1
|
# 首次部署 Agent:sudo sh deploy-node.sh agent --image-repo REPO --server https://panel --join jt_xxx --name hk-1
|
||||||
# 首次部署 Probe:sudo sh deploy-node.sh probe --image-repo REPO --server https://panel --join jt_xxx --name home-1
|
# 首次部署 Probe:sudo sh deploy-node.sh probe --image-repo REPO --server https://panel --join jt_xxx --name home-1
|
||||||
|
# 首次部署 Backend:sudo sh deploy-node.sh backend --channel dev --admin-password '…' [--public-url https://panel] [--port 29181]
|
||||||
# 更新(配置迁移、单元和更新器、镜像):sudo sh deploy-node.sh agent (其余参数沿用上次的更新器配置)
|
# 更新(配置迁移、单元和更新器、镜像):sudo sh deploy-node.sh agent (其余参数沿用上次的更新器配置)
|
||||||
|
# 旧版 Probe(probe.json 里没有 fleet 段):加上 --server --join --name 重新运行即可,旧文件备份为 probe.json.old
|
||||||
#
|
#
|
||||||
|
# Backend 只支持 Podman,更新策略固定为 manual(管理端确认),监听宿主网络的 --port。
|
||||||
# 需要 root、systemd,以及 Podman 或 Docker;脚本要和 packaging/ 里的 systemd/、update/ 放在一起。
|
# 需要 root、systemd,以及 Podman 或 Docker;脚本要和 packaging/ 里的 systemd/、update/ 放在一起。
|
||||||
# rootless Podman 见 docs/deployment.md。
|
# rootless Podman 见 docs/deployment.md。
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
echo "usage: deploy-node.sh <agent|probe> [--engine podman|docker] [--image-repo R] [--tag T] [--image REF]" >&2
|
echo "usage: deploy-node.sh <agent|probe|backend> [--engine podman|docker] [--image-repo R] [--tag T] [--image REF]" >&2
|
||||||
echo " [--server URL --join TOKEN --name NAME] [--policy auto|manual] [--authfile F]" >&2
|
echo " [--server URL --join TOKEN --name NAME] [--policy auto|manual] [--authfile F]" >&2
|
||||||
|
echo " backend: [--channel dev|release] [--port N] [--admin-user U] [--admin-password P] [--public-url URL]" >&2
|
||||||
exit 2
|
exit 2
|
||||||
}
|
}
|
||||||
|
|
||||||
ROLE="${1:-}"; shift || true
|
ROLE="${1:-}"; shift || true
|
||||||
case "$ROLE" in agent|probe) ;; *) usage ;; esac
|
case "$ROLE" in agent|probe|backend) ;; *) usage ;; esac
|
||||||
ENGINE=""; REPO=""; TAG=latest; IMAGE=""; SERVER=""; JOIN=""; NAME=""; POLICY=""; AUTHFILE=""
|
ENGINE=""; REPO=""; TAG=latest; IMAGE=""; SERVER=""; JOIN=""; NAME=""; POLICY=""; AUTHFILE=""; CHANNEL=""; PORT=""; ADMIN_USER=""; ADMIN_PASSWORD=""; PUBLIC_URL=""
|
||||||
while [ $# -gt 0 ]; do
|
while [ $# -gt 0 ]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--engine) ENGINE="$2"; shift 2 ;;
|
--engine) ENGINE="$2"; shift 2 ;;
|
||||||
@@ -30,6 +34,11 @@ while [ $# -gt 0 ]; do
|
|||||||
--name) NAME="$2"; shift 2 ;;
|
--name) NAME="$2"; shift 2 ;;
|
||||||
--policy) POLICY="$2"; shift 2 ;;
|
--policy) POLICY="$2"; shift 2 ;;
|
||||||
--authfile) AUTHFILE="$2"; shift 2 ;;
|
--authfile) AUTHFILE="$2"; shift 2 ;;
|
||||||
|
--channel) CHANNEL="$2"; shift 2 ;;
|
||||||
|
--port) PORT="$2"; shift 2 ;;
|
||||||
|
--admin-user) ADMIN_USER="$2"; shift 2 ;;
|
||||||
|
--admin-password) ADMIN_PASSWORD="$2"; shift 2 ;;
|
||||||
|
--public-url) PUBLIC_URL="$2"; shift 2 ;;
|
||||||
*) usage ;;
|
*) usage ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
@@ -46,19 +55,28 @@ conf_get() { [ -r "$CONF" ] && sed -n "s/^$1='\\(.*\\)'\$/\\1/p" "$CONF" | head
|
|||||||
[ -n "$POLICY" ] || POLICY="$(conf_get POLICY)"
|
[ -n "$POLICY" ] || POLICY="$(conf_get POLICY)"
|
||||||
[ -n "$AUTHFILE" ] || AUTHFILE="$(conf_get AUTHFILE)"
|
[ -n "$AUTHFILE" ] || AUTHFILE="$(conf_get AUTHFILE)"
|
||||||
[ -n "$ENGINE" ] || ENGINE="$(conf_get ENGINE)"
|
[ -n "$ENGINE" ] || ENGINE="$(conf_get ENGINE)"
|
||||||
|
[ -n "$CHANNEL" ] || CHANNEL="$(conf_get CHANNEL)"
|
||||||
|
if [ "$ROLE" = backend ]; then
|
||||||
|
[ -n "$CHANNEL" ] || { echo "backend needs --channel dev or release" >&2; exit 2; }
|
||||||
|
case "$CHANNEL" in dev) NAMESPACE=moshiro-dev ;; release) NAMESPACE=moshiro ;; *) echo "--channel must be dev or release" >&2; exit 2 ;; esac
|
||||||
|
[ -n "$REPO" ] || REPO="registry.oeo.one/$NAMESPACE/moshiro-backend"
|
||||||
|
[ -n "$PORT" ] || PORT=29181
|
||||||
|
ENGINE=podman; POLICY=manual
|
||||||
|
fi
|
||||||
[ -n "$REPO" ] || REPO="registry.oeo.one/moshiro/moshiro-$ROLE"
|
[ -n "$REPO" ] || REPO="registry.oeo.one/moshiro/moshiro-$ROLE"
|
||||||
[ -n "$POLICY" ] || POLICY=manual
|
[ -n "$POLICY" ] || POLICY=manual
|
||||||
if [ -z "$ENGINE" ]; then
|
if [ -z "$ENGINE" ]; then
|
||||||
if command -v podman >/dev/null 2>&1; then ENGINE=podman; elif command -v docker >/dev/null 2>&1; then ENGINE=docker; else echo "podman or docker is required" >&2; exit 1; fi
|
if command -v podman >/dev/null 2>&1; then ENGINE=podman; elif command -v docker >/dev/null 2>&1; then ENGINE=docker; else echo "podman or docker is required" >&2; exit 1; fi
|
||||||
fi
|
fi
|
||||||
case "$ENGINE" in
|
case "$ENGINE" in
|
||||||
podman) UNIT="moshiro-$ROLE-container.service" ;;
|
podman) UNIT_SRC="moshiro-$ROLE-container.service"; UNIT="$UNIT_SRC" ;;
|
||||||
docker) UNIT="moshiro-$ROLE-docker.service" ;;
|
docker) UNIT_SRC="moshiro-$ROLE-docker.service"; UNIT="$UNIT_SRC" ;;
|
||||||
*) echo "--engine must be podman or docker" >&2; exit 2 ;;
|
*) echo "--engine must be podman or docker" >&2; exit 2 ;;
|
||||||
esac
|
esac
|
||||||
V_CFG="moshiro-$ROLE-config"
|
V_CFG="moshiro-$ROLE-config"
|
||||||
V_STATUS="moshiro-$ROLE-status"
|
V_STATUS="moshiro-$ROLE-status"
|
||||||
for f in "$PACKAGING/systemd/$UNIT" "$PACKAGING/update/install-updater.sh" "$PACKAGING/update/moshiro-update.sh" "$PACKAGING/update/release-key.pub.pem"; do
|
if [ "$ROLE" = backend ]; then UNIT=moshiro-backend.service; V_CFG=moshiro-backend-data; fi
|
||||||
|
for f in "$PACKAGING/systemd/$UNIT_SRC" "$PACKAGING/update/install-updater.sh" "$PACKAGING/update/moshiro-update.sh" "$PACKAGING/update/release-key.pub.pem"; do
|
||||||
[ -r "$f" ] || { echo "missing $f (keep deploy-node.sh next to the packaging/ directory)" >&2; exit 1; }
|
[ -r "$f" ] || { echo "missing $f (keep deploy-node.sh next to the packaging/ directory)" >&2; exit 1; }
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -79,15 +97,38 @@ in_volume() {
|
|||||||
"$ENGINE" run --rm -i --pull=never --network none --cap-drop ALL --security-opt no-new-privileges \
|
"$ENGINE" run --rm -i --pull=never --network none --cap-drop ALL --security-opt no-new-privileges \
|
||||||
-v "$V_CFG:/etc/moshiro" --entrypoint /bin/sh "$IMAGE" -c "$1"
|
-v "$V_CFG:/etc/moshiro" --entrypoint /bin/sh "$IMAGE" -c "$1"
|
||||||
}
|
}
|
||||||
in_volume 'mkdir -p /etc/moshiro/update' </dev/null
|
[ "$ROLE" = backend ] || in_volume 'mkdir -p /etc/moshiro/update' </dev/null
|
||||||
|
|
||||||
# 3. 配置:身份由节点自己生成(Agent 和 Probe 一样),注册之后面板只认这把公钥
|
# 3. 配置:身份由节点自己生成(Agent 和 Probe 一样),注册之后面板只认这把公钥
|
||||||
|
if [ "$ROLE" = backend ]; then
|
||||||
|
# Backend 的环境文件放在宿主机上(单元用 --env-file 读取);已有的不会被覆盖
|
||||||
|
install -d -m 755 /etc/moshiro
|
||||||
|
if [ ! -f /etc/moshiro/backend.env ]; then
|
||||||
|
if [ -z "$ADMIN_PASSWORD" ]; then
|
||||||
|
ADMIN_PASSWORD="$(head -c 18 /dev/urandom | base64 | tr -d '/+=' | head -c 20)"
|
||||||
|
echo "generated admin password (shown once): $ADMIN_PASSWORD"
|
||||||
|
fi
|
||||||
|
(
|
||||||
|
umask 077
|
||||||
|
{
|
||||||
|
echo "MoShiro__DataDirectory=/data"
|
||||||
|
echo "MoShiro__UpdateChannel=$CHANNEL"
|
||||||
|
echo "MoShiro__ImageNamespace=$NAMESPACE"
|
||||||
|
echo "MoShiro__InitialAdminUser=${ADMIN_USER:-admin}"
|
||||||
|
echo "MoShiro__InitialAdminPassword=$ADMIN_PASSWORD"
|
||||||
|
[ -z "$PUBLIC_URL" ] || echo "MoShiro__PublicUrl=$PUBLIC_URL"
|
||||||
|
} > /etc/moshiro/backend.env
|
||||||
|
)
|
||||||
|
echo "config: created /etc/moshiro/backend.env"
|
||||||
|
fi
|
||||||
|
else
|
||||||
ID_DIR="/etc/moshiro/$ROLE-id"
|
ID_DIR="/etc/moshiro/$ROLE-id"
|
||||||
if ! in_volume "test -f $ID_DIR/node.json" </dev/null; then
|
if ! in_volume "test -f $ID_DIR/node.json" </dev/null; then
|
||||||
[ -n "$SERVER" ] && [ -n "$JOIN" ] && [ -n "$NAME" ] || { echo "first deployment needs --server, --join and --name" >&2; exit 1; }
|
[ -n "$SERVER" ] && [ -n "$JOIN" ] && [ -n "$NAME" ] || { echo "first deployment needs --server, --join and --name" >&2; exit 1; }
|
||||||
"$ENGINE" run --rm --pull=never -v "$V_CFG:/etc/moshiro" --entrypoint /usr/local/bin/fleet-enroll "$IMAGE" \
|
"$ENGINE" run --rm --pull=never -v "$V_CFG:/etc/moshiro" --entrypoint /usr/local/bin/fleet-enroll "$IMAGE" \
|
||||||
--server "$SERVER" --join "$JOIN" --name "$NAME" --identity-dir "$ID_DIR"
|
--server "$SERVER" --join "$JOIN" --name "$NAME" --identity-dir "$ID_DIR"
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
if [ "$ROLE" = agent ]; then
|
if [ "$ROLE" = agent ]; then
|
||||||
if ! in_volume 'test -f /etc/moshiro/agent.json' </dev/null; then
|
if ! in_volume 'test -f /etc/moshiro/agent.json' </dev/null; then
|
||||||
[ -n "$SERVER" ] || { echo "agent.json is missing; pass --server to create it" >&2; exit 1; }
|
[ -n "$SERVER" ] || { echo "agent.json is missing; pass --server to create it" >&2; exit 1; }
|
||||||
@@ -99,7 +140,12 @@ if [ "$ROLE" = agent ]; then
|
|||||||
in_volume 'sed -i "s/\"bind\" *: *\"0\.0\.0\.0\"/\"bind\": \"::\"/" /etc/moshiro/agent.json' </dev/null
|
in_volume 'sed -i "s/\"bind\" *: *\"0\.0\.0\.0\"/\"bind\": \"::\"/" /etc/moshiro/agent.json' </dev/null
|
||||||
echo "config: listen.bind 0.0.0.0 -> ::"
|
echo "config: listen.bind 0.0.0.0 -> ::"
|
||||||
fi
|
fi
|
||||||
else
|
elif [ "$ROLE" = probe ]; then
|
||||||
|
# 旧格式(面板生成的 probe.json:没有 fleet 段)备份之后按新格式重写
|
||||||
|
if in_volume 'test -f /etc/moshiro/probe.json' </dev/null && ! in_volume 'grep -q "\"fleet\"" /etc/moshiro/probe.json' </dev/null; then
|
||||||
|
in_volume 'mv /etc/moshiro/probe.json /etc/moshiro/probe.json.old' </dev/null
|
||||||
|
echo "config: old probe.json moved to probe.json.old"
|
||||||
|
fi
|
||||||
if ! in_volume 'test -f /etc/moshiro/probe.json' </dev/null; then
|
if ! in_volume 'test -f /etc/moshiro/probe.json' </dev/null; then
|
||||||
[ -n "$SERVER" ] || { echo "probe.json is missing; pass --server to create it" >&2; exit 1; }
|
[ -n "$SERVER" ] || { echo "probe.json is missing; pass --server to create it" >&2; exit 1; }
|
||||||
printf '{"fleet":{"server":"%s","identity_dir":"/etc/moshiro/probe-id"}}\n' "$SERVER" \
|
printf '{"fleet":{"server":"%s","identity_dir":"/etc/moshiro/probe-id"}}\n' "$SERVER" \
|
||||||
@@ -111,9 +157,11 @@ fi
|
|||||||
# 4. 单元和更新器(保持原来的更新策略)
|
# 4. 单元和更新器(保持原来的更新策略)
|
||||||
install -d -m 755 "$CONF_DIR"
|
install -d -m 755 "$CONF_DIR"
|
||||||
printf 'IMAGE=%s\n' "$IMAGE" > "$CONF_DIR/$ROLE.image"
|
printf 'IMAGE=%s\n' "$IMAGE" > "$CONF_DIR/$ROLE.image"
|
||||||
install -m 644 "$PACKAGING/systemd/$UNIT" "/etc/systemd/system/$UNIT"
|
install -m 644 "$PACKAGING/systemd/$UNIT_SRC" "/etc/systemd/system/$UNIT"
|
||||||
|
[ "$ROLE" != backend ] || sed -i "s/:29181/:$PORT/" "/etc/systemd/system/$UNIT"
|
||||||
set -- "$ROLE" --engine "$ENGINE" --volume "$V_CFG" --status-volume "$V_STATUS" --helper-image "$IMAGE" \
|
set -- "$ROLE" --engine "$ENGINE" --volume "$V_CFG" --status-volume "$V_STATUS" --helper-image "$IMAGE" \
|
||||||
--image-repo "$REPO" --unit "$UNIT" --policy "$POLICY" --no-enable
|
--image-repo "$REPO" --unit "$UNIT" --policy "$POLICY" --no-enable
|
||||||
|
[ "$ROLE" != backend ] || set -- "$@" --channel "$CHANNEL" --health-url "http://127.0.0.1:$PORT/healthz"
|
||||||
[ -z "$AUTHFILE" ] || set -- "$@" --authfile "$AUTHFILE"
|
[ -z "$AUTHFILE" ] || set -- "$@" --authfile "$AUTHFILE"
|
||||||
sh "$PACKAGING/update/install-updater.sh" "$@"
|
sh "$PACKAGING/update/install-updater.sh" "$@"
|
||||||
|
|
||||||
@@ -122,5 +170,13 @@ systemctl daemon-reload
|
|||||||
systemctl enable "$UNIT" "moshiro-update-$ROLE.timer" >/dev/null 2>&1
|
systemctl enable "$UNIT" "moshiro-update-$ROLE.timer" >/dev/null 2>&1
|
||||||
systemctl restart "$UNIT"
|
systemctl restart "$UNIT"
|
||||||
systemctl start "moshiro-update-$ROLE.timer"
|
systemctl start "moshiro-update-$ROLE.timer"
|
||||||
|
if [ "$ROLE" = backend ]; then
|
||||||
|
n=0
|
||||||
|
until curl -fsS -o /dev/null "http://127.0.0.1:$PORT/healthz" 2>/dev/null; do
|
||||||
|
n=$((n + 1)); [ "$n" -lt 30 ] || { echo "backend did not become healthy" >&2; systemctl status "$UNIT" --no-pager >&2 || true; exit 1; }
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
else
|
||||||
sleep 5
|
sleep 5
|
||||||
|
fi
|
||||||
systemctl is-active "$UNIT"
|
systemctl is-active "$UNIT"
|
||||||
Reference in new issue
Block a user