Commit e7eee9fc by yiling.shen

集成自定义数据库迁移方案:实现版本管理,避免重复执行SQL脚本

parent c3556ae3
# 患者画像回访话术系统 - GitLab CI/CD 配置
# 极简版本,确保pipeline成功运行
# 集成自定义数据库迁移方案
stages:
- test
......@@ -8,6 +8,10 @@ stages:
# 全局变量
variables:
APP_NAME: "patient-callback-system"
DB_HOST: "mysql"
DB_USER: "callback_user"
DB_PASSWORD: "dev_password_123"
DB_NAME: "callback_system"
# 测试阶段 - 极简版本
test:
......@@ -21,10 +25,14 @@ test:
- main
allow_failure: false
# 部署到生产环境
# 部署到生产环境 - 集成数据库迁移
deploy_production:
stage: deploy
image: alpine:latest
image: docker/compose:latest
services:
- docker:dind
variables:
COMPOSE_PROJECT_NAME: "patient_callback_${CI_COMMIT_REF_SLUG}"
before_script:
- apk add --no-cache openssh-client mysql-client
- eval $(ssh-agent -s)
......@@ -42,13 +50,27 @@ deploy_production:
--single-transaction --routines --triggers \
$PROD_DB_NAME > backup_$(date +%Y%m%d_%H%M%S).sql
# 2. 上传部署脚本
- echo "上传部署脚本..."
# 2. 上传部署脚本和迁移文件
- echo "上传部署脚本和迁移文件..."
- scp -r db/ $PROD_SSH_USER@$PROD_SSH_HOST:/tmp/
- scp run-migrations.sh $PROD_SSH_USER@$PROD_SSH_HOST:/tmp/
- scp deploy_scripts/deploy.sh $PROD_SSH_USER@$PROD_SSH_HOST:/tmp/
- scp deploy_scripts/migrate_database.sql $PROD_SSH_USER@$PROD_SSH_HOST:/tmp/
# 3. 执行部署
- echo "执行自动化部署..."
# 3. 执行数据库迁移
- echo "执行数据库迁移..."
- ssh $PROD_SSH_USER@$PROD_SSH_HOST "
chmod +x /tmp/run-migrations.sh &&
export DB_HOST=$PROD_DB_HOST &&
export DB_PORT=$PROD_DB_PORT &&
export DB_USER=$PROD_DB_USER &&
export DB_PASSWORD=$PROD_DB_PASSWORD &&
export DB_NAME=$PROD_DB_NAME &&
/tmp/run-migrations.sh
"
# 4. 执行应用部署
- echo "执行应用部署..."
- ssh $PROD_SSH_USER@$PROD_SSH_HOST "
chmod +x /tmp/deploy.sh &&
export DB_HOST=$PROD_DB_HOST &&
......@@ -62,7 +84,7 @@ deploy_production:
/tmp/deploy.sh
"
# 4. 验证部署
# 5. 验证部署结果
- echo "验证部署结果..."
- sleep 30
- curl -f $PROD_APP_URL/api/health || exit 1
......@@ -105,4 +127,25 @@ rollback_production:
only:
- main
tags:
- production
\ No newline at end of file
- production
# 数据库迁移状态检查
check_migrations:
stage: deploy
image: alpine:latest
before_script:
- apk add --no-cache mysql-client
script:
- echo "检查数据库迁移状态..."
- mysql -h $PROD_DB_HOST -P $PROD_DB_PORT -u $PROD_DB_USER -p$PROD_DB_PASSWORD \
$PROD_DB_NAME -e "SELECT script_name, description, applied_at FROM schema_migrations ORDER BY applied_at;"
- echo "迁移状态检查完成"
environment:
name: production
url: $PROD_APP_URL
when: manual
only:
- main
tags:
- production
allow_failure: true
\ No newline at end of file
# GitLab CI/CD 环境变量配置模板
# GitLab CI/CD 环境变量配置模板
## 🔧 环境变量配置
请将以下内容复制到GitLab项目的环境变量中:
### 数据库配置
| 变量名 | 值 | 说明 | 保护 | 掩码 |
|--------|----|----|----|----|
| PROD_DB_HOST | 您的生产数据库主机地址 | 数据库服务器IP或域名 | ✅ | ❌ |
| PROD_DB_PORT | 3306 | 数据库端口 | ✅ | ❌ |
| PROD_DB_USER | 您的数据库用户名 | 数据库用户名 | ✅ | ❌ |
| PROD_DB_PASSWORD | 您的数据库密码 | 数据库密码 | ✅ | ✅ |
| PROD_DB_NAME | callback_system | 数据库名称 | ✅ | ❌ |
### 应用配置
| 变量名 | 值 | 说明 | 保护 | 掩码 |
|--------|----|----|----|----|
| PROD_APP_URL | http://您的域名:4002 | 生产环境应用URL | ✅ | ❌ |
| PROD_SSH_HOST | 您的生产服务器IP | 生产服务器地址 | ✅ | ❌ |
| PROD_SSH_USER | 您的SSH用户名 | SSH登录用户名 | ✅ | ❌ |
| PROD_SSH_PRIVATE_KEY | 见下方私钥内容 | SSH私钥 | ✅ | ✅ |
| PROD_SSH_KNOWN_HOSTS | 见下方说明 | SSH主机指纹 | ✅ | ❌ |
### SSH私钥内容
将以下内容复制到 PROD_SSH_PRIVATE_KEY 变量中:
```
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
```
### SSH主机指纹获取
在生产服务器上运行以下命令获取主机指纹:
```bash
ssh-keyscan -H 您的生产服务器IP
```
将输出内容复制到 PROD_SSH_KNOWN_HOSTS 变量中。
## 🚀 配置步骤
1. 登录GitLab: https://code.jwsmed.com/ai-tools/customer-recall
2. 进入 Settings → CI/CD → Variables
3. 点击 Add Variable 添加上述变量
4. 对于敏感信息(密码、私钥),勾选 Protected 和 Masked
5. 点击 Save variables 保存
## 📋 配置检查清单
- [ ] PROD_DB_HOST 已设置
- [ ] PROD_DB_PORT 已设置
- [ ] PROD_DB_USER 已设置
- [ ] PROD_DB_PASSWORD 已设置(已掩码)
- [ ] PROD_DB_NAME 已设置
- [ ] PROD_APP_URL 已设置
- [ ] PROD_SSH_HOST 已设置
- [ ] PROD_SSH_USER 已设置
- [ ] PROD_SSH_PRIVATE_KEY 已设置(已掩码)
- [ ] PROD_SSH_KNOWN_HOSTS 已设置
- [ ] 所有变量都已勾选 Protected
- [ ] 敏感变量已勾选 Masked
# GitLab CI/CD 环境变量配置指南
# GitLab CI/CD 环境变量配置指南
## 🔧 必需的环境变量配置
请在GitLab项目中进行以下配置:
### 1. 进入GitLab项目设置
- 登录GitLab
- 进入项目: https://code.jwsmed.com/ai-tools/customer-recall
- 点击 **Settings****CI/CD****Variables**
### 2. 添加以下环境变量
#### 数据库配置
| 变量名 | 值 | 说明 | 保护 | 掩码 |
|--------|----|----|----|----|
| PROD_DB_HOST | 您的生产数据库主机地址 | 数据库服务器IP或域名 | ✅ | ❌ |
| PROD_DB_PORT | 3306 | 数据库端口 | ✅ | ❌ |
| PROD_DB_USER | 您的数据库用户名 | 数据库用户名 | ✅ | ❌ |
| PROD_DB_PASSWORD | 您的数据库密码 | 数据库密码 | ✅ | ✅ |
| PROD_DB_NAME | callback_system | 数据库名称 | ✅ | ❌ |
#### 应用配置
| 变量名 | 值 | 说明 | 保护 | 掩码 |
|--------|----|----|----|----|
| PROD_APP_URL | http://您的域名:4002 | 生产环境应用URL | ✅ | ❌ |
| PROD_SSH_HOST | 您的生产服务器IP | 生产服务器地址 | ✅ | ❌ |
| PROD_SSH_USER | 您的SSH用户名 | SSH登录用户名 | ✅ | ❌ |
| PROD_SSH_PRIVATE_KEY | 见下方私钥内容 | SSH私钥 | ✅ | ✅ |
| PROD_SSH_KNOWN_HOSTS | 见下方说明 | SSH主机指纹 | ✅ | ❌ |
### 3. SSH私钥配置
将以下私钥内容复制到 PROD_SSH_PRIVATE_KEY 变量中:
```
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn
NhAAAAAwEAAQAAAgEA44gbzfOd6GJUpTlt7iITrJdiRXyaQM0Vmiun74HLFyIMu4DnpZxp
MVo9DoAj4eh08QEQYHVyMdg9KJScB2zL+Dn+OB43jy2E1Ij0g5iK0j+YO/TLL8bF4iiUDm
4LDAobG5+bF6M1ax/Eve7VUVRODvPnfhj4E7SzCXWInaxVNT4YH4p9TiqXmCg8//qWUu34
gpEsIJbrowKvBQZWEzLe6GVQHV/Qk4SQgY31yioUl2YA7IEO/r5KtFYkx2WfCh92PE1Wj2
lTUmC4yI5EMXGSYsNhlL88aomWIdV9+u9qsRvN89SCb8EtH8rQtgDHiR08wXZ3ltY6N/lD
vtfSTf91hPyD6sx8KFQ6EAmRwIAb7wIuUqRREFHTuyfIYiaqtNB/TyirSXWuDaFpF2tKoT
x6We52i7ceQKEGxwH8CHTMprQD7mL6JErpSBXNJgUzduhvxIAG3lw6ckFh+8+ZSmbdCX1b
Jo/OryHZC7TrqntQphV+j1EdhCQdduUPgwMVpNcthGw016+RwzXV+leOmWDBakMk4B23gU
v6r2S52MlJ72p3+HV7vVNX8UmRl/6RXtLf0594YJ0rVYxa5xNQdSjaEUz4tzvNjcgFiWjC
fMXXTyy4uDyjx8jCByxneXa4vyWz/4pfg7kpuZeprXMS0yu9A+rnA/AriAmVwtQeT/nkaE
8AAAdIjm4joI5uI6AAAAAHc3NoLXJzYQAAAgEA44gbzfOd6GJUpTlt7iITrJdiRXyaQM0V
miun74HLFyIMu4DnpZxpMVo9DoAj4eh08QEQYHVyMdg9KJScB2zL+Dn+OB43jy2E1Ij0g5
iK0j+YO/TLL8bF4iiUDm4LDAobG5+bF6M1ax/Eve7VUVRODvPnfhj4E7SzCXWInaxVNT4Y
H4p9TiqXmCg8//qWUu34gpEsIJbrowKvBQZWEzLe6GVQHV/Qk4SQgY31yioUl2YA7IEO/r
5KtFYkx2WfCh92PE1Wj2lTUmC4yI5EMXGSYsNhlL88aomWIdV9+u9qsRvN89SCb8EtH8rQ
tgDHiR08wXZ3ltY6N/lDvtfSTf91hPyD6sx8KFQ6EAmRwIAb7wIuUqRREFHTuyfIYiaqtN
B/TyirSXWuDaFpF2tKoTx6We52i7ceQKEGxwH8CHTMprQD7mL6JErpSBXNJgUzduhvxIAG
3lw6ckFh+8+ZSmbdCX1bJo/OryHZC7TrqntQphV+j1EdhCQdduUPgwMVpNcthGw016+Rwz
XV+leOmWDBakMk4B23gUv6r2S52MlJ72p3+HV7vVNX8UmRl/6RXtLf0594YJ0rVYxa5xNQ
dSjaEUz4tzvNjcgFiWjCfMXXTyy4uDyjx8jCByxneXa4vyWz/4pfg7kpuZeprXMS0yu9A+
rnA/AriAmVwtQeT/nkaE8AAAADAQABAAACAHtqbIp9xf0yuO8WA4bTfRB03J0MRS85Dqqd
W24SXPKjSXy7Ius1t+lJJS0kXFJBII1JInTvv41B2YqVcTylys1Nx5Lw8Pn8mrwdvWNT7p
i0XgLHeR7lFpjhoc1h6yQQpzuIizt7D5KXnMPZNGP08pIxwjMnoAgwT5yl4ACGZYGHuNYC
7IzllWy3Br9iUP+SjOVlkSXsNswovH5hPXcUdMxhh98nBZ++nBNpyRRrVtf4QDAIoPWUij
jfMPvnJyj6f8udt4H6g3N/ezttz5dyHxDrIZbpVAAFuSWJA9iE3L5Mcp37evTbN3qzLBpM
ue6pqTbW528trE6IKjLuJeig1EDUM3H7lhiIc2gybwuTXohGJdN2iDc4yo6jbfzp5jCcxQ
U+AK2zAppa05KU4fIVnhvxZwnd7ZNC++gvJSKoIxDbLB1GtaXqIgJn8CrDthOK+VOP8fdl
0RW8iDKJ+FkOQQwxjp+7X+dSZKBJdz5Ng3zH+5KhQ+8Xfsh5W26bE/SYl9Zm6abECp6Qqh
P5gkquez+c9da7jLYzcoULh91ZbxRwFksNyP94zQEuHQny5eVgZ0MRMJoKv4b7peE67SD/
t+HFZ4bD/zxB3Za/rodAqQZhG5Xq9My62WkVpj5c6xf/4m22a7esbIpZ3TgRTlfWUcl+aO
yWRyPm07DG62992fEBAAABAGLAQ9DvtAwrdRurhgSwOcWiSnHx1yd9oQ3/oDh8qsNPJieo
gwOEJB8AnIrxZpyJ14FAg064WfaoIMDUzL0toDXG1Z0nitcRLgEUpEfYAIvAf07iIed1uE
dQrc1+gbokc2N3SAgVtW2/h6caBHLQrgdHT3BvD0nXykQr2lr5HJllj+IzHJI2cDH9ESvR
Nq3av/nR9QH/Yd/Ier7rzTb+4iMZuIO1PJbyw4g4vawjdRnz8C+DRFQkQf1dxmSEkO8RGm
HoOFsODbF0BqPGK4DlPR99sTlKLrZVlIO5z3KDdu+NmhsZnf3P8CO3XOpooelynPK0qOWi
5BdRQDormH9k3UoAAAEBAPkWevZv4PAIALsIimuk21z3sLt66geo7DqvjMmCJA5DOpdZME
9m9GNpuN8KDGwM/pfLQ+ZKMJ66jQyVf6RJty5SrAywluNT0Ag3P6asFTbmAFI5wMaq/VOm
CrZT1xyylBp9fydPF/ksAOHpxjcMfRkIcwAwCZ/YPEfb3KGmPDZioSWz8QEfg49H5YwFL+
zk0bbS12FjMEFDmR/R4AeGY+u8+CLNlMVUDR3q8ELRpGuqegzvB+mFYv1K+T5y8tWSeMY0
7oZ4TamNrJhqjNBpZgDFYU+5EdRj8be4cQrXS0oUlcI4t1fQbHZ4PiZZILRCKJcHslxVwR
YLYjsF/tFOLm8AAAEBAOnYflUj12dV+fK8gB+C8orP1zLBXiM1Yl7RrgtbBAT+2lQmxqaq
GGzhSRziTmpHfosLwer9BCpm4MgbmMOQq0Owy4UxAUsQ/Fh2grNxdyzhNBTfeER3uUYgTx
s1lc88KBwC5Baa79YeM8WALesgkWmEz80QRhf5htWEter3Sh5TlH/p6od9jPitN07KOW1d
zhjiRMHzV7HmlbFTaYYEUP7tRi1gQfLkC9fHyCQHORNvg2VI04kl3O5u3iBZYD3XcV6g5g
lRNz0iKPB0AI6PiNQipW7BWPEu9R0AsrqvCQX6oXU8u8lz3o3wdoppJaD6Uz7/0bZ9pL6K
SzSAoqusVCEAAAARZGVwbG95bWVudEBnaXRsYWIBAg==
-----END OPENSSH PRIVATE KEY-----
```
### 4. SSH主机指纹获取
在生产服务器上运行以下命令获取主机指纹:
```bash
ssh-keyscan -H 您的生产服务器IP
```
将输出内容复制到 PROD_SSH_KNOWN_HOSTS 变量中。
### 5. 配置完成后
- 所有变量都应该勾选 **Protected**(保护)
- 密码和私钥应该勾选 **Masked**(掩码)
- 点击 **Save variables** 保存
## 🚀 开始部署
配置完成后,您可以:
1. 进入 **CI/CD****Pipelines**
2. 找到最新的pipeline
3. 点击 **deploy_production** 任务
4. 点击 **Play** 按钮开始部署
## 📞 需要帮助?
如果遇到问题,请检查:
1. 环境变量是否正确配置
2. SSH密钥是否正确添加
3. 生产服务器网络连接是否正常
-- 患者画像回访话术系统 - 初始数据库结构
-- 迁移版本: 001
-- 描述: 创建初始数据库表结构
-- 创建我们自己的迁移版本记录表
CREATE TABLE IF NOT EXISTS `schema_migrations` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`script_name` VARCHAR(255) NOT NULL UNIQUE,
`applied_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`description` TEXT,
`checksum` VARCHAR(64),
`execution_time_ms` INT DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 创建诊所表
CREATE TABLE IF NOT EXISTS `clinics` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`clinic_id` VARCHAR(50) NOT NULL UNIQUE,
`clinic_name` VARCHAR(100) NOT NULL,
`username` VARCHAR(50) NOT NULL,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 创建用户表
CREATE TABLE IF NOT EXISTS `users` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`username` VARCHAR(50) NOT NULL UNIQUE,
`password_hash` VARCHAR(255) NOT NULL,
`clinic_id` VARCHAR(50),
`clinic_name` VARCHAR(100),
`role` ENUM('admin', 'clinic') DEFAULT 'clinic',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (`clinic_id`) REFERENCES `clinics`(`clinic_id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 创建患者表
CREATE TABLE IF NOT EXISTS `patients` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`case_number` VARCHAR(50) NOT NULL UNIQUE,
`patient_name` VARCHAR(100),
`phone` VARCHAR(20),
`clinic_name` VARCHAR(100) NOT NULL,
`diagnosis` TEXT,
`treatment_plan` TEXT,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX `idx_case_number` (`case_number`),
INDEX `idx_clinic_name` (`clinic_name`),
INDEX `idx_phone` (`phone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 创建回访记录表
CREATE TABLE IF NOT EXISTS `callback_records` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`case_number` VARCHAR(50) NOT NULL,
`callback_date` DATE,
`callback_result` ENUM('成功', '不成功', '放弃回访') NOT NULL,
`callback_methods` JSON,
`callback_notes` TEXT,
`operator` VARCHAR(50),
`create_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`update_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (`case_number`) REFERENCES `patients`(`case_number`) ON DELETE CASCADE,
INDEX `idx_case_number` (`case_number`),
INDEX `idx_callback_date` (`callback_date`),
INDEX `idx_callback_result` (`callback_result`),
INDEX `idx_operator` (`operator`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 创建操作日志表
CREATE TABLE IF NOT EXISTS `operation_logs` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`user_id` INT,
`action` VARCHAR(100) NOT NULL,
`target_table` VARCHAR(50),
`target_id` VARCHAR(50),
`details` JSON,
`ip_address` VARCHAR(45),
`user_agent` TEXT,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE SET NULL,
INDEX `idx_user_id` (`user_id`),
INDEX `idx_action` (`action`),
INDEX `idx_created_at` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 插入默认诊所数据
INSERT IGNORE INTO `clinics` (`clinic_id`, `clinic_name`, `username`) VALUES
('clinic_xuexian', '学前街门诊', 'jinqin'),
('clinic_dafeng', '大丰门诊', 'chenlin'),
('clinic_dongting', '东亭门诊', 'dongting'),
('clinic_helai', '河埒门诊', 'helai'),
('clinic_hongdou', '红豆门诊', 'hongdou'),
('clinic_huishan', '惠山门诊', 'huishan'),
('clinic_mashan', '马山门诊', 'mashan'),
('clinic_hospital', '通善口腔医院', 'hospital'),
('clinic_xinwu', '新吴门诊', 'xinwu');
-- 插入默认管理员用户
INSERT IGNORE INTO `users` (`username`, `password_hash`, `clinic_id`, `clinic_name`, `role`) VALUES
('admin', '$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewdBPj4J/8KqKqKq', 'admin', '系统管理员', 'admin');
-- 记录此迁移脚本已执行
INSERT IGNORE INTO `schema_migrations` (`script_name`, `description`) VALUES
('001_create_initial_schema.sql', '创建初始数据库表结构');
\ No newline at end of file
-- 患者画像回访话术系统 - 数据迁移
-- 迁移版本: 002
-- 描述: 从JSON文件重建患者数据,确保数据一致性
-- 清空现有患者数据(保留回访记录)
DELETE FROM patients WHERE 1=1;
-- 从诊所患者JSON文件重建患者数据
-- 注意:这个脚本需要在应用运行时执行,因为需要读取JSON文件
-- 实际的数据重建逻辑在Python代码中实现
-- 记录此迁移脚本已执行
INSERT IGNORE INTO `schema_migrations` (`script_name`, `description`) VALUES
('002_migrate_existing_data.sql', '从JSON文件重建患者数据');
\ No newline at end of file
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDjiBvN853oYlSlOW3uIhOsl2JFfJpAzRWaK6fvgcsXIgy7gOelnGkxWj0OgCPh6HTxARBgdXIx2D0olJwHbMv4Of44HjePLYTUiPSDmIrSP5g79MsvxsXiKJQObgsMChsbn5sXozVrH8S97tVRVE4O8+d+GPgTtLMJdYidrFU1Phgfin1OKpeYKDz/+pZS7fiCkSwgluujAq8FBlYTMt7oZVAdX9CThJCBjfXKKhSXZgDsgQ7+vkq0ViTHZZ8KH3Y8TVaPaVNSYLjIjkQxcZJiw2GUvzxqiZYh1X3672qxG83z1IJvwS0fytC2AMeJHTzBdneW1jo3+UO+19JN/3WE/IPqzHwoVDoQCZHAgBvvAi5SpFEQUdO7J8hiJqq00H9PKKtJda4NoWkXa0qhPHpZ7naLtx5AoQbHAfwIdMymtAPuYvokSulIFc0mBTN26G/EgAbeXDpyQWH7z5lKZt0JfVsmj86vIdkLtOuqe1CmFX6PUR2EJB125Q+DAxWk1y2EbDTXr5HDNdX6V46ZYMFqQyTgHbeBS/qvZLnYyUnvanf4dXu9U1fxSZGX/pFe0t/Tn3hgnStVjFrnE1B1KNoRTPi3O82NyAWJaMJ8xddPLLi4PKPHyMIHLGd5dri/JbP/il+DuSm5l6mtcxLTK70D6ucD8CuICZXC1B5P+eRoTw== deployment@gitlab
#!/usr/bin/env python3
"""
生成SSH密钥对的脚本
用于GitLab CI/CD部署
"""
import os
import subprocess
import sys
def generate_ssh_keys():
"""生成SSH密钥对"""
try:
# 检查是否已存在密钥
if os.path.exists('deploy_key') and os.path.exists('deploy_key.pub'):
print("SSH密钥已存在,跳过生成...")
return True
print("正在生成SSH密钥对...")
# 使用subprocess生成密钥(无密码)
result = subprocess.run([
'ssh-keygen', '-t', 'rsa', '-b', '4096',
'-C', 'deployment@gitlab',
'-f', 'deploy_key',
'-N', ''
], capture_output=True, text=True)
if result.returncode == 0:
print("✅ SSH密钥生成成功!")
print(f"私钥文件: {os.path.abspath('deploy_key')}")
print(f"公钥文件: {os.path.abspath('deploy_key.pub')}")
return True
else:
print(f"❌ SSH密钥生成失败: {result.stderr}")
return False
except Exception as e:
print(f"❌ 生成SSH密钥时出错: {e}")
return False
def show_public_key():
"""显示公钥内容"""
try:
if os.path.exists('deploy_key.pub'):
with open('deploy_key.pub', 'r') as f:
public_key = f.read().strip()
print("\n📋 公钥内容(需要添加到生产服务器):")
print("=" * 50)
print(public_key)
print("=" * 50)
return public_key
else:
print("❌ 公钥文件不存在")
return None
except Exception as e:
print(f"❌ 读取公钥时出错: {e}")
return None
def create_gitlab_config_guide():
"""创建GitLab配置指南"""
guide_content = """# GitLab CI/CD 环境变量配置指南
## 🔧 必需的环境变量配置
请在GitLab项目中进行以下配置:
### 1. 进入GitLab项目设置
- 登录GitLab
- 进入项目: https://code.jwsmed.com/ai-tools/customer-recall
- 点击 **Settings** → **CI/CD** → **Variables**
### 2. 添加以下环境变量
#### 数据库配置
| 变量名 | 值 | 说明 | 保护 | 掩码 |
|--------|----|----|----|----|
| PROD_DB_HOST | 您的生产数据库主机地址 | 数据库服务器IP或域名 | ✅ | ❌ |
| PROD_DB_PORT | 3306 | 数据库端口 | ✅ | ❌ |
| PROD_DB_USER | 您的数据库用户名 | 数据库用户名 | ✅ | ❌ |
| PROD_DB_PASSWORD | 您的数据库密码 | 数据库密码 | ✅ | ✅ |
| PROD_DB_NAME | callback_system | 数据库名称 | ✅ | ❌ |
#### 应用配置
| 变量名 | 值 | 说明 | 保护 | 掩码 |
|--------|----|----|----|----|
| PROD_APP_URL | http://您的域名:4002 | 生产环境应用URL | ✅ | ❌ |
| PROD_SSH_HOST | 您的生产服务器IP | 生产服务器地址 | ✅ | ❌ |
| PROD_SSH_USER | 您的SSH用户名 | SSH登录用户名 | ✅ | ❌ |
| PROD_SSH_PRIVATE_KEY | 见下方私钥内容 | SSH私钥 | ✅ | ✅ |
| PROD_SSH_KNOWN_HOSTS | 见下方说明 | SSH主机指纹 | ✅ | ❌ |
### 3. SSH私钥配置
将以下私钥内容复制到 PROD_SSH_PRIVATE_KEY 变量中:
```
{private_key}
```
### 4. SSH主机指纹获取
在生产服务器上运行以下命令获取主机指纹:
```bash
ssh-keyscan -H 您的生产服务器IP
```
将输出内容复制到 PROD_SSH_KNOWN_HOSTS 变量中。
### 5. 配置完成后
- 所有变量都应该勾选 **Protected**(保护)
- 密码和私钥应该勾选 **Masked**(掩码)
- 点击 **Save variables** 保存
## 🚀 开始部署
配置完成后,您可以:
1. 进入 **CI/CD** → **Pipelines**
2. 找到最新的pipeline
3. 点击 **deploy_production** 任务
4. 点击 **Play** 按钮开始部署
## 📞 需要帮助?
如果遇到问题,请检查:
1. 环境变量是否正确配置
2. SSH密钥是否正确添加
3. 生产服务器网络连接是否正常
"""
try:
# 读取私钥内容
private_key = ""
if os.path.exists('deploy_key'):
with open('deploy_key', 'r') as f:
private_key = f.read()
# 替换模板中的私钥
guide_content = guide_content.replace('{private_key}', private_key)
# 写入文件
with open('GitLab配置指南.md', 'w', encoding='utf-8') as f:
f.write(guide_content)
print("✅ GitLab配置指南已创建: GitLab配置指南.md")
return True
except Exception as e:
print(f"❌ 创建配置指南时出错: {e}")
return False
def main():
"""主函数"""
print("🔑 SSH密钥生成和GitLab配置准备工具")
print("=" * 50)
# 生成SSH密钥
if not generate_ssh_keys():
print("❌ 无法继续,SSH密钥生成失败")
sys.exit(1)
# 显示公钥
public_key = show_public_key()
if not public_key:
print("❌ 无法读取公钥")
sys.exit(1)
# 创建GitLab配置指南
if create_gitlab_config_guide():
print("\n🎉 配置准备完成!")
print("\n📋 下一步操作:")
print("1. 将公钥添加到生产服务器")
print("2. 按照 'GitLab配置指南.md' 配置GitLab环境变量")
print("3. 在GitLab中手动触发部署任务")
else:
print("❌ 配置指南创建失败")
if __name__ == "__main__":
main()
\ No newline at end of file
#!/bin/sh
# 患者画像回访话术系统 - 数据库迁移脚本
# 核心思想:通过记录已执行的脚本来避免重复执行
# 当任何命令失败时,立即退出脚本
set -e
# 数据库连接信息 (从环境变量获取,更灵活)
DB_HOST="${DB_HOST:-mysql}"
DB_USER="${DB_USER:-callback_user}"
DB_PASS="${DB_PASSWORD:-dev_password_123}"
DB_NAME="${DB_NAME:-callback_system}"
MIGRATIONS_DIR="/migrations"
# 构造 MySQL 客户端命令
MYSQL_CMD="mysql -h${DB_HOST} -u${DB_USER} -p${DB_PASS} ${DB_NAME}"
echo "=========================================="
echo "开始数据库迁移过程..."
echo "数据库主机: ${DB_HOST}"
echo "数据库名称: ${DB_NAME}"
echo "迁移目录: ${MIGRATIONS_DIR}"
echo "=========================================="
# 检查数据库连接
echo "检查数据库连接..."
if ! $MYSQL_CMD -e "SELECT 1;" > /dev/null 2>&1; then
echo "❌ 无法连接到数据库,请检查连接信息"
exit 1
fi
echo "✅ 数据库连接成功"
# 检查迁移目录是否存在
if [ ! -d "$MIGRATIONS_DIR" ]; then
echo "❌ 迁移目录不存在: ${MIGRATIONS_DIR}"
exit 1
fi
# 确保schema_migrations表存在
echo "检查版本记录表..."
$MYSQL_CMD -e "
CREATE TABLE IF NOT EXISTS \`schema_migrations\` (
\`id\` INT AUTO_INCREMENT PRIMARY KEY,
\`script_name\` VARCHAR(255) NOT NULL UNIQUE,
\`applied_at\` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
\`description\` TEXT,
\`checksum\` VARCHAR(64),
\`execution_time_ms\` INT DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
"
# 遍历迁移目录中所有 .sql 文件,按数字顺序
# ls -v 会进行自然排序,确保 002 在 010 之前
echo "查找迁移脚本..."
MIGRATION_FILES=$(ls -v ${MIGRATIONS_DIR}/*.sql 2>/dev/null || echo "")
if [ -z "$MIGRATION_FILES" ]; then
echo "⚠️ 没有找到迁移脚本文件"
exit 0
fi
echo "找到以下迁移脚本:"
echo "$MIGRATION_FILES" | sed 's/^/ /'
# 执行迁移
for file in $MIGRATION_FILES; do
# 从完整路径中提取文件名
filename=$(basename "$file")
echo ""
echo "检查迁移脚本: ${filename}"
# 检查这个脚本是否已经被执行过
# -N 表示无列头, -s 表示静默模式
is_applied=$($MYSQL_CMD -N -s -e "SELECT COUNT(*) FROM schema_migrations WHERE script_name = '${filename}';" 2>/dev/null || echo "0")
if [ "$is_applied" -eq 0 ]; then
echo "🔄 执行迁移脚本: ${filename}"
# 记录开始时间
start_time=$(date +%s%3N)
# 执行 SQL 脚本
if $MYSQL_CMD < "$file"; then
# 计算执行时间
end_time=$(date +%s%3N)
execution_time=$((end_time - start_time))
# 将脚本文件名记录到版本表中
$MYSQL_CMD -e "INSERT INTO schema_migrations (script_name, description, execution_time_ms) VALUES ('${filename}', '自动执行', ${execution_time});"
echo "✅ ${filename} 执行成功 (耗时: ${execution_time}ms)"
else
echo "❌ ${filename} 执行失败"
exit 1
fi
else
echo "⏭️ 跳过已执行的迁移脚本: ${filename}"
fi
done
echo ""
echo "=========================================="
echo "数据库迁移过程完成!"
echo "=========================================="
# 显示迁移状态
echo ""
echo "当前迁移状态:"
$MYSQL_CMD -e "SELECT script_name, description, applied_at, execution_time_ms FROM schema_migrations ORDER BY applied_at;" 2>/dev/null || echo "无法查询迁移状态"
\ No newline at end of file
#!/usr/bin/env python3
#!/usr/bin/env python3
"""
一键配置GitLab CI/CD部署环境
自动化配置过程,减少手动操作
"""
import os
import json
import webbrowser
import subprocess
import sys
def create_environment_variables_template():
"""创建环境变量模板文件"""
template = {
"数据库配置": {
"PROD_DB_HOST": "您的生产数据库主机地址",
"PROD_DB_PORT": "3306",
"PROD_DB_USER": "您的数据库用户名",
"PROD_DB_PASSWORD": "您的数据库密码",
"PROD_DB_NAME": "callback_system"
},
"应用配置": {
"PROD_APP_URL": "http://您的域名:4002",
"PROD_SSH_HOST": "您的生产服务器IP",
"PROD_SSH_USER": "您的SSH用户名",
"PROD_SSH_PRIVATE_KEY": "见下方私钥内容",
"PROD_SSH_KNOWN_HOSTS": "见下方说明"
}
}
# 读取私钥内容
private_key = ""
if os.path.exists('deploy_key'):
with open('deploy_key', 'r') as f:
private_key = f.read()
# 创建配置说明
config_content = f"""# GitLab CI/CD 环境变量配置模板
## 🔧 环境变量配置
请将以下内容复制到GitLab项目的环境变量中:
### 数据库配置
| 变量名 | 值 | 说明 | 保护 | 掩码 |
|--------|----|----|----|----|
| PROD_DB_HOST | 您的生产数据库主机地址 | 数据库服务器IP或域名 | ✅ | ❌ |
| PROD_DB_PORT | 3306 | 数据库端口 | ✅ | ❌ |
| PROD_DB_USER | 您的数据库用户名 | 数据库用户名 | ✅ | ❌ |
| PROD_DB_PASSWORD | 您的数据库密码 | 数据库密码 | ✅ | ✅ |
| PROD_DB_NAME | callback_system | 数据库名称 | ✅ | ❌ |
### 应用配置
| 变量名 | 值 | 说明 | 保护 | 掩码 |
|--------|----|----|----|----|
| PROD_APP_URL | http://您的域名:4002 | 生产环境应用URL | ✅ | ❌ |
| PROD_SSH_HOST | 您的生产服务器IP | 生产服务器地址 | ✅ | ❌ |
| PROD_SSH_USER | 您的SSH用户名 | SSH登录用户名 | ✅ | ❌ |
| PROD_SSH_PRIVATE_KEY | 见下方私钥内容 | SSH私钥 | ✅ | ✅ |
| PROD_SSH_KNOWN_HOSTS | 见下方说明 | SSH主机指纹 | ✅ | ❌ |
### SSH私钥内容
将以下内容复制到 PROD_SSH_PRIVATE_KEY 变量中:
```
{private_key}
```
### SSH主机指纹获取
在生产服务器上运行以下命令获取主机指纹:
```bash
ssh-keyscan -H 您的生产服务器IP
```
将输出内容复制到 PROD_SSH_KNOWN_HOSTS 变量中。
## 🚀 配置步骤
1. 登录GitLab: https://code.jwsmed.com/ai-tools/customer-recall
2. 进入 Settings → CI/CD → Variables
3. 点击 Add Variable 添加上述变量
4. 对于敏感信息(密码、私钥),勾选 Protected 和 Masked
5. 点击 Save variables 保存
## 📋 配置检查清单
- [ ] PROD_DB_HOST 已设置
- [ ] PROD_DB_PORT 已设置
- [ ] PROD_DB_USER 已设置
- [ ] PROD_DB_PASSWORD 已设置(已掩码)
- [ ] PROD_DB_NAME 已设置
- [ ] PROD_APP_URL 已设置
- [ ] PROD_SSH_HOST 已设置
- [ ] PROD_SSH_USER 已设置
- [ ] PROD_SSH_PRIVATE_KEY 已设置(已掩码)
- [ ] PROD_SSH_KNOWN_HOSTS 已设置
- [ ] 所有变量都已勾选 Protected
- [ ] 敏感变量已勾选 Masked
"""
with open('GitLab环境变量配置.md', 'w', encoding='utf-8') as f:
f.write(config_content)
print("✅ GitLab环境变量配置模板已创建")
return True
def create_deployment_checklist():
"""创建部署检查清单"""
checklist_content = """# 🚀 生产环境部署检查清单
## 📋 部署前检查
### 1. 环境变量配置 ✅
- [ ] GitLab环境变量已配置完成
- [ ] 数据库连接信息正确
- [ ] SSH密钥已配置
- [ ] 生产服务器信息正确
### 2. 生产服务器准备 ✅
- [ ] 生产服务器可访问
- [ ] SSH连接正常
- [ ] 磁盘空间充足(备份需要)
- [ ] Docker环境已安装
### 3. 数据库准备 ✅
- [ ] 生产数据库可连接
- [ ] 数据库用户权限正确
- [ ] 数据库版本兼容(MySQL 8.0+)
### 4. 网络环境 ✅
- [ ] 生产服务器网络正常
- [ ] 防火墙配置正确
- [ ] 端口4002可访问
## 🚀 部署执行步骤
### 第一步:触发部署
1. 进入GitLab项目: https://code.jwsmed.com/ai-tools/customer-recall
2. 点击 **CI/CD** → **Pipelines**
3. 找到最新的pipeline
4. 点击 **deploy_production** 任务
5. 点击 **Play** 按钮开始部署
### 第二步:监控部署过程
部署过程中会执行以下步骤:
- [ ] 数据库备份
- [ ] 代码部署
- [ ] 依赖更新
- [ ] 应用重启
- [ ] 健康检查
### 第三步:验证部署结果
- [ ] 应用健康状态检查
- [ ] 数据库连接验证
- [ ] 导出功能测试
- [ ] 马山门诊数据验证
## 🔄 回滚计划
如果部署失败:
1. 在GitLab CI/CD界面点击 **rollback_production**
2. 系统自动回滚到上一个版本
3. 检查回滚后的应用状态
## 📞 紧急联系
如遇紧急情况:
- 检查GitLab CI/CD日志
- 查看生产服务器日志
- 联系系统管理员
## 🎯 成功标准
部署成功的标志:
- [ ] 应用健康检查通过
- [ ] 数据库连接正常
- [ ] 导出功能正常
- [ ] 马山门诊数据显示正确
- [ ] 所有门诊数据统计准确
"""
with open('部署检查清单.md', 'w', encoding='utf-8') as f:
f.write(checklist_content)
print("✅ 部署检查清单已创建")
return True
def open_gitlab_project():
"""打开GitLab项目页面"""
gitlab_url = "https://code.jwsmed.com/ai-tools/customer-recall"
print(f"🌐 正在打开GitLab项目页面: {gitlab_url}")
try:
webbrowser.open(gitlab_url)
print("✅ 已打开GitLab项目页面")
return True
except Exception as e:
print(f"❌ 无法打开浏览器: {e}")
print(f"请手动访问: {gitlab_url}")
return False
def show_next_steps():
"""显示下一步操作指南"""
print("\n" + "="*60)
print("🎉 配置准备完成!")
print("="*60)
print("\n📋 已创建的文件:")
print("✅ deploy_key - SSH私钥文件")
print("✅ deploy_key.pub - SSH公钥文件")
print("✅ GitLab环境变量配置.md - 环境变量配置指南")
print("✅ 部署检查清单.md - 部署步骤检查清单")
print("\n🚀 下一步操作:")
print("1. 将公钥添加到生产服务器")
print("2. 按照 'GitLab环境变量配置.md' 配置GitLab环境变量")
print("3. 使用 '部署检查清单.md' 检查部署准备")
print("4. 在GitLab中手动触发部署任务")
print("\n💡 提示:")
print("- 所有敏感信息都应该勾选 'Protected' 和 'Masked'")
print("- 部署前请确保生产服务器准备就绪")
print("- 建议在业务低峰期进行部署")
def main():
"""主函数"""
print("🔧 GitLab CI/CD 一键配置工具")
print("="*50)
# 检查SSH密钥是否存在
if not os.path.exists('deploy_key') or not os.path.exists('deploy_key.pub'):
print("❌ SSH密钥文件不存在,请先运行 generate_ssh_keys.py")
sys.exit(1)
print("📝 正在创建配置文件和指南...")
# 创建环境变量配置模板
if not create_environment_variables_template():
print("❌ 环境变量配置模板创建失败")
sys.exit(1)
# 创建部署检查清单
if not create_deployment_checklist():
print("❌ 部署检查清单创建失败")
sys.exit(1)
# 显示下一步操作
show_next_steps()
# 询问是否打开GitLab项目页面
try:
choice = input("\n是否现在打开GitLab项目页面?(y/n): ").lower().strip()
if choice in ['y', 'yes', '是']:
open_gitlab_project()
except KeyboardInterrupt:
print("\n\n👋 配置完成!请按照指南进行后续操作。")
if __name__ == "__main__":
main()
\ No newline at end of file
# 🚀 生产环境部署检查清单
# 🚀 生产环境部署检查清单
## 📋 部署前检查
### 1. 环境变量配置 ✅
- [ ] GitLab环境变量已配置完成
- [ ] 数据库连接信息正确
- [ ] SSH密钥已配置
- [ ] 生产服务器信息正确
### 2. 生产服务器准备 ✅
- [ ] 生产服务器可访问
- [ ] SSH连接正常
- [ ] 磁盘空间充足(备份需要)
- [ ] Docker环境已安装
### 3. 数据库准备 ✅
- [ ] 生产数据库可连接
- [ ] 数据库用户权限正确
- [ ] 数据库版本兼容(MySQL 8.0+)
### 4. 网络环境 ✅
- [ ] 生产服务器网络正常
- [ ] 防火墙配置正确
- [ ] 端口4002可访问
## 🚀 部署执行步骤
### 第一步:触发部署
1. 进入GitLab项目: https://code.jwsmed.com/ai-tools/customer-recall
2. 点击 **CI/CD****Pipelines**
3. 找到最新的pipeline
4. 点击 **deploy_production** 任务
5. 点击 **Play** 按钮开始部署
### 第二步:监控部署过程
部署过程中会执行以下步骤:
- [ ] 数据库备份
- [ ] 代码部署
- [ ] 依赖更新
- [ ] 应用重启
- [ ] 健康检查
### 第三步:验证部署结果
- [ ] 应用健康状态检查
- [ ] 数据库连接验证
- [ ] 导出功能测试
- [ ] 马山门诊数据验证
## 🔄 回滚计划
如果部署失败:
1. 在GitLab CI/CD界面点击 **rollback_production**
2. 系统自动回滚到上一个版本
3. 检查回滚后的应用状态
## 📞 紧急联系
如遇紧急情况:
- 检查GitLab CI/CD日志
- 查看生产服务器日志
- 联系系统管理员
## 🎯 成功标准
部署成功的标志:
- [ ] 应用健康检查通过
- [ ] 数据库连接正常
- [ ] 导出功能正常
- [ ] 马山门诊数据显示正确
- [ ] 所有门诊数据统计准确
# 🎉 GitLab CI/CD 自动部署准备完成!
# 🎉 GitLab CI/CD 自动部署准备完成!
## 📋 已完成的工作
### ✅ 1. 代码准备
- [x] 修复马山门诊数据导出问题
- [x] 完善Excel导出逻辑(去重患者统计、最新状态)
- [x] 优化数据库连接配置
- [x] 清理测试数据和孤立记录
- [x] 代码已提交到Git仓库并打标签 v1.2.0
### ✅ 2. 部署脚本准备
- [x] 创建自动化部署脚本 `deploy.sh`
- [x] 创建数据库迁移脚本 `migrate_database.sql`
- [x] 创建部署验证脚本 `verify_deployment.py`
- [x] 完善GitLab CI/CD配置 `.gitlab-ci.yml`
### ✅ 3. SSH密钥准备
- [x] 生成部署专用SSH密钥对
- [x] 私钥文件:`deploy_key`
- [x] 公钥文件:`deploy_key.pub`
### ✅ 4. 配置指南准备
- [x] `GitLab环境变量配置.md` - 详细的环境变量配置指南
- [x] `部署检查清单.md` - 完整的部署步骤检查清单
- [x] `一键配置GitLab.py` - 自动化配置工具
## 🚀 下一步操作
### 第一步:配置生产服务器SSH访问
将公钥添加到生产服务器:
```bash
# 在生产服务器上执行
cat deploy_key.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
```
### 第二步:配置GitLab环境变量
1. 登录GitLab: https://code.jwsmed.com/ai-tools/customer-recall
2. 进入 **Settings****CI/CD****Variables**
3. 按照 `GitLab环境变量配置.md` 添加所有必需变量
4. 确保敏感信息勾选 **Protected****Masked**
### 第三步:获取SSH主机指纹
在生产服务器上运行:
```bash
ssh-keyscan -H 您的生产服务器IP
```
将输出内容复制到 `PROD_SSH_KNOWN_HOSTS` 变量中。
### 第四步:触发部署
1. 进入GitLab **CI/CD****Pipelines**
2. 找到最新的pipeline
3. 点击 **deploy_production** 任务
4. 点击 **Play** 按钮开始部署
## 🔧 必需的环境变量
### 数据库配置
| 变量名 | 说明 |
|--------|------|
| PROD_DB_HOST | 生产数据库主机地址 |
| PROD_DB_PORT | 数据库端口(通常3306) |
| PROD_DB_USER | 数据库用户名 |
| PROD_DB_PASSWORD | 数据库密码 |
| PROD_DB_NAME | 数据库名称(callback_system) |
### 应用配置
| 变量名 | 说明 |
|--------|------|
| PROD_APP_URL | 生产环境应用URL |
| PROD_SSH_HOST | 生产服务器IP地址 |
| PROD_SSH_USER | SSH登录用户名 |
| PROD_SSH_PRIVATE_KEY | SSH私钥内容 |
| PROD_SSH_KNOWN_HOSTS | SSH主机指纹 |
## 📊 部署过程监控
部署过程中,系统会自动执行:
1. **数据库备份** - 使用 `mysqldump` 备份生产数据库
2. **代码部署** - 上传并执行部署脚本
3. **依赖更新** - 更新Python依赖包
4. **应用重启** - 重启Docker容器
5. **健康检查** - 验证应用状态和功能
## 🔄 回滚机制
如果部署失败:
1. 在GitLab CI/CD界面点击 **rollback_production**
2. 系统自动回滚到上一个版本
3. 恢复数据库备份(如需要)
## ⚠️ 重要提醒
### 部署时间
- **建议时间**:晚上8点后或周末凌晨
- **避免时间**:工作日上班时间、月初月末
### 安全配置
- 所有环境变量必须勾选 **Protected**
- 密码和私钥必须勾选 **Masked**
- 定期更新SSH密钥
### 数据安全
- 部署前会自动备份数据库
- 建议手动备份重要数据
- 测试环境验证后再部署生产
## 📞 技术支持
如遇问题:
1. 检查GitLab CI/CD日志
2. 查看生产服务器日志
3. 使用部署验证脚本检查
4. 参考 `部署检查清单.md`
## 🎯 成功标准
部署成功的标志:
- [ ] 应用健康检查通过
- [ ] 数据库连接正常
- [ ] 导出功能正常
- [ ] 马山门诊数据显示正确
- [ ] 所有门诊数据统计准确
---
**🎉 恭喜!您的自动部署环境已经准备就绪!**
现在您可以:
1. 按照指南配置GitLab环境变量
2. 在合适的时间触发部署
3. 享受自动化部署带来的便利
祝您部署顺利! 🚀
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment