一、从“人肉运维”到“脚本化”的第一步
记得刚接手一套200+节点的微服务集群时,每天最痛苦的就是重复执行“ssh到每台机器,重启服务”。我决定用Ansible来终结这种低效。
第一个坑就来了:环境一致性。有些机器是CentOS 7,有些是Ubuntu 20.04,Python版本也不统一。Ansible默认依赖Python,但部分机器上Python3未安装。
解决方案:在Ansible的inventory中按操作系统分组,并编写预检查playbook:
# inventory/hosts
[centos]
node1 ansible_host=192.168.1.10
node2 ansible_host=192.168.1.11
[ubuntu]
node3 ansible_host=192.168.1.12
预检查playbook:
- hosts: all
gather_facts: yes
tasks:
- name: 检查Python3
raw: which python3 || echo "missing"
register: python_check
- name: 安装Python3(如果缺失)
raw: |
if [ "$(uname)" == "Linux" ]; then
if command -v yum; then
yum install -y python3
elif command -v apt; then
apt update && apt install -y python3
fi
fi
when: "'missing' in python_check.stdout"
这个预检查避免了90%的因环境不一致导致的失败。教训:自动化工具本身也需要“自动化”的依赖管理。
二、设置管理中的“幽灵差异”
第二个坑出现在设置管理上。我们用Ansible的template模块管理Nginx设置,但某次上线后,部分节点出现了502错误。
排查发现:template中使用了{{ ansible_processor_cores }}变量来动态设置worker_processes,但有些虚拟机上报的CPU核心数与实际分配的vCPU不一致。
排坑过程:
- 先确认实际可用资源:
cat /proc/cpuinfo | grep processor | wc -l - 发现虚拟机上报了32核,但实际只分配了4个vCPU
# nginx.conf.j2
worker_processes {% if ansible_processor_cores > 8 %}auto{% else %}{{ ansible_processor_cores }}{% endif %};
同时,在playbook中增加变量覆盖:
- hosts: nginx_servers
vars:
nginx_worker_processes: "{{ ansible_processor_vcpus | default(ansible_processor_cores) }}"
tasks:
- name: 搭建Nginx设置
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: reload nginx
教训:自动化设置不能完全信任系统上报的数据,必须加入人工校验和兜底逻辑。
三、监控告警的“静默危机”
自动化搭建完成后,监控系统开始报警。我们使用Prometheus + Grafana做监控,但发现大量误报。
排查发现:自动化搭建脚本在启动服务时,会先停止旧进程,再启动新进程。这中间有短暂的端口不可用时间,导致Prometheus抓取失败,触发告警。
解决方案:在Prometheus中增加“启动宽限期”:
# prometheus.yml
scrape_configs:
- job_name: 'my_service'
scrape_interval: 15s
scrape_timeout: 10s
# 增加启动宽限期,避免搭建时的误报
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_probe]
regex: "true"
action: keep
# 使用up指标,但增加降噪
metric_relabel_configs:
- source_labels: [__name__]
regex: 'up'
replacement: 'up{job="my_service"}'
action: replace
同时,在Grafana告警规则中增加“持续时间”条件:
- alert: ServiceDown
expr: up{job="my_service"} == 0
for: 2m # 持续2分钟才告警
labels:
severity: warning
annotations:
summary: "服务 {{ $labels.instance }} 不可用超过2分钟"
教训:自动化搭建必须与监控系统协同设计,避免“搭建即报警”的尴尬。
四、日志管理的“海量陷阱”
自动化运维后,日志量呈指数级增长。我们用ELK做日志收集,但某天发现Elasticsearch集群OOM了。
排查发现:一个业务模块的日志中,某个字段值长度超过10MB,导致ES索引时内存内存异常。
解决方案:在Logstash设置中增加字段长度控制:
# logstash.conf
filter {
mutate {
# 控制message字段最大长度
gsub => ["message", "^.{10000}.*", "\1[TRUNCATED]"]
}
# 或者使用truncate插件
truncate {
fields => ["message"]
length_bytes => 10000
}
}
同时,在应用层增加日志轮转设置:
# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
copytruncate
maxsize 100M
}
教训:自动化收集日志前,必须先定义好日志规范,包括字段长度、轮转策略等。
五、总结与思考
自动化运维落地不是简单地把手动操作改成脚本,而是需要:
最后,推荐大家使用Ansible的ansible-lint检查playbook规范,用yamllint检查YAML格式,这些工具能避免很多低级错误。
自动化运维是一场持久战,每填一个坑,系统就稳定一分。希望我的经验能帮你少走一些弯路。
👨💻 运维老兵经验:根据实际生产环境,以上步骤建议先在测试环境验证,并做好备份。参数值需根据服务器设置调整,不要盲目照搬。