Share
Embed
Deploy Silverstripe with Ansible
Talk on the Silverstripe Conference 2015 in London. www.stripecon.eu
wernerkrauss
October 17, 2015
Transcript
66 slides
-
Deploy Silverstripe with Ansible And setup a server for free
©Kraft/www.hallstatt.net -
About me • Werner M. Krauß • Located in Hallstatt,
Austria • wmk on IRC / github / stackoverflow • PHP since 1998 • Freelancer since 2006 (netwerkstatt) • SilverStripe since 2009 -
Overview • What is this thing called ansible? • What
is debops? • What is deployment? • How can we put this things together and deploy a SilverStripe site with it? -
What is Ansible • IT automation tool • Based on
python • Free, open source • Agentless, over ssh • Batteries included (comes with many useful modules) -
Ansible is indempotent • Produces the same results if executed
multiple times • Declarative tasks define the wanted state -
Ansible scales down • Of course you can manage tons
of servers • Configuring a single node is also easy • "Simple things should be simple, complex things should be possbile" (Alan Kay) -
Requirements • Control Machine: – Python 2.6 or 2.7 –
gcc (for installing some python packages) – Linux, OSX, any BSD…. – Windows isn‘t supported • Managed Node: – SSH – Python 2.4 or later -
Installation • Python 2.7, gcc on the management machine •
Install requirements: sudo pip install paramiko PyYAML Jinja2 httplib2 six • sudo pip install ansible -
Inventory • INI format of your hosts • Group hosts
• Subgroups are possible -
Example Inventory [digitalocean] demo ansible_ssh_host=demo.silverstrip.es ansible_ssh_user=root mysite ansible_ssh_host=123.45.67.89 [webservers] demo
www[01:50].example.com [mysql] db-[a:f].example.com -
Ad-hoc commands • ansible <host-pattern> [options] –ansible all -m ping
–ansible all -a "free m" –ansible webservers -m apt -a "name=tree state=latest" ansible module shell command -
Concepts • Playbook • Plays • Tasks and handlers •
Modules • Variables -
Playbooks • Infrastructure as code • yml files • We
SilverStripers love yml • pre_tasks, tasks, post_tasks and handlers -
Variables • Playbooks • Inventory (group vars, host vars) •
Command line • Discovered vars (aka facts) • Of course defaults in a role -
Roles • reusable components • ~3.500 ready-to-use roles on ansible
galaxy • create your own role: ansible-galaxy init <name> like SilverStripe modules -
Ansible vault • For saving sensible data encrypted – passwords
– keys etc… • Vault files can be distributed or placed in vcs -
What is debops? • Your Debian-based data center in a
box • Collection of Ansible playbooks • Scalable • 80+ highly extensible roles • Some custom scripts • Since October 2013 • Small but very helpful community -
Installing debops • sudo pip install debops • Create your
DebOps project: debops-init /path/to/myproject • Download playbooks and roles: debops-update -
What is deployment? Deployment is a word, often used by
the military, for sending troops into duty. A soldier could be part of a deployment to the Middle East. Deployment refers to assigning people to serve in various locations, especially soldiers and other military personnel. www.vocabulary.com/dictionary/deployment -
What is deployment? #2 In its IT context, deployment encompasses
all the processes involved in getting new software or hardware up and running properly in its environment, including installation, configuration, running, testing, and making necessary changes. whatis.techtarget.com/definition/deploy -
Deploying SilverStripe • Check if all required packages are installed
– nginx, mysql, memcache etc… • Set up a virtual host • Create needed directories • Create database • Create _ss_environment.php or mariaDB -
Deploying Silverstripe #2 • Copy files (checkout from git) •
Install composer packages • Import database and assets • Run dev/build • Optional: setup cron tasks • …and anything you need for a happy site -
Basic server setup • Depops bootstrap • Setup ssh key
on the machine • Add host to the webserver, php (and db) groups in inventory • Configure group vars -
Example group vars --- ntp_timezone: 'Europe/Berlin' postfix_relayhost: 'smtp.mydomain.com' postfix_default_local_alias_recipients: ['[email protected]']
console_root: false #don't manage root account now... console_locales: ['de_DE.UTF-8', 'de_AT.UTF-8', ] important for localised dates -
Run first setup • debops bootstrap -k -u root -l
demo wrapper for ansible-playbook ask for password limit hosts playbook for basic server setup -
Install packages • Add the host to special groups in
inventory to install: – mySQL – nginx – PHP -
Run debops again • debops -l demo – downloads and
installs a lot • e.g. mysql role also installs automysqlbackup – takes some time…. -
MORE TASKS TO GET OUR SITE RUNNING Source: artgirl from
Canada, CC BY-SA 2.0 -
Create project user - name: create project user user: name:
'{{ silverstripe_user }}' group: '{{ silverstripe_group }}' comment: 'project user for {{ silverstripe_project }}' home : '{{ silverstripe_user_home}}' state: present append: True system: True some variables defined before -
Configure PHP - role: debops.php5 php5_packages: - php5-memcached - php5-memcache
- php5-gd - php5-curl - php5-mcrypt php5_pools: ['{{ silverstripe_php5_pool }}'] -
Install composer Command line: ansible-galaxy install loranger.debian-composer Playbook: - role:
loranger.debian-composer downloads the role installs composer and keeps it updated when you run the playbook -
Configure nginx • Basically role configuration • Sets up redirect
from e.g. from example.com to www.example.com • Setup virtual host and configure it for SilverStripe -
- role: debops.nginx nginx_upstreams: ['{{ nginx_upstream }}'] nginx_servers: - name:
'{{ silverstripe_domains }}' enabled: True redirect_from: True root: '{{ silverstripe_path_wwwroot }}' owner: '{{ silverstripe_user }}' group: '{{ silverstripe_webserver_user }}' type: 'php5' php5: '{{ silverstripe_user }}' location: '/': try_files $uri @silverstripe; '@silverstripe': | fastcgi_keep_conn on; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass {{ silverstripe_user }}; fastcgi_index index.php; include fastcgi_params; fastcgi_read_timeout 120; fastcgi_connect_timeout 60; fastcgi_send_timeout 120; fastcgi_buffer_size 64k; fastcgi_buffers 4 65k; fastcgi_busy_buffers_size 128k; fastcgi_param SCRIPT_FILENAME $document_root/framework/main.php; fastcgi_param SCRIPT_NAME /framework/main.php; fastcgi_param QUERY_STRING url=$uri&$args; … redirect all domains to the first, e.g. www.demo.silverstrip.es => demo.silverstrip.es -
• silverstripe_db_password: '' #will be created silverstripe_db_pass: '{{ silverstripe_db_password if
silverstripe_db_password|d() else lookup("password", secret + "/credentials/" + ansible_fqdn + "/mysql/" + silverstripe_db_user + "/password length=" + mysql_password_length) }}' • - role: debops.mysql mysql_users: - name: '{{ silverstripe_db_user }}' state: 'present' password: '{{ silverstripe_db_pass }}' priv: '{{ silverstripe_db_database }}.*:ALL' mysql_databases: - name: '{{ silverstripe_db_database }}' -
Setup directories • Webroot • Log dirs • Cache dir
for staticpublisher • etc.. -
- name: Create silverstipe directories file: path: '{{ item }}'
state: 'directory' owner: '{{ silverstripe_user }}' group: '{{ silverstripe_webserver_user }}' mode: '0755' with_items: [ '{{ silverstripe_path_home }}', '{{ silverstripe_path_wwwroot }}' ] - name: create error log dir file: path: '{{ silverstripe_error_log | dirname }}' state: 'directory' owner: '{{ silverstripe_user }}' group: '{{ silverstripe_webserver_user }}' mode: '0750' when: silverstripe_error_log_enabled -
Setup _ss_environment.php • From Jinja2 template • Using vars for
db, domain and paths from above • … and copy it to the server -
- name: create _ss_environment.php template: src: '../templates/_ss_environment.j2' dest: '{{ silverstripe_path_home
+ "/_ss_environment.php" }}' owner: '{{ silverstripe_user }}' group: '{{ silverstripe_webserver_user }}' -
<?php // {{ ansible_managed }} define('SS_ENVIRONMENT_TYPE', '{{ silverstripe_environment_type | default("live")
}}'); /* Database connection */ define('SS_DATABASE_CLASS', '{{ silverstripe_db_class }}'); define('SS_DATABASE_SERVER', '{{ silverstripe_db_host }}'); define('SS_DATABASE_USERNAME', '{{ silverstripe_db_user }}'); define('SS_DATABASE_PASSWORD', '{{ silverstripe_db_pass }}'); define('SS_DATABASE_NAME','{{ silverstripe_db_database }}'); {% if silverstripe_error_log_enabled %} define('SS_ERROR_LOG', '{{ silverstripe_error_log }}'); {% endif %} $_FILE_TO_URL_MAPPING['{{ silverstripe_path_wwwroot }}'] = 'http://{{ silverstripe_domains|first }}'; fallback for undefined variables -
- name: checkout project repository in webroot git: repo='{{ silverstripe_repo_url
}}' dest='{{ silverstripe_path_wwwroot }}' accept_hostkey=yes tags: deploy-update - name: set file ownership file: > path={{ silverstripe_path_wwwroot }} recurse=yes owner='{{ silverstripe_user }}' group='{{ silverstripe_webserver_user }}' tags: deploy-update tags are useful if you want to run a set of tasks only -
Run installation scripts - name: run composer update shell: 'cd
{{ silverstripe_path_wwwroot }} && composer install --no-dev --prefer-dist -o' tags: deploy-update - name: ensure sake is executable file: > path='{{ silverstripe_sake}}' mode='o+x' tags: deploy-update - name: run dev/build shell: '{{ silverstripe_sake + " dev/build flush" }}' tags: deploy-update -o : optimize autoloader -
Import data • SQL dump • Assets • Only when
variables are defined • Best define it in command line when you really want to overwrite the database -
- name: copy dump to remote copy: > src='{{ silverstripe_db_dump
}}' dest='{{ silverstripe_path_temp + "/" + silverstripe_db_dump|basename }}' owner='{{ silverstripe_user }}' group='{{ silverstripe_webserver_user }}' when: silverstripe_db_dump is defined - name: import sql dump mysql_db: > name='{{ silverstripe_db_database }}' state=import target='{{ silverstripe_path_temp + "/" + silverstripe_db_dump|basename }}' when: silverstripe_db_dump is defined - name: import assets unarchive: > src='{{ silverstripe_assets_dump }}' dest='{{ silverstripe_path_wwwroot + "/assets" }}' copy=yes owner='{{ silverstripe_user }}' group='{{ silverstripe_webserver_user }}' when: silverstripe_assets_dump is defined takes e.g. a .tgz and unpacks it in assets Jinja2 filter to get the filename -
Import Data #2 • Note to myself: SSPak is made
for this https://github.com/silverstripe/sspak • But copy, mysql and unarchive modules are good examples -
Setup other stuff • You can define whatever you need
for your app, e.g. – cache settings (memcached) – cron tasks – … -
- name: setup cron tasks to rebuild the site every
night cron: > name='{{ "rebuild " + silverstripe_project + ", locale " + item.locale }}' job='{{ silverstripe_sake + " dev/tasks/RebuildStaticCacheTask locale=" + item.locale }}' hour='1' minute='{{ item.minute }}' user='{{ silverstripe_user }}' state=present with_items: - { locale: 'de_DE', minute: '22'} - { locale: 'en_US', minute: '24'} could also be a predefined list -
Run the playbook debops silverstripe-demo.yml -e silverstripe_db_dump=/path/to/demo.sql -e silverstripe_assets_dump=/path/to/assets.tgz define
a variable on the command line name of the playbook -
Is there a role for it? • Silverstripe deploy role
is in development • Capistrano like deploy with releases: f500 project_deploy https://galaxy.ansible.com/list#/roles/732