30秒安装一套MySQL数据库,支持远程数据库一键安装和一键备份!这个数据库运维平台,源码公布!
http://192.168.1.5:5000/添加了备份MySQL的功能
通过平台,先一键安装一套新的测试MySQL,耗时不到30秒。
不到30秒安装完成
Mysql root默认密码: MyNewPass!123
[root@cjc-db-03 ~]# systemctl status mysqld.service●mysqld.service - MySQL ServerLoaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)Active: active (running) since Fri 2025-06-27 17:18:24 CST; 2min 55s agoDocs: man:mysqld(8)http://dev.mysql.com/doc/refman/en/using-systemd.htmlProcess: 5776 ExecStartPre=/usr/bin/mysqld_pre_systemd (code=exited, status=0/SUCCESS)Main PID: 5804 (mysqld)Status: "Server is operational"CGroup: /system.slice/mysqld.service└─5804 /usr/sbin/mysqldJun 27 17:18:22 cjc-db-03 systemd[1]: Starting MySQL Server...Jun 27 17:18:24 cjc-db-03 systemd[1]: Started MySQL Server.
创建测试用户
mysql> select version();+-----------+| version() |+-----------+| 8.0.42|+-----------+1 row in set (0.00 sec)mysql> create user cjc@'%' identified with mysql_native_password by "MyNewPass!123";Query OK, 0 rows affected (0.00 sec)mysql> grant all privileges on *.* to cjc@'%';Query OK, 0 rows affected (0.00 sec)mysql> flush privileges;Query OK, 0 rows affected (0.00 sec)
创建测试数据
mysql> use cjc;Database changedmysql> create table t1 as select * from information_schema.processlist;Query OK, 2 rows affected, 1 warning (0.02 sec)Records: 2Duplicates: 0Warnings: 1mysql> create table t2 as select * from mysql.user;Query OK, 5 rows affected (0.02 sec)Records: 5Duplicates: 0Warnings: 0mysql> create table t3 as select * from mysql.plugin;Query OK, 0 rows affected (0.01 sec)Records: 0Duplicates: 0Warnings: 0
通过平台,一键备份
执行备份
备份成功
检查备份文件
[cjc@cjc-db-02 backups]$ ls -lrthtotal 24K-rw-rw-r-- 1 cjc cjc 2.4K Jun 27 17:52 backup_cjc_t1_20250627_175241.sql-rw-rw-r-- 1 cjc cjc 7.8K Jun 27 17:52 backup_cjc_t2_20250627_175241.sql-rw-rw-r-- 1 cjc cjc 2.4K Jun 27 18:03 backup_cjc_t1_20250627_180329.sql-rw-rw-r-- 1 cjc cjc 7.8K Jun 27 18:03 backup_cjc_t2_20250627_180329.sql[cjc@cjc-db-02 backups]$ more backup_cjc_t1_20250627_180329.sql……
架构介绍
~/script_runner/├── app.py # Flask 主应用├── tasks.db # SQLite 数据库├── backups/ # 备份文件存储目录├── scripts/ # MySQL 安装脚本│ ├── install_deps.sh│ ├── download_mysql.sh│ ├── setup_mysql.sh│ ├── configure_repl.sh│ └── start_service.sh└── templates/ # HTML 模板├── index.html # 安装页面└── backup.html # 备份页面
详细代码如下:
app.py
[cjc@cjc-db-02 script_runner]$ cat app.pyfrom flask import Flask, render_template, requestimport sqlite3import paramikoimport osimport timefrom datetime import datetimeapp = Flask(__name__)# 配置BASE_DIR = os.path.dirname(os.path.abspath(__file__))SCRIPTS_DIR = os.path.join(BASE_DIR, "scripts")DB_PATH = os.path.join(BASE_DIR, "tasks.db")# 初始化数据库def init_db():conn = sqlite3.connect(DB_PATH)c = conn.cursor()c.execute('''CREATE TABLE IF NOT EXISTS execution_logs (id INTEGER PRIMARY KEY AUTOINCREMENT,host TEXT NOT NULL,script_name TEXT NOT NULL,output TEXT,start_time TIMESTAMP,end_time TIMESTAMP,task_type TEXT)''')conn.commit()conn.close()# 执行远程脚本def execute_remote_script(host, username, password, script_name):log_output = ""start_time = datetime.now()try:# 连接SSHssh = paramiko.SSHClient()ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())ssh.connect(host, username=username, password=password, timeout=10)# 上传脚本local_script = os.path.join(SCRIPTS_DIR, script_name)remote_script = f"/tmp/{script_name}"sftp = ssh.open_sftp()sftp.put(local_script, remote_script)sftp.chmod(remote_script, 0o755) # 设置可执行权限sftp.close()# 执行脚本log_output += f"开始执行脚本: {script_name}\n"command = f"bash {remote_script}"stdin, stdout, stderr = ssh.exec_command(command)# 获取输出stdout_output = stdout.read().decode('utf-8')stderr_output = stderr.read().decode('utf-8')log_output += stdout_outputif stderr_output:log_output += "\n错误输出:\n" + stderr_output# 清理临时文件ssh.exec_command(f"rm -f {remote_script}")log_output += f"\n脚本执行完成: {script_name}\n"status = "success"except Exception as e:log_output += f"\n执行脚本时出错: {str(e)}\n"status = "failed"finally:end_time = datetime.now()ssh.close() if 'ssh' in locals() else None# 保存日志到数据库save_log_to_db(host, script_name, log_output, start_time, end_time)return log_output# 保存日志到数据库def save_log_to_db(host, script_name, output, start_time, end_time):conn = sqlite3.connect(DB_PATH)c = conn.cursor()c.execute('''INSERT INTO execution_logs(host, script_name, output, start_time, end_time)VALUES (?, ?, ?, ?, ?)''',(host, script_name, output, start_time, end_time))conn.commit()conn.close()# app.py 中新增函数def perform_mysql_backup(ssh_host, ssh_user, ssh_pass,db_host, db_port, db_name, tables, db_user, db_pass):"""执行MySQL备份操作"""log_output = ""start_time = datetime.now()try:# 连接SSHssh = paramiko.SSHClient()ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())ssh.connect(ssh_host, username=ssh_user, password=ssh_pass, timeout=10)# 创建备份文件名timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")backup_dir = os.path.join(BASE_DIR, "backups")os.makedirs(backup_dir, exist_ok=True)# 处理表名table_list = [t.strip() for t in tables.split(",")]backup_files = [] # 存储成功备份的文件名# 执行备份for table in table_list:backup_file = f"backup_{db_name}_{table}_{timestamp}.sql"local_path = os.path.join(backup_dir, backup_file)# 构建mysqldump命令dump_cmd = (f"mysqldump -h{db_host} -P{db_port} -u{db_user} -p'{db_pass}' "f"{db_name}{table} > /tmp/{backup_file}")log_output += f"备份表: {table}...\n"# 执行备份命令stdin, stdout, stderr = ssh.exec_command(dump_cmd)# 获取输出stdout_output = stdout.read().decode('utf-8')stderr_output = stderr.read().decode('utf-8')# 检查是否有真正的错误(忽略安全警告)if stderr_output and "Warning" not in stderr_output:# 有真正的错误log_output += f"备份错误: {stderr_output}\n"raise Exception(f"备份表 {table} 失败")# 下载备份文件sftp = ssh.open_sftp()sftp.get(f"/tmp/{backup_file}", local_path)sftp.remove(f"/tmp/{backup_file}") # 清理临时文件sftp.close()log_output += f"成功备份到: {local_path}\n"backup_files.append(backup_file)status = "success"except Exception as e:log_output += f"\n备份过程中出错: {str(e)}\n"status = "failed"backup_files = []finally:end_time = datetime.now()ssh.close() if 'ssh' in locals() else None# 保存日志到数据库save_backup_log(ssh_host, db_name, tables, log_output, start_time, end_time, status)return log_output, backup_filesdef save_backup_log(host, db_name, tables, output, start_time, end_time, status):"""保存备份日志到数据库"""conn = sqlite3.connect(DB_PATH)c = conn.cursor()c.execute('''INSERT INTO execution_logs(host, script_name, output, start_time, end_time, task_type)VALUES (?, ?, ?, ?, ?, ?)''',(host, f"backup_{db_name}", output, start_time, end_time, "backup"))conn.commit()conn.close()# 路由定义@app.route('/')def index():return render_template('index.html', logs="请填写信息并执行脚本")# 新增:备份页面路由@app.route('/backup')def backup_page():return render_template('backup.html', logs="请填写信息并执行备份")@app.route('/execute', methods=['POST'])def execute_scripts():host = request.form['host']username = request.form['username']password = request.form['password']scripts = request.form.getlist('scripts')if not scripts:return render_template('index.html', logs="错误:未选择任何脚本!")full_log = f"===== 开始执行MySQL安装任务 =====\n"full_log += f"目标主机: {host}\n"full_log += f"执行时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"full_log += f"将执行 {len(scripts)} 个脚本\n\n"for script in scripts:script_log = execute_remote_script(host, username, password, script)full_log += script_logfull_log += "\n" + "="*50 + "\n"full_log += "\n===== 所有脚本执行完成! ====="return render_template('index.html', logs=full_log)# 执行备份@app.route('/do_backup', methods=['POST'])def execute_backup():# 获取表单数据host = request.form['host']username = request.form['username']password = request.form['password']db_host = request.form['db_host']db_port = request.form['db_port']db_name = request.form['db_name']tables = request.form['tables']db_user = request.form['db_user']db_pass = request.form['db_pass']full_log = f"===== 开始MySQL备份任务 =====\n"full_log += f"目标主机: {host}\n"full_log += f"数据库: {db_name}\n"full_log += f"表: {tables}\n"full_log += f"执行时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"# 执行备份backup_log = perform_mysql_backup(host, username, password,db_host, db_port, db_name, tables, db_user, db_pass)full_log += backup_logfull_log += "\n===== 备份任务完成! ====="return render_template('backup.html', logs=full_log)if __name__ == '__main__':init_db()app.run(host='0.0.0.0', port=5000, debug=True)
backup.html
<!DOCTYPE html><html><head><title>MySQL备份工具</title><style>body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }.navbar { background: #333; overflow: hidden; margin-bottom: 20px; }.navbar a { float: left; color: white; text-align: center; padding: 14px 16px; text-decoration: none; }.navbar a:hover { background: #ddd; color: black; }.form-group { margin-bottom: 15px; }label { display: block; margin-bottom: 5px; font-weight: bold; }input[type="text"], input[type="password"] {width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;}button {background: #2196F3; color: white; border: none; padding: 10px 20px;border-radius: 4px; cursor: pointer; font-size: 16px;}button:hover { background: #0b7dda; }.logs {background: #333; color: #fff; padding: 15px; border-radius: 4px;margin-top: 20px; max-height: 400px; overflow-y: auto;}</style></head><body><h1>MySQL数据库备份</h1><formaction="/do_backup"method="POST"><divclass="navbar"><ahref="/">安装MySQL</a><ahref="/backup">备份MySQL</a></div><h3>SSH连接信息:</h3><divclass="form-group"><labelfor="host">目标主机IP:</label><inputtype="text"id="host"name="host"placeholder="例如: 192.168.1.100"required></div><divclass="form-group"><labelfor="username">SSH用户名:</label><inputtype="text"id="username"name="username"placeholder="例如: root"required></div><divclass="form-group"><labelfor="password">SSH密码:</label><inputtype="password"id="password"name="password"placeholder="输入密码"required></div><h3>数据库信息:</h3><divclass="form-group"><labelfor="db_host">数据库IP:</label><inputtype="text"id="db_host"name="db_host"value="localhost"required></div><divclass="form-group"><labelfor="db_port">数据库端口:</label><inputtype="text"id="db_port"name="db_port"value="3306"required></div><divclass="form-group"><labelfor="db_name">数据库名称:</label><inputtype="text"id="db_name"name="db_name"placeholder="例如: mydb"required></div><divclass="form-group"><labelfor="tables">表名(多个表用逗号分隔):</label><inputtype="text"id="tables"name="tables"placeholder="例如: users,products"required></div><divclass="form-group"><labelfor="db_user">数据库用户名:</label><inputtype="text"id="db_user"name="db_user"value="root"required></div><divclass="form-group"><labelfor="db_pass">数据库密码:</label><inputtype="password"id="db_pass"name="db_pass"placeholder="数据库密码"required></div><buttontype="submit">执行备份</button></form><h3>备份日志:</h3><preclass="logs">{{ logs }}</pre></body></html>
欢迎关注我的公众号《IT小Chen》
知识星球,限时优惠
近期和多位专家联合创建了两个知识星球,一个是面试方向的,有大量的面试真题和解析,另一个是AI运维方向的。限时优惠100元,感兴趣的可以看看,支持72小时内无理由退款。