SlideShare a Scribd company logo
1 of 114
Download to read offline
LOYM ENT
DEP   ICS
  TACT
   Managing code from
development to production
Ian Barber - ian.barber@gmail.com
twitter.com/ianbarber | phpir.com
Image: http://flickr.com/photos/denisdervisevic/4527695803
- Table of Contents -

1.... Change Control
2.... Environments
3.... Version Control
4.... The Deploy Process
5.... Scripts
6.... Continuous Integration
7.... Remote Releases
8.... Packaged Releases
9.... Package Management
10.. Managing Hotfixes
11.. Managing Database Changes
12.. Rollbacks
13.. Tactical Deployment
Change control
            plan    execute
           change   change



identify
                              verify
  need



           close    deliver
export   copy to
           code    server



require                  compare
release                    md5



          report   restart
           back    apache
Change Request Form

Requested By: J. Teamlead Authorised By: S. Manager
Submit Date: 2011-01-27 Change Date: 2011-02-04

Reason For Change:
Resolve JIRA-1602 - Listen for new .com variants on vhost
Change Request:
Release tag 1.1.3 via normal process
mv /etc/httpd/conf.d/fooweb.conf /etc/httpd/conf.d/fooweb.old
mv ~releases/1.1.3/conf/fooweb.conf /etc/httpd/conf.d/
fooweb.conf
Verification:
http://foweb.com shows the same page as http://fooweb.com
Rollback:
Re-release 1.1.2
mv /etc/httpd/conf.d/fooweb.old /etc/httpd/conf.d/fooweb.conf
Environments


 Production    Development



static              verbose
robust             dynamic
reliable           unstable
optimised      experimental
on Envir onment
The Producti

    Image: http://flickr.com/photos/lejoe/3763218501
The Staging Environment




Image: http://flickr.com/photos/simononly/4454401446
n Enviro nment
    The Int egratio

Image: http://flickr.com/photos/unfoldedorigami/2374016430
The Developme
             nt Environmen
                                      t
     Image: http://flickr.com/photos/drewnew/511936681
VERSION CONTROL




   Image: http://flickr.com/photos/robbie73/4346732208
/branches/newpage             /branches/...

         /branches/search




/trunk




                             /branches/1.1.2    /tags/1.1.2
Development

         /branches/newpage            /branches/...

         /branches/search




/trunk


Integration

                             /branches/1.1.2   /tags/1.1.2


            Staging                                   Production
master


                           release1.1.1




devel



         search feature

            long feature
Production
master


                             release1.1.1

Staging

devel



          search feature                    Integration

             long feature


                            Development
The DEPLoy PROCESS
The DEPLoy PROCESS

transparent   flexible     easy




 scalable     graceful   reliable
support       SMTP
          process       config
                                   apache
                                    vhost
 app
update

             code     config


                                  file perms
          packages   commands
libpng
update



          cache         restart
         service        service
code               config        package
repository          repository    repository


               ta
             da



server              commands     deployment
 server
  server                          controller
code        config             package
repository   repository         repository




                          da
                          ta
server       commands          deployment
 server        + data           controller
  server
BUILD SCRIPTS

#!/bin/bash
# Deployment script for FooWeb Project
git archive --format=tar 
  --remote=git://repo.com/myrepo/myrepo.git 
  HEAD -o fooweb.tar
tar -xf fooweb.tar /var/www
service httpd restart
#!/bin/bash
# Deployment script for FooWeb Project
svn export svn://localhost/fooweb-service/
trunk release
cd release && mkdir build
cp -r web/* build/
javac -cp /usr/share/java/servlet-api-2.5.jar
      -d build/WEB-INF/classes
      src/com/fooweb/service/*.java
cd build && jar cvf ../fooweb.war * && cd ../
# assumes autoDeploy is true
cp fooweb.war /var/lib/tomcat6/webapps
BUILDS TOOLS

       tests               release



code               build         docs


                             test
   assets                  results
build
tools
<?xml version="1.0" encoding="UTF-8"?>
<project name="FooWeb">
<property name="install" location="/var/lib/
tomcat6/webapps" />
<property name="svn.repo" value="svn://
localhost/fooweb-service/trunk" />

<!--A "clean" target to delete compiled
files-->
<target name="clean">
    <delete dir="build" />
    <delete dir="release" />
    <delete file="fooweb.war" />
</target>
<!-- Checkout, mkdir and compile-->
<target name="build">
    <exec executable="svn">
        <arg line="export ${svn.repo}
release" />
    </exec>
    <mkdir dir="build"/>
    <copy todir="build">
        <fileset dir="release/web" />
    </copy>
    <javac srcdir="release/src"
destdir="build/WEB-INF/classes/">
        <classpath>
              <pathelement path="/usr/share/
java/servlet-api-2.5.jar"/>
        </classpath>
    </javac>
</target>
<!-- Build our WAR file -->
<target name="war" depends="build">
    <war destfile="fooweb.war" webxml="build/
WEB-INF/web.xml">
        <fileset dir="build"/>
        <classes dir="build/WEB-INF/classes"/>
    </war>
</target>

<!-- Copy our file -->
<target name="deploy" depends="war">
    <copy file="fooweb.war" todir="$
{install}" />
</target>

</project>
$ sudo ant deploy
Buildfile: build.xml
build:
      [exec] Exported revision 8.
     [mkdir] Created dir: /tmp/build
      [copy] Copying 2 files to /tmp/build
      [copy] Copied 3 empty directories to 1 empty
               directory under /tmp/build
     [javac] Compiling 1 source file to
               /tmp/build/WEB-INF/classes
war:
       [war] Building war: /tmp/fooweb.war
deploy:
      [copy] Copying 1 file to /var/lib/tomcat6/
webapps

BUILD SUCCESSFUL Total time: 2 seconds
CONTINUOUS
               INTEGRATION
       Look at the
    Hud  son Wiki at
               dson-ci.org
http://wiki.hu
Deployment Tactics
Deployment Tactics
Deployment Tactics
Deployment Tactics
Deployment Tactics
<project name="Fooweb" default="build">
  <target name="build" depends="phpunit" />

  <target name="init">
    <mkdir dir="${basedir}/build/logs" />
  </target>

  <target name="phpunit" depends="init">
   <exec executable="phpunit"
      dir="${basedir}/tests" failonerror="on">
     <arg line=" --log-junit '${basedir}/
build/logs/phpunit.xml' --coverage-clover '$
{basedir}/build/logs/clover.xml' --coverage-
html '${basedir}/build/logs/coverage'" />
   </exec>
  </target>
<target name="phpcpd" depends="init">
   <exec executable="phpcpd"
         dir="${basedir}/application"
         failonerror="on">
    <arg line=" --log-pmd
     '${basedir}/build/logs/php-cpd.xml' ." />
   </exec>
  </target>
</project>
Deployment Tactics
Deployment Tactics
REMOTE RELEASES




    Image: http://flickr.com/photos/scragz/309353618
server                            server
   authorized_keys                  authorized_keys




                                   cp
                ss




                               /s
                  h
                     /s




                              h
                             ss
                      cp

                     deployment
                      controller

                      id_rsa.pub
user “deploy”                           ssh-keygen -t rsa
Fabric
from fabric.api import *        http://fabfile
                                              .org
# Development environment
def dev():
  env.user = 'deployer'
  env.roledefs = {
    "web" : ['localhost'],
    "db" : ['localhost'],
  }

# Production environment
def production():
  env.user = 'deployer'
  env.roledefs = {
    "web" : ['primary.fooweb.com',
             'secondary.fooweb.com'],
    "db" : ['backend.fooweb.com'],
  }
# Package up release - run local
def prepare_deploy():
  local('svn export svn://localhost/fooweb/
trunk release')
  with cd('release'):
    local('tar cvzf ../fooweb.tar.gz .')
    local('rm -rf release')

# Restart web server
@roles('web')
def restart_webserver():
  sudo('/etc/init.d/apache2 restart')
# Deploy to remote servers
@roles('web')
def deploy():
  prepare_deploy()
  # in case of already existing
  with settings(warn_only=True):
    run('mkdir /tmp/release')
  run('rm -rf /tmp/release/*')
  put("fooweb.tar.gz", '/tmp/release')
  with cd('/tmp/release'):
    run("tar xvzf fooweb.tar.gz")
    run("rm -rf fooweb.tar.gz")
    run("mv * /tmp/test")
  restart_webserver();
  local("rm -rf fooweb.tar.gz");
$ fab dev deploy

[localhost] run: svn export svn://localhost/
fooweb/trunk release
[localhost] run: tar cvzf ../fooweb.tar.gz .
[localhost] run: rm -rf release
[localhost] run: mkdir /tmp/release
[localhost] err: mkdir: cannot create
directory `/tmp/release': File exists

Warning: run() encountered an error (return
code 1) while executing 'mkdir /tmp/release'

[localhost] run: rm -rf /tmp/release/*
[localhost] put: fooweb.tar.gz -> /tmp/
release/fooweb.tar.gz
[localhost] run: tar xvzf fooweb.tar.gz
[localhost] run: rm -rf fooweb.tar.gz
[localhost] run: mv * /tmp/test
[localhost] sudo: /etc/init.d/apache2 restart
Password for ianbarber@localhost:
[localhost] out: * Restarting web server
apache2
[localhost] out: ... waiting      ...done.
[localhost] run: rm -rf fooweb.tar.gz

Done.
Disconnecting from localhost... done.
$ fab production deploy
[localhost] run: tar cvzf ../fooweb.tar.gz .
....
[primary.fooweb.com] run: rm -rf /tmp/release/
[localhost] run: tar cvzf ../fooweb.tar.gz .
....
[secondary.fooweb.com] run: mkdir /tmp/release
....
Disconnecting from secondary.fooweb.com...done
Disconnecting from primary.fooweb.com... done
$ mkdir config && cd config && capify .
[add] writing './Capfile'
[add] making directory './config'
[add] writing './config/deploy.rb'
[done] capified!


set :application, "set your application name "
set :repository, "set your repository"
set :scm, :subversion
role :web, "your web-server here"
role :app, "your app-server here"
role :db, "your primary db-server
here", :primary => true
                                   Capi  strano
role :db, "slave db"                          .com/
                              https:/ /github
                               capis trano/
set :application, "fooweb"
set :repository,"svn://localhost/fooweb/trunk"

set   :scm, :subversion
set   :scm_username, "deployment"
set   :scm_password, "s3kkr3tp4a55"
set   :scm_checkout, "export"
set   :keep_releases, 4
set   :normalize_asset_timestamps, false
set   :deploy_to, "/usr/local/#{application}"

role :web, "primary.fooweb.com"
role :web, "secondary.fooweb.com"
role :db, "backend.fooweb.com"
namespace :deploy do
  task :migrate do
    # nothing
  end

  task :restart do
    sudo "/etc/init.d/apache2 restart"
  end
end

namespace :fooweb do
  task :perms do
    sudo "chmod -R a+w #{deploy_to}"
  end
end

after "deploy:setup", "fooweb:perms"
$ cap deploy:setup
 * executing `deploy:setup'
 * executing
        "sudo mkdir -p /usr/local/fooweb [...]"
  servers: ["primary","secondary", "backend"]
    [backend] executing command [...]
    command finished
  triggering after callbacks for deploy:setup
 * executing `fooweb:perms'
 * executing "sudo chmod -R a+w /usr/local/
fooweb"
  servers: ["primary","secondary","backend"]
    [primary] executing command [...]
    command finished
$ cap deploy
  * executing `deploy'
  * executing `deploy:update'
 ** transaction: start
  * executing `deploy:update_code'
    executing locally: "svn info svn://
localhost/fooweb/trunk -rHEAD"
/usr/bin/svn
  * executing "svn checkout -q -r17 svn://
localhost/fooweb/trunk /usr/local/fooweb/
releases/20110116192456 && (echo 17 > /usr/
local/fooweb/releases/20110116192456/
REVISION)"
    servers: ["primary.fooweb.com"]
    [primary.fooweb.com] executing command
[....]
  * executing `deploy:finalize_update'
  * executing "chmod -R g+w /usr/local/fooweb/
/usr/local/fooweb/
!"" current -> releases/20110116192316
!"" releases
#   !"" 20110116190608
#   #   !"" application
#   #   !"" log -> /usr/local/fooweb/shared/log
#   #   !"" public
#   #   !"" REVISION
#   #   !"" tmp
#   !"" 20110116192316
#   #   !"" application
#   #   !"" log -> /usr/local/fooweb/shared/log
#   #   !"" public
#   #   !"" REVISION
#   #   !"" tmp
$"" shared
Webistrano
https://g ithub.com/
perito r/webistrano
Deployment Tactics
Deployment Tactics
Deployment Tactics
Deployment Tactics
Deployment Tactics
Deployment Tactics
Deployment Tactics
Deployment Tactics
Deployment Tactics
PACKAGED
  RELEASES




Image: http://flickr.com/photos/halfbisqued/2353845688
Fooweb


    Fooweb                      Fooweb
     Mail                       Service



Any SMTP
                 Symfony 1.3     Tomcat 6.0
 Server



           PHP 5.2.12          Java 1.6
!""   application
#     !"" controllers
#     #   $"" home.php
#     $"" library
#         $"" Foow
#             $"" Router.php
!""   fooweb.spec
!""   public
#     $"" index.php
$""   vhosts
      $"" fooweb.conf
Summary: Fooweb Application
Vendor: Fooweb
Name: fooweb
Version: 1.0
Release: 1
Source0: fooweb-%{version}.tar.gz
License: BSD
Group: Fooweb
BuildArch: noarch
BuildRoot: %{_tmppath}/%{name}-%{version}-
buildroot
Requires: php
%description
This is the Fooweb web application

%prep
%setup
%install
mkdir -p $RPM_BUILD_ROOT/var/www/fooweb
mkdir -p $RPM_BUILD_ROOT/etc/httpd/conf.d/
cp -r application $RPM_BUILD_ROOT/var/www/fooweb
cp -r public $RPM_BUILD_ROOT/var/www/fooweb
cp vhosts/fooweb.conf $RPM_BUILD_ROOT/etc/httpd/
conf.d/

%clean
rm -rf $RPM_BUILD_ROOT

%files
%dir /var/www
%dir /var/www/fooweb
%config /etc/httpd/conf.d/fooweb.conf
/var/www/fooweb/*
~$ mkdir buildroot buildroot/tmp
~$ cat .rpmmacro
%packager Fooweb Release Manager
%_topdir ~/buildroot
%_tmppath ~/buildroot/tmp
~$ cd ~/tags
~/tags$ tar cvzf fooweb-1.0.tar.gz fooweb-1.0
~$ rpmbuild -ta fooweb-1.0.tar.gz
~$ rpm -qip ~/rpmbuild/RPMS/noarch/
fooweb-1.0-1.noarch.rpm
Name        : fooweb
Relocations: (not relocatable)
Version     : 1.0
Vendor: Fooweb
Release     : 1
Build Date: Thu 13 Jan 2011 12:26:24 AM PST
Install Date: (not installed)
Build Host: ubuntu.localdomain
Group       : Fooweb
Source RPM: fooweb-1.0-1.src.rpm
Size        : 781
License     : BSD
Signature   : (none)
Summary     : Fooweb Application
Description : This is the Fooweb web application
$ mkdir /var/www/repo
$ cd /var/www/repo
$ mkdir centox/5/fooweb/
{SRPMS,X86_64,i386,noarch}
$ cp ~rpmbuild/RPMS/noarch/* centos/5/fooweb/
noarch
$ cp ~rpmbuild/SRPMS/* centos/5/fooweb/SRPMS
$ createrepo -v centos/5/fooweb/noarch/

centos/5/fooweb/noarch/
!"" fooweb-1.0-1.noarch.rpm
$"" repodata
    !"" filelists.xml.gz
    !"" other.xml.gz
    !"" primary.xml.gz
    $"" repomd.xml
$ cat /etc/yum.repos.d/fooweb.repo
[fooweb_noarch]
name = Fooweb Private Repository
baseurl = http://fooweb.com/repo/centos/5/fooweb/
noarch
enabled = 1
gpgcheck = 0
gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-
fooweb

$ yum update
fooweb_noarch             100% |========|   951 B
fooweb_noarch/primary     100% |========|   701 B
fooweb_noarch
1/1
Setting up Update Process
No Packages marked for Update
$ yum info fooweb
Available Packages
Name       : fooweb
Arch       : noarch
Version    : 1.0
Release    : 1
Size       : 3.3 k
Repo       : fooweb_noarch
Summary    : Fooweb Application
License    : BSD
Description: This is the Fooweb web application
Deployment Tactics
<target name="buildrpm" depends="init">
 <tar destfile="build/rpm/SOURCES/
fooweb.tar.gz" compression="gzip">
  <tarfileset dir="${basedir}"
prefix="fooweb-1.0">
   <include name="*/**" />
   <exclude name="build/**" />
  </tarfileset>
 </tar>
 <copy file="${basedir}/fooweb.spec" tofile="$
{basedir}/build/rpm/SPECS/fooweb.spec" />
 <rpm command="-ba" specFile="fooweb.spec"
topDir="${basedir}/build/rpm"
cleanBuildDir="true" failOnError="true" />
</target>
PACKAGE
     MANAGEMENT




Image: http://flickr.com/photos/southerncalifornian/2129676744
$ sudo aptitude install puppetmaster
0 packages upgraded, 10 newly installed, 0 to
remove and 76 not upgraded.
Need to get 3,233kB of archives. After unpacking
13.7MB will be used.

                                        Puppet
                                http://puppetlabs.com
$ sudo aptitude install puppet
0 packages upgraded, 5 newly installed, 0 to
remove and 76 not upgraded.
Need to get 587kB of archives. After unpacking
1,892kB will be used.
backend
                       fooweb.com
       primary
     fooweb.com

                                     seconday
                                    fooweb.com

    int
fooweb.com
                                      staging
                                    fooweb.com
                  Puppet
                  master
/etc/puppet
!"" auth.conf
!"" fileserver.conf
!"" manifests
#   $"" site.pp
!"" modules
#   !"" apache2
#   #   $"" manifests
#   #       $"" init.pp
#   $"" fooweb
#       !"" files
#       #   $"" fooweb.conf
#       $"" manifests
#           $"" init.pp
!"" puppet.conf
$"" templates
class fooweb {
  package { "fooweb":
    ensure => latest,
  }
"
  file { "/etc/apache2/sites-enabled/fooweb.conf":
    owner => root,
    group => root,
    mode => 0444,
    source =>
        "puppet:///files/fooweb/files/fooweb.conf",
    notify => Service["apache2"]
  }
}
                              mod ules/fooweb
                              manif ests/init.pp
node "ubuntu.localdomain" {   manifests/site.pp
 include fooweb
 include apache2
}




class apache2 {
 service { apache2:
   ensure => running
 }
                              modules/apache2
                              manifests/init.pp
# puppet agent -o -v --no-daemonize
info: Caching catalog for ubuntu.localdomain
info: Applying configuration version '1295514488'
notice: /Stage[main]/Fooweb/Package[fooweb]/
ensure: ensure changed 'purged' to 'latest'
notice: /Stage[main]/Fooweb/File[/etc/apache2/
sites-enabled/fooweb.conf]/ensure: defined
content as '{md5}
d41d8cd98f00b204e9800998ecf8427e'
info: /Stage[main]/Fooweb/File[/etc/apache2/
sites-enabled/fooweb.conf]: Scheduling refresh of
Service[apache2]
notice: /Stage[main]/Apache2/Service[apache2]:
Triggered 'refresh' from 1 events
notice: Finished catalog run in 3.33 seconds
# ls /etc/httpd/conf.d/fooweb.conf
/etc/httpd/conf.d/fooweb.conf
# ls /var/www/fooweb/
application public
MANAGING HOTFIXES




     Image: http://flickr.com/photos/moogan/8206134
/branches/1.1.3




    /trunk


/tags/1.1.2                 /tags/1.1.3
package


          copy code


                      run db
                      backup

                                run db
                               changes

                                         make code
                                          active
package


          copy code


                      run db
                      backup

                                run db
                               changes

                                         make code
                                          active
MANAGING Database
    ChanGES




  Image: http://flickr.com/photos/theplanetdotcom/4878814847
Deployment Tactics
CREATE TABLE `blogpost` (
 `id` int(11) auto_increment NOT NULL PRIMARY
KEY,
 `title` VARCHAR(255),
 `timestamp` DATETIME,
 `content` TEXT
);

--//@UNDO
                                   DBDeploy
                               tp://dbdeploy.com
DROP TABLE `blogpost`;
                            ht
ALTER TABLE `blogpost`
       ADD `author` varchar(255) NULL;

--//@UNDO

ALTER TABLE `blogpost` DROP `author`;
$ wget http://dbdeploy.googlecode.com/files/
dbdeploy-dist-3.0M2-distribution.zip

CREATE TABLE changelog (
   change_number BIGINT NOT NULL,
   delta_set VARCHAR(10) NOT NULL,
   start_dt TIMESTAMP NOT NULL,
   complete_dt TIMESTAMP NULL,
   applied_by VARCHAR(100) NOT NULL,
   description VARCHAR(500) NOT NULL,
   PRIMARY KEY(change_number, delta_set)
);
$ java -cp mysql-connector-java.jar:dbdeploy-
cli-3.0M2.jar com.dbdeploy.CommandLineTarget -
D com.mysql.jdbc.Driver -d mysql -o delta.sql
-u jdbc:mysql://localhost/foowebdb -U root -P
******
dbdeploy 3.0M2
Reading change scripts from directory
dbdeploy.
Changes currently applied to database:
  (none)
Scripts available:
  1, 2
To be applied:
  1, 2
-- START CHANGE SCRIPT #1: 1-create-blogposts.sql

CREATE TABLE `blogpost` (
 `id` int(11) auto_increment NOT NULL PRIMARY
KEY,
 `title` VARCHAR(255),
 `timestamp` DATETIME,
 `content` TEXT
);

INSERT INTO changelog (change_number,
complete_dt, applied_by, description)
VALUES
(1, CURRENT_TIMESTAMP, USER(), '1-create-
blogposts.sql');

COMMIT;
-- END CHANGE SCRIPT #1: 1-create-blogposts.sql

-- START CHANGE SCRIPT #2: 2-add-author.sql

ALTER TABLE `blogpost` ADD `author` varchar(255)
NULL;


INSERT INTO changelog (change_number,
complete_dt, applied_by, description)
 VALUES (2, CURRENT_TIMESTAMP, USER(), '2-add-
author.sql');

COMMIT;

-- END CHANGE SCRIPT #2: 2-add-author.sql
<?xml version="1.0" encoding="UTF-8"
standalone="no"?>
<databaseChangeLog [....]>
 <changeSet author="ianbarber" id="1">
  <createTable tableName="blogposts">
   <column autoIncrement="true" name="id"
type="int(11)">
    <constraints nullable="false"
primaryKey="true" />
   </column>
   <column name="title" type="varchar(255)" />
   <column name="body" type="text" />
   <column name="author" type="varchar(255)"/>
   <column name="date" type="timestamp" />
  </createTable>
 </changeSet>                      Liquibase
                              ht tp://liquibase.org
<?xml version="1.0" encoding="UTF-8"
standalone="no"?>
<databaseChangeLog [....] >
  <include file="v000/master.xml" />
</databaseChangeLog>
                                    update.xml


<?xml version="1.0" encoding="UTF-8"
standalone="no"?>
<databaseChangeLog [....]>
  <include file="v000/create-blog-
posts-1.xml" />
</databaseChangeLog>
                                 v000/master.xml
$ wget http://downloads.sourceforge.net/
project/liquibase/Liquibase%20Core/2.0.0/
liquibase-2.0.0-bin.zip

# Liquibase properties
driver: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost/fooweb
classpath: /usr/share/java/mysql-connector-
java.jar
username: root
password: *******                          roperties
                               liquibase.p
$ liquibase --changeLogFile=update.xml update
Liquibase Home: /opt/liquibase
INFO 1/18/11 1:32 PM:liquibase: Successfully
acquired change log lock
INFO 1/18/11 1:32 PM:liquibase: Reading from
`DATABASECHANGELOG`
INFO 1/18/11 1:32 PM:liquibase: Reading from
`DATABASECHANGELOG`
INFO 1/18/11 1:32 PM:liquibase: ChangeSet
v000/create-blog-posts-1.xml::1::ianbarber ran
successfully in 101ms
INFO 1/18/11 1:32 PM:liquibase: Successfully
released change log lock
Liquibase Update Successful
class CreateProjects < ActiveRecord::Migration
  def self.up
    create_table :projects do |t|
      t.column :name, :string
      t.column :description, :text
      t.column :template, :string
      t.column :created_at, :datetime
      t.column :updated_at, :datetime
    end
  end

  def self.down
    drop_table :projects
  end
end
ROLLING BACK




  Image: http://flickr.com/photos/roolrool/4758613588
<?xml version="1.0" encoding="UTF-8"
standalone="no"?>
<databaseChangeLog [....]>
 <changeSet author="ianbarber" id="2">
  <addColumn tableName="blogposts">
   <column name="commenter" type="varchar
(255)" />
  </addColumn>
 </changeSet>
</databaseChangeLog>

$ liquibase --changeLogFile=update.xml update
Liquibase Home: /opt/liquibase
INFO 1/18/11 2:38 PM:liquibase: ChangeSet v000/
add_commenter-2.xml::2::ianbarber ran
successfully in 136ms
Liquibase Update Successful
$ liquibase --changeLogFile=update.xml
rollbackCount 1
Liquibase Home: /opt/liquibase
INFO 1/18/11 2:39 PM:liquibase: Successfully
acquired change log lock
INFO 1/18/11 2:39 PM:liquibase: Reading from
`DATABASECHANGELOG`
INFO 1/18/11 2:39 PM:liquibase: Rolling Back
Changeset:v000/add_commenter-2.xml::
2::ianbarber::(Checksum:
3:cc45ae1014b26f8b35cb70a5fc39a1ae)
INFO 1/18/11 2:39 PM:liquibase: Successfully
released change log lock
Liquibase Rollback Successful
Deployment Tactics
TACTICAL
DEPLOYMENTS




 Image: http://flickr.com/photos/romainguy/230416692
E.G. mk_
         Primary                 slave_de
                       http://bi          lay
            DB                  t.ly/hDW
                                         DFi


         Replication


read
                          read slave
slave



                         30 Minute
Backup
                           Delay
namespace :deploy do
 namespace :web do
  task :disable, :roles => :web do

  on_rollback {
  rm "#{shared_path}/system/maintenance.html"
  }

  require 'erb'
  deadline, reason = ENV['DATE'], ENV['WHY']
  maintenance = ERB.new(
    File.read("./templates/maintenance.erb"
    )).result(binding)

  put maintenance,
     "#{shared_path}/system/maintenance.html",
     :mode => 0644
 end
end
# DATE="16:00 MST" WHY="a database upgrade"
cap deploy:web:disable


if (-f $document_root/system/maintenance.html)
{
  rewrite ^(.*)$ /system/maintenance.html last;
  break;
}
warm                 redirect




caches &
           sessions    links
 proxies




           migrate
developers




          devops

  sys
                      QA
admins
See : Continuous
Deplo  yment In 5
Easy Steps
http://o reil.ly/13EPgd




                  Image: http://flickr.com/photos/jurvetson/3961794276
Feature F
                                        la  gs




Image: http://flickr.com/photos/rossharmes/4153769740
Gradual Ramp

          With Feature        Without Feature
100%



75%



50%



25%



 0%
       Day 1         Day 2    Day 3             Day 4
Dark Lau
        nches
THanks!
Deployment Tactics: Managing
  code from development to
          production
 Ian Barber - ian.barber@gmail.com
 twitter.com/ianbarber | phpir.com

More Related Content

What's hot

The How and Why of Windows containers
The How and Why of Windows containersThe How and Why of Windows containers
The How and Why of Windows containersBen Hall
 
Real World Experience of Running Docker in Development and Production
Real World Experience of Running Docker in Development and ProductionReal World Experience of Running Docker in Development and Production
Real World Experience of Running Docker in Development and ProductionBen Hall
 
A Hitchhiker's Guide to Cloud Native Java EE
A Hitchhiker's Guide to Cloud Native Java EEA Hitchhiker's Guide to Cloud Native Java EE
A Hitchhiker's Guide to Cloud Native Java EEMario-Leander Reimer
 
Drone CI/CD 自動化測試及部署
Drone CI/CD 自動化測試及部署Drone CI/CD 自動化測試及部署
Drone CI/CD 自動化測試及部署Bo-Yi Wu
 
Composer - Package Management for PHP. Silver Bullet?
Composer - Package Management for PHP. Silver Bullet?Composer - Package Management for PHP. Silver Bullet?
Composer - Package Management for PHP. Silver Bullet?Kirill Chebunin
 
Dependency management with Composer
Dependency management with ComposerDependency management with Composer
Dependency management with ComposerJason Grimes
 
Continuous delivery with docker
Continuous delivery with dockerContinuous delivery with docker
Continuous delivery with dockerJohan Janssen
 
Hyperledger composer
Hyperledger composerHyperledger composer
Hyperledger composerwonyong hwang
 
Docker in Production: Reality, Not Hype
Docker in Production: Reality, Not HypeDocker in Production: Reality, Not Hype
Docker in Production: Reality, Not Hypebridgetkromhout
 
파이썬 개발환경 구성하기의 끝판왕 - Docker Compose
파이썬 개발환경 구성하기의 끝판왕 - Docker Compose파이썬 개발환경 구성하기의 끝판왕 - Docker Compose
파이썬 개발환경 구성하기의 끝판왕 - Docker Composeraccoony
 
Deploying Symfony2 app with Ansible
Deploying Symfony2 app with AnsibleDeploying Symfony2 app with Ansible
Deploying Symfony2 app with AnsibleRoman Rodomansky
 
Vagrant move over, here is Docker
Vagrant move over, here is DockerVagrant move over, here is Docker
Vagrant move over, here is DockerNick Belhomme
 
PHP Dependency Management with Composer
PHP Dependency Management with ComposerPHP Dependency Management with Composer
PHP Dependency Management with ComposerAdam Englander
 
Dependency Management with Composer
Dependency Management with ComposerDependency Management with Composer
Dependency Management with ComposerJordi Boggiano
 
青云虚拟机部署私有Docker Registry
青云虚拟机部署私有Docker Registry青云虚拟机部署私有Docker Registry
青云虚拟机部署私有Docker RegistryZhichao Liang
 
PHP development with Docker
PHP development with DockerPHP development with Docker
PHP development with DockerYosh de Vos
 
Streamline your development environment with docker
Streamline your development environment with dockerStreamline your development environment with docker
Streamline your development environment with dockerGiacomo Bagnoli
 
手把手帶你學Docker 03042017
手把手帶你學Docker 03042017手把手帶你學Docker 03042017
手把手帶你學Docker 03042017Paul Chao
 

What's hot (20)

GO-CFを試してみる
GO-CFを試してみるGO-CFを試してみる
GO-CFを試してみる
 
The How and Why of Windows containers
The How and Why of Windows containersThe How and Why of Windows containers
The How and Why of Windows containers
 
Real World Experience of Running Docker in Development and Production
Real World Experience of Running Docker in Development and ProductionReal World Experience of Running Docker in Development and Production
Real World Experience of Running Docker in Development and Production
 
A Hitchhiker's Guide to Cloud Native Java EE
A Hitchhiker's Guide to Cloud Native Java EEA Hitchhiker's Guide to Cloud Native Java EE
A Hitchhiker's Guide to Cloud Native Java EE
 
Drone CI/CD 自動化測試及部署
Drone CI/CD 自動化測試及部署Drone CI/CD 自動化測試及部署
Drone CI/CD 自動化測試及部署
 
Composer - Package Management for PHP. Silver Bullet?
Composer - Package Management for PHP. Silver Bullet?Composer - Package Management for PHP. Silver Bullet?
Composer - Package Management for PHP. Silver Bullet?
 
Dependency management with Composer
Dependency management with ComposerDependency management with Composer
Dependency management with Composer
 
Continuous delivery with docker
Continuous delivery with dockerContinuous delivery with docker
Continuous delivery with docker
 
Hyperledger composer
Hyperledger composerHyperledger composer
Hyperledger composer
 
Docker in Production: Reality, Not Hype
Docker in Production: Reality, Not HypeDocker in Production: Reality, Not Hype
Docker in Production: Reality, Not Hype
 
파이썬 개발환경 구성하기의 끝판왕 - Docker Compose
파이썬 개발환경 구성하기의 끝판왕 - Docker Compose파이썬 개발환경 구성하기의 끝판왕 - Docker Compose
파이썬 개발환경 구성하기의 끝판왕 - Docker Compose
 
Deploying Symfony2 app with Ansible
Deploying Symfony2 app with AnsibleDeploying Symfony2 app with Ansible
Deploying Symfony2 app with Ansible
 
Native Hadoop with prebuilt spark
Native Hadoop with prebuilt sparkNative Hadoop with prebuilt spark
Native Hadoop with prebuilt spark
 
Vagrant move over, here is Docker
Vagrant move over, here is DockerVagrant move over, here is Docker
Vagrant move over, here is Docker
 
PHP Dependency Management with Composer
PHP Dependency Management with ComposerPHP Dependency Management with Composer
PHP Dependency Management with Composer
 
Dependency Management with Composer
Dependency Management with ComposerDependency Management with Composer
Dependency Management with Composer
 
青云虚拟机部署私有Docker Registry
青云虚拟机部署私有Docker Registry青云虚拟机部署私有Docker Registry
青云虚拟机部署私有Docker Registry
 
PHP development with Docker
PHP development with DockerPHP development with Docker
PHP development with Docker
 
Streamline your development environment with docker
Streamline your development environment with dockerStreamline your development environment with docker
Streamline your development environment with docker
 
手把手帶你學Docker 03042017
手把手帶你學Docker 03042017手把手帶你學Docker 03042017
手把手帶你學Docker 03042017
 

Viewers also liked

Deloitte-2014-Technology-Fast500
Deloitte-2014-Technology-Fast500Deloitte-2014-Technology-Fast500
Deloitte-2014-Technology-Fast500Seth Greenberg
 
Teaching Your Machine To Find Fraudsters
Teaching Your Machine To Find FraudstersTeaching Your Machine To Find Fraudsters
Teaching Your Machine To Find FraudstersIan Barber
 
Deloittes 2009 Technology Fast 500™ Ranking
Deloittes 2009 Technology Fast 500™  RankingDeloittes 2009 Technology Fast 500™  Ranking
Deloittes 2009 Technology Fast 500™ Rankinglisaswiftney
 
dollar general annual reports 2002
dollar general annual reports 2002dollar general annual reports 2002
dollar general annual reports 2002finance41
 
Arc Sight Info Documents 10 21 2009
Arc Sight Info Documents 10 21 2009Arc Sight Info Documents 10 21 2009
Arc Sight Info Documents 10 21 2009mattdriscoll
 
The Pixel Lab 2015 | Don't lose heart - Sean Coleman
The Pixel Lab 2015 | Don't lose heart - Sean Coleman The Pixel Lab 2015 | Don't lose heart - Sean Coleman
The Pixel Lab 2015 | Don't lose heart - Sean Coleman power to the pixel
 
Arc Sight Info Documents 12 3 2009
Arc Sight Info Documents 12 3 2009Arc Sight Info Documents 12 3 2009
Arc Sight Info Documents 12 3 2009mattdriscoll
 
Document Classification In PHP - Slight Return
Document Classification In PHP - Slight ReturnDocument Classification In PHP - Slight Return
Document Classification In PHP - Slight ReturnIan Barber
 
ZeroMQ Is The Answer: PHP Tek 11 Version
ZeroMQ Is The Answer: PHP Tek 11 VersionZeroMQ Is The Answer: PHP Tek 11 Version
ZeroMQ Is The Answer: PHP Tek 11 VersionIan Barber
 
Social media & dirigeants du Cac 40 : que disent les conversations ?
Social media & dirigeants du Cac 40 : que disent les conversations ?Social media & dirigeants du Cac 40 : que disent les conversations ?
Social media & dirigeants du Cac 40 : que disent les conversations ?Linkfluence
 
Israel pide un rey
Israel pide un reyIsrael pide un rey
Israel pide un reyCoke Neto
 
Technology-Fast-500-Winners-Brochure.PDF
Technology-Fast-500-Winners-Brochure.PDFTechnology-Fast-500-Winners-Brochure.PDF
Technology-Fast-500-Winners-Brochure.PDFJustin Campbell
 

Viewers also liked (17)

Deloitte-2014-Technology-Fast500
Deloitte-2014-Technology-Fast500Deloitte-2014-Technology-Fast500
Deloitte-2014-Technology-Fast500
 
Teaching Your Machine To Find Fraudsters
Teaching Your Machine To Find FraudstersTeaching Your Machine To Find Fraudsters
Teaching Your Machine To Find Fraudsters
 
Deloittes 2009 Technology Fast 500™ Ranking
Deloittes 2009 Technology Fast 500™  RankingDeloittes 2009 Technology Fast 500™  Ranking
Deloittes 2009 Technology Fast 500™ Ranking
 
dollar general annual reports 2002
dollar general annual reports 2002dollar general annual reports 2002
dollar general annual reports 2002
 
Canada Deber 2pdf
Canada Deber 2pdfCanada Deber 2pdf
Canada Deber 2pdf
 
20140528 valeant story draft deckv85
20140528 valeant story draft deckv8520140528 valeant story draft deckv85
20140528 valeant story draft deckv85
 
Arc Sight Info Documents 10 21 2009
Arc Sight Info Documents 10 21 2009Arc Sight Info Documents 10 21 2009
Arc Sight Info Documents 10 21 2009
 
The Pixel Lab 2015 | Don't lose heart - Sean Coleman
The Pixel Lab 2015 | Don't lose heart - Sean Coleman The Pixel Lab 2015 | Don't lose heart - Sean Coleman
The Pixel Lab 2015 | Don't lose heart - Sean Coleman
 
Arc Sight Info Documents 12 3 2009
Arc Sight Info Documents 12 3 2009Arc Sight Info Documents 12 3 2009
Arc Sight Info Documents 12 3 2009
 
Document Classification In PHP - Slight Return
Document Classification In PHP - Slight ReturnDocument Classification In PHP - Slight Return
Document Classification In PHP - Slight Return
 
ZeroMQ Is The Answer: PHP Tek 11 Version
ZeroMQ Is The Answer: PHP Tek 11 VersionZeroMQ Is The Answer: PHP Tek 11 Version
ZeroMQ Is The Answer: PHP Tek 11 Version
 
Social media & dirigeants du Cac 40 : que disent les conversations ?
Social media & dirigeants du Cac 40 : que disent les conversations ?Social media & dirigeants du Cac 40 : que disent les conversations ?
Social media & dirigeants du Cac 40 : que disent les conversations ?
 
Eca´s probabilidad y estadística Agosto 2012-Enero 2013
Eca´s probabilidad y estadística Agosto 2012-Enero 2013Eca´s probabilidad y estadística Agosto 2012-Enero 2013
Eca´s probabilidad y estadística Agosto 2012-Enero 2013
 
4 de febrero de 1992 pdf
4 de febrero de 1992 pdf4 de febrero de 1992 pdf
4 de febrero de 1992 pdf
 
Israel pide un rey
Israel pide un reyIsrael pide un rey
Israel pide un rey
 
Technology-Fast-500-Winners-Brochure.PDF
Technology-Fast-500-Winners-Brochure.PDFTechnology-Fast-500-Winners-Brochure.PDF
Technology-Fast-500-Winners-Brochure.PDF
 
D41d8cd91 (1)
D41d8cd91 (1)D41d8cd91 (1)
D41d8cd91 (1)
 

Similar to Deployment Tactics

The Modern Developer Toolbox
The Modern Developer ToolboxThe Modern Developer Toolbox
The Modern Developer ToolboxPablo Godel
 
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)Fabrice Bernhard
 
[EXTENDED] Ceph, Docker, Heroku Slugs, CoreOS and Deis Overview
[EXTENDED] Ceph, Docker, Heroku Slugs, CoreOS and Deis Overview[EXTENDED] Ceph, Docker, Heroku Slugs, CoreOS and Deis Overview
[EXTENDED] Ceph, Docker, Heroku Slugs, CoreOS and Deis OverviewLeo Lorieri
 
Capistrano deploy Magento project in an efficient way
Capistrano deploy Magento project in an efficient wayCapistrano deploy Magento project in an efficient way
Capistrano deploy Magento project in an efficient waySylvain Rayé
 
Bangpypers april-meetup-2012
Bangpypers april-meetup-2012Bangpypers april-meetup-2012
Bangpypers april-meetup-2012Deepak Garg
 
Toolbox of a Ruby Team
Toolbox of a Ruby TeamToolbox of a Ruby Team
Toolbox of a Ruby TeamArto Artnik
 
Docker jako prostředí pro automatizaci testů
Docker jako prostředí pro automatizaci testůDocker jako prostředí pro automatizaci testů
Docker jako prostředí pro automatizaci testůRadim Daniel Pánek
 
A Fabric/Puppet Build/Deploy System
A Fabric/Puppet Build/Deploy SystemA Fabric/Puppet Build/Deploy System
A Fabric/Puppet Build/Deploy Systemadrian_nye
 
Advanced Eclipse Workshop (held at IPC2010 -spring edition-)
Advanced Eclipse Workshop (held at IPC2010 -spring edition-)Advanced Eclipse Workshop (held at IPC2010 -spring edition-)
Advanced Eclipse Workshop (held at IPC2010 -spring edition-)Bastian Feder
 
Control your deployments with Capistrano
Control your deployments with CapistranoControl your deployments with Capistrano
Control your deployments with CapistranoRamazan K
 
Deploying Symfony | symfony.cat
Deploying Symfony | symfony.catDeploying Symfony | symfony.cat
Deploying Symfony | symfony.catPablo Godel
 
Lightning branches at RedMart (Js conf Asia 2014 Talk)
Lightning branches at RedMart (Js conf Asia 2014  Talk)Lightning branches at RedMart (Js conf Asia 2014  Talk)
Lightning branches at RedMart (Js conf Asia 2014 Talk)Ritesh Angural
 
Django dev-env-my-way
Django dev-env-my-wayDjango dev-env-my-way
Django dev-env-my-wayRobert Lujo
 
Fargate 를 이용한 ECS with VPC 1부
Fargate 를 이용한 ECS with VPC 1부Fargate 를 이용한 ECS with VPC 1부
Fargate 를 이용한 ECS with VPC 1부Hyun-Mook Choi
 
The Docker "Gauntlet" - Introduction, Ecosystem, Deployment, Orchestration
The Docker "Gauntlet" - Introduction, Ecosystem, Deployment, OrchestrationThe Docker "Gauntlet" - Introduction, Ecosystem, Deployment, Orchestration
The Docker "Gauntlet" - Introduction, Ecosystem, Deployment, OrchestrationErica Windisch
 
Develop with docker 2014 aug
Develop with docker 2014 augDevelop with docker 2014 aug
Develop with docker 2014 augVincent De Smet
 

Similar to Deployment Tactics (20)

The Modern Developer Toolbox
The Modern Developer ToolboxThe Modern Developer Toolbox
The Modern Developer Toolbox
 
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)
 
[EXTENDED] Ceph, Docker, Heroku Slugs, CoreOS and Deis Overview
[EXTENDED] Ceph, Docker, Heroku Slugs, CoreOS and Deis Overview[EXTENDED] Ceph, Docker, Heroku Slugs, CoreOS and Deis Overview
[EXTENDED] Ceph, Docker, Heroku Slugs, CoreOS and Deis Overview
 
Capistrano deploy Magento project in an efficient way
Capistrano deploy Magento project in an efficient wayCapistrano deploy Magento project in an efficient way
Capistrano deploy Magento project in an efficient way
 
Bangpypers april-meetup-2012
Bangpypers april-meetup-2012Bangpypers april-meetup-2012
Bangpypers april-meetup-2012
 
Toolbox of a Ruby Team
Toolbox of a Ruby TeamToolbox of a Ruby Team
Toolbox of a Ruby Team
 
Write php deploy everywhere
Write php deploy everywhereWrite php deploy everywhere
Write php deploy everywhere
 
Docker jako prostředí pro automatizaci testů
Docker jako prostředí pro automatizaci testůDocker jako prostředí pro automatizaci testů
Docker jako prostředí pro automatizaci testů
 
A Fabric/Puppet Build/Deploy System
A Fabric/Puppet Build/Deploy SystemA Fabric/Puppet Build/Deploy System
A Fabric/Puppet Build/Deploy System
 
Advanced Eclipse Workshop (held at IPC2010 -spring edition-)
Advanced Eclipse Workshop (held at IPC2010 -spring edition-)Advanced Eclipse Workshop (held at IPC2010 -spring edition-)
Advanced Eclipse Workshop (held at IPC2010 -spring edition-)
 
Control your deployments with Capistrano
Control your deployments with CapistranoControl your deployments with Capistrano
Control your deployments with Capistrano
 
Write php deploy everywhere tek11
Write php deploy everywhere   tek11Write php deploy everywhere   tek11
Write php deploy everywhere tek11
 
Deploying Symfony | symfony.cat
Deploying Symfony | symfony.catDeploying Symfony | symfony.cat
Deploying Symfony | symfony.cat
 
Devopstore
DevopstoreDevopstore
Devopstore
 
Lightning branches at RedMart (Js conf Asia 2014 Talk)
Lightning branches at RedMart (Js conf Asia 2014  Talk)Lightning branches at RedMart (Js conf Asia 2014  Talk)
Lightning branches at RedMart (Js conf Asia 2014 Talk)
 
Belvedere
BelvedereBelvedere
Belvedere
 
Django dev-env-my-way
Django dev-env-my-wayDjango dev-env-my-way
Django dev-env-my-way
 
Fargate 를 이용한 ECS with VPC 1부
Fargate 를 이용한 ECS with VPC 1부Fargate 를 이용한 ECS with VPC 1부
Fargate 를 이용한 ECS with VPC 1부
 
The Docker "Gauntlet" - Introduction, Ecosystem, Deployment, Orchestration
The Docker "Gauntlet" - Introduction, Ecosystem, Deployment, OrchestrationThe Docker "Gauntlet" - Introduction, Ecosystem, Deployment, Orchestration
The Docker "Gauntlet" - Introduction, Ecosystem, Deployment, Orchestration
 
Develop with docker 2014 aug
Develop with docker 2014 augDevelop with docker 2014 aug
Develop with docker 2014 aug
 

More from Ian Barber

How to stand on the shoulders of giants
How to stand on the shoulders of giantsHow to stand on the shoulders of giants
How to stand on the shoulders of giantsIan Barber
 
ZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made SimpleZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made SimpleIan Barber
 
Debugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 VersionDebugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 VersionIan Barber
 
ZeroMQ Is The Answer: DPC 11 Version
ZeroMQ Is The Answer: DPC 11 VersionZeroMQ Is The Answer: DPC 11 Version
ZeroMQ Is The Answer: DPC 11 VersionIan Barber
 
ZeroMQ Is The Answer
ZeroMQ Is The AnswerZeroMQ Is The Answer
ZeroMQ Is The AnswerIan Barber
 
In Search Of: Integrating Site Search (PHP Barcelona)
In Search Of: Integrating Site Search (PHP Barcelona)In Search Of: Integrating Site Search (PHP Barcelona)
In Search Of: Integrating Site Search (PHP Barcelona)Ian Barber
 
Debugging: Rules & Tools
Debugging: Rules & ToolsDebugging: Rules & Tools
Debugging: Rules & ToolsIan Barber
 
In Search Of... (Dutch PHP Conference 2010)
In Search Of... (Dutch PHP Conference 2010)In Search Of... (Dutch PHP Conference 2010)
In Search Of... (Dutch PHP Conference 2010)Ian Barber
 
In Search Of... integrating site search
In Search Of... integrating site search In Search Of... integrating site search
In Search Of... integrating site search Ian Barber
 
Document Classification In PHP
Document Classification In PHPDocument Classification In PHP
Document Classification In PHPIan Barber
 

More from Ian Barber (10)

How to stand on the shoulders of giants
How to stand on the shoulders of giantsHow to stand on the shoulders of giants
How to stand on the shoulders of giants
 
ZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made SimpleZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made Simple
 
Debugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 VersionDebugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 Version
 
ZeroMQ Is The Answer: DPC 11 Version
ZeroMQ Is The Answer: DPC 11 VersionZeroMQ Is The Answer: DPC 11 Version
ZeroMQ Is The Answer: DPC 11 Version
 
ZeroMQ Is The Answer
ZeroMQ Is The AnswerZeroMQ Is The Answer
ZeroMQ Is The Answer
 
In Search Of: Integrating Site Search (PHP Barcelona)
In Search Of: Integrating Site Search (PHP Barcelona)In Search Of: Integrating Site Search (PHP Barcelona)
In Search Of: Integrating Site Search (PHP Barcelona)
 
Debugging: Rules & Tools
Debugging: Rules & ToolsDebugging: Rules & Tools
Debugging: Rules & Tools
 
In Search Of... (Dutch PHP Conference 2010)
In Search Of... (Dutch PHP Conference 2010)In Search Of... (Dutch PHP Conference 2010)
In Search Of... (Dutch PHP Conference 2010)
 
In Search Of... integrating site search
In Search Of... integrating site search In Search Of... integrating site search
In Search Of... integrating site search
 
Document Classification In PHP
Document Classification In PHPDocument Classification In PHP
Document Classification In PHP
 

Deployment Tactics

  • 1. LOYM ENT DEP ICS TACT Managing code from development to production Ian Barber - ian.barber@gmail.com twitter.com/ianbarber | phpir.com
  • 3. - Table of Contents - 1.... Change Control 2.... Environments 3.... Version Control 4.... The Deploy Process 5.... Scripts 6.... Continuous Integration 7.... Remote Releases 8.... Packaged Releases 9.... Package Management 10.. Managing Hotfixes 11.. Managing Database Changes 12.. Rollbacks 13.. Tactical Deployment
  • 4. Change control plan execute change change identify verify need close deliver
  • 5. export copy to code server require compare release md5 report restart back apache
  • 6. Change Request Form Requested By: J. Teamlead Authorised By: S. Manager Submit Date: 2011-01-27 Change Date: 2011-02-04 Reason For Change: Resolve JIRA-1602 - Listen for new .com variants on vhost Change Request: Release tag 1.1.3 via normal process mv /etc/httpd/conf.d/fooweb.conf /etc/httpd/conf.d/fooweb.old mv ~releases/1.1.3/conf/fooweb.conf /etc/httpd/conf.d/ fooweb.conf Verification: http://foweb.com shows the same page as http://fooweb.com Rollback: Re-release 1.1.2 mv /etc/httpd/conf.d/fooweb.old /etc/httpd/conf.d/fooweb.conf
  • 7. Environments Production Development static verbose robust dynamic reliable unstable optimised experimental
  • 8. on Envir onment The Producti Image: http://flickr.com/photos/lejoe/3763218501
  • 9. The Staging Environment Image: http://flickr.com/photos/simononly/4454401446
  • 10. n Enviro nment The Int egratio Image: http://flickr.com/photos/unfoldedorigami/2374016430
  • 11. The Developme nt Environmen t Image: http://flickr.com/photos/drewnew/511936681
  • 12. VERSION CONTROL Image: http://flickr.com/photos/robbie73/4346732208
  • 13. /branches/newpage /branches/... /branches/search /trunk /branches/1.1.2 /tags/1.1.2
  • 14. Development /branches/newpage /branches/... /branches/search /trunk Integration /branches/1.1.2 /tags/1.1.2 Staging Production
  • 15. master release1.1.1 devel search feature long feature
  • 16. Production master release1.1.1 Staging devel search feature Integration long feature Development
  • 18. The DEPLoy PROCESS transparent flexible easy scalable graceful reliable
  • 19. support SMTP process config apache vhost app update code config file perms packages commands libpng update cache restart service service
  • 20. code config package repository repository repository ta da server commands deployment server server controller
  • 21. code config package repository repository repository da ta server commands deployment server + data controller server
  • 22. BUILD SCRIPTS #!/bin/bash # Deployment script for FooWeb Project git archive --format=tar --remote=git://repo.com/myrepo/myrepo.git HEAD -o fooweb.tar tar -xf fooweb.tar /var/www service httpd restart
  • 23. #!/bin/bash # Deployment script for FooWeb Project svn export svn://localhost/fooweb-service/ trunk release cd release && mkdir build cp -r web/* build/ javac -cp /usr/share/java/servlet-api-2.5.jar -d build/WEB-INF/classes src/com/fooweb/service/*.java cd build && jar cvf ../fooweb.war * && cd ../ # assumes autoDeploy is true cp fooweb.war /var/lib/tomcat6/webapps
  • 24. BUILDS TOOLS tests release code build docs test assets results
  • 26. <?xml version="1.0" encoding="UTF-8"?> <project name="FooWeb"> <property name="install" location="/var/lib/ tomcat6/webapps" /> <property name="svn.repo" value="svn:// localhost/fooweb-service/trunk" /> <!--A "clean" target to delete compiled files--> <target name="clean"> <delete dir="build" /> <delete dir="release" /> <delete file="fooweb.war" /> </target>
  • 27. <!-- Checkout, mkdir and compile--> <target name="build"> <exec executable="svn"> <arg line="export ${svn.repo} release" /> </exec> <mkdir dir="build"/> <copy todir="build"> <fileset dir="release/web" /> </copy> <javac srcdir="release/src" destdir="build/WEB-INF/classes/"> <classpath> <pathelement path="/usr/share/ java/servlet-api-2.5.jar"/> </classpath> </javac> </target>
  • 28. <!-- Build our WAR file --> <target name="war" depends="build"> <war destfile="fooweb.war" webxml="build/ WEB-INF/web.xml"> <fileset dir="build"/> <classes dir="build/WEB-INF/classes"/> </war> </target> <!-- Copy our file --> <target name="deploy" depends="war"> <copy file="fooweb.war" todir="$ {install}" /> </target> </project>
  • 29. $ sudo ant deploy Buildfile: build.xml build: [exec] Exported revision 8. [mkdir] Created dir: /tmp/build [copy] Copying 2 files to /tmp/build [copy] Copied 3 empty directories to 1 empty directory under /tmp/build [javac] Compiling 1 source file to /tmp/build/WEB-INF/classes war: [war] Building war: /tmp/fooweb.war deploy: [copy] Copying 1 file to /var/lib/tomcat6/ webapps BUILD SUCCESSFUL Total time: 2 seconds
  • 30. CONTINUOUS INTEGRATION Look at the Hud son Wiki at dson-ci.org http://wiki.hu
  • 36. <project name="Fooweb" default="build"> <target name="build" depends="phpunit" /> <target name="init"> <mkdir dir="${basedir}/build/logs" /> </target> <target name="phpunit" depends="init"> <exec executable="phpunit" dir="${basedir}/tests" failonerror="on"> <arg line=" --log-junit '${basedir}/ build/logs/phpunit.xml' --coverage-clover '$ {basedir}/build/logs/clover.xml' --coverage- html '${basedir}/build/logs/coverage'" /> </exec> </target>
  • 37. <target name="phpcpd" depends="init"> <exec executable="phpcpd" dir="${basedir}/application" failonerror="on"> <arg line=" --log-pmd '${basedir}/build/logs/php-cpd.xml' ." /> </exec> </target> </project>
  • 40. REMOTE RELEASES Image: http://flickr.com/photos/scragz/309353618
  • 41. server server authorized_keys authorized_keys cp ss /s h /s h ss cp deployment controller id_rsa.pub user “deploy” ssh-keygen -t rsa
  • 42. Fabric from fabric.api import * http://fabfile .org # Development environment def dev(): env.user = 'deployer' env.roledefs = { "web" : ['localhost'], "db" : ['localhost'], } # Production environment def production(): env.user = 'deployer' env.roledefs = { "web" : ['primary.fooweb.com', 'secondary.fooweb.com'], "db" : ['backend.fooweb.com'], }
  • 43. # Package up release - run local def prepare_deploy(): local('svn export svn://localhost/fooweb/ trunk release') with cd('release'): local('tar cvzf ../fooweb.tar.gz .') local('rm -rf release') # Restart web server @roles('web') def restart_webserver(): sudo('/etc/init.d/apache2 restart')
  • 44. # Deploy to remote servers @roles('web') def deploy(): prepare_deploy() # in case of already existing with settings(warn_only=True): run('mkdir /tmp/release') run('rm -rf /tmp/release/*') put("fooweb.tar.gz", '/tmp/release') with cd('/tmp/release'): run("tar xvzf fooweb.tar.gz") run("rm -rf fooweb.tar.gz") run("mv * /tmp/test") restart_webserver(); local("rm -rf fooweb.tar.gz");
  • 45. $ fab dev deploy [localhost] run: svn export svn://localhost/ fooweb/trunk release [localhost] run: tar cvzf ../fooweb.tar.gz . [localhost] run: rm -rf release [localhost] run: mkdir /tmp/release [localhost] err: mkdir: cannot create directory `/tmp/release': File exists Warning: run() encountered an error (return code 1) while executing 'mkdir /tmp/release' [localhost] run: rm -rf /tmp/release/* [localhost] put: fooweb.tar.gz -> /tmp/ release/fooweb.tar.gz
  • 46. [localhost] run: tar xvzf fooweb.tar.gz [localhost] run: rm -rf fooweb.tar.gz [localhost] run: mv * /tmp/test [localhost] sudo: /etc/init.d/apache2 restart Password for ianbarber@localhost: [localhost] out: * Restarting web server apache2 [localhost] out: ... waiting ...done. [localhost] run: rm -rf fooweb.tar.gz Done. Disconnecting from localhost... done.
  • 47. $ fab production deploy [localhost] run: tar cvzf ../fooweb.tar.gz . .... [primary.fooweb.com] run: rm -rf /tmp/release/ [localhost] run: tar cvzf ../fooweb.tar.gz . .... [secondary.fooweb.com] run: mkdir /tmp/release .... Disconnecting from secondary.fooweb.com...done Disconnecting from primary.fooweb.com... done
  • 48. $ mkdir config && cd config && capify . [add] writing './Capfile' [add] making directory './config' [add] writing './config/deploy.rb' [done] capified! set :application, "set your application name " set :repository, "set your repository" set :scm, :subversion role :web, "your web-server here" role :app, "your app-server here" role :db, "your primary db-server here", :primary => true Capi strano role :db, "slave db" .com/ https:/ /github capis trano/
  • 49. set :application, "fooweb" set :repository,"svn://localhost/fooweb/trunk" set :scm, :subversion set :scm_username, "deployment" set :scm_password, "s3kkr3tp4a55" set :scm_checkout, "export" set :keep_releases, 4 set :normalize_asset_timestamps, false set :deploy_to, "/usr/local/#{application}" role :web, "primary.fooweb.com" role :web, "secondary.fooweb.com" role :db, "backend.fooweb.com"
  • 50. namespace :deploy do task :migrate do # nothing end task :restart do sudo "/etc/init.d/apache2 restart" end end namespace :fooweb do task :perms do sudo "chmod -R a+w #{deploy_to}" end end after "deploy:setup", "fooweb:perms"
  • 51. $ cap deploy:setup * executing `deploy:setup' * executing "sudo mkdir -p /usr/local/fooweb [...]" servers: ["primary","secondary", "backend"] [backend] executing command [...] command finished triggering after callbacks for deploy:setup * executing `fooweb:perms' * executing "sudo chmod -R a+w /usr/local/ fooweb" servers: ["primary","secondary","backend"] [primary] executing command [...] command finished
  • 52. $ cap deploy * executing `deploy' * executing `deploy:update' ** transaction: start * executing `deploy:update_code' executing locally: "svn info svn:// localhost/fooweb/trunk -rHEAD" /usr/bin/svn * executing "svn checkout -q -r17 svn:// localhost/fooweb/trunk /usr/local/fooweb/ releases/20110116192456 && (echo 17 > /usr/ local/fooweb/releases/20110116192456/ REVISION)" servers: ["primary.fooweb.com"] [primary.fooweb.com] executing command [....] * executing `deploy:finalize_update' * executing "chmod -R g+w /usr/local/fooweb/
  • 53. /usr/local/fooweb/ !"" current -> releases/20110116192316 !"" releases #   !"" 20110116190608 #   #   !"" application #   #   !"" log -> /usr/local/fooweb/shared/log #   #   !"" public #   #   !"" REVISION #   #   !"" tmp #   !"" 20110116192316 #   #   !"" application #   #   !"" log -> /usr/local/fooweb/shared/log #   #   !"" public #   #   !"" REVISION #   #   !"" tmp $"" shared
  • 64. PACKAGED RELEASES Image: http://flickr.com/photos/halfbisqued/2353845688
  • 65. Fooweb Fooweb Fooweb Mail Service Any SMTP Symfony 1.3 Tomcat 6.0 Server PHP 5.2.12 Java 1.6
  • 66. !"" application #   !"" controllers #   #   $"" home.php #   $"" library #   $"" Foow #   $"" Router.php !"" fooweb.spec !"" public #   $"" index.php $"" vhosts $"" fooweb.conf
  • 67. Summary: Fooweb Application Vendor: Fooweb Name: fooweb Version: 1.0 Release: 1 Source0: fooweb-%{version}.tar.gz License: BSD Group: Fooweb BuildArch: noarch BuildRoot: %{_tmppath}/%{name}-%{version}- buildroot Requires: php %description This is the Fooweb web application %prep %setup
  • 68. %install mkdir -p $RPM_BUILD_ROOT/var/www/fooweb mkdir -p $RPM_BUILD_ROOT/etc/httpd/conf.d/ cp -r application $RPM_BUILD_ROOT/var/www/fooweb cp -r public $RPM_BUILD_ROOT/var/www/fooweb cp vhosts/fooweb.conf $RPM_BUILD_ROOT/etc/httpd/ conf.d/ %clean rm -rf $RPM_BUILD_ROOT %files %dir /var/www %dir /var/www/fooweb %config /etc/httpd/conf.d/fooweb.conf /var/www/fooweb/*
  • 69. ~$ mkdir buildroot buildroot/tmp ~$ cat .rpmmacro %packager Fooweb Release Manager %_topdir ~/buildroot %_tmppath ~/buildroot/tmp ~$ cd ~/tags ~/tags$ tar cvzf fooweb-1.0.tar.gz fooweb-1.0
  • 70. ~$ rpmbuild -ta fooweb-1.0.tar.gz ~$ rpm -qip ~/rpmbuild/RPMS/noarch/ fooweb-1.0-1.noarch.rpm Name : fooweb Relocations: (not relocatable) Version : 1.0 Vendor: Fooweb Release : 1 Build Date: Thu 13 Jan 2011 12:26:24 AM PST Install Date: (not installed) Build Host: ubuntu.localdomain Group : Fooweb Source RPM: fooweb-1.0-1.src.rpm Size : 781 License : BSD Signature : (none) Summary : Fooweb Application Description : This is the Fooweb web application
  • 71. $ mkdir /var/www/repo $ cd /var/www/repo $ mkdir centox/5/fooweb/ {SRPMS,X86_64,i386,noarch} $ cp ~rpmbuild/RPMS/noarch/* centos/5/fooweb/ noarch $ cp ~rpmbuild/SRPMS/* centos/5/fooweb/SRPMS $ createrepo -v centos/5/fooweb/noarch/ centos/5/fooweb/noarch/ !"" fooweb-1.0-1.noarch.rpm $"" repodata !"" filelists.xml.gz !"" other.xml.gz !"" primary.xml.gz $"" repomd.xml
  • 72. $ cat /etc/yum.repos.d/fooweb.repo [fooweb_noarch] name = Fooweb Private Repository baseurl = http://fooweb.com/repo/centos/5/fooweb/ noarch enabled = 1 gpgcheck = 0 gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY- fooweb $ yum update fooweb_noarch 100% |========| 951 B fooweb_noarch/primary 100% |========| 701 B fooweb_noarch 1/1 Setting up Update Process No Packages marked for Update
  • 73. $ yum info fooweb Available Packages Name : fooweb Arch : noarch Version : 1.0 Release : 1 Size : 3.3 k Repo : fooweb_noarch Summary : Fooweb Application License : BSD Description: This is the Fooweb web application
  • 75. <target name="buildrpm" depends="init"> <tar destfile="build/rpm/SOURCES/ fooweb.tar.gz" compression="gzip"> <tarfileset dir="${basedir}" prefix="fooweb-1.0"> <include name="*/**" /> <exclude name="build/**" /> </tarfileset> </tar> <copy file="${basedir}/fooweb.spec" tofile="$ {basedir}/build/rpm/SPECS/fooweb.spec" /> <rpm command="-ba" specFile="fooweb.spec" topDir="${basedir}/build/rpm" cleanBuildDir="true" failOnError="true" /> </target>
  • 76. PACKAGE MANAGEMENT Image: http://flickr.com/photos/southerncalifornian/2129676744
  • 77. $ sudo aptitude install puppetmaster 0 packages upgraded, 10 newly installed, 0 to remove and 76 not upgraded. Need to get 3,233kB of archives. After unpacking 13.7MB will be used. Puppet http://puppetlabs.com $ sudo aptitude install puppet 0 packages upgraded, 5 newly installed, 0 to remove and 76 not upgraded. Need to get 587kB of archives. After unpacking 1,892kB will be used.
  • 78. backend fooweb.com primary fooweb.com seconday fooweb.com int fooweb.com staging fooweb.com Puppet master
  • 79. /etc/puppet !"" auth.conf !"" fileserver.conf !"" manifests #   $"" site.pp !"" modules #   !"" apache2 #   #   $"" manifests #   #   $"" init.pp #   $"" fooweb #   !"" files #   #   $"" fooweb.conf #   $"" manifests #   $"" init.pp !"" puppet.conf $"" templates
  • 80. class fooweb { package { "fooweb": ensure => latest, } " file { "/etc/apache2/sites-enabled/fooweb.conf": owner => root, group => root, mode => 0444, source => "puppet:///files/fooweb/files/fooweb.conf", notify => Service["apache2"] } } mod ules/fooweb manif ests/init.pp
  • 81. node "ubuntu.localdomain" { manifests/site.pp include fooweb include apache2 } class apache2 { service { apache2: ensure => running } modules/apache2 manifests/init.pp
  • 82. # puppet agent -o -v --no-daemonize info: Caching catalog for ubuntu.localdomain info: Applying configuration version '1295514488' notice: /Stage[main]/Fooweb/Package[fooweb]/ ensure: ensure changed 'purged' to 'latest' notice: /Stage[main]/Fooweb/File[/etc/apache2/ sites-enabled/fooweb.conf]/ensure: defined content as '{md5} d41d8cd98f00b204e9800998ecf8427e' info: /Stage[main]/Fooweb/File[/etc/apache2/ sites-enabled/fooweb.conf]: Scheduling refresh of Service[apache2] notice: /Stage[main]/Apache2/Service[apache2]: Triggered 'refresh' from 1 events notice: Finished catalog run in 3.33 seconds # ls /etc/httpd/conf.d/fooweb.conf /etc/httpd/conf.d/fooweb.conf # ls /var/www/fooweb/ application public
  • 83. MANAGING HOTFIXES Image: http://flickr.com/photos/moogan/8206134
  • 84. /branches/1.1.3 /trunk /tags/1.1.2 /tags/1.1.3
  • 85. package copy code run db backup run db changes make code active
  • 86. package copy code run db backup run db changes make code active
  • 87. MANAGING Database ChanGES Image: http://flickr.com/photos/theplanetdotcom/4878814847
  • 89. CREATE TABLE `blogpost` ( `id` int(11) auto_increment NOT NULL PRIMARY KEY, `title` VARCHAR(255), `timestamp` DATETIME, `content` TEXT ); --//@UNDO DBDeploy tp://dbdeploy.com DROP TABLE `blogpost`; ht
  • 90. ALTER TABLE `blogpost` ADD `author` varchar(255) NULL; --//@UNDO ALTER TABLE `blogpost` DROP `author`;
  • 91. $ wget http://dbdeploy.googlecode.com/files/ dbdeploy-dist-3.0M2-distribution.zip CREATE TABLE changelog ( change_number BIGINT NOT NULL, delta_set VARCHAR(10) NOT NULL, start_dt TIMESTAMP NOT NULL, complete_dt TIMESTAMP NULL, applied_by VARCHAR(100) NOT NULL, description VARCHAR(500) NOT NULL, PRIMARY KEY(change_number, delta_set) );
  • 92. $ java -cp mysql-connector-java.jar:dbdeploy- cli-3.0M2.jar com.dbdeploy.CommandLineTarget - D com.mysql.jdbc.Driver -d mysql -o delta.sql -u jdbc:mysql://localhost/foowebdb -U root -P ****** dbdeploy 3.0M2 Reading change scripts from directory dbdeploy. Changes currently applied to database: (none) Scripts available: 1, 2 To be applied: 1, 2
  • 93. -- START CHANGE SCRIPT #1: 1-create-blogposts.sql CREATE TABLE `blogpost` ( `id` int(11) auto_increment NOT NULL PRIMARY KEY, `title` VARCHAR(255), `timestamp` DATETIME, `content` TEXT ); INSERT INTO changelog (change_number, complete_dt, applied_by, description) VALUES (1, CURRENT_TIMESTAMP, USER(), '1-create- blogposts.sql'); COMMIT;
  • 94. -- END CHANGE SCRIPT #1: 1-create-blogposts.sql -- START CHANGE SCRIPT #2: 2-add-author.sql ALTER TABLE `blogpost` ADD `author` varchar(255) NULL; INSERT INTO changelog (change_number, complete_dt, applied_by, description) VALUES (2, CURRENT_TIMESTAMP, USER(), '2-add- author.sql'); COMMIT; -- END CHANGE SCRIPT #2: 2-add-author.sql
  • 95. <?xml version="1.0" encoding="UTF-8" standalone="no"?> <databaseChangeLog [....]> <changeSet author="ianbarber" id="1"> <createTable tableName="blogposts"> <column autoIncrement="true" name="id" type="int(11)"> <constraints nullable="false" primaryKey="true" /> </column> <column name="title" type="varchar(255)" /> <column name="body" type="text" /> <column name="author" type="varchar(255)"/> <column name="date" type="timestamp" /> </createTable> </changeSet> Liquibase ht tp://liquibase.org
  • 96. <?xml version="1.0" encoding="UTF-8" standalone="no"?> <databaseChangeLog [....] > <include file="v000/master.xml" /> </databaseChangeLog> update.xml <?xml version="1.0" encoding="UTF-8" standalone="no"?> <databaseChangeLog [....]> <include file="v000/create-blog- posts-1.xml" /> </databaseChangeLog> v000/master.xml
  • 97. $ wget http://downloads.sourceforge.net/ project/liquibase/Liquibase%20Core/2.0.0/ liquibase-2.0.0-bin.zip # Liquibase properties driver: com.mysql.jdbc.Driver url: jdbc:mysql://localhost/fooweb classpath: /usr/share/java/mysql-connector- java.jar username: root password: ******* roperties liquibase.p
  • 98. $ liquibase --changeLogFile=update.xml update Liquibase Home: /opt/liquibase INFO 1/18/11 1:32 PM:liquibase: Successfully acquired change log lock INFO 1/18/11 1:32 PM:liquibase: Reading from `DATABASECHANGELOG` INFO 1/18/11 1:32 PM:liquibase: Reading from `DATABASECHANGELOG` INFO 1/18/11 1:32 PM:liquibase: ChangeSet v000/create-blog-posts-1.xml::1::ianbarber ran successfully in 101ms INFO 1/18/11 1:32 PM:liquibase: Successfully released change log lock Liquibase Update Successful
  • 99. class CreateProjects < ActiveRecord::Migration def self.up create_table :projects do |t| t.column :name, :string t.column :description, :text t.column :template, :string t.column :created_at, :datetime t.column :updated_at, :datetime end end def self.down drop_table :projects end end
  • 100. ROLLING BACK Image: http://flickr.com/photos/roolrool/4758613588
  • 101. <?xml version="1.0" encoding="UTF-8" standalone="no"?> <databaseChangeLog [....]> <changeSet author="ianbarber" id="2"> <addColumn tableName="blogposts"> <column name="commenter" type="varchar (255)" /> </addColumn> </changeSet> </databaseChangeLog> $ liquibase --changeLogFile=update.xml update Liquibase Home: /opt/liquibase INFO 1/18/11 2:38 PM:liquibase: ChangeSet v000/ add_commenter-2.xml::2::ianbarber ran successfully in 136ms Liquibase Update Successful
  • 102. $ liquibase --changeLogFile=update.xml rollbackCount 1 Liquibase Home: /opt/liquibase INFO 1/18/11 2:39 PM:liquibase: Successfully acquired change log lock INFO 1/18/11 2:39 PM:liquibase: Reading from `DATABASECHANGELOG` INFO 1/18/11 2:39 PM:liquibase: Rolling Back Changeset:v000/add_commenter-2.xml:: 2::ianbarber::(Checksum: 3:cc45ae1014b26f8b35cb70a5fc39a1ae) INFO 1/18/11 2:39 PM:liquibase: Successfully released change log lock Liquibase Rollback Successful
  • 105. E.G. mk_ Primary slave_de http://bi lay DB t.ly/hDW DFi Replication read read slave slave 30 Minute Backup Delay
  • 106. namespace :deploy do namespace :web do task :disable, :roles => :web do on_rollback { rm "#{shared_path}/system/maintenance.html" } require 'erb' deadline, reason = ENV['DATE'], ENV['WHY'] maintenance = ERB.new( File.read("./templates/maintenance.erb" )).result(binding) put maintenance, "#{shared_path}/system/maintenance.html", :mode => 0644 end end
  • 107. # DATE="16:00 MST" WHY="a database upgrade" cap deploy:web:disable if (-f $document_root/system/maintenance.html) { rewrite ^(.*)$ /system/maintenance.html last; break; }
  • 108. warm redirect caches & sessions links proxies migrate
  • 109. developers devops sys QA admins
  • 110. See : Continuous Deplo yment In 5 Easy Steps http://o reil.ly/13EPgd Image: http://flickr.com/photos/jurvetson/3961794276
  • 111. Feature F la gs Image: http://flickr.com/photos/rossharmes/4153769740
  • 112. Gradual Ramp With Feature Without Feature 100% 75% 50% 25% 0% Day 1 Day 2 Day 3 Day 4
  • 113. Dark Lau nches
  • 114. THanks! Deployment Tactics: Managing code from development to production Ian Barber - ian.barber@gmail.com twitter.com/ianbarber | phpir.com