跳转到内容
搜索 RunEntLinux 文档

仅搜索 RunEntLinux 通用文档,各发行版文档使用各自的搜索入口。

    浏览当前文档目录

    Ansible 自动化

    Ansible 是一款无代理(Agentless)的 IT 自动化工具,通过 SSH 连接远程主机并执行配置管理、应用部署和任务编排。它使用 YAML 格式编写 Playbook,学习曲线平缓,是 Enterprise Linux 环境中最流行的自动化方案之一。

    Ansible 只需要安装在控制节点(你执行命令的机器)上,被管理的远程主机不需要安装任何额外软件,只需要有 SSH 和 Python。

    Terminal window
    # 方法一:通过 DNF 安装(推荐)
    sudo dnf install -y epel-release
    sudo dnf install -y ansible-core
    # 方法二:通过 pip 安装(获取最新版本)
    sudo dnf install -y python3 python3-pip
    pip3 install --user ansible
    # 验证安装
    ansible --version

    Ansible 的模块以集合(Collection)形式分发:

    Terminal window
    # 安装常用集合
    ansible-galaxy collection install ansible.posix
    ansible-galaxy collection install community.general
    ansible-galaxy collection install community.mysql
    # 查看已安装集合
    ansible-galaxy collection list

    Inventory 文件定义了 Ansible 要管理的主机和分组信息。

    创建 /etc/ansible/hosts 或项目目录下的 inventory.ini:

    # 单独的主机
    10.0.0.100
    # 定义组
    [webservers]
    web01.example.com
    web02.example.com
    web03.example.com
    [dbservers]
    db01.example.com ansible_port=2222
    db02.example.com
    [appservers]
    app[01:05].example.com # app01 到 app05
    # 组变量
    [webservers:vars]
    ansible_user=ops
    ansible_become=true
    http_port=80
    [dbservers:vars]
    ansible_user=dba
    ansible_become=true
    # 父组(包含多个子组)
    [production:children]
    webservers
    dbservers
    appservers
    inventory.yml
    all:
    children:
    webservers:
    hosts:
    web01.example.com:
    web02.example.com:
    vars:
    ansible_user: ops
    http_port: 80
    dbservers:
    hosts:
    db01.example.com:
    ansible_port: 2222
    db02.example.com:
    vars:
    ansible_user: dba
    production:
    children:
    webservers:
    dbservers:
    Terminal window
    # 查看所有主机
    ansible-inventory -i inventory.yml --list
    # 以图形方式展示
    ansible-inventory -i inventory.yml --graph
    # 查看特定主机的变量
    ansible-inventory -i inventory.yml --host web01.example.com

    Ad-Hoc 命令适合执行一次性的快速操作。

    Terminal window
    # 测试所有主机连通性
    ansible all -i inventory.yml -m ping
    # 查看远程主机信息
    ansible webservers -i inventory.yml -m setup
    # 执行 Shell 命令
    ansible all -i inventory.yml -m shell -a "uptime"
    ansible all -i inventory.yml -m shell -a "free -h"
    ansible all -i inventory.yml -m shell -a "df -h /"
    # 管理软件包
    ansible webservers -i inventory.yml -m dnf -a "name=nginx state=present" --become
    ansible webservers -i inventory.yml -m dnf -a "name=* state=latest" --become
    # 管理服务
    ansible webservers -i inventory.yml -m service -a "name=nginx state=started enabled=yes" --become
    # 复制文件
    ansible webservers -i inventory.yml -m copy -a "src=/tmp/app.conf dest=/etc/app.conf owner=root mode=0644" --become
    # 管理用户
    ansible all -i inventory.yml -m user -a "name=deploy state=present groups=wheel" --become
    # 重启主机
    ansible dbservers -i inventory.yml -m reboot --become
    # 限制执行范围
    ansible webservers -i inventory.yml -m shell -a "hostname" --limit web01.example.com
    # 并行控制(默认 5 个并行)
    ansible all -i inventory.yml -m ping -f 20

    Playbook 是 Ansible 的核心配置文件,使用 YAML 格式定义一系列有序的任务。

    # site.yml - 基础 Web 服务器配置
    ---
    - name: 配置 Web 服务器
    hosts: webservers
    become: true
    vars:
    http_port: 80
    doc_root: /var/www/myapp
    tasks:
    - name: 安装必要软件包
    ansible.builtin.dnf:
    name:
    - nginx
    - firewalld
    - vim-enhanced
    state: present
    - name: 创建网站目录
    ansible.builtin.file:
    path: "{{ doc_root }}"
    state: directory
    owner: nginx
    group: nginx
    mode: '0755'
    - name: 部署首页
    ansible.builtin.copy:
    content: |
    <!DOCTYPE html>
    <html>
    <head><title>Welcome</title></head>
    <body><h1>Server: {{ ansible_hostname }}</h1></body>
    </html>
    dest: "{{ doc_root }}/index.html"
    owner: nginx
    group: nginx
    mode: '0644'
    - name: 启动并启用 Nginx
    ansible.builtin.service:
    name: nginx
    state: started
    enabled: true
    - name: 启动并启用 Firewalld
    ansible.builtin.service:
    name: firewalld
    state: started
    enabled: true
    - name: 开放 HTTP 端口
    ansible.posix.firewalld:
    service: http
    permanent: true
    state: enabled
    immediate: true
    Terminal window
    # 执行 Playbook
    ansible-playbook -i inventory.yml site.yml
    # 模拟运行(不实际执行变更)
    ansible-playbook -i inventory.yml site.yml --check
    # 显示详细输出
    ansible-playbook -i inventory.yml site.yml -v
    ansible-playbook -i inventory.yml site.yml -vvv
    # 限制在特定主机上运行
    ansible-playbook -i inventory.yml site.yml --limit web01.example.com
    # 从指定任务开始执行
    ansible-playbook -i inventory.yml site.yml --start-at-task="启动并启用 Nginx"
    # 逐步确认执行
    ansible-playbook -i inventory.yml site.yml --step
    # 指定额外变量
    ansible-playbook -i inventory.yml site.yml -e "http_port=8080"
    tasks:
    # 安装单个软件包
    - name: 安装 Nginx
    ansible.builtin.dnf:
    name: nginx
    state: present
    # 安装多个软件包
    - name: 安装开发工具
    ansible.builtin.dnf:
    name:
    - gcc
    - make
    - python3-devel
    state: present
    # 安装指定版本
    - name: 安装指定版本
    ansible.builtin.dnf:
    name: nginx-1.20.1
    state: present
    # 更新所有软件包
    - name: 系统更新
    ansible.builtin.dnf:
    name: '*'
    state: latest
    # 安装软件包组
    - name: 安装开发工具组
    ansible.builtin.dnf:
    name: '@Development Tools'
    state: present
    # 卸载软件包
    - name: 移除旧软件
    ansible.builtin.dnf:
    name: httpd
    state: absent
    tasks:
    - name: 启动并启用服务
    ansible.builtin.service:
    name: nginx
    state: started
    enabled: true
    - name: 重启服务
    ansible.builtin.service:
    name: nginx
    state: restarted
    - name: 重新加载服务配置
    ansible.builtin.service:
    name: nginx
    state: reloaded
    - name: 停止并禁用服务
    ansible.builtin.service:
    name: postfix
    state: stopped
    enabled: false
    tasks:
    # 从控制节点复制文件
    - name: 复制配置文件
    ansible.builtin.copy:
    src: files/nginx.conf
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'
    backup: true
    notify: 重载 Nginx
    # 直接写入内容
    - name: 写入配置
    ansible.builtin.copy:
    content: |
    server {
    listen 80;
    server_name {{ ansible_fqdn }};
    root /var/www/html;
    }
    dest: /etc/nginx/conf.d/default.conf
    owner: root
    group: root
    mode: '0644'

    Jinja2 模板是 Ansible 最强大的功能之一,可以根据变量动态生成配置文件。

    创建模板文件 templates/nginx.conf.j2:

    # Ansible managed - Do not edit manually
    worker_processes {{ ansible_processor_vcpus }};
    events {
    worker_connections {{ nginx_worker_connections | default(1024) }};
    }
    http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    sendfile on;
    keepalive_timeout 65;
    {% for vhost in virtual_hosts %}
    server {
    listen {{ vhost.port | default(80) }};
    server_name {{ vhost.server_name }};
    root {{ vhost.doc_root }};
    {% if vhost.ssl | default(false) %}
    listen 443 ssl;
    ssl_certificate {{ vhost.ssl_cert }};
    ssl_certificate_key {{ vhost.ssl_key }};
    {% endif %}
    }
    {% endfor %}
    }

    在 Playbook 中使用模板:

    - name: 配置 Web 服务器
    hosts: webservers
    become: true
    vars:
    nginx_worker_connections: 2048
    virtual_hosts:
    - server_name: app.example.com
    doc_root: /var/www/app
    port: 80
    - server_name: api.example.com
    doc_root: /var/www/api
    port: 8080
    tasks:
    - name: 部署 Nginx 配置
    ansible.builtin.template:
    src: templates/nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'
    validate: nginx -t -c %s
    notify: 重载 Nginx
    handlers:
    - name: 重载 Nginx
    ansible.builtin.service:
    name: nginx
    state: reloaded
    tasks:
    # 文件和目录管理
    - name: 创建目录
    ansible.builtin.file:
    path: /data/app
    state: directory
    owner: app
    group: app
    mode: '0755'
    - name: 创建符号链接
    ansible.builtin.file:
    src: /data/app/current
    dest: /var/www/app
    state: link
    # 管理计划任务
    - name: 添加定时备份任务
    ansible.builtin.cron:
    name: "数据库备份"
    minute: "0"
    hour: "2"
    job: "/usr/local/bin/backup.sh >> /var/log/backup.log 2>&1"
    user: root
    # 管理 SELinux 布尔值
    - name: 允许 Nginx 连接网络
    ansible.posix.seboolean:
    name: httpd_can_network_connect
    state: true
    persistent: true
    # 管理 sysctl 参数
    - name: 设置内核参数
    ansible.posix.sysctl:
    name: net.ipv4.ip_forward
    value: '1'
    sysctl_set: true
    reload: true
    # 从 URL 下载文件
    - name: 下载应用包
    ansible.builtin.get_url:
    url: https://example.com/releases/app-1.0.tar.gz
    dest: /tmp/app-1.0.tar.gz
    checksum: sha256:abc123...
    # 解压文件
    - name: 解压应用
    ansible.builtin.unarchive:
    src: /tmp/app-1.0.tar.gz
    dest: /opt/
    remote_src: true
    tasks:
    - name: 仅在 AlmaLinux 上执行
    ansible.builtin.dnf:
    name: almalinux-release
    state: latest
    when: ansible_distribution == "AlmaLinux"
    - name: 仅在 EL9 上执行
    ansible.builtin.debug:
    msg: "Running on EL9"
    when: ansible_distribution_major_version == "9"
    - name: 当服务存在时重启
    ansible.builtin.service:
    name: nginx
    state: restarted
    when: "'nginx' in ansible_facts.packages"
    tasks:
    - name: 创建多个用户
    ansible.builtin.user:
    name: "{{ item.name }}"
    groups: "{{ item.groups }}"
    state: present
    loop:
    - { name: 'alice', groups: 'wheel' }
    - { name: 'bob', groups: 'developers' }
    - { name: 'charlie', groups: 'developers' }
    - name: 启动多个服务
    ansible.builtin.service:
    name: "{{ item }}"
    state: started
    enabled: true
    loop:
    - nginx
    - firewalld
    - fail2ban

    Handlers 是一种特殊任务,仅在被 notify 触发时才执行,且在所有任务执行完毕后才运行:

    - name: 配置服务器
    hosts: webservers
    become: true
    tasks:
    - name: 更新 Nginx 配置
    ansible.builtin.template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    notify:
    - 验证 Nginx 配置
    - 重载 Nginx
    - name: 更新 sysctl 配置
    ansible.builtin.copy:
    src: sysctl.conf
    dest: /etc/sysctl.d/99-custom.conf
    notify: 应用 sysctl
    handlers:
    - name: 验证 Nginx 配置
    ansible.builtin.command: nginx -t
    - name: 重载 Nginx
    ansible.builtin.service:
    name: nginx
    state: reloaded
    - name: 应用 sysctl
    ansible.builtin.command: sysctl --system

    Role 是组织 Playbook 的最佳实践,将相关的任务、变量、模板、文件等按功能归类到标准化目录结构中。

    Terminal window
    # 使用 ansible-galaxy 创建 role 骨架
    ansible-galaxy role init roles/webserver
    # 生成的目录结构
    tree roles/webserver/
    # roles/webserver/
    # ├── defaults/
    # │ └── main.yml # 默认变量(优先级最低)
    # ├── files/ # 静态文件
    # ├── handlers/
    # │ └── main.yml # Handlers
    # ├── meta/
    # │ └── main.yml # Role 元数据和依赖
    # ├── tasks/
    # │ └── main.yml # 主要任务
    # ├── templates/ # Jinja2 模板
    # └── vars/
    # └── main.yml # 角色变量(优先级较高)
    roles/webserver/defaults/main.yml
    ---
    nginx_port: 80
    nginx_worker_connections: 1024
    doc_root: /var/www/html
    roles/webserver/tasks/main.yml
    ---
    - name: 安装 Nginx
    ansible.builtin.dnf:
    name: nginx
    state: present
    - name: 部署 Nginx 配置
    ansible.builtin.template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    notify: 重载 Nginx
    - name: 创建网站目录
    ansible.builtin.file:
    path: "{{ doc_root }}"
    state: directory
    owner: nginx
    group: nginx
    mode: '0755'
    - name: 启动 Nginx
    ansible.builtin.service:
    name: nginx
    state: started
    enabled: true
    roles/webserver/handlers/main.yml
    ---
    - name: 重载 Nginx
    ansible.builtin.service:
    name: nginx
    state: reloaded
    site.yml
    ---
    - name: 配置 Web 服务器
    hosts: webservers
    become: true
    roles:
    - webserver
    - name: 配置数据库服务器
    hosts: dbservers
    become: true
    roles:
    - role: database
    vars:
    db_port: 3306
    Terminal window
    # 搜索 role
    ansible-galaxy role search nginx --platforms EL # 顶层 search 在 ansible-core 2.10 起已移除
    # 安装 role
    ansible-galaxy role install geerlingguy.nginx
    # 从 requirements 文件批量安装
    cat > requirements.yml << 'EOF'
    ---
    roles:
    - name: geerlingguy.nginx
    - name: geerlingguy.mysql
    collections:
    - name: community.general
    - name: ansible.posix
    EOF
    ansible-galaxy install -r requirements.yml
    ansible-project/
    ├── ansible.cfg # Ansible 配置
    ├── inventory/
    │ ├── production.yml # 生产环境主机
    │ └── staging.yml # 测试环境主机
    ├── group_vars/
    │ ├── all.yml # 所有主机的变量
    │ ├── webservers.yml # Web 服务器组变量
    │ └── dbservers.yml # 数据库组变量
    ├── host_vars/
    │ └── web01.example.com.yml
    ├── roles/
    │ ├── common/
    │ ├── webserver/
    │ └── database/
    ├── site.yml # 主 Playbook
    ├── webservers.yml
    └── dbservers.yml
    # ansible.cfg
    [defaults]
    inventory = inventory/production.yml
    remote_user = ops
    roles_path = roles
    host_key_checking = False
    retry_files_enabled = False
    stdout_callback = yaml
    [privilege_escalation]
    become = True
    become_method = sudo
    become_ask_pass = False
    Terminal window
    # 加密文件
    ansible-vault encrypt group_vars/dbservers.yml
    # 编辑加密文件
    ansible-vault edit group_vars/dbservers.yml
    # 解密文件
    ansible-vault decrypt group_vars/dbservers.yml
    # 运行包含加密数据的 Playbook
    ansible-playbook site.yml --ask-vault-pass
    # 使用密码文件
    ansible-playbook site.yml --vault-password-file ~/.vault_pass

    Ansible 是 Enterprise Linux 运维自动化的利器,从简单的 Ad-Hoc 命令到复杂的多角色 Playbook,都能高效地管理大规模服务器集群。结合 Cloud-Init 进行初始配置、再用 Ansible 完成后续部署是非常经典的工作流。