Ansible自动化部署LNMP架构
1.资源规划及拓扑图
暂时无法在飞书文档外展示此内容
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