iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 26
1
Kubernetes

在地端建置Angular+ASP.NET Core的DevOps環境系列 第 26

day26_ansible04_modules_pip,mysql_db,mysql_user,wait_for,uri,register,when

  • 分享至 

  • xImage
  •  

前言

科科科,繼續吧~(到day29都是這些 = =)
幾乎參考都來自ansible官網手冊
基本一定要會的:wait_for,uri,register,when
介紹一點for特定軟體&工具的,讓大家體驗一下:pip,mysql_db,mysql_user
(就是有非常多modules啦,列幾個讓大家體驗一下,其他modules就會很好上手)

所以如果貴公司在選擇資料庫、作業系統、公有雲時,可以考慮ansible有modules的那些
如果都支援,還要看支援的modules數量

ansible支援度高的作業系統:

  • macOS(pip、homebrew)
    如果伺服器是linux、unix的話,蠻適合配macOS給員工當工作機的
  • centOS(yum)
    從這幾天在ansible galaxy查role的經驗來看,支援最多的OS是centOS
  • Ubuntu(apt)
    一堆「docker image」、「ansible專案裡的vagrant」都用他來當os

工具、軟體:

  • 資料庫:mongodb、mysql、postgresql
  • 版控:git、gitlab、github、jenkins
  • 其他:vmware、ladp

公有雲

azure、gcp、aws都支援
helm、k8s、route53、grafana、docker

開發環境

node.js(npm)

下次如果有業務到貴公司推銷軟硬體,先查看看有沒有modules,也是一種指標喔

windows也有modules喔

https://docs.ansible.com/ansible/latest/modules/list_of_windows_modules.html

===

Application Modules: pip

https://docs.ansible.com/ansible/latest/modules/pip_module.html

範例

# Install specified python requirements.
- pip:
    requirements: /my_app/requirements.txt
# Install multi python packages with version specifiers
- pip:
    name:
      - django>1.11.0,<1.12.0
      - bottle>0.10,<0.20,!=0.11
# Install specified python requirements in indicated (virtualenv).
- pip:
    requirements: /my_app/requirements.txt
    virtualenv: /my_app/venv
    # Path to the requirements file
    # Path to the virtualenv,如果virtualenv path是存在的,會回傳success
# Install (Bottle) while ensuring the umask is 0022 (to ensure other users can use it)
- pip:
    name: bottle
    umask: "0022" # 設權限
  become: True    # 作設權限要升權

===

mysql_db

https://docs.ansible.com/ansible/latest/modules/mysql_db_module.html

#先把mysql跑起來
- name: ensure mysql started
  service: name=mysql state=started enabled=yes 

- name: Create a new database with name 'bobdata'
  mysql_db:
    name: bobdata # 建資料庫
    state: present # 如果資料庫已經存在,不知道會怎樣?
- name: create database
  mysql_db: 
    name={{ db_name }} # 或者用變數帶
    state=present
    
    # Copy database dump file to remote host and restore it to database 'my_db'
    - name: Copy database dump file
      copy:
        src: dump.sql.bz2
        dest: /tmp # 把資料備出來
    - name: Restore database
      mysql_db:
        name: my_db
        state: import # 再restore成my_db
        target: /tmp/dump.sql.bz2
    
    - name: Dump all databases to hostname.sql
      mysql_db:
        state: dump # dump所有資料庫
        name: all
        target: /tmp/{{ inventory_hostname }}.sql
    
    - name: Import file.sql similar to mysql -u <username> -p <password> < hostname.sql
      mysql_db:
        state: import
        name: all
        target: /tmp/{{ inventory_hostname }}.sql

===

mysql_user

https://docs.ansible.com/ansible/latest/modules/mysql_user_module.html#examples
紙上談兵不太準,可能要多嘗試

# Removes anonymous user account for localhost
- mysql_user:
    name: ''
    host: localhost
    state: absent # 刪掉匿名帳號

# Removes all anonymous user accounts
- mysql_user:
    name: ''
    host_all: yes
    state: absent

# Create database user with name 'bob' and password '12345' with all database privileges
- mysql_user:
    name: bob
    password: 12345
    priv: '*.*:ALL'
    state: present # 建帳號,給所有的權八裂

# Create database user with name 'bob' and previously hashed mysql native password 
# mysql> SELECT PASSWORD('bob');
# '*EE0D72C1085C46C5278932678FBE2C6A782821B4' with all database privileges
- mysql_user:
    name: bob
    password: '*EE0D72C1085C46C5278932678FBE2C6A782821B4'
    encrypted: yes # 上面的password欄位是`mysql_native_password` hash
    priv: '*.*:ALL'
    state: present

# Creates database user 'bob' and password '12345' with all database privileges and 'WITH GRANT OPTION'
- mysql_user:
    name: bob
    password: 12345
    priv: '*.*:ALL,GRANT'
    state: present

# 既有user加權限
- mysql_user:
    name: bob
    append_privs: true  
    priv: '*.*:REQUIRESSL'
    state: present

# Revoke all privileges for user 'bob' and password '12345'
- mysql_user:
    name: bob
    password: 12345
    priv: "*.*:USAGE" # 所有bob有的權限
    state: present # 去掉

# 權限字串的格式
# mydb.*:INSERT,UPDATE/anotherdb.*:SELECT/yetanotherdb.*:ALL

# 用login_unix_socket連線
- mysql_user:
    name: root
    password: abc123
    login_unix_socket: /var/run/mysqld/mysqld.sock

===

wait_for

https://docs.ansible.com/ansible/latest/modules/wait_for_module.html

active_connection_states
TCP connection states的list
Default:
[u'ESTABLISHED', u'FIN_WAIT1', u'FIN_WAIT2', u'SYN_RECV', u'SYN_SENT', u'TIME_WAIT']

state:

  • absent: check that file is absent or removed
  • drained: check for active connections
  • present: ensure that the file or string is present before continuing
  • started : 確認port是打開的
  • stopped
- name: sleep for 300 seconds and continue with play
  wait_for: timeout=300 # 最多等300秒
  delegate_to: localhost
# 驗證8000 port is listening
- name: Wait for port 8000 to become open on the host, don't start checking for 10 seconds
  wait_for:
    port: 8000 timeout =1(沒寫預設是300秒)
    delay: 10 # 先等10秒再check

    - name: verify mysql is listening on 3306
      wait_for: host=mysqlserver port=3306 timeout=1


- name: Waits for port 8000 of any IP to close active connections, don't start checking for 10 seconds
  wait_for:
    host: 0.0.0.0 # 所有ip
    port: 8000
    delay: 10 # 1、先等10秒
    state: drained

- name: Wait for port 8000 of any IP to close active connections, ignoring connections for specified hosts
  wait_for:
    host: 0.0.0.0
    port: 8000
    state: drained # 斷掉所有連線,除了exclude_hosts的
    exclude_hosts: 10.2.1.2,10.2.1.3 # 除外

- name: Wait until the file /tmp/foo is present before continuing
  wait_for:
    path: /tmp/foo

- name: Wait until the string "completed" is in the file /tmp/foo before continuing
  wait_for:
    path: /tmp/foo
    search_regex: completed # 等到/tmp/foo有completed字串

- name: Wait until the lock file is removed
  wait_for:
    path: /var/lock/file.lock
    state: absent

- name: Wait until the process is finished and pid was destroyed
  wait_for:
    path: /proc/3466/status
    state: absent

- name: Output customized message when failed
  wait_for:
    path: /tmp/foo # 等到出現/tmp/foo,輸出msg
    state: present
    msg: Timeout to find file /tmp/foo

# Don't assume the inventory_hostname is resolvable and delay 10 seconds at start
# inventory_hostname可能是無法解析的
# 如果ssh連不到inventory_hostname(等300秒)
- name: Wait 300 seconds for port 22 to become open and contain "OpenSSH"
  wait_for:
    port: 22
    host: '{{ (ansible_ssh_host|default(ansible_host))|default(inventory_hostname) }}'
    search_regex: OpenSSH
    delay: 10
  connection: local

===

uri

https://docs.ansible.com/ansible/latest/modules/uri_module.html

method有這麼多

  • GET
  • POST
  • PUT
  • HEAD
  • DELETE
  • OPTIONS
  • PATCH
  • TRACE
  • CONNECT
  • REFRESH
  • client_cert :如果需要用來作ssl client認證的話,餵pem格式的憑證
  • client_key:同上,key,pem格式
  • body_format :這就很像用postman
  • form-urlencoded
  • json
  • raw
- name: 用 http get url,如果正常傳回status 200
  uri:
    url: http://www.example.com

# Check that a page returns a status 200 and fail if the word AWESOME is not
# in the page contents.
# 如果content裡有AWESOME,就fail
- uri:
    url: http://www.example.com
    return_content: yes
  register: this
  failed_when: "'AWESOME' not in this.content"

# Login to a form based webpage, then use the returned cookie to
# access the app in later tasks
# 試著對form based的網頁login
- uri:
    url: https://your.form.based.auth.example.com/index.php
    method: POST
    body_format: form-urlencoded
    body:
      name: your_username
      password: your_password
      enter: Sign in
    status_code: 302
  register: login

# Same, but now using a list of tuples
- uri:
    url: https://your.form.based.auth.example.com/index.php
    method: POST
    body_format: form-urlencoded
    body:
    - [ name, your_username ]
    - [ password, your_password ]
    - [ enter, Sign in ]
    status_code: 302
  register: login

- uri:
    url: https://your.form.based.auth.example.com/dashboard.php
    method: GET
    return_content: yes
    headers:
      Cookie: "{{ login.set_cookie }}" # header設cookie,再去get
# 有用jenkins的朋友可以試試
- name: Queue build of a project in Jenkins
  uri:
    url: http://{{ jenkins.host }}/job/{{ jenkins.job }}/build?token={{ jenkins.token }}
    method: GET
    user: "{{ jenkins.user }}"
    password: "{{ jenkins.password }}"
    force_basic_auth: yes
    status_code: 201
# 上傳檔案
- name: POST from contents of local file
  uri:
    url: "https://httpbin.org/post"
    method: POST
    src: file.json

- name: POST from contents of remote file
  uri:
    url: "https://httpbin.org/post"
    method: POST
    src: /path/to/my/file.json
    remote_src: true

===

register註冊變數

https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#register-variables
簡單常用的,可用在templates、action lines、when等地方

- name: test play
  hosts: all
  tasks:
      - shell: cat /etc/motd
        register: motd_contents # /etc/motd就會存到motd_contents

      - shell: echo "motd contains the word hi"
        when: motd_contents.stdout.find('hi') != -1 # 用stdout(標準輸出串流)操作

- name: registered variable usage as a loop list
  hosts: all
  tasks:
    - name: retrieve the list of home directories
      command: ls /home
      register: home_dirs # 如果是list,就可以用stdout_line或stdout.split()跑Loop

    - name: add home dirs to the backup spooler
      file:
        path: /mnt/bkspool/{{ item }}
        src: /home/{{ item }}
        state: link
      loop: "{{ home_dirs.stdout_lines }}"
      # same as loop: "{{ home_dirs.stdout.split() }}"

- name: check registered variable for emptiness
  hosts: all
  tasks:
      - name: list contents of directory
        command: ls mydir
        register: contents

      - name: check contents for emptiness
        debug:
          msg: "Directory is empty"
        when: contents.stdout == "" # 檢查目錄是不是空的


===

when

類似if...then,條件語句,非常常用
https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#the-when-statement

# 如果是Debian系列的話…
tasks:
  - name: "shut down Debian flavored systems"
    command: /sbin/shutdown -t now
    when: ansible_facts['os_family'] == "Debian"
    # note that all variables can be directly in conditionals without double curly braces

# https://docs.ansible.com/ansible/2.7/user_guide/playbooks_variables.html
# 變數:ansible_facts,跟system有關的資訊
# 有2種方式可以看
# 利用debug輸出
- debug: var=ansible_facts
# 原始資訊
ansible hostname -m setup
例如:ubuntu的
{
    "ansible_all_ipv4_addresses": [
        "REDACTED IP ADDRESS"
    ],
    "ansible_all_ipv6_addresses": [
        "REDACTED IPV6 ADDRESS"
    ],
    "ansible_architecture": "x86_64",
    "ansible_bios_date": "09/20/2012",
"sr0": {
            "holders": [],
            "host": "IDE interface: Intel Corporation 82371AB/EB/MB PIIX4 IDE (rev 01)",
            "model": "VMware IDE CDR10",
            "partitions": {},
....

ansible_facts的用法

{{ ansible_facts['devices']['sda']['model'] }}
{{ ansible_facts['hostname'] }}

不收集facts

- hosts: whatever
  gather_facts: no # 可以省很多時間!!

local facts

/etc/ansible/facts.d

利用ansible_facts看os跟版本

tasks:
  - name: "shut down CentOS 6 and Debian 7 systems"
    command: /sbin/shutdown -t now
    when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or
          (ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7")

tasks:
  - command: /bin/false
    register: result
    ignore_errors: True

  - command: /bin/something
    when: result is failed

  # In older versions of ansible use ``success``, now both are valid but succeeded uses the correct tense.
# 現在應該要用 true | false
  - command: /bin/something_else
    when: result is succeeded  # 指令回傳的result

  - command: /bin/still/something_else
    when: result is skipped
# 用來介斷變數
vars:
  epic: true
tasks:
    - shell: echo "This certainly is epic!"
      when: epic # 或者加not => not epic
# 檢查變數有沒有定義
tasks:
    - shell: echo "I've got '{{ foo }}' and am not afraid to use it!"
      when: foo is defined

    - fail: msg="Bailing out. this play requires 'bar'"
      when: bar is undefined
# 用來當loop的終止條件
tasks:
    - command: echo {{ item }}
      loop: [ 0, 2, 4, 6, 8, 10 ]
      when: item > 5

上一篇
day25_ansible03_module01_apt,become,with_items,service,handlers,notify,Files,inlinfile
下一篇
day27_ansible05_vault,variables_facts,defaults,vars
系列文
在地端建置Angular+ASP.NET Core的DevOps環境31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言