当前位置: 首页 > news >正文

【软件运维】前后端部署启动的几种方式

.sh启动

#!/bin/bash# 解析软链接,获取真实脚本目录
SOURCE="${BASH_SOURCE[0]}"
while [ -L "$SOURCE" ]; doDIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"SOURCE="$(readlink "$SOURCE")"[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
done
CURRENT_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
echo "当前脚本所在目录: $CURRENT_DIR"# ================ 配置参数 ================
# conda环境名称
CONDA_ENV="hr"# 程序路径 - 使用当前目录作为基础
PROGRAM_PATH="$CURRENT_DIR/backend/run.py"# 程序启动参数(如有)
PROGRAM_ARGS=""# 日志文件路径 - 使用当前目录下的logs文件夹
LOG_FILE="$CURRENT_DIR/logs/backend/backend.log"# 日志保留天数
LOG_RETENTION_DAYS=7# 日志切割频率(分钟)
LOG_ROTATE_INTERVAL=1440  # 默认24小时# 上次切割日志的时间戳文件
LAST_ROTATE_FILE="/tmp/backend_log_rotate.timestamp"# ================ 函数定义 ================# 加载conda环境
load_conda_env() {# 尝试加载conda初始化脚本,增加Miniforge的路径if [ -f "$HOME/miniforge3/etc/profile.d/conda.sh" ]; thensource "$HOME/miniforge3/etc/profile.d/conda.sh"elif [ -f "$HOME/mambaforge/etc/profile.d/conda.sh" ]; thensource "$HOME/mambaforge/etc/profile.d/conda.sh"elif [ -f "$HOME/miniconda3/etc/profile.d/conda.sh" ]; thensource "$HOME/miniconda3/etc/profile.d/conda.sh"elif [ -f "$HOME/anaconda3/etc/profile.d/conda.sh" ]; thensource "$HOME/anaconda3/etc/profile.d/conda.sh"elif [ -f "/opt/conda/etc/profile.d/conda.sh" ]; thensource "/opt/conda/etc/profile.d/conda.sh"else# 尝试查找系统中的conda.sh文件CONDA_SH=$(find $HOME -name "conda.sh" -path "*/etc/profile.d/*" 2>/dev/null | head -n 1)if [ -n "$CONDA_SH" ]; thensource "$CONDA_SH"elseecho "错误: 找不到conda初始化脚本,请检查Miniforge/conda安装路径" >&2exit 1fifi# 激活指定环境conda activate "$CONDA_ENV"if [ $? -ne 0 ]; thenecho "错误: 无法激活conda环境 '$CONDA_ENV'" >&2exit 1fiecho "已激活conda环境: $CONDA_ENV"
}# 启动后端程序
start_backend() {# 确保日志目录存在LOG_DIR=$(dirname "$LOG_FILE")mkdir -p "$LOG_DIR"# 检查程序是否已运行if pgrep -f "python.*$PROGRAM_PATH $PROGRAM_ARGS" > /dev/null; thenecho "警告: 程序已在运行中,PID: $(pgrep -f "python.*$PROGRAM_PATH $PROGRAM_ARGS")"return 1fi# 启动程序并记录PID - 使用python命令echo "正在启动程序: python $PROGRAM_PATH $PROGRAM_ARGS"cd "$(dirname "$PROGRAM_PATH")"  # 切换到脚本所在目录nohup python "$(basename "$PROGRAM_PATH")" $PROGRAM_ARGS > "$LOG_FILE" 2>&1 &PID=$!# 保存PID到文件(可选)echo $PID > "$LOG_DIR/backend.pid"echo "程序已启动,PID: $PID,日志输出到: $LOG_FILE"# 启动守护进程DAEMON_SH="$CURRENT_DIR/deamon.sh"if ! pgrep -f "$DAEMON_SH" > /dev/null; thennohup bash "$DAEMON_SH" > /dev/null 2>&1 &echo "守护进程已启动"elseecho "守护进程已在运行"fireturn 0
}# 切割日志文件
rotate_log() {# 创建日志目录(如果不存在)LOG_DIR=$(dirname "$LOG_FILE")mkdir -p "$LOG_DIR"# 生成备份文件名(包含时间戳)TIMESTAMP=$(date +%Y%m%d_%H%M%S)BACKUP_FILE="${LOG_FILE}.${TIMESTAMP}"# 移动当前日志文件到备份if [ -f "$LOG_FILE" ]; thenmv "$LOG_FILE" "$BACKUP_FILE"echo "日志已切割: $BACKUP_FILE"# 更新上次切割时间echo $(date +%s) > "$LAST_ROTATE_FILE"# 清理过期日志find "$LOG_DIR" -name "$(basename $LOG_FILE).*" -type f -mtime +$LOG_RETENTION_DAYS -deletefi
}# 检查是否需要切割日志
check_rotate_needed() {# 如果时间戳文件不存在,创建并返回需要切割if [ ! -f "$LAST_ROTATE_FILE" ]; thenecho $(date +%s) > "$LAST_ROTATE_FILE"return 0fi# 计算上次切割到现在的时间(分钟)LAST_ROTATE=$(cat "$LAST_ROTATE_FILE")CURRENT_TIME=$(date +%s)ELAPSED_MINUTES=$(( (CURRENT_TIME - LAST_ROTATE) / 60 ))# 如果超过设定的时间间隔,返回需要切割if [ $ELAPSED_MINUTES -ge $LOG_ROTATE_INTERVAL ]; thenreturn 0fireturn 1
}# 显示使用帮助
show_help() {echo "用法: $0 [选项]"echo "选项:"echo "  start    启动后端程序"echo "  rotate   手动切割日志"echo "  status   检查程序状态"echo "  stop     停止后端程序"echo "  restart  重启后端程序"echo "  help     显示此帮助信息"exit 0
}# 停止后端程序
stop_backend() {LOG_DIR=$(dirname "$LOG_FILE")PID_FILE="$LOG_DIR/backend.pid"# 如果有PID文件,尝试通过PID停止if [ -f "$PID_FILE" ]; thenPID=$(cat "$PID_FILE")if ps -p $PID > /dev/null; thenecho "正在停止程序,PID: $PID"kill $PID# 等待最多10秒for i in {1..10}; doif ! ps -p $PID > /dev/null; thenecho "程序已停止"rm -f "$PID_FILE"return 0fisleep 1done# 如果10秒后仍在运行,强制终止echo "程序未响应,强制终止"kill -9 $PIDrm -f "$PID_FILE"return 0elseecho "警告: PID文件存在但进程不存在,删除PID文件"rm -f "$PID_FILE"fifi# 如果没有PID文件,尝试通过程序名查找PROGRAM_NAME=$(basename "$PROGRAM_PATH")PID=$(pgrep -f "python.*$PROGRAM_PATH $PROGRAM_ARGS")if [ -n "$PID" ]; thenecho "找到程序实例,PID: $PID"kill $PID# 等待最多10秒for i in {1..10}; doif ! ps -p $PID > /dev/null; thenecho "程序已停止"return 0fisleep 1done# 如果10秒后仍在运行,强制终止echo "程序未响应,强制终止"kill -9 $PIDreturn 0fiecho "未找到运行中的程序实例"return 1
}# 检查程序状态
check_status() {LOG_DIR=$(dirname "$LOG_FILE")PID_FILE="$LOG_DIR/backend.pid"if [ -f "$PID_FILE" ]; thenPID=$(cat "$PID_FILE")if ps -p $PID > /dev/null; thenecho "程序正在运行,PID: $PID"echo "日志文件: $LOG_FILE"return 0elseecho "程序未运行"return 1fielseecho "程序未运行"return 1fi
}# ================ 主程序 ================# 检查命令行参数
case "$1" instart)load_conda_envstart_backend;;rotate)rotate_log;;status)check_status;;stop)stop_backend;;restart)stop_backendload_conda_envstart_backend;;help|--help|-h)show_help;;*)echo "错误: 未知命令 '$1'"show_help;;
esacexit 0


这个Bash脚本是一个用于管理Python后端程序的工具脚本,提供了启动、停止、重启、状态检查以及日志管理等功能。下面我将分部分详细解释这个脚本的内容和工作原理。

1. 获取真实脚本目录

SOURCE="${BASH_SOURCE[0]}"
while [ -L "$SOURCE" ]; doDIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"SOURCE="$(readlink "$SOURCE")"[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
done
CURRENT_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
echo "当前脚本所在目录: $CURRENT_DIR"

这部分代码的作用是获取脚本的真实路径,即使脚本是通过软链接调用的。它通过以下步骤实现:

  1. 获取脚本路径(SOURCE)

  2. 如果路径是软链接(-L),则解析真实路径

  3. 处理相对路径的情况(SOURCE != /*)

  4. 最终获取脚本所在目录的绝对路径(CURRENT_DIR)

2. 配置参数

CONDA_ENV="hr"  # conda环境名称
PROGRAM_PATH="$CURRENT_DIR/backend/run.py"  # 程序路径
PROGRAM_ARGS=""  # 程序启动参数
LOG_FILE="$CURRENT_DIR/logs/backend/backend.log"  # 日志文件路径
LOG_RETENTION_DAYS=7  # 日志保留天数
LOG_ROTATE_INTERVAL=1440  # 日志切割频率(分钟,默认24小时)
LAST_ROTATE_FILE="/tmp/backend_log_rotate.timestamp"  # 上次切割日志的时间戳文件

这部分定义了脚本使用的各种参数,包括:

  • Conda环境名称

  • 要运行的Python程序路径

  • 程序启动参数

  • 日志文件位置和保留策略

3. 函数定义

3.1 load_conda_env 函数

load_conda_env() {# 尝试从多个可能的位置加载conda初始化脚本if [ -f "$HOME/miniforge3/etc/profile.d/conda.sh" ]; thensource "$HOME/miniforge3/etc/profile.d/conda.sh"elif [ -f ... ]; then  # 其他可能的位置...fi# 激活指定conda环境conda activate "$CONDA_ENV"...
}

这个函数负责加载conda环境,它会尝试从多个常见位置查找conda初始化脚本,然后激活指定的conda环境(hr)。

3.2 start_backend 函数

start_backend() {# 确保日志目录存在mkdir -p "$LOG_DIR"# 检查程序是否已运行if pgrep -f "python.*$PROGRAM_PATH $PROGRAM_ARGS" > /dev/null; thenecho "警告: 程序已在运行中..."return 1fi# 启动程序并记录PIDnohup python "$(basename "$PROGRAM_PATH")" $PROGRAM_ARGS > "$LOG_FILE" 2>&1 &PID=$!echo $PID > "$LOG_DIR/backend.pid"# 启动守护进程DAEMON_SH="$CURRENT_DIR/deamon.sh"if ! pgrep -f "$DAEMON_SH" > /dev/null; thennohup bash "$DAEMON_SH" > /dev/null 2>&1 &fi
}

这个函数负责启动后端程序,它会:

  1. 创建必要的日志目录

  2. 检查程序是否已经在运行

  3. 使用nohup在后台启动Python程序,并重定向输出到日志文件

  4. 保存进程ID(PID)到文件

  5. 启动守护进程(如果未运行)

3.3 日志管理函数

rotate_log() {# 创建日志备份文件TIMESTAMP=$(date +%Y%m%d_%H%M%S)BACKUP_FILE="${LOG_FILE}.${TIMESTAMP}"mv "$LOG_FILE" "$BACKUP_FILE"# 清理过期日志find "$LOG_DIR" -name "$(basename $LOG_FILE).*" -type f -mtime +$LOG_RETENTION_DAYS -delete
}check_rotate_needed() {# 检查是否需要切割日志(基于时间间隔)...
}

这些函数负责日志的轮转(切割)管理:

  • rotate_log: 将当前日志重命名为带时间戳的备份文件,并清理过期的日志

  • check_rotate_needed: 检查是否到了需要切割日志的时间

3.4 其他管理函数

stop_backend() {# 通过PID文件或程序名查找并停止程序...
}check_status() {# 检查程序运行状态...
}show_help() {# 显示使用帮助...
}

这些函数提供了其他管理功能:

  • 停止程序

  • 检查程序状态

  • 显示帮助信息

4. 主程序

case "$1" instart)load_conda_envstart_backend;;rotate)rotate_log;;status)check_status;;stop)stop_backend;;restart)stop_backendload_conda_envstart_backend;;help|--help|-h)show_help;;*)echo "错误: 未知命令 '$1'"show_help;;
esac

这部分是脚本的入口,根据传入的参数调用相应的函数:

  • start: 启动程序

  • rotate: 手动切割日志

  • status: 检查状态

  • stop: 停止程序

  • restart: 重启程序

  • help: 显示帮助

要启动这个脚本,你需要根据脚本提供的功能选项来执行相应的命令。以下是使用这个脚本的各种方法:

基本使用方法

bash 脚本文件名.sh [选项]

具体操作命令

  1. 启动后端程序

    bash script.sh start
    • 这会激活conda环境并启动Python后端程序

    • 同时会启动守护进程(如果配置了的话)

  2. 停止后端程序

    bash script.sh stop
  3. 重启后端程序

    bash script.sh restart
  4. 手动切割日志

    bash script.sh rotate
  5. 检查程序状态

    bash script.sh status
  6. 查看帮助信息

    bash script.sh help
    或
    bash script.sh --help
    或
    bash script.sh -h

 守护进程脚本

后端启动后意外停止的常见原因:

Python 脚本自身崩溃
  • 可能原因

    • 未捕获的异常(如 KeyErrorImportError)。

    • 内存泄漏导致被系统 OOM Killer 终止。

    • 第三方库的 Bug 或兼容性问题。

  • 排查方法

    # 查看脚本是否有崩溃日志(如果未重定向输出)
    cat nohup.out
    # 或主动记录错误到文件
    python run.py >> run.log 2>&1
系统资源不足
  • 可能原因

    • 内存不足:进程占用内存过多被系统 OOM Killer 杀死。

      dmesg | grep -i "killed"  # 检查是否有 OOM 记录
    • CPU/磁盘过载:长时间高负载导致进程卡死。

      top -p $(pgrep -f "run.py")  # 监控资源占用
会话中断导致信号终止
  • 可能原因

    • nohup 虽然能忽略 SIGHUP 信号,但可能收到其他信号(如 SIGTERM)。

    • 服务器运维操作(如定期重启、Cron 任务)可能主动终止进程。

  • 排查方法

    # 检查系统日志(如 syslog/auth.log)
    grep -i "kill" /var/log/syslog
依赖服务不可用
  • 可能原因

    • 数据库/Redis 等依赖服务断开,导致 Python 脚本主动退出。

    • 网络波动导致 HTTP 请求超时。

  • 排查方法

    • 在代码中添加依赖服务的健康检查(如数据库连接重试逻辑)。

Python 环境问题
  • 可能原因

    • 虚拟环境未激活或包版本冲突。

    • Python 解释器自身崩溃(罕见但可能)。

  • 排查方法

    # 检查 Python 版本和依赖
    python -V
    pip list | grep "关键依赖包名"
定时任务或运维脚本干扰
  • 可能原因

    • 服务器上有其他 Cron 任务或监控脚本误杀进程。

    crontab -l  # 检查当前用户的定时任务

因此用了一个监控和自动重启后端服务的 Bash 守护进程脚本(deamon.sh)。我来逐步解析它的功能和工作原理:


1. 基础设置

OP_SCRIPT="$(dirname "$(readlink -f "$0")")/op.sh"
  • 作用:定位同目录下的 op.sh 脚本(假设这是管理后端服务的脚本)。

  • 技术点:

    • $0 是当前脚本路径(如 ./deamon.sh)。

    • readlink -f 解析符号链接并返回绝对路径。

    • dirname 提取目录路径。

CHECK_INTERVAL=300  # 检查间隔(秒,这里是5分钟)
LOG_FILE="$(dirname "$OP_SCRIPT")/logs/backend/daemon.log"
  • 定义检查服务状态的间隔时间(300秒)和日志文件路径。


2. 日志函数

log() {echo "$(date '+%Y-%m-%d %H:%M:%S') $*" >> "$LOG_FILE"
}
  • 将带时间戳的消息追加到日志文件(如 2024-01-01 12:00:00 守护进程启动...)。


3. 服务状态检测

is_running() {"$OP_SCRIPT" status | grep -q "程序正在运行"
}
  • 逻辑

    1. 调用 op.sh status 检查服务状态。

    2. 用 grep -q 静默匹配输出中是否包含 程序正在运行

    3. 如果匹配成功(服务在运行),返回 0(成功);否则返回非零。


4. 服务启动函数

start_service() {log "检测到服务未运行,尝试启动...""$OP_SCRIPT" start >> "$LOG_FILE" 2>&1
}
  • 如果服务未运行:

    1. 记录日志。

    2. 调用 op.sh start 启动服务,并将输出和错误重定向到日志文件。


5. 主循环

log "守护进程启动,开始监控后端服务..."
while true; doif ! is_running; thenstart_servicefisleep $CHECK_INTERVAL
done
  • 无限循环

    1. 检查服务状态(is_running)。

    2. 如果服务停止,调用 start_service

    3. 休眠 CHECK_INTERVAL 秒后重复检查。


关键点总结

  1. 依赖关系

    • 需要同目录下的 op.sh 脚本,且该脚本需支持 status 和 start 命令。

    • 假设 op.sh status 的输出中包含 程序正在运行 字符串。

  2. 日志管理

    • 所有操作记录到 logs/backend/daemon.log,便于排查问题。

  3. 工作场景

    • 适合监控需要长期运行的后端服务(如Web API、数据库等)。

    • 当服务意外崩溃时,自动尝试重启。

#!/bin/bash# deamon.sh:守护op.sh启动的后端服务OP_SCRIPT="$(dirname "$(readlink -f "$0")")/op.sh"
CHECK_INTERVAL=300
LOG_FILE="$(dirname "$OP_SCRIPT")/logs/backend/daemon.log"log() {echo "$(date '+%Y-%m-%d %H:%M:%S') $*" >> "$LOG_FILE"
}is_running() {"$OP_SCRIPT" status | grep -q "程序正在运行"
}start_service() {log "检测到服务未运行,尝试启动...""$OP_SCRIPT" start >> "$LOG_FILE" 2>&1
}log "守护进程启动,开始监控后端服务..."
while true; doif ! is_running; thenstart_servicefisleep $CHECK_INTERVAL
done

Make dev命令

看到了一个谷歌项目,他的前后端启动方式很方便

https://github.com/google-gemini/gemini-fullstack-langgraph-quickstart/blob/main/README.md

项目最外部有一个makefile

.PHONY: help dev-frontend dev-backend devhelp:@echo "Available commands:"@echo "  make dev-frontend    - Starts the frontend development server (Vite)"@echo "  make dev-backend     - Starts the backend development server (Uvicorn with reload)"@echo "  make dev             - Starts both frontend and backend development servers"dev-frontend:@echo "Starting frontend development server..."@cd frontend && npm run devdev-backend:@echo "Starting backend development server..."@cd backend && langgraph dev# Run frontend and backend concurrently
dev:@echo "Starting both frontend and backend development servers..."@make dev-frontend & make dev-backend 

这个 Makefile 是一个用于管理项目开发工作流的构建文件,特别适合同时包含前端和后端的项目。让我们逐部分深入分析:

1. .PHONY 声明

.PHONY: help dev-frontend dev-backend dev
  • .PHONY 是一个特殊目标,用于声明哪些目标是"伪目标"(不是实际的文件名)

  • 这里声明了 helpdev-frontenddev-backend 和 dev 都是伪目标

  • 这意味着即使存在同名文件,Make 也会执行这些目标下的命令

2. help 目标

help:@echo "Available commands:"@echo "  make dev-frontend    - Starts the frontend development server (Vite)"@echo "  make dev-backend     - Starts the backend development server (Uvicorn with reload)"@echo "  make dev             - Starts both frontend and backend development servers"
  • 这是一个帮助信息目标,显示可用的命令及其描述

  • @ 符号表示在执行时不显示命令本身,只显示输出

  • 这是典型的自文档化 Makefile 的做法

3. dev-frontend 目标

dev-frontend:@echo "Starting frontend development server..."@cd frontend && npm run dev
  • 用于启动前端开发服务器

  • 先显示启动信息,然后:

    • cd frontend 进入 frontend 目录

    • npm run dev 运行 npm 的 dev 脚本(假设使用 Vite,如帮助信息所示)

  • 这要求项目有一个 frontend 目录,并且其中 package.json 中定义了 dev 脚本

4. dev-backend 目标

dev-backend:@echo "Starting backend development server..."@cd backend && langgraph dev
  • 用于启动后端开发服务器

  • 先显示启动信息,然后:

    • cd backend 进入 backend 目录

    • langgraph dev 运行 langgraph 的开发命令(看起来是使用某种 Python 框架)

  • 这要求项目有一个 backend 目录,并且安装了 langgraph

5. dev 目标

dev:@echo "Starting both frontend and backend development servers..."@make dev-frontend & make dev-backend 
  • 这是最常用的目标,同时启动前后端开发服务器

  • 使用 & 运算符在后台并行运行两个 make 命令

  • 注意:

    • 这种方式简单但不够健壮,如果某个进程失败不会自动停止另一个

    • 更高级的替代方案是使用 concurrently 或 docker-compose 等工具

使用场景

这个 Makefile 典型用于全栈 JavaScript/Python 项目,其中:

  • 前端使用 Vite(现代前端构建工具)

  • 后端使用某种 Python 框架(可能是 FastAPI 或其他,基于 langgraph 命令判断)

总结

这个 Makefile 提供了一个简洁的接口来管理常见的开发任务,通过简单的 make dev 命令就能启动整个开发环境,大大简化了开发者的工作流程。它体现了 Makefile 作为项目任务自动化工具的经典用法,特别适合需要同时管理多个服务的项目。

Docker前端启动

FROM m.daocloud.io/docker.io/library/nginx:latest# 移除默认的nginx配置
RUN rm -rf /etc/nginx/conf.d/*# 创建目录结构
RUN mkdir -p /usr/share/nginx/html/dist
RUN mkdir -p /etc/nginx/ssl# 暴露端口
EXPOSE 80CMD ["nginx", "-g", "daemon off;"]

这是一个用于配置 Nginx 服务器的 Dockerfile,让我们逐部分分析它的结构和功能:

基础镜像

FROM m.daocloud.io/docker.io/library/nginx:latest
  • 使用 DaoCloud 镜像源(中国国内常用的镜像加速源)拉取官方的 Nginx 镜像

  • library/nginx:latest 表示使用 Docker 官方仓库中的最新版 Nginx 镜像

  • m.daocloud.io/ 前缀是为了加速在中国地区的下载

清理默认配置

RUN rm -rf /etc/nginx/conf.d/*
  • 删除 Nginx 默认的配置文件

  • /etc/nginx/conf.d/ 是 Nginx 加载额外配置文件的目录

  • 这样做是为了准备完全自定义的 Nginx 配置

创建目录结构

RUN mkdir -p /usr/share/nginx/html/dist
RUN mkdir -p /etc/nginx/ssl
  1. 前端静态文件目录

    • /usr/share/nginx/html/dist 是准备存放前端构建产物(如 Vue/React 打包后的文件)的目录

    • -p 参数确保即使父目录不存在也会创建

  2. SSL 证书目录

    • /etc/nginx/ssl 是为 HTTPS 准备的 SSL 证书存放目录

    • 虽然当前 Dockerfile 没有配置 HTTPS,但预留了这个目录

暴露端口

EXPOSE 80
  • 声明容器将监听 80 端口(HTTP 默认端口)

  • 这只是文档性质的声明,实际端口映射需要在 docker run 时用 -p 参数指定

启动命令

CMD ["nginx", "-g", "daemon off;"]
  • 以非守护进程模式运行 Nginx

  • -g "daemon off;" 是 Nginx 的参数,表示在前台运行

  • 这是 Docker 容器的最佳实践,因为容器需要有一个持续运行的前台进程

典型使用场景

这个 Dockerfile 适合用于:

  1. 部署前端静态资源(如 Vue/React 应用)

  2. 需要自定义 Nginx 配置的情况

  3. 作为基础镜像进一步扩展

docker-compose.yaml

version: '3'   services:nginx:build: .image: hrfusion-fd-nginx:v1.0container_name: hrfusion-fd-hyqrestart: alwaysports:- "18001:80"                                             # docker端口映射[宿主机端口:容器内部端口]volumes:# - ./ssl_certs:/etc/nginx/ssl                              # 证书目录- ./frontend/dist:/usr/share/nginx/html/dist              # 项目目录- ./frontend/default.conf:/etc/nginx/conf.d/default.conf  # 服务配置

这个 docker-compose.yml 文件定义了一个 Nginx 服务的配置,用于部署前端应用。让我们逐部分深入分析:

文件结构概览

version: '3'   
services:nginx:# 配置详情...
  • version: '3' - 指定使用 Docker Compose 文件格式版本 3

  • services: - 定义要运行的服务列表

  • nginx: - 定义一个名为 "nginx" 的服务

服务配置详解

1. 构建与镜像

build: .
image: hrfusion-fd-nginx:v1.0
  • build: . - 使用当前目录下的 Dockerfile 构建镜像

  • image: hrfusion-fd-nginx:v1.0 - 为构建的镜像指定名称和标签

    • 这样构建后会有两个引用:

      • 一个是通过构建过程生成的匿名镜像

      • 一个是命名为 hrfusion-fd-nginx:v1.0 的镜像

2. 容器设置

container_name: hrfusion-fd-hyq
restart: always
  • container_name: hrfusion-fd-hyq - 为容器指定固定名称(而不是随机生成)

  • restart: always - 容器退出时自动重启

    • 这确保了服务在崩溃或服务器重启后自动恢复

3. 端口映射

ports:- "18001:80"
  • 将宿主机的 18001 端口映射到容器的 80 端口

  • 格式:"主机端口:容器端口"

  • 这意味着:

    • 外部访问 http://主机IP:18001

    • 请求会被转发到容器的 80 端口

    • Nginx 在容器内监听 80 端口

4. 数据卷挂载

volumes:# - ./ssl_certs:/etc/nginx/ssl- ./frontend/dist:/usr/share/nginx/html/dist- ./frontend/default.conf:/etc/nginx/conf.d/default.conf
  1. 前端静态文件

    • ./frontend/dist:/usr/share/nginx/html/dist

    • 将本地 frontend/dist 目录挂载到容器的 Nginx 静态文件目录

    • 这样前端构建后文件可以直接被 Nginx 服务

  2. Nginx 配置

    • ./frontend/default.conf:/etc/nginx/conf.d/default.conf

    • 使用本地的 Nginx 配置文件覆盖容器默认配置

    • 这是自定义 Nginx 行为的常见方式

  3. 注释掉的 SSL 证书

    • 如果需要 HTTPS 支持,可以取消注释并配置证书路径

典型工作流程

  1. 前端构建

    • 开发者运行 npm run build 生成 frontend/dist 目录

  2. 启动服务

    • 运行 docker-compose up -d 启动服务

    • Docker 会:

      • 根据 Dockerfile 构建镜像

      • 创建并启动容器

      • 设置所有端口映射和卷挂载

  3. 访问应用

    • 通过 http://服务器IP:18001 访问应用

    • Nginx 会:

      • 读取挂载的配置文件

      • 从挂载的 dist 目录提供静态文件

配置亮点

  1. 开发-生产一致性

    • 使用相同的 Nginx 配置和部署方式开发和生产环境

  2. 快速更新

    • 修改前端代码后只需重新构建 dist 目录

    • 无需重建 Docker 镜像或重启容器(Nginx 会自动提供新文件)

  3. 配置与代码分离

    • Nginx 配置可以独立修改而不影响应用代码

这个配置非常适合前端项目的容器化部署,提供了灵活性、可维护性和便捷的开发体验。

具体联系

(1) docker-compose.yml 依赖 Dockerfile 构建镜像
services:nginx:build: .  # 这里会调用当前目录下的 Dockerfile 构建镜像image: hrfusion-fd-nginx:v1.0
  • build: . 表示 Compose 会读取当前目录的 Dockerfile 来构建镜像。

  • 构建后的镜像会被标记为 hrfusion-fd-nginx:v1.0

(2) Dockerfile 提供基础环境,docker-compose.yml 补充运行时配置
  • Dockerfile 中

    • 定义了基础镜像(nginx:latest)。

    • 清除了默认配置(rm -rf /etc/nginx/conf.d/*)。

    • 创建了目录结构(如 /usr/share/nginx/html/dist)。

  • docker-compose.yml 中

    • 通过 volumes 动态挂载了配置文件(default.conf)和前端代码(dist)。

    • 通过 ports 暴露了端口(18001:80)。

    • 这些配置在容器运行时生效,覆盖或补充了 Dockerfile 的静态设置。

总结

下面我将系统性地总结这些启动方式及其适用场景,并给出如何统一管理的建议:


一、后端启动方式

1. 直接运行 .py 文件
python main.py  # 或使用模块方式
python -m uvicorn main:app --reload
  • 适用场景:开发调试、快速验证

  • 特点

    • 最直接的方式,依赖本地Python环境

    • 需手动安装所有依赖(pip install -r requirements.txt

2. 通过 .sh 脚本启动
#!/bin/bash
# run.sh
pip install -r requirements.txt
python main.py
  • 适用场景:标准化本地开发或简单部署

  • 特点

    • 可封装复杂命令(如环境变量、参数传递)

    • 适合团队统一开发流程

3. 通过 Docker 启动
# Dockerfile
FROM python:3.9
COPY . /app
RUN pip install -r requirements.txt
CMD ["python", "main.py"]
docker build -t backend . && docker run -p 8000:8000 backend
  • 适用场景:生产部署、环境隔离

  • 特点

    • 环境一致性高

    • 需提前构建镜像

4. 通过 Docker Compose 启动
# docker-compose.yml
services:backend:build: ./backendports:- "8000:8000"
  • 适用场景:多服务协作(如需要同时启动数据库)


二、前端启动方式

1. 开发模式(Node.js 直接运行)
npm run dev  # Vite/Webpack等工具
  • 适用场景:前端开发热重载

2. 生产构建 + Docker 托管
# 前端Dockerfile
FROM nginx
COPY dist /usr/share/nginx/html
  • 适用场景:生产环境部署

  • 特点

    • 需先执行 npm run build 生成静态文件

    • 通过Nginx提供高性能静态资源服务

3. 通过 Docker Compose 与后端联动
services:frontend:build: ./frontendports:- "80:80"backend:build: ./backendports:- "8000:8000"

三、统一启动方案

方案1:Makefile 整合多命令
dev:@echo "Starting all services..."cd backend && python main.py & cd frontend && npm run devdocker-up:docker-compose up -d --build
  • 优点:简单直接,适合开发者本地使用

  • 缺点:进程管理较原始(如用 & 后台运行)

方案2:Docker Compose 统一管理
version: '3'
services:frontend:build: ./frontendports: ["3000:3000"]volumes:- ./frontend:/app- /app/node_modulesbackend:build: ./backendports: ["8000:8000"]volumes:- ./backend:/codedb:image: postgresenvironment:POSTGRES_PASSWORD: example
  • 优点

    • 一键启动完整环境(前端+后端+数据库)

    • 环境隔离彻底

  • 缺点

    • 开发时前端热更新需要配置额外卷(如 node_modules 排除)

方案3:混合模式(开发 vs 生产)
.
├── Makefile           # 开发命令(直接运行.py/npm)
├── docker-compose.yml # 生产环境Docker部署
└── docker-compose.dev.yml # 开发环境(带热更新)
  • 开发时

    make dev  # 使用本地Python/Node环境
  • 生产部署

    docker-compose -f docker-compose.prod.yml up -d

四、如何选择?

场景推荐方案
个人开发调试Makefile + 直接运行.py/npm
团队统一开发环境Docker Compose + 代码卷挂载
生产部署Docker Compose(无卷挂载)
需要快速切换多环境混合模式(Makefile + 多Compose文件)

通过灵活组合这些方案,你可以实现从开发到生产的一体化高效工作流!

http://www.lryc.cn/news/583203.html

相关文章:

  • Live555-RTSP服务器
  • Linux——I/O复用
  • 零知开源——STM32F407VET6驱动SHT41温湿度传感器完整教程
  • Linux 中的 .bashrc 是什么?配置详解
  • Python 初识网络爬虫:从概念到实践
  • 什么是公链?
  • 微软 Bluetooth LE Explorer 实用工具的详细使用分析
  • 新零售“云化”进化:基于定制开发开源AI智能名片S2B2C商城小程序的探索
  • 【视频观看系统】- 技术与架构选型
  • HashMap源码分析:put与get方法详解
  • 爬楼梯及其进阶
  • Kubernetes 存储入门
  • 由 DB_FILES 参数导致的 dg 服务器无法同步问题
  • 搭建一款结合传统黄历功能的日历小程序
  • 汽车智能化2.0引爆「万亿蛋糕」,谁在改写游戏规则?
  • A1220LUA-T Allegro高精度霍尔效应开关 车规+极致功耗+全极触发 重新定义位置检测标准
  • 【Gin】HTTP 请求调试器
  • 微软官方C++构建工具:历史演变、核心组件与现代实践指南
  • Rust与Cypress应用
  • 在Ubuntu上安装配置 LLaMA-Factory
  • 人工智能-基础篇-27-模型上下文协议--MCP到底怎么理解?对比HTTP的区别?
  • AI应用实践:制作一个支持超长计算公式的计算器,计算内容只包含加减乘除算法,保存在一个HTML文件中
  • Apache Tomcat SessionExample 漏洞分析与防范
  • 【AI大模型】PyTorch Lightning 简化工具
  • Node.js 是什么?npm 是什么? Vue 为什么需要他们?
  • Flutter基础(前端教程⑦-Http和卡片)
  • 【数字后端】- Standard Cell Status
  • SQLZoo 练习与测试答案汇总(复杂题有最优解与其他解法分析、解题技巧)
  • Java 各集合接口常用方法对照表
  • 解决SQL Server SQL语句性能问题(9)——SQL语句改写(7)