0. 写在前面:为什么你需要“神器”而非“常用命令
大家好,我是老杨,干货满满的老杨.欢迎来到互联网遥遥领先的博客. 欢迎点击原文链接或直接访问vps.top365app.com,来看老杨的全球vps信息还有各种咱们用得着的信息实时收集分析项目.
帮老杨点赞、转发、在看以及打开小星标哦
攒今世之功德,修来世之福报
背锅这个词咋来的?
老杨今天给各位补习一下这个看似没用,实则一点都用不着的知识点。
传说古代军中如果有人犯错,就会被降级去炊事班并且负责背着大锅行军。军队做大锅饭那个铸铁锅可不是一般的沉。而且这个锅到底有多重要,当年项羽要拼命了才下令破釜沉舟,也就是把锅砸了。
你背这玩意,而且要像初恋一样的保护它!
慢慢的这个岗位就被引申到了职场中。
蝙蝠侠、蜘蛛侠、闪电侠、背锅侠,这四个都是拯救苍生的英雄人物。唯一的区别大概只有背锅侠不戴面具了。
看老杨的文章涨知识吧!
进入今天的主题.
见过太多同行因为一些看似无关紧要的操作,最后成了大铁锅。
不对!是背锅侠。
有的是技术问题,有的是流程问题,但更多的是意识问题。
比如公司数据库崩了,老板直接问运维搞咋回事。结果查来查去,发现是开发改了个配置没通知,但最后还是运维背锅——"你们怎么不知道?监控呢?"
反正运维就别想跑,出了问题第一个被怀疑,背锅是常态。但有些锅其实可以避免。
这是运维背锅的头号原因。很多人觉得改个配置、重启个服务很简单,直接上生产操作。结果一旦出问题,你就是那个"擅自修改生产环境"的人。
之前就有发现Nginx配置有个小错误,想着就改一行代码,直接vim修改了。结果手抖多删了一个分号,整个网站500错误。更要命的是,没有人知道他改了什么,因为没有变更记录。
这种情况下,100%背锅。
正确的做法:
# 1. 创建变更工单
# 2. 在测试环境验证
$ nginx -t -c /etc/nginx/nginx.conf.new
nginx: configuration file /etc/nginx/nginx.conf.new syntax is ok
nginx: configuration file /etc/nginx/nginx.conf.new test is successful
# 3. 备份原配置
$ cp /etc/nginx/nginx.conf /backup/nginx.conf.$(date +%Y%m%d_%H%M%S)
# 4. 执行变更并记录
$ echo"变更时间: $(date)" >> /var/log/change.log
$ echo"操作人员: 老杨" >> /var/log/change.log
$ echo"变更内容: 修改upstream配置" >> /var/log/change.log
# 5. 应用配置
$ nginx -s reload运维最怕的就是删除操作。一个rm命令,可能毁掉整个职业生涯。
之前有个哥们,想清理 /tmp 目录下的临时文件,结果命令写成了:
$ rm -rf /tmp /*注意那个空格,本来想删 /tmp/* ,结果变成了删除 /tmp 和 /* 。服务器直接GG了。
更可怕的是这种情况:
# 本意是删除旧的备份文件
$ rm -rf $BACKUP_DIR/old_backup/*
# 但如果$BACKUP_DIR变量为空...
$ rm -rf /old_backup/*
# 这就变成了删除根目录下的old_backup目录正确的删除姿势:
# 1. 先用ls确认要删除的内容
$ ls -la /tmp/old_logs/
total 1024
drwxr-xr-x 2 root root 4096 Dec 1 10:00 .
drwxr-xr-x 8 root root 4096 Dec 1 09:00 ..
-rw-r--r-- 1 root root 1048576 Nov 30 23:59 app.log.old
# 2. 使用find命令精确匹配
$ find /tmp/old_logs/ -name "*.log.old" -type f -mtime +7 -print
/tmp/old_logs/app.log.old
/tmp/old_logs/error.log.old
# 3. 确认无误后执行删除
$ find /tmp/old_logs/ -name "*.log.old" -type f -mtime +7 -delete
# 4. 或者更安全的做法,先移动到回收站
$ mkdir -p /tmp/trash/$(date +%Y%m%d)
$ mv /tmp/old_logs/*.log.old /tmp/trash/$(date +%Y%m%d)/而且删除数据库数据时,一定要先备份:
# 绝对不要直接删除
# DELETE FROM users WHERE created_at < '2023-01-01';
# 正确做法:
# 1. 先查询要删除的数据量
SELECT COUNT(*) FROM users WHERE created_at < '2023-01-01';
-- 返回: 50000
# 2. 创建备份表
CREATE TABLE users_backup_20241201 AS
SELECT * FROM users WHERE created_at < '2023-01-01';
# 3. 确认备份成功
SELECT COUNT(*) FROM users_backup_20241201;
-- 返回: 50000
# 4. 小批量删除,避免锁表
DELETE FROM users WHERE created_at < '2023-01-01' LIMIT 1000;监控系统天天发告警,很多运维觉得都是"狼来了",直接忽略。等真出问题了,老板问为什么没有预警,你说监控有告警但没处理,这就是典型的失职。
比如磁盘使用率超过90%的告警连续一周都在发,觉得还有10%空间,应该没事。结果某天日志爆增,磁盘满了,数据库写入失败,订单系统瘫痪2小时。
正确的监控处理流程:
# 1. 收到磁盘告警后立即检查
$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 50G 45G 2.6G 95% /
/dev/sda2 100G 92G 4.2G 96% /var
# 2. 分析磁盘使用情况
$ du -h --max-depth=1 /var | sort -hr
85G /var/log
3.2G /var/lib
1.8G /var/cache
...
# 3. 找到占用空间最大的日志文件
$ find /var/log -type f -size +1G -execls -lh {} \;
-rw-r--r-- 1 root root 15G Dec 1 10:30 /var/log/mysql/mysql.log
-rw-r--r-- 1 root root 8.5G Dec 1 10:25 /var/log/nginx/access.log
# 4. 清理日志并配置轮转
$ echo > /var/log/mysql/mysql.log
$ echo > /var/log/nginx/access.log
# 5. 配置logrotate防止再次发生
$ vim /etc/logrotate.d/mysql
/var/log/mysql/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
postrotate
/bin/kill -HUP $(cat /var/run/mysqld/mysqld.pid 2>/dev/null) 2>/dev/null || true
endscript
}而且要建立告警处理机制:
# 告警处理脚本 alert_handler.py
import json
import time
import subprocess
from datetime import datetime
defhandle_disk_alert(server, mount_point, usage_percent):
"""处理磁盘告警"""
print(f"处理磁盘告警: {server}:{mount_point} 使用率{usage_percent}%")
if usage_percent > 95:
# 紧急处理:清理临时文件
subprocess.run([
"ssh", server,
"find /tmp -type f -mtime +1 -delete"
])
# 清理日志文件
subprocess.run([
"ssh", server,
"find /var/log -name '*.log' -size +1G -exec truncate -s 0 {} \\;"
])
# 记录处理动作
withopen('/var/log/alert_actions.log', 'a') as f:
f.write(f"{datetime.now()}: 自动清理{server}磁盘空间\n")
elif usage_percent > 85:
# 预警处理:发送通知给运维
send_wework_notification(
f"磁盘预警: {server}:{mount_point} 使用率{usage_percent}%,请及时处理"
)
defsend_wework_notification(message):
"""发送企业微信通知"""
# 实现企业微信通知逻辑
pass
if __name__ == "__main__":
# 模拟处理告警
handle_disk_alert("web-01", "/var", 96)很多运维图方便,把各种密码写在脚本里,或者所有人共用一个root账号。出了安全问题,你就是第一责任人。
我见过这样的脚本:
#!/bin/bash
# 备份脚本 - 错误示例
mysql -h localhost -u root -p123456 mydb > backup.sql
scp backup.sql admin@192.168.1.100:/backup/密码直接写在脚本里,任何能看到这个脚本的人都知道数据库密码。更可怕的是,这个脚本还被提交到Git仓库里,整个公司的人都能看到。
正确的密码管理:
# 1. 使用环境变量
export MYSQL_PASSWORD="your_secure_password"
mysql -h localhost -u root -p$MYSQL_PASSWORD mydb > backup.sql
# 2. 使用配置文件(权限600)
$ vim ~/.my.cnf
[client]
user=backup_user
password=your_secure_password
host=localhost
$ chmod 600 ~/.my.cnf
# 3. 在脚本中使用
mysql --defaults-file=~/.my.cnf mydb > backup.sql
# 4. 或者使用密钥管理系统
$ vault kv get -field=password secret/mysql/prod
your_secure_password
$ MYSQL_PASSWORD=$(vault kv get -field=password secret/mysql/prod)
$ mysql -h localhost -u root -p$MYSQL_PASSWORD mydb > backup.sql权限管理也要规范:
# 1. 每个人独立账号,禁止共享root
$ useradd -m -s /bin/bash zhangsan
$ usermod -aG sudo zhangsan
# 2. 配置sudo权限,只给必要的命令权限
$ vim /etc/sudoers.d/zhangsan
zhangsan ALL=(ALL) NOPASSWD: /bin/systemctl restart nginx
zhangsan ALL=(ALL) NOPASSWD: /bin/systemctl restart mysql
zhangsan ALL=(ALL) NOPASSWD: /usr/bin/docker restart *
# 3. 使用密钥登录,禁止密码登录
$ ssh-keygen -t rsa -b 4096 -C "zhangsan@company.com"
$ ssh-copy-id zhangsan@server
# 4. 配置SSH只允许密钥登录
$ vim /etc/ssh/sshd_config
PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin no很多运维做了备份,但从来不验证备份的完整性。等真需要恢复的时候,发现备份文件损坏或者根本恢复不了,这时候就只能背锅了。
比如某公司数据库崩了,运维信心满满地说:"没事,我们有备份。" 结果恢复的时候发现,备份脚本有bug,备份出来的数据都是空的,持续了3个月。
正确的备份验证流程:
#!/bin/bash
# 数据库备份与验证脚本
DB_NAME="production"
BACKUP_DIR="/backup/mysql"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/${DB_NAME}_${TIMESTAMP}.sql"
echo"开始备份数据库 $DB_NAME..."
# 1. 执行备份
mysqldump --single-transaction \
--routines \
--triggers \
--hex-blob \
--lock-tables=false \
$DB_NAME > $BACKUP_FILE
# 2. 检查备份文件大小
BACKUP_SIZE=$(stat -c%s $BACKUP_FILE)
echo"备份文件大小: $(($BACKUP_SIZE / 1024 / 1024))MB"
if [ $BACKUP_SIZE -lt 1048576 ]; then# 小于1MB可能有问题
echo"警告:备份文件过小,可能备份失败"
exit 1
fi
# 3. 验证SQL文件语法
if ! mysql --force --batch --skip-column-names -e "source $BACKUP_FILE" test_restore_db 2>/dev/null; then
echo"警告:备份文件SQL语法错误"
exit 1
fi
# 4. 创建测试数据库并恢复验证
TEST_DB="test_restore_$(date +%s)"
echo"创建测试数据库 $TEST_DB 进行恢复验证..."
mysql -e "CREATE DATABASE $TEST_DB"
mysql $TEST_DB < $BACKUP_FILE
# 5. 验证数据完整性
ORIGINAL_COUNT=$(mysql -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='$DB_NAME'")
RESTORED_COUNT=$(mysql -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='$TEST_DB'")
echo"原数据库表数量: $ORIGINAL_COUNT"
echo"恢复数据库表数量: $RESTORED_COUNT"
if [ "$ORIGINAL_COUNT" != "$RESTORED_COUNT" ]; then
echo"错误:恢复后表数量不一致"
mysql -e "DROP DATABASE $TEST_DB"
exit 1
fi
# 6. 清理测试数据库
mysql -e "DROP DATABASE $TEST_DB"
# 7. 压缩备份文件
gzip $BACKUP_FILE
echo"备份完成并验证通过: ${BACKUP_FILE}.gz"
# 8. 记录备份日志
echo"$(date): $DB_NAME 备份成功,文件: ${BACKUP_FILE}.gz" >> $BACKUP_DIR/backup.log而且要定期做恢复演练:
#!/bin/bash
# 每月备份恢复演练脚本
echo"开始每月备份恢复演练..."
# 1. 随机选择一个备份文件进行恢复测试
BACKUP_FILES=$(find /backup/mysql -name "*.sql.gz" -mtime -30 | shuf -n 1)
echo"选择备份文件: $BACKUP_FILES"
# 2. 创建独立的恢复测试环境
DRILL_DB="drill_test_$(date +%s)"
zcat $BACKUP_FILES | mysql $DRILL_DB
# 3. 执行数据一致性检查
# 这里可以加入具体的业务数据检查逻辑
# 4. 记录演练结果
echo"$(date): 恢复演练完成,备份文件: $BACKUP_FILES" >> /var/log/backup_drill.log
# 5. 清理测试数据
mysql -e "DROP DATABASE $DRILL_DB"这里老杨先声明一下,日常生活中大家都叫老杨波哥,跟辈分没关系,主要是岁数大了.就一个代称而已. 老杨的00后小同事老杨喊都是带哥的.张哥,李哥的. 但是这个称呼呀,在线下参加一些活动时.金主爸爸也这么叫就显的不太合适. 比如上次某集团策划总监,公司开大会来一句:“今个咱高兴!有请IT运维技术圈的波哥讲两句“ 这个氛围配这个称呼在互联网这行来讲就有点对不齐! 每次遇到这个情况老杨就想这么接话: “遇到各位是缘分,承蒙厚爱,啥也别说了,都在酒里了.老杨干了,你们随意!” 所以以后咱们改叫老杨,即市井又低调.还挺亲切,老杨觉得挺好.
运维X档案系列文章:
企业级 Kubernetes 集群安全加固全攻略( 附带一键检查脚本)
看完别走.修行在于点赞、转发、在看.攒今世之功德,修来世之福报
点击阅读原文或打开地址实时收集分析全球vps的项目 vps.top365app.com
老杨AI的号: 98dev