Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions base-images/operating-systems/alpine/3.22/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# 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 ALPINE_IMAGE=alpine:3.22
# 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 ${ALPINE_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}
# Bash is required to execute the shared tooling scripts.
COPY build.sh /build.sh
RUN apk add --no-cache bash && \
chmod +x /build.sh && \
/build.sh && \
rm -f /build.sh && \
rm -rf ${BASE_TOOLS_DIR}
## Alpine uses musl; export UTF-8 defaults for non-login processes.
ENV LANG=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8
ENTRYPOINT [ "/init" ]
49 changes: 49 additions & 0 deletions base-images/operating-systems/alpine/3.22/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/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 the Alpine/APK family.
"$BASE_TOOLS_DIR/scripts/install-base-pkg-apk.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"

# Product-provided startup scripts can remain active for the DevBox lifetime
# (for example, while serving VS Code Web). Core services must not wait for
# that startup oneshot to exit before they are allowed to run.
rm -f \
/etc/s6-overlay/s6-rc.d/sshd/dependencies.d/startup \
/etc/s6-overlay/s6-rc.d/crond/dependencies.d/startup

# 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"
25 changes: 25 additions & 0 deletions runtime-images/operating-systems/alpine/3.22/Dockerfile
Original file line number Diff line number Diff line change
@@ -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}/alpine-3.22:${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
34 changes: 34 additions & 0 deletions runtime-images/operating-systems/alpine/3.22/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/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/"
chmod 0755 "$TARGET_DIR/"*.sh

# Set ownership to default devbox user.
chown -R "$DEFAULT_DEVBOX_USER:$DEFAULT_DEVBOX_USER" "$TARGET_DIR"
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Alpine 3.22 Runtime Template

This template provides a minimal **operating-system runtime** based on Alpine Linux 3.22.
Use it when you want a compact Linux environment and full control of your language, framework, or application stack.

## Runtime Summary

- OS version: `Alpine Linux 3.22`
- Base runtime image: `alpine-3.22`
- Package manager: `apk`
- C library: `musl`
- 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 the `PORT` environment variable when provided, and 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!
```

## Package Management

Install application dependencies with `apk`:

```bash
sudo apk add --no-cache file
```

## Compatibility

Alpine uses musl instead of the glibc used by Debian, Ubuntu, and Fedora. The image includes `gcompat`, `libgcc`, and `libstdc++` for practical compatibility, but these packages do not make every glibc-only binary or native extension compatible. Validate third-party development tools against Alpine before relying on them.

## Customization

- Replace `entrypoint.sh` with your own process startup script.
- Use `apk` to install application dependencies.
- Align container exposed ports with your service port.
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Alpine 3.22 运行时模板

该模板提供一个基于 Alpine Linux 3.22 的最小化**操作系统运行时**。
适用于需要轻量 Linux 环境,并在其上自行安装语言、框架或业务依赖的场景。

## 运行时概览

- 系统版本:`Alpine Linux 3.22`
- 基础运行时镜像:`alpine-3.22`
- 包管理器:`apk`
- C 标准库:`musl`
- 启动脚本:`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!
```

## 包管理

使用 `apk` 安装业务依赖:

```bash
sudo apk add --no-cache file
```

## 兼容性说明

Alpine 使用 musl,而 Debian、Ubuntu 和 Fedora 通常使用 glibc。镜像包含 `gcompat`、`libgcc` 和 `libstdc++` 以提供常见兼容能力,但这些软件包不能保证所有仅支持 glibc 的二进制文件或原生扩展都能运行。依赖第三方开发工具时,应先单独验证其 Alpine 兼容性。

## 自定义建议

- 可将 `entrypoint.sh` 替换为你的进程启动脚本。
- 使用 `apk` 安装业务依赖。
- 保持容器暴露端口与服务监听端口一致。
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions tests/runtime-conformance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Runtime-specific checks:
| Runtime | Checks |
| --- | --- |
| `operating-systems/anolis/23.4` | Anolis identity, busybox, localized README, root/devbox entrypoint order |
| `operating-systems/alpine/3.22` | Alpine 3.22 identity, `apk`, busybox, Bash, sudo, network/archive tools, OpenSSH without embedded host keys, musl compatibility packages (`gcompat`, `libstdc++`, `libgcc`), 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 |
Expand Down
29 changes: 29 additions & 0 deletions tests/runtime-conformance/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,32 @@ check_os_runtime() {
assert_command busybox
}

check_alpine_runtime() {
check_os_runtime alpine
grep -Eq 'VERSION_ID="?3[.]22"?' /etc/os-release || fail "expected Alpine 3.22 in /etc/os-release"
assert_command apk
assert_command bash
assert_command sudo
assert_command curl
assert_command wget
assert_command git
assert_command python3
assert_command tar
assert_command gzip
assert_command unzip
assert_command zip
assert_command ssh
assert_executable /usr/sbin/sshd
for package_name in gcompat libstdc++ libgcc openssh openssh-client openssh-server bash sudo; do
apk info -e "$package_name" >/dev/null 2>&1 || fail "missing Alpine package: $package_name"
done
for service_name in sshd crond; do
if [ -e "/etc/s6-overlay/s6-rc.d/$service_name/dependencies.d/startup" ]; then
fail "$service_name must not wait for the long-running DevBox startup service"
fi
done
}

check_cuda_runtime() {
log "check CUDA runtime"
if command -v nvcc >/dev/null 2>&1; then
Expand Down Expand Up @@ -599,6 +625,9 @@ check_runtime_specifics() {
operating-systems/anolis/23.4)
check_os_runtime anolis
;;
operating-systems/alpine/3.22)
check_alpine_runtime
;;
operating-systems/debian/12.6)
check_os_runtime debian
;;
Expand Down
Loading