码巢引擎2026年开发文档
00-开发规范
后端规范
README
后端开发手册
前端规范
README
TypeScript最佳实践
前端布局规范
前端页面模板
前端颜色与组件规范
核心规范
组件配置手册
问题排查指南
页面模板
最佳实践
README
bp-20260223-m7ps
图片上传优化总结
BUG自动记录系统使用指南
README
TYPE_SAFETY_GUIDE
常见BUG知识库
常见BUG知识库
开发前检查清单
开发安全规范
开发规范-完整版-含FutureBirdAadminAi部署
数据模型字典
文档分类规范
文档标准化规范
文档模板-基础版
文档模板-技术版
类型安全快速参考卡
类型安全规范体系
规范更新指南
过期文档清理机制
错误处理规范
错误预防指南
常见BUG知识库
常见BUG知识库
01-快速开始
Gitee快速开始
README
协作快速开始
快速开始
质量保证快速开始
02-部署指南
Docker更新指南
Docker部署
FutureBirdAadminAi部署指南
FutureBirdAadminAi部署问题分析
README
发布指南
宝塔Docker部署教程
宝塔PM2部署教程
宝塔图形化部署教程
快速发布指南
数据库和依赖变更处理指南
构建和发布
构建标准
构建检查清单
生产部署快速开始
生产部署方案
生产部署标准
生产部署检查清单
程序备份性能
自动修复和发布指南
自动化发布命令使用指南
部署快速开始
部署指南
项目更新部署指南
03-开发指南
Git凭据配置
Git推送规则
Git自动配置
README
全局样式
协作设置
定时任务
开发指南
开发流程
开发环境标准
技术改进
贡献指南
项目目录树
项目目录结构
04-API文档
API接口文档
README
hr-api
企业API
05-数据库
DATABASE_SCHEMA
README
分区指南
数据库字典
数据持久化
数据模型统一
数据迁移
06-架构设计
RBAC-PERMISSIONS
README
SaaS客户引导流程设计
companyId统一规范
employee-permission-system-design
enterprise-data-linkage
仓库实现总结
仓库模式
企业管理端员工权限系统分析
前端架构
前端重构总结
员工权限系统评估报告
员工管理菜单重构方案
权限系统混乱问题分析
架构优化计划
架构使用指南
架构结构
架构结构
状态管理
用户身份管理体系
系统架构
面试管理模块重构规划
项目技术栈
07-测试质量
README
测试修复标准
测试报告
质量保证系统
08-版本管理
CHANGELOG
README
VERSION_RULES
09-配置指南
README
SMTP配置指南
主题切换指南
渠道配置指南
环境变量指南
环境隔离
12-项目记忆
README
知识库导入指南
记忆系统指南
13-迁移指南
README
备份迁移指南
管理员迁移指南
迁移快速开始
17-其他
README
压缩摘要
18-开放平台
01-架构设计
02-API接口设计
03-安全机制
04-前端设计
05-数据库设计
开放平台API指南
开放平台API说明
19-智能进化
AI执行规则
AI进化机制
README
自动化实现总览
黄金规则
40-操作教程
README
微信公众号域名配置指南
微信本地开发调试指南
44-技能文件
alipay-payment-integration
references
checklist
SKILL
audio
python
README
typescript
README
SKILL
database
python
README
typescript
README
SKILL
design-style-thinking
SKILL
doctor
references
sql-patterns
SKILL
document-generation
python
README
SKILL
email
SKILL
embedding
python
README
typescript
README
SKILL
expo-advanced
references
audio-record-play
file-upload
masonry-layout
save-to-gallery
top-tab-navigation
SKILL
feishu-base
SKILL
feishu-message
SKILL
fetch-url
python
README
typescript
README
SKILL
frontend-design
LICENSE
SKILL
FutureBird-coding-web-performance-best-practice
SKILL
general-dev-preview
references
web-preview
SKILL
image-generation
python
README
typescript
README
SKILL
knowledge
references
python
README
typescript
README
cli
SKILL
llm
python
README
typescript
README
SKILL
miniapp-upload-asr
SKILL
pptx-generation
python
README
SKILL
project-memory-loader
scripts
project_memory_loader
SKILL
repair
scripts
merge-commit-map
SKILL
shadcn-web-base-theme
assets
colors
amber
artistic-green
bento-blue
blue
cyan
emerald
fuchsia
gray
green
indigo
lime
low-pink
neutral
orange
purple
red
retro-brown
rose
sky
supbase-green
teal
tech-purple
vintage-grey
violet
yellow
fonts
business
classic
playful
radius
2xl
2xs
lg
md
none
sm
xl
xs
shadow
artistic
bento
cool
retro
superbase
tech
tool
vintage
default
references
colors
fonts
quick
radius
shadows
scripts
theme
SKILL
package
skill-creator-coze
scripts
init_skill
quick_validate
SKILL
storage
python
README
typescript
README
SKILL
supabase
assets
supabase-client
supabase-client
references
_future
asset-supabase-browser
asset-supabase-config-inject
asset-supabase-config-route
python-auth
python-realtime
python-storage
typescript-auth
typescript-realtime
typescript-storage
typescript-supabase-browser
typescript-supabase-config-inject
typescript-supabase-config-route
python
README
database
edge-functions
orm-model-guide
supabase_client
typescript
README
database
drizzle-schema-guide
edge-functions
supabase-client
cli
rls
SKILL
supabase-auth
references
typescript
supabase-browser
supabase-config-inject
supabase-config-route
auth-config
verify-session
SKILL
ui-design-ref
reference
3D黏土风
克莱因蓝高定风
暗黑科技风
杂志风
极光柔和
柔和卡片
玻璃拟态
纯白极简风
自然有机
SKILL
ui-ux-pro-max
scripts
core
design_system
search
SKILL
vercel-composition-patterns
rules
architecture-avoid-boolean-props
architecture-compound-components
patterns-children-over-render-props
patterns-explicit-variants
react19-no-forwardref
state-context-interface
state-decouple-implementation
state-lift-state
AGENTS
SKILL
vercel-react-best-practices
rules
advanced-event-handler-refs
advanced-init-once
advanced-use-latest
async-api-routes
async-defer-await
async-dependencies
async-parallel
async-suspense-boundaries
bundle-barrel-imports
bundle-conditional
bundle-defer-third-party
bundle-dynamic-imports
bundle-preload
client-event-listeners
client-localstorage-schema
client-passive-event-listeners
client-swr-dedup
js-batch-dom-css
js-cache-function-results
js-cache-property-access
js-cache-storage
js-combine-iterations
js-early-exit
js-hoist-regexp
js-index-maps
js-length-check-first
js-min-max-loop
js-set-map-lookups
js-tosorted-immutable
rendering-activity
rendering-animate-svg-wrapper
rendering-conditional-render
rendering-content-visibility
rendering-hoist-jsx
rendering-hydration-no-flicker
rendering-hydration-suppress-warning
rendering-svg-precision
rendering-usetransition-loading
rerender-defer-reads
rerender-dependencies
rerender-derived-state-no-effect
rerender-derived-state
rerender-functional-setstate
rerender-lazy-state-init
rerender-memo-with-default-value
rerender-memo
rerender-move-effect-to-event
rerender-simple-expression-in-memo
rerender-transitions
rerender-use-ref-transient-values
server-auth-actions
server-cache-lru
server-cache-react
server-dedup-props
server-parallel-fetching
server-serialization
AGENTS
SKILL
video-edit
python
README
typescript
README
SKILL
video-generation
python
README
typescript
README
SKILL
volcano-ark
SKILL
web-design-guidelines
SKILL
web-search
python
README
typescript
README
SKILL
webrtc-best-practice
SKILL
websocket-guide
references
nextjs
nodejs
SKILL
wechat-bot
SKILL
wechat-official-account
SKILL
README
README
未来鸟:企业数字化转型奔腾的力量!
-
+
首页
Docker更新指南
# 宝塔 Docker 部署更新指南 > 本指南详细说明使用 Docker 部署后如何更新项目,包括代码更新和数据库更新。 ## 📋 目录 1. [Docker 更新原理](#1-docker-更新原理) 2. [更新前准备](#2-更新前准备) 3. [方式一:重新构建镜像更新](#3-方式一重新构建镜像更新) 4. [方式二:Git 拉取 + 重建更新](#4-方式二git-拉取--重建更新) 5. [方式三:滚动更新(零停机)](#5-方式三滚动更新零停机) 6. [数据库更新处理](#6-数据库更新处理) 7. [回滚方案](#7-回滚方案) 8. [自动化更新脚本](#8-自动化更新脚本) 9. [常见问题](#9-常见问题) --- ## 1. Docker 更新原理 ### 1.1 Docker 更新的本质 ``` ┌─────────────────────────────────────────────────────────┐ │ Docker 更新流程 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 旧容器 (运行中) 新容器 (待启动) │ │ ┌─────────────┐ ┌─────────────┐ │ │ │ v1.0.0 │ → │ v1.0.1 │ │ │ │ 旧代码 │ │ 新代码 │ │ │ │ 旧数据库 │ │ 同一数据库 │ │ │ └─────────────┘ └─────────────┘ │ │ │ │ 步骤:拉代码 → 构建新镜像 → 停旧容器 → 启新容器 │ └─────────────────────────────────────────────────────────┘ ``` ### 1.2 关键点理解 | 概念 | 说明 | 数据持久性 | |------|------|------------| | **镜像** | 包含代码和运行环境 | 不持久,每次更新重建 | | **容器** | 镜像的运行实例 | 不持久,删除就没了 | | **数据卷** | 数据库文件、上传文件 | **持久**,更新不丢失 | | **环境变量** | 配置信息 | 通过参数传递 | **重要**:数据库数据存储在 Docker 数据卷或外部 PostgreSQL,不会被更新影响! --- ## 2. 更新前准备 ### 2.1 查看当前状态 ```bash # SSH 登录服务器 ssh root@your-server-ip # 查看运行中的容器 docker ps | grep hrm-app # 输出示例: # CONTAINER ID IMAGE COMMAND STATUS PORTS # abc123def456 hrm-app:1.0.0 "pnpm start" Up 2 days 0.0.0.0:5000->5000/tcp # 查看镜像版本 docker images | grep hrm-app # 查看数据卷 docker volume ls | grep hrm ``` ### 2.2 备份数据库(重要!) ```bash # 方式一:从容器内备份 docker exec hrm-app pg_dump -U hrm_user hrm_db > /root/backup/db_$(date +%Y%m%d_%H%M%S).sql # 方式二:如果使用外部 PostgreSQL pg_dump -h 127.0.0.1 -U hrm_user hrm_db > /root/backup/db_$(date +%Y%m%d_%H%M%S).sql # 压缩备份 gzip /root/backup/db_*.sql ``` ### 2.3 创建备份脚本 ```bash # 创建备份脚本 cat > /root/scripts/docker-backup.sh << 'EOF' #!/bin/bash BACKUP_DIR="/root/backup/hrm-docker" DATE=$(date +%Y%m%d_%H%M%S) mkdir -p $BACKUP_DIR/$DATE echo "========== Docker 备份开始 ==========" # 1. 备份数据库 echo "1. 备份数据库..." docker exec hrm-app pg_dump -U hrm_user hrm_db > $BACKUP_DIR/$DATE/database.sql 2>/dev/null if [ $? -eq 0 ]; then gzip $BACKUP_DIR/$DATE/database.sql echo " ✅ 数据库备份完成" else echo " ⚠️ 数据库备份失败(可能使用外部数据库)" fi # 2. 导出当前镜像 echo "2. 导出当前镜像..." docker save -o $BACKUP_DIR/$DATE/image.tar hrm-app:latest echo " ✅ 镜像导出完成" # 3. 记录容器信息 echo "3. 记录容器信息..." docker inspect hrm-app > $BACKUP_DIR/$DATE/container-info.json docker logs hrm-app --tail 100 > $BACKUP_DIR/$DATE/container-logs.txt echo " ✅ 容器信息记录完成" # 4. 备份上传文件(如果有) echo "4. 备份上传文件..." docker cp hrm-app:/app/public/uploads $BACKUP_DIR/$DATE/uploads 2>/dev/null if [ $? -eq 0 ]; then echo " ✅ 上传文件备份完成" else echo " ⚠️ 无上传文件目录" fi # 计算大小 BACKUP_SIZE=$(du -sh $BACKUP_DIR/$DATE | cut -f1) echo "" echo "========== 备份完成 ==========" echo "备份路径: $BACKUP_DIR/$DATE" echo "备份大小: $BACKUP_SIZE" # 清理旧备份(保留7天) find $BACKUP_DIR -type d -name "20*" -mtime +7 -exec rm -rf {} \; 2>/dev/null EOF chmod +x /root/scripts/docker-backup.sh # 创建目录 mkdir -p /root/backup/hrm-docker /root/scripts # 执行备份 /root/scripts/docker-backup.sh ``` --- ## 3. 方式一:重新构建镜像更新 ### 3.1 适用场景 - 本地开发环境可用 - 需要完全控制构建过程 - 有自定义修改 ### 3.2 完整流程 #### 步骤 1:本地构建新镜像 ```bash # 在本地开发机器上 cd /workspace/projects # 拉取最新代码 git pull origin main # 检查是否有数据库变更 git diff --name-only HEAD~1 HEAD | grep -E "schema.ts|drizzle/" # 如果有输出,说明有数据库变更,需要特别处理! # 构建新镜像 docker build -t hrm-app:1.0.1 . # 打标签 docker tag hrm-app:1.0.1 hrm-app:latest ``` #### 步骤 2:导出镜像 ```bash # 导出为 tar 文件 docker save -o hrm-app-1.0.1.tar hrm-app:1.0.1 # 压缩(可选,节省传输时间) gzip hrm-app-1.0.1.tar ``` #### 步骤 3:上传到服务器 ```bash # 方式 A:使用 scp scp hrm-app-1.0.1.tar.gz root@your-server-ip:/root/ # 方式 B:使用 rsync(更快,支持断点续传) rsync -avz --progress hrm-app-1.0.1.tar.gz root@your-server-ip:/root/ # 方式 C:使用宝塔面板 # 打开宝塔 → 文件 → 上传 hrm-app-1.0.1.tar.gz 到 /root/ ``` #### 步骤 4:服务器加载镜像 ```bash # SSH 登录服务器 ssh root@your-server-ip # 解压(如果压缩了) gunzip /root/hrm-app-1.0.1.tar.gz # 加载镜像 docker load -i /root/hrm-app-1.0.1.tar # 验证镜像已加载 docker images | grep hrm-app ``` #### 步骤 5:停止旧容器 ```bash # 查看当前容器 docker ps | grep hrm-app # 停止容器 docker stop hrm-app # (可选)重命名旧容器作为备份 docker rename hrm-app hrm-app-old ``` #### 步骤 6:启动新容器 ```bash # 启动新容器(使用相同的数据卷和配置) docker run -d \ --name hrm-app \ --restart unless-stopped \ -p 5000:5000 \ -v hrm-uploads:/app/public/uploads \ -e DATABASE_URL="postgresql://hrm_user:your_password@postgres:5432/hrm_db" \ -e JWT_SECRET="your-jwt-secret" \ -e FutureBirdAadminAi_PROJECT_ENV=PROD \ -e FutureBirdAadminAi_PROJECT_DOMAIN_DEFAULT="https://your-domain.com" \ --network hrm-network \ hrm-app:1.0.1 # 查看启动状态 docker logs -f hrm-app ``` #### 步骤 7:验证更新 ```bash # 检查容器状态 docker ps | grep hrm-app # 检查健康状态 curl -I http://localhost:5000 # 查看日志 docker logs hrm-app --tail 50 ``` #### 步骤 8:清理旧资源 ```bash # 确认新容器运行正常后,清理旧资源 # 删除旧容器 docker rm hrm-app-old # 删除旧镜像 docker image prune -f # 删除上传的 tar 文件 rm /root/hrm-app-1.0.1.tar ``` --- ## 4. 方式二:Git 拉取 + 重建更新 ### 4.1 适用场景 - 服务器可以直接访问 Git 仓库 - 不想每次上传镜像文件 - 更新频繁 ### 4.2 服务器准备工作 ```bash # 首次配置(只需执行一次) # 创建项目目录 mkdir -p /www/docker-build/hrm-app cd /www/docker-build/hrm-app # 克隆代码 git clone https://your-git-repo.git . # 或使用私有仓库 git clone https://username:token@your-git-repo.git . # 创建构建脚本 cat > /www/docker-build/hrm-app/build-and-update.sh << 'EOF' #!/bin/bash set -e PROJECT_DIR="/www/docker-build/hrm-app" IMAGE_NAME="hrm-app" CONTAINER_NAME="hrm-app" echo "========== Docker 构建更新 ==========" cd $PROJECT_DIR # 1. 拉取最新代码 echo "1. 拉取最新代码..." BEFORE=$(git rev-parse HEAD) git pull origin main AFTER=$(git rev-parse HEAD) if [ "$BEFORE" = "$AFTER" ]; then echo "没有新代码,跳过更新" exit 0 fi echo "版本更新: $BEFORE → $AFTER" # 2. 检查数据库变更 echo "2. 检查数据库变更..." if git diff $BEFORE $AFTER --name-only | grep -qE "schema.ts|drizzle/"; then echo "⚠️ 检测到数据库变更,需要手动处理迁移!" echo "请执行数据库迁移后再继续" exit 1 fi # 3. 构建新镜像 echo "3. 构建新镜像..." docker build -t $IMAGE_NAME:latest . docker tag $IMAGE_NAME:latest $IMAGE_NAME:$AFTER # 4. 停止旧容器 echo "4. 停止旧容器..." docker stop $CONTAINER_NAME 2>/dev/null || true docker rename $CONTAINER_NAME ${CONTAINER_NAME}-old 2>/dev/null || true # 5. 启动新容器 echo "5. 启动新容器..." # 使用之前保存的配置 source /root/docker-config.sh docker run -d \ --name $CONTAINER_NAME \ --restart unless-stopped \ -p 5000:5000 \ -v hrm-uploads:/app/public/uploads \ -e DATABASE_URL="$DATABASE_URL" \ -e JWT_SECRET="$JWT_SECRET" \ -e FutureBirdAadminAi_PROJECT_ENV=PROD \ -e FutureBirdAadminAi_PROJECT_DOMAIN_DEFAULT="$DOMAIN" \ --network hrm-network \ $IMAGE_NAME:latest # 6. 等待启动 echo "6. 等待启动..." sleep 10 # 7. 验证 echo "7. 验证..." HTTP=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:5000) if [ "$HTTP" = "200" ] || [ "$HTTP" = "307" ]; then echo "✅ 更新成功 (HTTP $HTTP)" # 清理旧容器 docker rm ${CONTAINER_NAME}-old 2>/dev/null || true else echo "❌ 启动失败 (HTTP $HTTP)" echo "回滚到旧版本..." docker stop $CONTAINER_NAME docker rm $CONTAINER_NAME docker rename ${CONTAINER_NAME}-old $CONTAINER_NAME docker start $CONTAINER_NAME exit 1 fi echo "========== 更新完成 ==========" EOF chmod +x /www/docker-build/hrm-app/build-and-update.sh # 保存 Docker 配置 cat > /root/docker-config.sh << 'EOF' DATABASE_URL="postgresql://hrm_user:your_password@postgres:5432/hrm_db" JWT_SECRET="your-jwt-secret" DOMAIN="https://your-domain.com" EOF chmod 600 /root/docker-config.sh ``` ### 4.3 执行更新 ```bash # 执行更新 /www/docker-build/hrm-app/build-and-update.sh ``` --- ## 5. 方式三:滚动更新(零停机) ### 5.1 适用场景 - 不能停机服务 - 有负载均衡器 - 高可用要求 ### 5.2 架构说明 ``` Nginx 负载均衡 │ ┌────────────┼────────────┐ ▼ ▼ ┌─────────────┐ ┌─────────────┐ │ hrm-app-1 │ │ hrm-app-2 │ │ 端口 5001 │ │ 端口 5002 │ └─────────────┘ └─────────────┘ ``` ### 5.3 实现步骤 ```bash # 配置 Nginx 负载均衡 cat > /www/server/panel/vhost/nginx/hrm-app.conf << 'EOF' upstream hrm_backend { server 127.0.0.1:5001 weight=1; server 127.0.0.1:5002 weight=1; } server { listen 80; server_name your-domain.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name your-domain.com; ssl_certificate /www/server/panel/vhost/cert/your-domain.com/fullchain.pem; ssl_certificate_key /www/server/panel/vhost/cert/your-domain.com/privkey.pem; location / { proxy_pass http://hrm_backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } EOF # 重载 Nginx nginx -s reload ``` ### 5.4 滚动更新脚本 ```bash cat > /root/scripts/rolling-update.sh << 'EOF' #!/bin/bash set -e IMAGE_NAME="hrm-app" NEW_IMAGE="$1" if [ -z "$NEW_IMAGE" ]; then echo "用法: $0 <新镜像名:标签>" echo "示例: $0 hrm-app:1.0.1" exit 1 fi echo "========== 滚动更新 ==========" # 1. 更新 hrm-app-2 echo "1. 更新 hrm-app-2..." docker stop hrm-app-2 docker rm hrm-app-2 docker run -d \ --name hrm-app-2 \ --restart unless-stopped \ -p 5002:5000 \ -v hrm-uploads:/app/public/uploads \ -e DATABASE_URL="$DATABASE_URL" \ -e JWT_SECRET="$JWT_SECRET" \ -e FutureBirdAadminAi_PROJECT_ENV=PROD \ --network hrm-network \ $NEW_IMAGE # 等待启动 sleep 10 # 验证 HTTP=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:5002) if [ "$HTTP" != "200" ] && [ "$HTTP" != "307" ]; then echo "❌ hrm-app-2 启动失败" exit 1 fi echo "✅ hrm-app-2 更新成功" # 2. 更新 hrm-app-1 echo "2. 更新 hrm-app-1..." docker stop hrm-app-1 docker rm hrm-app-1 docker run -d \ --name hrm-app-1 \ --restart unless-stopped \ -p 5001:5000 \ -v hrm-uploads:/app/public/uploads \ -e DATABASE_URL="$DATABASE_URL" \ -e JWT_SECRET="$JWT_SECRET" \ -e FutureBirdAadminAi_PROJECT_ENV=PROD \ --network hrm-network \ $NEW_IMAGE # 等待启动 sleep 10 # 验证 HTTP=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:5001) if [ "$HTTP" != "200" ] && [ "$HTTP" != "307" ]; then echo "❌ hrm-app-1 启动失败" exit 1 fi echo "✅ hrm-app-1 更新成功" echo "========== 滚动更新完成 ==========" EOF chmod +x /root/scripts/rolling-update.sh # 使用 /root/scripts/rolling-update.sh hrm-app:1.0.1 ``` --- ## 6. 数据库更新处理 ### 6.1 数据库更新流程 Docker 容器更新时,数据库可能需要迁移: ```bash # 1. 备份数据库(必须!) docker exec hrm-app pg_dump -U hrm_user hrm_db > /root/backup/db_before_update.sql # 2. 进入容器执行迁移 docker exec -it hrm-app bash # 在容器内执行: cd /app # 生成迁移文件 pnpm drizzle-kit generate # 执行迁移 pnpm drizzle-kit push # 退出容器 exit # 3. 验证数据库 docker exec hrm-app psql -U hrm_user -d hrm_db -c "\dt" ``` ### 6.2 使用迁移容器 创建专门的迁移容器: ```bash # 创建迁移脚本 cat > /root/scripts/db-migrate.sh << 'EOF' #!/bin/bash IMAGE_NAME="hrm-app:latest" DATABASE_URL="postgresql://hrm_user:your_password@postgres:5432/hrm_db" echo "========== 数据库迁移 ==========" # 运行迁移容器 docker run --rm \ --network hrm-network \ -e DATABASE_URL="$DATABASE_URL" \ $IMAGE_NAME \ sh -c "pnpm drizzle-kit generate && pnpm drizzle-kit push" if [ $? -eq 0 ]; then echo "✅ 迁移成功" else echo "❌ 迁移失败" exit 1 fi EOF chmod +x /root/scripts/db-migrate.sh # 执行迁移 /root/scripts/db-migrate.sh ``` --- ## 7. 回滚方案 ### 7.1 快速回滚到上一版本 ```bash cat > /root/scripts/docker-rollback.sh << 'EOF' #!/bin/bash CONTAINER_NAME="hrm-app" echo "========== Docker 回滚 ==========" # 1. 查看可用镜像 echo "可用镜像:" docker images | grep hrm-app echo "" # 2. 输入要回滚的镜像 read -p "请输入要回滚的镜像标签(如 1.0.0): " TAG if [ -z "$TAG" ]; then echo "未输入标签,取消回滚" exit 1 fi IMAGE="hrm-app:$TAG" # 3. 确认 echo "即将回滚到: $IMAGE" read -p "确认回滚?(y/n): " CONFIRM if [ "$CONFIRM" != "y" ]; then echo "取消回滚" exit 0 fi # 4. 停止当前容器 echo "停止当前容器..." docker stop $CONTAINER_NAME docker rename $CONTAINER_NAME ${CONTAINER_NAME}-failed # 5. 启动旧版本 echo "启动旧版本..." source /root/docker-config.sh docker run -d \ --name $CONTAINER_NAME \ --restart unless-stopped \ -p 5000:5000 \ -v hrm-uploads:/app/public/uploads \ -e DATABASE_URL="$DATABASE_URL" \ -e JWT_SECRET="$JWT_SECRET" \ -e FutureBirdAadminAi_PROJECT_ENV=PROD \ -e FutureBirdAadminAi_PROJECT_DOMAIN_DEFAULT="$DOMAIN" \ --network hrm-network \ $IMAGE # 6. 验证 sleep 10 HTTP=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:5000) if [ "$HTTP" = "200" ] || [ "$HTTP" = "307" ]; then echo "✅ 回滚成功" docker rm ${CONTAINER_NAME}-failed else echo "❌ 回滚失败" fi EOF chmod +x /root/scripts/docker-rollback.sh ``` ### 7.2 数据库回滚 ```bash # 如果更新导致数据库问题,需要恢复备份 # 1. 找到备份文件 ls -lt /root/backup/hrm-docker/ # 2. 恢复数据库 BACKUP_FILE="/root/backup/hrm-docker/20260517_143000/database.sql.gz" # 解压 gunzip -c $BACKUP_FILE > /tmp/database.sql # 恢复到容器内的数据库 docker exec -i hrm-app psql -U hrm_user -d hrm_db < /tmp/database.sql # 清理 rm /tmp/database.sql ``` --- ## 8. 自动化更新脚本 ### 8.1 完整自动化脚本 ```bash cat > /root/scripts/docker-auto-update.sh << 'EOF' #!/bin/bash set -e # 配置 PROJECT_DIR="/www/docker-build/hrm-app" IMAGE_NAME="hrm-app" CONTAINER_NAME="hrm-app" BACKUP_DIR="/root/backup/hrm-docker" DATE=$(date +%Y%m%d_%H%M%S) # 加载配置 source /root/docker-config.sh 2>/dev/null || { echo "❌ 请先配置 /root/docker-config.sh" exit 1 } echo "==========================================" echo " Docker 自动化更新脚本" echo " 时间: $(date)" echo "==========================================" echo "" # Step 1: 备份 echo "【Step 1/7】备份..." mkdir -p $BACKUP_DIR/$DATE # 备份数据库 docker exec $CONTAINER_NAME pg_dump -U hrm_user hrm_db 2>/dev/null | gzip > $BACKUP_DIR/$DATE/database.sql.gz echo " ✅ 数据库已备份" # 导出当前镜像 docker save -o $BACKUP_DIR/$DATE/image.tar $IMAGE_NAME:latest 2>/dev/null echo " ✅ 当前镜像已保存" # Step 2: 拉取代码 echo "" echo "【Step 2/7】拉取最新代码..." cd $PROJECT_DIR BEFORE=$(git rev-parse --short HEAD) git fetch origin git pull origin main AFTER=$(git rev-parse --short HEAD) if [ "$BEFORE" = "$AFTER" ]; then echo " 无新代码,退出" exit 0 fi echo " ✅ 代码已更新: $BEFORE → $AFTER" # Step 3: 检查数据库变更 echo "" echo "【Step 3/7】检查数据库变更..." DB_CHANGED=0 if git diff $BEFORE $AFTER --name-only | grep -qE "schema.ts|drizzle/"; then DB_CHANGED=1 echo " ⚠️ 检测到数据库变更" else echo " ✅ 无数据库变更" fi # Step 4: 数据库迁移 if [ $DB_CHANGED -eq 1 ]; then echo "" echo "【Step 4/7】执行数据库迁移..." # 运行迁移 docker run --rm \ --network hrm-network \ -e DATABASE_URL="$DATABASE_URL" \ $IMAGE_NAME:latest \ sh -c "cd /app && pnpm drizzle-kit generate && pnpm drizzle-kit push" 2>&1 if [ $? -ne 0 ]; then echo " ❌ 迁移失败,恢复备份..." gunzip -c $BACKUP_DIR/$DATE/database.sql.gz | docker exec -i $CONTAINER_NAME psql -U hrm_user -d hrm_db exit 1 fi echo " ✅ 迁移完成" fi # Step 5: 构建新镜像 echo "" echo "【Step 5/7】构建新镜像..." docker build -t $IMAGE_NAME:$AFTER -t $IMAGE_NAME:latest . echo " ✅ 镜像构建完成" # Step 6: 更新容器 echo "" echo "【Step 6/7】更新容器..." # 停止旧容器 docker stop $CONTAINER_NAME docker rename $CONTAINER_NAME ${CONTAINER_NAME}-old # 启动新容器 docker run -d \ --name $CONTAINER_NAME \ --restart unless-stopped \ -p 5000:5000 \ -v hrm-uploads:/app/public/uploads \ -e DATABASE_URL="$DATABASE_URL" \ -e JWT_SECRET="$JWT_SECRET" \ -e FutureBirdAadminAi_PROJECT_ENV=PROD \ -e FutureBirdAadminAi_PROJECT_DOMAIN_DEFAULT="$DOMAIN" \ --network hrm-network \ $IMAGE_NAME:latest echo " ✅ 新容器已启动" # Step 7: 验证 echo "" echo "【Step 7/7】验证..." sleep 10 HTTP=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:5000) if [ "$HTTP" = "200" ] || [ "$HTTP" = "307" ]; then echo " ✅ 应用运行正常 (HTTP $HTTP)" # 清理旧容器 docker rm ${CONTAINER_NAME}-old 2>/dev/null # 清理旧镜像 docker image prune -f echo "" echo "==========================================" echo " ✅ 更新完成" echo " 版本: $AFTER" echo " 备份: $BACKUP_DIR/$DATE" echo "==========================================" else echo " ❌ 应用启动失败 (HTTP $HTTP)" echo " 正在回滚..." docker stop $CONTAINER_NAME docker rm $CONTAINER_NAME docker rename ${CONTAINER_NAME}-old $CONTAINER_NAME docker start $CONTAINER_NAME echo " 已回滚到旧版本" exit 1 fi EOF chmod +x /root/scripts/docker-auto-update.sh ``` ### 8.2 定时自动更新 ```bash # 添加 crontab 定时任务 crontab -e # 添加以下内容(每天凌晨 3 点检查更新) 0 3 * * * /root/scripts/docker-auto-update.sh >> /root/logs/auto-update.log 2>&1 # 创建日志目录 mkdir -p /root/logs ``` --- ## 9. 常见问题 ### Q1: 更新后容器启动失败 ```bash # 查看日志 docker logs hrm-app # 常见原因: # 1. 端口被占用 # 2. 数据库连接失败 # 3. 环境变量缺失 # 4. 数据库结构不匹配 # 快速排查 docker inspect hrm-app docker exec hrm-app env ``` ### Q2: 数据库连接失败 ```bash # 检查网络 docker network inspect hrm-network # 检查数据库容器 docker ps | grep postgres # 测试连接 docker exec hrm-app psql -U hrm_user -d hrm_db -c "SELECT 1" ``` ### Q3: 镜像太大传输慢 ```bash # 使用 .dockerignore 减小镜像 cat > .dockerignore << 'EOF' node_modules .next .git *.log *.md .env.local EOF # 使用多阶段构建优化 Dockerfile ``` ### Q4: 如何查看容器资源使用 ```bash # 实时查看 docker stats hrm-app # 查看详细信息 docker inspect hrm-app | grep -A 10 "Memory" ``` ### Q5: 如何进入容器调试 ```bash # 进入容器 docker exec -it hrm-app bash # 查看文件 ls -la /app # 查看环境变量 env # 测试数据库连接 psql -U hrm_user -d hrm_db # 退出 exit ``` ### Q6: 数据卷数据如何迁移 ```bash # 查看数据卷 docker volume ls # 备份数据卷 docker run --rm -v hrm-uploads:/data -v $(pwd):/backup alpine tar czf /backup/uploads.tar.gz -C /data . # 恢复数据卷 docker run --rm -v hrm-uploads:/data -v $(pwd):/backup alpine tar xzf /backup/uploads.tar.gz -C /data ``` --- ## 📝 Docker 更新速查表 | 操作 | 命令 | |------|------| | 查看容器状态 | `docker ps -a \| grep hrm-app` | | 查看容器日志 | `docker logs hrm-app --tail 100` | | 进入容器 | `docker exec -it hrm-app bash` | | 重启容器 | `docker restart hrm-app` | | 停止容器 | `docker stop hrm-app` | | 启动容器 | `docker start hrm-app` | | 查看镜像 | `docker images \| grep hrm-app` | | 删除旧镜像 | `docker image prune -f` | | 备份数据库 | `docker exec hrm-app pg_dump -U hrm_user hrm_db > backup.sql` | | 查看资源使用 | `docker stats hrm-app` | | 查看网络 | `docker network inspect hrm-network` | --- ## 🎯 最佳实践 1. **更新前必备份**:每次更新前备份数据库和镜像 2. **使用版本标签**:不要只用 latest,给镜像打版本标签 3. **测试后部署**:先在测试环境验证,再部署生产 4. **监控告警**:设置容器健康检查和告警 5. **回滚预案**:确保随时可以快速回滚 6. **文档记录**:记录每次更新的内容和结果
未来鸟
2026年7月27日 10:12
转发
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
分享
链接
类型
密码
更新密码
有效期
Markdown文件
Word文件
PDF文档(打印)
AI