Ansible自动化运维

前言:你还在手动管理上百台服务器吗?

还记得我刚入行做运维的时候,公司业务刚起步,整个团队只有 5 台服务器,那时候觉得手动管理也没什么,装个 Nginx、改个配置,SSH 上去输两行命令就搞定了。

结果不到半年,业务爆发式增长,服务器一下子从 5 台涨到了 120 台,那时候刚好赶上 Nginx 出了一个高危漏洞,要紧急更新所有服务器的 Nginx 版本。我从早上 9 点开始,一台台 SSH 登录,输命令,装包,重启服务,搞到下午 6 点,才更了 80 多台,累的腰都直不起来,结果晚上线上还出了问题 ------ 我漏了两台边缘服务器没更,被黑客扫到了漏洞,差点搞出大事故。

那时候我就想,难道就没有什么办法,能让我一键搞定所有服务器的操作吗?不用再一台台重复劳动,不用再怕漏了哪台,不用再熬夜加班?

后来我接触到了 Ansible,用了之后才发现,原来原来一天的活,现在 10 分钟就能搞定!原来要手动做的初始化、装软件、改配置,现在写个脚本,点一下执行,所有服务器自动就完成了,效率直接提升了 10 倍都不止。

这篇文章,我就把我这几年用 Ansible 的经验,从 0 到 1,全部教给你,不管你是刚入行的运维新手,还是已经做了几年的老运维,都能跟着这篇文章,直接把自动化用起来,全程无坑,我踩过的所有坑,都会在文章里告诉你,让你少走弯路。

一、Ansible 是什么?为什么选它?

可能还有朋友不太了解 Ansible,我先简单给大家介绍一下:

Ansible 是 RedHat 旗下的一款开源自动化运维工具,它的核心特点就是简单、无代理、上手快

和其他的自动化工具比如 SaltStack、Puppet 比起来,Ansible 真的太友好了:

  1. 不用装客户端:你不需要在每台被管理的服务器上装任何 Agent,只要你的服务器开了 SSH 服务,能正常连接,Ansible 就能管理它,不管是 Linux、Windows 还是 Mac,都能管。

  2. 上手极快:Ansible 用的是 YAML 语法,写的配置文件普通人看一眼就能懂,不用学什么复杂的 DSL,新手几个小时就能上手写自己的脚本。

  3. 功能强大:从简单的批量执行命令,到复杂的服务部署、集群配置,Ansible 都能搞定,而且有海量的现成模块,不用你自己写脚本。

  4. 生态完善:官方有上千个现成的模块,还有 Ansible Galaxy,上面有无数开发者分享的现成角色,你要装什么服务,直接下载就能用,不用自己从零写。

现在不管是中小团队,还是像腾讯、阿里这样的大厂,都在大量用 Ansible 做自动化运维,它真的是能让你从重复的手动劳动里解放出来的神器。


二、环境准备:从 0 搭建 Ansible 管理环境

好了,废话不多说,我们直接开始动手,先把 Ansible 的环境搭起来。

2.1 控制节点安装 Ansible

首先,Ansible 的架构是控制节点 + 被管理节点,控制节点就是你自己的工作机,你在这台机器上装 Ansible,然后用它来管理其他所有的服务器。

控制节点的安装很简单,不同的系统有不同的安装方式,我都给你列出来了,你照着自己的系统来就行:

CentOS/RHEL 系统
复制代码
# 先安装EPEL源
yum install -y epel-release
# 然后安装Ansible
yum install -y ansible
Ubuntu/Debian 系统
复制代码
# 添加Ansible的官方源
apt-add-repository --yes --update ppa:ansible/ansible
# 安装Ansible
apt install -y ansible
Mac 系统

如果你用 Mac 做控制节点,用 Homebrew 安装就行:

复制代码
brew install ansible
Windows 系统

Windows 的话,建议你用 WSL2,装个 Ubuntu 子系统,然后按照上面 Ubuntu 的方法安装就行,当然你也可以用 pip 安装:

复制代码
pip install ansible

安装完之后,你可以执行ansible --version来检查有没有安装成功,如果能输出版本号,就说明装好了:

复制代码
$ ansible --version
ansible [core 2.16.6]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.9/site-packages/ansible
  ansible collection location = /root/.ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.9.18 (main, Mar 12 2024, 13:13:32) [GCC 11.2.0]
  jinja version = 3.1.4
  libyaml = True

2.2 被管理节点的要求

说完控制节点,再说说被管理的节点,也就是你要管理的那些服务器,它们的要求真的非常低:

  1. 开启 SSH 服务,能让控制节点 SSH 连接上去就行

  2. 安装了 Python 2.6 或者更高的版本,现在的 CentOS7、Ubuntu20.04 这些默认都带了,不用你额外装

就这两个要求,没有别的了,不用装任何客户端,不用开任何额外的端口,是不是超级简单?

2.3 配置 SSH 免密登录,告别输密码

接下来,我们要配置 SSH 免密登录,不然你每次执行 Ansible 命令,都要给每台服务器输一遍密码,100 台服务器你就要输 100 次,那也太麻烦了。

配置免密登录的步骤很简单:

  1. 首先在控制节点上生成 SSH 密钥,执行这个命令,一路回车就行:

    复制代码
    ssh-keygen
  2. 然后把你的公钥拷贝到每台被管理的服务器上,用ssh-copy-id命令:

cpp 复制代码
ssh-copy-id root@192.168.1.101
ssh-copy-id root@192.168.1.102
# ... 所有的服务器都执行一遍

这里给大家提个我踩过的坑:如果你的服务器很多,一个个输太麻烦,你可以写个小循环批量执行:

cpp 复制代码
for ip in 192.168.1.{101..200}; do
  ssh-copy-id root@$ip
done

这样 100 台服务器的密钥,一下就传完了。

如果你的服务器没有ssh-copy-id命令,也可以手动拷贝: 把控制节点~/.ssh/id_rsa.pub的内容,加到被管理节点的~/.ssh/authorized_keys文件里就行。

还有一个很常见的坑:很多人配置完免密,还是要输密码,那大概率是权限不对!SSH 对权限的要求很严格,.ssh目录的权限必须是 700,authorized_keys的权限必须是 600,不然 SSH 会认为这个文件不安全,拒绝免密登录。你在被管理节点执行这两个命令就行:

cpp 复制代码
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

配置完之后,你测试一下,执行ssh root@你的服务器IP,如果不用输密码就能直接登录,就说明免密配置成功了。

2.4 主机清单 Inventory:把你的服务器分组管理

接下来,我们要配置主机清单,也就是告诉 Ansible,你有哪些服务器要管理,这些服务器怎么分组。

主机清单的配置文件,默认是/etc/ansible/hosts,你也可以自己写一个,比如在你的工作目录下建一个inventory.ini文件,这样更方便管理。

编辑这个文件,内容大概是这样的:

cpp 复制代码
# Ansible 主机清单 Inventory

# Web服务器组,所有的Web服务器都放在这里
[webservers]
192.168.1.101
192.168.1.102
192.168.1.103
192.168.1.104
...
# 这里可以把你所有的Web服务器IP都列出来,100台也没问题

# 数据库服务器组,所有的数据库服务器放在这里
[dbservers]
192.168.1.201
192.168.1.202
192.168.1.203
...

是不是很简单?你可以把你的服务器按照业务分组,比如 Web 组、DB 组、缓存组、监控组,这样以后你就可以针对某个组执行操作,比如只给 Web 组装 Nginx,只给 DB 组装 MySQL,不用每次都操作所有服务器。

2.5 测试连通性:确认所有服务器都能连上

配置完主机清单,我们来测试一下,Ansible 能不能连上所有的服务器,执行这个命令:

cpp 复制代码
ansible all -m ping -i inventory.ini

这个命令的意思是,对所有的服务器,执行 ping 模块,测试连通性。

如果一切正常的话,你会看到下面这样的输出:

看到了吗?100 台服务器,全部都返回了 pong,说明所有的服务器都能正常连接,没有问题!到这里,我们的 Ansible 环境就已经搭好了,是不是比你想象的简单多了?


三、Ansible 基础:Ad-Hoc 命令,批量操作随手来

环境搭好了,我们先从最简单的 Ad-Hoc 命令开始学,这个是日常运维用的最多的,很多临时的操作,不用写脚本,输一行命令就搞定了。

3.1 什么是 Ad-Hoc 命令?

Ad-Hoc 命令说白了,就是临时执行的命令,你不需要写任何脚本,直接在命令行输 Ansible 命令,就能批量在所有服务器上执行操作,非常适合临时的、一次性的任务。

比如你突然要查一下所有服务器的磁盘够不够,或者要重启一下所有服务器的 Nginx,这时候用 Ad-Hoc 命令,一行就搞定了,比你写 Playbook 还快。

3.2 常用 Ad-Hoc 命令实战,日常运维够用了

我给大家整理了几个日常运维最常用的 Ad-Hoc 命令,你学会这些,日常的临时操作就都够用了:

1. 批量查看所有服务器的磁盘使用率
cpp 复制代码
ansible all -m shell -a "df -h" -i inventory.ini

这个命令会在所有服务器上执行df -h,然后把结果返回给你,不用你一台台登上去看了。

2. 批量重启所有 Web 服务器的 Nginx
cpp 复制代码
ansible webservers -m service -a "name=nginx state=restarted" -i inventory.ini

针对 webservers 组,重启 Nginx 服务,一行命令,所有 Web 服务器的 Nginx 就都重启好了。

3. 批量把本地文件拷贝到所有服务器
cpp 复制代码
ansible all -m copy -a "src=/local/your/file.txt dest=/tmp/file.txt mode=0644" -i inventory.ini

把你本地的文件,批量拷贝到所有服务器的 /tmp 目录,还能顺便设置权限,太方便了。

4. 批量检查所有服务器的 8080 端口有没有打开
cpp 复制代码
ansible all -m shell -a "netstat -tlnp | grep 8080" -i inventory.ini

批量检查端口,看看你的服务有没有正常启动。

5. 批量更新所有服务器的系统包
cpp 复制代码
ansible all -m yum -a "name=* state=latest" -i inventory.ini

批量更新所有服务器的系统,一键搞定,不用你一台台更。

6. 批量重启所有服务器
cpp 复制代码
ansible all -m shell -a "reboot" -i inventory.ini

如果要重启所有服务器,也是一行命令的事。

这些命令是不是都很简单?日常运维的大部分临时操作,用这些命令都能搞定,原来要半小时的活,现在 10 秒钟就搞定了。

3.3 最常用的 5 个 Ansible 模块,学会就能解决 80% 的问题

Ansible 的模块有上千个,但是你不用都学,我告诉你,只要学会这 5 个最常用的模块,你就能解决 80% 的运维问题:

  1. shell 模块:执行 Shell 命令,这个是最常用的,你要执行什么自定义的命令,都用这个模块。

  2. copy 模块:拷贝文件,把本地的文件拷贝到远程服务器,还能设置权限。

  3. file 模块:管理文件和目录,比如创建目录、删除文件、修改权限。

  4. service 模块:管理服务,启动、停止、重启服务,设置开机自启。

  5. yum/apt 模块:安装软件包,yum 用来管理 CentOS 的包,apt 用来管理 Ubuntu 的包。

就这 5 个模块,真的够你用了,剩下的模块,你用到的时候再查就行,不用提前记。


四、核心实战:Playbook 编写,一键部署不是梦

Ad-Hoc 命令适合临时操作,但是如果是复杂的、重复的任务,比如部署服务、初始化服务器,那就要用 Playbook 了,这个是 Ansible 的核心,也是实现一键部署的关键。

4.1 Playbook 是什么?YAML 语法快速入门

Playbook 说白了,就是把你要执行的任务,写成一个 YAML 格式的文件,Ansible 会按照你写的顺序,在所有服务器上依次执行这些任务,你写完之后,只要执行一次,所有的任务就自动完成了。

YAML 语法非常简单,你只要记住这几点就行:

  1. 缩进用空格,不能用 Tab,一般用 2 个或者 4 个空格

  2. 键值对用key: value的格式,冒号后面要加空格

  3. 列表用-开头,比如- name: 安装Nginx

就这么简单,新手看一眼就能学会,根本不用花时间学语法。

4.2 第一个 Playbook:批量安装 Nginx,一步到位

我们先来写第一个 Playbook,批量给所有 Web 服务器安装 Nginx,这个是最常用的,我们一步一步来。

首先,创建一个install_nginx.yml文件,内容如下:

XML 复制代码
---
- name: 批量安装并配置Nginx
  hosts: webservers  # 针对webservers组的服务器
  become: yes        # 提权,用root用户执行,因为装软件需要root权限

  tasks:  # 任务列表,Ansible会按顺序执行这些任务
    # 任务1:安装Nginx软件包
    - name: 安装Nginx软件包
      ansible.builtin.yum:
        name: nginx
        state: present

    # 任务2:复制Nginx配置文件
    - name: 复制Nginx配置文件
      ansible.builtin.copy:
        src: ./nginx.conf  # 你本地的Nginx配置文件
        dest: /etc/nginx/nginx.conf  # 远程服务器的目标路径
        mode: '0644'  # 文件权限
      notify: 重启Nginx服务  # 如果配置文件变了,就触发重启Nginx的触发器

    # 任务3:启动Nginx服务,设置开机自启
    - name: 启动Nginx服务,并设置开机自启
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: yes

  # 触发器,只有配置文件变化的时候才会执行
  handlers:
    - name: 重启Nginx服务
      ansible.builtin.service:
        name: nginx
        state: restarted

写完之后,你的文件大概是这个样子的,在 VS Code 里还有语法高亮,非常清晰:

这个 Playbook 是什么意思呢?我给你解释一下:

  • 首先,我们针对 webservers 组的服务器,用 root 权限执行

  • 第一个任务,用 yum 安装 Nginx 软件包

  • 第二个任务,把你本地的 Nginx 配置文件,拷贝到所有服务器上,如果配置文件有变化,就触发重启 Nginx 的触发器

  • 第三个任务,启动 Nginx 服务,并且设置开机自启

  • handlers 里的触发器,只有当配置文件真的变了的时候,才会重启 Nginx,如果配置文件没变化,就不会重启,不会影响线上的服务,是不是很智能?

然后,你只要执行这个命令,就能一键安装所有 Web 服务器的 Nginx 了:

XML 复制代码
ansible-playbook install_nginx.yml -i inventory.ini

然后你就等着就行,Ansible 会自动在所有 100 台 Web 服务器上执行这些任务,原来你要一天才能干完的活,现在 10 分钟就搞定了,而且不会出错,不会漏服务器。

4.3 进阶:用 Template 模板,动态生成配置文件

刚才我们用 copy 模块拷贝配置文件,是所有服务器用同一个配置,但是如果你的服务器配置不一样,比如有的 Web 服务器端口是 80,有的是 8080,那怎么办?

这时候就要用 Template 模板了,你可以写一个模板文件,里面用变量,Ansible 会根据不同的服务器,自动替换变量,生成不同的配置文件,超级灵活。

比如,我们写一个 Nginx 的模板文件,叫nginx.conf.j2,里面的内容是这样的:

java 复制代码
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       {{ nginx_port }};  # 这里用变量,不同的服务器可以不一样
        server_name  {{ nginx_domain }};

        root   {{ nginx_root }};
        index  index.html index.htm;

        location / {
            try_files $uri $uri/ =404;
        }
    }
}

看到了吗?里面的{``{ nginx_port }}{``{ nginx_domain }}这些都是变量,然后你在 Playbook 里定义这些变量,不同的服务器用不同的变量值,Ansible 就会自动生成不同的配置文件了。

比如你的 Playbook 里可以这么写:

java 复制代码
vars: nginx_port: 80 nginx_domain: www.test.com nginx_root: /var/www/html

然后用 template 模块代替 copy 模块:

java 复制代码
- name: 部署Nginx配置文件
  ansible.builtin.template:
    src: ./nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    mode: '0644'
  notify: 重启Nginx服务
复制代码
这样,Ansible 就会自动把变量替换进去,生成对应的配置文件,是不是超级灵活?不管你的服务器有多少种不同的配置,都能搞定。

4.4 实战 2:批量安装 JDK,配置 Java 环境

装完 Nginx,我们再来装 JDK,很多 Java 项目都需要 Java 环境,我们写个 Playbook,批量给所有服务器装 JDK8:

复制代码
java 复制代码
---
- name: 批量安装JDK8
  hosts: all
  become: yes
  vars:
    jdk_version: "1.8.0_401"
    jdk_install_dir: /usr/local/jdk

  tasks:
    # 1. 创建JDK安装目录
    - name: 创建JDK安装目录
      ansible.builtin.file:
        path: "{{ jdk_install_dir }}"
        state: directory
        mode: '0755'

    # 2. 解压JDK安装包
    - name: 解压JDK安装包到目标目录
      ansible.builtin.unarchive:
        src: ./jdk-8u401-linux-x64.tar.gz  # 你本地的JDK安装包
        dest: "{{ jdk_install_dir }}"
        remote_src: no
        creates: "{{ jdk_install_dir }}/jdk1.8.0_401"  # 如果已经存在就跳过,不用重复解压

    # 3. 配置Java环境变量
    - name: 配置Java环境变量
      ansible.builtin.lineinfile:
        path: /etc/profile
        line: |
          export JAVA_HOME={{ jdk_install_dir }}/jdk1.8.0_401
          export PATH=$PATH:$JAVA_HOME/bin
        state: present

    # 4. 刷新环境变量
    - name: 刷新环境变量
      ansible.builtin.shell: source /etc/profile
      args:
        executable: /bin/bash

这个 Playbook,会自动创建目录,解压 JDK,配置环境变量,所有服务器的 Java 环境一键就装好了,原来你手动装,一台要 5 分钟,100 台要 500 分钟,现在 5 分钟就搞定了。

4.5 实战 3:批量安装 MySQL,初始化数据库

接下来,我们来装 MySQL,这个稍微复杂一点,但是用 Playbook,也能一键搞定:

java 复制代码
---
- name: 批量安装MySQL8.0
  hosts: dbservers
  become: yes
  vars:
    mysql_root_password: "YourStrongRootPassword123!"  # 你的root密码,改成自己的

  tasks:
    # 1. 安装MySQL的Yum源
    - name: 安装MySQL Yum源
      ansible.builtin.yum:
        name: https://dev.mysql.com/get/mysql80-community-release-el7-7.noarch.rpm
        state: present

    # 2. 安装MySQL服务器
    - name: 安装MySQL社区版服务器
      ansible.builtin.yum:
        name: mysql-community-server
        state: present

    # 3. 启动MySQL服务,设置开机自启
    - name: 启动MySQL服务,并设置开机自启
      ansible.builtin.service:
        name: mysqld
        state: started
        enabled: yes

    # 4. 等待MySQL初始化完成
    - name: 等待MySQL初始化完成
      ansible.builtin.wait_for:
        path: /var/log/mysqld.log
        search_regex: 'root@localhost'
        timeout: 300

    # 5. 获取MySQL的临时密码
    - name: 获取MySQL临时密码
      ansible.builtin.shell: grep 'temporary password' /var/log/mysqld.log | awk '{print $NF}'
      register: mysql_temp_password

    # 6. 修改root用户的密码,授权远程访问
    - name: 修改root用户密码
      ansible.builtin.mysql_user:
        name: root
        host: '%'
        password: "{{ mysql_root_password }}"
        login_password: "{{ mysql_temp_password.stdout }}"
        login_user: root
        check_implicit_admin: yes
        priv: '*.*:ALL,GRANT'

这个 Playbook,从安装源,到装服务,到初始化,到改密码,一步到位,所有的数据库服务器,一键就装好了,不用你手动去记那些复杂的初始化步骤,Ansible 都帮你做了。


五、进阶玩法:Roles 角色,让你的代码复用 100%

你可能会说,我写了 Nginx 的 Playbook,写了 MySQL 的,写了 JDK 的,以后我新搭环境,要把这些代码都复制粘贴吗?那也太麻烦了。

当然不用,这时候我们就要用 Roles 了,Roles 就是把你的 Playbook 拆成独立的、可复用的角色,你写一次,以后随便用。

5.1 为什么要用 Roles?

Roles 的好处就是复用性,你把 Nginx 封装成一个角色,把 MySQL 封装成一个,把 JDK 封装成一个,以后你要部署新的服务器,只要调用这些角色就行,不用再重写一遍代码,一次编写,到处用,不管你是 1 台服务器还是 100 台,都一样。

而且用 Roles,你的目录结构会非常清晰,方便维护,别人看你的代码,一眼就知道哪个角色是干嘛的。

5.2 搭建 Roles 目录结构

首先,我们先创建 Roles 的目录结构,大概是这样的:

java 复制代码
project/
├── inventory.ini  # 主机清单
├── site.yml       # 主Playbook
└── roles/         # 角色目录
    ├── nginx/     # Nginx角色
    │   ├── tasks/
    │   │   └── main.yml
    │   ├── handlers/
    │   │   └── main.yml
    │   ├── templates/
    │   │   └── nginx.conf.j2
    │   ├── vars/
    │   │   └── main.yml
    │   └── defaults/
    │       └── main.yml
    ├── mysql/     # MySQL角色
    └── jdk/      # JDK角色

每个角色下面,都有自己的 tasks、handlers、templates、vars,和我们之前写的 Playbook 是一样的,只是拆成了独立的目录。

5.3 把 Nginx 封装成 Role,一次编写到处用

比如,我们把之前写的 Nginx 的 Playbook,拆成 Nginx 角色:

首先,roles/nginx/tasks/main.yml,就是我们之前的任务:

java 复制代码
# tasks file for nginx
- name: 安装Nginx软件包
  ansible.builtin.yum:
    name: nginx
    state: present

- name: 部署Nginx配置文件
  ansible.builtin.template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    mode: '0644'
  notify: 重启Nginx服务

- name: 启动Nginx服务,并设置开机自启
  ansible.builtin.service:
    name: nginx
    state: started
    enabled: yes

然后roles/nginx/handlers/main.yml,就是触发器:

java 复制代码
# handlers file for nginx
- name: 重启Nginx服务
  ansible.builtin.service:
    name: nginx
    state: restarted

然后把模板文件放到roles/nginx/templates/nginx.conf.j2,变量放到roles/nginx/vars/main.yml

这样,Nginx 的角色就写好了,以后你要用的时候,只要在你的主 Playbooksite.yml里调用它就行:

java 复制代码
---
- name: 部署Web服务器
  hosts: webservers
  become: yes
  roles:
    - jdk
    - nginx

看到了吗?只要两行,就自动把 JDK 和 Nginx 都装好了,超级简单!如果你要部署数据库服务器,就调用 mysql 角色:

java 复制代码
---
- name: 部署数据库服务器
  hosts: dbservers
  become: yes
  roles:
    - mysql

是不是太方便了?一次写好角色,以后不管什么时候用,直接调用就行,不用再重写代码,复用率 100%。

而且,你不用自己写所有的角色,Ansible Galaxy 上有无数现成的角色,比如你要装 Redis,要装 Elasticsearch,直接去 Galaxy 上下载别人写好的角色,直接用就行,不用自己从零写。


六、企业级实战案例:百台服务器一键初始化

讲了这么多基础的,我们来个企业级的实战案例,就是我之前做的,新买了 100 台服务器,要做初始化,原来手动做要一周,用 Ansible,一天就搞定了。

6.1 案例背景:新买的服务器要做哪些初始化?

新买的服务器,默认的配置都是不能直接用的,要做很多初始化的操作:

  1. 关闭防火墙,关闭 SELinux

  2. 修改时区为上海时区

  3. 安装常用的工具,比如 wget、curl、vim、net-tools

  4. 添加运维用户,配置 sudo 权限

  5. 配置 SSH,禁止 root 远程登录,修改 SSH 端口

  6. 更新系统补丁

  7. 配置时间同步

这些操作,每台都要做,100 台的话,手动做要好久,但是用 Ansible,一键就搞定了。

6.2 编写初始化 Playbook,一键完成所有配置

我们来写这个初始化的 Playbook:

复制代码
java 复制代码
---
- name: 服务器初始化配置
  hosts: all
  become: yes

  tasks:
    # 1. 关闭防火墙
    - name: 关闭防火墙
      ansible.builtin.service:
        name: firewalld
        state: stopped
        enabled: no

    # 2. 关闭SELinux
    - name: 关闭SELinux
      ansible.builtin.selinux:
        state: disabled

    # 3. 修改时区为上海
    - name: 修改时区为亚洲/上海
      ansible.builtin.timezone:
        name: Asia/Shanghai

    # 4. 安装常用工具
    - name: 安装常用运维工具
      ansible.builtin.yum:
        name:
          - wget
          - curl
          - vim
          - net-tools
          - lsof
          - iotop
          - htop
          - iftop
        state: present

    # 5. 添加运维用户
    - name: 添加运维普通用户
      ansible.builtin.user:
        name: ops
        state: present
        shell: /bin/bash

    # 6. 给ops用户配置sudo免密权限
    - name: 给ops用户配置sudo权限
      ansible.builtin.lineinfile:
        path: /etc/sudoers
        line: 'ops ALL=(ALL) NOPASSWD: ALL'
        validate: 'visudo -cf %s'

    # 7. 配置SSH,禁止root登录
    - name: 禁止root远程登录SSH
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^#PermitRootLogin'
        line: 'PermitRootLogin no'
      notify: 重启SSH服务

    # 8. 配置时间同步
    - name: 安装chrony时间同步服务
      ansible.builtin.yum:
        name: chrony
        state: present

    - name: 启动chrony服务,设置开机自启
      ansible.builtin.service:
        name: chronyd
        state: started
        enabled: yes

  handlers:
    - name: 重启SSH服务
      ansible.builtin.service:
        name: sshd
        state: restarted

就这个 Playbook,执行一下,所有 100 台服务器的初始化,一键就完成了,原来要一周的活,现在 10 分钟就搞定了,而且所有服务器的配置都是统一的,不会出现这台和那台配置不一样的情况,太爽了。

6.3 批量巡检:每天 1 分钟,掌握所有服务器状态

除了部署,日常的巡检也是运维的大活,每天要查所有服务器的 CPU、内存、磁盘,有没有异常,原来要一台台看,现在用 Ansible,批量巡检,1 分钟就搞定。

我们写一个巡检的 Playbook,批量收集所有服务器的状态:

java 复制代码
---
- name: 批量服务器巡检
  hosts: all
  become: yes
  gather_facts: yes

  tasks:
    # 收集CPU使用率
    - name: 获取CPU使用率
      ansible.builtin.shell: top -bn1 | grep Cpu | awk '{print $2}' | cut -d'%' -f1
      register: cpu_usage

    # 收集内存使用率
    - name: 获取内存使用率
      ansible.builtin.shell: free | grep Mem | awk '{print $3/$2 * 100.0}'
      register: mem_usage

    # 收集磁盘使用率
    - name: 获取磁盘使用率
      ansible.builtin.shell: df -h | grep /dev/vda1 | awk '{print $5}' | cut -d'%' -f1
      register: disk_usage

    # 输出结果
    - name: 输出巡检结果
      ansible.builtin.debug:
        msg: "服务器 {{ inventory_hostname }} CPU: {{ cpu_usage.stdout }}% 内存: {{ mem_usage.stdout | float | round(2) }}% 磁盘: {{ disk_usage.stdout }}%"

执行完这个 Playbook,你就会得到所有服务器的巡检结果,汇总起来就是这样的:

所有服务器的状态一目了然,哪台服务器磁盘满了,哪台 CPU 过高,一眼就能看到,原来要半小时的巡检,现在 1 分钟就搞定了,每天花 1 分钟,就能掌握所有服务器的状态,太省心了。


七、我踩过的坑:常见问题排错指南

用 Ansible 这几年,我踩了不少坑,这里给大家整理了最常见的几个问题,大家遇到的时候,直接就能解决:

  1. 免密登录失败,还是要输密码 这个 90% 是权限的问题,.ssh 目录的权限必须是 700,authorized_keys 的权限必须是 600,SSH 对权限要求很严格,权限不对就会拒绝免密,执行这两个命令就行:

    java 复制代码
    chmod 700 ~/.ssh
    chmod 600 ~/.ssh/authorized_keys
  2. Ansible 执行太慢,100 台要跑好久 默认情况下,Ansible 的并行数是 5,也就是一次只处理 5 台服务器,你可以改大一点,编辑/etc/ansible/ansible.cfg,把forks = 5改成forks = 50,这样一次就能处理 50 台,速度直接快 10 倍,还有,如果你不需要收集 facts 的话,可以加gather_facts: no,也能快很多。

  3. Playbook 执行报错,不知道哪里错了 写完 Playbook,先执行ansible-playbook --check your_playbook.yml,这个是预执行,不会真的改服务器,就能帮你检查语法和错误,还有,加-v参数,能看到详细的执行日志,比如ansible-playbook your_playbook.yml -v,出错了就能看到详细的错误信息。

  4. CentOS 和 Ubuntu 的兼容问题 如果你同时管理 CentOS 和 Ubuntu 的服务器,安装命令不一样,yum 和 apt,这时候你可以用ansible_os_family来判断系统,然后执行不同的任务:

    java 复制代码
    - name: 安装Nginx on CentOS
      ansible.builtin.yum:
        name: nginx
        state: present
      when: ansible_os_family == 'RedHat'
    
    - name: 安装Nginx on Ubuntu
      ansible.builtin.apt:
        name: nginx
        state: present
      when: ansible_os_family == 'Debian'

    这样就自动兼容不同的系统了。

  5. 普通用户执行,权限不够 很多时候,你用普通用户连接服务器,装软件需要 root 权限,这时候只要在 Playbook 里加become: yes就行,Ansible 会自动用 sudo 提权,前提是你的用户有 sudo 权限。


八、总结:自动化运维,解放你的双手

到这里,这篇文章就差不多了,我们从 0 开始,搭了 Ansible 的环境,学了 Ad-Hoc 命令,学了 Playbook,学了 Roles,还做了企业级的实战案例,相信你跟着做下来,已经能把 Ansible 用起来了。

其实 Ansible 真的没有那么难,它就是一个帮你把重复的手动劳动自动化的工具,原来你要一天干的活,现在 10 分钟就搞定,原来你要熬夜加班,现在写完脚本,点一下执行,就能去喝茶了。

我现在管理 200 多台服务器,日常的部署、更新、巡检,都用 Ansible,原来要几个人干的活,我一个人就搞定了,再也不用怕漏了服务器,再也不用怕输错命令,再也不用熬夜加班了。

希望这篇文章能帮到你,也希望你能早点用上自动化运维,把自己从重复的劳动里解放出来,去做更有价值的事。

最后,给大家放几个有用的链接,大家可以去看看:

如果这篇文章对你有帮助,欢迎点赞、收藏、关注,我后面还会分享更多运维自动化的干货~


标签: #运维 #Ansible #Linux #自动化运维 #批量部署 #Nginx #MySQL #Java #服务器

相关推荐
笨拙的老猴子1 小时前
Git 翻车现场:那些年我 git push --force 毁掉的东西
git·代码管理
GitCode官方2 小时前
投稿|Git + Docker 零基础入门攻略
git·docker·容器
_可乐无糖3 小时前
Windows本地安装git
git
2301_780029043 小时前
.gitignore不可以忽略文件问题
git·gitee·开源
用户824451499703 小时前
点到线段距离怎么求导?一个被忽视的"硬边界"微分难题!
github
用户824451499703 小时前
一行代码让 sign()、round() 可微:sll-core 源码解读与边界梯度机制。
github
无限进步_3 小时前
【C++】从红黑树到 map 和 set:封装设计与迭代器实现
开发语言·数据结构·数据库·c++·windows·github·visual studio
饕餮争锋3 小时前
PR中的P为什么是pull而非push?
git