Files
planet/scripts/lib/docker-bootstrap.zsh
rayd1o a54fcdbeed
Some checks failed
ci / backend (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / delivery (push) Has been cancelled
release / images (push) Has been cancelled
ci / backend (pull_request) Has been cancelled
ci / frontend (pull_request) Has been cancelled
ci / delivery (pull_request) Has been cancelled
release: bump version to 0.74.3
2026-09-13 02:17:55 +08:00

240 lines
8.9 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env zsh
# Docker prerequisites for planet.sh; lifecycle and logging remain in planet.sh.
DOCKER_MIN_BUILDX_VERSION="0.17.0"
compose_available() {
docker compose version >/dev/null 2>&1
}
compose_v1_available() {
command -v docker-compose >/dev/null 2>&1
}
buildx_version() {
docker buildx version 2>/dev/null | awk '{print $2}' | sed 's/^v//'
}
buildx_meets_minimum() {
local current_version="$1"
local required_version="$2"
[ -n "$current_version" ] || return 1
[ -n "$required_version" ] || return 1
if [ "$(printf '%s\n%s\n' "$required_version" "$current_version" | sort -V | head -n 1)" = "$required_version" ]; then
return 0
fi
return 1
}
docker_daemon_available() {
command -v docker >/dev/null 2>&1 && command docker info >/dev/null 2>&1
}
docker_uses_local_engine() {
local endpoint="${DOCKER_HOST:-}"
if [ -n "${DOCKER_CONTEXT:-}" ] || [ -z "$endpoint" ]; then
if command -v docker >/dev/null 2>&1; then
endpoint="$(command docker context inspect --format '{{.Endpoints.docker.Host}}' 2>/dev/null)" || return 1
elif [ -n "${DOCKER_CONTEXT:-}" ]; then
return 1
else
endpoint="unix:///var/run/docker.sock"
fi
fi
case "$endpoint" in
unix:///var/run/docker.sock|unix:///run/docker.sock) return 0 ;;
*) return 1 ;;
esac
}
docker_desktop_present() {
local docker_path=""
[ -d /mnt/wsl/docker-desktop ] && return 0
docker_path="$(command -v docker 2>/dev/null || true)"
[ -n "$docker_path" ] || return 1
docker_path="$(readlink -f "$docker_path" 2>/dev/null || true)"
[[ "$docker_path" == */docker-desktop/* ]]
}
docker_systemd_unit_exists() {
command -v systemctl >/dev/null 2>&1 || return 1
[ "$(systemctl show --property=LoadState --value "$1" 2>/dev/null)" = "loaded" ]
}
docker_socket_needs_group_access() {
[ -S /var/run/docker.sock ] && { [ ! -r /var/run/docker.sock ] || [ ! -w /var/run/docker.sock ]; }
}
docker_require_sudo() {
[ "$(id -u)" -eq 0 ] && return 0
if ! command -v sudo >/dev/null 2>&1; then
log_error "缺少 sudo无法安装或配置 Docker请先由管理员安装 sudo 并授予当前用户权限。"
return 1
fi
# Authenticate in the foreground, before command output is redirected to a log.
sudo -v
}
docker_as_root() {
if [ "$(id -u)" -eq 0 ]; then
"$@"
else
sudo -- "$@"
fi
}
refresh_docker_group() {
[ "$(id -u)" -ne 0 ] || return 0
command -v docker >/dev/null 2>&1 || return 0
docker_uses_local_engine || return 0
docker_socket_needs_group_access || return 0
local username="$(id -un)"
local groups="$(id -nG "$username")"
[[ " $groups " == *" docker "* ]] || return 0
if [ "${PLANET_DOCKER_GROUP_REEXEC:-0}" = "1" ]; then
log_error "刷新组权限后仍无法访问 Docker socket请检查 socket 的属组和权限。"
return 1
fi
docker_require_sudo || return 1
log_note "刷新 Docker 组权限,以当前用户继续执行。"
# Preserve WSL interop/tool paths even when sudo applies secure_path.
# argv stays an array: repository paths and arguments are never evaluated as shell text.
exec sudo -E -u "$username" -g docker -- env PLANET_DOCKER_GROUP_REEXEC=1 "PATH=$PATH" \
"$(command -v zsh)" "$SCRIPT_DIR/planet.sh" "$@"
}
docker_bootstrap_os_id() {
[ -r /etc/os-release ] || return 1
(. /etc/os-release; printf '%s\n' "$ID")
}
install_docker_prerequisites() {
local log_file="$PLANET_STATE_DIR/docker_install.log"
local engine_package="docker.io"
local compose_package="docker-compose-v2"
local buildx_package="docker-buildx"
local -a packages=()
if [ "$(docker_bootstrap_os_id)" != "ubuntu" ] || ! command -v apt-get >/dev/null 2>&1; then
log_error "Docker 自动安装目前支持 Ubuntu / Ubuntu WSL请先安装本系统的 Docker Engine、Compose v2 和 Buildx。"
return 1
fi
if command -v dpkg-query >/dev/null 2>&1 &&
[ "$(dpkg-query -W -f='${Status}' docker-ce-cli 2>/dev/null)" = "install ok installed" ]; then
engine_package="docker-ce"
compose_package="docker-compose-plugin"
buildx_package="docker-buildx-plugin"
fi
if ! command -v docker >/dev/null 2>&1 ||
{ ! docker_daemon_available && ! command -v dockerd >/dev/null 2>&1; }; then
packages+=("$engine_package")
fi
compose_available || packages+=("$compose_package")
buildx_meets_minimum "$(buildx_version)" "$DOCKER_MIN_BUILDX_VERSION" || packages+=("$buildx_package")
[ "${#packages[@]}" -gt 0 ] || return 0
docker_require_sudo || return 1
log_step "安装 Docker 依赖: ${packages[*]}"
if ! run_command_quiet_unless_verbose "$log_file" docker_as_root apt-get update --error-on=any ||
! run_command_quiet_unless_verbose "$log_file" docker_as_root apt-get install -y "${packages[@]}"; then
log_error "Docker 依赖安装失败,请检查软件源、网络和 apt 错误。"
tail -20 "$log_file" 2>/dev/null || true
return 1
fi
rehash
}
start_local_docker_engine() {
local log_file="$PLANET_STATE_DIR/docker_service.log"
if ! docker_systemd_unit_exists docker.service; then
log_error "没有可用的 docker.service请确认 Docker Engine 已安装且 systemd 正常运行。"
log_note "Ubuntu WSL 可在 /etc/wsl.conf 的 [boot] 下启用 systemd=true再重启 WSL。"
return 1
fi
docker_require_sudo || return 1
if ! run_command_quiet_unless_verbose "$log_file" docker_as_root systemctl enable --now docker.service; then
log_error "Docker Engine 启动失败。"
tail -20 "$log_file" 2>/dev/null || true
log_note "查看原因: journalctl -u docker.service -n 50 --no-pager"
return 1
fi
}
ensure_docker_user_access() {
[ "$(id -u)" -ne 0 ] || return 0
docker_socket_needs_group_access || return 0
docker_require_sudo || return 1
ensure_system_command usermod passwd "usermod" || return 1
log_note "将当前用户加入 docker 组(该组可管理本机 Docker。"
docker_as_root usermod -aG docker "$(id -un)" || return 1
refresh_docker_group "$@"
}
ensure_docker_runtime() {
if docker_daemon_available && compose_available &&
buildx_meets_minimum "$(buildx_version)" "$DOCKER_MIN_BUILDX_VERSION"; then
return 0
fi
if docker_desktop_present; then
log_error "检测到 Docker Desktop但当前 WSL 的 Docker / Compose / Buildx 尚不可用。"
log_note "请启动 Docker Desktop并为当前发行版启用 WSL Integration。"
return 1
fi
if ! docker_uses_local_engine; then
log_error "当前 Docker 使用其他 context 或远程/rootless endpoint请先检查该环境的连接和插件。"
return 1
fi
install_docker_prerequisites || return 1
if ! command -v docker >/dev/null 2>&1 || ! compose_available ||
! buildx_meets_minimum "$(buildx_version)" "$DOCKER_MIN_BUILDX_VERSION"; then
log_error "安装后 Docker CLI、Compose v2 或 Buildx >= ${DOCKER_MIN_BUILDX_VERSION} 仍不可用。"
return 1
fi
if ! docker_daemon_available; then
start_local_docker_engine || return 1
ensure_docker_user_access "$@" || return 1
fi
if ! docker_daemon_available; then
log_error "Docker 已安装,但当前用户仍无法连接 daemon。"
log_docker_daemon_diagnostics
return 1
fi
}
log_docker_daemon_diagnostics() {
if ! command -v docker >/dev/null 2>&1; then
log_note "未找到 Docker CLI尚未安装 DockerUbuntu / WSL 请先执行 ./planet.sh init。"
return 0
fi
if docker_desktop_present; then
log_note "请启动 Docker Desktop并确认当前 WSL 已启用 WSL Integration。"
return 0
fi
if ! docker_uses_local_engine; then
log_note "当前使用其他 Docker endpoint请检查 docker context ls 和 docker info。"
return 0
fi
if docker_socket_needs_group_access; then
log_note "Docker socket 存在,但当前用户没有读写权限;请执行 ./planet.sh init 配置 docker 组。"
return 0
fi
if ! docker_systemd_unit_exists docker.service; then
log_note "未检测到可用的 docker.serviceUbuntu / WSL 请执行 ./planet.sh init 检查安装。"
return 0
fi
if [ "$(systemctl is-active docker.service 2>/dev/null)" = "active" ]; then
log_note "Docker 服务已启动,但 CLI 无法连接;请检查 docker context ls 和 docker info。"
return 0
fi
if docker_systemd_unit_exists docker.socket; then
log_note "可先执行: sudo systemctl enable --now docker.socket && sudo systemctl restart docker.service"
else
log_note "可先执行: sudo systemctl enable --now docker.service"
fi
log_note "如仍失败,查看: journalctl -u docker.service -n 50 --no-pager"
}