FULL-STACK CAKEPHP
   DEPLOYMENT


                Pay attention to this corner
NOT MARKSTORY
SPONSORED BY
~WHOAMI

• Jose   Diaz-Gonzalez

• Resident   IRC Troll (savant)

• Rants   at http://josediazgonzalez.com




                                              ➘
• Harasses   as @savant
                                            me
• Codes    as josegonzalez on github

• EMPLOYED      at @seatgeek
                                           not me
                                                       ➘
                                                    I’m also hot like sriracha sauce
WHO IS THIS TALK FOR?


• Devs/Sysadmins   not afraid of Ruby

• Developers   who don’t have time to waste with sysops

• Sysadmins   who are looking to automate more of their
 workflow


                                          Also anyone who couldn’t get into Mark’s talk
WHY AM I SPEAKING ABOUT
           THIS?


• I’m   no Sysadmin; Sysadmining on half of the projects I’m on

• Devs    do servers wrong; Perhaps I do too

• PHPNut     Parole Policy (PPP)



                                                   My Crime: The Patriot Ale House
WHAT THE HELL IS THIS


• Being   lazy

• Deploying      a SERVAR

• CHARGING         LAYSHURS

• What    about the app?


                              ¡¡¡SHOOP DA WOOP!!!
IN THE BEGINNING



             There was PHPNut, and all was good
#
Every
policy
must
have
a
bundlesequence      •    Geared towards automated
body
common
control                                 deployments of workstations, not
{                                                   servers
bundlesequence

=>
{
"test"
};
inputs
=>
{
"cfengine_stdlib.cf"
};            •    Convergence implies we may never
}                                                   be within compliance
bundle
agent
test
{                                              •    Community maintained packages?
files:

#
This
is
a
throw‐away
comment,
below
is
a
full‐bodied
promise

"/tmp/testfile"





















#
promiser



comment
=>
"This
is
for
keeps...",
#
Live
comment




create
=>
"true",
















#
Constraint
1





perms
=>
m("612");














#
Constraint
2,
rw‐‐‐x‐
w‐
}
                                                   I love it when an automation tool makes a promise
THINGS WERE COMPLICATE



                    @drunkhulk
MODULES AND CLASSES
#
ntp‐class1.pp

class
ntp
{


case
$operatingsystem
{




centos,
redhat:
{







$service_name
=
'ntpd'






$conf_file



=
'ntp.conf.el'




}




debian,
ubuntu:
{







$service_name
=
'ntp'






$conf_file



=
'ntp.conf.debian'




}


}





package
{
'ntp':




ensure
=>
installed,


}





service
{
'ntp':




name





=>
$service_name,




ensure



=>
running,




enable



=>
true,




subscribe
=>
File['ntp.conf'],


}





file
{
'ntp.conf':




path



=>
'/etc/ntp.conf',




ensure

=>
file,                                         http://forge.puppetlabs.com/




require
=>
Package['ntp'],




source

=>
"/root/learning‐manifests/${conf_file}",


}
}




                                                          Free beer to the first person to raise their hand
WE CAN DO BETTER



           If we couldn’t, this would be the end of my talk
now we’re cooking!
WHY CHEF?

• Uses a Ruby DSL; Doesn’t   • All
                                 the cool rails developers
 re-invent the wheel          are using it

• Officially-sanctioned       • Awesome     logo
 Cookbooks
                             • Screams   when things are
• Community-supported         broken
 Cookbooks
                             • Extensive   Documentation

                                            And the obvious Chef/CakePHP pun
HOW IS DEPLOYMENT FORMED?


• Each   server can have one or more cookbooks

• Cookbooks are like plugins (nginx, apache, memcache) that
 can depend upon/require one another

• Cookbooks     have recipes, libraries, templates, definitions, files

• Recipes   are sets of instructions

                                                   I vote we rename “plugins” to “recipes”
WHAT’S IN A RESOURCE CALL?

resource       special node var                name of resource
   ➘
           ➘




                                                     ➘
    git
"#{node[:server][:production][:dir]}/#{hostname}/#{base}/public"
do
    

repository
info[:repository]
    

user
"deploy"
    

group
"deploy"
    end              ➘
                      options

                                                     http://wiki.opscode.com/display/chef/Resources
ROLL YOUR OWN
  RESOURCES?


         Yo dawg, I hurd u liek yo yos so I gave yo dawg
         a yo yo so yo dawg can yo yo while yo dawg yo
                         yos yo dawg yo
Resources on the Cheap
#
Definition
define
:nginx_up,
:enable
=>
true
do


template
params[:name]
do




source
"html.erb"




owner
"deploy"                        ➘
                                                          Just chain resources




group
"deploy"




mode
0644




variables(params[:variables])


end


nginx_site
params[:hostname]
do




action
:enable
                                                                     Fire at will


end




                                                          ➘
end

#
Usage
nginx_up
"#{node[:nginx][:dir]}/sites‐available/#{hostname}.#{base}"
do


hostname
"#{info[:hostname]}.#{info[:base]}"


variables(info[:variables])
end


                                 “Fake” resources, for more info see http://wiki.opscode.com/display/chef/Providers
ALL TOGETHER NOW
node[:static_applications].each
do
|hostname,
sites|


sites.each
do
|base,
info|




directory
"#{node[:server][:production][:dir]}/#{hostname}/#{base}"
do








owner
"deploy"








group
"deploy"








mode
"0755"








recursive
true




end





git
"#{node[:server][:production][:dir]}/#{hostname}/#{base}/public"
do






repository
info[:repository]






user
"deploy"






group
"deploy"




end





nginx_up
"#{node[:nginx][:dir]}/sites‐available/#{hostname}.#{base}"
do






hostname
"#{hostname}.#{base}"






variables(info[:variables])




end


end
end

                                                   Simplified version of something in production use
server
{



listen






80;


server_name

<%=
@subdomain
%><%=
@hostname
%>
www.<%=
@subdomain
%><%=
@hostname
%>;


root








<%=
@root
%>;


index







index.html
index.htm;


error_page


500
501
502
503
504

/error_500.html;


charset





utf‐8;



access_log


<%=
@node[:nginx][:log_dir]
%>/<%=
@subdomain
%><%=
@hostname
%>‐access.log;


error_log



<%=
@node[:nginx][:log_dir]
%>/<%=
@subdomain
%><%=
@hostname
%>‐error.log;



#
remove
www
from
the
url


if
($host
~*
www.(.*))
{




set
$host_without_www
$1;




rewrite
^(.*)$
http://$host_without_www$1
permanent;


}

}




                     ^ FROM THIS ^
                                                                                          here it comes...
server
{



listen






80;


server_name

areyousmokingcrack.com
www.areyousmokingcrack.com;


root








/apps/production/areyousmokingcrack.com/default;


index







index.html
index.htm;


error_page


500
501
502
503
504

/error_500.html;


charset





utf‐8;



access_log


/var/log/nginx/areyousmokingcrack.com‐access.log;


error_log



/var/log/nginx/areyousmokingcrack.com‐error.log;



#
remove
www
from
the
url


if
($host
~*
www.(.*))
{




set
$host_without_www
$1;




rewrite
^(.*)$
http://$host_without_www$1
permanent;


}

}




                 ^ TO THIS ^
                                                                    this site actually exists
DEMO



       stop using the internet please
SERVER DNA


• An   instance is defined as a JSON DNA file

• dna.json   reference both recipes and configurations

• Modifying   DNA should reconfigure server

• DNA    can be versioned with the app


                                                    You too can be a Geneticist
BACK TO CAKE?

• Defineone set of              • Automateserver
 cookbooks, use everywhere      deployment:

• Share, collaborate, grow      • server      new 127.0.0.1 lb.json
 optimized server cookbooks
                               • CakePHP        http://bit.ly/cakechef
• Define servers in terms of
 DNA files: lb.json, db.json,
 web.json, etc.

                                 Contributions welcome, documentation being fleshed out
DEMO



       you can start using the internet now
WHAT ABOUT THE APP?


      what about it?




                       INCEPTION
BASH


• Usable   everywhere

• Easy   to read/write

• Everything   is custom; Don’t be your own giant



                                               Have fun handling multiple server types
FREDISTRANO


    NO




         Never use something just because it’s written in CakePHP
PHING


 NO




        Yo dawg, I hurd u liek XML
ANT


I’ll cut you




    So I put some RDFA in your XML so you can SPARQL while you parse
23 DEPLOYMENT TOOLS
        LATER


         It’s like deployment tools are project management software, sheesh
CAPISTRANO

• MOAR      Ruby                 • Easy
                                      to extend and
                                  manipulate
• Similar
        in concept to Chef -
 has deployment strategies       • Docs
                                      are a bit hazy at the
                                  moment
• Separates related tasks into
 namespaces (deploy,             • Geared   towards SCM users
 migration, etc.)



                                                    http://capistranorb.com
INSTALL


• Install   Ruby/RubyGems

• gem   install capistrano

• cd   path/to/local/app/repository

• capify    .


                                       the other 8 steps of the process involve alcohol
CAPIFY?


• “capify   .” creates a Capfile and a config/deploy.rb file

• deploy.rbis by convention; we can move the contents to the
 Capfile if it bothers you

• Capfile    is necessary and proper; loads capistrano plugins
deploy.rb
                 milliondollarapp.com

                        ➘                                        <3 Perforce




                                                              ➘
set
:application,
"set
your
application
name
here"
set
:repository,

"set
your
repository
location
here"

set
:scm,
:subversion
#
Or:
`accurev`,
`bzr`,
`cvs`,
`darcs`,
`git`,
`mercurial`,
`perforce`,
`subversion`
or
`none`

role
:web,
“your
web‐server
here”

























#
Your
HTTP
server,
Apache/etc
role
:app,
“your
app‐server
here”

























#
This
may
be
the
same
as
your
`Web`
server
role
:db,

“your
primary
db‐server
here”,
:primary
=>
true
#
This
is
where
Rails
migrations
will
run
role
:db,

“your
slave
db‐server
here”




                                                                        ➘
                      ➘
                                                             CakePHP is cool too
  Cause we’re all on failover servers, right?
CUSTOMIZABLE


• Set   your own SCM, deploy paths, even callbacks

• Define    custom namespaces and tasks

• Override   core functionality
ENVIRONMENT HANDLING

##
Available
Environments
task
:production
do


server













$config[“servers”][“prod”][“server”],
:web,
:god


set
:application,


$config[“servers”][“prod”][“application”]


set
:deploy_to,




$config[“servers”][“prod”][“deploy_to”]


set
:branch,







:master
end

task
:staging
do


role
:web,









$config[“servers”][“dev”][“server”]


set
:application,


$config[“servers”][“dev”][“application”]


set
:deploy_to,




$config[“servers”][“dev”][“deploy_to”]


set
:branch,







ENV[‘branch’]
if
ENV.has_key?(‘branch’)
&&
ENV[‘branch’]
=~
/[w_‐]+/i
end
CUSTOM TASKS
##
Tasks
involving
assets
namespace
:asset
do


desc
"Clears
assets"


task
:clear
do




run
"cd
#{app_dir}
&&
../cake/console/cake
‐app
#{app_dir}
asset_compress
clear"


end



desc
"Builds
all
assets"


task
:build
do




run
"cd
#{app_dir}
&&
../cake/console/cake
‐app
#{app_dir}
asset_compress
build"


end



desc
"Builds
ini
assets"


task
:build_ini
do




run
"cd
#{app_dir}
&&
../cake/console/cake
‐app
#{app_dir}
asset_compress
build_ini"


end



desc
"Rebuilds
assets"


task
:rebuild
do




run
"cd
#{app_dir}
&&
../cake/console/cake
‐app
#{app_dir}
asset_compress
clear"




run
"cd
#{app_dir}
&&
../cake/console/cake
‐app
#{app_dir}
asset_compress
build"


end
end
CAP PROD ASSET:REBUILD
CAVEATS

• Path   to Cake Core may be incorrect - use -app flag

• Takes   some initial setup

• Behaves   funky with multiple concurrent deploys

• Potentially   slow with large deploys

• Will
     murder your datacenter if deploying to hundreds of
 servers
CLAP



       Props to Michael D’Auria, Sysadmin extraordinaire
LINKS

• CFEngine:

• Puppet: http://puppetlabs.com

• Chef: http://opscode.com/chef

• CakePHP     Chef Cookbooks: http://bit.ly/cakechef

• Capistrano: http://capistranorb.com

Full-Stack CakePHP Deployment