.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"
這部分代碼的作用是獲取腳本的真實路徑,即使腳本是通過軟鏈接調用的。它通過以下步驟實現:
-
獲取腳本路徑(
SOURCE
) -
如果路徑是軟鏈接(
-L
),則解析真實路徑 -
處理相對路徑的情況(
SOURCE != /*
) -
最終獲取腳本所在目錄的絕對路徑(
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
}
這個函數負責啟動后端程序,它會:
-
創建必要的日志目錄
-
檢查程序是否已經在運行
-
使用nohup在后臺啟動Python程序,并重定向輸出到日志文件
-
保存進程ID(PID)到文件
-
啟動守護進程(如果未運行)
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 [選項]
具體操作命令
-
啟動后端程序:
bash script.sh start
-
這會激活conda環境并啟動Python后端程序
-
同時會啟動守護進程(如果配置了的話)
-
-
停止后端程序:
bash script.sh stop
-
重啟后端程序:
bash script.sh restart
-
手動切割日志:
bash script.sh rotate
-
檢查程序狀態:
bash script.sh status
-
查看幫助信息:
bash script.sh help 或 bash script.sh --help 或 bash script.sh -h
?守護進程腳本
后端啟動后意外停止的常見原因:
Python 腳本自身崩潰
-
可能原因:
-
未捕獲的異常(如?
KeyError
,?ImportError
)。 -
內存泄漏導致被系統 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 "程序正在運行"
}
-
邏輯:
-
調用?
op.sh status
?檢查服務狀態。 -
用?
grep -q
?靜默匹配輸出中是否包含?程序正在運行
。 -
如果匹配成功(服務在運行),返回?
0
(成功);否則返回非零。
-
4. 服務啟動函數
start_service() {log "檢測到服務未運行,嘗試啟動...""$OP_SCRIPT" start >> "$LOG_FILE" 2>&1
}
-
如果服務未運行:
-
記錄日志。
-
調用?
op.sh start
?啟動服務,并將輸出和錯誤重定向到日志文件。
-
5. 主循環
log "守護進程啟動,開始監控后端服務..."
while true; doif ! is_running; thenstart_servicefisleep $CHECK_INTERVAL
done
-
無限循環:
-
檢查服務狀態(
is_running
)。 -
如果服務停止,調用?
start_service
。 -
休眠?
CHECK_INTERVAL
?秒后重復檢查。
-
關鍵點總結
-
依賴關系:
-
需要同目錄下的?
op.sh
?腳本,且該腳本需支持?status
?和?start
?命令。 -
假設?
op.sh status
?的輸出中包含?程序正在運行
?字符串。
-
-
日志管理:
-
所有操作記錄到?
logs/backend/daemon.log
,便于排查問題。
-
-
工作場景:
-
適合監控需要長期運行的后端服務(如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
?是一個特殊目標,用于聲明哪些目標是"偽目標"(不是實際的文件名) -
這里聲明了?
help
,?dev-frontend
,?dev-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
-
前端靜態文件目錄:
-
/usr/share/nginx/html/dist
?是準備存放前端構建產物(如 Vue/React 打包后的文件)的目錄 -
-p
?參數確保即使父目錄不存在也會創建
-
-
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 適合用于:
-
部署前端靜態資源(如 Vue/React 應用)
-
需要自定義 Nginx 配置的情況
-
作為基礎鏡像進一步擴展
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
-
前端靜態文件:
-
./frontend/dist:/usr/share/nginx/html/dist
-
將本地?
frontend/dist
?目錄掛載到容器的 Nginx 靜態文件目錄 -
這樣前端構建后文件可以直接被 Nginx 服務
-
-
Nginx 配置:
-
./frontend/default.conf:/etc/nginx/conf.d/default.conf
-
使用本地的 Nginx 配置文件覆蓋容器默認配置
-
這是自定義 Nginx 行為的常見方式
-
-
注釋掉的 SSL 證書:
-
如果需要 HTTPS 支持,可以取消注釋并配置證書路徑
-
典型工作流程
-
前端構建:
-
開發者運行?
npm run build
?生成?frontend/dist
?目錄
-
-
啟動服務:
-
運行?
docker-compose up -d
?啟動服務 -
Docker 會:
-
根據 Dockerfile 構建鏡像
-
創建并啟動容器
-
設置所有端口映射和卷掛載
-
-
-
訪問應用:
-
通過?
http://服務器IP:18001
?訪問應用 -
Nginx 會:
-
讀取掛載的配置文件
-
從掛載的?
dist
?目錄提供靜態文件
-
-
配置亮點
-
開發-生產一致性:
-
使用相同的 Nginx 配置和部署方式開發和生產環境
-
-
快速更新:
-
修改前端代碼后只需重新構建?
dist
?目錄 -
無需重建 Docker 鏡像或重啟容器(Nginx 會自動提供新文件)
-
-
配置與代碼分離:
-
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文件) |
通過靈活組合這些方案,你可以實現從開發到生產的一體化高效工作流!