http://steinim.github.io/slides/fosdem/zero-downtime-ansible
git@github.com:steinim/zero-downtime-ansible.git
http://steinim.github.io/slides/fosdem/zero-downtime-ansible/tutorial.html
#!/bin/bash
if $( command -v vim >/dev/null 2>&1 ); then
echo "vim is already installed."
else
apt-get install vim
fi
if $( grep -Fxq "filetype indent off" /etc/vim/vimrc ); then
echo "set filetype indent off is already in /etc/vim/vimrc."
else
echo "filetype indent off" >> /etc/vim/vimrc
# TODO: Do not continue if this fails.
fi
# TODO: Rollback if something fails.
- name: Ensure installed vim
apt:
pkg: vim
state: present
update_cache: no
tags:
- vim
- name: Set filetype indent off
lineinfile:
dest: /etc/vim/vimrc
line: 'filetype indent off'
state: present
tags:
- vim
vagrant up
├── ansible.cfg
├── hosts
├── site.yml
├── group_vars
│ └── <group name>
├── host_vars
│ └── <host name>
├── roles
│ ├── <role>
│ │ ├── files
│ │ └── <file>
│ │ └── templates
│ │ └── <template>.j2
│ │ ├── handlers
│ │ │ └── main.yml
│ │ ├── tasks
│ │ │ └── main.yml
│ │ ├── vars
│ │ │ └── main.yml
ansible-playbook site.yml
ansible -m setup app1.local
git checkout start
Help: http://docs.ansible.com/apt_module.html http://docs.ansible.com/lineinfile_module.html
- name: Ensure installed vim
apt:
pkg: vim
state: present
update_cache: no
tags:
- vim
- name: Set filetype indent off
lineinfile:
dest: /etc/vim/vimrc
line: 'filetype indent off'
state: present
tags:
- vim
ansible-playbook site.yml --tags vim
ProTip: Use '--tags', '--skip-tags', '--limit' and/or 'gather_facts: False'
to reduce execution time.
Help: http://docs.ansible.com/group_module.html http://docs.ansible.com/user_module.html http://docs.ansible.com/file_module.html (create a directory) http://docs.ansible.com/lineinfile_module.html (.ssh/authorized_keys) http://docs.ansible.com/playbooks_best_practices.html#group-and-host-variables
# group_vars/appservers
user: devops
group: devops
user_name: "Devops app user"
# roles/users/tasks/main.yml
- name: Create group
group:
name: "{{ group }}"
state: present
tags:
- users
- name: Create user
user:
name: "{{ user }}"
comment: "{{ user_name }}"
group: "{{ group }}"
createhome: yes
home: "/home/{{ user }}"
shell: /bin/bash
state: present
tags:
- users
- name: Ensure ssh directory exists for user
file:
dest: "/home/{{ user }}/.ssh"
owner: "{{ user }}"
group: "{{ group }}"
state: directory
mode: 0700
tags:
- users
- name: Ensure public key is in authorized_keys
lineinfile:
dest: "/home/{{ user }}/.ssh/authorized_keys"
state: present
line: "{{ lookup('file','~/.ssh/id_rsa.pub') }}"
insertafter: EOF
create: yes
owner: "{{ user }}"
group: "{{ group }}"
mode: 0600
regexp: ^ssh-rsa
tags:
- users
ansible-playbook site.yml --limit appservers --skip-tags apt,vim,java
ssh devops@app1.local
roles/postgresql
├── files
│ └── postgresql.conf
├── handlers
│ └── main.yml
├── tasks
│ ├── main.yml
│ └── ...
└── templates
└── pg_hba.conf.j2
Use variables (group_vars/all and/or group_vars/dbservers).
Use handler to restart postgresql upon notification
Template: git checkout task3 -- roles/postgresql/templates/pg_hba.conf.j2
Help: http://docs.ansible.com/template_module.html (pg_hba.conf.j2) http://docs.ansible.com/postgresql_user_module.html http://docs.ansible.com/postgresql_db_module.html http://docs.ansible.com/playbooks_intro.html#handlers-running-operations-on-change http://docs.ansible.com/playbooks_best_practices.html#group-and-host-variables
# group_vars/dbservers
postgresql:
version: 9.4
repo: 'deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main'
user: postgres
group: postgres
data_dir: /var/lib/pgsql/data
address: 192.168.101.0/24
db:
name: devops
user: devops
password: devops123
# roles/postgresql/templates/pg_hba.conf.j2
# TYPE DATABASE USER ADDRESS METHOD
local all all trust
host {{ db.name }} {{ db.user }} {{ postgresql.address }} md5
# roles/postgresql/handlers/main.yml
- name: Restart postgresql
service:
name: postgresql
state: restarted
# roles/postgresql/tasks/postgresql.yml
- name: Install Postgresql and dependencies
apt:
pkg: "{{ item }}"
state: installed
with_items:
- "postgresql-{{ postgresql.version }}"
- python-psycopg2
tags:
- pg_install
- name: Install postgresql.conf
copy:
src: postgresql.conf
dest: "/etc/postgresql/{{ postgresql.version }}/main/postgresql.conf"
owner: "{{ postgresql.user }}"
group: "{{ postgresql.group }}"
notify:
- Restart postgresql
tags:
- pg_install
- name: Install pg_hba.conf
template:
src: pg_hba.conf.j2
dest: "/etc/postgresql/{{ postgresql.version }}/main/pg_hba.conf"
owner: "{{ postgresql.user }}"
group: "{{ postgresql.group }}"
notify:
- Restart postgresql
tags:
- pg_install
- name: Ensure that postgresql is started
service:
name: postgresql
state: started
tags:
- pg_install
- name: Create database
postgresql_db:
name: "{{ db.name }}"
become_user: postgres
tags:
- pg_install
- name: Create db user
postgresql_user:
db: "{{ db.name }}"
name: "{{ db.user }}"
password: "{{ db.password }}"
become_user: postgres
tags:
- pg_install
- name: Ensure that postgresql is started
service:
name: postgresql
state: started
tags:
- pg_install
ansible-playbook site.yml --limit dbservers --tags pg_install
$ vagrant ssh db
vagrant@db:~$ psql -d devops -U devops -W
devops=> \q
roles/app
├── files
│ └── init.sh
├── tasks
│ └── main.yml
└── templates
└── config.properties.j2
NB! Use variables (./hosts).
Set 'serial: 1' for appservers in the playbook (site.yml).
Help: http://docs.ansible.com/service_module.html
ansible-playbook site.yml --limit appservers --tags deploy
/home/devops
├── config.properties
├── current -> /home/devops/devops_1416228023.jar
├── previous -> /home/devops/devops_1416221573.jar
├── devops_1416221573.jar
├── devops_1416228023.jar
└── logs
├── stderr.log
└── stdout.log
/etc/init.d
└── devops
roles/db
├── files
│ └── migrate_db.sql
└── tasks
└── main.yml
Help: http://docs.ansible.com/command_module.html
psql -d {{ db.name }} -q -f /tmp/migrate_db.sql
become_user: postgres
- name: Copy db migration script
copy:
src: migrate_db.sql
dest: /tmp/migrate_db.sql
become_user: postgres
tags:
- deploy
- name: Run db migration script
command: psql -d {{ db.name }} -q -f /tmp/migrate_db.sql
become_user: postgres
tags:
- deploy
ansible-playbook site.yml --limit dbservers --tags deploy
$ vagrant ssh db
vagrant@db:~$ psql -d devops -U devops -W
devops=> \dt
devops=> select * from hello;
devops=> \q
Browse to http://app1.local:1234/
roles/nginx
├── handlers
│ └── main.yml
├── tasks
│ ├── config_nginx.yml
│ ├── install_nginx.yml
│ └── main.yml
└── templates
└── devops.conf.j2
Help: http://jinja.pocoo.org/docs/latest/templates/#for
upstream backend {
{% for appserver in groups.appservers %}
server {{ appserver }}:{{ app_port }} fail_timeout=1s;
{% endfor %}
}
server {
listen 80;
server_name _;
access_log /var/log/nginx/devops-access.log;
location / {
proxy_pass http://backend;
proxy_redirect off;
proxy_next_upstream error timeout invalid_header http_500 http_502;
proxy_connect_timeout 2;
}
}
ansible-playbook site.yml --limit proxies --tags nginx
Expand | Contract |
---|---|
|
|
All will be decrypted on the target host
(assuming a valid vault password is supplied when running the play)
ansible-vault create group_vars/vault
ansible-playbook site.yml --ask-vault-pass
Help: http://docs.ansible.com/ansible/playbooks_vault.html