From ed898aef9c498f744f3ecada90af05715666639d Mon Sep 17 00:00:00 2001 From: rayd1o Date: Thu, 9 Apr 2026 23:08:31 +0800 Subject: [PATCH] docs: add docker compose and buildx upgrade guide - add a standalone docs guide for reinstalling Docker, Compose, and Buildx from the official Ubuntu repository - refine planet.sh compose/build diagnostics so docker compose is the primary wording and missing buildx / fallback cases report more accurately - keep the startup failure output aligned with the existing terminal tone while reducing misleading compose-version messaging --- docs/docker-compose-buildx-upgrade.md | 105 +++++++++++++++++++++ planet.sh | 130 ++++++++++++++++++++++---- 2 files changed, 219 insertions(+), 16 deletions(-) create mode 100644 docs/docker-compose-buildx-upgrade.md diff --git a/docs/docker-compose-buildx-upgrade.md b/docs/docker-compose-buildx-upgrade.md new file mode 100644 index 00000000..000c0556 --- /dev/null +++ b/docs/docker-compose-buildx-upgrade.md @@ -0,0 +1,105 @@ +# Docker + Compose + Buildx 升级教程 + +流程:删除旧版 -> 安装新版 -> 验证 + +--- + +# 1. 删除旧版本 + +## 删除 apt 安装的旧包 + +```bash +sudo apt remove -y docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc +``` + +--- + +## 删除系统中的 `docker-compose`(V1) + +```bash +sudo rm -f "$(which docker-compose 2>/dev/null)" +``` + +--- + +## 查找并删除手动安装的 Buildx 插件 + +```bash +docker info | sed -n '/Plugins:/,/^ Server:/p' | grep -A2 buildx +``` + +从输出中获取 `Path`,然后执行: + +```bash +rm -f +``` + +--- + +## 清理无用依赖 + +```bash +sudo apt autoremove -y +``` + +--- + +# 2. 安装 Docker 官方版本 + +包含 Docker Engine、Docker Compose 插件、Docker Buildx 插件。 + +## 安装依赖 + +```bash +sudo apt update +sudo apt install -y ca-certificates curl gnupg +``` + +--- + +## 添加 Docker GPG key + +```bash +sudo install -m 0755 -d /etc/apt/keyrings +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \ + sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg +sudo chmod a+r /etc/apt/keyrings/docker.gpg +``` + +--- + +## 添加官方仓库 + +```bash +echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ +sudo tee /etc/apt/sources.list.d/docker.list > /dev/null +``` + +--- + +## 安装 Docker + Compose + Buildx + +```bash +sudo apt update +sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin +``` + +--- + +# 3. 验证安装 + +```bash +docker --version +docker compose version +docker buildx version +``` + +--- + +# 4. 常用命令 + +```bash +docker compose up -d +docker compose down +docker buildx build . +``` diff --git a/planet.sh b/planet.sh index 5ced3165..4b9be282 100755 --- a/planet.sh +++ b/planet.sh @@ -84,7 +84,7 @@ ensure_local_runtime_bins_on_path() { ensure_local_runtime_bins_on_path # Shell / Docker helpers -compose_v2_available() { +compose_available() { docker compose version >/dev/null 2>&1 } @@ -95,9 +95,9 @@ compose_v1_available() { report_missing_compose() { clear_wait_spinner log_error "未检测到可用的 Docker Compose" - log_note "优先需要 Docker Compose v2 (`docker compose`)" + log_note '优先使用 `docker compose`' log_note "如果当前机器仍只装有旧版 `docker-compose`,也请确认该命令可执行" - log_note "推荐安装 Docker Compose v2 插件:" + log_note "推荐安装 Docker Compose 插件:" log_note ' mkdir -p ~/.docker/cli-plugins' log_note ' curl -SL https://github.com/docker/compose/releases/download/v2.40.3/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose' log_note ' chmod +x ~/.docker/cli-plugins/docker-compose' @@ -105,16 +105,53 @@ report_missing_compose() { return 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 +} + +log_buildx_diagnostics_if_needed() { + local current_buildx_version="" + local required_buildx_version="0.17.0" + + current_buildx_version="$(buildx_version)" + + if [ -z "$current_buildx_version" ]; then + log_note "未检测到 docker buildx,AI Provider 镜像构建依赖 buildx。" + log_note "请先执行: docker buildx version" + return 0 + fi + + if ! buildx_meets_minimum "$current_buildx_version" "$required_buildx_version"; then + log_note "检测到 docker buildx 当前版本为 v${current_buildx_version},但 compose build 需要 v${required_buildx_version} 或更高。" + log_note "可先升级 buildx 插件,再重新执行 ./planet.sh start" + log_note "请先执行: docker buildx version" + fi +} + compose_up() { local args=("$@") local arg_text="$*" - if compose_v2_available; then - set_wait_detail "正在用 docker compose v2 执行: ${arg_text}" + if compose_available; then + set_wait_detail "正在用 docker compose 执行: ${arg_text}" if docker compose "${args[@]}"; then return 0 fi - log_warn "docker compose v2 执行失败,回退到 docker-compose v1" + log_warn "docker compose 执行失败,回退到 docker-compose v1" fi if compose_v1_available; then @@ -123,7 +160,7 @@ compose_up() { return 0 fi clear_wait_spinner - log_error "docker compose v2 与 docker-compose v1 均执行失败" + log_error "docker compose 与 docker-compose v1 均执行失败" log_note "最后尝试的命令: docker-compose ${arg_text}" return 1 fi @@ -132,7 +169,7 @@ compose_up() { } compose_supports_build() { - if compose_v2_available; then + if compose_available; then docker compose build --help >/dev/null 2>&1 && return 0 fi if compose_v1_available; then @@ -392,6 +429,58 @@ run_with_retry() { return 1 } +docker_daemon_available() { + docker info >/dev/null 2>&1 +} + +log_docker_daemon_diagnostics() { + local docker_service_status="" + local docker_socket_status="" + local service_hint="sudo systemctl enable --now docker.socket && sudo systemctl restart docker" + + docker_service_status="$(systemctl is-active docker 2>/dev/null || true)" + docker_socket_status="$(systemctl is-active docker.socket 2>/dev/null || true)" + + if [ -S /var/run/docker.sock ] && [ ! -r /var/run/docker.sock ]; then + log_note "检测到 /var/run/docker.sock 存在,但当前用户无法访问。" + log_note "请确认当前用户已加入 docker 组,并重新登录会话。" + return 0 + fi + + if [ "$docker_service_status" = "active" ]; then + log_note "Docker CLI 可执行,但当前会话仍无法连接 daemon。" + log_note "请先执行: docker info" + return 0 + fi + + if [ "$docker_service_status" = "failed" ] || [ "$docker_socket_status" = "failed" ]; then + log_note "检测到 Docker daemon 当前未正常运行。" + log_note "可先执行: ${service_hint}" + log_note "如仍失败,继续查看: journalctl -u docker.service -n 50 --no-pager" + return 0 + fi + + if [ "$docker_socket_status" != "active" ]; then + log_note "检测到 Docker socket 未激活,daemon 可能无法通过 systemd socket activation 启动。" + log_note "可先执行: ${service_hint}" + return 0 + fi + + log_note "当前无法连接 Docker daemon,请先执行: docker info" + log_note "若 daemon 未启动,可尝试: ${service_hint}" +} + +print_database_failure_diagnostics() { + if ! docker_daemon_available; then + log_note "数据库容器尚未真正开始启动,当前失败更像是 Docker 运行时不可用。" + log_docker_daemon_diagnostics + return 0 + fi + + docker logs --tail 20 planet_postgres 2>/dev/null || true + docker logs --tail 20 planet_redis 2>/dev/null || true +} + compute_ai_provider_build_fingerprint() { ( cd "$SCRIPT_DIR" || exit 1 @@ -481,6 +570,7 @@ ensure_ai_provider_image_current() { clear_wait_spinner log_error "AI Provider 镜像构建失败" tail -20 "$AI_PROVIDER_BUILD_LOG_FILE" 2>/dev/null || true + log_buildx_diagnostics_if_needed exit 1 fi log_success "AI Provider 镜像已构建" @@ -490,12 +580,17 @@ ensure_ai_provider_image_current() { } build_ai_provider_image_with_fallback() { - if compose_v2_available; then - set_wait_detail "使用 Docker Compose v2 构建 AI Provider 镜像" + if compose_available; then + set_wait_detail "使用 docker compose 构建 AI Provider 镜像" if run_command_with_spinner "构建 AI Provider 镜像" sh -c "docker compose build aiprovider > \"$AI_PROVIDER_BUILD_LOG_FILE\" 2>&1"; then return 0 fi - log_warn "Docker Compose v2 构建失败,回退到 docker-compose v1" + if compose_v1_available; then + log_warn "docker compose 构建失败,回退到 docker-compose v1" + else + log_warn "docker compose 构建失败,当前环境未安装 docker-compose v1,无法继续回退" + return 1 + fi fi if compose_v1_available; then @@ -969,8 +1064,7 @@ ensure_database_services_healthy() { if [ "$retry" -eq "$DATABASE_START_MAX_RETRIES" ]; then log_error "数据库启动失败,已重试 ${DATABASE_START_MAX_RETRIES} 次" - docker logs --tail 20 planet_postgres 2>/dev/null || true - docker logs --tail 20 planet_redis 2>/dev/null || true + print_database_failure_diagnostics exit 1 fi @@ -990,7 +1084,12 @@ ensure_postgres_service_healthy() { if [ "$retry" -eq "$DATABASE_START_MAX_RETRIES" ]; then log_error "PostgreSQL 启动失败,已重试 ${DATABASE_START_MAX_RETRIES} 次" - docker logs --tail 20 planet_postgres 2>/dev/null || true + if ! docker_daemon_available; then + log_note "PostgreSQL 容器尚未真正开始启动,当前失败更像是 Docker 运行时不可用。" + log_docker_daemon_diagnostics + else + docker logs --tail 20 planet_postgres 2>/dev/null || true + fi exit 1 fi @@ -1012,8 +1111,7 @@ restart_database_service() { if [ "$retry" -eq "$DATABASE_START_MAX_RETRIES" ]; then log_error "数据库重启失败,已重试 ${DATABASE_START_MAX_RETRIES} 次" - docker logs --tail 20 planet_postgres 2>/dev/null || true - docker logs --tail 20 planet_redis 2>/dev/null || true + print_database_failure_diagnostics exit 1 fi