【視頻】特別適合新手的運維利器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="[\u@\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="[\u@\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




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章