新聞中心
這是一篇關(guān)于 Ansible 的速成課程,你可以用作小項(xiàng)目的模板,或者幫你深入了解這個(gè)神奇的工具。閱讀了本指南之后,你將對(duì)自動(dòng)化服務(wù)器配置、部署等有足夠的了解。

Ansible 是什么,為什么你該了解?
Ansible 簡(jiǎn)單的說(shuō)是一個(gè)配置管理系統(tǒng)(configuration management system)。你只需要可以使用 ssh 訪(fǎng)問(wèn)你的服務(wù)器或設(shè)備就行。它也不同于其他工具,因?yàn)樗褂猛扑偷姆绞?,而不是?puppet 或 chef 那樣使用拉取的方式。你可以將代碼部署到任意數(shù)量的服務(wù)器上,配置網(wǎng)絡(luò)設(shè)備或在基礎(chǔ)架構(gòu)中自動(dòng)執(zhí)行任何操作。
前置要求
假設(shè)你使用 Mac 或 Linux 作為你的工作站,Ubuntu Trusty 作為你的服務(wù)器,并有一些安裝軟件包的經(jīng)驗(yàn)。此外,你的計(jì)算機(jī)上將需要以下軟件。所以,如果你還沒(méi)有它們,請(qǐng)先安裝:
- Virtualbox
- Vagrant
- Mac 用戶(hù):Homebrew
情景
我們將模擬 2 個(gè)連接到 MySQL 數(shù)據(jù)庫(kù)的 Web 應(yīng)用程序服務(wù)器。Web 應(yīng)用程序使用 Rails 5 和 Puma。
準(zhǔn)備
Vagrantfile
為這個(gè)項(xiàng)目創(chuàng)建一個(gè)文件夾,并將下面的內(nèi)容保存到名為 Vagrantfile 的文件。
VMs = [
[ "web1", "10.1.1.11"],
[ "web2", "10.1.1.12"],
[ "dbserver", "10.1.1.21"],
]
Vagrant.configure(2) do |config|
VMs.each { |vm|
config.vm.define vm[0] do |box|
box.vm.box = "ubuntu/trusty64"
box.vm.network "private_network", ip: vm[1]
box.vm.hostname = vm[0]
box.vm.provider "virtualbox" do |vb|
vb.memory = "512"
end
end
}
end
配置你的虛擬網(wǎng)絡(luò)
我們希望我們的虛擬機(jī)能互相交互,但不要讓流量流出到真實(shí)的網(wǎng)絡(luò),所以我們將在 Virtualbox 中創(chuàng)建一個(gè)僅主機(jī)(HOST-Only)的網(wǎng)絡(luò)適配器。
- 打開(kāi) Virtualbox
- 轉(zhuǎn)到 Preferences
- 轉(zhuǎn)到 Network
- 單擊 Host-Only
- 單擊添加網(wǎng)絡(luò)
- 單擊 Adapter
- 將 IPv4 設(shè)置為
10.1.1.1,IPv4 網(wǎng)絡(luò)掩碼:255.255.255.0 - 單擊 “OK”
測(cè)試虛擬機(jī)及虛擬網(wǎng)絡(luò)
在終端中,在存放 Vagrantfile 的項(xiàng)目目錄中,輸入下面的命令:
vagrant up
它會(huì)創(chuàng)建你的虛擬機(jī),因此會(huì)花費(fèi)一會(huì)時(shí)間。輸入下面的命令并驗(yàn)證輸出內(nèi)容以檢查是否已經(jīng)工作:
$ vagrant status
Current machine states:
web1 running (virtualbox)
web2 running (virtualbox)
master running (virtualbox)
This environment represents multiple VMs. The VMs are all listed
above with their current state. For more information about a specific
VM, run `vagrant status NAME`.
現(xiàn)在使用 vagrant 的用戶(hù)名和密碼 ,按 Vagrantfile 中的 IP 登錄其中一臺(tái)虛擬機(jī),這將驗(yàn)證虛擬機(jī)并將它們的密鑰添加到你的已知主機(jī)(known_hosts)文件中。
ssh [email protected] # password is `vagrant`
ssh [email protected]
ssh [email protected]
恭喜你!現(xiàn)在你已經(jīng)有可以實(shí)驗(yàn)的服務(wù)器了。下面的剩下的部分!
安裝 Ansible
對(duì)于 Mac 用戶(hù):
$ brew install ansible
對(duì)于 Ubuntu 用戶(hù):
$ sudo apt install ansible
確保你使用了ansible 最近的版本 2.1 或者更高的版本:
$ ansible --version
ansible 2.1.1.0
清單
Ansible 使用清單文件來(lái)了解要使用的服務(wù)器,以及如何將它們分組以并行執(zhí)行任務(wù)。讓我們?yōu)檫@個(gè)項(xiàng)目創(chuàng)建我們的清單文件 inventory,并將它放在與 Vagrantfile 相同的文件夾中:
[all:children]
webs
db
[all:vars]
ansible_user=vagrant
ansible_ssh_pass=vagrant
[webs]
web1 ansible_host=10.1.1.11
web2 ansible_host=10.1.1.12
[db]
dbserver ansible_host=10.1.1.21
[all:children]定義一個(gè)組的組(all)[all:vars]定義屬于組all的變量[webs]定義一個(gè)組,就像[db]一樣- 文件的其余部分只是主機(jī)的聲明,帶有它們的名稱(chēng)和 IP
- 空行表示聲明結(jié)束
現(xiàn)在我們有了一個(gè)清單,我們可以從命令行開(kāi)始使用 ansible,指定一個(gè)主機(jī)或一個(gè)組來(lái)執(zhí)行命令。以下是檢查與服務(wù)器的連接的命令示例:
$ ansible -i inventory all -m ping
-i指定清單文件all指定要操作的服務(wù)器或服務(wù)器組-m' 指定一個(gè) ansible 模塊,在這種情況下為ping`
下面是命令輸出:
dbserver | SUCCESS => {
"changed": false,
"ping": "pong"
}
web1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
web2 | SUCCESS => {
"changed": false,
"ping": "pong"
}
服務(wù)器以不同的順序響應(yīng),這只取決于誰(shuí)先響應(yīng),但是這個(gè)沒(méi)有關(guān)系,因?yàn)?ansible 獨(dú)立保持每臺(tái)服務(wù)器的狀態(tài)。
你也可以使用另外一個(gè)選項(xiàng)來(lái)運(yùn)行任何命令:
-a
$ ansible -i inventory all -a uptime
web1 | SUCCESS | rc=0 >>
21:43:27 up 25 min, 1 user, load average: 0.00, 0.01, 0.05
dbserver | SUCCESS | rc=0 >>
21:43:27 up 24 min, 1 user, load average: 0.00, 0.01, 0.05
web2 | SUCCESS | rc=0 >>
21:43:27 up 25 min, 1 user, load average: 0.00, 0.01, 0.05
這是只有一臺(tái)服務(wù)器的另外一個(gè)例子:
$ ansible -i inventory dbserver -a "df -h /"
dbserver | SUCCESS | rc=0 >>
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 40G 1.4G 37G 4% /
劇本
劇本(playbook)只是個(gè) YAML 文件,它將清單文件中的服務(wù)器組與命令關(guān)聯(lián)。在 ansible 中的對(duì)于關(guān)鍵字是 tasks,它可以是一個(gè)預(yù)期的狀態(tài)、shell 命令或許多其它的選項(xiàng)。有關(guān) ansible 可做的所有事情列表,可以查看所有模塊的列表。
下面是一個(gè)運(yùn)行 shell 命令的劇本示例,將其保存為 playbook1.yml:
---
- hosts: all
tasks:
- shell: uptime
---是 YAML 文件的開(kāi)始- hosts:指定要使用的組tasks:標(biāo)記任務(wù)列表的開(kāi)始- shell:指定第一個(gè)任務(wù)使用 shell 模塊- 記?。篩AML 需要縮進(jìn)結(jié)構(gòu),確保你始終遵循劇本中的正確結(jié)構(gòu)
用下面的命令運(yùn)行它:
$ ansible-playbook -i inventory playbook1.yml
PLAY [all] *********************************************************************
TASK [setup] *******************************************************************
ok: [web1]
ok: [web2]
ok: [dbmaster]
TASK [command] *****************************************************************
changed: [web1]
changed: [web2]
changed: [dbmaster]
PLAY RECAP *********************************************************************
dbmaster : ok=2 changed=1 unreachable=0 failed=0
web1 : ok=2 changed=1 unreachable=0 failed=0
web2 : ok=2 changed=1 unreachable=0 failed=0
正如你所見(jiàn),ansible 運(yùn)行了 2 個(gè)任務(wù),而不是只有劇本中的一個(gè)。TASK [setup] 是一個(gè)隱式任務(wù),它會(huì)首先運(yùn)行以捕獲服務(wù)器的信息,如主機(jī)名、IP、發(fā)行版和更多詳細(xì)信息,然后可以使用這些信息運(yùn)行條件任務(wù)。
還有最后的 PLAY RECAP,其中 ansible 顯示了運(yùn)行了多少個(gè)任務(wù)以及每個(gè)對(duì)應(yīng)的狀態(tài)。在我們的例子中,因?yàn)槲覀冞\(yùn)行了一個(gè) shell 命令,ansible 不知道結(jié)果的狀態(tài),它被認(rèn)為是 changed。
安裝軟件
我們將使用 apt 在我們的服務(wù)器上安裝軟件,因?yàn)槲覀冃枰?root 權(quán)限,所以我們必須使用 become 語(yǔ)句,將這個(gè)內(nèi)容保存在 playbook2.yml 中并運(yùn)行它(ansible-playbook playbook2.yml):
---
- hosts: webs
become_user: root
become: true
tasks:
- apt: name=git state=present
有一些語(yǔ)句可以應(yīng)用于 ansible 中所有模塊;一個(gè)是 name 語(yǔ)句,可以讓我們輸出關(guān)于正在執(zhí)行的任務(wù)的更具描述性的文本。要使用它,保持任務(wù)內(nèi)容一樣,但是添加 name :描述性文本 作為第一行,所以我們以前的文本將改成:
---
- hosts: webs
become_user: root
become: true
tasks:
- name: This task will make sure git is present on the system
apt: name=git state=present
使用 with_items
當(dāng)你要處理一個(gè)列表時(shí),比如要安裝的項(xiàng)目和軟件包、要?jiǎng)?chuàng)建的文件,可以用 ansible 提供的 with_items。下面是我們?nèi)绾卧?playbook3.yml 中使用它,同時(shí)添加一些我們已經(jīng)知道的其他語(yǔ)句:
---
- hosts: all
become_user: root
become: true
tasks:
- name: Installing dependencies
apt: name={{item}} state=present
with_items:
- git
- mysql-client
- libmysqlclient-dev
- build-essential
- python-software-properties
使用 template 和 vars
vars 是一個(gè)定義變量語(yǔ)句,可以在 task 語(yǔ)句或 template 文件中使用。 Jinja2 是 Ansible 中使用的模板引擎,但是關(guān)于它你不需要學(xué)習(xí)很多。在你的劇本中定義變量,如下所示:
---
- hosts: all
vars:
- secret_key: VqnzCLdCV9a3jK
- path_to_vault: /opt/very/deep/path
tasks:
- name: Setting a configuration file using template
template: src=myconfig.j2 dest={{path_to_vault}}/app.conf
正如你看到的,我可以使用 {{path_to_vault}} 作為劇本的一部分,但也因?yàn)槲沂褂昧?template語(yǔ)句,我可以使用 myconfig.j2 中的任何變量,該文件必須存在一個(gè)名為 templates 的子文件夾中。你項(xiàng)目樹(shù)應(yīng)該如下所示:
├── Vagrantfile
├── inventory
├── playbook1.yml
├── playbook2.yml
└── templates
└── myconfig.j2
當(dāng) ansible 找到一個(gè) template 語(yǔ)句后它會(huì)在 templates 文件夾內(nèi)查找,并將把被 {{ 和 }} 括起來(lái)的變量展開(kāi)來(lái)。
示例模板:
this is just an example vault_dir: {{path_to_vault}} secret_password: {{secret_key}}
即使你不擴(kuò)展變量你也可以使用 template??紤]到將來(lái)會(huì)添加所以我先做了。比如創(chuàng)建一個(gè) hosts.j2 模板并加入主機(jī)名和 IP。
10.1.1.11 web1
10.1.1.12 web2
10.1.1.21 dbserver
這里要用像這樣的語(yǔ)句:
- name: Installing the hosts file in all servers
template: src=hosts.j2 dest=/etc/hosts mode=644
shell 命令
你應(yīng)該盡量使用模塊,因?yàn)?Ansible 可以跟蹤任務(wù)的狀態(tài),并避免不必要的重復(fù),但有時(shí) shell 命令是不可避免的。 對(duì)于這些情況,Ansible 提供兩個(gè)選項(xiàng):
- command:直接運(yùn)行一個(gè)命令,沒(méi)有環(huán)境變量或重定向(
|,<,>等) - shell:運(yùn)行
/bin/sh并展開(kāi)變量和支持重定向
其他有用的模塊
- apt_repository - 在 Debian 系的發(fā)行版中添加/刪除包倉(cāng)庫(kù)
- yum_repository - 在 RedHat 系的發(fā)行版中添加/刪除包倉(cāng)庫(kù)
- service - 啟動(dòng)/停止/重新啟動(dòng)/啟用/禁用服務(wù)
- git - 從 git 服務(wù)器部署代碼
- unarchive - 從 Web 或本地源解開(kāi)軟件包
只在一臺(tái)服務(wù)器中運(yùn)行任務(wù)
Rails 使用 migrations 來(lái)逐步更改數(shù)據(jù)庫(kù),但由于你有多個(gè)應(yīng)用程序服務(wù)器,因此這些遷移任務(wù)不能被分配為組任務(wù),而我們只需要一個(gè)服務(wù)器來(lái)運(yùn)行遷移。在這種情況下,當(dāng)使用 run_once 時(shí),run_once 將分派任務(wù)到一個(gè)服務(wù)器,并直到這個(gè)任務(wù)完成繼續(xù)下一個(gè)任務(wù)。你只需要在你的任務(wù)中設(shè)置 run_once:true。
- name: 'Run db:migrate'
shell: cd {{appdir}};rails db:migrate
run_once: true
會(huì)失敗的任務(wù)
通過(guò)指定 ignore_errors:true,你可以運(yùn)行可能會(huì)失敗的任務(wù),但不會(huì)影響劇本中剩余的任務(wù)完成。這是非常有用的,例如,當(dāng)刪除最初并不存在的日志文件時(shí)。
- name: 'Delete logs'
shell: rm -f /var/log/nginx/errors.log
ignore_errors: true
放到一起
現(xiàn)在用我們先前學(xué)到的,這里是每個(gè)文件的最終版:
Vagrantfile:
VMs = [
[ "web1", "10.1.1.11"],
[ "web2", "10.1.1.12"],
[ "dbserver", "10.1.1.21"],
]
Vagrant.configure(2) do |config|
VMs.each { |vm|
config.vm.define vm[0] do |box|
box.vm.box = "ubuntu/trusty64"
box.vm.network "private_network", ip: vm[1]
box.vm.hostname = vm[0]
box.vm.provider "virtualbox" do |vb|
vb.memory = "512"
end
end
}
end
inventory:
[all:children]
webs
db
[all:vars]
ansible_user=vagrant
ansible_ssh_pass=vagrant
[webs]
web1 ansible_host=10.1.1.11
web2 ansible_host=10.1.1.12
[db]
dbserver ansible_host=10.1.1.21
templates/hosts.j2:
10.1.1.11 web1
10.1.1.12 web2
10.1.1.21 dbserver
templates/my.cnf.j2:
[client]
port = 3306
socket = /var/run/mysqld/mysqld.sock
[mysqld_safe]
socket = /var/run/mysqld/mysqld.sock
nice = 0
[mysqld]
server-id = 1
user = mysql
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
port = 3306
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
lc-messages-dir = /usr/share/mysql
skip-external-locking
bind-address = 0.0.0.0
key_buffer = 16M
max_allowed_packet = 16M
thread_stack = 192K
thread_cache_size = 8
myisam-recover = BACKUP
query_cache_limit = 1M
query_cache_size = 16M
log_error = /var/log/mysql/error.log
expire_logs_days = 10
max_binlog_size = 100M
[mysqldump]
quick
quote-names
max_allowed_packet = 16M
[mysql]
[isamchk]
key_buffer = 16M
!includedir /etc/mysql/conf.d/
final-playbook.yml:
- hosts: all
become_user: root
become: true
tasks:
- name: 'Install common software on all servers'
apt: name={{item}} state=present
with_items:
- git
- mysql-client
- libmysqlclient-dev
- build-essential
- python-software-properties
- name: 'Install hosts file'
template: src=hosts.j2 dest=/etc/hosts mode=644
- hosts: db
become_user: root
become: true
tasks:
- name: 'Software for DB server'
apt: name={{item}} state=present
with_items:
- mysql-server
- percona-xtrabackup
- mytop
- mysql-utilities
- name: 'MySQL config file'
template: src=my.cnf.j2 dest=/etc/mysql/my.cnf
- name: 'Restart MySQL'
service: name=mysql state=restarted
- name: 'Grant access to web app servers'
shell: echo 'GRANT ALL PRIVILEGES ON *.* TO "root"@"%" WITH GRANT OPTION;FLUSH PRIVILEGES;'|mysql -u root mysql
- hosts: webs
vars:
- appdir: /opt/dummyapp
become_user: root
become: true
tasks:
- name: 'Add ruby-ng repo'
apt_repository: repo='ppa:brightbox/ruby-ng'
- name: 'Install rails software'
apt: name={{item}} state=present
with_items:
- ruby-dev
- ruby-all-dev
- ruby2.2
- ruby2.2-dev
- ruby-switch
- libcurl4-openssl-dev
- libssl-dev
- zlib1g-dev
- nodejs
- name: 'Set ruby to 2.2'
shell: ruby-switch --set ruby2.2
- name: 'Install gems'
shell: gem install bundler rails
- name: 'Kill puma if running'
shell: file /run/puma.pid >/dev/null && kill `cat /run/puma.pid` 2>/dev/null
ignore_errors: True
- name: 'Clone app repo'
git:
repo=https://github.com/c0d5x/rails_dummyapp.git
dest={{appdir}}
version=staging
force=yes
- name: 'Run bundler'
shell: cd {{appdir}};bundler
- name: 'Run db:setup'
shell: cd {{appdir}};rails db:setup
run_once: true
- name: 'Run db:migrate'
shell: cd {{appdir}};rails db:migrate
run_once: true
- name: 'Run rails server'
shell: cd {{appdir}};rails server -b 0.0.0.0 -p 80 --pid /run/puma.pid -d
放在你的環(huán)境中
將這些文件放在相同的目錄,運(yùn)行下面的命令打開(kāi)你的開(kāi)發(fā)環(huán)境:
vagrant up
ansible-playbook -i inventory final-playbook.yml
部署新的代碼
確保修改了代碼并推送到了倉(cāng)庫(kù)中。接下來(lái),確保你 git 語(yǔ)句中使用了正確的分支:
- name: 'Clone app repo'
git:
repo=https://github.com/c0d5x/rails_dummyapp.git
dest={{appdir}}
version=staging
force=yes
作為一個(gè)例子,你可以修改 version 字段為 master,再次運(yùn)行劇本:
ansible-playbook -i inventory final-playbook.yml
檢查所有的 web 服務(wù)器上的頁(yè)面是否已更改:http://10.1.1.11 或 http://10.1.1.12。將其更改為 version = staging 并重新運(yùn)行劇本并再次檢查頁(yè)面。
你還可以創(chuàng)建只包含與部署相關(guān)的任務(wù)的替代劇本,以便其運(yùn)行更快。
接下來(lái)是什么 ?!
這只是可以做的很小一部分。我們沒(méi)有接觸角色(role)、過(guò)濾器(filter)、調(diào)試等許多其他很棒的功能,但我希望它給了你一個(gè)良好的開(kāi)始!所以,請(qǐng)繼續(xù)學(xué)習(xí)并使用它。如果你有任何問(wèn)題,你可以在 twitter 或評(píng)論欄聯(lián)系我,讓我知道你還想知道哪些關(guān)于 ansible 的東西!
分享題目:Ansible起步指南
URL鏈接:http://fisionsoft.com.cn/article/djiijoe.html


咨詢(xún)
建站咨詢(xún)
