diff --git a/docs/服务端启动命令.md b/docs/服务端启动命令.md index 5178900..98d0458 100644 --- a/docs/服务端启动命令.md +++ b/docs/服务端启动命令.md @@ -1,23 +1,294 @@ -启动 -systemctl daemon-reload +## 方式一:使用 systemd 服务(推荐) + +### 自动安装(推荐) + +使用安装脚本自动配置 systemd 服务: + +```bash +# 进入脚本目录 +cd /www/wwwroot/api.yunzer.cn/scripts + +# 添加执行权限 +chmod +x install-systemd-service.sh + +# 运行安装脚本 +sudo bash install-systemd-service.sh +``` + +脚本会自动: +- 停止现有服务和进程 +- 创建正确的 systemd 配置文件 +- 启动服务 +- 启用开机自启 +- 显示服务状态和日志 + +### 手动安装 + +如果需要手动配置: + +```bash +# 1. 停止现有服务 +systemctl stop go-api +pkill -f "go run main.go" + +# 2. 复制服务文件 +sudo cp /www/wwwroot/api.yunzer.cn/scripts/go-api.service /etc/systemd/system/ + +# 3. 重载 systemd +sudo systemctl daemon-reload + +# 4. 启动服务 +sudo systemctl start go-api + +# 5. 启用开机自启 +sudo systemctl enable go-api + +# 6. 查看状态 +sudo systemctl status go-api +``` + +### 启动服务 +```bash +systemctl start go-api +``` + +### 查看状态 +```bash +systemctl status go-api +``` + +### 常用命令 +```bash +# 启动 systemctl start go-api -查看是否成功 +# 停止 +systemctl stop go-api + +# 重启 +systemctl restart go-api + +# 查看状态 systemctl status go-api -启动:systemctl start go-api -停止:systemctl stop go-api -重启:systemctl restart go-api -查看状态:systemctl status go-api +# 查看日志(systemd 日志) +journalctl -u go-api -f +# 查看日志(文件日志) +tail -f /www/wwwroot/api.yunzer.cn/go.log -后台直接启动 +# 开机自启 +systemctl enable go-api + +# 禁用开机自启 +systemctl disable go-api +``` + +## 方式二:使用管理脚本(推荐) + +### 脚本位置 +```bash +/www/wwwroot/api.yunzer.cn/scripts/service.sh +``` + +### 添加执行权限 +```bash +chmod +x /www/wwwroot/api.yunzer.cn/scripts/service.sh +``` + +### 常用命令 +```bash +# 启动服务 +bash /www/wwwroot/api.yunzer.cn/scripts/service.sh start + +# 停止服务 +bash /www/wwwroot/api.yunzer.cn/scripts/service.sh stop + +# 重启服务 +bash /www/wwwroot/api.yunzer.cn/scripts/service.sh restart + +# 查看状态 +bash /www/wwwroot/api.yunzer.cn/scripts/service.sh status + +# 查看日志(最后 50 行) +bash /www/wwwroot/api.yunzer.cn/scripts/service.sh logs + +# 实时查看日志 +bash /www/wwwroot/api.yunzer.cn/scripts/service.sh logs -f + +# 查看最后 100 行日志 +bash /www/wwwroot/api.yunzer.cn/scripts/service.sh logs 100 +``` + +### 创建快捷命令(可选) +```bash +# 添加到 ~/.bashrc +echo 'alias go-service="bash /www/wwwroot/api.yunzer.cn/scripts/service.sh"' >> ~/.bashrc +source ~/.bashrc + +# 使用快捷命令 +go-service start +go-service restart +go-service status +go-service logs -f +``` + +## 方式三:后台直接启动 + +### 启动服务 +```bash cd /www/wwwroot/api.yunzer.cn -nohup go run main.go & +nohup go run main.go > go.log 2>&1 & +``` -查看是否运行成功 +### 查看是否运行成功 +```bash tail -f go.log +``` +### 查看进程 +```bash +ps aux | grep "go run main.go" | grep -v grep +``` -下次要重启 -pkill go && cd /www/wwwroot/api.yunzer.cn && nohup go run main.go & \ No newline at end of file +### 重启服务 +```bash +pkill -f "go run main.go" && cd /www/wwwroot/api.yunzer.cn && nohup go run main.go > go.log 2>&1 & +``` + +### 停止服务 +```bash +pkill -f "go run main.go" +``` + +## 日志查看 + +### 查看实时日志 +```bash +# systemd 方式 +journalctl -u go-api -f + +# 直接启动方式 +tail -f /www/wwwroot/api.yunzer.cn/go.log +``` + +### 查看最近日志 +```bash +# systemd 方式 +journalctl -u go-api -n 100 + +# 直接启动方式 +tail -n 100 /www/wwwroot/api.yunzer.cn/go.log +``` + +### 查看错误日志 +```bash +# systemd 方式 +journalctl -u go-api -p err + +# 直接启动方式 +grep -i error /www/wwwroot/api.yunzer.cn/go.log +``` + +## 常见问题 + +### 1. 服务启动失败 + +**检查日志**: +```bash +# systemd +journalctl -u go-api -n 50 + +# 直接启动 +tail -n 50 /www/wwwroot/api.yunzer.cn/go.log +``` + +**常见原因**: +- 端口被占用(8081) +- 数据库连接失败 +- 配置文件错误 + +### 2. 端口被占用 + +**查看端口占用**: +```bash +netstat -tlnp | grep 8081 +# 或 +lsof -i :8081 +``` + +**停止占用进程**: +```bash +# 找到 PID +lsof -i :8081 + +# 停止进程 +kill -9 +``` + +### 3. 进程残留 + +**查找残留进程**: +```bash +ps aux | grep "go run main.go" | grep -v grep +``` + +**清理残留进程**: +```bash +pkill -9 -f "go run main.go" +``` + +### 4. 日志文件不存在 + +**原因**:启动命令没有重定向输出 + +**解决**:使用正确的启动命令 +```bash +nohup go run main.go > go.log 2>&1 & +``` + +## 性能监控 + +### 查看资源占用 +```bash +# CPU 和内存 +top -p $(pgrep -f "go run main.go") + +# 详细信息 +ps aux | grep "go run main.go" | grep -v grep +``` + +### 查看连接数 +```bash +netstat -an | grep 8081 | wc -l +``` + +### 查看文件描述符 +```bash +lsof -p $(pgrep -f "go run main.go") | wc -l +``` + +## 生产环境建议 + +1. **使用 systemd 服务**:更稳定,支持自动重启 +2. **配置日志轮转**:防止日志文件过大 +3. **监控服务状态**:使用监控工具(如 Prometheus) +4. **定期备份**:备份数据库和配置文件 +5. **使用编译后的二进制**:比 `go run` 更高效 + +### 编译并运行(推荐生产环境) +```bash +# 编译 +cd /www/wwwroot/api.yunzer.cn +go build -o server main.go + +# 运行 +nohup ./server > go.log 2>&1 & + +# 或使用 systemd(修改 ExecStart) +# ExecStart=/www/wwwroot/api.yunzer.cn/server +``` + +## 更新日期 + +2026-04-09 \ No newline at end of file diff --git a/scripts/go-api.service b/scripts/go-api.service new file mode 100644 index 0000000..f87efb5 --- /dev/null +++ b/scripts/go-api.service @@ -0,0 +1,29 @@ +[Unit] +Description=Go API Server +After=network.target mysql.service +Wants=mysql.service + +[Service] +Type=simple +User=root +Group=root +WorkingDirectory=/www/wwwroot/api.yunzer.cn +ExecStart=/usr/local/go/bin/go run main.go +Restart=always +RestartSec=5 +StandardOutput=append:/www/wwwroot/api.yunzer.cn/go.log +StandardError=append:/www/wwwroot/api.yunzer.cn/go.log + +# 环境变量 +Environment="PATH=/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + +# 资源限制 +LimitNOFILE=65535 +LimitNPROC=65535 + +# 安全设置 +PrivateTmp=true +NoNewPrivileges=false + +[Install] +WantedBy=multi-user.target diff --git a/scripts/install-systemd-service.sh b/scripts/install-systemd-service.sh new file mode 100644 index 0000000..5c3e392 --- /dev/null +++ b/scripts/install-systemd-service.sh @@ -0,0 +1,168 @@ +#!/bin/bash + +# ======================================== +# 安装 systemd 服务脚本 +# 用途:配置 Go API 为 systemd 服务 +# ======================================== + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 配置 +SERVICE_NAME="go-api" +SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SERVICE_TEMPLATE="${SCRIPT_DIR}/${SERVICE_NAME}.service" +WORK_DIR="/www/wwwroot/api.yunzer.cn" +MAIN_FILE="${WORK_DIR}/main.go" + +echo -e "${BLUE}========================================${NC}" +echo -e "${BLUE}安装 Go API systemd 服务${NC}" +echo -e "${BLUE}========================================${NC}" +echo "" + +# 检查是否为 root +if [ "$EUID" -ne 0 ]; then + echo -e "${RED}错误:请使用 root 用户运行此脚本${NC}" + echo "使用方法: sudo bash $0" + exit 1 +fi + +# 检查工作目录 +if [ ! -d "$WORK_DIR" ]; then + echo -e "${RED}错误:工作目录不存在: $WORK_DIR${NC}" + exit 1 +fi + +# 检查 main.go +if [ ! -f "$MAIN_FILE" ]; then + echo -e "${RED}错误:找不到 main.go: $MAIN_FILE${NC}" + exit 1 +fi + +# 检查 Go 是否安装 +if ! command -v go &> /dev/null; then + echo -e "${RED}错误:Go 未安装或不在 PATH 中${NC}" + exit 1 +fi + +GO_PATH=$(which go) +echo -e "${GREEN}✓ Go 路径: $GO_PATH${NC}" + +# 停止现有服务 +echo -e "${YELLOW}1. 停止现有服务...${NC}" +if systemctl is-active --quiet "$SERVICE_NAME"; then + systemctl stop "$SERVICE_NAME" + echo -e "${GREEN} ✓ 已停止现有服务${NC}" +else + echo -e "${YELLOW} - 服务未运行${NC}" +fi + +# 停止可能的手动启动进程 +echo -e "${YELLOW}2. 清理手动启动的进程...${NC}" +if pgrep -f "go run main.go" > /dev/null; then + pkill -f "go run main.go" + echo -e "${GREEN} ✓ 已清理手动启动的进程${NC}" +else + echo -e "${YELLOW} - 无手动启动的进程${NC}" +fi + +# 创建服务文件 +echo -e "${YELLOW}3. 创建 systemd 服务文件...${NC}" + +cat > "$SERVICE_FILE" << EOF +[Unit] +Description=Go API Server +After=network.target mysql.service +Wants=mysql.service + +[Service] +Type=simple +User=root +Group=root +WorkingDirectory=$WORK_DIR +ExecStart=$GO_PATH run main.go +Restart=always +RestartSec=5 +StandardOutput=append:$WORK_DIR/go.log +StandardError=append:$WORK_DIR/go.log + +# 环境变量 +Environment="PATH=$GO_PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + +# 资源限制 +LimitNOFILE=65535 +LimitNPROC=65535 + +# 安全设置 +PrivateTmp=true +NoNewPrivileges=false + +[Install] +WantedBy=multi-user.target +EOF + +echo -e "${GREEN} ✓ 服务文件已创建: $SERVICE_FILE${NC}" + +# 重载 systemd +echo -e "${YELLOW}4. 重载 systemd 配置...${NC}" +systemctl daemon-reload +echo -e "${GREEN} ✓ systemd 配置已重载${NC}" + +# 启动服务 +echo -e "${YELLOW}5. 启动服务...${NC}" +systemctl start "$SERVICE_NAME" +sleep 2 + +# 检查服务状态 +if systemctl is-active --quiet "$SERVICE_NAME"; then + echo -e "${GREEN} ✓ 服务启动成功${NC}" +else + echo -e "${RED} ✗ 服务启动失败${NC}" + echo "" + echo -e "${YELLOW}查看错误日志:${NC}" + journalctl -u "$SERVICE_NAME" -n 20 --no-pager + exit 1 +fi + +# 启用开机自启 +echo -e "${YELLOW}6. 启用开机自启...${NC}" +systemctl enable "$SERVICE_NAME" +echo -e "${GREEN} ✓ 已启用开机自启${NC}" + +# 显示服务状态 +echo "" +echo -e "${BLUE}========================================${NC}" +echo -e "${BLUE}安装完成!${NC}" +echo -e "${BLUE}========================================${NC}" +echo "" +echo -e "${GREEN}服务信息:${NC}" +echo -e " 服务名称: $SERVICE_NAME" +echo -e " 工作目录: $WORK_DIR" +echo -e " 日志文件: $WORK_DIR/go.log" +echo -e " 配置文件: $SERVICE_FILE" +echo "" +echo -e "${GREEN}常用命令:${NC}" +echo -e " 启动服务: systemctl start $SERVICE_NAME" +echo -e " 停止服务: systemctl stop $SERVICE_NAME" +echo -e " 重启服务: systemctl restart $SERVICE_NAME" +echo -e " 查看状态: systemctl status $SERVICE_NAME" +echo -e " 查看日志: journalctl -u $SERVICE_NAME -f" +echo -e " 查看文件日志: tail -f $WORK_DIR/go.log" +echo "" +echo -e "${YELLOW}当前服务状态:${NC}" +systemctl status "$SERVICE_NAME" --no-pager -l +echo "" +echo -e "${YELLOW}最近日志(最后 10 行):${NC}" +if [ -f "$WORK_DIR/go.log" ]; then + tail -n 10 "$WORK_DIR/go.log" +else + echo " 日志文件尚未创建" +fi +echo "" diff --git a/scripts/service.sh b/scripts/service.sh new file mode 100644 index 0000000..c050654 --- /dev/null +++ b/scripts/service.sh @@ -0,0 +1,285 @@ +#!/bin/bash + +# ======================================== +# Go 服务管理脚本 +# 用途:启动、停止、重启、查看状态 +# ======================================== + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 配置 +SERVICE_DIR="/www/wwwroot/api.yunzer.cn" +LOG_FILE="$SERVICE_DIR/go.log" +PID_FILE="$SERVICE_DIR/go.pid" +MAIN_FILE="$SERVICE_DIR/main.go" + +# 检查服务目录 +if [ ! -d "$SERVICE_DIR" ]; then + echo -e "${RED}错误:服务目录不存在: $SERVICE_DIR${NC}" + exit 1 +fi + +# 检查 main.go +if [ ! -f "$MAIN_FILE" ]; then + echo -e "${RED}错误:找不到 main.go: $MAIN_FILE${NC}" + exit 1 +fi + +# 获取进程 ID +get_pid() { + if [ -f "$PID_FILE" ]; then + cat "$PID_FILE" + else + # 通过进程名查找 + pgrep -f "go run main.go" | head -n 1 + fi +} + +# 检查服务是否运行 +is_running() { + local pid=$(get_pid) + if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then + return 0 + else + return 1 + fi +} + +# 启动服务 +start() { + echo -e "${BLUE}========================================${NC}" + echo -e "${BLUE}启动 Go 服务${NC}" + echo -e "${BLUE}========================================${NC}" + echo "" + + if is_running; then + local pid=$(get_pid) + echo -e "${YELLOW}服务已在运行中 (PID: $pid)${NC}" + return 0 + fi + + echo -e "${YELLOW}切换到服务目录...${NC}" + cd "$SERVICE_DIR" + + echo -e "${YELLOW}启动服务...${NC}" + nohup go run main.go > "$LOG_FILE" 2>&1 & + local pid=$! + echo $pid > "$PID_FILE" + + # 等待服务启动 + sleep 2 + + if is_running; then + echo -e "${GREEN}✓ 服务启动成功 (PID: $pid)${NC}" + echo -e "${GREEN}✓ 日志文件: $LOG_FILE${NC}" + echo "" + echo -e "${YELLOW}查看日志:${NC}" + echo -e " tail -f $LOG_FILE" + echo "" + echo -e "${YELLOW}查看最近日志:${NC}" + tail -n 20 "$LOG_FILE" + else + echo -e "${RED}✗ 服务启动失败${NC}" + if [ -f "$LOG_FILE" ]; then + echo -e "${YELLOW}最近的错误日志:${NC}" + tail -n 20 "$LOG_FILE" + fi + exit 1 + fi +} + +# 停止服务 +stop() { + echo -e "${BLUE}========================================${NC}" + echo -e "${BLUE}停止 Go 服务${NC}" + echo -e "${BLUE}========================================${NC}" + echo "" + + if ! is_running; then + echo -e "${YELLOW}服务未运行${NC}" + rm -f "$PID_FILE" + return 0 + fi + + local pid=$(get_pid) + echo -e "${YELLOW}停止服务 (PID: $pid)...${NC}" + + # 尝试优雅停止 + kill "$pid" 2>/dev/null || true + + # 等待最多 10 秒 + local count=0 + while is_running && [ $count -lt 10 ]; do + sleep 1 + count=$((count + 1)) + echo -n "." + done + echo "" + + # 如果还在运行,强制停止 + if is_running; then + echo -e "${YELLOW}强制停止服务...${NC}" + kill -9 "$pid" 2>/dev/null || true + sleep 1 + fi + + # 清理所有相关进程 + pkill -f "go run main.go" 2>/dev/null || true + + rm -f "$PID_FILE" + + if is_running; then + echo -e "${RED}✗ 服务停止失败${NC}" + exit 1 + else + echo -e "${GREEN}✓ 服务已停止${NC}" + fi +} + +# 重启服务 +restart() { + echo -e "${BLUE}========================================${NC}" + echo -e "${BLUE}重启 Go 服务${NC}" + echo -e "${BLUE}========================================${NC}" + echo "" + + stop + echo "" + sleep 2 + start +} + +# 查看状态 +status() { + echo -e "${BLUE}========================================${NC}" + echo -e "${BLUE}Go 服务状态${NC}" + echo -e "${BLUE}========================================${NC}" + echo "" + + if is_running; then + local pid=$(get_pid) + echo -e "${GREEN}✓ 服务运行中${NC}" + echo -e " PID: $pid" + echo -e " 目录: $SERVICE_DIR" + echo -e " 日志: $LOG_FILE" + echo "" + + # 显示进程信息 + echo -e "${YELLOW}进程信息:${NC}" + ps aux | grep "$pid" | grep -v grep + echo "" + + # 显示端口监听 + echo -e "${YELLOW}端口监听:${NC}" + netstat -tlnp 2>/dev/null | grep "$pid" || lsof -i -P -n | grep "$pid" || echo " 无法获取端口信息" + echo "" + + # 显示最近日志 + if [ -f "$LOG_FILE" ]; then + echo -e "${YELLOW}最近日志(最后 10 行):${NC}" + tail -n 10 "$LOG_FILE" + fi + else + echo -e "${RED}✗ 服务未运行${NC}" + + # 检查是否有残留进程 + local pids=$(pgrep -f "go run main.go" || true) + if [ -n "$pids" ]; then + echo -e "${YELLOW}发现残留进程:${NC}" + ps aux | grep "go run main.go" | grep -v grep + echo "" + echo -e "${YELLOW}清理残留进程:${NC}" + echo " bash $0 stop" + fi + + # 显示最近日志 + if [ -f "$LOG_FILE" ]; then + echo "" + echo -e "${YELLOW}最近日志(最后 20 行):${NC}" + tail -n 20 "$LOG_FILE" + fi + fi +} + +# 查看日志 +logs() { + if [ ! -f "$LOG_FILE" ]; then + echo -e "${RED}日志文件不存在: $LOG_FILE${NC}" + exit 1 + fi + + if [ "$1" = "-f" ] || [ "$1" = "--follow" ]; then + echo -e "${YELLOW}实时查看日志(Ctrl+C 退出):${NC}" + tail -f "$LOG_FILE" + else + local lines=${1:-50} + echo -e "${YELLOW}最近 $lines 行日志:${NC}" + tail -n "$lines" "$LOG_FILE" + fi +} + +# 显示帮助 +help() { + echo -e "${BLUE}========================================${NC}" + echo -e "${BLUE}Go 服务管理脚本${NC}" + echo -e "${BLUE}========================================${NC}" + echo "" + echo "用法: $0 {start|stop|restart|status|logs}" + echo "" + echo "命令:" + echo " start - 启动服务" + echo " stop - 停止服务" + echo " restart - 重启服务" + echo " status - 查看服务状态" + echo " logs - 查看日志(默认最后 50 行)" + echo " logs -f - 实时查看日志" + echo " logs 100 - 查看最后 100 行日志" + echo "" + echo "示例:" + echo " $0 start # 启动服务" + echo " $0 restart # 重启服务" + echo " $0 status # 查看状态" + echo " $0 logs -f # 实时查看日志" + echo " $0 logs 100 # 查看最后 100 行" + echo "" +} + +# 主函数 +main() { + case "${1:-}" in + start) + start + ;; + stop) + stop + ;; + restart) + restart + ;; + status) + status + ;; + logs) + logs "${2:-}" + ;; + help|--help|-h) + help + ;; + *) + echo -e "${RED}错误:未知命令 '$1'${NC}" + echo "" + help + exit 1 + ;; + esac +} + +# 运行主函数 +main "$@"