星期六, 10月 31, 2015

Ansible playbook小記

上一次寫完 Ansible 簡單的指令測試
今天來介紹 playbook

playbook  簡單來說就是
  • 把要執行的 ansible 指令還有可能遠端主機會使用到的檔案都集中到一個目錄內.
  • 以YAML 語法來寫
  • ansible-playbook 指令執行
  • playbook 裡面會有不同的 play ( 可以把看成要執行的script )
    • 每個 play 必須有
      • 要執行的 host ( 對應我們設定的 hosts 或是 inventory 檔案 )
      • task ( 執行那些工作)

以下是看書上,自己的整理筆記

playbook
  • A script is called a playbook.
  • A playbook describes which hosts( what Ansible calls remote servers ) to configure, and an ordered list of tasks to perform on those hosts.
    • Ansible runs each task in parallel across all hosts.
    • Ansible waits until all hosts have completed a task before moving to the next task.
    • Ansible runs the tasks in the order that you specify them.
  • 使用 ansible-playbook 指令來執行
    • # 例如 ansible-playbook  web-notls.yml
    • 如果檔案本身可以被執行
    • 也可以在檔案第一行加上
    • #!/usr/bin/env  ansible-playbook
    • 來直接執行
  • Ansible playbooks written in YAML syntax.
    • YAML
    • Yet Another Markup Language
      • Start of File
        • 以 3 個 --- 開始
        • 不加上去也可以
      • 註解
        • 以 # 來進行單行註解
        • #就是註解開始
      • Strings
        • 不一定要加上引號
        • 可是有的時候為了易讀性, 可以使用 單引號或是雙引號
      • Booleans
        • 使用 True 或是 Yes 都可以視為真
        • 但是還是用 True 不會混亂
      • Lists
They are delimited with hyphens, like this:
- My Fair Lady
- Oklahoma
- The pirates of Penzance
# inline 格式list
[My Fair Lady, Oklahoma, The Pirates of Penzance]
      • Dictionaries
They look like this:
address: 742 Evergreen Terrace
city: Springfield
state: North Takoma
# inline  格式
{address: 742 Evergreen Terrace, city: Springfield, state: North Takoma}
      • Line Folding
# 使用 > 符號來進行 單行摺疊, 有點類似 shell script 放在行尾的 \
# 目的在於讓一個很長的單行, 有效率地被呈現
address: >
     Department of Computer Science,
     A.V. Williams Building,
     University of Maryland
city: College Park
state: Maryland
# address 那邊就可以看成一行
  • A playbook is a list of plays
    • Plays
      • Every play must contain:
        • * A set of hosts to configure
        • * A list of tasks to be executed on those hosts
      • Three common optional settings are
        • name
          • A comment that describes what the play is about.
          • Ansible will print this out when the play starts to run.
        • sudo
          • If true, Ansible will run every task by sudo.
        • vars
          • A list of variables and values.
          • 在 play 內用  {{  }} 來使用 variables
      • Other optional settings are
        • Handlers
A handler is similar to a task, but it runs only if it has been notified by a task.
A task will fire the notification if Ansible recognizes that the task has changed the state of the system.
# 當 task 改變系統狀態時, 會進行 notify 的動作
tasks:
 - name: copy TLS key
    copy: src=files/nginx.key dest={{ key_file }} owner=root mode=0600
    notify: restart nginx
# handlers 可能有很多個, notify 會去比對 handlers 的名稱, 如果符合就進行該模組
handlers:
- name: restart nginx
  service: name=nginx state=restarted
# 也就是說, 只有真的系統產生改變的時候, 例如 TLS key 被換掉, 才會重新啟動 nginx
          • Handlers only run after all of the tasks are run, and the only run once, even they are notified multiple times.
          • # Handlers 在所有tasks執行完才執行, 不管被呼叫多少次, 都只執行一次.
      • hosts
        • default: /etc/ansible/hosts
      • Tasks

星期五, 10月 30, 2015

Ansible 練習小記 - 簡單的 ansible 指令練習

記錄一下相關練習

以下的練習, 前提是
  • SSH 可以使用 Key 登入 Remote Hosts

例如 在 Control Machine 上面( Mac / Linux )

$ ssh  -l   使用者名稱   -i   key檔案位置  RemoteHost_IP
可以直接登入

SSH 建立以及複製到遠端可以參考 這篇

建立 playbooks  目錄來進行之後練習

$ mkdir   playbooks

Lab:  簡單的 ansible 指令練習

建立遠端主機相關資訊
$ vi  hosts
# syntax: servername  options
# ansible_ssh_host -- Remote Host IP
# ansible_ssh_user -- Remote SSH User Name
# ansible_ssh_private_key_file -- SSH Key
testserver   ansible_ssh_host=遠端主機IP   ansible_ssh_user=遠端使用者名稱


測試 ansible 指令, 這邊使用 ping 的 module 

$ ansible   testserver   -i   hosts   -m   ping
testserver | success >> {
   "changed": false,
   "ping": "pong"
}

$ ansible   all   -i   hosts   -m   ping
testserver | success >> {
   "changed": false,
   "ping": "pong"
}

根據上面的指令來驗證
ansible
  • 可以指定某台主機, 例如 testserver 或是全部 all
  • -i 為 inventory 清單檔案所在
  • -m 為 module name, 這個案例使用的是 ping


但是如果每台主機的使用者帳號還有 key 都是同一把, 那就可以建立 ansible.cfg 來設定成預設

Lab: 使用 ansible.cfg

建立 ansible.cfg 放在 playbook 目錄下
$ vi   ~/playbooks/ansible.cfg
[defaults]
# 主機清單的檔案, 這樣可以不用下 -i 選項指定
hostfile = hosts
# 遠端使用者名稱, 換成自己的使用者名稱
remote_user = cc
# SSH Key 位置, 換成自己的 key path
private_key_file = ~/.ssh/id_dsa

修改  ~/playbooks/hosts ( 因為 ansible.cfg 已經有設定 remote_user, 就不用重複設定 )

$ vi   ~/playbooks/hosts
# syntax: servername  options
# ansible_ssh_host -- Remote Host IP
# ansible_ssh_user -- Remote SSH User Name
# testserver   ansible_ssh_host=遠端主機IP   ansible_ssh_user=遠端使用者名稱
testserver   ansible_ssh_host=遠端主機IP

$ ansible   testserver    -m ping
testserver | success >> {
   "changed": false,
   "ping": "pong"
}


但是如果對象是要用兩種以上的 ssh key 來控制, 那就可以考慮把相關的設定寫在 hosts, 並利用 群組的做法
$ cat   hosts
ubuntu_utah ansible_ssh_host=遠端主機IP ansible_ssh_user=maxhuang ansible_ssh_private_key_file=~/id_ssh_rsa

ubuntu_cenic ansible_ssh_host=遠端主機IP ansible_ssh_user=maxhuang ansible_ssh_private_key_file=~/id_ssh_rsa

[geni]
ubuntu_utah
ubuntu_cenic


接下來嘗試使用 ansible 來安裝套件

Lab: 安裝套件

查詢套件是否安裝, 這邊使用 shell module
可以參考 http://docs.ansible.com/ansible/shell_module.html

$ ansible  ubuntu_utah   -m   shell   -a   "dpkg -l | grep nginx"
ubuntu_utah | FAILED | rc=1 >>


安裝套件
$ ansible ubuntu_utah  -s -m apt -a 'name=nginx update_cache=yes'

確認是否安裝
$ ansible ubuntu_utah  -m  shell  -a  "dpkg -l | grep nginx"
ubuntu_utah | success | rc=0 >>
ii  nginx                               1.4.6-1ubuntu3.3                    all          small, powerful, scalable web/proxy server

今天就先到這邊

~ enjoy it

星期日, 10月 25, 2015

Paramiko在Python執行 SSH 小記

最近因為工作的關係, 要在 JupyterHub 上面執行一些部署 script, 因為使用 jupyter 的關係, 所以就開始使用 python 來進行相關執行動作.

剛開始的做法是 使用 shell script 在主機上面執行, 確認可以自動安裝完成, 接下來就是在 JupyterHub 上面藉由執行 python notebook 來達成 執行 遠端 shell script 的目的.

Jupyter / JupterHub 的好處就是可以馬上執行, 並看到輸出的結果
我常用到的是 2 種 block
  • Markdown -- 用來說明之後要進行的程式目的
  • Cell - 根據開啟的 kernel 決定執行的程式語言, 我目前都是使用 python 3
螢幕快照 2015-10-24 下午5.32.25.png

既然使用 shell script 沒有問題, 接下來就是考慮如何用 python 去遠端執行指令了, 這個時候當然是想到 SSH. 既然要遠端執行指令, 那必要的要素就有:
  • 遠端的主機 FQDN 或是 IP
  • 遠端主機的登入使用者名稱
  • SSH Key

Google 了一下, python 在 ssh 的方案, 找了很多方式, 後來是使用 paramiko 這個方式

根據上述三個要素, 所以就先準備了 3 個 Markdown 還有 3 個 cell 來記錄相關資料讓等下的python 應用

  • 使用 REMOTEHOST 變數記錄遠端機器的 IP 或是 FQDN
  • 使用 USERNAME 變數記錄遠端的使用者名稱
  • 使用 KEYPATH 記錄使用者 SSH Key 私鑰路徑, 我最後有設計一個 block 把 Key 刪除
輸入完執行結果如下
螢幕快照 2015-10-24 下午5.45.26.png

接下來就是 paramiko 的執行方式

# 匯入 paramiko
import paramiko
# 定義 ssh 為使用 paramiko.SSHClient()
ssh = paramiko.SSHClient()
# 設定自動加入 遠端主機的 SSH Key
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

# define where is the SSH DSA key, use SSH key to connect remote host
# 如果是 使用 DSA Key 請用以下的設定
# key = paramiko.DSSKey.from_private_key_file('./sshkey/id_dsa')

# if your use .pem key, please comment above line and use below
# 如果是 使用 RSA 或是 .pem 的 key 使用以下的設定
key = paramiko.RSAKey.from_private_key_file(KEYPATH)

# 設定連接 ssh 的主機名稱, 使用者名稱, ssh 私鑰路徑
ssh.connect(hostname=REMOTEHOST, username=USERNAME, pkey=key)

# 如果遠端是採取帳號密碼驗證使用以下的方式
# ssh.connect(hostname="127.0.0.1", username="openSUSE", password="Password_there")


# Test uptime command with remote host
# 測試遠端指令
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command('uptime')

# 列出結果
print(ssh_stdout.read())
這個是在 jupyter 執行的結果
螢幕快照 2015-10-24 下午6.14.03.png

輸出的結果算是有點差強人意, 接下來就去看如何處理輸出

如果今天執行的是 ls -l 這樣的指令
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command('ls -l /share')
print()
print(ssh_stdout.read())
print()

螢幕快照 2015-10-24 下午6.19.20.png

輸出的結果真的不好閱讀
b'total 1010272\n-rwxr-xr-x 1 2000 libuuid   5636574 Sep  4  2014 kernel-9.3.xen\n-rw-r--r-- 1 2000 libuuid 865739683 Sep  4  2014 obj.tar.gz\n-rw-r--r-- 1 2000 libuuid 162685234 Sep  4  2014 src.tar.gz\n'

所以改變一下處理的方式, 使用 readlines() 還有透過 .join 的方式來處理
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command('ls -l /share')
print()
print( '\n'.join( ssh_stdout.readlines() ) )
print()

螢幕快照 2015-10-24 下午6.21.54.png
這樣的結果就比較好閱讀了

total 1010272

-rwxr-xr-x 1 2000 libuuid   5636574 Sep  4  2014 kernel-9.3.xen

-rw-r--r-- 1 2000 libuuid 865739683 Sep  4  2014 obj.tar.gz

-rw-r--r-- 1 2000 libuuid 162685234 Sep  4  2014 src.tar.gz


今天的小記就先到這邊, 看來我的 python 還要好好加油

~ enjoy it