Ansible自动化部署LNMP架构

1.资源规划及拓扑图

序号

角色

ip地址

描述

1

Keepalived

192.168.146.200

路由冗余为nginx故障转移

2

Nginx1

192.168.146.100

负载均衡

3

Nginx2

192.168.146.101

负载均衡

4

web服务1

192.168.146.102

业务应用服务器

5

web服务2

192.168.146.103

业务应用服务器

6

NFS

192.168.146.104

共享存储

7

mysql主库

192.168.146.105

数据库主库负责写

8

mysql从库

192.168.146.106

数据库从库提供数据冗余及读

9

prometheus

192.168.146.107

全链路服务监控及告警

10

Rsync

192.168.146.108

nas备份

11

redis主库

192.168.146.109

缓存服务器

12

redis从库

192.168.146.110

redis数据冗余

13

redis哨兵

192.168.146.111

redis监控节点

暂时无法在飞书文档外展示此内容

2.服务器初始化配置

负载均衡Nginx

  • nginx1:192.168.146.100

1.查看服务器网卡

nmcli connection show

2.根据连接名修改网卡IP

nmcli connection modify ens33 ipv4.address 192.168.146.100/24 ipv4.gateway 192.168.146.2 ipv4.dns 114.114.114.114 ipv4.method manual

3.重启网络服务

service  networking restart 
  • nginx2:192.168.146.101

1.根据连接名修改网卡IP

nmcli connection modify ens33 ipv4.address 192.168.146.101/24 ipv4.gateway 192.168.146.2 ipv4.dns 114.114.114.114 ipv4.method manual

2.重启网络服务

service  networking restart 

web服务器

  • apache1:192.168.146.102

nmcli connection modify ens33 ipv4.address 192.168.146.102/24 ipv4.gateway 192.168.146.2 ipv4.dns 114.114.114.114 ipv4.method manual
  • apache2:192.168.146.103

nmcli connection modify ens33 ipv4.address 192.168.146.103/24 ipv4.gateway 192.168.146.2 ipv4.dns 114.114.114.114 ipv4.method manual

重启网络服务

NAS存储节点

  • NFS服务器:192.168.146.104

nmcli connection modify ens33 ipv4.address 192.168.146.104/24 ipv4.gateway 192.168.146.2 ipv4.dns 114.114.114.114 ipv4.method manual

Mysql主从集群

  • master:192.168.146.105

nmcli connection modify ens33 ipv4.address 192.168.146.105/24 ipv4.gateway 192.168.146.2 ipv4.dns 114.114.114.114 ipv4.method manual
  • slave:192.168.146.106

nmcli connection modify ens33 ipv4.address 192.168.146.106/24 ipv4.gateway 192.168.146.2 ipv4.dns 114.114.114.114 ipv4.method manual

重启网络服务

Prometheus

  • prometheus:192.168.146.107

nmcli connection modify ens33 ipv4.address 192.168.146.107/24 ipv4.gateway 192.168.146.2 ipv4.dns 114.114.114.114 ipv4.method manual

rsync

  • rsyncd:192.168.146.108

nmcli connection modify ens33 ipv4.address 192.168.146.108/24 ipv4.gateway 192.168.146.2 ipv4.dns 114.114.114.114 ipv4.method manual

3.ssh免密登录

1.在ansible管理机上,生成密钥对。

ssh-keygen

2.将公钥id_rsa.pub发送至各个服务器,以下命令在每个服务器包括管理节点都执行一遍,IP换成对应的即可

ssh-copy-id -i /root/.ssh/id_rsa.pub 192.168.146.139  
ssh-copy-id -i /root/.ssh/id_rsa.pub 192.168.146.100  
ssh-copy-id -i /root/.ssh/id_rsa.pub 192.168.146.101  
ssh-copy-id -i /root/.ssh/id_rsa.pub 192.168.146.102  
ssh-copy-id -i /root/.ssh/id_rsa.pub 192.168.146.103  
ssh-copy-id -i /root/.ssh/id_rsa.pub 192.168.146.104  
ssh-copy-id -i /root/.ssh/id_rsa.pub 192.168.146.105
ssh-copy-id -i /root/.ssh/id_rsa.pub 192.168.146.106
ssh-copy-id -i /root/.ssh/id_rsa.pub 192.168.146.108

出现以下信息即完成传输

3.在其他服务器上检查一下是否存在authorized_keys文件,存在该文件就说明公钥从管理节点接收成功了

在管理节点上,可以验证一下是否可以成功ssh免密登录到其他节点

4.集群搭建

1.使用yum安装ansible工具

# 安装epel扩展源
yum install epel-release.noarch -y
# 安装ansible
yum install -y ansible

2.编写ansible主机清单/etc/ansible/hosts文件,在文件末尾添加如下内容

[all_ip]
192.168.146.134 hostname=manager
192.168.146.100 hostname=nginx1
192.168.146.101 hostname=nginx2
192.168.146.102 hostname=apache1
192.168.146.103 hostname=apache2
192.168.146.104 hostname=nas rsync_server=192.168.146.108
192.168.146.105 hostname=master
192.168.146.106 hostname=slave
192.168.146.107 hostname=prometheus
192.168.146.108 hostname=rsyncd
192.168.146.109 hostname=redis_master
192.168.146.110 hostname=redis_slave
192.168.146.111 hostname=redis_sentinel

[balancers]
nginx1 mb=MASTER priority=100
nginx2 mb=BACKUP priority=98

[web]
apache1
apache2

[mysql]
master master=true
slave slave=true

#定义mysql变量
[mysql:vars]
master_ip=192.168.146.105
slave_ip=192.168.146.106

[nfs]
nas

#定义nfs变量
[nfs:vars]
rsync_server=192.168.146.108

[rsync]
rsyncd

[redis_servers]
192.168.146.109 redis_role=redis_master
192.168.146.110 redis_role=redis_slave
192.168.146.111 redis_role=redis_sentinel

[redis_master]
192.168.146.109

[redis_slave]
192.168.146.110

[redis_sentinel]
192.168.146.111

[prometheus]
prometheus

[alertmanagers]
prometheus

[node-exporter]
192.168.146.100
192.168.146.101
192.168.146.102
192.168.146.103
192.168.146.104
192.168.146.105
192.168.146.106
192.168.146.108

3.检查连通性,所有服务器均响应pong才表示管理节点与所有服务器连通无误

4.为所有服务器设置主机名,并关闭selinux和防火墙

[root@server1 ansible]# vim prepare_work.yml 

- name: prepare work
  hosts: all_ip
  tasks:

    - name: set hostname
      shell: hostnamectl set-hostname {{ hostname }}

    - name: stop firewalld
      service:
        name: firewalld
        state: stopped
        enabled: no

    - name: disabled selinux
      selinux:
        state: disabled
        
# 执行剧本!
[root@server1 ansible]# ansible-playbook prepare_work.yml

5.为所有服务器主机生成/etc/hosts/解析文件

[root@server1 ~]# mkdir ansible
[root@server1 ~]# cd ansible/

# 编写hosts的模板文件
[root@server1 ansible]# vim hosts.j2
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

{% for host in groups.all_ip %}
{{ hostvars[host].ansible_ens33.ipv4.address }} {{ hostvars[host].ansible_hostname }}
{% endfor %}

# 编写剧本yml文件
[root@server1 ansible]# vim hosts.yml
- name: update hosts file
  hosts: all_ip
  tasks:
    - name: copy hosts.j2 to other servers
      template:
        src: hosts.j2
        dest: /etc/hosts

# 执行剧本yml文件
[root@server1 ansible]# ansible-playbook hosts.yml 

4.1搭建数据库

  • 创建数据库msql角色

[root@server1 ansible]# ansible-galaxy init role/mysql
- Role role/mysql was created successfully
  • 定义数据库变量

[root@server1 ansible]# vim roles/mysql/vars/main.yml
---
# vars file for role/mysql
mysql_sock: /var/lib/mysql/mysql.sock
mysql_port: 3306
repl_user: repl
repl_passwd: "123456"
  • 编写模板文件,用于配置my.cnf。

[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0

#判断服务器是否为master节点,并设置相对应的id
{% if master is defined %}
server-id=1
innodb_file_per_table=on
{% else %}
server-id=2
{% endif %}

log-bin=master-bin
binlog-format=ROW

# 这些是开启gtid的参数
log-slave-updates=true
gtid-mode=on
enforce-gtid-consistency=true
master-info-repository=TABLE
relay-log-info-repository=TABLE
sync-master-info=1
binlog-rows-query-log_events=1

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
  • 编写 mysql/tasks/main.yml 文件,完成一键搭建主从架构的ansible脚本

[root@server1 ansible]# vim roles/mysql/tasks/main.yml 

---
# tasks file for role/mysql
- name: 安装wget
  yum:
    name: wget
    state: present

- name: 下载mysql的repo源
  shell: wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm

- name: 安装mysql的repo
  shell: rpm -ivh mysql-community-release-el7-5.noarch.rpm
  ignore_errors: True

- name: 安装mysql服务
  yum:
    name: mysql-server
    state: present

- name: 分发my.cnf配置文件
  template:
    src: my.cnf.j2
    dest: /etc/my.cnf

- name: 启动mysql并设置开机自启
  service:
    name: mysqld
    state: restarted
    enabled: yes

- name: 安装MYSQL-python
  yum:
    name: MySQL-python
    state: present

- name: 更新mysql的root用户密码
  shell: mysql -e "update mysql.user set password=password('123456') where user='root' and host='localhost';flush privileges;"
  ignore_errors: True

- name: 创建从库复制用户repl,并配置主服务器
  mysql_user:
    name: "{{ repl_user }}"
    host: '192.168.146.%'
    password: "{{ repl_passwd }}"
    priv: "*.*:REPLICATION SLAVE"
    state: present
    login_user: 'root'
    login_password: '123456'
    login_host: localhost
    login_unix_socket: "{{ mysql_sock }}"
    login_port: "{{ mysql_port }}"
  when: master is defined
  
  
- name: 配置从服务器连接主服务器信息
  mysql_replication:
    mode: changemaster
    master_host: "{{ master_ip }}"
    master_user: "{{ repl_user }}"
    master_password: "{{ repl_passwd }}"
    login_password: '123456'
    login_host: localhost
    login_unix_socket: "{{ mysql_sock }}"
    login_port: "{{ mysql_port }}"
  when: slave is defined

- name: 启动从服务器的复制进程
  mysql_replication:
    mode: startslave
    login_user: 'root'
    login_password: '123456'
    login_host: localhost
    login_unix_socket: "{{ mysql_sock }}"
    login_port: "{{ mysql_port }}"
  when: slave is defined

- name: 获取从服务器的复制信息
  mysql_replication:
    login_host: localhost
    login_user: root
    login_port: "{{ mysql_port }}"
    login_password: '123456'
    login_unix_socket: "{{ mysql_sock }}"
    mode: getslave
  when: slave is defined
  register: info

- name: 输出从服务器的复制状态
  debug:
    msg: "Slave_IO_Running={{ info.Slave_IO_Running }}       Slave_SQL_Running={{ info.Slave_SQL_Running }}"
  when: slave is defined

4.2搭建NAS存储节点

  • 创建nfs角色

[root@server1 ansible]# ansible-galaxy init role/nfs
- Role role/nfs was created successfully
  • 准备expect脚本的模板文件 rsync.exp.j2

[root@manager ansible]# vim roles/nfs/templates/rsync.exp.j2

#!/usr/bin/expect
set mulu [lindex $argv 0]
set timeout 10
spawn rsync -avzr /backup/$mulu root@{{ rsync_server }}::backup_server
expect Password
send "123456\r"
expect eof
  • 准备备份脚本的模板文件 beifen.sh.j2

[root@manager ansible]# vim roles/nfs/templates/beifen.sh.j2

#!/bin/bash
# 准备压缩文件的目录
mulu=`ip a | grep global|awk -F'[ /]+' '{print $3}'`_`date +%F`
echo $mulu
mkdir -pv /backup/$mulu &> /dev/null
# 打包待发送的数据
tar zcf /backup/$mulu/conf.tar.gz /data/* &> /dev/null
touch /backup/$mulu
# 发送数据
# 这一句就是执行expect脚本
expect /sh/rsync.exp $mulu
# 保留七天以内的数据
find /backup -mtime +7 -delete
  • 创建好角色后,编写nfs/tasks/main.yml 文件

[root@server1 ansible]# vim role/nfs/tasks/main.yml 

---
# tasks file for role/nfs
- name: 安装所需的软件包
  yum:
    name: "{{ item }}"
    state: present
  loop:
    - nfs-utils
    - rpcbind
    - expect*

- name: 创建并配置NFS共享目录
  shell: mkdir /data | chmod -Rf 777 /data | echo "/data 192.168.146.0/24(rw,sync,no_root_squash)" >> /etc/exports


- name: 创建/sh目录
  file:
    path: /sh
    state: directory
    
- name: 创建/backup目录
  file:
    path: /backup
    state: directory

- name: 使用rsync脚本
  template:
    src: rsync.exp.j2
    dest: /sh/rsync.exp
    
- name: 使用beifen脚本
  template:
    src: beifen.sh.j2
    dest: /sh/beifen.sh

- name: 更改beifen脚本权限
  file:
    path: /sh/beifen.sh
    mode: '0755'
    
- name: 添加beifen脚本到定时任务
  shell: echo "0 1 * * * root /sh/beifen.sh" >> /etc/crontab                           

- name: 启动服务
  service:
    name: "{{ item }}"
    state: restarted
    enabled: yes
  loop:
    - rpcbind
    - nfs-server

4.3搭建备份节点

  • 备份选择rsync服务端,定时接收NAS存储节点推送的备份文件。因此先创建rsync角色

[root@manager ansible]# ansible-galaxy init roles/rsync
- Role roles/rsync was created successfully
  • 编写文件 rsyncd.conf

[root@manager ~]# vim ansible/roles/rsync/files/rsyncd.conf 

[backup_server]
path = /backup
uid = root
gid = root
max connections = 2
timeout = 300
read only = false
auth users = root
secrets file = /etc/rsync.passwd
strict modes = yes
use chroot = yes
  • 编写 rsync/tasks/main.yml 文件

[root@manager ansible]# vim roles/rsync/tasks/main.yml 

---
# tasks file for roles/rsync
- name: 安装rsync
  yum:
    name: rsync
    state: present

- name: 分发配置文件
  copy:
    src: rsyncd.conf
    dest: /etc/rsyncd.conf

- name: 创建/backup目录
  file:
    path: /backup
    state: directory

- name: 配置rsync.passwd
  shell: echo "root:123456" >> /etc/rsync.passwd | chmod 600 /etc/rsync.passwd

- name: 启动rsync
  service:
    name: rsyncd
    state: started
    enabled: yes

4.4搭建web节点

  • 使用是LNMP环境,web服务器选用nginx,因此先创建nginx角色

[root@server1 ansible]# ansible-galaxy init role/web
- Role role/apache was created successfully
  • 编写 web/tasks/main.yml 文件

---
# tasks file for role/web
- name: 下载 Nginx and PHP
  yum:
    name: ['nginx', 'php-fpm', 'php-mysql']
    state: present
    update_cache: yes

- name: 启动Nginx
  service:
    name: nginx
    state: restarted
    enabled: yes

- name: 启动PHP-FPM
  service:
    name: php-fpm
    state: restarted
    enabled: yes

- name: 安装nfs客户端
  yum:
    name: nfs-utils
    state: present

- name: 挂载nfs资源
  mount:
    src: nas:/data
    path: /var/www/html
    fstype: nfs
    opts: defaults
    state: mounted

4.5搭建负载均衡节点

  • 本架构的负载均衡实现选择的是nginx,先创建nginx角色

# 创建nginx角色
[root@server1 ansible]# ansible-galaxy init role/nginx
- Role role/nginx was created successfully
  • 编写模板文件,为前端的两台nginx负载均衡节点创建负载均衡的配置文件lb.conf,为了实现会话保持使用基于ip hash算法的负载均衡

[root@server1 ansible]# vim role/nginx/templates/lb.conf.j2
upstream webservers {
    server apache1;
    server apache2;
    ip_hash;
}

server {

    location / {
        proxy_pass http://webservers;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_504;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
  • 编写nginx/tasks/main.yml 文件

[root@server1 ansible]# vim role/nginx/tasks/main.yml 

---
# tasks file for nginx
- name: 安装epel源
  yum:
    name: epel-release.noarch
    state: present

- name: 安装nginx
  yum:
    name: nginx
    state: present

- name: 分发配置文件lb.conf
  template:
    src: lb.conf.j2
    dest: /etc/nginx/conf.d/lb.conf

- name: 启动nginx
  service:
    name: nginx
    state: restarted
    enabled: yes

4.6配置keepalived高可用

  • 创建keepalived角色,VIP:192.168.146.200

[root@server1 ansible]# ansible-galaxy init role/keepalived
- Role role/keepalived was created successfully
  • 编写模板文件,用于在负载均衡节点上创建keepalived的配置文件

[root@server1 ansible]# vim role/keepalived/templates/keepalived.conf.j2

!Configuration File for keepalived

global_defs {
    router_id {{ ansible_hostname }}
}

vrrp_script check_nginx {
    script "/usr/local/src/check_nginx_pid.sh"
    interval 1
    weight -10
}

vrrp_instance VI_1 {
    state {{ mb }}
    interface ens33
    virtual_router_id 10
    priority {{ priority }}
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
}

track_script {
    check_nginx
}

    virtual_ipaddress {
        192.168.146.200
}
}
  • 编写用于检测nginx服务状态的脚本,以便于keepalived实现VIP飘移

[root@manager ansible]# vim roles/keepalived/files/check_nginx_pid.sh
#!/bin/bash
nginx_process_num=`ps -C nginx --no-header | wc -l`
if [ $nginx_process_num -eq 0 ];then
  exit 1
else
  exit 0
fi
  • 创建好keepalived角色和模板文件后,开始编写keepalived/tasks/main.yml 文件

[root@server1 ansible]# vim role/keepalived/tasks/main.yml 

---
# tasks file for role/keepalived
- name: yum install keepalived
  yum:
    name: keepalived
    state: present

- name: copy check_nginx_pid.sh
  copy:
    src: check_nginx_pid.sh
    dest: /usr/local/src/check_nginx_pid.sh

- name: chmod sh
  file:
    path: /usr/local/src/check_nginx_pid.sh
    mode: '0755'

- name: config keepalived.conf
  template:
    src: keepalived.conf.j2
    dest: /etc/keepalived/keepalived.conf

- name: start keepalived
  service:
    name: keepalived
    state: restarted
    enabled: yes

4.7搭建redis哨兵集群

  • 创建redis角色

[root@server1 ansible]# ansible-galaxy init role/redis
- Role role/keepalived was created successfully
  • 编写用于定义Redis配置文件的模板redis.conf.j2

vim role/redis/templates/redis.conf.j2
# Redis configuration file

# 设置Redis监听的IP地址
bind {{ redis_bind_ip }}

# 设置Redis监听的端口
port {{ redis_port }}

# 设置Redis的工作目录
dir /var/lib/redis

# 设置Redis的日志文件路径
logfile /var/log/redis/redis-server.log

# 设置Redis的日志级别
loglevel notice

# 设置Redis的数据库数量
databases 16

# 设置Redis的密码
{% if redis_password %}
requirepass {{ redis_password }}
masterauth {{ redis_password }}
{% endif %}

# 设置Redis的主从复制
{% if redis_master_ip %}
slaveof {{ redis_master_ip }} {{ redis_port }}
{% endif %}

# 设置Redis的哨兵模式
{% if redis_sentinel %}
sentinel monitor mymaster {{ redis_master_ip }} {{ redis_port }} 2
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 10000
{% endif %}
  • 编辑变量文件

vim role/redis/vars/main.yml

---
redis_bind_ip: "{{ ansible_host }}"
redis_port: 6379
redis_password: your_password
redis_master_ip: "{{ groups['redis_master'][0] }}"
redis_sentinel: "{{ 'redis_sentinel' in group_names }}"
  • 最后编辑tasks/main.yml 文件

---
- name: Install Redis
  yum:
    name: redis
    state: present

- name: Configure Redis
  template:
    src: redis.conf.j2
    dest: /etc/redis/redis.conf
    mode: 0644
  notify:
    - restart redis

- name: Ensure Redis is running
  service:
    name: redis
    state: started
    enabled: true

5.总剧本

1.编写总剧本

[root@server1 ansible]# vim all.yml

- name: config mysql replication
  hosts: mysql
  roles:
  - mysql

- name: config nfs
  hosts: nfs
  roles:
  - nfs

- name: config rsync
  hosts: rsync
  roles:
  - rsync

- name: config lamp
  hosts: web
  roles:
  - apache

- name: config lb
  hosts: balancers
  roles:
  - nginx
  - keepalived

- name: install prometheus
  hosts: prometheus
  roles:
    - prometheus
    - alertmanager

- name: install node-exporter
  hosts: node-exporter
  roles:
    - node-exporter

2.启动总剧本

ansible-playbook all.yml

消息盒子

# 暂无消息 #

只显示最新10条未读和已读信息