What is Ansible? It is open source software that automates software delivery, configuration management, and application deployment. Ansible helps DevOps professionals automate complex tasks.
Note You are reading an improved version of an article we once released.
-
-
- Key features of Ansible
- Installation and launch
- Ansible structure
- Demo “Real Application”
- Additional materials
-
Key features of Ansible
- Agentless . The client does not have software installed or an agent that communicates with the server.
- Idempotent . No matter how many times you call the operation, the result is the same.
- Simple and extensible . Ansible is written in Python and uses YAML to write commands. Both languages are considered relatively easy to learn.
Installation and launch
# ubuntu
sudo apt-get install ansible
#mac-OS
brew install ansible
Installation instructions for other operating systems can be found here .
Ansible structure
Modules
These are small programs that do some work on the server. For example, instead of running this command:
sudo apt-get install htop
We can use the apt module and install htop :
- name: Install htop
apt: name=htop
Using a module will give you the ability to know if it is installed or not.
Plugins
Ansible comes with several handy plugins and you can easily write your own.
Host inventory
To provide a list of hosts, we need to denote the list found in the inventory file. It resembles the contents of the hosts file .
In its simplest form, it can contain one line:
35.178.45.231 ansible_ssh_user=ubuntu
Playbooks
Ansible playbooks are a way to send commands to remote computers using scripts. Rather than individually using commands to remotely configure computers from the command line, you can customize entire complex environments by passing a script to one or more systems.
group_vars
The file contains a set of variables, such as the database username and password.
Roles
It is a way to group multiple tasks into one container to efficiently automate your work with an easy-to-understand directory structure.
Handlers
They are lists of tasks that do not really differ from regular tasks, which are referenced by a globally unique name and are advertised by notifiers. If nothing notifies the handler, it will not run. No matter how many tasks the handler notifies, it only runs once, after all tasks have completed.
Tags
If you have a large playbook, it can be useful to be able to run only a certain part of its configuration.
Demo “Real Application”
The purpose of this demo is to install a Laravel application in a VPS. We’ll use Lightsail for this .
Steps to create and run the Laravel APP:
-
- Create an instance of Ubuntu Lightsail .
- Install Ansible dependencies on your VPS .
- Add SSH keys to Git .
- Build hosts and ansible.cfg .
- Define a role in Ansible .
- Define a handler .
- Install PHP modules .
- Install Nginx .
- Add the default Nginx configuration .
- Add variables to manage DB credentials, host credentials, GitHub origin url, and .env variables .
- Use Ansible-Vault .
- Create a MySql database, username, and password .
- Clone the codebase to your VPS .
- Generate .env .
- Create a playbook .
Let’s consider each item in more detail.
Creating an Ubuntu Lightsail Instance
Go to your Lightsail dashboard and click Create Instance.
Select Add Startup Script, which runs after your instance is created. Don’t forget to get your SSH key.
Installing Ansible dependencies on our VPS
Add these sh commands to install dependencies:
sudo add-apt-repository ppa:deadsnakes/ppa -y
sudo apt-get update
sudo apt-get install -y python2.7 python3 python-pip
Now we have a ready-made instance, let’s move on to building the Ansible Project.
Adding SSH Keys to Git
You have to add your server id_rsa.pub to your GitHub SSH keys by logging into your server.
# Подключитесь к вашему серверу через SSH и запустите
ssh-keygen
sudo chmod -R 644 .ssh/id_rsa
cat .ssh/id_rsa.pub
# Добавьте результат команды в аккаунт Git
# github settings=> SSH keys => Add new Key
# bitbucket settings=> ssh-keys => Add new Key
Build hosts and ansible.cfg
hosts.ini
[aws]
# Ваш IP сервера
127.0.0.39
ansible.cfg
[defaults]
hostfile = hosts.ini
# configure log dir
log_path= logs/ansible-log.log
Defining a role in Ansible
We use the Ping module to make sure the host is working, after which we need to update all packages and install two modules: git and htop .
---
- ping: ~
###
- name: Update apt packages
apt:
update_cache: yes
##
- name: Install GIT VCS
apt:
name: git
state: latest
##
- name: Install htop
apt: name=htop
Defining a handler
---
- name: Restart PHP-FPM
service:
name: php{{php_version}}-fpm
state: restarted
####
- name: Restart Nginx
service:
name: nginx
state: restarted
Installing PHP modules
To call the handler, we must use notify: Restart PHP-FPM , the handler names must be unique.
In this tutorial, we have defined php as a tag, so, for example, if you only want to run this task from your playbook, you need to execute it with —tags = ”php” which will only execute it.
---
- name: Install PHP {{php_version}} PPA Repo
apt_repository:
repo: 'ppa:ondrej/php'
tags:
- php
##
- name: Install PHP {{php_version}}
apt: name=php{{php_version}} state=latest
##
- name: Install PHP packages
become: true
apt:
name: "{{ item }}"
state: latest
with_items:
- php{{php_version}}-curl
- php{{php_version}}-fpm
- php{{php_version}}-intl
- php{{php_version}}-mysql
- php{{php_version}}-xml
- php{{php_version}}-mbstring
notify: Restart PHP-FPM
tags:
- php
Installing Nginx
- name: Install Nginx web server
apt:
name: nginx
state: latest
notify: Restart Nginx
tags:
- nginx
###
- name: Update nginx config files
become: true
template:
src: templates/nginx.conf
dest: "/etc/nginx/sites-available/default"
tags:
- nginx
notify: Restart Nginx
###
- name: link nginx config
become: true
file:
src: "/etc/nginx/sites-available/default"
dest: "/etc/nginx/sites-enabled/default"
state: link
tags:
- nginx
notify: Restart Nginx
Adding the default Nginx configuration
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name {{ server_name }};
root {{ app_work_dir }}public;
location / {
try_files $uri $uri/ /index.php?$args;
index index.php index.html index.htm;
}
if (!-d $request_filename) {
rewrite ^/(.*)/$ /$1 permanent;
}
location = /favicon.ico {
access_log off;
log_not_found off;
}
location ~ \.php$ {
try_files $uri $uri/ /index.php?$args;
index index.php index.html index.htm;
fastcgi_pass unix:/var/run/php/php{{php_version}}-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME {{app_work_dir}}public$fastcgi_script_name;
fastcgi_param APPLICATION_ENV testing;
fastcgi_param PATH /usr/bin:/bin:/usr/sbin:/sbin;
fastcgi_intercept_errors on;
include fastcgi_params;
}
}
vars.yml
---
##@ref https://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html#variables-and-vaults
ansible_ssh_user: "ubuntu"
current_user: "ubuntu"
server_name: "app_name"
repo_git_url: "app_github_url"
ansible_ssh_private_key_file: "ssh_dir"
php_version: 7.2
app_work_dir: /var/www/app_name/
#mysql config
mysql_host: "mysql_host"
mysql_db: app_name
mysql_user: sql_user
mysql_pass: sql_pass
#other config
cache_driver: file
session_driver: file
app_env: production
app_debug: false
app_key: "your_app_key"
app_name: "app_name"
app_url: "your_app_url"
Note: It is recommended to use ansible-vault to encrypt and decrypt variables.
How to use Ansible-Vault
Create a secret vault file containing an encryption key that encrypts your variables.
touch .vault_pass.txt
echo 'YOUR_CONFIG_PASS' > .vault_pass.txt
To encrypt variables use:
ansible-vault encrypt group_vars/vars.yml --vault-password-file .vault_pass.txt
To decrypt variables use:
ansible-vault decrypt group_vars/vars.yml --vault-password-file .vault_pass.txt
Create MySql Database, Username and Password
- mysql_user:
name: "{{mysql_user}}"
password: "{{mysql_pass}}"
priv: '*.*:ALL'
state: present
tags:
- mysql-db
##
- name: Create APP DB database
mysql_db: name="{{mysql_db}}" state=present login_user="{{mysql_user}}" login_password="{{mysql_pass}}"
mysql_user
and are mysql_pass
defined inside vars.yml .
Cloning the codebase
- name: update repo - pull the latest changes
git:
repo: "{{repo_git_url}}"
dest: "{{app_work_dir}}"
update: yes
version: master
accept_hostkey: yes
key_file: /home/{{current_user}}/.ssh/id_rsa
tags:
- code-deploy
repo_git_url
and are app_work_dir
defined inside vars.yml .
Generating .env
Ansible uses the Jinja2 templating engine for dynamic expressions and variable access. Let’s create an env.conf file .
APP_ENV={{app_env}}
APP_DEBUG={{app_debug}}
APP_KEY={{app_key}}
APP_URL={{app_url}}
APP_NAME={{app_name}}
DB_HOST={{mysql_host}}
DB_DATABASE={{mysql_db}}
DB_USERNAME={{mysql_user}}
DB_PASSWORD={{mysql_pass}}
CACHE_DRIVER={{cache_driver}}
SESSION_DRIVER={{session_driver}}
Let’s define role
to move this template to our application directory.
---
- name: Copy lara env file
become: true
template:
src: templates/env.conf
dest: "{{app_work_dir}}/.env"
tags:
- env-file
Creating a playbook
---
- hosts: aws
#common options between modules
sudo: yes
gather_facts: no
vars_files:
- ./group_vars/vars.yml
roles:
- misc
- php
- mysql
- redis
- nginx
- bootstrap-app
- code-deploy
###
handlers:
- include: handlers/main.yml
As you can see, we have defined aws as the host for this playbook, and sudo yes gives us the ability to execute the command as the sudo user . We have vars_files where we store our vars . We have set up roles , each role has a specific task. Finally, we have the handlers that contain all the handlers for the project.
Launching a playbook
#ansible-playbook playbookName
ansible-playbook code-deploy.yml
# Запуск с конкретными тегами
ansible-playbook playbook.yml --tags="env-files,php"
# Если вы используете ansible-vault
ansible-playbook code-deploy.yml --vault-password-file .vault_pass.txt
Complete project structure
├── ansible.cfg
├── code-deploy.yml
├── files
│ └── dump.sql
├── group_vars
│ └── vars.yml
├── handlers
│ └── main.yml
├── hosts.ini
├── logs
│ └── ansible-log.log
├── roles
│ ├── bootstrap-app
│ │ └── tasks
│ │ └── main.yml
│ ├── code-deploy
│ │ ├── tasks
│ │ │ ├── config-files.yml
│ │ │ └── main.yml
│ │ └── templates
│ │ └── env.conf
│ ├── misc
│ │ └── tasks
│ │ └── main.yml
│ ├── mysql
│ │ └── tasks
│ │ ├── config.yml
│ │ └── main.yml
│ ├── nginx
│ │ ├── tasks
│ │ │ └── main.yml
│ │ └── templates
│ │ └── nginx.conf
│ ├── php
│ │ └── tasks
│ │ └── main.yml
│ └── redis
│ └── tasks
│ └── main.yml
├── scripts
│ ├── install_composer.sh
│ └── startup.sh
└── site.yml
Comments 1