Ansible is a scripting language mostly used to automate installing applications, deploying apps etc..
Why Ansible:
You may think why to learn a new language if I can do the same using shell scripts, well that's ok but in my opinion ansible doesn't take much time to learn and shell scripts could become complex as the projects scale up. You can read further details over here(https://news.ycombinator.com/item?id=6431552).
Before we start it's important that you have an overview of uwsgi and Nginx configurations to deploy a project. You can look over this(http://uwsgi-docs.readthedocs.org/en/latest/tutorials/Django_and_nginx.html) beautiful and simple docs.
Lets start:
1. Install ansible:
Recomended: pip install ansible
Archlinux: pacman -S ansible Note: archlinux uses python3 as default so you need to create a file /etc/ansible/group_vars/all and paste: --- ansible_python_interpreter: /usr/bin/python2
Ubuntu:
sudo apt-add-repository ppa:ansible/ansible
sudo apt-get update
sudo apt-get install ansible
2. Check if it's working:
Create /etc/ansible/hosts file with
[server1]
your_server_ip_address_here
and execute: ansible all -m ping
you will get a response as pong. The above command executes ping over all servers to specify any group(specific servers) then execute: ansible server1 -m ping
3. Example ansible playbook.
Note: Here I assume Ubuntu 14.04 server and ssh permission to it.
Let's install vim over the server.
First provide the IP address in /etc/ansible/hosts file
[my_server]
my_server_ip_address
Now create a task file. Ansible uses yml language.
create script.yml and paste the following
---
- name: install vim package
apt: name=vim state=latest force=yes
Now create a playbook which runs above created role over specified hosts:
create playbook.yml with the following
---
- hosts: my_server
remote_user: root
roles:
- script
Now run:
ansible-playbook playbook.yml
The above script installs latest vim package with apt-get package manager.
4. Update your ubuntu server:
First, before updating we have to create grub file as some packages require it. So create update_ubuntu.yml file with
---
- name: check grub file # task name
shell: test -f /boot/grub/menu.lst # shell module is no different than executing a command in shell eg: /bin/sh
register: grub_file # store the result of a shell command in grub_file
failed_when: False # silently fail when there are errors
- name: update grub
command: "sudo update-grub -y" # different from shell module as this does not have access to variables like $HOME etc..
environment:
DEBIAN_FRONTEND: noninteractive # suppress debconf questions
when: grub_file.rc != 0
- name: update apt-packages
apt: "upgrade=dist update_cache=yes" # uses apt module to upgrade distribution
Now as before creating a playbook with required configs:
In playbook.yml:
---
- hosts: my_server
remote_user: root
roles:
- update_ubuntu
5. Create Django project:
Create file django_project.yml and paste:
Note: project_name is provided in the playbook.yml file.
---
- name: Install required apt-packages
apt: "name='{{ item }}' state=present force=yes" # this is like looping through all the items provided and install each respectively.
with_items:
- python-dev
- python-virtualenv
- python-pip
- openjdk-7-jre-headless
- libjpeg8-dev
- zlib1g-dev
- libfreetype6-dev
- liblcms2-dev
- libwebp-dev
- libtiff-dev
- tcl-dev
- tk-dev
- python-tk
- redis-server
- git
- ruby
- name: Creates directory
file: "path=/home/{{project_name}} state=directory" # similar to mkdir this creates directory given by project_name
- name: create virtualenv and install django in it
pip: "name=django virtualenv=/home/{{project_name}}/env virtualenv_command=virtualenv"
- name: install a django project
command: "/home/{{project_name}}/env/bin/django-admin.py startproject {{project_name}} chdir=/home/{{project_name}}/"
Now create playbook.yml file:
---
- hosts: my_server
remote_user: root
roles:
- { role: django_project, project_name: 'mysite' }
run ansible-playbook playbook.yml
That's it, your django project is created.
6. Create templates for uwsgi, Nginx and supervisor
The supervisor is just a process control system like it starts or stops an instance. Here we control uwsgi service using su
Things that we need here are the configuration files, ansible uses jinja2 template for configurations.
First create uwsgi template:
create uwsgi.j2 file and paste:
[uwsgi]
chdir = /home/{{project_name}}/{{project_name}}/
module = {{project_name}}.wsgi
home = /home/{{project_name}}/env
master = true
processes = 4
socket = /home/{{project_name}}/{{project_name}}.sock
chmod-socket = 666
vacuum = true
harakiri = 60
max-requests = 5000
For running uwsgi in emperor mode we use supervisor.
Create configuration for supervisor, so create uwsgi_server.j2 jinja2 template and paste:
[program:uwsgi-runner]
stdout_logfile = /var/log/supervisor/uwsgi-runner-out.log
stderr_logfile = /var/log/supervisor/uwsgi-runner-err.log
logfile_maxbytes = 50MB
logfile_backups = 10
command = /usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals
Now create nginx templates:
In nginx.j2 paste:
upstream {{project_name}} {
server unix:///home/{{project_name}}/{{project_name}}.sock;
}
server {
listen {{ server_port }};
server_name {{ server_name }};
charset utf-8;
client_max_body_size 75M;
error_log {{nginx_error_log}};
location / {
uwsgi_pass {{project_name}};
include uwsgi_params;
}
location /static {
alias /home/{{project_name}}/{{project_name}}/static;
expires 365d;
}
location /media {
alias /home/{{project_name}}/{{project_name}}/media;
expires 365d;
}
location /player/private/media/ {
alias /home/{{project_name}}/{{project_name}}/media/;
}
location /robots.txt { root /home/{{project_name}}/{{project_name}}/static/; }
location /favicon.ico { root /home/{{project_name}}/{{project_name}}/static/; }
}
In step 7 we create roles using these templates.
7. uWSGI and Nginx roles:
Create uwsgi_django_setup.yml file and include:
---
- name: Install python-dev
apt: "name='python-dev' state=present force=yes"
- name: Install python-pip
apt: "name='python-pip' state=present force=yes"
- name: install uwsgi
pip: name=uwsgi
- name: Install supervisor
apt: name=supervisor state=present force=yes
when: is_installed.rc != 0
- name: Create UWSGI vassals directory
file: "path={{vassals_dir}} state=directory"
- name: setup uwsgi in supervisor
template: "src=uwsgi-server.j2 dest={{supervisor_conf_dir}}/uwsgi-runner.conf"
- name: update supervisor
supervisorctl: name=uwsgi-runner state=restarted
- name: setup project uwsgi configuration file
template: "src=uwsgi.j2 dest=/home/{{project_name}}/{{project_name}}_uwsgi.ini"
- name: create a symlink of uwsgi in vassals
file: "src=/home/{{project_name}}/{{project_name}}_uwsgi.ini dest=/etc/uwsgi/vassals/{{project_name}}_uwsgi.ini state=link"
- name: touch the symlink file
command: "touch /etc/uwsgi/vassals/{{project_name}}_uwsgi.ini"
Nginx Django setup role:
create file nginx_django_setup.yml and paste:
---
- name: Install nginx
apt: "name='nginx' state=present force=yes"
- name: copy nginx config of project
template: "src=nginx.j2 dest={{nginx_conf_dir}}/{{project_name}}.conf"
- name: copy nginx conf from sites-available to sites-enabled
file: "src={{nginx_conf_dir}}/{{project_name}}.conf dest={{nginx_sites_dir}}/{{project_name}}.conf state=link"
- name: create project log directory
file: "path=/home/{{project_name}}/logs state=directory"
- name: start nginx
service: "name=nginx state=started"
Finally, create a playbook.yml:
---
- hosts: my_server
remote_user: root
roles:
- { role: uwsgi_django_setup, project_name: 'mysite'}
- { role: nginx_django_setup, project_name: 'mysite' }
Run ansible-playbook playbook.yml, your project will be deployed.
Note: We have hosted these scripts over ansible galaxy. You can pull using:
ansible-galaxy pull micropyramid.django