最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于Python編寫一個(gè)自動(dòng)化部署腳本的完整代碼

 更新時(shí)間:2026年03月05日 08:26:55   作者:運(yùn)維老王  
運(yùn)維日常最煩的就是重復(fù)部署,今天分享一個(gè)我常用的Python自動(dòng)化部署腳本,支持多服務(wù)器、回滾、日志記錄,開箱即用,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下

前言

運(yùn)維日常最煩的就是重復(fù)部署。今天分享一個(gè)我常用的自動(dòng)化部署腳本,支持多服務(wù)器、回滾、日志記錄,開 箱即用。 16 年運(yùn)維經(jīng)驗(yàn),這個(gè)腳本我已經(jīng)在線上用了半年,穩(wěn)定可靠。

功能需求

  • 支持多服務(wù)器并行部署
  • 部署失敗自動(dòng)回滾
  • 完整的日志記錄
  • 配置文件管理
  • 釘釘/企業(yè)微信告警

項(xiàng)目結(jié)構(gòu)

deploy_tool/
├── config.yaml
├── deploy.py
├── utils/

├── ssh_client.py

├── logger.py

└── notifier.py
├── scripts/

└── deploy_app.sh # 部署腳本
└── requirements.txt# 依賴

代碼實(shí)現(xiàn)

1. 配置文件 (config.yaml)

servers:
- host: 192.168.1.10port: 22
user: root
password: your_password
- host: 192.168.1.11
port: 22
user: root
password: your_password
app:
name: myapp
deploy_dir: /opt/myapp
backup_dir: /opt/backup
version: 1.0.0
notify:
dingtalk_webhook: https://oapi.dingtalk.com/robot/send?access_token=xxx
enabled: true

2. SSH 連接工具 (utils/ssh_client.py)

import paramiko
from typing import Tuple
class SSHClient:
def __init__(self, host, port, user, password):
self.host = host
self.ssh = paramiko.SSHClient()
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.ssh.connect(host, port, user, password, timeout=10)
def exec(self, command: str) -> Tuple[int, str, str]:
"""執(zhí)行命令,返回退出碼、輸出、錯(cuò)誤"""
stdin, stdout, stderr = self.ssh.exec_command(command)
exit_code = stdout.channel.recv_exit_status()
return exit_code, stdout.read().decode(), stderr.read().decode()
def upload(self, local_path, remote_path):
"""上傳文件"""
sftp = self.ssh.open_sftp()
sftp.put(local_path, remote_path)
sftp.close()
def close(self):
self.ssh.close()

3. 日志工具 (utils/logger.py)

import logging
from datetime import datetime
def get_logger(name: str) -> logging.Logger:
logger = logging.getLogger(name)
logger.setLevel(logging.INFO)
# 控制臺(tái)輸出
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
# 文件輸出
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
fh = logging.FileHandler(f'logs/deploy_{timestamp}.log')
fh.setLevel(logging.INFO)
# 格式
formatter = logging.Formatter(
'%(asctime)s - %(levelname)s - %(message)s'
)
ch.setFormatter(formatter)
fh.setFormatter(formatter)
logger.addHandler(ch)
logger.addHandler(fh)
return logger

4. 通知工具 (utils/notifier.py)

import requests
import logging
logger = logging.getLogger(__name__)
def send_dingtalk(webhook: str, message: str):
"""發(fā)送釘釘通知"""
try:
data = {
"msgtype": "text",
"text": {
"content": f"
部署通知\n\n{message}"
}
}
??
response = requests.post(webhook, json=data, timeout=10)if response.status_code == 200:
logger.info("釘釘通知發(fā)送成功")
else:
logger.error(f"釘釘通知發(fā)送失?。簕response.text}")
except Exception as e:
logger.error(f"釘釘通知異常:{str(e)}")
def send_wechat(webhook: str, message: str):
"""發(fā)送企業(yè)微信通知"""
try:
data = {
"msgtype": "text",
"text": {
"content": message
}
}
response = requests.post(webhook, json=data, timeout=10)
if response.status_code == 200:
logger.info("企業(yè)微信通知發(fā)送成功")
else:
logger.error(f"企業(yè)微信通知發(fā)送失敗:{response.text}")
except Exception as e:
logger.error(f"企業(yè)微信通知異常:{str(e)}")

5. 部署主程序 (deploy.py)

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import yaml
import datetime
import sys
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor, as_completed
from utils.ssh_client import SSHClient
from utils.logger import get_logger
from utils.notifier import send_dingtalk
logger = get_logger(__name__)
class DeployTool:
def __init__(self, config_path='config.yaml'):
self.config_path = Path(config_path)
self.load_config()
def load_config(self):"""加載配置文件"""
if not self.config_path.exists():
logger.error(f"配置文件不存在:{self.config_path}")
raise FileNotFoundError(f"Config file not found: {self.config_path}")
with open(self.config_path, 'r', encoding='utf-8') as f:
self.config = yaml.safe_load(f)
logger.info(f"配置文件加載成功:{self.config_path}")
def deploy_server(self, server: dict) -> bool:
"""部署單臺(tái)服務(wù)器"""
host = server['host']
try:
logger.info(f"[{host}] 開始部署...")
ssh = SSHClient(
server['host'],
server['port'],
server['user'],
server.get('password', '')
)
# 1. 備份當(dāng)前版本
logger.info(f"[{host}] 正在備份...")
backup_dir = self.config['app']['backup_dir']
deploy_dir = self.config['app']['deploy_dir']
timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
backup_cmd = f"cp -r {deploy_dir} {backup_dir}/backup_{timestamp}"
exit_code, _, stderr = ssh.exec(backup_cmd)
if exit_code != 0:
logger.error(f"[{host}] 備份失?。簕stderr}")
ssh.close()
return False
# 2. 執(zhí)行部署腳本
logger.info(f"[{host}] 正在部署應(yīng)用...")
deploy_script = self.config['app'].get('deploy_script',
'/opt/scripts/deploy_app.sh')
exit_code, output, stderr = ssh.exec(f"bash {deploy_script}")
if exit_code != 0:
logger.error(f"[{host}] 部署失敗:{stderr}")
self.rollback(server, backup_dir)
ssh.close()
return False# 3. 健康檢查
logger.info(f"[{host}] 執(zhí)行健康檢查...")
health_check = self.config['app'].get('health_check', 'systemctl
status myapp')
exit_code, _, stderr = ssh.exec(health_check)
if exit_code != 0:
logger.warning(f"[{host}] 健康檢查未通過(guò):{stderr}")
logger.info(f"[{host}]
ssh.close()
return True
? 部署成功")
except Exception as e:
logger.error(f"[{host}] 部署異常:{str(e)}")
self.rollback(server, backup_dir)
return False
def rollback(self, server: dict, backup_dir: str):
"""回滾到上一個(gè)版本"""
host = server['host']
deploy_dir = self.config['app']['deploy_dir']
try:
logger.info(f"[{host}] 開始回滾...")
ssh = SSHClient(
server['host'],
server['port'],
server['user'],
server.get('password', '')
)
# 獲取最新備份
ls_cmd = f"ls -t {backup_dir} | head -1"
exit_code, latest_backup, _ = ssh.exec(ls_cmd)
if exit_code == 0 and latest_backup.strip():
rollback_cmd = f"rm -rf {deploy_dir} && cp -r
{backup_dir}/{latest_backup.strip()} {deploy_dir}"
ssh.exec(rollback_cmd)
logger.info(f"[{host}]
回滾完成")
else:
logger.error(f"[{host}] 未找到備份文件")
?
ssh.close()
except Exception as e:
logger.error(f"[{host}] 回滾異常:{str(e)}")def deploy_all(self) -> bool:
"""并行部署所有服務(wù)器"""
servers = self.config['servers']
total = len(servers)
logger.info(f"開始部署,共 {total} 臺(tái)服務(wù)器")
success_count = 0
failed_servers = []
with ThreadPoolExecutor(max_workers=5) as executor:
future_to_server = {
executor.submit(self.deploy_server, server): server
for server in servers
}
for future in as_completed(future_to_server):
server = future_to_server[future]
host = server['host']
try:
if future.result():
success_count += 1
else:
failed_servers.append(host)
except Exception as e:
logger.error(f"[{host}] 部署異常:{str(e)}")
failed_servers.append(host)
# 發(fā)送通知
self.send_notification(success_count, total, failed_servers)
# 返回結(jié)果
if success_count == total:
logger.info(f"
部署完成:{success_count}/{total} 成功")
return True
else:
logger.warning(f"
部署部分失?。簕success_count}/{total} 成功")
return False
??
??
def send_notification(self, success: int, total: int, failed: list):
"""發(fā)送部署通知"""
if not self.config.get('notify', {}).get('enabled', False):
return
webhook = self.config['notify'].get('dingtalk_webhook', '')
?
if success == total:
message = f"
部署成功\n\n 成功:{success}/{total}\n 時(shí)間:
{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"??
else:
message = f"
部署部分失敗\n\n 成功:{success}/{total}\n 失?。簕',
'.join(failed)}\n 時(shí)間:{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
send_dingtalk(webhook, message)
if __name__ == '__main__':
try:
deploy_tool = DeployTool()
success = deploy_tool.deploy_all()
sys.exit(0 if success else 1)
except Exception as e:
logger.error(f"部署失?。簕str(e)}")
sys.exit(1)

6. 部署腳本示例 (scripts/deploy_app.sh)

#!/bin/bash
# 應(yīng)用部署腳本
set -e
APP_NAME="myapp"
APP_DIR="/opt/myapp"
VERSION="1.0.0"
echo "開始部署 $APP_NAME v$VERSION"
# 1. 停止服務(wù)
echo "停止服務(wù)..."
systemctl stop $APP_NAME
# 2. 備份當(dāng)前版本
echo "備份當(dāng)前版本..."
# (已在 Python 腳本中完成)
# 3. 下載新版本
echo "下載新版本..."
cd $APP_DIR
wget http://your-server.com/$APP_NAME-$VERSION.tar.gz
tar -xzf $APP_NAME-$VERSION.tar.gz
# 4. 啟動(dòng)服務(wù)
echo "啟動(dòng)服務(wù)..."
systemctl start $APP_NAME
# 5. 檢查狀態(tài)
echo "檢查服務(wù)狀態(tài)..."
systemctl status $APP_NAME
echo "部署完成!"```
---
#### 7. 依賴文件 (requirements.txt)

paramiko==3.4.0

pyyaml==6.0.1

requests==2.31.0

使用方法

1. 安裝依賴

pip install -r requirements.txt

2. 修改配置

vim config.yaml

修改:

  • 服務(wù)器列表(IP、用戶名、密碼)
  • 部署目錄
  • 釘釘 webhook(可選)

3. 執(zhí)行部署

python deploy.py

運(yùn)行效果

進(jìn)階功能

1. 添加健康檢查

在 config.yaml 中配置:

app:
health_check: |
curl -f http://localhost:8080/health || exit 1

2. 灰度發(fā)布

修改 deploy_all 方法,先部署一臺(tái),檢查成功后再部署其他:

def deploy_canary(self):
"""灰度發(fā)布"""
servers = self.config['servers']
# 先部署第一臺(tái)
if not self.deploy_server(servers[0]):
logger.error("灰度部署失敗,停止")
return False
# 檢查通過(guò),部署其他
for server in servers[1:]:
self.deploy_server(server)
return True

3. 集成 CI/CD

在 Jenkins/GitLab CI 中調(diào)用:

# .gitlab-ci.yml
deploy:
stage: deploy
script:
- pip install -r requirements.txt
- python deploy.py
only:
- master

總結(jié)

這個(gè)腳本的核心優(yōu)勢(shì):

  • 簡(jiǎn)單 - 代碼清晰,容易理解
  • 實(shí)用 - 覆蓋部署的核心場(chǎng)景
  • 可靠 - 有回滾、有日志、有通知
  • 可擴(kuò)展 - 可以根據(jù)需求添加功能

到此這篇關(guān)于基于Python編寫一個(gè)自動(dòng)化部署腳本的完整代碼的文章就介紹到這了,更多相關(guān)Python自動(dòng)化部署腳本內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python 正則表達(dá)式進(jìn)階用法之字符集與字符范圍詳解

    Python 正則表達(dá)式進(jìn)階用法之字符集與字符范圍詳解

    本文詳細(xì)介紹了Python正則表達(dá)式中的字符集和字符范圍,包括字符集的基本概念、特殊字符、示例和注意事項(xiàng),通過(guò)這些進(jìn)階用法,我們可以更高效地處理復(fù)雜的文本模式,感興趣的朋友跟隨小編一起看看吧
    2024-11-11
  • Python實(shí)現(xiàn)將Markdown轉(zhuǎn)為Word、HTML、PDF、PNG和JPG

    Python實(shí)現(xiàn)將Markdown轉(zhuǎn)為Word、HTML、PDF、PNG和JPG

    Markdown(MD)是一種輕量級(jí)的標(biāo)記語(yǔ)言,廣泛應(yīng)用于文本格式化,本文將探討如何使用 Python 將 Markdown 轉(zhuǎn)換為 Word、HTML、PDF、PNG 和 JPG 圖片格式,希望對(duì)大家有所幫助
    2025-11-11
  • python實(shí)現(xiàn) 獲取b站主播直播間 粉絲牌信息的方法

    python實(shí)現(xiàn) 獲取b站主播直播間 粉絲牌信息的方法

    這篇文章主要介紹了python實(shí)現(xiàn) 獲取b站主播直播間粉絲牌信息 ,用于實(shí)現(xiàn)通過(guò)牌子逆向查主播信息這個(gè)功能,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-02-02
  • Python自動(dòng)化辦公之生成PDF報(bào)告詳解

    Python自動(dòng)化辦公之生成PDF報(bào)告詳解

    因?yàn)楣ぷ餍枰?jīng)常需要生成很多的PDF報(bào)告給客戶查看產(chǎn)品效果以及過(guò)程的講解,每次都需要按照一定的格式的編寫文檔并生成PDF報(bào)告,這樣重復(fù)性的工作實(shí)在太累。本文就來(lái)用Python實(shí)現(xiàn)自動(dòng)生成PDF報(bào)告吧
    2023-03-03
  • Pandas分組函數(shù)groupby的用法詳解

    Pandas分組函數(shù)groupby的用法詳解

    在數(shù)據(jù)分析時(shí),經(jīng)常需要將數(shù)據(jù)分成不同的群組,pandas中的groupby()函數(shù)可以完美地完成各種分組操作,本文就來(lái)介紹一下Pandas分組函數(shù)groupby的用法,感興趣的可以了解一下
    2024-01-01
  • Python logging模塊進(jìn)行封裝實(shí)現(xiàn)原理解析

    Python logging模塊進(jìn)行封裝實(shí)現(xiàn)原理解析

    這篇文章主要介紹了Python logging模塊進(jìn)行封裝實(shí)現(xiàn)原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • 基于Python實(shí)現(xiàn)格斗小游戲的示例代碼

    基于Python實(shí)現(xiàn)格斗小游戲的示例代碼

    格斗游戲,曾經(jīng)是街機(jī)廳里最火爆的游戲之一,甚至可以把“之一”去掉,那個(gè)年代的格斗游戲就是街機(jī)游戲的王。本文就來(lái)用Python實(shí)現(xiàn)一個(gè)簡(jiǎn)單的格斗游戲,感興趣的可以了解一下
    2023-03-03
  • python 圖像插值 最近鄰、雙線性、雙三次實(shí)例

    python 圖像插值 最近鄰、雙線性、雙三次實(shí)例

    這篇文章主要介紹了python 圖像插值 最近鄰、雙線性、雙三次實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-07-07
  • PyTorch中clone()、detach()及相關(guān)擴(kuò)展詳解

    PyTorch中clone()、detach()及相關(guān)擴(kuò)展詳解

    這篇文章主要給大家介紹了關(guān)于PyTorch中clone()、detach()及相關(guān)擴(kuò)展的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • python socket多線程實(shí)現(xiàn)客戶端與服務(wù)器連接

    python socket多線程實(shí)現(xiàn)客戶端與服務(wù)器連接

    這篇文章主要為大家詳細(xì)介紹了python socket多線程實(shí)現(xiàn)客戶端與服務(wù)器連接,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09

最新評(píng)論

平南县| 长治市| 嘉禾县| 伊金霍洛旗| 壤塘县| 衢州市| 蓬莱市| 池州市| 抚宁县| 丹凤县| 申扎县| 隆安县| 衡阳市| 南安市| 绍兴县| 台中县| 三台县| 莆田市| 天峻县| 珠海市| 土默特右旗| 楚雄市| 长沙县| 马公市| 林州市| 通道| 日喀则市| 页游| 修文县| 象山县| 海口市| 静乐县| 临桂县| 雅江县| 哈密市| 永清县| 定南县| 铜梁县| 定日县| 冷水江市| 旌德县|