顯示具有 playbook 標籤的文章。 顯示所有文章
顯示具有 playbook 標籤的文章。 顯示所有文章

2016年9月8日 星期四

Ansible 筆記 - 設定 Nginx 啟用 ngx_http_geoip_module.so 片段程式 @ Ubuntu 14.0

其實該寫成 Ansible Role 的,但一時之間有點懶,先把練習的片段紀錄一下。

安裝 nginx-module-geoip:

$ cat geoip-nginx.yml
---
    - name: install geoip packages
      apt: name={{ item }} update_cache=yes state=latest
      with_items:
        - nginx-module-geoip
      when: install_package is defined and install_package

    - name: check maxmind db - http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
      command: bash -c 'test -e /data/GeoIP.dat || curl http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz | gunzip - > /data/GeoIP.dat'

    - name: check maxmind db - http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
      command: bash -c 'test -e /data/GeoLiteCity.dat || curl http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz | gunzip - > /data/GeoLiteCity.dat'


設定 nginx.conf:

$ cat server-deploy.yml
...
  tasks:
    ...
    - include: geoip-nginx.yml
    - name: setup nginx config file - add modules/ngx_http_geoip_module.so
      lineinfile:
        dest: /etc/nginx/nginx.conf
        insertbefore: '^user '
        line: 'load_module "modules/ngx_http_geoip_module.so";'

    - name: setup nginx config file - setup geoip resource path
      lineinfile:
        dest: /etc/nginx/nginx.conf
        insertafter: '^http {'
        line: '    geoip_country /data/GeoIP.dat; geoip_proxy 192.168.0.0/16; geoip_proxy 10.0.0.0/24; geoip_proxy_recursive on;'
        #line: '    geoip_city    /data/GeoLiteCity.dat;'

    - name: setup nginx file to enable geoip - update log format
      lineinfile:
        dest: /etc/nginx/nginx.conf
        regexp: ".*?http_user_agent.*?http_x_forwarded_for"
        line: "                      '\"$http_user_agent\" \"$http_x_forwarded_for\"' $geoip_country_code \"$geoip_country_name\" ;"

    - name: setup nginx file to enable geoip - add GEOIP_COUNTRY_CODE for FastCGI
      lineinfile:
        dest: /etc/nginx/fastcgi_params
        insertbefore: "^fastcgi_param QUERY_STRING"
        line: "fastcgi_param     GEOIP_COUNTRY_CODE $geoip_country_code;"


如此一來,產生的 nginx.conf 如下:

$ cat /etc/nginx/nginx.conf && sudo nginx -t

load_module "modules/ngx_http_geoip_module.so";
user www-data;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    geoip_country /data/GeoIP.dat; geoip_proxy 192.168.0.0/16; geoip_proxy 10.0.0.0/24; geoip_proxy_recursive on;
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"' $geoip_country_code "$geoip_country_name" ;

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful


查看 /var/log/nginx/access.log 就可以看到類似的範例:

.... CN,CHN,"China"
.... US,USA,"United States"


更多變數定義,請參考:http://nginx.org/en/docs/http/ngx_http_geoip_module.html

2015年11月18日 星期三

Ansible 筆記 - 透過 find-package 找到指定安裝檔進行遠端部署 @ Ubuntu 14.04

手癢貢獻一個 ansible role 出去:changyy.find-package 。透過 find-package 功能,可以將包裝好的 package 複製到遠端機器安裝,這個方式可以偷懶省去架設 package server (例如 Yum Server)。

以下是簡易的範例,透過 unix find 指令,找尋剛製作好的 package ,把它記錄在變數中:

$ mkdir -p ansible-test/roles && cd ansible-test && ansible-galaxy install changyy.find-package -p roles/
- downloading role 'find-package', owned by changyy
- downloading role from https://github.com/changyy/ansible-role-find-package/archive/master.tar.gz
- extracting changyy.find-package to roles/changyy.find-package
- changyy.find-package was installed successfully

$ vim test.yml
---
- hosts: localhost
  roles:
  - { role: changyy.find-package, package_dir: "/data/rpm/production/" , package_name_prefix: "package-*" }

- hosts: 127.0.0.1

  tasks:
  - name: copy package
    copy: src="{{hostvars['localhost']['package_path']}}" dest=/tmp

$ ansible-playbook test.yml


連續動作還可以發佈至指定機器上,詳情請見:https://github.com/changyy/ansible-role-find-package

Ansible 筆記 - 找尋本機端資源並部署至遠端機器,包含複雜 shell 指令、資源尋找錯誤處理、hosts 之間變數傳遞等

這個需求其實還滿簡單實現的,但為了想要達成更仔細的錯誤偵測,後來越改越複雜 XD 順便筆記一下。完整的使用情境:每次部署遠端機器前,本地端會有一個 package 產出(rpm),透過 find 指令找到最新產出的 package 後,再部署到遠端機器(其實也可以把架設 yum server 來搞定啦 XD)

最簡單的方式,使用 vars 紀錄:

- hosts: YourTargetServers

  vars:
    rpm_dir: "/data/rpm/production/"
    rpm_name_prefix: "packagename*"
    rpm_find_command: "find {{ rpm_dir }} -name '{{ rpm_name_prefix }}' -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d ' ' "
    rpm_path: "{{ lookup('pipe', 'rpm_find_command') }}"

  tasks:
    - name: find rpm prefix name
      debug: msg="{{rpm_name_prefix}}"

    - name: find rpm command
      debug: msg="{{rpm_find_command}}"

    - name: find rpm path
      debug: msg="{{rpm_path}}"


這樣算是收工了,但是 rpm_path 若沒找到時,卻無法有洽當的錯誤偵測 Orz

所以第一次再改成這招:

- hosts: YourTargetServers

  vars:
    rpm_dir: "/data/rpm/production/"
    rpm_name_prefix: "packagename*"
    rpm_find_command: "find {{ rpm_dir }} -name '{{ rpm_name_prefix }}' -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d ' ' "

  tasks:
    - name: find rpm prefix name
      debug: msg="{{rpm_name_prefix}}"

    - name: find rpm command
      debug: msg="{{rpm_find_command}}"

    - name: find rpm path
      local_action: command /bin/bash -c "{{ rpm_find_command }}"
      sudo: False
      failed_when: " '' != rpm_path_result.stderr"

    - name: get rpm path
      debug: msg="{{ rpm_path_result.stdout }}"


但這樣仍有個缺點,那就是若有 roles 等一堆工作,會變成那堆工作做完才會跑 tasks,這時就會希望先偵測本地端的資料在跑 roles 工作,於是乎又改成:

- hosts: loclahost

  vars:
    rpm_dir: "/data/rpm/production/"
    rpm_name_prefix: "packagename*"
    rpm_find_command: "find {{ rpm_dir }} -name '{{ rpm_name_prefix }}' -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d ' ' "

  tasks:
    - name: find rpm prefix name
      debug: msg="{{rpm_name_prefix}}"

    - name: find rpm command
      debug: msg="{{rpm_find_command}}"

    - name: find rpm path
      local_action: command /bin/bash -c "{{ rpm_find_command }}"
      failed_when: " '' != rpm_path_result.stderr"

    - name: get rpm path
      debug: msg="{{ rpm_path_result.stdout }}"

- hosts: YourTargetServers

  vars:
    rpm_path: "{{ hostvars['localhost']['rpm_path_result']['stdout'] }}"

  tasks:
    - name: find rpm path
      debug: msg="{{rpm_path}}"


如此一來,就可以先確保在 localhost 把資源準備齊了,再進行遠端部署動作,也包含偵錯處理啦。

2015年11月13日 星期五

Ansible 筆記 - 建立自己的 roles ,以架設 Nginx 為例 @ Ubuntu 14.04

目前的目錄結構:

$ tree
.
├── add_authorized_key.yml
├── ansible-deploy.pem
├── ansible-deploy.pub
├── etc
│   └── ansible
│       └── hosts
└── mysite.yml

$ mkdir -p roles && cd roles && ansible-galaxy init nginx && cd - && tree .
- nginx was created successfully
.
├── add_authorized_key.yml
├── ansible-deploy.pem
├── ansible-deploy.pub
├── etc
│   └── ansible
│       └── hosts
├── roles
│   └── nginx
│       ├── defaults
│       │   └── main.yml
│       ├── files
│       ├── handlers
│       │   └── main.yml
│       ├── meta
│       │   └── main.yml
│       ├── README.md
│       ├── tasks
│       │   └── main.yml
│       ├── templates
│       └── vars
│           └── main.yml
└── mysite.yml

11 directories, 11 files


開始撰寫 mysite.yml 跟 nginx 相關資料:

$ cat mysite.yml
---
- hosts: mysite
  remote_user: ubuntu
  sudo: yes

  roles:
    - nginx

  tasks:
    - name: ubuntu system upgrade
      apt: upgrade=dist

$ ansible-playbook mysite.yml -i etc/ansible/hosts --private-key=ansible-deploy.pem

PLAY [mysite] **************************************************

GATHERING FACTS ***************************************************************
ok: [XX.XX.XX.XX]

TASK: [ubuntu system upgrade] *************************************************
ok: [XX.XX.XX.XX]

PLAY RECAP ********************************************************************
XX.XX.XX.XX             : ok=2    changed=0    unreachable=0    failed=0


代表目標機器已經更新好系統了,而剛剛添加的 roles/nginx 目前還是個空殼所以沒有任何動作。

接著要研究一下 Nginx 官方安裝位置:http://nginx.org/packages 和 http://nginx.org/en/linux_packages.html 對照表。此例需要添加官方 repo 的原始指令方式:

$ vim /etc/apt/sources.list
deb http://nginx.org/packages/ubuntu/ trusty nginx
deb-src http://nginx.org/packages/ubuntu/ trusty nginx


指令方式:

$ echo "deb http://nginx.org/packages/ubuntu/ trusty nginx" | sudo tee -a /etc/apt/sources.list
$ echo "deb-src http://nginx.org/packages/ubuntu/ trusty nginx" | sudo tee -a /etc/apt/sources.list
$ sudo apt-get update


而在 ansible 則是透過:

- name: Add Nginx Official Repo - deb
  apt_repository: repo='deb http://nginx.org/packages/ubuntu/ {{ ansible_distribution_release }} nginx' state=present

- name: Add Nginx Official Repo - deb-src
  apt_repository: repo='deb-src http://nginx.org/packages/ubuntu/ {{ ansible_distribution_release }} nginx' state=present

# http://docs.ansible.com/ansible/apt_key_module.html
- name: Add Nginx Official Repo - package signing key
  apt_key: url=http://nginx.org/packages/keys/nginx_signing.key state=present

#- name: Add Nginx Official Repo - ppa:nginx/stable
#  apt_repository: repo='ppa:nginx/stable'

- name: Update cache
  apt: update_cache=yes

- name: Install Nginx
  apt:
    pkg: nginx
    state: installed


到現在為止,整個 nginx role 的安裝設定:

$ tree .
.
├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── README.md
├── tasks
│   ├── main.yml
│   └── task-Ubuntu.yml
├── templates
└── vars
    └── main.yml

7 directories, 7 files

$ cat tasks/main.yml
---
# tasks file for nginx

- include: task-Ubuntu.yml
  when: ansible_distribution == 'Ubuntu'

$ cat tasks/task-Ubuntu.yml
---
# http://docs.ansible.com/ansible/apt_repository_module.html
- name: Add Nginx Official Repo - deb
  apt_repository: repo='deb http://nginx.org/packages/ubuntu/ {{ ansible_distribution_release }} nginx' state=present

- name: Add Nginx Official Repo - deb-src
  apt_repository: repo='deb-src http://nginx.org/packages/ubuntu/ {{ ansible_distribution_release }} nginx' state=present

# http://docs.ansible.com/ansible/apt_key_module.html
# $ curl -s 'http://nginx.org/packages/keys/nginx_signing.key' | sudo apt-key add -
- name: Add Nginx Official Repo - package signing key
  apt_key: url=http://nginx.org/packages/keys/nginx_signing.key state=present

#- name: Add Nginx Official Repo - ppa:nginx/stable
#  apt_repository: repo='ppa:nginx/stable'

- name: Update cache
  apt: update_cache=yes

- name: Install Nginx
  apt:
    pkg: nginx
    state: installed


其中 ansible_distribution_release, ansible_distribution 環境變數,可以透過 ansible -i host mysite -m setup 得知。接著再次執行 ansible-playbook ,過程就會安裝 nginx 啦(changed=4 都落在 nginx role 動作) :

$ ansible-playbook mysite.yml -i etc/ansible/hosts --private-key=ansible-deploy.pem

PLAY [mysite] **************************************************

GATHERING FACTS ***************************************************************
ok: [XX.XX.XX.XX]

TASK: [nginx | Add Nginx Official Repo - deb] *********************************
changed: [XX.XX.XX.XX]

TASK: [nginx | Add Nginx Official Repo - deb-src] *****************************
changed: [XX.XX.XX.XX]

TASK: [nginx | Add Nginx Official Repo - package signing key] *****************
changed: [XX.XX.XX.XX]

TASK: [nginx | Update cache] **************************************************
ok: [XX.XX.XX.XX]

TASK: [nginx | Install Nginx] *************************************************
changed: [XX.XX.XX.XX]

TASK: [ubuntu system upgrade] *************************************************
ok: [XX.XX.XX.XX]

PLAY RECAP ********************************************************************
XX.XX.XX.XX             : ok=7    changed=4    unreachable=0    failed=0


最後要客製化 Nginx 的話,就變成要改寫設定檔了,改寫設定檔前,當然要來個設定檔測試,這時規劃在 roles/nginx/handlers/main.yml 設定一些事件處理:

$ cat handlers/main.yml
---
# handlers file for nginx

- name: set nginx auto start
  service: name=nginx state=started enabled=yes

- name: restart nginx
  service: name=nginx state=restarted

- name: test nginx config
  shell: service nginx configtest
  register: result
  changed_when: "result.rc != 0"
  always_run: yes


接著回到 mysite.yml 設定檔,可以添加:

- hosts: mysite
  remote_user: ubuntu
  sudo: yes

  roles:
    - nginx

  tasks:
    - name: ubuntu system upgrade
      apt: upgrade=dist update_cache=yes

    - name: ensure nginx auto start
      service: name=nginx state=started enabled=yes

    - name: test webserver configure files
      always_run: yes
      shell: date
      notify: test nginx config


如此一來,除了安裝 nginx 、更新系統外,還會多了測試 nginx configure files:

$ ansible-playbook mysite.yml -i etc/ansible/hosts --private-key=ansible-deploy.pem

PLAY [mysite] **************************************************

GATHERING FACTS ***************************************************************
ok: [XX.XX.XX.XX]

TASK: [nginx | Add Nginx Official Repo - deb] *********************************
ok: [XX.XX.XX.XX]

TASK: [nginx | Add Nginx Official Repo - deb-src] *****************************
ok: [XX.XX.XX.XX]

TASK: [nginx | Add Nginx Official Repo - package signing key] *****************
ok: [XX.XX.XX.XX]

TASK: [nginx | Update cache] **************************************************
ok: [XX.XX.XX.XX]

TASK: [nginx | Install Nginx] *************************************************
ok: [XX.XX.XX.XX]

TASK: [ubuntu system upgrade] *************************************************
ok: [XX.XX.XX.XX]

TASK: [ensure nginx auto start] ***********************************************
ok: [XX.XX.XX.XX]

TASK: [test webserver configure files] ****************************************
changed: [XX.XX.XX.XX]

NOTIFIED: [nginx | test nginx config] *****************************************
ok: [XX.XX.XX.XX]

PLAY RECAP ********************************************************************
XX.XX.XX.XX             : ok=10   changed=1    unreachable=0    failed=0


這邊發動測試 nginx 測試檔是綁定在一個 date 指令上,因為 date 每次結果都不一樣,將導致永遠都是 changed=1 結果。以上就完成了建立一個 role 並且納入使用的方式。

接著試試設定的部分吧!把一些設定檔那來做模板(templates),未來可以透過引入 nginx role 時,搭配指定參數後,即可產生客製化的設定檔:

先將機器上的 nginx 設定檔搬到 roles/nginx/templates 中,且檔案結尾改成 .j2 ,這是因為 ansible template 採用 Jinja2 方案。

$ scp -r -i ansible-deploy.pem ubuntu@XX.XX.XX.XX:/etc/nginx/conf.d  roles/nginx/templates/
$ cp roles/nginx/templates/conf.d/default.conf roles/nginx/templates/default.conf.j2
$ tree roles/nginx/templates/
roles/nginx/templates/
├── conf.d
│   ├── default.conf
│   └── example_ssl.conf
└── default.conf.j2


之後就是把機器上的 default.conf 覆蓋掉或是刪掉並搭配新增一則 mysite.conf 來啟用 nginx 了,在此先沿用覆蓋方式。

接著在 mysite.yml 或是 roles/nginx/task/task-Ubuntu.yml 中,就可以引入從 template 取得資料來蓋掉系統檔案,若在 mysite.yml 中:

- name: Update Nginx configure files
  template: src=roles/nginx/templates/default.conf.j2 dest=/etc/nginx/conf.d/default.conf


在 roles/nginx/task/task-Ubuntu.yml:

- name: Update Nginx configure files
  template: src=default.conf.j2 dest=/etc/nginx/conf.d/default.conf


通常都會寫在 roles/nginx/task/main.yml 為多,而上述是因為有偵測系統狀況決定 nginx 設定檔位置,因此我一樣寫在 task-Ubuntu.yml 中。接下來可以朝改寫 default.conf.j2 內變數地用法,將一些常見數值改成變動的,並且在 roles/nginx/defaults/main.yml 定義好,如此一來,在 mysite.yml 引用 roles nginx 時,也就可達成動態變動的方式。

例如:

$ tree .
.
├── ansible-deploy.pem
├── ansible-deploy.pub
├── etc
│   └── ansible
│       └── hosts
├── roles
│   └── nginx
│       ├── defaults
│       │   └── main.yml
│       ├── files
│       ├── handlers
│       │   └── main.yml
│       ├── meta
│       │   └── main.yml
│       ├── README.md
│       ├── tasks
│       │   ├── main.yml
│       │   └── task-Ubuntu.yml
│       ├── templates
│       │   ├── conf.d
│       │   │   ├── default.conf
│       │   │   └── example_ssl.conf
│       │   └── default.conf.j2
│       └── vars
│           └── main.yml
└── mysite.yml

$ cat roles/nginx/templates/default.conf.j2
server {
    listen       {{ nginx_listen }};
    server_name  {{ nginx_server_name }};

    #charset koi8-r;
    #access_log  /var/log/nginx/log/host.access.log  main;

    location / {
        root   {{ nginx_document_root }};
        index  index.html index.htm;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}


提供了 nginx_listen、nginx_server_name 和 nginx_document_root 三個變數,並且定義預設數值:

$ cat roles/nginx/defaults/main.yml
---
# defaults file for nginx
nginx_listen: 80
nginx_server_name: localhost
nginx_document_root: /usr/share/nginx/html


如此一來,在 mysite.yml 中,引入 roles 可以改成:

$ cat mysite.yml
---
- hosts: mysite
  remote_user: ubuntu
  sudo: yes

  roles:
    - { role: 'nginx', nginx_listen: 8080 }

  tasks:
    - name: ubuntu system upgrade
      apt: upgrade=dist update_cache=yes

    - name: test webserver configure files
      always_run: yes
      shell: date
      notify: test nginx config

    - name: reload webserver configure files
      always_run: yes
      shell: date
      notify: restart nginx


透過 ansible-playbook mysite.yml 後,可以去該 server:/etc/nginx/conf.d/default.conf 觀看到數值啦

$ ansible-playbook mysite.yml -i etc/ansible/hosts --private-key=ansible-deploy.pem
PLAY [mysite] **************************************************

GATHERING FACTS ***************************************************************
ok: [XX.XX.XX.XX]

TASK: [nginx | Add Nginx Official Repo - deb] *********************************
ok: [XX.XX.XX.XX]

TASK: [nginx | Add Nginx Official Repo - deb-src] *****************************
ok: [XX.XX.XX.XX]

TASK: [nginx | Add Nginx Official Repo - package signing key] *****************
ok: [XX.XX.XX.XX]

TASK: [nginx | Update cache] **************************************************
ok: [XX.XX.XX.XX]

TASK: [nginx | Install Nginx] *************************************************
ok: [XX.XX.XX.XX]

TASK: [nginx | Update Nginx configure files] **********************************
ok: [XX.XX.XX.XX]

TASK: [ubuntu system upgrade] *************************************************
ok: [XX.XX.XX.XX]

TASK: [ensure nginx auto start] ***********************************************
ok: [XX.XX.XX.XX]

TASK: [test webserver configure files] ****************************************
changed: [XX.XX.XX.XX]

TASK: [reload webserver configure files] **************************************
changed: [XX.XX.XX.XX]

NOTIFIED: [nginx | restart nginx] *********************************************
changed: [XX.XX.XX.XX]

NOTIFIED: [nginx | test nginx config] *****************************************
ok: [XX.XX.XX.XX]

PLAY RECAP ********************************************************************
XX.XX.XX.XX             : ok=13   changed=3    unreachable=0    failed=0