1. 程式人生 > >【視訊】特別適合新手的運維利器ansible入門教程手冊(附帶視訊演示和原始碼)

【視訊】特別適合新手的運維利器ansible入門教程手冊(附帶視訊演示和原始碼)

作者: 李佶澳   轉載請保留:原文地址   釋出時間:2018/03/12 15:43:00


說明

ansible是一個常用的運維管理工具,使用它可以避免很多重複性工作,節省大量時間。

這裡是IT技術快速入門學院演示視訊中使用的文件,可以在系列教程中找到該系列所有文章。

QQ交流群(ansible實踐互助):955105412。


一句話原理

ansible就是把你手動ssh登入到多個目標機器上進行的一系列操作的過程自動化。

你只需要確保執行ansible命令的本地機器能夠通過使用者名稱和密碼登入到目標機器上,並且在本地機器上的ansible檔案中寫好要在目標機器上執行的操作。

目標機器只需要支援ssh登入和python命令(一般的linux作業系統都有,ansible會將python寫的任務指令碼上傳到目標機器上執行)。

文件介紹

ansible的文件首頁 https://docs.ansible.com/ 對文件進行了分類,都是接到了文件內容頁面

安裝文件中介紹了ansible的安裝方法,作為一個很基礎的工具,基本上每個作業系統,都有對應的安裝方法。

官方的Getting Started介紹的太簡單了,對初學者來說,看完還是一頭霧水。

下載素材

git clone https://github.com/lijiaocn/ansible-example.git

兩個命令: ansible 與 ansible-playbook

ansible有兩個命令,一個是ansible,一個是ansible-playbook,前者需要每次輸入要執行的命令,後者可以讀取playbook檔案,一次性完成playbook檔案中指定一系列操作。

playbook檔案是重點,文件中有很大篇幅是介紹playbook的:playbook

用ansible命令操作目標機器

準備hosts檔案

需要準備一個檔案,在檔案中寫下目標機器的地址,這個檔案預設是/etc/ansible/hosts,但是為了管理方便,最好為每個環境單獨建立一個hosts檔案。

比方說建立一個名為inventories的目錄,在這個目錄下,為生產環境的機器建立一個production目錄,production/hosts中記錄的是生產環境中的機器的地址,demo/hosts中記錄的是演示環境中機器的地址,這樣將不同環境中的機器明確地分開了,可以減少運維事故。

$ tree inventories/
inventories/
├── production
│   └── hosts
└── demo
    └── hosts

hosts檔案中可以直接是目標機器的地址,可以是IP,也可以是域名,每個地址佔用一行,例如:

192.168.33.11
www.baidu.com

如果目標叢集中的機器的角色相同,承擔的是同樣任務,這種方式一般也足夠了。如果目標叢集中的機器分別承擔不同任務,最好將它們按照各自的角色分組,例如:

[master]192.168.33.11[nodes]192.168.33.11192.168.33.12192.168.33.13

同一個地址,可以同時位於多個組中。

可以對分組再次分組,例如《Kubernetes1.12從零開始》中使用的hosts檔案是這樣的:

[etcd]192.168.33.11192.168.33.12192.168.33.13[master]192.168.33.11192.168.33.12192.168.33.13[node]192.168.33.11192.168.33.12192.168.33.13[kube-router]192.168.33.11192.168.33.12192.168.33.13#############   group's group   ##############[etcd_client:children]etcdmaster[etcd_server:children]etcd[etcd_peer:children]etcd[apiserver:children]master[controller:children]master[scheduler:children]master[kubelet_client:children]master[kubelet:children]node

名稱裡有:children的分組,是分組的分組,它的成員是前面定義的分組。

還可以在這裡為每個機器設定變數,譬如《HyperLedger Fabric手把手入門》中使用的hosts檔案:

[orderer]orderer0.member1.example.com MSPID=orderers.member1.example.com ORG_DOMAIN=member1.example.com ansible_host=192.168.33.11[peer]peer0.member1.example.com MSPID=peers.member1.example.com ORG_DOMAIN=member1.example.com ansible_host=192.168.33.11 STATE_DB=CouchDB COUCH_USER=admin COUCH_PASS=passwordpeer1.member1.example.com MSPID=peers.member1.example.com ORG_DOMAIN=member1.example.com ansible_host=192.168.33.12 STATE_DB=CouchDB COUCH_USER=admin COUCH_PASS=passwordpeer0.member2.example.com MSPID=peers.member2.example.com ORG_DOMAIN=member2.example.com ansible_host=192.168.33.13 STATE_DB=CouchDB COUCH_USER=admin COUCH_PASS=password[machine]192.168.33.11192.168.33.12192.168.33.13

你已經注意到了,這個hosts檔案不太一樣,地址後面多出了一些諸如MSPID=XXX樣式的內容,它們是為對應機器設定的變數,這些變數在可以在後面要講的playbook檔案中引用。

分組和變數的使用方法在後面演示,現在你先記得有這麼一回事就行。

另外關於分組還要多說一句,ansible有兩個預設的分組:allungrouped:all分組包括所有分組的中的機器,ungrouped是所有隻屬於all分組,不屬於其它分組的機器。 在定義你自己的分組的時候,要注意分組名稱不要與它們衝突。

講述這部分內容的官方文件是:Working with Inventory

使用modules開始操作

Modules是ansible的“軍火庫”,幾乎所有的操作功能都是用module實現的。

ansible用到最後,就是在使用module。 module的數量相當多,好在常用的就那麼幾個,這裡演示一些常用的,其它的你可以通過每個module的文件學習。

ping模組是用來測試目標機器是否可達的,用法如下:

lijiaos-mbp:example lijiao$ ansible -i inventories/demo/hosts -u root -k all -m ping
SSH password:
192.168.33.12 | SUCCESS => {
    "changed": false,    "ping": "pong"}192.168.33.11 | SUCCESS => {
    "changed": false,    "ping": "pong"}

-i指定hosts檔案,-u指定目標機器上的使用者名稱,-k指定目標機器登入密碼,all是要操作的hosts檔案中的分組,前面我們說過,all是預設存在的一個分組,包括所有機器,-m指定要使用的模組ping

ping模組大概是最簡單的一個模組,沒有引數,再來看一個複雜一點的模組shell,它的功能是在目標機器上執行shell命令:

lijiaos-mbp:example lijiao$  ansible -i inventories/demo/hosts -u root -k all -m shell -a "hostname"SSH password:
192.168.33.11 | SUCCESS | rc=0 >>192.168.33.11

192.168.33.12 | SUCCESS | rc=0 >>192.168.33.12

-a是指定傳遞給模組的引數。

ansible命令對目標機器操作時,都是在命令列指定要做的操作,一般都是一些比較簡單操作,譬如檢視下狀態、上傳下載檔案等。

很多強大的功能要通過ansible-playbook才能發揮出來。

用ansible-playbook命令操作目標機器

playbooks是yml格式的檔案,描述了要在哪些機器上執行哪些操作。

在目標機器上建立一個檔案

建立一個playbook檔案,playbook-single.yml,如下:

- hosts: machines
  remote_user: root
  tasks:
  - name: create a tmp file
    shell: |
      cd /tmp/
      touch abcd123

這個playbook檔案的意思是,在所有的machines上,用root的身份執行,並通過shell模組建立檔案/tmp/abcd123,用法如下:

lijiaos-mbp:example lijiao$ ansible-playbook -i inventories/demo/hosts -k playbook-single.yml
SSH password:

PLAY [machines] ******************************************************************************TASK [Gathering Facts] ***********************************************************************ok: [192.168.33.12]
ok: [192.168.33.11]

TASK [create a tmp file] *********************************************************************changed: [192.168.33.12]
changed: [192.168.33.11]

PLAY RECAP ***********************************************************************************192.168.33.11              : ok=2    changed=1    unreachable=0    failed=0
192.168.33.12              : ok=2    changed=1    unreachable=0    failed=0

注意這裡使用ansible-playbook命令,-i-k引數含義與前面ansible命令的引數相同,這裡沒有使用-u指定賬號,是因為在playbook-single.yml中已經設定了使用root:

remote_user: root

操作在playbook檔案的tasks中設定,tasks是一個數組,可以新增多個任務:

  tasks:
  - name: create a tmp file      # 自定義的操作名稱
    shell: |                     # 使用shell模組,後面的|是yaml語法,表示後面空行之前的內容都是shell模組的引數
      cd /tmp/
      touch abcd123

用ansible命令來看一下檔案是否建立:

lijiaos-mbp:example lijiao$  ansible -i inventories/demo/hosts -u root -k all -m shell -a "ls /tmp/abc*"SSH password:
192.168.33.11 | SUCCESS | rc=0 >>/tmp/abcd123

192.168.33.12 | SUCCESS | rc=0 >>/tmp/abcd123

將操作以role為單位進行分組

前面給出的ansible-playbook的用法,是最初級的用法,比較完整的用法是將操作封裝到role中。

先解釋一下什麼是role,為什麼要有role。

在ansible看來role就是對playbook中的操作做了一次分組,把一些操作放在這個role中,另一些操作放在那個role中。

在我們看來,role是目標機器的角色之一,我們把不同的角色的操作劃分到不同的目錄中,一是管理方便,二是可以複用。

role要在roles目錄中定義,在roles目錄中建立與role同名的目錄,每個role目錄中包含四個目錄:

lijiaos-mbp:example lijiao$ tree roles/
roles/
└── prepare
    ├── files
    │   └── demo.file
    ├── handlers
    │   └── main.yml
    │   └── centos.yml
    ├── tasks
    │   └── main.yml
    └── templates
        └── demo.template.j2

tasks目錄中的main.yml是這個role的操作入口,handlers/main.yml中是一些可以被觸發的操作,files中存放可以直接被上傳到目標機器的檔案,templates中存放的是可以直接上傳到目標機器的模版檔案,這兩個的區別後面說明。

注意tasks/main.yml是必須要有的,其它目錄中如果沒有檔案,可以不建立。

上面的目錄中建立了一個名為prepare的role,我們計劃將機器的初始化設定操作全部在收集在這個role中,task/main.yml是這樣寫的:

	- name: Set authorized key
	  tags: ssh
	  authorized_key:
	      user: root
	      key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
	
	- name: Set hostname
	  hostname:
	    name: "{{ inventory_hostname }}"
	
	- name: Set bash prompt
	  shell: |
	      echo 'export PS1="[\[email protected]\H \W]\\$ "'>> ~/.bashrc
	
	- name: install dependent packages
	  import_tasks: centos.yml
	  when: ansible_distribution == "CentOS"

用到了authorized_keyhostnameshellimport_tasks四個模組。

當目標機器的作業系統是ansible的時候,import_tasks引入了centos.yml檔案:

- name: set time zone
  file:
    src: '{{ item.src }}'
    dest: '{{ item.dest }}'
    state: link
  with_items:
    - { src: "/usr/share/zoneinfo/Asia/Shanghai", dest: "/etc/localtime" }

- name: set local
  shell: localedef -i zh_CN  -f UTF-8 zh_CN.UTF-8

- name: install epel
  yum: 
    name: "{{ item }}"
    state: present
  with_items:
    - epel-release

- name: install pkgs
  yum: 
    name: "{{ item }}"
    state: present
  with_items:
    - yum-utils
    - ipset
    - iptables
    - iproute
    - ipvsadm
    - supervisor
    - ntp  

- name: start basic service
  systemd:
     enabled: yes
     name: "{{ item }}"
     state: started
  with_items:
    - ntpd
    - supervisord

這些操作的含義在後面章節逐一說明,先給出用法:

ansible-playbook -i inventories/demo/hosts  -u root -k prepare.yml

常用的目標機器初始化操作

這裡介紹role/prepare/task/main.yml檔案中的操作。

設定免密碼登入

前面的操作過程中使用了-k引數,每次都需要輸入密碼,一是比較煩,二是如果機器的密碼不同,那就失靈了(後面會演示一下如果目標機器密碼不同該怎樣操作)。

最好把本地的證書傳到目標機器上,實現免密碼登入,prepare的task/main.yml中,有這樣一段:

- name: Set authorized key
  tags: ssh
  authorized_key:
      user: root
      key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"

它就是用authorized_key模組將本地的證書~/.ssh/id_rsa.pub上傳到目標機器上,實現免密碼登入。

注意你需要確保你本地有id_rsa.pub檔案,否則用ssh-keygen命令建立一個:

$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/lijiao/.ssh/id_rsa):

設定目標機器的hostname

- name: Set hostname
  hostname:
    name: "{{ inventory_hostname }}"

- name: Set bash prompt
  shell: |
      echo 'export PS1="[\[email protected]\H \W]\\$ "'>> ~/.bashrc

設定目標機器的時區

- name: set time zone
  file:
    src: '{{ item.src }}'
    dest: '{{ item.dest }}'
    state: link
  with_items:
    - { src: "/usr/share/zoneinfo/Asia/Shanghai", dest: "/etc/localtime" }

用yum安裝依賴包

- name: install epel
  yum: 
    name: "{{ item }}"
    state: present
  with_items:
    - epel-release

- name: install pkgs
  yum: 
    name: "{{ item }}"
    state: present
  with_items:
    - yum-utils
    - ipset
    - iptables
    - iproute
    - ipvsadm
    - supervisor
    - ntp

用systemd啟動服務

- name: start basic service
  systemd:
     enabled: yes
     name: "{{ item }}"
     state: started
  with_items:
    - ntpd
    - supervisord

變數、檔案、模版與Handler

這裡通過在目標機器上部署、設定nginx,講解角色下面的files、templates和handlers目錄的作用。

nginx role的檔案如下:

lijiaos-mbp:example lijiao$ tree roles/nginx/
roles/nginx/
├── files
│   ├── start.sh
│   └── stop.sh
├── handlers
│   └── main.yml
├── tasks
│   └── main.yml
└── templates
    └── hello.com.conf.j2

變數的定義和引用

nginx/tasks/main.yml內容是:

- name: install pkgs
  yum: 
    name: "{{ item }}"
    state: present
  with_items:
    - nginx

- name: nginx is running
  systemd:
    name: nginx
    state: started
    daemon_reload: yes

- name: create directory
  file:
    path: "{{ item }}"
    state: directory
  with_items:
    - "{{ nginx_config_path }}"
    - "{{ nginx_script_path }}"

- name: upload template config
  notify: reload nginx
  template: 
    src: "{{ item }}.j2"      
    dest: "{{ nginx_config_path }}/{{ item }}"
  with_items:
  - hello.com.conf

- name: upload files 
  copy:
    src: "{{ item }}"
    dest: "{{ nginx_script_path }}/{{ item }}"
    mode: u=rwx
  with_items:
  - start.sh
  - stop.sh

這裡有兩個變數:nginx_config_pathnginx_script_path,用兩個大括號包裹引用。

它們是在inventories/demo/group_vars/all中定義的:

nginx_config_path:  /etc/nginx/conf.d
nginx_script_path: /root/nginx

變數除了可以在group_varshost_vars目錄中定義,還可以在hosts檔案中定義:

[machines]
192.168.33.11 port=8001
192.168.33.12 port=8002

以及在playbook檔案中定義,回想一下我們用到的第一個playbook,裡面有vars

$ cat playbook-single.yml
- hosts: machines
  vars:
    http_port: 80
    max_clients: 200
  remote_user: root
  tasks:
  - name: create a tmp file
    shell: |      cd /tmp/
      touch abcd123

模版上傳

role/nginx/templates/hello.com.conf.j2是一個模版檔案: ,模版檔案中可以使用變數:

server {
	listen {{ port }};
	location / {
		proxy_pass https://www.baidu.com ;
	}
}

模版檔案中可以使用變數,這裡使用的變數port是在hosts檔案中定義的,可以為每個機器定義不同的埠:

[machines]
192.168.33.11 port=8001
192.168.33.12 port=8002

它們被用template模組上傳,上傳時會將模版檔案中的變數換成變數的值,如下:

- name: upload template config
  notify: reload nginx
  template: 
    src: "{{ item }}.j2"      
    dest: "{{ nginx_config_path }}/{{ item }}"
  with_items:
  - hello.com.conf

檔案上傳

role/nginx/files中的檔案,用COPY命令上傳,檔案不會被做任何改動,這一點和templates顯著不同:

- name: upload files 
  copy:
    src: "{{ item }}"
    dest: "{{ nginx_script_path }}/{{ item }}"
    mode: u=rwx
  with_items:
  - start.sh
  - stop.sh

handler的觸發

在tasks中,用notify命令觸發handler的執行:

- name: upload template config
  notify: reload nginx
  template: 
    src: "{{ item }}.j2"      
    dest: "{{ nginx_config_path }}/{{ item }}"
  with_items:
  - hello.com.conf

只有被觸發的handler才會執行,並且是在所有的task之後執行。

如果有多個handler被觸發,按照它們在handlers/main.yml中出現的順序執行。

什麼時候要用handler?

譬如說,配置檔案被更新以後,需要重啟或者重新載入的服務,這時候就可以在更新配置檔案的task中,使用notify觸發handler。

參考

  1. ansible documents

  2. ansible Dynamic Inventory

  3. ansible playbook Best Practices

  4. ansible Delegation, Rolling Updates, and Local Actions

  5. ansible Jinja2 templating

  6. ansible all modules

  7. how to access host variable of a different host with Ansible?

  8. Ansible Loops

  9. Ansible Conditionals

  10. ansible special variables