現在要來把之前機器初始化的手動腳本, 改成自動化
如果你是 Mac 又沒裝 XCode 可參考做法 Install Ansible on Mac
如果是 CentOS 就順著往下做就可以
安裝 Ansible
先更新
1 | sudo yum install epel-release -y |
Install python-pip from epel
1 | sudo yum install python-pip -y |
Verify using
1 | sudo pip -V |
Upgrade pip
1 | sudo pip install --upgrade pip |
Install Ansible
1 | sudo yum install ansible -y |
Install Verify Tool
1 | sudo pip install ansible-lint |
到這一步我們控制的主機基本上是裝好了
接下來我們來初始化 Ansible Controller 資料夾
Ansible config file
配置文件 按優先級排序如下:
- ANSIBLE_CONFIG (環境變量,如果不為空則最優先)
- ansible.cfg (當前路徑下的配置)
- ~/.ansible.cfg (用戶主目錄下)
- /etc/ansible/ansible.cfg (全局配置文件)
CentOS 裝好預設是會有建立目錄1
2
3
4
5$ ls -lh /etc/ansible
total 24K
-rw-r--r--. 1 root root 20K Feb 21 18:04 ansible.cfg
-rw-r--r--. 1 root root 1016 Feb 21 18:04 hosts
drwxr-xr-x. 2 root root 6 Feb 21 18:04 roles
ansible.cfg => Setting ansible執行roles路徑及其他設定功能
hosts => Setting ssh 遠端vm
roles => defule 角色
如果沒有的話也可以下載範例來修改1
curl -sSL https://raw.githubusercontent.com/ansible/ansible/devel/examples/ansible.cfg -o ~/.ansible.cfg
Inventory
受 Ansible 管理的主機列表
格式如下1
2
3
4
5
6
7[group_eureka]
eureka-01 ansible_host=192.168.0.11 ansible_user=root
eureka-02 ansible_host=192.168.0.12 ansible_user=root
[group_config]
config_01 ansible_host=192.168.0.31 ansible_user=root
config_02 ansible_host=192.168.0.32 ansible_user=root
方括弧內的就是所謂群組, 你可以一次指定一個群組, 或是單一一台主機名
例如
指定 eureka-01 一台1
ansible-playbook playbooks/PLAYBOOK_NAME.yml --limit "eureka-01"
指定一個群組 group_config 主機 config_01 & config_02 都會執行1
ansible-playbook playbooks/PLAYBOOK_NAME.yml --limit 'group_config'
做個練習讓 Ansible 去 ping 看看所有主機
1 | cat << 'EOF' > inventory |
假設 eureka-01 & config_01 都是正常可以 ping 得到 結果應該類似如下就成功了1
2
3
4
5
6
7
8
9
10ansible -i ./inventory group_config -m ping
config_02 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: ssh: connect to host 192.168.0.32 port 22: Operation timed out",
"unreachable": true
}
config_01 | SUCCESS => {
"changed": false,
"ping": "pong"
}
其他說明參考官網 Ansible Limiting Playbook/Task Runs
Ansible initialization folder
要透過 ansible 操作當然免不了要分資料夾來做管理不同環境
你可以參考官方 Ansible Best Practices Directory Layout,
或是 凍仁翔 大大的實戰分享 現代 IT 人一定要知道的 Ansible 自動化組態技巧 19. 如何維護大型的 Ansible Playbooks?
我簡化一下只列出這次練習會用得到的部分, 完整的到官網看吧1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43production # 正式環境主機管理檔
staging # 測試環境主機管理檔
group_vars/ # 群組變數
all.yml # 各環境共用的群組變數
production.yml # 正式環境的群組變數
staging.yml # 測試環境的群組變數
host_vars/ # 主機變數
hostname1.yml # here we assign variables to particular systems
hostname2.yml
library/ # if any custom modules, put them here (optional)
module_utils/ # if any custom module_utils to support modules, put them here (optional)
filter_plugins/ # if any custom filter plugins, put them here (optional)
site.yml # master playbook
webservers.yml # playbook for webserver tier
dbservers.yml # playbook for dbserver tier
roles/
common/ # this hierarchy represents a "role"
tasks/ #
main.yml # <-- tasks file can include smaller files if warranted
handlers/ #
main.yml # <-- handlers file
templates/ # <-- files for use with the template resource
ntp.conf.j2 # <------- templates end in .j2
files/ #
bar.txt # <-- files for use with the copy resource
foo.sh # <-- script files for use with the script resource
vars/ #
main.yml # <-- variables associated with this role
defaults/ #
main.yml # <-- default lower priority variables for this role
meta/ #
main.yml # <-- role dependencies
library/ # roles can also include custom modules
module_utils/ # roles can also include custom module_utils
lookup_plugins/ # or other types of plugins, like lookup in this case
webtier/ # same kind of structure as "common" was above, done for the webtier role
monitoring/ # ""
fooapp/ # ""
在範例資料夾來建立一些目錄讓他跟官方建議的目錄比較接近1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31cat << 'EOF' > README.md
Ansible 腳本範例
EOF
# 開發環境
cat << 'EOF' > dev
[group_eureka]
eureka-01 ansible_host=192.168.1.11 ansible_user=root
eureka-02 ansible_host=192.168.1.12 ansible_user=root
[group_config]
config_01 ansible_host=192.168.1.31 ansible_user=root
config_02 ansible_host=192.168.1.32 ansible_user=root
EOF
# 開發預發佈環境
cat << 'EOF' > dev-release
[group_eureka]
eureka-01 ansible_host=192.168.2.11 ansible_user=root
eureka-02 ansible_host=192.168.2.12 ansible_user=root
[group_config]
config_01 ansible_host=192.168.2.31 ansible_user=root
config_02 ansible_host=192.168.2.32 ansible_user=root
EOF
mkdir group_vars
mkdir roles
mkdir files
Playbook
第一個 playbook
建立初始化 playbook, 但是剛開始練首先用簡單一點的 印出主機名稱1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21cat << 'EOF' > initial.yml
- name: Ansible Check
hosts: "{{ myhosts }}"
serial: 1
tasks:
- name: echo whoami
command: whoami
register: whoami_result
- name: print whoami result
debug:
msg: "{{ whoami_result.stdout }}"
- name: echo hostname
command: hostname
register: hostname_result
- name: print hostname result
debug:
msg: "{{ hostname_result.stdout }}"
EOF
目前結構1
2
3
4
5
6
7
8
9
10$ tree
.
├── README.md
├── dev
├── dev-release
├── group_vars
├── initial.yml
└── roles
2 directories, 4 files
如何執行, 重要的參數使用系統變數來讀入執行1
2
3export myhosts=all
export ansible_password=1qaz2wsx
ansible-playbook -i ./dev ./initial.yml -e "myhosts=${myhosts}" -vv --extra-vars "ansible_password=${ANSIBLE_PASSWORD}"
免詢問登入
如果你還沒有修改免確認登入會變成卡在這邊1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19$ ansible-playbook -i ./dev ./initial.yml -e "myhosts=${myhosts}" -vv --extra-vars "ansible_password=${ANSIBLE_PASSWORD}"
ansible-playbook 2.8.1
config file = None
configured module search path = ['/Users/shanglichu/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/Cellar/ansible/2.8.1_1/libexec/lib/python3.7/site-packages/ansible
executable location = /usr/local/bin/ansible-playbook
python version = 3.7.3 (default, Jun 19 2019, 07:38:49) [Clang 10.0.1 (clang-1001.0.46.4)]
No config file found; using defaults
PLAYBOOK: initial.yml ****************************************************************************************************************************************************
1 plays in ./initial.yml
PLAY [Ansible Check] *****************************************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************************************
task path: /ansible-demo/initial.yml:1
The authenticity of host '10.0.29.95 (10.0.29.95)' can't be established.
ECDSA key fingerprint is SHA256:rfeIQ8KcFwSk24fnjYelPAb1wXFuL4Byok0hPXMzylQ.
Are you sure you want to continue connecting (yes/no)?
依照官方文件Host Key Checking
你可以在設定檔 /etc/ansible/ansible.cfg or ~/.ansible.cfg 配置1
2[defaults]
host_key_checking = False
或是配在環境變數1
export ANSIBLE_HOST_KEY_CHECKING=False
缺 sshpass 工具
接下來你可能會遇到這個錯1
2
3
4
5
6
7
8
9$ ansible-playbook -i ./dev ./initial.yml -e "myhosts=${myhosts}" -e ansible_password=1qaz2wsx
PLAY [Ansible Check] *****************************************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************************************
fatal: [eureka-01]: FAILED! => {"msg": "to use the 'ssh' connection type with passwords, you must install the sshpass program"}
PLAY RECAP ***************************************************************************************************************************************************************
eureka-01 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
安裝方式1
2
3
4
5
6
7
8# CentOS
yum -y install sshpass
# Mac
brew install https://raw.githubusercontent.com/kadwanev/bigboybrew/master/Library/Formula/sshpass.rb
# 網路找到另一個地方 程式碼一樣
brew install http://git.io/sshpass.rb
Mac 執行結果1
2
3
4
5
6
7
8
9
10
11
12
13
14
15$ brew install https://raw.githubusercontent.com/kadwanev/bigboybrew/master/Library/Formula/sshpass.rb
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 1 tap (homebrew/core).
==> Updated Formulae
angular-cli bazel devspace exploitdb grpc libuv neo4j skaffold wireguard-tools
argon2 blink1 dub gatsby-cli kubeless mujs paket terragrunt
######################################################################## 100.0%
==> Downloading http://sourceforge.net/projects/sshpass/files/sshpass/1.06/sshpass-1.06.tar.gz
==> Downloading from https://nchc.dl.sourceforge.net/project/sshpass/sshpass/1.06/sshpass-1.06.tar.gz
######################################################################## 100.0%
==> ./configure --prefix=/usr/local/Cellar/sshpass/1.06
==> make install
🍺 /usr/local/Cellar/sshpass/1.06: 9 files, 41.6KB, built in 24 seconds
執行結果
再執行一次1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28$ export myhosts=all
$ export ansible_password=1qaz2wsx
$ export ANSIBLE_HOST_KEY_CHECKING=False
$ ansible-playbook -i ./dev ./initial.yml -e "myhosts=${myhosts}" -e "ansible_password=${ansible_password}"
PLAY [Ansible Check] *****************************************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************************************
ok: [eureka-01]
TASK [echo whoami] *******************************************************************************************************************************************************
changed: [eureka-01]
TASK [print whoami result] ***********************************************************************************************************************************************
ok: [eureka-01] => {
"msg": "root"
}
TASK [echo hostname] *****************************************************************************************************************************************************
changed: [eureka-01]
TASK [print hostname result] *********************************************************************************************************************************************
ok: [eureka-01] => {
"msg": "localhost.localdomain"
}
PLAY RECAP ***************************************************************************************************************************************************************
eureka-01 : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
這樣我們就可以順利操作遠端的機器, 並取得登入帳號跟 hostname 了
Role
當你要配置的功能種類越來越多的時候, Role 會是比較好管理的選擇
初始化特定角色資料夾1
2$ ansible-galaxy init roles/springboot
- roles/springboot was created successfully
這樣我們就有一個 springboot 角色資料夾, 有關 springboot 部署要用的檔案或配置就可以放這了
完整結構1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27$ tree
.
├── README.md
├── dev
├── dev-release
├── group_vars
├── initial.yml
└── roles
└── springboot
├── README.md
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── tasks
│ └── main.yml
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
11 directories, 12 files
如何練習
基本的介紹完了
要開始正式寫腳本, 會需要常常重置 VM, 蠻推薦使用
VirtualBox 加上 Vagrant
來當作一個組合技, 非常之好用.
References
現代 IT 人一定要知道的 Ansible 自動化組態技巧 19. 如何維護大型的 Ansible Playbooks?
Ansible中文权威指南
SAM的程式筆記 由朱尚禮製作,以創用CC 姓名標示-非商業性-相同方式分享 4.0 國際 授權條款釋出。