运维笔记:自动化与脚本

一、自动化运维概述

1.1 自动化运维的价值

自动化运维通过工具和脚本替代人工操作,实现重复任务的自动化执行,其核心价值包括:

  • 提高效率:减少人工干预,缩短任务完成时间,例如批量服务器配置、软件部署等。
  • 降低错误率:避免人为操作失误(如命令输入错误、配置遗漏),确保操作一致性。
  • 可扩展性:支持大规模服务器集群管理,适应业务增长带来的运维压力。
  • 标准化流程:将运维流程固化到脚本或工具中,实现标准化操作,便于新人上手和团队协作。
  • 解放人力:让运维工程师从重复劳动中解脱,专注于架构设计、性能优化等核心工作。

1.2 自动化运维工具链

  • 脚本语言:Shell(适合系统级操作)、Python(适合复杂逻辑和跨平台开发)、Perl(文本处理强大)、PowerShell(Windows 环境首选)。
  • 配置管理工具:Ansible、Puppet、SaltStack,用于批量配置服务器、安装软件、管理服务。
  • 自动化部署工具:Jenkins、GitLab CI/CD、GitHub Actions,实现代码编译、测试、部署的自动化流程。
  • 任务调度工具:Cron(Linux 定时任务)、Windows 任务计划程序、Airflow(复杂工作流调度)。
  • 监控与告警自动化:Prometheus+Alertmanager(指标监控与告警)、ELK Stack(日志分析与告警)。

二、Shell 脚本进阶

2.1 高级变量与参数处理

  • 位置参数与特殊变量
    • $0:脚本文件名;$1-$9:第 1 到第 9 个参数;${10}及以上:第 10 个及以后的参数(需用大括号)。
    • $#:参数总数;$*:所有参数作为单个字符串;$@:所有参数作为独立字符串(推荐使用,适合循环)。
    • $?:上一条命令的退出状态(0 表示成功,非 0 表示失败);$$:当前脚本的 PID;$!:后台运行的最后一个进程的 PID。
  • 参数解析:使用getopts处理短选项(如-h、-v),示例:
while getopts "h:v" opt; do
  case $opt in
    h)
      echo "使用方法: $0 -h 主机名 -v 版本号"
      exit 0
      ;;
    v)
      version=$OPTARG
      ;;
    \?)
      echo "无效选项: -$OPTARG" >&2
      exit 1
      ;;
    :)
      echo "选项 -$OPTARG 需要参数" >&2
      exit 1
      ;;
  esac
done

2.2 文本处理高级技巧

  • awk 实战:用于数据提取、统计和格式化输出。
    • 统计日志中不同状态码的数量:awk '{print $9}' access.log | sort | uniq -c | sort -nr。
    • 提取 CSV 文件中特定列:awk -F ',' '{print $1, $3}' data.csv(以逗号为分隔符,打印第 1 和第 3 列)。
    • 条件过滤:awk '$9 == 404 {print $0}' access.log(打印 404 错误的日志行)。
  • sed 高级用法
    • 批量替换文件内容:sed -i 's/old_string/new_string/g' file.txt(-i直接修改文件,g全局替换)。
    • 删除空行:sed -i '/^$/d' file.txt。
    • 插入文本:sed -i '3i insert_line' file.txt(在第 3 行前插入文本)。
  • grep 与正则表达式
    • 递归查找包含特定字符串的文件:grep -r "error" /var/log/。
    • 显示匹配行的前后内容:grep -A 3 -B 2 "critical" app.log(显示匹配行及后 3 行、前 2 行)。
    • 正则匹配 IP 地址:grep -E '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' file.txt。

2.3 函数与模块化脚本

  • 函数定义与调用
# 定义函数
log_info() {
  local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
  echo "[$timestamp] INFO: $1"
}

log_error() {
  local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
  echo "[$timestamp] ERROR: $1" >&2  # 错误信息输出到stderr
}

# 调用函数
log_info "开始部署应用"
if ! command -v nginx &> /dev/null; then
  log_error "nginx未安装"
  exit 1
fi
  • 模块化脚本:将通用函数放入独立文件(如common.sh),通过source或.引入其他脚本:
# common.sh
check_root() {
  if [ $EUID -ne 0 ]; then
    echo "请以root用户运行" >&2
    exit 1
  fi
}

# 主脚本
source ./common.sh
check_root  # 调用common.sh中的函数

2.4 错误处理与日志

  • 错误处理机制
    • set -e:脚本中任何命令失败(退出码非 0)则立即终止脚本。
    • set -u:引用未定义变量时终止脚本。
    • set -o pipefail:管道中任一命令失败则整个管道返回失败。
    • 结合使用:set -euo pipefail,增强脚本健壮性。
  • 日志管理:将脚本输出重定向到日志文件,同时保留控制台输出:
log_file="deploy_$(date +%Y%m%d).log"

# 执行命令并将stdout和stderr写入日志

./deploy.sh > >(tee -a $log_file) 2> >(tee -a $log_file >&2)

2.5 实战脚本示例

  • 服务器初始化脚本
#!/bin/bash
set -euo pipefail

# 引入通用函数
source ./common.sh

log_info "开始初始化服务器"

# 更新系统
log_info "更新系统软件包"
yum update -y || apt update -y && apt upgrade -y

# 安装常用工具
log_info "安装基础工具"
tools="vim wget curl net-tools htop"
if command -v yum &> /dev/null; then
  yum install -y $tools
elif command -v apt &> /dev/null; then
  apt install -y $tools
else
  log_error "不支持的包管理器"
  exit 1
fi

# 配置防火墙(开放22、80、443端口)
log_info "配置防火墙"
if command -v firewall-cmd &> /dev/null; then
  firewall-cmd --add-port=22/tcp --permanent
  firewall-cmd --add-port=80/tcp --permanent
  firewall-cmd --add-port=443/tcp --permanent
  firewall-cmd --reload
elif command -v ufw &> /dev/null; then
  ufw allow 22/tcp
  ufw allow 80/tcp
  ufw allow 443/tcp
  ufw --force enable
fi

log_info "服务器初始化完成"

三、Python 运维脚本开发

3.1 常用运维库

  • paramiko:实现 SSH 远程连接,执行命令、传输文件:
import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())  # 自动接受未知主机密钥
ssh.connect('192.168.1.100', username='root', password='password')

# 执行命令
stdin, stdout, stderr = ssh.exec_command('df -h')
print(stdout.read().decode())

# 传输文件到远程
sftp = ssh.open_sftp()
sftp.put('local_file.txt', '/remote/path/file.txt')
sftp.close()

ssh.close()
  • requests:发送 HTTP/HTTPS 请求,用于 API 调用、监控网页状态:
import requests

url = 'https://api.example.com/status'
try:
    response = requests.get(url, timeout=5)
    if response.status_code == 200:
        print("服务正常")
    else:
        print(f"服务异常,状态码: {response.status_code}")
except requests.exceptions.RequestException as e:
    print(f"请求失败: {e}")
  • subprocess:调用系统命令,替代 os.system,更灵活:
import subprocess

def run_command(cmd):
    try:
        result = subprocess.run(
            cmd,
            shell=True,
            check=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )
        return result.stdout
    except subprocess.CalledProcessError as e:
        print(f"命令执行失败: {e.stderr}")
        raise

output = run_command('ls -l /home')
print(output)
  • configparser:解析配置文件(INI 格式),管理脚本参数:
import configparser

config = configparser.ConfigParser()
config.read('config.ini')

# 读取配置
db_host = config.get('database', 'host')
db_port = config.getint('database', 'port')  # 转换为整数
db_user = config.get('database', 'user')

# config.ini内容
#[database]
#host = 192.168.1.10
#port = 3306
#user = admin

3.2 批量操作脚本

  • 批量执行远程命令
import paramiko
import threading

def ssh_exec(host, cmd, username, password):
    try:
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(host, username=username, password=password, timeout=10)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        output = stdout.read().decode()
        error = stderr.read().decode()
        print(f"==== {host} 执行结果 ====")
        print(output)
        if error:
            print(f"错误: {error}")
        ssh.close()
    except Exception as e:
        print(f"{host} 连接失败: {e}")

# 主机列表
hosts = ['192.168.1.101', '192.168.1.102', '192.168.1.103']
cmd = 'free -m'  # 查看内存使用情况
username = 'root'
password = 'password'

# 多线程并发执行
threads = []
for host in hosts:
    t = threading.Thread(target=ssh_exec, args=(host, cmd, username, password))
    threads.append(t)
    t.start()

# 等待所有线程完成
for t in threads:
    t.join()

3.3 监控脚本开发

  • 服务器资源监控脚本
import psutil
import time
import smtplib
from email.mime.text import MIMEText

# 配置
thresholds = {
    'cpu': 80,    # CPU使用率阈值(%)
    'memory': 80, # 内存使用率阈值(%)
    'disk': 85    # 磁盘使用率阈值(%)
}
smtp_server = 'smtp.example.com'
smtp_port = 587
sender = 'alert@example.com'
receiver = 'admin@example.com'
password = 'smtp_password'

def get_system_stats():
    # CPU使用率(间隔1秒取平均值)
    cpu_usage = psutil.cpu_percent(interval=1)
    # 内存使用率
    mem = psutil.virtual_memory()
    mem_usage = mem.percent
    # 磁盘使用率(根目录)
    disk = psutil.disk_usage('/')
    disk_usage = disk.percent
    return {
        'cpu': cpu_usage,
        'memory': mem_usage,
        'disk': disk_usage
    }

def send_alert(message):
    msg = MIMEText(message)
    msg['Subject'] = '服务器资源告警'
    msg['From'] = sender
    msg['To'] = receiver
    with smtplib.SMTP(smtp_server, smtp_port) as server:
        server.starttls()
        server.login(sender, password)
        server.send_message(msg)

def monitor():
    stats = get_system_stats()
    alert_msg = []
    for resource, usage in stats.items():
        if usage > thresholds[resource]:
            alert_msg.append(f"{resource}使用率过高: {usage}% (阈值: {thresholds[resource]}%)")
    if alert_msg:
        send_alert('\n'.join(alert_msg))
        print("已发送告警")
    else:
        print("所有资源正常")

if __name__ == '__main__':
    monitor()
    # 可结合crontab定时执行,如每5分钟一次

四、配置管理工具

4.1 Ansible 深度应用

  • Ansible 架构:控制节点(安装 Ansible 的机器)通过 SSH 连接被控节点,无需在被控节点安装代理,基于模块执行任务,通过 Playbook 定义自动化流程。
  • Playbook 核心元素
    • hosts:目标主机或主机组(在/etc/ansible/hosts定义)。
    • tasks:任务列表,每个任务调用一个模块。
    • vars:变量定义。
    • handlers:触发式任务(如配置文件修改后重启服务)。
    • roles:将任务、变量、模板等按角色模块化组织。
  • 常用模块示例
    • package:管理软件包(兼容 yum 和 apt):
- name: 安装nginx
  package:
    name: nginx
    state: present  # 确保安装
  • service:管理服务:
- name: 启动并设置nginx开机自启
  service:
    name: nginx
    state: started
    enabled: yes
  • template:使用 Jinja2 模板生成配置文件:
- name: 部署nginx配置
  template:
    src: ./templates/nginx.conf.j2  # 本地模板文件
    dest: /etc/nginx/nginx.conf     # 目标路径
    mode: '0644'
  notify: 重启nginx  # 配置文件变化时触发handler
  • file:管理文件 / 目录:
- name: 创建网站目录
  file:
    path: /var/www/html
    state: directory
    mode: '0755'
    owner: nginx
    group: nginx
  • Handlers 示例
handlers:
  - name: 重启nginx
    service:
      name: nginx
      state: restarted
  • Roles 结构
roles/
  webserver/
    tasks/         # 主任务文件(main.yml)
    handlers/      # handlers文件(main.yml)
    templates/     # 模板文件
    vars/          # 变量文件(main.yml)
    defaults/      # 默认变量(优先级低)
    meta/          # 角色依赖信息roles/
  webserver/
    tasks/         # 主任务文件(main.yml)
    handlers/      # handlers文件(main.yml)
    templates/     # 模板文件
    vars/          # 变量文件(main.yml)
    defaults/      # 默认变量(优先级低)
    meta/          # 角色依赖信息
  • Playbook 调用 Role
- hosts: webservers
  roles:
    - webserver

4.2 SaltStack 基础

  • 架构:包含 Salt Master 和 Salt Minion,Minion 主动连接 Master,支持批量执行命令、状态管理。
  • 远程执行:salt 'web*' cmd.run 'free -m'(在所有 web 开头的 Minion 上执行命令)。
  • 状态文件(SLS):/srv/salt/nginx.sls,定义系统状态:
nginx-install:
  pkg.installed:
    - name: nginx

nginx-service:
  service.running:
    - name: nginx
    - enable: True
    - require:
      - pkg: nginx-install  # 依赖nginx安装

nginx-config:
  file.managed:
    - name: /etc/nginx/nginx.conf
    - source: salt://templates/nginx.conf
    - mode: 644
    - watch_in:
      - service: nginx-service  # 配置变化时重启服务
  • 应用状态:salt 'web*' state.apply nginx(在 web 节点应用 nginx 状态)。

4.3 Puppet 基础

  • 架构:Client-Server 模式,Puppet Agent(客户端)定期向 Puppet Master 请求配置,应用配置后汇报状态。
  • Manifest 文件(.pp):定义资源和配置,如/etc/puppetlabs/code/environments/production/manifests/nginx.pp:
package { 'nginx':
  ensure => installed,
}

service { 'nginx':
  ensure => running,
  enable => true,
  require => Package['nginx'],  # 依赖关系
}

file { '/etc/nginx/nginx.conf':
  ensure => file,
  source => 'puppet:///modules/nginx/nginx.conf',
  mode => '0644',
  notify => Service['nginx'],  # 文件变化通知服务重启
  require => Package['nginx'],
}
  • 模块结构:与 Ansible Roles 类似,存放 manifest、模板等。

五、CI/CD 与自动化部署

5.1 CI/CD 概念

  • 持续集成(CI):开发人员频繁将代码提交到版本库,自动执行构建和测试,尽早发现代码问题。
  • 持续部署(CD):通过自动化流程将通过测试的代码部署到生产环境,实现快速、可靠的发布。

5.2 Jenkins 实战

  • 安装与配置
    • 安装:yum install jenkins(CentOS)或通过 Docker 部署:docker run -d -p 8080:8080 -p 50000:50000 -v jenkins_home:/var/jenkins_home jenkins/jenkins:lts。
    • 初始化:访问http://ip:8080,输入初始密码(cat /var/jenkins_home/secrets/initialAdminPassword),安装推荐插件。
  • 创建 Pipeline 项目:使用 Jenkinsfile 定义流水线,示例(部署 Node.js 应用):
pipeline {
    agent any  # 在任何可用节点执行
    stages {
        stage('拉取代码') {
            steps {
                git url: 'https://github.com/example/node-app.git', branch: 'main'
            }
        }
        stage('安装依赖') {
            steps {
                sh 'npm install'
            }
        }
        stage('运行测试') {
            steps {
                sh 'npm test'
            }
        }
        stage('构建') {
            steps {
                sh 'npm run build'
            }
        }
        stage('部署到生产') {
            steps {
                // 通过SSH部署到远程服务器
                sshagent(['production-server-ssh-key']) {
                    sh '''
                        scp -r dist/* user@192.168.1.200:/var/www/node-app/
                        ssh user@192.168.1.200 'sudo systemctl restart node-app'
                    '''
                }
            }
        }
    }
    post {
        success {
            echo '部署成功'
            // 可发送通知(邮件、Slack等)
        }
        failure {
            echo '部署失败'
        }
    }
}
  • 插件推荐:Git、Pipeline、SSH Agent、Email Extension、NodeJS Plugin(用于前端构建)。

5.3 GitLab CI/CD

  • 配置文件:在代码库根目录创建.gitlab-ci.yml,定义 CI/CD 流程:
stages:
  - test
  - build
  - deploy

test:
  stage: test
  image: node:16
  script:
    - npm install
    - npm test

build:
  stage: build
  image: node:16
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - dist/  # 保存构建产物,供后续阶段使用

deploy:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache openssh-client
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -  # 从GitLab变量获取SSH密钥
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - ssh-keyscan -H 192.168.1.200 >> ~/.ssh/known_hosts
  script:
    - scp -r dist/* user@192.168.1.200:/var/www/node-app/
    - ssh user@192.168.1.200 'sudo systemctl restart node-app'
  only:
    - main  # 仅main分支触发部署
  • Runner 配置:GitLab Runner 是执行 CI/CD 任务的代理,安装后注册到 GitLab 项目,支持 Shell、Docker 等执行器。

5.4 配置管理与 CI/CD 集成

  • Ansible 与 Jenkins 集成:在 Jenkins Pipeline 中调用 Ansible Playbook 部署:
stage('部署应用') {
    steps {
        sh 'ansible-playbook -i inventory/production deploy.yml'
    }
}
  • 基础设施即代码(IaC):使用 Terraform 定义云资源(如 AWS EC2、阿里云 ECS),通过 CI/CD 流程自动创建和管理基础设施:
# .gitlab-ci.yml 中集成Terraform
deploy-infra:
  stage: deploy
  image: hashicorp/terraform:latest
  script:
    - cd terraform
    - terraform init
    - terraform plan
    - terraform apply -auto-approve

六、任务调度与自动化工具

6.1 Cron 定时任务

  • 基本格式:* * * * * command,五个字段分别表示:分钟(0-59)、小时(0-23)、日(1-31)、月(1-12)、星期(0-6,0 表示周日)。
  • 示例
    • 0 2 * * * /backup/backup.sh:每天凌晨 2 点执行备份脚本。
    • */30 * * * * /scripts/monitor.sh:每 30 分钟执行监控脚本。
    • 0 1 * * 0 /scripts/cleanup.sh:每周日凌晨 1 点执行清理脚本。
  • 管理工具:crontab -e编辑当前用户的定时任务;crontab -l查看任务;crontab -r删除任务。系统级任务可放在/etc/cron.d/目录。

6.2 Airflow 工作流调度

  • 概念:用于编排复杂的有依赖关系的任务,通过 DAG(有向无环图)定义任务流程。
  • 安装:pip install apache-airflow,初始化数据库:airflow db init。
  • DAG 示例(数据备份工作流):
from datetime import datetime, timedelta
from airflow import DAG
from airflow.operators.bash import BashOperator

default_args = {
    'owner': 'airflow',
    'depends_on_past': False,
    'email_on_failure': True,
    'email': ['admin@example.com'],
    'retries': 1,
    'retry_delay': timedelta(minutes=5),
}

with DAG(
    'data_backup',
    default_args=default_args,
    description='数据备份工作流',
    schedule_interval=timedelta(days=1),  # 每天执行
    start_date=datetime(2023, 1, 1),
    catchup=False,
) as dag:
    # 任务1:备份数据库
    backup_db = BashOperator(
        task_id='backup_database',
        bash_command='/scripts/backup_db.sh',
    )

    # 任务2:备份文件(依赖任务1完成)
    backup_files = BashOperator(
        task_id='backup_files',
        bash_command='/scripts/backup_files.sh',
    )

    # 任务3:上传到云存储(依赖任务2完成)
    upload_to_cloud = BashOperator(
        task_id='upload_to_cloud',
        bash_command='/scripts/upload_cloud.sh',
    )

    # 定义任务依赖
    backup_db >> backup_files >> upload_to_cloud
  • 启动:airflow webserver -p 8080(Web 界面)、airflow scheduler(调度器),通过 Web 界面监控任务执行状态。

6.3 其他自动化工具

  • Fabric:基于 Python 的 SSH 命令行工具,用于批量执行远程命令,适合简单的自动化任务:
from fabric import Connection

def deploy(c):
    c.run('cd /app && git pull')
    c.run('cd /app && docker-compose up -d --build')

# 执行
with Connection('user@192.168.1.100') as c:
    deploy(c)

# 批量执行
from fabric import SerialGroup as Group
servers = Group('user@192.168.1.101', 'user@192.168.1.102')
servers.run('uname -a')
  • Invoke:Fabric 的姊妹项目,专注于本地任务自动化,类似 Makefile 但使用 Python。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值