Ansible之Playbook(六):实例部署实战

OpenEuler系统全栈自动化部署实战

一、前言

在之前的Playbook系列文章中,我们学习了Ansible的基础语法、变量、条件判断、循环和Handlers等核心概念。本文将通过一个综合性的实战案例,演示如何使用Ansible Playbook在OpenEuler系统上一键部署一个完整的企业级服务集群,包括:远程获取SSH密钥认证、部署Nginx Web服务、搭建Keepalived高可用反向代理集群、配置DNS域名解析服务以及DHCP动态IP分配服务。

本文将按照CSDN博客的完整格式,带你从环境规划、目录结构设计到Playbook编写,一步步完成整个自动化部署项目。

二、环境规划

2.1 主机清单(Inventory)

在Ansible控制节点192.168.64.128上,编辑/etc/ansible/hosts文件:

bash 复制代码
[all:vars]
ansible_user=root
ansible_password=openeuler123
# ansible_ssh_private_key_file=/root/.ssh/id_rsa  # 密钥认证后可切换为私钥认证

[webservers]
192.168.64.100
192.168.64.101

[loadbalancers]
192.168.64.200  priority=100  state=MASTER  vip=192.168.64.250
192.168.64.201  priority=90   state=BACKUP  vip=192.168.64.250

[dnsserver]
192.168.64.108

[dhcpserver]
192.168.64.109

2.2 服务器角色规划

IP地址 主机名建议 角色说明
192.168.64.100 web01 Nginx Web服务器(主)
192.168.64.101 web02 Nginx Web服务器(备)
192.168.64.108 dns01 DNS域名解析服务器
192.168.64.109 dhcp01 DHCP动态IP分配服务器
192.168.64.200 lb01 Keepalived + Nginx反向代理(Master)
192.168.64.201 lb02 Keepalived + Nginx反向代理(Backup)
192.168.64.128 ansible Ansible控制节点

2.3 VIP规划

  • VIP地址:192.168.64.250

  • 作用:Keepalived虚拟IP,作为整个集群的统一入口,客户端访问此VIP即可获得Nginx反向代理服务

三、项目目录结构

在Ansible控制节点上创建如下目录结构:

bash 复制代码
mkdir -p /ansible/playbooks/roles/{common,nginx,keepalived,dns,dhcp}/{tasks,handlers,templates,files,vars}
mkdir -p /ansible/playbooks/{group_vars,host_vars}

完整目录结构:

bash 复制代码
/ansible/playbooks/
├── site.yml                      # 主入口Playbook
├── ssh_key_distribution.yml      # SSH密钥分发Playbook
├── inventory                     # 主机清单文件
├── group_vars/
│   └── all.yml                   # 全局变量
├── roles/
│   ├── common/
│   │   └── tasks/
│   │       └── main.yml          # 通用任务(防火墙、SELinux等)
│   ├── nginx/
│   │   ├── tasks/
│   │   │   └── main.yml          # Nginx安装配置任务
│   │   ├── handlers/
│   │   │   └── main.yml          # Nginx服务重启处理
│   │   ├── templates/
│   │   │   ├── nginx.conf.j2     # Nginx主配置模板
│   │   │   └── index.html.j2     # Web页面模板
│   │   └── vars/
│   │       └── main.yml
│   ├── keepalived/
│   │   ├── tasks/
│   │   │   └── main.yml
│   │   ├── handlers/
│   │   │   └── main.yml
│   │   └── templates/
│   │       ├── keepalived.conf.j2
│   │       └── nginx-lb.conf.j2  # 反向代理配置模板
│   ├── dns/
│   │   ├── tasks/
│   │   │   └── main.yml
│   │   └── templates/
│   │       ├── named.conf.j2
│   │       └── zone.db.j2
│   └── dhcp/
│       ├── tasks/
│       │   └── main.yml
│       └── templates/
│           └── dhcpd.conf.j2
└── files/
    └── id_rsa.pub                # Ansible控制节点的SSH公钥

四、SSH密钥远程分发

在执行所有自动化部署任务之前,首先需要将Ansible控制节点的SSH公钥分发到所有目标主机,实现免密登录。这一步是后续Playbook顺畅执行的基础。

4.1 生成SSH密钥对

在Ansible控制节点上执行:

bash 复制代码
ssh-keygen -t rsa -b 4096 -N "" -f ~/.ssh/id_rsa

4.2 编写SSH密钥分发Playbook

创建/ansible/playbooks/ssh_key_distribution.yml

bash 复制代码
---
- name: 分发SSH公钥到所有目标主机
  hosts: all
  gather_facts: no
  vars:
    ansible_user: root
    ansible_password: "openeuler123"  # 首次连接使用的密码
    
  tasks:
    - name: 确保目标主机.ssh目录存在
      ansible.builtin.file:
        path: /root/.ssh
        state: directory
        owner: root
        group: root
        mode: '0700'
      
    - name: 读取控制节点的SSH公钥
      ansible.builtin.slurp:
        src: /root/.ssh/id_rsa.pub
      register: ssh_pub_key
      delegate_to: localhost
      run_once: true
      
    - name: 将公钥添加到目标主机的authorized_keys
      ansible.posix.authorized_key:
        user: root
        state: present
        key: "{{ ssh_pub_key.content | b64decode }}"
        exclusive: no
        manage_dir: yes
      
    - name: 关闭SSH密码认证(可选,提高安全性)
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^PasswordAuthentication'
        line: 'PasswordAuthentication no'
        state: present
      notify: restart sshd
      
  handlers:
    - name: restart sshd
      ansible.builtin.service:
        name: sshd
        state: restarted

执行命令

bash 复制代码
ansible-playbook /ansible/playbooks/ssh_key_distribution.yml

注意authorized_key模块位于ansible.posix集合中,如果未安装,先执行:

bash

复制代码
ansible-galaxy collection install ansible.posix

密钥分发成功后,可以将inventory中的密码认证注释掉,改用私钥认证:

bash 复制代码
[all:vars]
ansible_user=root
ansible_ssh_private_key_file=/root/.ssh/id_rsa
# ansible_password=openeuler123  # 已注释

五、全局变量配置

创建/ansible/playbooks/group_vars/all.yml

bash 复制代码
---
# 网络配置
domain_name: "example.local"
dns_server: "192.168.64.108"
dhcp_server: "192.168.64.109"
gateway: "192.168.64.2"
netmask: "255.255.255.0"
network: "192.168.64.0"

# Nginx Web配置
nginx_version: "1.20.1"
web_domain: "www.example.local"
web_root: "/usr/share/nginx/html"

# Keepalived配置
vip_address: "192.168.64.250"
vip_interface: "ens33"           # 根据实际网卡修改
vrid: 51

# DNS配置
dns_zone: "example.local"
dns_network_reverse: "64.168.192"
dns_forwarders:
  - "114.114.114.114"
  - "8.8.8.8"

# DHCP配置
dhcp_subnet: "192.168.64.0"
dhcp_netmask: "255.255.255.0"
dhcp_range_start: "192.168.64.150"
dhcp_range_end: "192.168.64.200"
dhcp_lease_time: 3600
dhcp_max_lease_time: 7200

六、通用角色(common)

创建/ansible/playbooks/roles/common/tasks/main.yml

bash 复制代码
---
- name: 关闭SELinux
  ansible.builtin.selinux:
    state: disabled

- name: 停止并禁用firewalld
  ansible.builtin.service:
    name: firewalld
    state: stopped
    enabled: no
  ignore_errors: yes

- name: 安装基础工具包
  ansible.builtin.dnf:
    name:
      - vim
      - wget
      - curl
      - net-tools
      - lsof
      - tcpdump
      - bash-completion
    state: present

- name: 配置hosts文件
  ansible.builtin.lineinfile:
    path: /etc/hosts
    line: "{{ item }}"
    state: present
  loop:
    - "192.168.64.100 web01 web01.example.local"
    - "192.168.64.101 web02 web02.example.local"
    - "192.168.64.108 dns01 dns01.example.local"
    - "192.168.64.109 dhcp01 dhcp01.example.local"
    - "192.168.64.200 lb01 lb01.example.local"
    - "192.168.64.201 lb02 lb02.example.local"
    - "{{ vip_address }} vip.example.local"

七、Nginx Web服务器角色

7.1 Nginx安装配置任务

创建/ansible/playbooks/roles/nginx/tasks/main.yml

bash 复制代码
---
- name: 安装Nginx依赖包
  ansible.builtin.dnf:
    name:
      - gcc
      - pcre
      - pcre-devel
      - zlib
      - zlib-devel
      - openssl
      - openssl-devel
    state: present

- name: 安装Nginx(使用openEuler官方源)
  ansible.builtin.dnf:
    name: nginx
    state: present

- name: 创建Web根目录
  ansible.builtin.file:
    path: "{{ web_root }}"
    state: directory
    owner: nginx
    group: nginx
    mode: '0755'

- name: 配置Nginx主配置文件
  ansible.builtin.template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'
  notify: restart nginx

- name: 部署自定义首页
  ansible.builtin.template:
    src: index.html.j2
    dest: "{{ web_root }}/index.html"
    owner: nginx
    group: nginx
    mode: '0644'

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

7.2 Nginx配置模板

创建/ansible/playbooks/roles/nginx/templates/nginx.conf.j2

nginx

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

events {
    worker_connections 1024;
    use epoll;
}

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;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    server_tokens off;
    gzip on;
    gzip_vary on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript;
    
    server {
        listen 80;
        server_name {{ ansible_default_ipv4.address }} {{ ansible_hostname }} {{ web_domain }};
        root {{ web_root }};
        
        location / {
            index index.html index.htm;
        }
        
        location /health {
            access_log off;
            return 200 "healthy\n";
            add_header Content-Type text/plain;
        }
    }
}

7.3 自定义首页模板

创建/ansible/playbooks/roles/nginx/templates/index.html.j2

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Ansible自动化部署 - Nginx Web服务器</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; background: #f5f5f5; }
        .container { max-width: 800px; margin: 0 auto; background: white; padding: 30px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
        h1 { color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 10px; }
        .info { background: #ecf0f1; padding: 15px; border-radius: 5px; margin: 20px 0; }
        .footer { margin-top: 30px; color: #7f8c8d; font-size: 14px; text-align: center; }
    </style>
</head>
<body>
    <div class="container">
        <h1>🚀 Ansible自动化部署成功!</h1>
        <div class="info">
            <p><strong>服务器信息:</strong></p>
            <ul>
                <li>主机名:{{ ansible_hostname }}</li>
                <li>IP地址:{{ ansible_default_ipv4.address }}</li>
                <li>操作系统:{{ ansible_distribution }} {{ ansible_distribution_version }}</li>
                <li>内核版本:{{ ansible_kernel }}</li>
                <li>部署时间:{{ ansible_date_time.iso8601 }}</li>
            </ul>
        </div>
        <p>🎉 恭喜!Nginx Web服务器已通过Ansible Playbook成功部署在OpenEuler系统上。</p>
        <div class="footer">
            <p>Powered by Ansible | OpenEuler | Nginx</p>
        </div>
    </div>
</body>
</html>

7.4 Handlers

创建/ansible/playbooks/roles/nginx/handlers/main.yml

bash 复制代码
---
- name: restart nginx
  ansible.builtin.service:
    name: nginx
    state: restarted

八、Keepalived + Nginx反向代理角色

在两台负载均衡器(192.168.64.200和192.168.64.201)上部署Keepalived实现高可用,同时配置Nginx作为反向代理,将请求转发到后端Web服务器。Keepalived基于VRRP协议实现故障切换与健康检查功能。

8.1 Keepalived安装配置任务

创建/ansible/playbooks/roles/keepalived/tasks/main.yml

bash 复制代码
---
- name: 安装Nginx(反向代理)
  ansible.builtin.dnf:
    name: nginx
    state: present

- name: 安装Keepalived
  ansible.builtin.dnf:
    name: keepalived
    state: present

- name: 启用IP转发
  ansible.builtin.sysctl:
    name: net.ipv4.ip_forward
    value: '1'
    sysctl_set: yes
    state: present
    reload: yes

- name: 配置Nginx反向代理
  ansible.builtin.template:
    src: nginx-lb.conf.j2
    dest: /etc/nginx/conf.d/loadbalancer.conf
    owner: root
    group: root
    mode: '0644'
  notify: reload nginx

- name: 备份原有Keepalived配置
  ansible.builtin.copy:
    src: /etc/keepalived/keepalived.conf
    dest: /etc/keepalived/keepalived.conf.bak
    remote_src: yes
    force: no
  ignore_errors: yes

- name: 配置Keepalived
  ansible.builtin.template:
    src: keepalived.conf.j2
    dest: /etc/keepalived/keepalived.conf
    owner: root
    group: root
    mode: '0644'
  notify: restart keepalived

- name: 启动Nginx服务
  ansible.builtin.service:
    name: nginx
    state: started
    enabled: yes

- name: 启动Keepalived服务
  ansible.builtin.service:
    name: keepalived
    state: started
    enabled: yes

8.2 Nginx反向代理配置模板

创建/ansible/playbooks/roles/keepalived/templates/nginx-lb.conf.j2

bash 复制代码
# Nginx反向代理配置 - 负载均衡器
upstream backend_web {
    # 使用加权轮询算法,将请求分发到后端Web服务器
    server 192.168.64.100:80 weight=1 max_fails=3 fail_timeout=30s;
    server 192.168.64.101:80 weight=1 max_fails=3 fail_timeout=30s;
    
    # 开启会话保持
    keepalive 32;
}

upstream backend_api {
    # API反向代理后端服务
    server 192.168.64.100:8080 weight=1 max_fails=3 fail_timeout=30s;
    server 192.168.64.101:8080 weight=1 max_fails=3 fail_timeout=30s;
    
    keepalive 32;
}

server {
    listen 80;
    server_name {{ web_domain }} {{ vip_address }};
    
    # 访问日志
    access_log /var/log/nginx/lb_access.log main;
    error_log /var/log/nginx/lb_error.log;
    
    # Web流量转发
    location / {
        proxy_pass http://backend_web;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Connection "";
        
        # 超时设置
        proxy_connect_timeout 5s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
    
    # API流量转发
    location /api/ {
        proxy_pass http://backend_api;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Connection "";
        
        # 重写请求路径(可选)
        # rewrite ^/api/(.*)$ /$1 break;
    }
    
    # 健康检查端点
    location /health {
        access_log off;
        return 200 "LB-{{ ansible_hostname }}-OK\n";
        add_header Content-Type text/plain;
    }
    
    # Nginx状态页(仅内网访问)
    location /nginx_status {
        stub_status on;
        access_log off;
        allow 192.168.64.0/24;
        deny all;
    }
}

8.3 Keepalived配置模板

创建/ansible/playbooks/roles/keepalived/templates/keepalived.conf.j2

bash 复制代码
! Configuration File for keepalived

global_defs {
    router_id {{ ansible_hostname }}
    script_user root
    enable_script_security
}

vrrp_script check_nginx {
    script "/usr/bin/killall -0 nginx"
    interval 2
    weight -20
    fall 3
    rise 2
}

vrrp_instance VI_1 {
    state {{ state }}
    interface {{ vip_interface }}
    virtual_router_id {{ vrid }}
    priority {{ priority }}
    advert_int 1
    
    authentication {
        auth_type PASS
        auth_pass 123456
    }
    
    virtual_ipaddress {
        {{ vip_address }}/24 dev {{ vip_interface }}
    }
    
    track_script {
        check_nginx
    }
    
    notify_master "/usr/bin/echo '{{ ansible_hostname }} became MASTER' | /usr/bin/logger -t keepalived"
    notify_backup "/usr/bin/echo '{{ ansible_hostname }} became BACKUP' | /usr/bin/logger -t keepalived"
    notify_fault "/usr/bin/echo '{{ ansible_hostname }} became FAULT' | /usr/bin/logger -t keepalived"
}

8.4 Handlers

创建/ansible/playbooks/roles/keepalived/handlers/main.yml

bash 复制代码
---
- name: reload nginx
  ansible.builtin.service:
    name: nginx
    state: reloaded

- name: restart keepalived
  ansible.builtin.service:
    name: keepalived
    state: restarted

九、DNS域名解析角色

在DNS服务器(192.168.64.108)上部署BIND9,为内网提供域名解析服务。OpenEuler使用DNF包管理器,直接安装BIND即可。

9.1 DNS安装配置任务

创建/ansible/playbooks/roles/dns/tasks/main.yml

bash 复制代码
---
- name: 安装BIND9 DNS服务
  ansible.builtin.dnf:
    name: bind
    state: present

- name: 创建正向解析区域文件目录
  ansible.builtin.file:
    path: /var/named/zones
    state: directory
    owner: named
    group: named
    mode: '0750'

- name: 配置named主配置文件
  ansible.builtin.template:
    src: named.conf.j2
    dest: /etc/named.conf
    owner: root
    group: named
    mode: '0640'
  notify: restart named

- name: 配置正向解析区域文件
  ansible.builtin.template:
    src: zone.db.j2
    dest: "/var/named/zones/{{ dns_zone }}.db"
    owner: named
    group: named
    mode: '0640'
  notify: restart named

- name: 配置反向解析区域文件
  ansible.builtin.template:
    src: reverse.db.j2
    dest: "/var/named/zones/{{ dns_network_reverse }}.db"
    owner: named
    group: named
    mode: '0640'
  notify: restart named

- name: 配置防火墙规则(允许DNS查询)
  ansible.builtin.firewalld:
    service: dns
    permanent: yes
    state: enabled
    immediate: yes
  ignore_errors: yes

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

9.2 named主配置模板

创建/ansible/playbooks/roles/dns/templates/named.conf.j2

bash 复制代码
options {
    listen-on port 53 { any; };
    listen-on-v6 port 53 { ::1; };
    directory   "/var/named";
    dump-file   "/var/named/data/cache_dump.db";
    statistics-file "/var/named/data/named_stats.txt";
    memstatistics-file "/var/named/data/named_mem_stats.txt";
    secroots-file   "/var/named/data/named.secroots";
    recursing-file  "/var/named/data/named.recursing";
    allow-query     { any; };
    
    recursion yes;
    
    forwarders {
        {% for fwd in dns_forwarders %}
        {{ fwd }};
        {% endfor %}
    };
    
    dnssec-validation no;
    
    managed-keys-directory "/var/named/dynamic";
    pid-file "/run/named/named.pid";
    session-keyfile "/run/named/session.key";
};

logging {
    channel default_debug {
        file "data/named.run";
        severity dynamic;
    };
};

zone "." IN {
    type hint;
    file "named.ca";
};

# 正向解析区域
zone "{{ dns_zone }}" IN {
    type master;
    file "zones/{{ dns_zone }}.db";
    allow-update { none; };
};

# 反向解析区域
zone "{{ dns_network_reverse }}.in-addr.arpa" IN {
    type master;
    file "zones/{{ dns_network_reverse }}.db";
    allow-update { none; };
};

include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";

9.3 正向解析区域文件模板

创建/ansible/playbooks/roles/dns/templates/zone.db.j2

bash 复制代码
$TTL 86400
@       IN      SOA     dns01.{{ dns_zone }}. admin.{{ dns_zone }}. (
                        {{ ansible_date_time.epoch }} ; Serial
                        3600        ; Refresh
                        1800        ; Retry
                        604800      ; Expire
                        86400 )     ; Minimum TTL

; 名称服务器
@               IN      NS      dns01.{{ dns_zone }}.
dns01           IN      A       {{ dns_server }}

; Web服务器
web01           IN      A       192.168.64.100
web02           IN      A       192.168.64.101
www             IN      CNAME   web01
www2            IN      CNAME   web02

; 负载均衡器
lb01            IN      A       192.168.64.200
lb02            IN      A       192.168.64.201
lb              IN      CNAME   lb01

; 虚拟IP
vip             IN      A       {{ vip_address }}
portal          IN      CNAME   vip

; DHCP服务器
dhcp01          IN      A       {{ dhcp_server }}
dhcp            IN      CNAME   dhcp01

; 其他服务
api             IN      A       {{ vip_address }}

9.4 反向解析区域文件模板

创建/ansible/playbooks/roles/dns/templates/reverse.db.j2

bash 复制代码
$TTL 86400
@       IN      SOA     dns01.{{ dns_zone }}. admin.{{ dns_zone }}. (
                        {{ ansible_date_time.epoch }} ; Serial
                        3600        ; Refresh
                        1800        ; Retry
                        604800      ; Expire
                        86400 )     ; Minimum TTL

; 名称服务器
@               IN      NS      dns01.{{ dns_zone }}.

; PTR记录
100             IN      PTR     web01.{{ dns_zone }}.
101             IN      PTR     web02.{{ dns_zone }}.
108             IN      PTR     dns01.{{ dns_zone }}.
109             IN      PTR     dhcp01.{{ dns_zone }}.
200             IN      PTR     lb01.{{ dns_zone }}.
201             IN      PTR     lb02.{{ dns_zone }}.
250             IN      PTR     vip.{{ dns_zone }}.

9.5 Handlers

创建/ansible/playbooks/roles/dns/handlers/main.yml

bash 复制代码
---
- name: restart named
  ansible.builtin.service:
    name: named
    state: restarted

十、DHCP分配IP角色

在DHCP服务器(192.168.64.109)上部署DHCP服务,为内网客户端动态分配IP地址。DHCP服务器自身必须使用静态IP,否则服务会失效。

10.1 DHCP安装配置任务

创建/ansible/playbooks/roles/dhcp/tasks/main.yml

bash 复制代码
---
- name: 安装DHCP服务
  ansible.builtin.dnf:
    name: dhcp-server
    state: present

- name: 从模板复制DHCP配置文件
  ansible.builtin.template:
    src: dhcpd.conf.j2
    dest: /etc/dhcp/dhcpd.conf
    owner: root
    group: root
    mode: '0644'
  notify: restart dhcpd

- name: 配置DHCP监听网卡
  ansible.builtin.lineinfile:
    path: /etc/sysconfig/dhcpd
    line: 'DHCPDARGS="{{ ansible_default_ipv4.interface }}"'
    regexp: '^DHCPDARGS='
    state: present
  notify: restart dhcpd

- name: 配置防火墙规则(允许DHCP服务)
  ansible.builtin.firewalld:
    service: dhcp
    permanent: yes
    state: enabled
    immediate: yes
  ignore_errors: yes

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

10.2 DHCP配置模板

创建/ansible/playbooks/roles/dhcp/templates/dhcpd.conf.j2

bash 复制代码
# 全局配置
option domain-name "{{ domain_name }}";
option domain-name-servers {{ dns_server }};
default-lease-time {{ dhcp_lease_time }};
max-lease-time {{ dhcp_max_lease_time }};
authoritative;

# 禁用DNS动态更新
ddns-update-style none;

# 日志配置
log-facility local7;

# 子网配置
subnet {{ dhcp_subnet }} netmask {{ dhcp_netmask }} {
    range {{ dhcp_range_start }} {{ dhcp_range_end }};
    option routers {{ gateway }};
    option subnet-mask {{ dhcp_netmask }};
    option broadcast-address 192.168.64.255;
    option domain-name-servers {{ dns_server }};
    option domain-name "{{ domain_name }}";
}

# 为特定MAC地址分配固定IP
# 例如:为测试客户端分配固定IP
host test-client {
    hardware ethernet 00:0C:29:XX:XX:XX;  # 替换为实际MAC地址
    fixed-address 192.168.64.210;
    option host-name "test-client";
}

10.3 Handlers

创建/ansible/playbooks/roles/dhcp/handlers/main.yml

bash 复制代码
---
- name: restart dhcpd
  ansible.builtin.service:
    name: dhcpd
    state: restarted

十一、主入口Playbook(site.yml)

创建/ansible/playbooks/site.yml,作为整个自动化部署的入口:

bash 复制代码
---
- name: 1. 初始化所有服务器(通用配置)
  hosts: all
  gather_facts: yes
  roles:
    - common

- name: 2. 部署Nginx Web服务器
  hosts: webservers
  gather_facts: yes
  roles:
    - nginx

- name: 3. 部署Keepalived + Nginx反向代理(高可用负载均衡)
  hosts: loadbalancers
  gather_facts: yes
  roles:
    - keepalived

- name: 4. 部署DNS域名解析服务器
  hosts: dnsserver
  gather_facts: yes
  roles:
    - dns

- name: 5. 部署DHCP动态IP分配服务器
  hosts: dhcpserver
  gather_facts: yes
  roles:
    - dhcp

- name: 6. 部署后验证
  hosts: localhost
  gather_facts: no
  tasks:
    - name: 显示部署完成信息
      ansible.builtin.debug:
        msg:
          - "========================================"
          - "🎉 恭喜!全栈自动化部署已完成!"
          - "========================================"
          - "Nginx Web服务器: 192.168.64.100, 192.168.64.101"
          - "Keepalived高可用集群 (VIP: 192.168.64.250): 192.168.64.200(MASTER), 192.168.64.201(BACKUP)"
          - "DNS服务器: 192.168.64.108"
          - "DHCP服务器: 192.168.64.109"
          - "========================================"
          - "验证命令:"
          - "  curl http://192.168.64.250"
          - "  nslookup web01.example.local 192.168.64.108"
          - "  ip addr show | grep 192.168.64.250"
          - "  systemctl status dhcpd"
          - "========================================"

十二、执行Playbook

12.1 语法检查

bash 复制代码
cd /ansible/playbooks
ansible-playbook site.yml --syntax-check

12.2 试运行(Dry Run)

bash 复制代码
ansible-playbook site.yml --check

12.3 正式执行

bash 复制代码
ansible-playbook site.yml

12.4 指定执行部分角色

bash 复制代码
# 仅部署Web服务器
ansible-playbook site.yml --tags nginx

# 仅部署负载均衡器
ansible-playbook site.yml --tags keepalived

十三、部署验证

13.1 验证Nginx Web服务

bash 复制代码
# 访问单台Web服务器
curl http://192.168.64.100
curl http://192.168.64.101

# 查看Nginx服务状态
ansible webservers -m shell -a "systemctl status nginx | head -3"

13.2 验证Keepalived高可用集群

bash 复制代码
# 查看VIP所在节点
ansible loadbalancers -m shell -a "ip addr show | grep {{ vip_address }}"

# 模拟故障切换测试
# 在MASTER节点上停止Keepalived服务
ansible 192.168.64.200 -m service -a "name=keepalived state=stopped"

# 观察VIP是否漂移到BACKUP节点
ansible 192.168.64.201 -m shell -a "ip addr show | grep 192.168.64.250"

# 恢复MASTER节点
ansible 192.168.64.200 -m service -a "name=keepalived state=started"

13.3 验证反向代理

bash 复制代码
# 通过VIP访问(应该轮询分发到两台Web服务器)
for i in {1..10}; do curl -s http://192.168.64.250 | grep "主机名"; done

# 查看负载均衡器状态
curl http://192.168.64.250/nginx_status

13.4 验证DNS解析

bash 复制代码
# 测试正向解析
nslookup web01.example.local 192.168.64.108
nslookup www.example.local 192.168.64.108
nslookup vip.example.local 192.168.64.108

# 测试反向解析
nslookup 192.168.64.100 192.168.64.108

13.5 验证DHCP服务

bash 复制代码
# 查看DHCP服务状态
ansible dhcpserver -m shell -a "systemctl status dhcpd"

# 查看DHCP租约文件
ansible dhcpserver -m shell -a "cat /var/lib/dhcpd/dhcpd.leases"

十四、故障排查与优化建议

14.1 常见问题排查

问题现象 可能原因 解决方法
SSH连接失败 密钥未正确分发 重新执行ssh_key_distribution.yml
Nginx启动失败 端口被占用 `netstat -tlnp
Keepalived VIP不漂移 防火墙阻止VRRP协议 确保firewalld已关闭或放行VRRP(协议号112)
DNS解析失败 named服务未启动 systemctl restart named
DHCP分配失败 网卡配置错误 检查/etc/sysconfig/dhcpd中的网卡名称

14.2 优化建议

  1. 使用Ansible Vault加密敏感信息:将密码等敏感变量放入加密文件中

  2. 开启Pipeline :在ansible.cfg中设置pipelining = True可提升执行效率

  3. 配置Fact缓存 :设置fact_caching = jsonfile加速重复执行

  4. 使用Roles结构:将不同服务拆分为独立Role,便于维护和复用

十五、总结

本文通过一个完整的实战案例,演示了如何使用Ansible Playbook在OpenEuler系统上自动化部署一套企业级服务集群,涵盖:

  • SSH密钥分发 :使用authorized_key模块实现免密登录

  • Nginx Web服务:通过模板部署Web服务器和自定义页面

  • Keepalived高可用集群:基于VRRP协议实现VIP漂移,配合Nginx实现反向代理和API转发

  • DNS域名解析:部署BIND9服务,实现内网正向/反向域名解析

  • DHCP动态IP分配:为内网客户端自动分配IP地址

相关推荐
小梦爱安全2 小时前
ansible基础配置和ansible模块
运维·自动化·ansible
雨墨✘2 小时前
SAP硬件选择详解:服务器、存储与网络的全面解析
运维·服务器·网络
犽戾武2 小时前
VR遥操作机械臂系统:核心算法与数学方法全解析
linux·人工智能
Oll Correct2 小时前
实验十八:验证路由信息协议RIPv1
网络·笔记
不会写DN2 小时前
为什么TCP是三次握手?
服务器·网络·网络协议·tcp/ip
2501_913061342 小时前
网络编程——了解客户端与服务器端之间的交互(1)
java·网络
MIXLLRED2 小时前
随笔——ROS Ubuntu版本变化详解
linux·ubuntu·机器人·ros
M158227690552 小时前
三格电子 EtherNet/IP 协议网关产品介绍
网络·网络协议·tcp/ip