一、自动化运维概述
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。