把docker-compose之类的服务维护到systemd中去,手动有点麻烦,搞个脚本。

  1#!/bin/bash
  2
  3# ==============================================================================
  4# Docker Compose Systemd 服务交互式配置工具
  5# ==============================================================================
  6# 描述: 此脚本将引导用户为多个 Docker Compose 项目创建 systemd 服务,
  7#       从而实现应用的开机自启动和便捷管理。
  8# 版本: 1.0
  9# 作者: Gemini Assistant
 10# 日期: 2025-06-02
 11# ==============================================================================
 12
 13# --- 配置项 (通常无需修改) ---
 14# 默认的 docker-compose 命令路径。如果系统找不到,将尝试此路径。
 15DEFAULT_DOCKER_COMPOSE_CMD="/usr/local/bin/docker-compose"
 16
 17# --- 辅助函数 ---
 18
 19# 检查指定命令是否存在于 PATH 中
 20command_exists () {
 21  command -v "$1" >/dev/null 2>&1
 22}
 23
 24# 提示用户输入,并可选地进行路径或文件存在性验证
 25get_input() {
 26    local prompt="$1"         # 提示信息
 27    local var_name="$2"       # 存储用户输入的变量名
 28    local default_val="$3"    # 默认值 (可选)
 29    local check_type="$4"     # 检查类型: 'dir' (目录), 'file' (文件), '' (无检查)
 30
 31    while true; do
 32        if [ -n "$default_val" ]; then
 33            read -rp "$prompt [$default_val]: " input
 34        else
 35            read -rp "$prompt: " input
 36        fi
 37        input="${input:-$default_val}" # 如果用户输入为空,则使用默认值
 38
 39        if [ -z "$input" ]; then
 40            echo "输入不能为空,请重新输入。"
 41            continue
 42        fi
 43
 44        case "$check_type" in
 45            "dir")
 46                if [ ! -d "$input" ]; then
 47                    echo "错误:路径 '$input' 不存在或不是一个目录。请重新输入。"
 48                    continue
 49                fi
 50                # 对于 Docker Compose 项目目录,额外检查是否存在 docker-compose.yml
 51                if [ ! -f "$input/docker-compose.yml" ] && [ ! -f "$input/docker-compose.yaml" ]; then
 52                    echo "警告:在 '$input' 中找不到 'docker-compose.yml' 或 'docker-compose.yaml' 文件。"
 53                    read -rp "您确定要使用此路径吗?(y/N): " confirm_path
 54                    if [[ ! "$confirm_path" =~ ^[yY]$ ]]; then
 55                        continue
 56                    fi
 57                fi
 58                ;;
 59            "file")
 60                if [ ! -f "$input" ]; then
 61                    echo "错误:文件 '$input' 不存在。请重新输入。"
 62                    continue
 63                fi
 64                ;;
 65            *)
 66                # 无需特定检查
 67                ;;
 68        esac
 69
 70        # 将输入的值赋给指定的变量名
 71        eval "$var_name='$input'"
 72        break
 73    done
 74}
 75
 76# --- 主要逻辑 ---
 77
 78main() {
 79    echo "--- 欢迎使用 Docker Compose Systemd 服务交互式配置工具 ---"
 80    echo "此脚本将帮助您为多个 Docker Compose 项目创建 systemd 服务,实现开机自启动和便捷管理。"
 81    echo ""
 82
 83    # 1. 检查 docker-compose 命令路径
 84    echo "步骤 1/4: 检查 Docker Compose 命令路径..."
 85    local docker_compose_cmd_found=false
 86    if command_exists "docker-compose"; then
 87        DOCKER_COMPOSE_CMD=$(command -v docker-compose)
 88        docker_compose_cmd_found=true
 89        echo "✅ 检测到 'docker-compose' 命令路径: $DOCKER_COMPOSE_CMD"
 90    else
 91        echo "⚠️ 警告:未在 PATH 中找到 'docker-compose' 命令。"
 92        echo "   脚本将尝试使用默认路径: $DEFAULT_DOCKER_COMPOSE_CMD"
 93        DOCKER_COMPOSE_CMD="$DEFAULT_DOCKER_COMPOSE_CMD"
 94
 95        read -rp "   您是否希望手动指定 'docker-compose' 命令的完整路径?(y/N): " confirm_path_change
 96        if [[ "$confirm_path_change" =~ ^[yY]$ ]]; then
 97            get_input "   请输入正确的 'docker-compose' 命令完整路径" DOCKER_COMPOSE_CMD "$DOCKER_COMPOSE_CMD" "file"
 98        fi
 99
100        if [ ! -f "$DOCKER_COMPOSE_CMD" ]; then
101            echo "❌ 错误:指定的 Docker Compose 命令 '$DOCKER_COMPOSE_CMD' 不存在。"
102            echo "   请确保 Docker Compose 已正确安装并可执行。"
103            exit 1
104        fi
105        echo "✅ 将使用 'docker-compose' 命令路径: $DOCKER_COMPOSE_CMD"
106    fi
107    echo ""
108
109    # 存储所有已成功配置的服务名称
110    declare -a configured_services
111
112    # 2. 循环配置每个 Docker Compose 项目
113    while true; do
114        echo "--- 开始配置新的 Docker Compose 项目 ---"
115
116        local current_project_path
117        local current_service_name
118        local current_service_description
119
120        # 获取项目路径
121        get_input "请输入 Docker Compose 项目的**绝对路径** (例如: /opt/my-app)" current_project_path "" "dir"
122
123        # 生成并获取服务名称
124        # 尝试根据项目路径的最后一个目录名生成默认服务名称
125        local default_service_name
126        default_service_name=$(basename "$current_project_path" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g' | sed 's/^-*//' | sed 's/-*$//')
127        get_input "请输入此服务的名称 (例如: my-web-app)。这将是 systemd 服务文件名" current_service_name "$default_service_name" ""
128
129        # 检查服务名称是否重复
130        if [[ " ${configured_services[*]} " =~ " ${current_service_name} " ]]; then
131            echo "❌ 错误:服务名称 '$current_service_name' 已被使用,请使用不同的名称。"
132            continue # 重新开始当前项目的配置
133        fi
134
135        # 获取服务描述
136        get_input "请输入此服务的简短描述 (例如: My Web Application)" current_service_description "My Docker Compose Service" ""
137
138        local service_file="/etc/systemd/system/${current_service_name}.service"
139
140        echo ""
141        echo "--- 确认当前项目配置 ---"
142        echo "项目路径:              $current_project_path"
143        echo "服务名称:              $current_service_name"
144        echo "服务描述:              $current_service_description"
145        echo "将创建的服务文件:      $service_file"
146        echo "使用的 Docker Compose: $DOCKER_COMPOSE_CMD"
147        read -rp "以上信息确认无误?(y/N): " confirm_config
148        if [[ ! "$confirm_config" =~ ^[yY]$ ]]; then
149            echo "ℹ️ 取消当前项目的配置,请重新输入。"
150            continue # 重新开始当前项目的配置
151        fi
152
153        # 3. 创建 systemd 服务文件
154        echo ""
155        echo "步骤 2/4: 正在创建 systemd 服务文件:$service_file..."
156        local service_file_content="[Unit]
157Description=$current_service_description
158Requires=docker.service
159After=docker.service network-online.target
160
161[Service]
162Type=oneshot
163RemainAfterExit=yes
164WorkingDirectory=$current_project_path
165ExecStart=$DOCKER_COMPOSE_CMD up -d --remove-orphans
166ExecStop=$DOCKER_COMPOSE_CMD down
167ExecReload=$DOCKER_COMPOSE_CMD pull --quiet --parallel && $DOCKER_COMPOSE_CMD up -d
168
169[Install]
170WantedBy=multi-user.target
171"
172        echo "$service_file_content" | sudo tee "$service_file" > /dev/null
173
174        if [ $? -eq 0 ]; then
175            echo "✅ 服务文件创建成功。"
176        else
177            echo "❌ 错误:创建服务文件失败。请检查权限。"
178            read -rp "是否继续配置其他服务?(y/N): " continue_others
179            if [[ ! "$continue_others" =~ ^[yY]$ ]]; then break; fi
180            continue
181        fi
182
183        # 4. 重新加载 systemd 配置,启用并启动服务
184        echo "步骤 3/4: 重新加载 systemd 配置..."
185        sudo systemctl daemon-reload
186        if [ $? -eq 0 ]; then
187            echo "✅ systemd 配置重新加载成功。"
188        else
189            echo "❌ 错误:systemd 配置重新加载失败。"
190            read -rp "是否继续配置其他服务?(y/N): " continue_others
191            if [[ ! "$continue_others" =~ ^[yY]$ ]]; then break; fi
192            continue
193        fi
194
195        echo "步骤 4/4: 启用服务 ($current_service_name) 以便开机自启动..."
196        sudo systemctl enable "$current_service_name.service"
197        if [ $? -eq 0 ]; then
198            echo "✅ 服务已成功启用,将在系统启动时自动运行。"
199        else
200            echo "❌ 错误:启用服务失败。"
201            read -rp "是否继续配置其他服务?(y/N): " continue_others
202            if [[ ! "$continue_others" =~ ^[yY]$ ]]; then break; fi
203            continue
204        fi
205
206        echo "立即启动服务 ($current_service_name)..."
207        sudo systemctl start "$current_service_name.service"
208        if [ $? -eq 0 ]; then
209            echo "✅ 服务已成功启动。"
210        else
211            echo "❌ 错误:启动服务失败。请检查日志:sudo journalctl -u $current_service_name.service"
212            read -rp "是否继续配置其他服务?(y/N): " continue_others
213            if [[ ! "$continue_others" =~ ^[yY]$ ]]; then break; fi
214            continue
215        fi
216
217        # 将成功配置的服务名称添加到列表中
218        configured_services+=("$current_service_name")
219        echo ""
220        read -rp "成功配置 '$current_service_name'。是否需要配置另一个 Docker Compose 项目?(y/N): " another_project
221        if [[ ! "$another_project" =~ ^[yY]$ ]]; then
222            break # 退出循环
223        fi
224        echo "" # 打印空行以分隔不同项目的配置
225    done
226
227    # --- 总结与后续操作提示 ---
228    echo ""
229    echo "--- 所有 Docker Compose 服务配置完成! ---"
230    if [ ${#configured_services[@]} -gt 0 ]; then
231        echo "已成功配置以下服务:"
232        for svc in "${configured_services[@]}"; do
233            echo "  - ${svc}.service"
234        done
235        echo ""
236        echo "你可以使用以下命令来管理这些服务:"
237        echo "  - **查看所有 Docker Compose 服务的状态:**"
238        echo "    systemctl list-units --type=service | grep \"docker-compose\\|${configured_services[0]}\" # 或 grep 你服务名称的共同模式"
239        echo "  - **查看特定服务状态** (例如: ${configured_services[0]}.service):"
240        echo "    sudo systemctl status ${configured_services[0]}.service"
241        echo "  - **启动特定服务** (例如: ${configured_services[0]}.service):"
242        echo "    sudo systemctl start ${configured_services[0]}.service"
243        echo "  - **停止特定服务** (例如: ${configured_services[0]}.service):"
244        echo "    sudo systemctl stop ${configured_services[0]}.service"
245        echo "  - **重启特定服务** (例如: ${configured_services[0]}.service):"
246        echo "    sudo systemctl restart ${configured_services[0]}.service"
247        echo "  - **查看特定服务日志** (例如: ${configured_services[0]}.service):"
248        echo "    sudo journalctl -u ${configured_services[0]}.service -f"
249        echo "  - **禁用特定服务的开机自启动** (例如: ${configured_services[0]}.service):"
250        echo "    sudo systemctl disable ${configured_services[0]}.service"
251    else
252        echo "没有成功配置任何服务。"
253    fi
254    echo ""
255    echo "脚本执行完毕。感谢您的使用!"
256}
257
258# 运行主函数
259main "$@"