在之前我們知道了playbook,類似于shell的腳本,playbook适用于一些不太麻煩的部署任務,比如說使用playbook安裝mysql,那麼我們直接寫一個playbook檔案即可。可是如果我們還要搭建mysql的主從架構呢?一個playbook就會顯得會力不從心,這個時候我們可以使用roles。roles就是有互相關聯功能的集合。相對于playbook,roles更适合于大項目的編排和架構。
在使用roles之前,簡單說明一下include的用法,在playbook中可以引入另外的playbook腳本,這時候可以使用include指令。
- include test.yml
整體架構
roles主要依賴于目錄命名和擺放,預設tasks/main.yml是所有任務的入口,是以使用roles的過程可以了解為目錄規範化命名的過程。roles的目錄架構是确定的,如下:
roles/ #roles目錄下面存放對應的role
└── master_slave_mysql #目錄名以role名命名,目錄下面是每個role都包含的檔案,若是對應的檔案沒有使用可以不建立
├── files #files用于檔案傳輸,一些壓縮包可以放在這裡,在playbook中直接調用即可
├── handlers #role項目所有使用的handlers寫在這裡
├── tasks #主要的邏輯檔案,也就是playbook檔案執行的任務
├── templates #templates也用于檔案的傳輸,但是這裡的檔案可以使用jija2模闆文法,而files傳輸的檔案不能使用jija2模闆文法
└── vars #定義變量
#角色下面的每個檔案中【files和templates目錄下面不需要】,都必須需要一個main.yml檔案,作為該子產品的排程入口。而對應的邏輯檔案可以寫在對應的子產品下面,
#然後在main.yml檔案中使用include語句引入。
先來看一下一個完整role的所有目錄結構:
[[email protected] ~]# tree roles/
roles/
└── master_slave_mysql
├── files
│ ├── initmysql7.sh #MySQL安裝的初始化腳本
│ └── mysql-5.7.22-linux-glibc2.12-x86_64.tar.gz #MySQL安裝包
├── handlers
│ ├── all_handlers.yml #roles所有的handlers,若是所需handlers可以分多個檔案寫入,
│ └── main.yml #在main.yml檔案使用include語句,引入所有的handlers檔案
├── tasks #
│ ├── add_repl_user.yml #添加複制使用者的playbook檔案
│ ├── change_passwd.yml #MySQL5.7初始化後,需要修改密碼,這裡是修改密碼的playbook檔案
│ ├── install_mysql.yml #安裝mysql的playbook
│ ├── main.yml #在main中引入對應的playbook,注意引入的順序
│ └── set_replication.yml #配置主從複制的playbook
├── templates
│ ├── my.cnf.j2 #MySQL的配置檔案模闆
│ ├── test.retry #後面這兩個是我測試的時候的檔案,不用管
│ └── test.yml
└── vars #定義變量
└── main.yml #定義變量檔案,也可以單獨寫成playbook的形式,然後再引入,因為這裡變量比較少,就直接寫入了main.yml
6 directories, 13 files
在和roles同級目錄的結構中,我們還需要定義個yml檔案,作為項目的排程入口。
[[email protected] ~]# cat site.yml
---
# 該項目的排程入口
- hosts: all
remote_user: root
roles:
- master_slave_mysql
[[email protected] ~]# lsroles site.yml
#執行的時候直接執行入口檔案即可, 注意需要定義inventory檔案。
[[email protected] ~]# ansible-playbook site.yml
下面我們來一個個解析這個簡單的項目。
inventory檔案
預設是讀取/etc/ansible/hosts中的内容,其内容如下:【需要說明的是,這裡雖然定義了多個分組,但是在後面代碼中沒怎麼使用】
[[email protected] ~]# cat /etc/ansible/hosts
[all]
10.0.102.212
10.0.102.200
10.0.102.162
[master]
10.0.102.162
[slave]
10.0.102.200
10.0.102.212
files子產品
這各子產品主要用于檔案的傳輸,這個項目中我們在裡面放了一個初始化腳本和mysql5.7的安裝包。初始化腳本就是一條很簡單的指令,寫在這裡是為了說明files的用法。
初始化腳本如下:
[[email protected] files]# cat !$
cat initmysql7.sh
#!/bin/bash
./bin/mysqld --user=mysql --datadir=/data/mysql --initialize
[[email protected] files]#
#在playbook中引用時,可以直接引用,而不是使用絕對路徑
- name: copy the mysql install pkg
copy: src={{ install_pkg_name }}.tar.gz dest=/usr/local/src #src直接引用即可
- name: init mysql
script: chdir={{ basedir_name }} initmysql7.sh #執行這個腳本,而不是使用絕對路徑
handlers子產品
handlers的作用不再說明,這裡隻說明handlers在roles中的編排。
[[email protected] files]# cd ../handlers/
[[email protected] handlers]# ls
all_handlers.yml main.yml
[[email protected] handlers]# cat all_handlers.yml #直接寫入對應的handlers即可,
---
- name: start mysql
service: name=mysqld state=started
- name: restart mysql
service: name=mysqld state=restarted
- name: flush privileges
shell: chdir=/usr/local/mysql/bin ./mysql -u{{ login_user }} -p{{ login_passwd }} -e "flush privileges"
[[email protected] handlers]# cat main.yml
---
- include: all_handlers.yml
---
- name: start mysql
service: name=mysqld state=started
- name: restart mysql
service: name=mysqld state=restarted
- name: flush privileges
shell: chdir=/usr/local/mysql/bin ./mysql -u{{ login_user }} -p{{ login_passwd }} -e "flush privileges"
all_handlers.yml
---
- include: all_handlers.yml
main.yml
tasks子產品
tasks是roles主要的邏輯檔案,所有的play都在這裡執行,先來看一下main檔案。
[[email protected] tasks]# cat main.yml #包含了四個playbook檔案,要注意檔案的邏輯順序
---
- include:
install_mysql.yml
change_passwd.yml
add_repl_user.yml
set_replication.yml
install_mysql.yml檔案主要用來安裝MySQL,拷貝配置檔案并且啟動mysql,内容如下。
---
- name: copy the mysql install pkg
copy: src={{ install_pkg_name }}.tar.gz dest=/usr/local/src
- name: uncompress the pkg
unarchive: src=/usr/local/src/{{ install_pkg_name }}.tar.gz dest=/usr/local/ copy=no
- name: create a soft link
#shell: ln -s /usr/local/{{ install_pkg_name }} /usr/local/mysql
file: src=/usr/local/{{ install_pkg_name }} dest={{ basedir_name }} state=link
- name: create the mysql user
user: name={{ mysql_user }}
- name: create the datadir
file: path={{ datadir_name }} state=directory owner={{ mysql_user }} group={{ mysql_user }}
- name: init mysql
script: chdir={{ basedir_name }} initmysql7.sh
- name: copy the manage script
shell: cp -p /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
- name: change the start script
#shell: sed -i "s/^datadir=/datadir=\/data\/mysql/" /etc/init.d/mysqld
replace: path=/etc/init.d/mysqld replace="datadir={{ datadir_name }}" regexp="^datadir=" backup=yes
- name: copy the mysql config
template: src=my.cnf.j2 dest=/etc/my.cnf
notify:
- start mysql
install_mysql.yml
change_passwd.yml檔案主要用來更改密碼,因為MySQL5.7的密碼屬性,是以需要更改密碼才能使用。這裡沒有使用ansible的相關子產品,而是直接使用了sql指令。
---
- name: 設定資料庫密碼
shell: chdir={{ mysql_path }} ./mysql -e "update mysql.user set authentication_string=password("123456")"
- name: 開啟權限認證
replace:
path=/etc/my.cnf
regexp="^skip-grant-tables$"
replace="#skip-grant-tables"
notify:
restart mysql
- name: 設定密碼
shell: chdir={{ mysql_path }} ./mysql -uroot -p123456 --connect-expired-password -e 'alter user "root"@"localhost" identified by "123456"'
change_passwd.yml
add_repl_user.yml檔案用來在master上添加複制使用者,同樣的也沒有使用ansible相關的子產品,而是使用了sql指令。
---
- name: add the user to replication
shell: chdir=/usr/local/mysql/bin ./mysql -uroot -p123456 -e 'grant all privileges on *.* to "repl"@"%" identified by "123456"'
notify:
flush privileges
when: ansible_eth0.ipv4.address == "10.0.102.162"
add_repl_user.yml
set_replication.yml檔案用來在從上設定複制步驟,然後開啟複制,這裡使用了mysql_replication的子產品。因為這裡是全新的mysql,是以在change master時沒有指定二進制日志名和日志位置點。
---
- name: Get the current master servers replication status
mysql_replication:
login_user=root
login_password=123456
login_unix_socket=/tmp/mysql.sock
mode=getmaster
register: repl_stat
when: ansible_eth0.ipv4.address == "10.0.102.162"
- name: test
mysql_replication:
login_user={{ login_user }}
login_password={{ login_passwd }}
login_unix_socket={{ sock_path }}
mode=changemaster
master_host="10.0.102.162"
master_user="repl"
master_password="123456"
when: ansible_eth0.ipv4.address != "10.0.102.162"
- name: start slave in slave to start the replication
mysql_replication:
login_user=root
login_password=123456
login_unix_socket=/tmp/mysql.sock
mode=startslave
when: ansible_eth0.ipv4.address != "10.0.102.162"
set_replication.yml
這個檔案中的when語句可以換位委托語句delegate_to。另外需要說明的是when語句引用變量時會報如下錯誤:
[WARNING]: when statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: ansible_eth0.ipv4.address == {{ master_host }}
fatal: [10.0.102.200]: FAILED! => {"msg": "The conditional check 'ansible_eth0.ipv4.address == {{ master_host }}' failed. The error was: error while evaluating conditional (ansible_eth0.ipv4.address == {{ master_host }}): float object has no element 102\n\nThe error appears to have been in '/root/roles/master_slave_mysql/tasks/set_replication.yml': line 2, column 4, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n---\n - name: Get the current master servers replication status\n ^ here\n"}
解決辦法:http://blog.sina.com.cn/s/blog_704836f40102xbkt.html
就是把when後面的語句先用單引号括起來,裡面對應的變量再使用雙引号。
在這裡應用的時候還有一個問題,如果在changge master的時候指定日子檔案名和日志位置點,如下!我自己調用的時候總是報錯。
- name: Change the master in slave to start the replication
mysql_replication:
login_user=root
login_password=123456
login_unix_socket=/tmp/mysql.sock
master_log_file={{ repl_stat.File }} #加上這兩句,再執行的時候總是報錯
master_log_pos={{ repl_stat.Position }}
mode=changemaster
master_host="10.0.102.162"
master_user="repl"
master_password="123456"
when: ansible_eth0.ipv4.address != "10.0.102.162"
- name: start slave in slave to start the replication
mysql_replication:
login_user=root
login_password=123456
login_unix_socket=/tmp/mysql.sock
mode=startslave
when: ansible_eth0.ipv4.address != "10.0.102.162"
報錯提示如下:【求哪位知道怎麼解決了,告訴一下】
fatal: [10.0.102.200]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'File'\n\nThe error appears to have been in '/root/roles/master_slave_mysql/tasks/set_replication.yml': line 16, column 4, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: test\n ^ here\n"}
報錯提示
但是因為這裡我們的mysql都是全新安裝的,是以不需要指定日志名和日志位置掉,是以不需要加入這兩句,也就沒有報錯。
templates子產品
這個子產品與files子產品都可以用于檔案傳輸,最大的不同是,templates可以使用jija2文法。譬如這裡,我們使用這個子產品傳輸mysql的配置檔案,我們知道在主從叢集中在主上需要開通二進制日志,并且三個伺服器的server_id要不一樣。這個時候如果我們使用files子產品就需要三個不同的配置模闆,而是用templates子產品,則隻需要一個配置模闆即可。
[[email protected] templates]# cat my.cnf.j2
[mysqld]
datadir={{ datadir_name }}
socket={{ sock_path }}
symbolic-links=0
skip-grant-tables
server_id={{ ansible_eth0.ipv4.address| regex_search("([0-9]{1,3})$") }}
{% if ansible_eth0.ipv4.address == master_host %}
log-bin=
{% endif %}
[mysqld_safe]
log-error={{ datadir_name }}/{{ ansible_hostname }}.err
pid-file={{ datadir_name }}/mysql.pid
在templates模闆中可以使用定義變量,在這個模闆中我們定義了server_id為每個每個伺服器ip位址的最後一部分【如果伺服器跨網段,那麼這個數字可能重複,但是這裡是在同一網段的,是以數字是唯一的】
使用了if條件判斷,判斷若是目前主機ip和master對應主機相等,則設定log-bin參數,否則不設定。這就是一個簡單的模闆。
vars子產品
vars模闆主要是寫入roles中定義的變量,當然變量也可以定義在inventory檔案中。定義的變量最好加上注釋性的說明,這樣友善後續更改。
---
#資料庫安裝包的名字
install_pkg_name: mysql-5.7.22-linux-glibc2.12-x86_64
#初始化腳本的名字
init_mysql: initmysql.sh
#mysql使用者名
mysql_user: mysql
#資料庫資料目錄
datadir_name: /data/mysql
basedir_name: /usr/local/mysql
#mysql指令的絕對路徑
mysql_path: /usr/local/mysql/bin/
#連接配接mysql的變量
login_user: root
login_passwd: 123456
sock_path: /tmp/mysql.sock
#伺服器主機變量
master_host: "10.0.102.162"
slave1: "10.0.102.200"
slave2: "10.0.102.212"
設定完如上的檔案之後,一個簡單的roles已經完成。接下來直接隻要設定好ssh認證,那麼久可以執行。
轉載于:https://www.cnblogs.com/wxzhe/p/10418056.html