feat(images): optional openSUSE Leap 16 image builder
Add scripts/70-opensuse-image.sh, modeled on 60-rhel-image.sh: pulls images:opensuse/16.0, installs sshd + universal tooling via zypper, cleans caches, and publishes vpsmgr/opensuse-sshd (base deleted). - Register the alias in imageLabels so the reinstall dialog shows "openSUSE Leap 16"; extend collectManagedImages tests - Leap 16 ships systemd-networkd, so panel IPv6 config takes the existing Debian networkd branch — no runtime code changes needed - Optional: not part of install.sh, keeping small hosts lean - Document the new image in README (zh/en) and docs/architecture.md Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
This commit is contained in:
1 parent
98b730c2d0
commit
dcc2f767ff
6 files changed
+141
-7
No files matched your search
+3
-2
@@ -9,7 +9,7 @@ A lightweight Incus container hosting panel for small VPS instances and low-memo
|
||||
## Feature Details
|
||||
|
||||
- Admin panel: users, quotas, domains, IPv6 pool, and audit logs
|
||||
- User panel: power control, self-service Debian 13/AlmaLinux 9 reinstall, and domain configuration
|
||||
- User panel: power control, self-service Debian 13/AlmaLinux 9/openSUSE Leap 16 reinstall, and domain configuration
|
||||
- CPU, memory, and disk oversubscription; quota changes apply live without a container restart
|
||||
- Strict container network isolation; prefix mode assigns each container a dedicated `/112` IPv6 block that it can subdivide
|
||||
- Traffic is counted in both directions; over-quota containers are rate-limited to 1 Mbps both ways
|
||||
@@ -76,10 +76,11 @@ Users can define an init script in the panel. It runs as root inside the contain
|
||||
|
||||
## Additional Images
|
||||
|
||||
Debian 13 is the default image. To offer AlmaLinux 9 during reinstall, build it once:
|
||||
Debian 13 is the default image. To offer AlmaLinux 9 or openSUSE Leap 16 during reinstall, build it once:
|
||||
|
||||
```sh
|
||||
sudo bash scripts/60-rhel-image.sh # AlmaLinux 9
|
||||
sudo bash scripts/70-opensuse-image.sh # openSUSE Leap 16
|
||||
```
|
||||
|
||||
The image builder is not run by `install.sh`, keeping the default installation small.
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
## 功能细节
|
||||
|
||||
- 管理员面板:用户、配额、域名、IPv6 地址池和审计日志
|
||||
- 用户面板:电源控制、自助重装 Debian 13/AlmaLinux 9、域名配置
|
||||
- 用户面板:电源控制、自助重装 Debian 13/AlmaLinux 9/openSUSE Leap 16、域名配置
|
||||
- CPU、内存、磁盘支持超售;配额修改实时生效,无需重启容器
|
||||
- 容器网络严格隔离;IPv6 前缀模式下每个容器获得独立 `/112`,可继续划分子网
|
||||
- 流量按上下行合计,超额后双向限速至 1 Mbps
|
||||
@@ -76,10 +76,11 @@ vps config list|set|help
|
||||
|
||||
## 额外镜像
|
||||
|
||||
默认镜像是 Debian 13。需要 AlmaLinux 9 时,可手动构建一次:
|
||||
默认镜像是 Debian 13。需要 AlmaLinux 9 或 openSUSE Leap 16 时,可手动构建一次:
|
||||
|
||||
```sh
|
||||
sudo bash scripts/60-rhel-image.sh # AlmaLinux 9
|
||||
sudo bash scripts/70-opensuse-image.sh # openSUSE Leap 16
|
||||
```
|
||||
|
||||
该脚本不会由 `install.sh` 自动执行,以减少小型主机的安装负担。
|
||||
|
||||
@@ -233,6 +233,15 @@ validates that a picked non-default image still exists. Containers run from
|
||||
either base with the same light provisioning (random hostname, root password,
|
||||
sshd enabled — the service is `sshd` on RHEL and `ssh` on Debian).
|
||||
|
||||
## Optional openSUSE image (`vpsmgr/opensuse-sshd`)
|
||||
|
||||
`70-opensuse-image.sh` (also NOT part of `install.sh`) builds an openSUSE Leap
|
||||
16 image — `images:opensuse/16.0`, published as `vpsmgr/opensuse-sshd` — with
|
||||
the same hygiene: sshd + universal tooling via `zypper`, caches/logs cleaned,
|
||||
base image deleted after publishing. Leap 16 ships systemd-networkd by default,
|
||||
so its IPv6 is configured at runtime by the panel's standard networkd branch
|
||||
(static /128 + `fe80::1` gateway), unlike the RHEL-family nmcli path.
|
||||
|
||||
## Per-container provisioning
|
||||
|
||||
`mgr.Provision` runs inside every new or reinstalled container and:
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env bash
|
||||
# 70-opensuse-image.sh — OPTIONAL: build an openSUSE Leap 16 "sshd + universal
|
||||
# tooling" image so users can reinstall their container with something other
|
||||
# than the default Debian 13. Run as root AFTER install.sh, only when you
|
||||
# actually want the extra image (a toy panel should not build it on every box).
|
||||
#
|
||||
# sudo bash scripts/70-opensuse-image.sh
|
||||
#
|
||||
# Same hygiene as 50-image.sh: sshd + common tools baked in, zypper caches and
|
||||
# logs cleaned before publishing, base image deleted afterwards.
|
||||
set -uo pipefail
|
||||
|
||||
|
||||
REMOTE_ALIAS=images:opensuse/16.0
|
||||
IMAGE=vpsmgr/opensuse-sshd
|
||||
BASE_ALIAS=vpsmgr-opensuse-16
|
||||
|
||||
log(){ echo "[70] $*"; }
|
||||
|
||||
incus info >/dev/null 2>&1 || { echo "[70] error: Incus not ready" >&2; exit 1; }
|
||||
|
||||
if incus image show "$IMAGE" >/dev/null 2>&1; then
|
||||
log "image $IMAGE already present"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! incus image list "$BASE_ALIAS" --format=csv 2>/dev/null | grep -q .; then
|
||||
log "pulling $REMOTE_ALIAS (fallback base, deleted after build)..."
|
||||
if ! incus image copy "$REMOTE_ALIAS" local: --alias "$BASE_ALIAS"; then
|
||||
log " warn: image pull failed — nothing built"
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
log "base image $BASE_ALIAS already present"
|
||||
fi
|
||||
|
||||
log "building $IMAGE (this takes a few minutes)..."
|
||||
NAME=tmp-opensuse-builder
|
||||
incus delete --force "$NAME" >/dev/null 2>&1 || true
|
||||
if incus launch "$BASE_ALIAS" "$NAME"; then
|
||||
# wait until usable
|
||||
for i in $(seq 1 60); do
|
||||
if incus exec "$NAME" -- /bin/true >/dev/null 2>&1; then break; fi
|
||||
sleep 2
|
||||
done
|
||||
# openSUSE brings eth0 up via systemd-networkd, which lags the Incus agent by
|
||||
# a few seconds: running zypper before DHCP has written resolv.conf makes it
|
||||
# die with "Couldn't resolve". Wait until DNS answers, or the builder install
|
||||
# fails and a broken image gets published.
|
||||
DNS_OK=
|
||||
for i in $(seq 1 30); do
|
||||
if incus exec "$NAME" -- getent hosts download.opensuse.org >/dev/null 2>&1; then
|
||||
DNS_OK=1; break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
if [ -z "$DNS_OK" ]; then
|
||||
log " warn: builder never got working DNS; nothing built"
|
||||
incus delete --force "$NAME" >/dev/null 2>&1 || true
|
||||
incus image delete "$BASE_ALIAS" >/dev/null 2>&1 || true
|
||||
elif incus exec "$NAME" -- sh -c '
|
||||
set -e
|
||||
# universal user tooling (mirrors the Debian image): sshd, curl/wget need
|
||||
# ca-certificates or HTTPS fails; bind-utils is the openSUSE dig/nslookup
|
||||
# package. zypper is retried: the mirror can flap on a slow uplink right after
|
||||
# boot.
|
||||
for attempt in 1 2 3; do
|
||||
zypper --non-interactive install --no-recommends \
|
||||
openssh-server ca-certificates curl wget less bind-utils openssh-clients unzip nano \
|
||||
&& break
|
||||
sleep 5
|
||||
done
|
||||
# hard gate: never publish an image without sshd baked in
|
||||
rpm -q openssh-server >/dev/null
|
||||
mkdir -p /etc/ssh/sshd_config.d
|
||||
printf "PermitRootLogin yes\nPasswordAuthentication yes\n" > /etc/ssh/sshd_config.d/99-vpsmgr.conf
|
||||
systemctl enable sshd
|
||||
# slim the published image: drop zypper caches and logs
|
||||
zypper clean --all 2>/dev/null || true
|
||||
rm -rf /var/cache/zypp /var/log/* /tmp/* /var/tmp/* 2>/dev/null || true
|
||||
# Drop the baked-in machine-id so every container boots its own: a shared
|
||||
# machine-id means a shared DHCPv6 DUID, which breaks dnsmasq lease renewals
|
||||
# and drops the container global IPv6 at the 1h lease mark.
|
||||
rm -f /etc/machine-id /var/lib/dbus/machine-id 2>/dev/null || true
|
||||
# IPv6 for openSUSE containers is configured at runtime by the panel: Leap 16
|
||||
# ships systemd-networkd by default, so the panel networkd branch applies
|
||||
# (static /128 + fe80::1 gateway, no SLAAC/DHCPv6) — nothing to bake here.
|
||||
'; then
|
||||
incus stop "$NAME" --timeout=30 || true
|
||||
if incus publish "$NAME" --alias "$IMAGE"; then
|
||||
incus delete --force "$NAME" || true
|
||||
# keep only the modified image — the base was a build intermediate
|
||||
if incus image delete "$BASE_ALIAS" >/dev/null 2>&1; then
|
||||
log "removed base image $BASE_ALIAS (only $IMAGE kept)"
|
||||
else
|
||||
log " warn: could not remove base image $BASE_ALIAS"
|
||||
fi
|
||||
log "image published: $IMAGE"
|
||||
else
|
||||
log " warn: publish FAILED — $IMAGE NOT built (base image kept; re-run to retry)"
|
||||
incus delete --force "$NAME" >/dev/null 2>&1 || true
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
log " warn: install in builder failed; nothing built"
|
||||
incus delete --force "$NAME" >/dev/null 2>&1 || true
|
||||
incus image delete "$BASE_ALIAS" >/dev/null 2>&1 || true
|
||||
fi
|
||||
else
|
||||
log " warn: could not launch builder; nothing built"
|
||||
fi
|
||||
|
||||
echo "[70] done"
|
||||
@@ -13,9 +13,10 @@ type ManagedImage struct {
|
||||
|
||||
// imageLabels maps known managed image aliases to friendly display names.
|
||||
var imageLabels = map[string]string{
|
||||
"vpsmgr/debian-sshd": "Debian 13",
|
||||
"vpsmgr/alma-sshd": "Alma 9",
|
||||
"vpsmgr/rocky-sshd": "Rocky 9",
|
||||
"vpsmgr/debian-sshd": "Debian 13",
|
||||
"vpsmgr/alma-sshd": "Alma 9",
|
||||
"vpsmgr/rocky-sshd": "Rocky 9",
|
||||
"vpsmgr/opensuse-sshd": "openSUSE Leap 16",
|
||||
}
|
||||
|
||||
// collectManagedImages picks the reinstallable images out of a raw alias list:
|
||||
|
||||
@@ -34,6 +34,15 @@ func TestCollectManagedImages(t *testing.T) {
|
||||
{"vpsmgr/rocky-sshd", "Rocky 9"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "default plus opensuse, sorted after alma",
|
||||
defaultAlias: "vpsmgr/debian-sshd",
|
||||
aliases: []string{"vpsmgr/opensuse-sshd", "vpsmgr/debian-sshd"},
|
||||
want: []ManagedImage{
|
||||
{"vpsmgr/debian-sshd", "Debian 13"},
|
||||
{"vpsmgr/opensuse-sshd", "openSUSE Leap 16"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "default missing locally still offered, unknown alias humanized",
|
||||
defaultAlias: "vpsmgr/debian-sshd",
|
||||
|
||||
Reference in new issue
Block a user