Ansible 起步指南
這是一篇關於 Ansible 的速成課程,你可以用作小專案的模板,或者幫你深入瞭解這個神奇的工具。閱讀了本指南之後,你將對自動化伺服器配置、部署等有足夠的瞭解。
Ansible 是什麼,為什麼你該瞭解?
Ansible 簡單的說是一個配置管理系統。你只需要可以使用 ssh 訪問你的伺服器或裝置就行。它也不同於其他工具,因為它使用推送的方式,而不是像 puppet 或 chef 那樣使用拉取的方式。你可以將程式碼部署到任意數量的伺服器上,配置網路裝置或在基礎架構中自動執行任何操作。
前置要求
假設你使用 Mac 或 Linux 作為你的工作站,Ubuntu Trusty 作為你的伺服器,並有一些安裝軟體包的經驗。此外,你的計算機上將需要以下軟體。所以,如果你還沒有它們,請先安裝:
- Virtualbox
- Vagrant
- Mac 使用者:Homebrew
情景
我們將模擬 2 個連線到 MySQL 資料庫的 Web 應用程式伺服器。Web 應用程式使用 Rails 5 和 Puma。
準備
Vagrantfile
為這個專案建立一個資料夾,並將下面的內容儲存到名為 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
配置你的虛擬網路
我們希望我們的虛擬機器能互相互動,但不要讓流量流出到真實的網路,所以我們將在 Virtualbox 中建立一個僅主機(HOST-Only)的網路介面卡。
- 開啟 Virtualbox
- 轉到 Preferences
- 轉到 Network
- 單擊 Host-Only
- 單擊新增網路
- 單擊 Adapter
- 將 IPv4 設定為
10.1.1.1
,IPv4 網路掩碼:255.255.255.0
- 單擊 “OK”
測試虛擬機器及虛擬網路
在終端中,在存放 Vagrantfile
的專案目錄中,輸入下面的命令:
vagrant up
它會建立你的虛擬機器,因此會花費一會時間。輸入下面的命令並驗證輸出內容以檢查是否已經工作:
$ 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`.
現在使用 vagrant
的使用者名稱和密碼 ,按 Vagrantfile
中的 IP 登入其中一臺虛擬機器,這將驗證虛擬機器並將它們的金鑰新增到你的已知主機(known_hosts
)檔案中。
ssh vagrant@10.1.1.11 # password is `vagrant`
ssh vagrant@10.1.1.12
ssh vagrant@10.1.1.21
恭喜你!現在你已經有可以實驗的伺服器了。下面的剩下的部分!
安裝 Ansible
對於 Mac 使用者:
$ brew install ansible
對於 Ubuntu 使用者:
$ sudo apt install ansible
確保你使用了ansible 最近的版本 2.1 或者更高的版本:
$ ansible --version
ansible 2.1.1.0
清單
Ansible 使用清單檔案來了解要使用的伺服器,以及如何將它們分組以並行執行任務。讓我們為這個專案建立我們的清單檔案 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]
定義一個組的組(all
)[all:vars]
定義屬於組all
的變數[webs]
定義一個組,就像[db]
一樣- 檔案的其餘部分只是主機的宣告,帶有它們的名稱和 IP
- 空行表示宣告結束
現在我們有了一個清單,我們可以從命令列開始使用 ansible,指定一個主機或一個組來執行命令。以下是檢查與伺服器的連線的命令示例:
$ ansible -i inventory all -m ping
-i
指定清單檔案all
指定要操作的伺服器或伺服器組-m' 指定一個 ansible 模組,在這種情況下為
ping`
下面是命令輸出:
dbserver | SUCCESS => {
"changed": false,
"ping": "pong"
}
web1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
web2 | SUCCESS => {
"changed": false,
"ping": "pong"
}
伺服器以不同的順序響應,這隻取決於誰先響應,但是這個沒有關係,因為 ansible 獨立保持每臺伺服器的狀態。
你也可以使用另外一個選項來執行任何命令:
-a <command>
$ 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
這是隻有一臺伺服器的另外一個例子:
$ 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)只是個 YAML 檔案,它將清單檔案中的伺服器組與命令關聯。在 ansible 中的對於關鍵字是 tasks
,它可以是一個預期的狀態、shell 命令或許多其它的選項。有關 ansible 可做的所有事情列表,可以檢視所有模組的列表。
下面是一個執行 shell 命令的劇本示例,將其儲存為 playbook1.yml
:
---
- hosts: all
tasks:
- shell: uptime
---
是 YAML 檔案的開始- hosts
:指定要使用的組tasks
:標記任務列表的開始- shell
:指定第一個任務使用 shell 模組- 記住:YAML 需要縮排結構,確保你始終遵循劇本中的正確結構
用下面的命令執行它:
$ 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
正如你所見,ansible 執行了 2 個任務,而不是隻有劇本中的一個。TASK [setup]
是一個隱式任務,它會首先執行以捕獲伺服器的資訊,如主機名、IP、發行版和更多詳細資訊,然後可以使用這些資訊執行條件任務。
還有最後的 PLAY RECAP
,其中 ansible 顯示了執行了多少個任務以及每個對應的狀態。在我們的例子中,因為我們執行了一個 shell 命令,ansible 不知道結果的狀態,它被認為是 changed
。
安裝軟體
我們將使用 apt 在我們的伺服器上安裝軟體,因為我們需要 root 許可權,所以我們必須使用 become
語句,將這個內容儲存在 playbook2.yml
中並執行它(ansible-playbook playbook2.yml
):
---
- hosts: webs
become_user: root
become: true
tasks:
- apt: name=git state=present
有一些語句可以應用於 ansible 中所有模組;一個是 name
語句,可以讓我們輸出關於正在執行的任務的更具描述性的文字。要使用它,保持任務內容一樣,但是新增 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
當你要處理一個列表時,比如要安裝的專案和軟體包、要建立的檔案,可以用 ansible 提供的 with_items
。下面是我們如何在 playbook3.yml
中使用它,同時新增一些我們已經知道的其他語句:
---
- 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
是一個定義變數語句,可以在 task
語句或 template
檔案中使用。 Jinja2 是 Ansible 中使用的模板引擎,但是關於它你不需要學習很多。在你的劇本中定義變數,如下所示:
---
- 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}}
作為劇本的一部分,但也因為我使用了 template
語句,我可以使用 myconfig.j2
中的任何變數,該檔案必須存在一個名為 templates
的子資料夾中。你專案樹應該如下所示:
├── Vagrantfile
├── inventory
├── playbook1.yml
├── playbook2.yml
└── templates
└── myconfig.j2
當 ansible 找到一個 template
語句後它會在 templates
資料夾內查詢,並將把被 {{
和 }}
括起來的變數展開來。
示例模板:
this is just an example vault_dir: {{path_to_vault}} secret_password: {{secret_key}}
即使你不擴充套件變數你也可以使用 template
。考慮到將來會新增所以我先做了。比如建立一個 hosts.j2
模板並加入主機名和 IP。
10.1.1.11 web1
10.1.1.12 web2
10.1.1.21 dbserver
這裡要用像這樣的語句:
- name: Installing the hosts file in all servers
template: src=hosts.j2 dest=/etc/hosts mode=644
shell 命令
你應該儘量使用模組,因為 Ansible 可以跟蹤任務的狀態,並避免不必要的重複,但有時 shell 命令是不可避免的。 對於這些情況,Ansible 提供兩個選項:
其他有用的模組
- apt_repository - 在 Debian 系的發行版中新增/刪除包倉庫
- yum_repository - 在 RedHat 系的發行版中新增/刪除包倉庫
- service - 啟動/停止/重新啟動/啟用/禁用服務
- git - 從 git 伺服器部署程式碼
- unarchive - 從 Web 或本地源解開軟體包
只在一臺伺服器中執行任務
Rails 使用 migrations 來逐步更改資料庫,但由於你有多個應用程式伺服器,因此這些遷移任務不能被分配為組任務,而我們只需要一個伺服器來執行遷移。在這種情況下,當使用 run_once
時,run_once
將分派任務到一個伺服器,並直到這個任務完成繼續下一個任務。你只需要在你的任務中設定 run_once:true
。
- name: 'Run db:migrate'
shell: cd {{appdir}};rails db:migrate
run_once: true
會失敗的任務
透過指定 ignore_errors:true
,你可以執行可能會失敗的任務,但不會影響劇本中剩餘的任務完成。這是非常有用的,例如,當刪除最初並不存在的日誌檔案時。
- name: 'Delete logs'
shell: rm -f /var/log/nginx/errors.log
ignore_errors: true
放到一起
現在用我們先前學到的,這裡是每個檔案的最終版:
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
放在你的環境中
將這些檔案放在相同的目錄,執行下面的命令開啟你的開發環境:
vagrant up
ansible-playbook -i inventory final-playbook.yml
部署新的程式碼
確保修改了程式碼並推送到了倉庫中。接下來,確保你 git 語句中使用了正確的分支:
- name: 'Clone app repo'
git:
repo=https://github.com/c0d5x/rails_dummyapp.git
dest={{appdir}}
version=staging
force=yes
作為一個例子,你可以修改 version
欄位為 master
,再次執行劇本:
ansible-playbook -i inventory final-playbook.yml
檢查所有的 web 伺服器上的頁面是否已更改:http://10.1.1.11
或 http://10.1.1.12
。將其更改為 version = staging
並重新執行劇本並再次檢查頁面。
你還可以建立只包含與部署相關的任務的替代劇本,以便其執行更快。
接下來是什麼 ?!
這只是可以做的很小一部分。我們沒有接觸角色、過濾器、除錯等許多其他很棒的功能,但我希望它給了你一個良好的開始!所以,請繼續學習並使用它。如果你有任何問題,你可以在 twitter 或評論欄聯絡我,讓我知道你還想知道哪些關於 ansible 的東西!
via: https://gorillalogic.com/blog/getting-started-with-ansible/?utm_source=webopsweekly&utm_medium=email
作者:JOSE HIDALGO 譯者:geekpi 校對:wxy
相關文章
- 『Ansible 上手指南』
- 『Ansible 上手指南:2』
- 創業起步?先收藏這份終極指南創業
- webpack 起步Web
- thinkphp起步PHP
- Redis 起步Redis
- 基於Ansible實現Apache Doris快速部署運維指南Apache運維
- Appfuse:起步APP
- ansible
- 【Ansible】ansible任務失敗控制
- Vue起步(無cli)Vue
- laravel和thinkphp起步LaravelPHP
- Augularjs-起步JS
- 【Ansible】ansible容器學習環境搭建
- ansible高階應用ansible-vault
- Ansible學習筆記-Ansible安裝筆記
- Ansible Playbook
- ansible register
- Ansible——模組
- ansible模組
- Ansible教程
- ansible template
- Flutter起步之安裝Flutter
- go學習之路 --- 起步Go
- cmake使用教程(一)-起步
- vue.js的起步Vue.js
- Activity的起步流程分析
- 第1章 jQuery 起步jQuery
- 第1章jQuery起步jQuery
- ansible變數變數
- ansible簡介
- Ansible進階
- ansible常用模組
- Spring Boot 起步依賴Spring Boot
- vue.js起步式(二)Vue.js
- ModelMaker 新手起步(一) (轉)
- Linux架構31 ansible roles角色, ansible galaxyLinux架構
- Could not find or access '/etc/ansible/bin/cfssljson /etc/ansible/bin/cfsslJSON