第200集:Vue 3运维自动化脚本

概述

在本集中,我们将深入探讨Vue 3应用的运维自动化脚本设计与实现。自动化脚本是现代运维工作的核心,它可以提高工作效率、减少人为错误、确保操作一致性,并实现24/7不间断运行。我们将从脚本设计原则开始,逐步介绍系统监控、部署自动化、日志分析等方面的脚本实现。

一、脚本设计原则

1. 核心设计原则

原则 描述 实现方法
可读性 代码易于理解和维护 使用清晰的变量名、函数名和注释
可维护性 便于修改和扩展 模块化设计,避免硬编码
可靠性 脚本在各种情况下都能稳定运行 错误处理、边界检查、日志记录
可扩展性 容易添加新功能 函数式编程,参数化设计
安全性 防止安全漏洞 输入验证、权限控制、避免命令注入
可测试性 便于测试和验证 单元测试、模拟数据、测试环境
可移植性 在不同环境下都能运行 避免平台特定命令,使用标准工具

2. 脚本模板

#!/bin/bash
# script-template.sh
# 脚本模板,包含基本的错误处理和日志记录

# 配置信息
CONFIG_FILE="config.ini"
LOG_FILE="script.log"
VERBOSE=false

# 日志函数
log() {
    local level="$1"
    local message="$2"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $message" >> "$LOG_FILE"
    if [ "$VERBOSE" = true ] || [ "$level" = "ERROR" ] || [ "$level" = "CRITICAL" ]; then
        echo "[$level] $message"
    fi
}

# 错误处理函数
error_handler() {
    local exit_code="$1"
    local message="$2"
    log "ERROR" "$message"
    log "ERROR" "脚本执行失败,退出码: $exit_code"
    cleanup
    exit "$exit_code"
}

# 清理函数
cleanup() {
    log "INFO" "执行清理操作..."
    # 在这里添加清理逻辑,如删除临时文件等
    log "INFO" "清理完成"
}

# 参数解析
parse_args() {
    while getopts "vch" opt; do
        case "$opt" in
            v) VERBOSE=true ;;
            c) CONFIG_FILE="$OPTARG" ;;
            h) usage ; exit 0 ;;
            *) usage ; exit 1 ;;
        esac
    done
    shift $((OPTIND - 1))
}

# 帮助信息
usage() {
    echo "Usage: $0 [OPTIONS]"
    echo ""
    echo "Options:"
    echo "  -v          详细模式"
    echo "  -c FILE     指定配置文件"
    echo "  -h          显示帮助信息"
    echo ""
    echo "Example: $0 -v -c custom_config.ini"
}

# 主函数
main() {
    log "INFO" "开始执行脚本..."
    
    # 解析参数
    parse_args "$@"
    log "INFO" "使用配置文件: $CONFIG_FILE"
    
    # 检查配置文件是否存在
    if [ ! -f "$CONFIG_FILE" ]; then
        error_handler 1 "配置文件不存在: $CONFIG_FILE"
    fi
    
    # 读取配置文件
    log "INFO" "读取配置文件..."
    # 在这里添加读取配置的逻辑
    
    # 执行主要逻辑
    log "INFO" "执行主要逻辑..."
    # 在这里添加脚本的主要逻辑
    
    log "INFO" "脚本执行成功!"
    cleanup
    exit 0
}

# 设置错误陷阱
trap 'error_handler $? "脚本执行过程中发生未捕获的错误"' ERR

# 执行主函数
main "$@"

二、系统监控脚本

1. 系统资源监控脚本

#!/bin/bash
# system-monitor.sh
# 系统资源监控脚本,监控CPU、内存、磁盘和网络使用情况

# 配置
LOG_FILE="system-monitor.log"
CHECK_INTERVAL=60 # 检查间隔(秒)
THRESHOLDS="cpu=80,mem=90,disk=95" # 告警阈值
NOTIFICATION_EMAIL="admin@example.com"

# 日志函数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
    echo "$1"
}

# 发送告警邮件
send_alert() {
    local subject="$1"
    local message="$2"
    echo "$message" | mail -s "$subject" "$NOTIFICATION_EMAIL"
    log "发送告警邮件: $subject"
}

# 获取CPU使用率
get_cpu_usage() {
    local cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
    echo "$(printf "%.1f" "$cpu_usage")"
}

# 获取内存使用率
get_mem_usage() {
    local mem_total=$(free -m | grep Mem | awk '{print $2}')
    local mem_used=$(free -m | grep Mem | awk '{print $3}')
    local mem_usage=$(echo "scale=1; $mem_used / $mem_total * 100" | bc)
    echo "$mem_usage"
}

# 获取磁盘使用率
get_disk_usage() {
    local disk_usage=$(df -h / | grep / | awk '{print $5}' | sed 's/%//')
    echo "$disk_usage"
}

# 获取网络流量
get_network_traffic() {
    local rx_bytes=$(cat /proc/net/dev | grep eth0 | awk '{print $2}')
    local tx_bytes=$(cat /proc/net/dev | grep eth0 | awk '{print $10}')
    echo "rx:$rx_bytes tx:$tx_bytes"
}

# 监控主函数
monitor() {
    log "开始系统监控..."
    
    while true; do
        local cpu_usage=$(get_cpu_usage)
        local mem_usage=$(get_mem_usage)
        local disk_usage=$(get_disk_usage)
        local network=$(get_network_traffic)
        
        # 记录当前状态
        log "CPU: ${cpu_usage}% | 内存: ${mem_usage}% | 磁盘: ${disk_usage}% | 网络: ${network}"
        
        # 检查CPU阈值
        if (( $(echo "$cpu_usage > ${THRESHOLDS##*cpu=}" | bc -l) )); then
            send_alert "CPU使用率告警" "CPU使用率过高: ${cpu_usage}%,超过阈值 ${THRESHOLDS##*cpu=}%"
        fi
        
        # 检查内存阈值
        if (( $(echo "$mem_usage > ${THRESHOLDS##*mem=}" | bc -l) )); then
            send_alert "内存使用率告警" "内存使用率过高: ${mem_usage}%,超过阈值 ${THRESHOLDS##*mem=}%"
        fi
        
        # 检查磁盘阈值
        if (( $disk_usage > ${THRESHOLDS##*disk=} )); then
            send_alert "磁盘使用率告警" "磁盘使用率过高: ${disk_usage}%,超过阈值 ${THRESHOLDS##*disk=}%"
        fi
        
        sleep "$CHECK_INTERVAL"
    done
}

# 执行监控
monitor

2. 服务状态监控脚本

#!/bin/bash
# service-monitor.sh
# 服务状态监控脚本,监控指定服务是否正常运行

# 配置
SERVICES=("nginx" "node" "mysql" "redis")
CHECK_INTERVAL=30
LOG_FILE="service-monitor.log"
RESTART_FAILED_SERVICES=true

# 日志函数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
    echo "$1"
}

# 检查服务状态
check_service() {
    local service="$1"
    log "检查服务: $service"
    
    if systemctl is-active --quiet "$service"; then
        log "服务 $service 运行正常"
        return 0
    else
        log "ERROR: 服务 $service 未运行"
        return 1
    fi
}

# 重启服务
restart_service() {
    local service="$1"
    log "尝试重启服务: $service"
    
    if systemctl restart "$service"; then
        log "服务 $service 重启成功"
        return 0
    else
        log "ERROR: 服务 $service 重启失败"
        return 1
    fi
}

# 监控主函数
monitor() {
    log "开始服务监控..."
    
    while true; do
        for service in "${SERVICES[@]}"; do
            if ! check_service "$service"; then
                if [ "$RESTART_FAILED_SERVICES" = true ]; then
                    restart_service "$service"
                    # 检查重启是否成功
                    if ! check_service "$service"; then
                        log "CRITICAL: 服务 $service 重启失败,需要人工干预"
                        # 在这里可以添加告警逻辑,如发送邮件或短信
                    fi
                else
                    log "CRITICAL: 服务 $service 未运行,且自动重启已禁用"
                fi
            fi
        done
        
        sleep "$CHECK_INTERVAL"
    done
}

# 执行监控
monitor

三、部署自动化脚本

1. 前端部署自动化脚本

#!/bin/bash
# frontend-deploy.sh
# Vue 3前端部署自动化脚本

# 配置
APP_DIR="/var/www/vue3-app"
GIT_REPO="git@github.com:example/vue3-app.git"
BRANCH="main"
BUILD_CMD="npm run build"
DEPLOY_DIR="/var/www/html"
BACKUP_DIR="/backup/vue3-app"

trap "echo '部署过程中发生错误'; exit 1" ERR

# 日志函数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}

# 检查命令是否存在
check_command() {
    if ! command -v "$1" &> /dev/null; then
        log "错误:命令 $1 不存在"
        exit 1
    fi
}

# 备份当前部署
backup_current() {
    log "备份当前部署..."
    mkdir -p "$BACKUP_DIR"
    backup_file="$BACKUP_DIR/vue3-app_$(date +%Y%m%d_%H%M%S).tar.gz"
    tar -czf "$backup_file" "$DEPLOY_DIR"
    log "备份完成: $backup_file"
}

# 部署主函数
deploy() {
    log "开始部署Vue 3应用..."
    
    # 检查必要命令
    check_command "git"
    check_command "npm"
    
    # 1. 克隆或更新代码
    log "更新代码..."
    if [ -d "$APP_DIR" ]; then
        cd "$APP_DIR" && git checkout "$BRANCH" && git pull
    else
        git clone -b "$BRANCH" "$GIT_REPO" "$APP_DIR"
    fi
    
    # 2. 安装依赖
    log "安装依赖..."
    cd "$APP_DIR" && npm ci
    
    # 3. 构建应用
    log "构建应用..."
    cd "$APP_DIR" && npm run build
    
    # 4. 备份当前部署
    backup_current
    
    # 5. 部署新版本
    log "部署新版本..."
    rm -rf "$DEPLOY_DIR"/*
    cp -r "$APP_DIR/dist/*" "$DEPLOY_DIR/"
    
    # 6. 重启服务(如果需要)
    log "重启服务..."
    systemctl restart nginx
    
    # 7. 健康检查
    log "健康检查..."
    sleep 2
    if curl -s -o /dev/null -w "%{http_code}" http://localhost/health == 200; then
        log "部署成功!应用运行正常"
    else
        log "错误:部署后健康检查失败"
        exit 1
    fi
    
    log "部署完成!"
}

# 执行部署
deploy

2. Python部署自动化脚本

#!/usr/bin/env python3
# deploy.py
# 基于Python的部署自动化脚本

import os
import sys
import time
import logging
import subprocess
import argparse
from datetime import datetime

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='[%(asctime)s] [%(levelname)s] %(message)s',
    filename='deploy.log'
)
logger = logging.getLogger()

# 命令执行函数
def run_command(cmd, cwd=None, shell=True):
    """执行命令并返回结果"""
    logger.info(f"执行命令: {cmd}")
    try:
        result = subprocess.run(
            cmd,
            cwd=cwd,
            shell=shell,
            check=True,
            capture_output=True,
            text=True
        )
        logger.info(f"命令执行成功: {cmd}")
        if result.stdout:
            logger.info(f"命令输出: {result.stdout.strip()}")
        return True, result.stdout
    except subprocess.CalledProcessError as e:
        logger.error(f"命令执行失败: {cmd}")
        logger.error(f"错误输出: {e.stderr.strip()}")
        return False, e.stderr

# 备份函数
def backup_deployment(deploy_dir, backup_dir):
    """备份当前部署"""
    logger.info("开始备份当前部署...")
    os.makedirs(backup_dir, exist_ok=True)
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    backup_file = os.path.join(backup_dir, f"vue3_app_{timestamp}.tar.gz")
    cmd = f"tar -czf {backup_file} {deploy_dir}"
    success, _ = run_command(cmd)
    if success:
        logger.info(f"备份完成: {backup_file}")
        return backup_file
    else:
        logger.error("备份失败")
        return None

# 部署函数
def deploy(args):
    """执行部署流程"""
    logger.info("开始部署Vue 3应用...")
    
    # 1. 克隆或更新代码
    logger.info("更新代码...")
    if os.path.exists(args.app_dir):
        # 更新代码
        run_command(f"git checkout {args.branch}", cwd=args.app_dir)
        run_command("git pull", cwd=args.app_dir)
    else:
        # 克隆代码
        run_command(f"git clone -b {args.branch} {args.repo} {args.app_dir}")
    
    # 2. 安装依赖
    logger.info("安装依赖...")
    run_command("npm ci", cwd=args.app_dir)
    
    # 3. 构建应用
    logger.info("构建应用...")
    run_command("npm run build", cwd=args.app_dir)
    
    # 4. 备份当前部署
    backup_file = backup_deployment(args.deploy_dir, args.backup_dir)
    if not backup_file:
        logger.error("备份失败,取消部署")
        return False
    
    # 5. 部署新版本
    logger.info("部署新版本...")
    run_command(f"rm -rf {args.deploy_dir}/*")
    run_command(f"cp -r {args.app_dir}/dist/* {args.deploy_dir}/")
    
    # 6. 重启服务
    logger.info("重启服务...")
    run_command("systemctl restart nginx")
    
    # 7. 健康检查
    logger.info("健康检查...")
    time.sleep(2)
    success, _ = run_command("curl -s -o /dev/null -w '%{http_code}' http://localhost/health")
    if success:
        logger.info("部署成功!应用运行正常")
        return True
    else:
        logger.error("部署后健康检查失败")
        # 可以添加回滚逻辑
        return False

# 主函数
def main():
    parser = argparse.ArgumentParser(description="Vue 3应用部署脚本")
    parser.add_argument("--app-dir", default="/var/www/vue3-app", help="应用代码目录")
    parser.add_argument("--repo", default="git@github.com:example/vue3-app.git", help="Git仓库地址")
    parser.add_argument("--branch", default="main", help="Git分支")
    parser.add_argument("--deploy-dir", default="/var/www/html", help="部署目录")
    parser.add_argument("--backup-dir", default="/backup/vue3-app", help="备份目录")
    
    args = parser.parse_args()
    
    success = deploy(args)
    if success:
        logger.info("部署完成!")
        sys.exit(0)
    else:
        logger.error("部署失败!")
        sys.exit(1)

if __name__ == "__main__":
    main()

四、日志分析脚本

1. Nginx日志分析脚本

#!/usr/bin/env python3
# nginx-log-analyzer.py
# Nginx日志分析脚本,分析访问日志和错误日志

import re
import argparse
import collections
from datetime import datetime

# 配置日志格式
NGINX_ACCESS_LOG_PATTERN = r'^(?P<ip>\S+) - - \[(?P<time>[^\]]+)\] "(?P<request>[^"]+)" (?P<status>\d+) (?P<size>\S+) "(?P<referrer>[^"]*)" "(?P<user_agent>[^"]*)"$'

# 统计数据
stats = {
    'total_requests': 0,
    'status_codes': collections.Counter(),
    'top_ips': collections.Counter(),
    'top_urls': collections.Counter(),
    'top_user_agents': collections.Counter(),
    'hourly_stats': collections.Counter(),
    'total_bytes': 0
}

# 解析日志行
def parse_log_line(line):
    match = re.match(NGINX_ACCESS_LOG_PATTERN, line)
    if match:
        return match.groupdict()
    return None

# 分析日志文件
def analyze_log(file_path):
    print(f"分析日志文件: {file_path}")
    
    with open(file_path, 'r') as f:
        for line in f:
            log_entry = parse_log_line(line)
            if log_entry:
                process_log_entry(log_entry)

# 处理日志条目
def process_log_entry(entry):
    stats['total_requests'] += 1
    
    # 统计状态码
    stats['status_codes'][entry['status']] += 1
    
    # 统计IP
    stats['top_ips'][entry['ip']] += 1
    
    # 统计URL
    request = entry['request'].split()[1] if len(entry['request'].split()) > 1 else entry['request']
    stats['top_urls'][request] += 1
    
    # 统计用户代理
    stats['top_user_agents'][entry['user_agent']] += 1
    
    # 统计每小时请求数
    time_str = entry['time'].split()[0]  # 格式: 15/Jun/2023:14:23:45
    date_time = datetime.strptime(time_str, "%d/%b/%Y:%H:%M:%S")
    hour_key = date_time.strftime("%Y-%m-%d %H:00")
    stats['hourly_stats'][hour_key] += 1
    
    # 统计总流量
    if entry['size'] != '-':
        stats['total_bytes'] += int(entry['size'])

# 打印统计结果
def print_stats():
    print("\n" + "="*50)
    print("Nginx日志分析结果")
    print("="*50)
    
    print(f"总请求数: {stats['total_requests']}")
    print(f"总流量: {stats['total_bytes'] / (1024*1024):.2f} MB")
    
    print("\n状态码分布:")
    for status, count in stats['status_codes'].most_common():
        percentage = (count / stats['total_requests']) * 100
        print(f"  {status}: {count} ({percentage:.2f}%)")
    
    print("\n访问量最高的10个IP:")
    for ip, count in stats['top_ips'].most_common(10):
        print(f"  {ip}: {count}")
    
    print("\n访问量最高的10个URL:")
    for url, count in stats['top_urls'].most_common(10):
        print(f"  {url}: {count}")
    
    print("\n每小时请求数:")
    for hour, count in sorted(stats['hourly_stats'].items()):
        print(f"  {hour}: {count}")

# 主函数
def main():
    parser = argparse.ArgumentParser(description="Nginx日志分析脚本")
    parser.add_argument("log_file", help="Nginx访问日志文件路径")
    args = parser.parse_args()
    
    analyze_log(args.log_file)
    print_stats()

if __name__ == "__main__":
    main()

五、自动化最佳实践

1. 脚本管理与版本控制

  • 使用Git管理脚本:将所有自动化脚本存储在Git仓库中,便于版本控制和团队协作
  • 模块化设计:将常用功能封装为模块,便于复用和维护
  • 文档化:为每个脚本编写详细的README文档,包括功能、配置、使用方法等
  • 测试:为脚本编写单元测试,确保功能正确性
  • 定期更新:定期更新脚本,适配新的环境和需求

2. 自动化工作流设计

# GitHub Actions工作流示例
name: Vue 3自动化部署

on:
  push:
    branches:
      - main
  schedule:
    - cron: '0 2 * * *'  # 每天凌晨2点执行

env:
  APP_DIR: /var/www/vue3-app
  DEPLOY_DIR: /var/www/html

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
      - name: 检出代码
        uses: actions/checkout@v3
      
      - name: 设置Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '16'
          cache: 'npm'
      
      - name: 安装依赖
        run: npm ci
      
      - name: 构建应用
        run: npm run build
      
      - name: 部署到生产环境
        uses: easingthemes/ssh-deploy@v2
        with:
          SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
          REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
          REMOTE_USER: ${{ secrets.REMOTE_USER }}
          TARGET: ${{ env.DEPLOY_DIR }}
          SOURCE: dist/
      
      - name: 健康检查
        run: curl -s -o /dev/null -w "%{http_code}" https://example.com/health
        continue-on-error: false
      
      - name: 发送部署通知
        if: success()
        run: |
          curl -X POST -H "Content-Type: application/json" \
          -d '{"text": "Vue 3应用部署成功!"}' \
          ${{ secrets.SLACK_WEBHOOK }}

3. 自动化安全实践

  • 最小权限原则:脚本执行使用最小权限账号
  • 输入验证:对所有输入参数进行验证,防止注入攻击
  • 加密存储敏感信息:使用环境变量或加密工具存储敏感信息
  • 审计日志:记录脚本执行日志,便于审计和故障排查
  • 定期安全扫描:对脚本进行安全扫描,发现潜在漏洞

六、常用自动化工具介绍

1. Ansible

Ansible是一款开源的自动化工具,用于配置管理、应用部署和任务自动化。

Ansible剧本示例

---
# deploy-vue3.yml
- name: 部署Vue 3应用
  hosts: webservers
  become: yes
  vars:
    app_dir: /var/www/vue3-app
    deploy_dir: /var/www/html
    repo: git@github.com:example/vue3-app.git
    branch: main
  
  tasks:
    - name: 安装必要依赖
      apt:
        name: [git, npm]
        state: present
    
    - name: 克隆或更新代码
      git:
        repo: "{{ repo }}"
        dest: "{{ app_dir }}"
        version: "{{ branch }}"
        update: yes
    
    - name: 安装npm依赖
      npm:
        path: "{{ app_dir }}"
        ci: yes
    
    - name: 构建Vue应用
      command:
        cmd: npm run build
        chdir: "{{ app_dir }}"
    
    - name: 部署构建产物
      synchronize:
        src: "{{ app_dir }}/dist/"
        dest: "{{ deploy_dir }}"
        delete: yes
    
    - name: 重启Nginx
      service:
        name: nginx
        state: restarted

2. Terraform

Terraform是一款基础设施即代码工具,用于定义和部署云基础设施。

Terraform配置示例

# main.tf
provider "aws" {
  region = "us-east-1"
}

# 创建EC2实例
resource "aws_instance" "vue3_server" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
  
  tags = {
    Name = "Vue3-Server"
  }
}

# 创建S3存储桶用于静态资源
resource "aws_s3_bucket" "vue3_bucket" {
  bucket = "vue3-app-bucket"
  
  website {
    index_document = "index.html"
    error_document = "error.html"
  }
  
  tags = {
    Name = "Vue3-App-Bucket"
  }
}

# 输出EC2实例IP
output "instance_ip" {
  value = aws_instance.vue3_server.public_ip
}

# 输出S3存储桶URL
output "bucket_url" {
  value = aws_s3_bucket.vue3_bucket.website_endpoint
}

七、总结

在本集中,我们深入探讨了Vue 3应用的运维自动化脚本设计与实现,包括:

  1. 脚本设计原则:可读性、可维护性、可靠性、可扩展性、安全性
  2. 系统监控脚本:资源监控和服务状态监控
  3. 部署自动化脚本:前端部署和Python实现的部署脚本
  4. 日志分析脚本:Nginx日志分析
  5. 自动化最佳实践:脚本管理、工作流设计、安全实践
  6. 常用自动化工具:Ansible和Terraform示例

通过自动化脚本,我们可以显著提高运维效率,减少人为错误,确保操作一致性,并实现24/7不间断运行。自动化是现代运维的核心趋势,掌握自动化脚本编写是每个运维工程师的必备技能。

随着技术的不断发展,自动化工具和技术也在不断演进,我们需要持续学习和适应新的工具和技术,不断优化自动化流程,提高自动化水平。

八、后续学习资源

  1. 脚本编程

    • Shell脚本编程指南
    • Python自动化编程
    • PowerShell脚本编程(Windows环境)
  2. 自动化工具

  3. DevOps实践

    • 《DevOps实践指南》
    • 《持续交付:发布可靠软件的系统方法》
    • 《基础设施即代码》
  4. 监控与日志

通过本集的学习,你已经掌握了Vue 3应用运维自动化脚本的设计和实现方法。希望你能够将这些知识应用到实际工作中,提高运维效率,确保应用的稳定运行。

« 上一篇 Vue 3 回滚与灾备方案:保障应用稳定运行 下一篇 » 201-vue3-reactive-system-source