25
25
VilniusPy #3
2015-06-30
- Multi-node software deployment and configuration management tool.
In other words..
You can deploy your app multiple times on different servers with one command.
Fabric
You can learn it in 5 minutes, better than shell scripting.
Anslibe
You can learn it in one day, better than Fabric scripting.
SaltStack, Chef, Puppet and friends
I never had enough time to learn any of them, they say, that these tools are better than Ansible.
- One server.
- Many projects.
- Very few users using those projects.
- Apache or Nginx with mod_wsgi or uWSGI.
- PostgreSQL database (MySQL for older projects).
- Mostly Python 3.
akl.lt: Python 3, Nginx, uWSGI, PostgreSQL
atviriduomenys.lt: Python 3, Apache, mod_wsgi, PostgreSQL
manoseimas.lt: Python 2, Apache, mod_wsgi, MySQL, CouchDB
pydev.lt: Python 3, Apache, mod_wsgi, PostgreSQL
If you run a Debian based distro:
$ apt install ansible
pip install
also works:$ pip install ansible
Simplest possible way to make Ansible do something:
$ ansible host -c local -i host, -m ping
host | success >> {
"changed": false,
"ping": "pong"
}
- ansible command
- on host
- defined in -i host, inventory line
- using -c local connection backend
- runs -m ping module
playbook.yml:
---
- hosts: host
tasks:
- ping:
$ ansible-playbook -c local -i host, playbook.yml
It does same thing as:
$ ansible host -c local -i host, -m ping
Let's add some defaults using ansible.cfg:
[defaults]
inventory = inventory.cfg
inventory.cfg:
host ansible_connection=local
Now, I don't have to specify inventory file and connection:
$ ansible host -m ping
$ ansible-playbook playbook.yml
Modules have arguments:
$ ansible host -m command -a uptime
host | success | rc=0 >>
up 1 day, 1:17
Default module is command
:
$ ansible host -a uptime
host | success | rc=0 >>
up 1 day, 1:18
Argument can be a YAML expression or key=value
string.
Same thing using playbook playbook.yml:
---
- hosts: host
gather_facts: no
tasks:
- command: uptime
$ ansible-playbook playbook.yml
PLAY [host] ***********************************************
TASK: [command uptime] ************************************
changed: [host]
PLAY RECAP ************************************************
host : ok=1 changed=1 unreachable=0 failed=0
---
- hosts: host group name
vars: a dict of variables
tasks: list of tasks
handlers: list of handlers
roles/
role/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
playbook.yaml:
---
- hosts: host
roles:
- role
mymodule.py:
from ansible.module_utils.basic import *
def main():
module = AnsibleModule(
argument_spec = dict(
state = dict(default='present', choices=['present', 'absent']),
name = dict(required=True),
enabled = dict(required=True, choices=BOOLEANS),
something = dict(aliases=['whatever'])
)
)
module.exit_json(changed=True, something_else=12345)
if __name__ == '__main__':
main()
$ ansible-galaxy install rolename
Category | Total Roles |
---|---|
system | 1421 |
development | 788 |
web | 721 |
monitoring | 289 |
networking | 258 |
packaging | 248 |
database | 189 |
... | ... |
apt: pkg={{ item }} state=latest
with_items:
- build-essential
- postgresql
- python-psycopg2
- python-dev
- python-pip
- python-virtualenv
- apache2
- libapache2-mod-wsgi-py3
- git
user: >
name=myproject
system=yes
group=www-data
home={{ home }}
For this to work, you need sudo: yes
and home
variable:
hosts: host
sudo: yes
vars:
home: /opt/myproject
- postgresql_db: >
name=myproject
encoding='UTF-8'
lc_collate='C.UTF-8'
lc_ctype='C.UTF-8'
template='template0'
sudo_user: postgres
- postgresql_user: db=myproject name=myproject priv=ALL
sudo_user: postgres
- postgresql_user: >
name=myproject
role_attr_flags=NOSUPERUSER,NOCREATEDB
sudo_user: postgres
template: >
src=templates/apache.conf
dest=/etc/apache2/sites-enabled/myproject.conf
notify: reload apache
handlers:
- name: reload apache
service: name=apache2 state=reloaded
<VirtualHost *:80>
ServerName {{ server_name }}
DocumentRoot {{ path }}/var/www
Alias /media/ {{ path }}/var/www/media/
Alias /static/ {{ path }}/var/www/static/
<Directory {{ path }}/var/www>
Require all granted
</Directory>
WSGIDaemonProcess myproject user=myproject group=www-data
WSGIProcessGroup myproject
WSGIScriptAlias / {{ path }}/bin/django.wsgi
<Directory {{ path }}/bin/>
<Files django.wsgi>
Require all granted
</Files>
</Directory>
ErrorLog /var/log/apache2/myproject/error.log
CustomLog /var/log/apache2/myproject/access.log combined
</VirtualHost>
server {
listen 80;
charset utf-8;
server_name {{ server_name }};
location /media {
alias {{ path }}/var/www/media;
}
location /static {
alias {{ path }}/var/www/static;
}
location / {
include uwsgi_params;
uwsgi_pass unix:///run/uwsgi/app/myproject/socket;
}
access_log /var/log/nginx/myproject/access.log;
error_log /var/log/nginx/myproject/error.log;
}
- stat: path=/root/.my.cnf
register: root_my_cnf
- mysql_user: >
name=root host=localhost state=present
password={{ lookup('password', 'secrets/mysqlroot') }}
when: not root_my_cnf.stat.exists
- template: >
src=templates/root_my.cnf
dest=/root/.my.cnf owner=root mode=0600
when: not root_my_cnf.stat.exists
[client]
user = root
password = {{ lookup('password', 'secrets/mysqlroot') }}
default-character-set = utf8
git: >
repo=https://github.com/me/myproject
dest={{ path }}
force=yes
notify: reload source code
sudo_user: myproject
handlers:
- name: reload source code
command: touch --no-create {{ path }}/bin/django.wsgi
pip: >
virtualenv={{ path }}
requirements={{ path }}/requirements.txt
command: bin/django migrate --noinput chdir={{ path }}
sudo_user: myproject
command: bin/django collectstatic --noinput chdir={{ path }}
sudo_user: myproject
vars:
vars: production
vars_files:
- vars/{{ vars }}.yml
Changing environment from command line:
$ ansible-playbook playbook.yml -e vars=staging
Vagrantfile:
Vagrant.configure('2') do |config|
config.vm.define 'box' do |box|
box.vm.box = 'ubuntu/trusty64'
box.vm.network :forwarded_port, guest: 80, host: 8080
box.vm.synced_folder '.', '/vagrant', disabled: true
config.vm.provision "ansible" do |ansible|
ansible.playbook = "deploy.yml"
ansible.extra_vars = {
vars: "vagrant",
}
end
end
end
vagrant provision
$ ansible-playbook deploy.yml
Pros
- Quite easy to learn.
- Easy to set up.
- Better than Fabric or shell scripting (thanks to many modules).
Cons
- Very slow.
- Hides output and there is no easy way to get output.
50
for your attention.