diff --git a/base-images/operating-systems/anolis/23.4/Dockerfile b/base-images/operating-systems/anolis/23.4/Dockerfile new file mode 100644 index 00000000..239b9b44 --- /dev/null +++ b/base-images/operating-systems/anolis/23.4/Dockerfile @@ -0,0 +1,49 @@ +# These ARGs can be overridden at build time to customize the image +ARG REGISTRY=ghcr.io +ARG TOOLING_REPO=labring-actions/devbox-tooling +ARG L10N=en_US +ARG TARGETARCH +ARG ARCH=${TARGETARCH:-amd64} +ARG DEFAULT_DEVBOX_USER=devbox +ARG ANOLIS_IMAGE=openanolis/anolisos:23.4 +# These ARGs are not recommended to be overridden at build time. +# Instead, update the Dockerfile directly for consistent builds, +# and release new versions as needed. +ARG BASE_TOOLS_VERSION=v0.0.1-alpha.1 + +FROM ${REGISTRY}/${TOOLING_REPO}/tooling:${BASE_TOOLS_VERSION} AS tooling +FROM ${ANOLIS_IMAGE} +ARG L10N +ARG TARGETARCH +ARG ARCH=${TARGETARCH:-amd64} +ARG DEFAULT_DEVBOX_USER +LABEL org.opencontainers.image.authors="The Devbox Authors" +# Define some environment variables +## BASE_TOOLS_DIR: Directory where base tools are installed +ENV BASE_TOOLS_DIR=/opt/base-tools +## L10N: Internationalization setting +ENV L10N=${L10N} +## ARCH: System architecture (from build-arg) +ENV ARCH=${ARCH} +## DEFAULT_DEVBOX_USER: Default user for the devbox environment +ENV DEFAULT_DEVBOX_USER=${DEFAULT_DEVBOX_USER} +## PROJECT_DIR: Default devbox project directory inside the container +ENV PROJECT_DIR=/home/devbox/project +## S6_STAGE2_HOOK: Hook script executed BEFORE s6-rc compilation +## This allows us to dynamically disable services based on DEVBOX_ENV +ENV S6_STAGE2_HOOK=/etc/s6-overlay-hook/pre-rc-init.d/pre-rc-init.sh +## S6_KILL_GRACETIME: Time to wait before forcefully killing all processes during shutdown +ENV S6_KILL_GRACETIME=500 + +# Copy tooling assets from the tooling stage +COPY --from=tooling ${BASE_TOOLS_DIR} ${BASE_TOOLS_DIR} +# Add build script and execute it +COPY build.sh /build.sh +RUN chmod +x /build.sh && \ + /build.sh && \ + rm -f /build.sh && \ + rm -rf ${BASE_TOOLS_DIR} +## Locale: generated during build, but also export at runtime so non-login processes use UTF-8 +ENV LANG=en_US.UTF-8 +ENV LC_ALL=en_US.UTF-8 +ENTRYPOINT [ "/init" ] diff --git a/base-images/operating-systems/anolis/23.4/build.sh b/base-images/operating-systems/anolis/23.4/build.sh new file mode 100644 index 00000000..8e01ac7c --- /dev/null +++ b/base-images/operating-systems/anolis/23.4/build.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "Current BASE_TOOLS_DIR: $BASE_TOOLS_DIR" +echo "Current L10N: $L10N" +echo "Current ARCH: $ARCH" +echo "Current DEFAULT_DEVBOX_USER: $DEFAULT_DEVBOX_USER" + +chmod +x "$BASE_TOOLS_DIR/scripts/"*.sh + +# Install base packages for Anolis/RPM family +"$BASE_TOOLS_DIR/scripts/install-base-pkg-rpm.sh" + +# Install cron, s6, and the SDK server from the shared tooling scripts +"$BASE_TOOLS_DIR/scripts/install-crond.sh" +"$BASE_TOOLS_DIR/scripts/install-s6.sh" +"$BASE_TOOLS_DIR/scripts/install-sdk-server.sh" + +# Configure svc +"$BASE_TOOLS_DIR/scripts/configure-svc.sh" + +# Configure other utilities +"$BASE_TOOLS_DIR/scripts/configure-logrotate.sh" +"$BASE_TOOLS_DIR/scripts/configure-login.sh" + +# Configure localization (L10N) +"$BASE_TOOLS_DIR/scripts/configure-l10n.sh" + +# Configure user devbox +"$BASE_TOOLS_DIR/scripts/configure-user.sh" "$DEFAULT_DEVBOX_USER" + +# Install user-facing runtime docs (single source from the shared tooling bundle) +if [ -d "$BASE_TOOLS_DIR/docs" ]; then + install -d /usr/share/devbox/docs + cp "$BASE_TOOLS_DIR"/docs/README.s6-user-guide*.md /usr/share/devbox/docs/ + chmod 644 /usr/share/devbox/docs/README.s6-user-guide*.md +else + echo "No docs directory found in $BASE_TOOLS_DIR; skipping s6 user-guide install" +fi + +# Cleanup +"$BASE_TOOLS_DIR/scripts/cleanup.sh" diff --git a/base-images/operating-systems/kylin/v10-sp3/Dockerfile b/base-images/operating-systems/kylin/v10-sp3/Dockerfile new file mode 100644 index 00000000..721c0e40 --- /dev/null +++ b/base-images/operating-systems/kylin/v10-sp3/Dockerfile @@ -0,0 +1,49 @@ +# These ARGs can be overridden at build time to customize the image +ARG REGISTRY=ghcr.io +ARG TOOLING_REPO=labring-actions/devbox-tooling +ARG L10N=en_US +ARG TARGETARCH +ARG ARCH=${TARGETARCH:-amd64} +ARG DEFAULT_DEVBOX_USER=devbox +ARG KYLIN_IMAGE=macrosan/kylin:v10-sp3 +# These ARGs are not recommended to be overridden at build time. +# Instead, update the Dockerfile directly for consistent builds, +# and release new versions as needed. +ARG BASE_TOOLS_VERSION=v0.0.1-alpha.1 + +FROM ${REGISTRY}/${TOOLING_REPO}/tooling:${BASE_TOOLS_VERSION} AS tooling +FROM ${KYLIN_IMAGE} +ARG L10N +ARG TARGETARCH +ARG ARCH=${TARGETARCH:-amd64} +ARG DEFAULT_DEVBOX_USER +LABEL org.opencontainers.image.authors="The Devbox Authors" +# Define some environment variables +## BASE_TOOLS_DIR: Directory where base tools are installed +ENV BASE_TOOLS_DIR=/opt/base-tools +## L10N: Internationalization setting +ENV L10N=${L10N} +## ARCH: System architecture (from build-arg) +ENV ARCH=${ARCH} +## DEFAULT_DEVBOX_USER: Default user for the devbox environment +ENV DEFAULT_DEVBOX_USER=${DEFAULT_DEVBOX_USER} +## PROJECT_DIR: Default devbox project directory inside the container +ENV PROJECT_DIR=/home/devbox/project +## S6_STAGE2_HOOK: Hook script executed BEFORE s6-rc compilation +## This allows us to dynamically disable services based on DEVBOX_ENV +ENV S6_STAGE2_HOOK=/etc/s6-overlay-hook/pre-rc-init.d/pre-rc-init.sh +## S6_KILL_GRACETIME: Time to wait before forcefully killing all processes during shutdown +ENV S6_KILL_GRACETIME=500 + +# Copy tooling assets from the tooling stage +COPY --from=tooling ${BASE_TOOLS_DIR} ${BASE_TOOLS_DIR} +# Add build script and execute it +COPY build.sh /build.sh +RUN chmod +x /build.sh && \ + /build.sh && \ + rm -f /build.sh && \ + rm -rf ${BASE_TOOLS_DIR} +## Locale: generated during build, but also export at runtime so non-login processes use UTF-8 +ENV LANG=en_US.UTF-8 +ENV LC_ALL=en_US.UTF-8 +ENTRYPOINT [ "/init" ] diff --git a/base-images/operating-systems/kylin/v10-sp3/build.sh b/base-images/operating-systems/kylin/v10-sp3/build.sh new file mode 100644 index 00000000..3e02f35a --- /dev/null +++ b/base-images/operating-systems/kylin/v10-sp3/build.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "Current BASE_TOOLS_DIR: $BASE_TOOLS_DIR" +echo "Current L10N: $L10N" +echo "Current ARCH: $ARCH" +echo "Current DEFAULT_DEVBOX_USER: $DEFAULT_DEVBOX_USER" + +chmod +x "$BASE_TOOLS_DIR/scripts/"*.sh + +# Install base packages for Kylin/RPM family +"$BASE_TOOLS_DIR/scripts/install-base-pkg-rpm.sh" + +# Kylin V10 SP3 ships glibc 2.28, which meets the VS Code Server Linux +# prerequisite, but its GCC 7 libstdc++ only provides GLIBCXX_3.4.24. +# Install an Anolis 8 libstdc++ build with GLIBCXX_3.4.25 while keeping the +# system glibc unchanged. +tmp_dir="$(mktemp -d)" +trap 'rm -rf "$tmp_dir"' EXIT +case "${ARCH:-amd64}" in + amd64) + rpm_arch=x86_64 + libstdcxx_rpm_sha256="1cdcd031a575525b43c2787f750a855228433e982a7ddffc9d12d01f73f5ca68" + ;; + arm64) + rpm_arch=aarch64 + libstdcxx_rpm_sha256="412632fe27bf8ab264b8b4544a466225adc59bcb7cc30dce2f08f9630073b18c" + ;; + *) + echo "Unsupported ARCH for Kylin libstdc++ compatibility package: ${ARCH:-}" >&2 + exit 1 + ;; +esac +libstdcxx_rpm_url="https://mirrors.openanolis.cn/anolis/8/BaseOS/${rpm_arch}/os/Packages/libstdc++-8.5.0-24.0.1.an8.${rpm_arch}.rpm" +libstdcxx_rpm="$tmp_dir/libstdc++.rpm" +curl -fsSL "$libstdcxx_rpm_url" -o "$libstdcxx_rpm" +echo "$libstdcxx_rpm_sha256 $libstdcxx_rpm" | sha256sum -c - +( + cd "$tmp_dir" + rpm2cpio "$libstdcxx_rpm" | cpio -idm --quiet ./usr/lib64/libstdc++.so.6 ./usr/lib64/libstdc++.so.6.0.25 +) +install -m 0755 "$tmp_dir/usr/lib64/libstdc++.so.6.0.25" /usr/lib64/libstdc++.so.6.0.25 +ln -sf libstdc++.so.6.0.25 /usr/lib64/libstdc++.so.6 +ldconfig +if ! grep -ao 'GLIBCXX_3\.4\.25' /usr/lib64/libstdc++.so.6 >/dev/null 2>&1; then + echo "libstdc++ does not provide GLIBCXX_3.4.25" >&2 + exit 1 +fi +rm -rf "$tmp_dir" +trap - EXIT + +# Install cron, s6, and the SDK server from the shared tooling scripts +"$BASE_TOOLS_DIR/scripts/install-crond.sh" +"$BASE_TOOLS_DIR/scripts/install-s6.sh" +"$BASE_TOOLS_DIR/scripts/install-sdk-server.sh" + +# Configure svc +"$BASE_TOOLS_DIR/scripts/configure-svc.sh" + +# Configure other utilities +"$BASE_TOOLS_DIR/scripts/configure-logrotate.sh" +"$BASE_TOOLS_DIR/scripts/configure-login.sh" + +# Configure localization (L10N) +"$BASE_TOOLS_DIR/scripts/configure-l10n.sh" + +# Configure user devbox +"$BASE_TOOLS_DIR/scripts/configure-user.sh" "$DEFAULT_DEVBOX_USER" + +# Install user-facing runtime docs (single source from the shared tooling bundle) +if [ -d "$BASE_TOOLS_DIR/docs" ]; then + install -d /usr/share/devbox/docs + cp "$BASE_TOOLS_DIR"/docs/README.s6-user-guide*.md /usr/share/devbox/docs/ + chmod 644 /usr/share/devbox/docs/README.s6-user-guide*.md +else + echo "No docs directory found in $BASE_TOOLS_DIR; skipping s6 user-guide install" +fi + +# Cleanup +"$BASE_TOOLS_DIR/scripts/cleanup.sh" diff --git a/runtime-images/operating-systems/anolis/23.4/Dockerfile b/runtime-images/operating-systems/anolis/23.4/Dockerfile new file mode 100644 index 00000000..46051e71 --- /dev/null +++ b/runtime-images/operating-systems/anolis/23.4/Dockerfile @@ -0,0 +1,25 @@ +# These ARGs can be overridden at build time to customize the image +ARG REPO=labring-actions/devbox-base-images +ARG REGISTRY=ghcr.io +ARG L10N=en_US +ARG L10N_NORMALIZED=en-us +ARG DEFAULT_DEVBOX_USER=devbox + +# These ARGs are not recommended to be overridden at build time. +# Instead, update the Dockerfile directly for consistent builds, +# and release new versions as needed. +ARG OS_IMAGE_VERSION=v0.0.1-alpha.1-${L10N_NORMALIZED} + +FROM ${REGISTRY}/${REPO}/anolis-23.4:${OS_IMAGE_VERSION} +ARG L10N +ARG DEFAULT_DEVBOX_USER +ENV L10N=${L10N} +ENV PROJECT_TEMPLATE_DIR=/project-template +COPY ./project-template ${PROJECT_TEMPLATE_DIR} +COPY ./build.sh /build.sh +RUN chmod +x /build.sh && \ + /build.sh && \ + rm -f /build.sh && \ + rm -rf ${PROJECT_TEMPLATE_DIR} +# Set the working directory to the default devbox user's project directory +WORKDIR /home/${DEFAULT_DEVBOX_USER}/project diff --git a/runtime-images/operating-systems/anolis/23.4/build.sh b/runtime-images/operating-systems/anolis/23.4/build.sh new file mode 100644 index 00000000..590b98e8 --- /dev/null +++ b/runtime-images/operating-systems/anolis/23.4/build.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail + +L10N=${L10N:-en_US} +DEFAULT_DEVBOX_USER=${DEFAULT_DEVBOX_USER:-devbox} +PROJECT_TEMPLATE_DIR=${PROJECT_TEMPLATE_DIR:-/project-templates} +DOCS_DIR=${DOCS_DIR:-/usr/share/devbox/docs} + +if ! id -u "$DEFAULT_DEVBOX_USER" &>/dev/null; then + echo "User $DEFAULT_DEVBOX_USER does not exist" + exit 1 +fi + +TARGET_DIR="/home/$DEFAULT_DEVBOX_USER/project" +mkdir -p "$TARGET_DIR" + +if [ -f "$PROJECT_TEMPLATE_DIR/README.$L10N.md" ]; then + echo "README $PROJECT_TEMPLATE_DIR/README.$L10N.md exists. Copying to $TARGET_DIR/README.md" + cp "$PROJECT_TEMPLATE_DIR/README.$L10N.md" "$TARGET_DIR/README.md" +else + echo "README $PROJECT_TEMPLATE_DIR/README.$L10N.md does not exist. Skipping copy." +fi + +if [ -f "$DOCS_DIR/README.s6-user-guide.$L10N.md" ]; then + cp "$DOCS_DIR/README.s6-user-guide.$L10N.md" "$TARGET_DIR/README.s6-user-guide.md" +elif [ -f "$DOCS_DIR/README.s6-user-guide.en_US.md" ]; then + cp "$DOCS_DIR/README.s6-user-guide.en_US.md" "$TARGET_DIR/README.s6-user-guide.md" +fi + +cp "$PROJECT_TEMPLATE_DIR/"*.sh "$TARGET_DIR/" + +# Set ownership to default devbox user +chown -R "$DEFAULT_DEVBOX_USER:$DEFAULT_DEVBOX_USER" "$TARGET_DIR" diff --git a/runtime-images/operating-systems/anolis/23.4/project-template/README.en_US.md b/runtime-images/operating-systems/anolis/23.4/project-template/README.en_US.md new file mode 100644 index 00000000..75bad07f --- /dev/null +++ b/runtime-images/operating-systems/anolis/23.4/project-template/README.en_US.md @@ -0,0 +1,46 @@ +# AnolisOS 23.4 Runtime Template + +This template provides a minimal **operating-system runtime** based on Anolis OS 23.4. +Use it when you need a localized Linux base and full control of your language, framework, or application stack. + +## Runtime Summary + +- OS version: `Anolis OS 23.4` +- Base runtime image: `anolis-23.4` +- Entrypoint script: `entrypoint.sh` +- Default service port: `8080` + +## Template Files + +- `entrypoint.sh`: creates a static `index.html` and starts a lightweight HTTP server + +## Run in DevBox + +Run commands from `/home/devbox/project`. + +```bash +bash entrypoint.sh +``` + +Behavior: +- Uses `PORT` environment variable when provided, defaults to `8080`. +- Serves files from `/home/devbox/project/www`. +- Prefers `busybox httpd` and falls back to `python3 -m http.server` when that applet is unavailable. + +## Verify Service + +```bash +curl http://127.0.0.1:8080 +``` + +Expected output: + +```text +Hello, World! +``` + +## Customization + +- Replace `entrypoint.sh` with your own process startup script. +- Use `dnf` or `yum` to install application dependencies in this AnolisOS base. +- Align container exposed ports with your service port. diff --git a/runtime-images/operating-systems/anolis/23.4/project-template/README.zh_CN.md b/runtime-images/operating-systems/anolis/23.4/project-template/README.zh_CN.md new file mode 100644 index 00000000..e6075011 --- /dev/null +++ b/runtime-images/operating-systems/anolis/23.4/project-template/README.zh_CN.md @@ -0,0 +1,46 @@ +# AnolisOS 23.4 运行时模板 + +该模板提供一个基于 Anolis OS 23.4 的最小化**操作系统运行时**。 +适用于需要国产化 Linux 基础环境,并在其上自行安装语言、框架或业务依赖的场景。 + +## 运行时概览 + +- 系统版本:`Anolis OS 23.4` +- 基础运行时镜像:`anolis-23.4` +- 启动脚本:`entrypoint.sh` +- 默认服务端口:`8080` + +## 模板文件 + +- `entrypoint.sh`:生成静态 `index.html` 并启动轻量 HTTP 服务 + +## 在 DevBox 中运行 + +以下命令在 `/home/devbox/project` 目录执行。 + +```bash +bash entrypoint.sh +``` + +行为说明: +- 支持通过 `PORT` 环境变量覆盖端口,默认值为 `8080`。 +- 默认从 `/home/devbox/project/www` 目录提供静态内容。 +- 优先使用 `busybox httpd`,不可用时回退到 `python3 -m http.server`。 + +## 验证服务 + +```bash +curl http://127.0.0.1:8080 +``` + +预期输出: + +```text +Hello, World! +``` + +## 自定义建议 + +- 可将 `entrypoint.sh` 替换为你的进程启动脚本。 +- 使用 `dnf` 或 `yum` 在该 AnolisOS 基础镜像中安装业务依赖。 +- 保持容器暴露端口与服务监听端口一致。 diff --git a/runtime-images/operating-systems/anolis/23.4/project-template/entrypoint.sh b/runtime-images/operating-systems/anolis/23.4/project-template/entrypoint.sh new file mode 100644 index 00000000..b178e7fa --- /dev/null +++ b/runtime-images/operating-systems/anolis/23.4/project-template/entrypoint.sh @@ -0,0 +1,32 @@ +#!/bin/bash +set -euo pipefail + +if [ "$(id -u)" -eq 0 ] && [ "${DEVBOX_ENTRYPOINT_AS_DEVBOX:-1}" = "1" ] && id devbox >/dev/null 2>&1; then + export DEVBOX_ENTRYPOINT_AS_DEVBOX=0 + SCRIPT_PATH=$(readlink -f "$0") + exec runuser -u devbox -- bash "$SCRIPT_PATH" "$@" +fi + +# Serve a simple "Hello, World!" page +PORT=${PORT:-8080} +PROJECT_DIR=${PROJECT_DIR:-/home/devbox/project} +ROOT_DIR="$PROJECT_DIR/www" +mkdir -p "$ROOT_DIR" + +cat >"$ROOT_DIR/index.html" <<'HTML' +Hello, World! +HTML + +echo "Starting HTTP server on port $PORT (serving $ROOT_DIR)" + +if command -v busybox >/dev/null 2>&1 && busybox --list 2>/dev/null | grep -qx httpd; then + exec busybox httpd -f -p "$PORT" -h "$ROOT_DIR" +fi + +if command -v python3 >/dev/null 2>&1; then + cd "$ROOT_DIR" + exec python3 -m http.server "$PORT" --bind 0.0.0.0 +fi + +echo "No supported HTTP server found (busybox httpd or python3 http.server)." >&2 +exit 1 diff --git a/runtime-images/operating-systems/kylin/v10-sp3/Dockerfile b/runtime-images/operating-systems/kylin/v10-sp3/Dockerfile new file mode 100644 index 00000000..16eacc83 --- /dev/null +++ b/runtime-images/operating-systems/kylin/v10-sp3/Dockerfile @@ -0,0 +1,25 @@ +# These ARGs can be overridden at build time to customize the image +ARG REPO=labring-actions/devbox-base-images +ARG REGISTRY=ghcr.io +ARG L10N=en_US +ARG L10N_NORMALIZED=en-us +ARG DEFAULT_DEVBOX_USER=devbox + +# These ARGs are not recommended to be overridden at build time. +# Instead, update the Dockerfile directly for consistent builds, +# and release new versions as needed. +ARG OS_IMAGE_VERSION=v0.0.1-alpha.1-${L10N_NORMALIZED} + +FROM ${REGISTRY}/${REPO}/kylin-v10-sp3:${OS_IMAGE_VERSION} +ARG L10N +ARG DEFAULT_DEVBOX_USER +ENV L10N=${L10N} +ENV PROJECT_TEMPLATE_DIR=/project-template +COPY ./project-template ${PROJECT_TEMPLATE_DIR} +COPY ./build.sh /build.sh +RUN chmod +x /build.sh && \ + /build.sh && \ + rm -f /build.sh && \ + rm -rf ${PROJECT_TEMPLATE_DIR} +# Set the working directory to the default devbox user's project directory +WORKDIR /home/${DEFAULT_DEVBOX_USER}/project diff --git a/runtime-images/operating-systems/kylin/v10-sp3/build.sh b/runtime-images/operating-systems/kylin/v10-sp3/build.sh new file mode 100644 index 00000000..590b98e8 --- /dev/null +++ b/runtime-images/operating-systems/kylin/v10-sp3/build.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail + +L10N=${L10N:-en_US} +DEFAULT_DEVBOX_USER=${DEFAULT_DEVBOX_USER:-devbox} +PROJECT_TEMPLATE_DIR=${PROJECT_TEMPLATE_DIR:-/project-templates} +DOCS_DIR=${DOCS_DIR:-/usr/share/devbox/docs} + +if ! id -u "$DEFAULT_DEVBOX_USER" &>/dev/null; then + echo "User $DEFAULT_DEVBOX_USER does not exist" + exit 1 +fi + +TARGET_DIR="/home/$DEFAULT_DEVBOX_USER/project" +mkdir -p "$TARGET_DIR" + +if [ -f "$PROJECT_TEMPLATE_DIR/README.$L10N.md" ]; then + echo "README $PROJECT_TEMPLATE_DIR/README.$L10N.md exists. Copying to $TARGET_DIR/README.md" + cp "$PROJECT_TEMPLATE_DIR/README.$L10N.md" "$TARGET_DIR/README.md" +else + echo "README $PROJECT_TEMPLATE_DIR/README.$L10N.md does not exist. Skipping copy." +fi + +if [ -f "$DOCS_DIR/README.s6-user-guide.$L10N.md" ]; then + cp "$DOCS_DIR/README.s6-user-guide.$L10N.md" "$TARGET_DIR/README.s6-user-guide.md" +elif [ -f "$DOCS_DIR/README.s6-user-guide.en_US.md" ]; then + cp "$DOCS_DIR/README.s6-user-guide.en_US.md" "$TARGET_DIR/README.s6-user-guide.md" +fi + +cp "$PROJECT_TEMPLATE_DIR/"*.sh "$TARGET_DIR/" + +# Set ownership to default devbox user +chown -R "$DEFAULT_DEVBOX_USER:$DEFAULT_DEVBOX_USER" "$TARGET_DIR" diff --git a/runtime-images/operating-systems/kylin/v10-sp3/project-template/README.en_US.md b/runtime-images/operating-systems/kylin/v10-sp3/project-template/README.en_US.md new file mode 100644 index 00000000..810baf14 --- /dev/null +++ b/runtime-images/operating-systems/kylin/v10-sp3/project-template/README.en_US.md @@ -0,0 +1,46 @@ +# Kylin V10 SP3 Runtime Template + +This template provides a minimal **operating-system runtime** based on Kylin Linux Advanced Server V10 SP3. +Use it when you need a localized Linux base and full control of your language, framework, or application stack. + +## Runtime Summary + +- OS version: `Kylin Linux Advanced Server V10 SP3` +- Base runtime image: `kylin-v10-sp3` +- Entrypoint script: `entrypoint.sh` +- Default service port: `8080` + +## Template Files + +- `entrypoint.sh`: creates a static `index.html` and starts a lightweight HTTP server + +## Run in DevBox + +Run commands from `/home/devbox/project`. + +```bash +bash entrypoint.sh +``` + +Behavior: +- Uses `PORT` environment variable when provided, defaults to `8080`. +- Serves files from `/home/devbox/project/www`. +- Prefers `busybox httpd` and falls back to `python3 -m http.server` when that applet is unavailable. + +## Verify Service + +```bash +curl http://127.0.0.1:8080 +``` + +Expected output: + +```text +Hello, World! +``` + +## Customization + +- Replace `entrypoint.sh` with your own process startup script. +- Use `dnf` or `yum` to install application dependencies in this Kylin base. +- Align container exposed ports with your service port. diff --git a/runtime-images/operating-systems/kylin/v10-sp3/project-template/README.zh_CN.md b/runtime-images/operating-systems/kylin/v10-sp3/project-template/README.zh_CN.md new file mode 100644 index 00000000..3483e9a9 --- /dev/null +++ b/runtime-images/operating-systems/kylin/v10-sp3/project-template/README.zh_CN.md @@ -0,0 +1,46 @@ +# Kylin V10 SP3 运行时模板 + +该模板提供一个基于 Kylin Linux Advanced Server V10 SP3 的最小化**操作系统运行时**。 +适用于需要国产化 Linux 基础环境,并在其上自行安装语言、框架或业务依赖的场景。 + +## 运行时概览 + +- 系统版本:`Kylin Linux Advanced Server V10 SP3` +- 基础运行时镜像:`kylin-v10-sp3` +- 启动脚本:`entrypoint.sh` +- 默认服务端口:`8080` + +## 模板文件 + +- `entrypoint.sh`:生成静态 `index.html` 并启动轻量 HTTP 服务 + +## 在 DevBox 中运行 + +以下命令在 `/home/devbox/project` 目录执行。 + +```bash +bash entrypoint.sh +``` + +行为说明: +- 支持通过 `PORT` 环境变量覆盖端口,默认值为 `8080`。 +- 默认从 `/home/devbox/project/www` 目录提供静态内容。 +- 优先使用 `busybox httpd`,不可用时回退到 `python3 -m http.server`。 + +## 验证服务 + +```bash +curl http://127.0.0.1:8080 +``` + +预期输出: + +```text +Hello, World! +``` + +## 自定义建议 + +- 可将 `entrypoint.sh` 替换为你的进程启动脚本。 +- 使用 `dnf` 或 `yum` 在该 Kylin 基础镜像中安装业务依赖。 +- 保持容器暴露端口与服务监听端口一致。 diff --git a/runtime-images/operating-systems/kylin/v10-sp3/project-template/entrypoint.sh b/runtime-images/operating-systems/kylin/v10-sp3/project-template/entrypoint.sh new file mode 100644 index 00000000..b178e7fa --- /dev/null +++ b/runtime-images/operating-systems/kylin/v10-sp3/project-template/entrypoint.sh @@ -0,0 +1,32 @@ +#!/bin/bash +set -euo pipefail + +if [ "$(id -u)" -eq 0 ] && [ "${DEVBOX_ENTRYPOINT_AS_DEVBOX:-1}" = "1" ] && id devbox >/dev/null 2>&1; then + export DEVBOX_ENTRYPOINT_AS_DEVBOX=0 + SCRIPT_PATH=$(readlink -f "$0") + exec runuser -u devbox -- bash "$SCRIPT_PATH" "$@" +fi + +# Serve a simple "Hello, World!" page +PORT=${PORT:-8080} +PROJECT_DIR=${PROJECT_DIR:-/home/devbox/project} +ROOT_DIR="$PROJECT_DIR/www" +mkdir -p "$ROOT_DIR" + +cat >"$ROOT_DIR/index.html" <<'HTML' +Hello, World! +HTML + +echo "Starting HTTP server on port $PORT (serving $ROOT_DIR)" + +if command -v busybox >/dev/null 2>&1 && busybox --list 2>/dev/null | grep -qx httpd; then + exec busybox httpd -f -p "$PORT" -h "$ROOT_DIR" +fi + +if command -v python3 >/dev/null 2>&1; then + cd "$ROOT_DIR" + exec python3 -m http.server "$PORT" --bind 0.0.0.0 +fi + +echo "No supported HTTP server found (busybox httpd or python3 http.server)." >&2 +exit 1 diff --git a/tests/runtime-conformance/README.md b/tests/runtime-conformance/README.md index 7098014d..dda9c426 100644 --- a/tests/runtime-conformance/README.md +++ b/tests/runtime-conformance/README.md @@ -31,7 +31,9 @@ Runtime-specific checks: | Runtime | Checks | | --- | --- | +| `operating-systems/anolis/23.4` | Anolis identity, busybox, localized README, root/devbox entrypoint order | | `operating-systems/debian/12.6` | Debian identity, busybox, localized README, root/devbox entrypoint order | +| `operating-systems/kylin/v10-sp3` | Kylin identity, busybox, localized README, root/devbox entrypoint order | | `operating-systems/ubuntu/22.04` | Ubuntu identity, busybox, localized README, root/devbox entrypoint order | | `operating-systems/ubuntu-cuda/12.4.1` | Ubuntu identity, CUDA compiler/runtime presence, busybox, localized README, root/devbox entrypoint order | | `languages/c/gcc-12.2.0` | GCC version, C template, compile/server smoke, root/devbox entrypoint order | diff --git a/tests/runtime-conformance/run.sh b/tests/runtime-conformance/run.sh index 3072308b..276d52e2 100755 --- a/tests/runtime-conformance/run.sh +++ b/tests/runtime-conformance/run.sh @@ -572,12 +572,18 @@ check_sandbox_runtime() { check_runtime_specifics() { log "check runtime-specific contract" case "$RUNTIME_PATH" in + operating-systems/anolis/23.4) + check_os_runtime anolis + ;; operating-systems/debian/12.6) check_os_runtime debian ;; operating-systems/ubuntu/22.04) check_os_runtime ubuntu ;; + operating-systems/kylin/v10-sp3) + check_os_runtime kylin + ;; operating-systems/ubuntu-cuda/12.4.1) check_os_runtime ubuntu check_cuda_runtime diff --git a/tests/runtime-smoke/operating-systems/anolis/23.4/smoke.sh b/tests/runtime-smoke/operating-systems/anolis/23.4/smoke.sh new file mode 100644 index 00000000..7b84ae0f --- /dev/null +++ b/tests/runtime-smoke/operating-systems/anolis/23.4/smoke.sh @@ -0,0 +1,119 @@ +#!/bin/bash +set -eu + +project_dir=/home/devbox/project + +if [ ! -d "$project_dir" ]; then + echo "Missing project dir: $project_dir" >&2 + exit 1 +fi + +# load profile env (best effort) +set +u +[ -f /etc/profile ] && . /etc/profile || true +if [ -d /etc/profile.d ]; then + for f in /etc/profile.d/*.sh; do + [ -r "$f" ] && . "$f" || true + done +fi +[ -f /home/devbox/.bashrc ] && . /home/devbox/.bashrc || true +set -u + +if [ "${SMOKE_DEBUG:-}" = "1" ]; then + echo "SMOKE_DEBUG=1" + echo "user=$(id -un) uid=$(id -u) gid=$(id -g)" + echo "HOME=$HOME" + echo "SHELL=${SHELL:-}" + echo "PATH=$PATH" + for cmd in dnf yum rpm busybox bash sudo curl wget git python3; do + if command -v "$cmd" >/dev/null 2>&1; then + echo "cmd:$cmd=$(command -v "$cmd")" + else + echo "cmd:$cmd=missing" + fi + done +fi + +if ! grep -qi anolis /etc/os-release; then + echo "Expected Anolis in /etc/os-release" >&2 + exit 1 +fi + +if ! id devbox >/dev/null 2>&1; then + echo "User devbox not found" >&2 + exit 1 +fi + +if [ ! -f "$project_dir/README.md" ]; then + echo "Missing README.md in $project_dir" >&2 + exit 1 +fi + +if [ ! -f "$project_dir/entrypoint.sh" ]; then + echo "Missing entrypoint.sh in $project_dir" >&2 + exit 1 +fi + +if ! command -v busybox >/dev/null 2>&1; then + echo "busybox not found" >&2 + exit 1 +fi + +if ! command -v dnf >/dev/null 2>&1 && ! command -v yum >/dev/null 2>&1; then + echo "dnf/yum not found" >&2 + exit 1 +fi + +if [ ! -x /usr/sbin/sshd ]; then + echo "sshd not found" >&2 + exit 1 +fi + +for nologin_file in /run/nologin /etc/nologin; do + if [ -e "$nologin_file" ]; then + echo "$nologin_file blocks non-root SSH logins" >&2 + exit 1 + fi +done + +if ! /usr/sbin/sshd -T | grep -qx 'allowtcpforwarding yes'; then + echo "sshd AllowTcpForwarding is not enabled" >&2 + exit 1 +fi + +glibc_version="$(ldd --version | head -n1 | grep -oE '[0-9]+[.][0-9]+' | tail -n1)" +if ! awk -v version="$glibc_version" 'BEGIN { split(version, v, "."); exit !((v[1] > 2) || (v[1] == 2 && v[2] >= 28)) }'; then + echo "glibc $glibc_version is older than the VS Code Server minimum 2.28" >&2 + exit 1 +fi + +if ! grep -ao 'GLIBCXX_3\.4\.25' /usr/lib64/libstdc++.so.6 >/dev/null 2>&1; then + echo "libstdc++ does not provide GLIBCXX_3.4.25 required by VS Code Server" >&2 + exit 1 +fi + +# entrypoint smoke +entrypoint="$project_dir/entrypoint.sh" +if [ ! -f "$entrypoint" ]; then + echo "Missing entrypoint.sh in $project_dir" >&2 + exit 1 +fi + +if ! command -v bash >/dev/null 2>&1; then + echo "bash not found" >&2 + exit 1 +fi + +( cd "$project_dir" && bash "$entrypoint" ) >/tmp/entrypoint.log 2>&1 & +pid=$! +sleep 3 +if ! kill -0 "$pid" >/dev/null 2>&1; then + echo "entrypoint exited early" >&2 + echo "---- entrypoint log ----" >&2 + cat /tmp/entrypoint.log >&2 || true + exit 1 +fi +kill "$pid" >/dev/null 2>&1 || true +wait "$pid" >/dev/null 2>&1 || true + +echo "ok" diff --git a/tests/runtime-smoke/operating-systems/kylin/v10-sp3/smoke.sh b/tests/runtime-smoke/operating-systems/kylin/v10-sp3/smoke.sh new file mode 100644 index 00000000..4c280db2 --- /dev/null +++ b/tests/runtime-smoke/operating-systems/kylin/v10-sp3/smoke.sh @@ -0,0 +1,119 @@ +#!/bin/bash +set -eu + +project_dir=/home/devbox/project + +if [ ! -d "$project_dir" ]; then + echo "Missing project dir: $project_dir" >&2 + exit 1 +fi + +# load profile env (best effort) +set +u +[ -f /etc/profile ] && . /etc/profile || true +if [ -d /etc/profile.d ]; then + for f in /etc/profile.d/*.sh; do + [ -r "$f" ] && . "$f" || true + done +fi +[ -f /home/devbox/.bashrc ] && . /home/devbox/.bashrc || true +set -u + +if [ "${SMOKE_DEBUG:-}" = "1" ]; then + echo "SMOKE_DEBUG=1" + echo "user=$(id -un) uid=$(id -u) gid=$(id -g)" + echo "HOME=$HOME" + echo "SHELL=${SHELL:-}" + echo "PATH=$PATH" + for cmd in dnf yum rpm busybox bash sudo curl wget git; do + if command -v "$cmd" >/dev/null 2>&1; then + echo "cmd:$cmd=$(command -v "$cmd")" + else + echo "cmd:$cmd=missing" + fi + done +fi + +if ! grep -qi kylin /etc/os-release; then + echo "Expected Kylin in /etc/os-release" >&2 + exit 1 +fi + +if ! id devbox >/dev/null 2>&1; then + echo "User devbox not found" >&2 + exit 1 +fi + +if [ ! -f "$project_dir/README.md" ]; then + echo "Missing README.md in $project_dir" >&2 + exit 1 +fi + +if [ ! -f "$project_dir/entrypoint.sh" ]; then + echo "Missing entrypoint.sh in $project_dir" >&2 + exit 1 +fi + +if ! command -v busybox >/dev/null 2>&1; then + echo "busybox not found" >&2 + exit 1 +fi + +if ! command -v dnf >/dev/null 2>&1 && ! command -v yum >/dev/null 2>&1; then + echo "dnf/yum not found" >&2 + exit 1 +fi + +if [ ! -x /usr/sbin/sshd ]; then + echo "sshd not found" >&2 + exit 1 +fi + +for nologin_file in /run/nologin /etc/nologin; do + if [ -e "$nologin_file" ]; then + echo "$nologin_file blocks non-root SSH logins" >&2 + exit 1 + fi +done + +if ! /usr/sbin/sshd -T | grep -qx 'allowtcpforwarding yes'; then + echo "sshd AllowTcpForwarding is not enabled" >&2 + exit 1 +fi + +glibc_version="$(ldd --version | head -n1 | grep -oE '[0-9]+[.][0-9]+' | tail -n1)" +if ! awk -v version="$glibc_version" 'BEGIN { split(version, v, "."); exit !((v[1] > 2) || (v[1] == 2 && v[2] >= 28)) }'; then + echo "glibc $glibc_version is older than the VS Code Server minimum 2.28" >&2 + exit 1 +fi + +if ! grep -ao 'GLIBCXX_3\.4\.25' /usr/lib64/libstdc++.so.6 >/dev/null 2>&1; then + echo "libstdc++ does not provide GLIBCXX_3.4.25 required by VS Code Server" >&2 + exit 1 +fi + +# entrypoint smoke +entrypoint="$project_dir/entrypoint.sh" +if [ ! -f "$entrypoint" ]; then + echo "Missing entrypoint.sh in $project_dir" >&2 + exit 1 +fi + +if ! command -v bash >/dev/null 2>&1; then + echo "bash not found" >&2 + exit 1 +fi + +( cd "$project_dir" && bash "$entrypoint" ) >/tmp/entrypoint.log 2>&1 & +pid=$! +sleep 3 +if ! kill -0 "$pid" >/dev/null 2>&1; then + echo "entrypoint exited early" >&2 + echo "---- entrypoint log ----" >&2 + cat /tmp/entrypoint.log >&2 || true + exit 1 +fi +kill "$pid" >/dev/null 2>&1 || true +wait "$pid" >/dev/null 2>&1 || true + +echo "ok" diff --git a/tooling/scripts/cleanup.sh b/tooling/scripts/cleanup.sh index 37db5ea8..10ad6282 100644 --- a/tooling/scripts/cleanup.sh +++ b/tooling/scripts/cleanup.sh @@ -1,7 +1,18 @@ #!/usr/bin/env bash set -euo pipefail -# Remove apt cache to reduce image size -apt-get clean && rm -rf /var/lib/apt/lists/* + +# Remove package manager caches to reduce image size +if command -v apt-get >/dev/null 2>&1; then + apt-get clean + rm -rf /var/lib/apt/lists/* +fi +if command -v dnf >/dev/null 2>&1; then + dnf clean all + rm -rf /var/cache/dnf +elif command -v yum >/dev/null 2>&1; then + yum clean all + rm -rf /var/cache/yum +fi # Clear bash history rm -rf /root/.bash_history @@ -9,4 +20,4 @@ rm -rf /root/.bash_history # Remove log files and temporary files find /var/log -type f -delete find /tmp -type f -delete -find /var/tmp -type f -delete \ No newline at end of file +find /var/tmp -type f -delete diff --git a/tooling/scripts/configure-login.sh b/tooling/scripts/configure-login.sh index 36bffc8b..ec3cfcbe 100644 --- a/tooling/scripts/configure-login.sh +++ b/tooling/scripts/configure-login.sh @@ -1,21 +1,25 @@ #!/usr/bin/env bash set -euo pipefail +UTMP_GROUP=utmp +if ! getent group "$UTMP_GROUP" >/dev/null 2>&1; then + UTMP_GROUP=root +fi # Override wtmp rotation -cat > /etc/logrotate.d/wtmp <<'EOF' +cat > /etc/logrotate.d/wtmp < /etc/logrotate.d/btmp <<'EOF' +cat > /etc/logrotate.d/btmp < /run/utmp chmod 664 /run/utmp - chown root:utmp /run/utmp -fi \ No newline at end of file + chown root:"$UTMP_GROUP" /run/utmp +fi diff --git a/tooling/scripts/configure-user.sh b/tooling/scripts/configure-user.sh index f3a4679e..3adc7fdc 100644 --- a/tooling/scripts/configure-user.sh +++ b/tooling/scripts/configure-user.sh @@ -2,6 +2,7 @@ set -euo pipefail DEFAULT_USER=${1:-devbox} +ADMIN_GROUP=sudo # Add user devbox if id -u "$DEFAULT_USER" &>/dev/null; then echo "User $DEFAULT_USER already exists" @@ -20,8 +21,16 @@ else SHELL_PATH=/bin/sh fi useradd -m -s "$SHELL_PATH" "$DEFAULT_USER" -# Add user devbox to sudoers with NOPASSWD -usermod -aG sudo "$DEFAULT_USER" && echo "$DEFAULT_USER ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers +# Add user devbox to the distro's admin group and sudoers with NOPASSWD +if ! getent group "$ADMIN_GROUP" >/dev/null 2>&1; then + if getent group wheel >/dev/null 2>&1; then + ADMIN_GROUP=wheel + else + groupadd "$ADMIN_GROUP" + fi +fi +usermod -aG "$ADMIN_GROUP" "$DEFAULT_USER" +echo "$DEFAULT_USER ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers # Change the password of user devbox # The password is randomly generated and not logged or stored for security reasons. # SSH key-based authentication is required, as password authentication is disabled in sshd_config. diff --git a/tooling/scripts/install-base-pkg-rpm.sh b/tooling/scripts/install-base-pkg-rpm.sh new file mode 100644 index 00000000..890fa49b --- /dev/null +++ b/tooling/scripts/install-base-pkg-rpm.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +set -euo pipefail + +if command -v dnf >/dev/null 2>&1; then + PM=dnf +elif command -v yum >/dev/null 2>&1; then + PM=yum +else + echo "Neither dnf nor yum is available" >&2 + exit 1 +fi + +package_available() { + "$PM" list --showduplicates "$1" >/dev/null 2>&1 +} + +LOCALE_PACKAGES=( + glibc-locale-source + langpacks-en +) + +if package_available glibc-langpack-en; then + LOCALE_PACKAGES+=(glibc-langpack-en) +else + LOCALE_PACKAGES+=(glibc-all-langpacks) +fi + +if [ "${L10N:-en_US}" = "zh_CN" ]; then + LOCALE_PACKAGES+=(langpacks-zh_CN) +fi + +"$PM" install -y \ + bash \ + busybox \ + ca-certificates \ + cpio \ + cronie \ + curl \ + diffutils \ + findutils \ + git \ + gzip \ + iproute \ + logrotate \ + openssh-clients \ + openssh-server \ + openssl \ + passwd \ + procps-ng \ + shadow \ + sudo \ + tar \ + util-linux \ + vim-enhanced \ + wget \ + which \ + xz \ + "${LOCALE_PACKAGES[@]}" + +"$PM" clean all +rm -rf /var/cache/dnf /var/cache/yum diff --git a/tooling/scripts/l10n/en_US/configure-locale.sh b/tooling/scripts/l10n/en_US/configure-locale.sh index eb9a924f..24a63b52 100644 --- a/tooling/scripts/l10n/en_US/configure-locale.sh +++ b/tooling/scripts/l10n/en_US/configure-locale.sh @@ -1,7 +1,18 @@ #!/usr/bin/env bash set -euo pipefail -echo "LC_ALL=en_US.UTF-8" >> /etc/environment -echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen -echo "LANG=en_US.UTF-8" > /etc/locale.conf -locale-gen en_US.UTF-8 \ No newline at end of file +LOCALE=en_US.UTF-8 + +echo "LC_ALL=$LOCALE" >> /etc/environment +echo "$LOCALE UTF-8" >> /etc/locale.gen +echo "LANG=$LOCALE" > /etc/locale.conf + +if locale -a 2>/dev/null | grep -Eqi '^(en_US\.utf8|en_US\.UTF-8)$'; then + echo "$LOCALE already available" +elif command -v locale-gen >/dev/null 2>&1; then + locale-gen "$LOCALE" +elif command -v localedef >/dev/null 2>&1; then + localedef -i en_US -f UTF-8 "$LOCALE" || echo "Unable to generate $LOCALE with localedef; continuing" +else + echo "No locale generator found; continuing" +fi diff --git a/tooling/scripts/l10n/zh_CN/configure-locale.sh b/tooling/scripts/l10n/zh_CN/configure-locale.sh index f4d2074f..732a7653 100644 --- a/tooling/scripts/l10n/zh_CN/configure-locale.sh +++ b/tooling/scripts/l10n/zh_CN/configure-locale.sh @@ -2,7 +2,18 @@ set -euo pipefail # Currently, we set locale to en_US.UTF-8 even in zh_CN images -echo "LC_ALL=en_US.UTF-8" >> /etc/environment -echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen -echo "LANG=en_US.UTF-8" > /etc/locale.conf -locale-gen en_US.UTF-8 \ No newline at end of file +LOCALE=en_US.UTF-8 + +echo "LC_ALL=$LOCALE" >> /etc/environment +echo "$LOCALE UTF-8" >> /etc/locale.gen +echo "LANG=$LOCALE" > /etc/locale.conf + +if locale -a 2>/dev/null | grep -Eqi '^(en_US\.utf8|en_US\.UTF-8)$'; then + echo "$LOCALE already available" +elif command -v locale-gen >/dev/null 2>&1; then + locale-gen "$LOCALE" +elif command -v localedef >/dev/null 2>&1; then + localedef -i en_US -f UTF-8 "$LOCALE" || echo "Unable to generate $LOCALE with localedef; continuing" +else + echo "No locale generator found; continuing" +fi diff --git a/tooling/scripts/svc/configure-crond.sh b/tooling/scripts/svc/configure-crond.sh index 94f52181..6a614e5d 100644 --- a/tooling/scripts/svc/configure-crond.sh +++ b/tooling/scripts/svc/configure-crond.sh @@ -4,6 +4,10 @@ set -euo pipefail BASE_TOOLS_DIR=${BASE_TOOLS_DIR:-/opt/base-tools} ROOT_DIR=$BASE_TOOLS_DIR/scripts/svc source $ROOT_DIR/common.sh +LOG_GROUP=nogroup +if ! getent group "$LOG_GROUP" >/dev/null 2>&1; then + LOG_GROUP=nobody +fi # crond service make_longrun crond /usr/sbin/supercronic /etc/crontab touch "$S6_DIR/crond/dependencies.d/startup" @@ -18,7 +22,7 @@ echo 'crond-pipeline' > "$S6_DIR/crond-log/pipeline-name" # crond log preparation service make_oneshot_up crond-log-prepare \ 'if { mkdir -p /var/log/crond }' \ - 'if { chown nobody:nogroup /var/log/crond }' \ + "if { chown nobody:${LOG_GROUP} /var/log/crond }" \ 'chmod 02755 /var/log/crond' touch "$S6_DIR/crond-log-prepare/dependencies.d/base" @@ -33,4 +37,4 @@ for f in \ [ -f "$f" ] && chmod 700 "$f" || true done -echo "crond services ensured." >&2 \ No newline at end of file +echo "crond services ensured." >&2 diff --git a/tooling/scripts/svc/configure-sshd.sh b/tooling/scripts/svc/configure-sshd.sh index 68463c2c..c7fbb087 100644 --- a/tooling/scripts/svc/configure-sshd.sh +++ b/tooling/scripts/svc/configure-sshd.sh @@ -4,6 +4,10 @@ set -euo pipefail BASE_TOOLS_DIR=${BASE_TOOLS_DIR:-/opt/base-tools} ROOT_DIR=$BASE_TOOLS_DIR/scripts/svc source $ROOT_DIR/common.sh +LOG_GROUP=nogroup +if ! getent group "$LOG_GROUP" >/dev/null 2>&1; then + LOG_GROUP=nobody +fi # Configure sshd SSHD_CONFIG=/etc/ssh/sshd_config @@ -11,8 +15,8 @@ set_sshd_config() { local key value key="$(echo "$1" | awk '{print $1}')" value="$(echo "$1" | cut -d' ' -f2-)" - if grep -q "^$key " "$SSHD_CONFIG"; then - sed -i "s|^$key .*|$key $value|" "$SSHD_CONFIG" + if grep -Eq "^[[:space:]]*$key[[:space:]]+" "$SSHD_CONFIG"; then + sed -i -E "s|^[[:space:]]*$key[[:space:]]+.*|$key $value|" "$SSHD_CONFIG" else echo "$key $value" >> "$SSHD_CONFIG" fi @@ -23,6 +27,7 @@ set_sshd_config 'IgnoreRhosts yes' set_sshd_config 'ListenAddress 0.0.0.0' set_sshd_config 'Port 22' set_sshd_config 'AuthorizedKeysFile /usr/start/.ssh/authorized_keys' +set_sshd_config 'AllowTcpForwarding yes' set_sshd_config 'PasswordAuthentication no' set_sshd_config 'PubKeyAuthentication yes' set_sshd_config 'PermitRootLogin prohibit-password' @@ -31,6 +36,25 @@ mkdir -p /run/sshd && chmod 755 /run/sshd # sshd service make_longrun sshd /usr/sbin/sshd -D -e +cat > "$S6_DIR/sshd/run" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +exec 2>&1 + +mkdir -p /run/sshd +chmod 755 /run/sshd +rm -f /run/nologin /etc/nologin + +if ! ls /etc/ssh/ssh_host_*_key >/dev/null 2>&1; then + if ! command -v ssh-keygen >/dev/null 2>&1; then + echo "ssh-keygen is required to generate sshd host keys" >&2 + exit 1 + fi + ssh-keygen -A +fi + +exec /usr/sbin/sshd -D -e +EOF touch "$S6_DIR/sshd/dependencies.d/startup" echo 'sshd-log' > "$S6_DIR/sshd/producer-for" @@ -43,7 +67,7 @@ echo 'sshd-pipeline' > "$S6_DIR/sshd-log/pipeline-name" # Prepare sshd log directory service make_oneshot_up sshd-log-prepare \ 'if { mkdir -p /var/log/sshd }' \ - 'if { chown nobody:nogroup /var/log/sshd }' \ + "if { chown nobody:${LOG_GROUP} /var/log/sshd }" \ 'chmod 02755 /var/log/sshd' touch "$S6_DIR/sshd-log-prepare/dependencies.d/base" @@ -58,4 +82,4 @@ for f in \ [ -f "$f" ] && chmod 700 "$f" || true done -echo "sshd services ensured." >&2 \ No newline at end of file +echo "sshd services ensured." >&2