Slide 1

Slide 1 text

Rails Machine Thursday, January 15, 2009

Slide 2

Slide 2 text

The State of Rails Application Deployment Thursday, January 15, 2009

Slide 3

Slide 3 text

It’s easy, I’ll just use Capistrano. Thursday, January 15, 2009

Slide 4

Slide 4 text

It’s easy, I’ll just use Capistrano. ssh [email protected] Thursday, January 15, 2009

Slide 5

Slide 5 text

It’s easy, I’ll just use Capistrano. apt‐get install libmagick10 libmagick9‐dev ssh [email protected] Thursday, January 15, 2009

Slide 6

Slide 6 text

It’s easy, I’ll just use Capistrano. gem install rmagick apt‐get install libmagick10 libmagick9‐dev ssh [email protected] Thursday, January 15, 2009

Slide 7

Slide 7 text

It’s easy, I’ll just use Capistrano. gem install rmagick apt‐get install libmagick10 libmagick9‐dev ssh [email protected] apt‐get install mysql‐ server libmysql‐ruby libmysqlclient15‐dev Thursday, January 15, 2009

Slide 8

Slide 8 text

It’s easy, I’ll just use Capistrano. gem install rmagick apt‐get install libmagick10 libmagick9‐dev ssh [email protected] vi /etc/my.cnf apt‐get install mysql‐ server libmysql‐ruby libmysqlclient15‐dev Thursday, January 15, 2009

Slide 9

Slide 9 text

It’s easy, I’ll just use Capistrano. gem install rmagick apt‐get install libmagick10 libmagick9‐dev ssh [email protected] vi /etc/my.cnf apt‐get install mysql‐ server libmysql‐ruby libmysqlclient15‐dev /etc/init.d/mysql start Thursday, January 15, 2009

Slide 10

Slide 10 text

UR SHIPMENT OF FAIL HAS ARRIVED Thursday, January 15, 2009

Slide 11

Slide 11 text

What is deployment? Thursday, January 15, 2009

Slide 12

Slide 12 text

A Series of Dependencies • Rails v2.2.2, v1.2.3, etc • Ruby/Ruby Enterprise • Apache/Nginx • Passenger/Thin/Mongrel • MySQL/PostgreSQL • system user Thursday, January 15, 2009

Slide 13

Slide 13 text

A Series of Dependencies • rmagick • libmagick10 libmagick9-dev • thinking-sphinx • compile by hand • memcached • libmemcached, rubygem, service Thursday, January 15, 2009

Slide 14

Slide 14 text

Satisfying these dependencies via shell commands is backwards Thursday, January 15, 2009

Slide 15

Slide 15 text

• impossible to verify • not revisioned • no ‘migrations’ • not DRY • not testable Thursday, January 15, 2009

Slide 16

Slide 16 text

Not “The Rails Way” Thursday, January 15, 2009

Slide 17

Slide 17 text

script/plugin install moonshine_rails* script/generate moonshine Thursday, January 15, 2009

Slide 18

Slide 18 text

Moonshine::Manifest #config/moonshine/default.rb class Moonshine::Manifest::Rails::Production < Moonshine::Manifest::Rails #packages(%w(vim curl)) #service('memcached', %w(memcache libmemcached)) #puppet.exec 'foo', # :command => "echo 'normal puppet stuff' > /tmp/test" end Thursday, January 15, 2009

Slide 19

Slide 19 text

Opinionated Software Thursday, January 15, 2009

Slide 20

Slide 20 text

Opinionated Deployment Thursday, January 15, 2009

Slide 21

Slide 21 text

• Ubuntu • Apache • Passenger • Ruby Enterprise Edition • MySQL • ‘rails’ user • /srv/rails Decisions We’ve Made For You Thursday, January 15, 2009

Slide 22

Slide 22 text

class Moonshine::Manifest::Rails < Moonshine::Manifest requires [ :user, :ruby, :rubygems, :db, :web, :rails, :deploy ] provides :user, 'rails' provides :ruby, 'enterprise_ruby' provides :rubygems, 'enterprise_rubygems' provides :db, 'mysql' provides :web, 'apache2' provides :rails, 'passenger' provides :deploy, 'git' end Look at all the choices I’m not making Thursday, January 15, 2009

Slide 23

Slide 23 text

On your server... Thursday, January 15, 2009

Slide 24

Slide 24 text

sudo apt‐get install moonshine* sudo moonshine Thursday, January 15, 2009

Slide 25

Slide 25 text

Answer some questions • application name • git repo • branch to deploy from • user to create • generates SSH key for git host • server ‘tags’ Thursday, January 15, 2009

Slide 26

Slide 26 text

Moonshine goes to work • clones your repo • parses and executes generated moonshine manifests • installs needed gems • install dependencies • migrates your db • deploys your app Thursday, January 15, 2009

Slide 27

Slide 27 text

Gem Dependencies gem_dependencies do |gem| #lots of dependencies are specified for you already #gem.packages 'mysql', %w(mysql‐dev libmysqlclient5‐dev) #gem.packages 'rmagick', %w(ruby‐dev libmagick9‐dev) #... #can specify a mini‐manifest to satisfy before #installation of this gem gem.custom 'urgem' do |puppet| puppet.file '/file/needed/by/ur/gem', :ensure => 'present', :content => 'foo' build_tarball('http://whatever.com/lib‐something.tgz') end end Thursday, January 15, 2009

Slide 28

Slide 28 text

#need to deploy again? sudo moonshine Thursday, January 15, 2009

Slide 29

Slide 29 text

On subsequent runs • updates your repo • parses and executes updated moonshine manifests • verifies needed gems • verifies dependencies • migrates your db • deploys your app Thursday, January 15, 2009

Slide 30

Slide 30 text

• Reproducible • Verified from top-bottom on each deploy • Versionable with your application • same commit can contain, for example, thinking sphinx and installation of the sphinx searchd daemon • DRY Deployment is now... Thursday, January 15, 2009

Slide 31

Slide 31 text

Puppet Based class MysqlMain < Moonshine::Manifest puppet.file '/etc/my.cnf', :ensure => 'present', :content => """ [client] port = 3306 socket = /var/run/mysqld/mysqld.sock [mysqld] default‐character‐set = utf8 key_buffer = 16M max_allowed_packet = 16M thread_stack = 128K thread_cache_size = 8 """ end Thursday, January 15, 2009

Slide 32

Slide 32 text

But Ruby class MysqlMain < Moonshine::Manifest puppet.file '/etc/my.cnf', :ensure => 'present', :content => ArbitraryKlass.arbitrary_function('foo') end Thursday, January 15, 2009

Slide 33

Slide 33 text

Modular UrClass < Moonshine::Manifest::Rails < Moonshine::Manifest •easy to create your own reusable server manifests •extend existing ones with modules Thursday, January 15, 2009

Slide 34

Slide 34 text

Sample ‘plugin’ module MoonshineOrderedPackages def packages(array_or_name, params = {}) package_array = array_or_name.to_a params = { :ensure => 'installed' }.merge(params) package_array.each_with_index do |name,index| #ensure packages are installed in order given package_params = params if package_array[index+1] package_params.merge({ :before => package(package_array[index+1]) }) end puppet.package name.to_s, package_params end end end Moonshine::Manifest::Rails.send(:extend, MoonshineOrderedPackages) Thursday, January 15, 2009

Slide 35

Slide 35 text

Coming Soon • screencast demo (blog.railsmachine.com) • source on GitHub Thursday, January 15, 2009

Slide 36

Slide 36 text

Questions? Thursday, January 15, 2009

Slide 37

Slide 37 text

Jesse Newland [email protected] Thursday, January 15, 2009

Slide 38

Slide 38 text

Flickr FTW • http://www.flickr.com/photos/wolfgangstaudt/2279651479/sizes/o/ • http://www.flickr.com/photos/ramdac/373881476/sizes/o/ • http://www.flickr.com/photos/striatic/2192189572/sizes/o/ • http://www.flickr.com/photos/blakespot/2376243022/sizes/o • http://www.flickr.com/photos/gravestone/449328990/sizes/l/ • http://www.flickr.com/photos/redglow/410800461/sizes/o/ Thursday, January 15, 2009