Quantcast
Channel: Building Web Apps
Viewing all articles
Browse latest Browse all 27

Lab 7. Deployment

$
0
0

In this final lab, we are going to focus on moving your code into a source code control system, preparing a production server for your application, and finally, conducting an actual deployment.

While this lab will use specific services, tools, and server software, the general concepts we will discuss can be applied to most environments. That said, we will not be going too deeply into system administrative tasks. For instance, we won’t be discussing how to properly configure Apache or how to monitor logs. Deploying and conducting daily operations activities on a public production server is a deep topic and is completely independent of your use of Ruby on Rails. If you are new to server administration, it is definitely well worth your time to explore other books, web sites, and experts who can help you out. You’ll find the links that we’ve collected at www.buildingwebapps.com/topic/3-servers.

Note also that this lab uses files that are available in the sample application available to you in the seminar’s Subversion repository. If you have been following the previous labs and recreating the project from scratch, we recommend that you get a copy of our code from Subversion so you can easily copy files over. In addition, the essential files are attached as resources to this write-up.

1. Putting source code into Subversion

The Ruby on Rails ecosystem has developed a number of tools to help make deployment and maintenance of your application easier and less time consuming. Automation is the mainstay of deployment practices where you want a reproducible and controlled process for moving software from development into production.

Ruby on Rails practice, like many other programming environments, fundamentally assumes that you will use a source code control system (SCCS) such as Subversion as the intermediary between your development computers and your production servers. While other deployment strategies are supported, using a SCCS, especially Subversion, is by far the most common, and we’ll focus on that technique here.

Getting set up with Subversion is a three-step process:

  1. Export the code from our shared repository to a directory on your computer. (You can skip this step if you are using your own code but you’ll want a few of our files.)
  2. Import the code into your personal repository on Unfuddle (uploading from your computer to your repository).
  3. Check out a working copy from your personal repository on Unfuddle to a directory on your computer. This is the copy you will modify as you continue working on the code.

This third step is necessary, even though you already have another copy of the code on your computer from step 3, to create a copy that is linked to your personal repository.

Once you’ve done this, adding updates to the repository is simple, and you’ll have a record of every update you’ve ever done and the ability to go back to any point in time.

If you’re using NetBeans, you can do most of these task using its graphical user interface. For the initial process, though, it’s easiest to use the command line. Then, to commit updates you’ve made, you can right-click on your project name, and choose Subversion > Commit.

a. Grab clean copy of latest project

We are using Subversion as our source code control system. The first thing you need to do is get your project into a new Subversion repository that is yours and yours alone. To do this, however, you need a clean copy of the latest code.

Subversion works by keeping private metadata in the same directories as your source code. This means that you can’t simply copy a directory using your operating system that is checked in to another Subversion repository. If you try to do so, you also bring the old metadata, and if you try to add the copied directory into a new repository, Subversion complains.

Note that there are two cases:

  1. If you have not been typing the code in from scratch during the other labs, you should export a clean copy of the code from the seminar repository, as we will use the fresh copy as the basis for our first check-in to your own repository.
  2. If you have been typing in the code from scratch, you should still get a clean copy of the code and stash it in a temporary directory so it will be easier to copy a few files over to your project when we call them out later in this write-up.

First, go in to your command line and make a new directory. Consult your operating system documentation if you aren’t familiar with this process.

Next, change your current working directory to be in the new directory. List the directory contents. It should be empty.

Now, pull down the latest code with the Subversion command:

svn export --username student http://railsquickstart.unfuddle.com/svn/railsquickstart_labs/trunk/labs

If you don’t remember the password, check the Files area of the private Google group for a document that lists the shared passwords.

You should see various messages fly by. You will see something like this (most of the middle messages were deleted here for space):

A    labs
A    labs/test
A    labs/test/unit
A    labs/test/unit/user_test.rb
A    labs/test/unit/asset_test.rb
...
A    labs/public/.htaccess
A    labs/public/stylesheets
A    labs/public/stylesheets/quickstart.css
A    labs/public/stylesheets/scaffold.css
A    labs/public/favicon.ico
Exported revision 10.	

Once the code is downloaded, list your directory again. You should see a labs directory. Change directory into labs.

If you have been typing in your own copy, change directory into that location instead.

Pushing clean copy into your repository

You are now ready to import the clean code base into Subversion. In this lab, we are using the Unfuddle service. Unfuddle provides Subversion hosting as well as a number of other useful project management tools (like notes, todo lists, issue tracking, etc.). You received an Unfuddle account welcome sheet at the seminar, and you’ll need to substitute information from that sheet into the following commands.

Issue the Subversion import command to establish your new repository:

svn import --username rqsXX_deploy http://rqsXX.unfuddle.com/svn/rqsXX_labs/trunk/labs -m "Initial import"

Substitute your Unfuddle account number for all three instances of XX in the above command. On pressing return, you should see a number of messages fly by indicating that your source is being imported. You will be queried for your password. If you need a reminder of the deploy account password, see the document in the Files area of the Google group.

Here is what this step looks like on my machine (again, cutting out a chunk of “Adding” messages in the middle):

Necrons:~/Development/work/labs chaupt$ svn import --username rqsXX_deploy http://rqsXX.unfuddle.com/svn/rqsXX_labs/trunk/labs -m "Initial import"
Authentication realm: <http://rqsXX.unfuddle.com:80> Unfuddle Repository
Password for 'rqs21_deploy': 
Adding         test
Adding         test/unit
Adding         test/unit/user_test.rb
Adding         test/unit/asset_test.rb
Adding         test/unit/customer_test.rb
Adding         test/unit/contact_mailer_test.rb
...
Adding         public/422.html
Adding         public/.htaccess
Adding         public/stylesheets
Adding         public/stylesheets/quickstart.css
Adding         public/stylesheets/scaffold.css
Adding         public/favicon.ico

Committed revision 1.

Once the source is imported into your own repository, you can delete the local version in preparation for checking out a version-controlled copy. If you checked in your own, typed in source, keep the spare copy of the lab source in a temporary directory, you’ll want to refer to it later.

Change directory up one level from the labs (or your own) directory and use the appropriate operating system command to delete the labs directory. If you are worried about doing this, archive a copy in a safe place.

First checkout of version-controlled source

Choose where you are going to keep your development directory. Either stay in the current location or change directory to some other place now. Once ready, issue the Subversion checkout command to get a version controlled copy of your source code:

svn co --username rqsXX_deploy http://rqsXX.unfuddle.com/svn/rqsXX_labs/trunk/labs

Again, remember to substitute your Unfuddle account number for XX.

The results will be a long list of files:

Necrons:~/Development/work chaupt$ svn co --username rqsXX_deploy http://rqsXX.unfuddle.com/svn/rqsXX_labs/trunk/labs
A    labs/test
A    labs/test/unit
A    labs/test/unit/user_test.rb
A    labs/test/unit/asset_test.rb
A    labs/test/unit/customer_test.rb
A    labs/test/unit/contact_mailer_test.rb
...
A    labs/public/.htaccess
A    labs/public/stylesheets
A    labs/public/stylesheets/quickstart.css
A    labs/public/stylesheets/scaffold.css
A    labs/public/favicon.ico
Checked out revision 1.

You have now placed your code into source code control, and you have a copy with all of Subversion’s special metadata on your local disk. From here on out, you need to remember that you must use Subversion commands to manipulate files, and not your operating system commands. The Subversion Book is a free, complete reference book about using Subversion that you might want to consult.

Change directory into the newly checked out code. If you’re using our default name, you would enter the labs directory.

2. Configuring Capistrano

Our next step is to prepare your project for using the Capistrano utility. Capistrano is a tool that can run commands and scripts (sometimes called recipes or tasks) on remote computers. This is particularly handy as you will by issuing the same commands over and over again as you develop your application and it is a pain to continually log in to one or more remote computers, type a bunch of commands, then do it again.

Note that you enter all Capistrano commands in your local terminal, even though the Capistrano scripts perform actions on your server. Capistrano makes an SSH connection to the server and issues commands there.

a. Capify your project

Make sure you are in your project’s directory now. You should be at the top level of the Rails application that you just checked out. Make extra certain you are in that directory or the rest of this lab will not work! If you list the contents of this directory, you should see the folders app, config, etc.

Issue the capify command to create the initial Capistrano configuration files:

capify .

Note that period at the end. If you are using the seminar provided code, you will see some “skip” messages, otherwise you will see a couple of files are created:

Necrons:~/Development/work/test chaupt$ capify .
[add] writing `./Capfile'
[add] writing `./config/deploy.rb'
[done] capified!

b. Copy in lab provided recipes

This step is only for those of you working on your own project or typing in the labs from scratch. If you are using the exported seminar files, you can skip this step.

To complete this step you will need access to the lab files (or the attachments to this write-up).

First, replace the config/deploy.rb file with the one we provide.

Second, create the file config/mongrel_cluster.yml and put the following contents inside:

port: 8000
pid_file: /tmp/`hostname`-mongrel.pid
servers: 4
environment: production
address: 127.0.0.1

The mongrel_cluster.yml file specifies on which ports your application server will listen, waiting for traffic to be forwarded to it from Apache. In the default Joyent configuration we are using, four instances of the app server are expected. By default, the app servers will listen on ports 8000, 8001, 8002, and 8003. The corresponding Apache configuration file that is generated during setup will use those ports too.

If you have another application on the same server, you will want to minimally change the port number to be a set of four ports outside of the 8000-8003 range.

Third, copy the lab’s config/accelerator directory into your config directory. It should contain three files: accelerator_tasks.rb, apache_vhost.erb, smf_template.erb.

Lastly, copy the lab’s config/quickstart directory into your config directory. It should contain one file: quickstart_tasks.rb.

At the command line at the top level of your project, issue the command cap -T. You should see something like this:

cap accelerator:create_smf          # Adds a SMF for the application
cap accelerator:create_vhost        # Creates an Apache 2.2 compatible virtua...
cap accelerator:restart_apache      # Restart apache
cap accelerator:setup_smf_and_vhost # After setup, creates Solaris SMF config...
cap accelerator:smf_delete          # Deletes the configuration
cap accelerator:smf_restart         # Restarts the application
cap accelerator:smf_start           # Starts the application
cap accelerator:smf_stop            # Stops the application
cap accelerator:svcs                # Shows all Services
cap deploy                          # Deploys your project.
cap deploy:check                    # Test deployment dependencies.
cap deploy:cleanup                  # Clean up old releases.
cap deploy:cold                     # Deploys and starts a `cold' application.
cap deploy:migrate                  # Run the migrate rake task.
cap deploy:migrations               # Deploy and run pending migrations.
cap deploy:pending                  # Displays the commits since your last de...
cap deploy:pending:diff             # Displays the `diff' since your last dep...
cap deploy:rollback                 # Rolls back to a previous version and re...
cap deploy:rollback_code            # Rolls back to the previously deployed v...
cap deploy:setup                    # Prepares one or more servers for deploy...
cap deploy:symlink                  # Updates the symlink to the most recentl...
cap deploy:update                   # Copies your project and updates the sym...
cap deploy:update_code              # Copies your project to the remote servers.
cap deploy:upload                   # Copy files to the currently deployed ve...
cap deploy:web:disable              # Present a maintenance page to visitors.
cap deploy:web:enable               # Makes the application web-accessible ag...
cap invoke                          # Invoke a single command on the remote s...
cap quickstart:copy_revision_info   # Make REVISION available from site
cap quickstart:get_db_dump          # Retrieve production DB Dump
cap quickstart:tail_server_logs     # Tail production server log files
cap shell                           # Begin an interactive Capistrano session.

Some tasks were not listed, either because they have no description,
or because they are only used internally by other tasks. To see all
tasks, type `cap -Tv'.

Extended help may be available for these tasks.
Type `cap -e taskname' to view it.

Note the accelerator and quickstart lines. If you don’t see those, you didn’t copy the lab files correctly. Go back and check that they are in your config directory.

c. Update deploy.rb with your info

Open up the deploy.rb file with a programmer’s editor. We are going to change the project metadata so it points to your personal Accelerator and Subversion repository. Each area we need to edit has a TODO comment immediately above it.

First, if you are not using the name “labs” for your application, change this line:

#
# TODO: change to your application (labs)
#
set :application, "labs"

The name of your application is typically the name of the directory your code is sitting in. Rails created this directory if you started your project from scratch. If you peek inside of your config/database.yml file, your application name was also used as the root of the database name (e.g. labs_production).

In this write-up, we assume you are using “labs” for the rest of the exercise. We will point out other places you need change but not always provide full commands in those cases.

Next, change the location of your Subversion repository:

#
# TODO: change to your subversion repository (railsquickstart -> rqsNN) (_quickstart -> _labs)
#
set :repository,  "http://railsquickstart.unfuddle.com/svn/railsquickstart_labs/trunk/#{application}"

Here, you should change the words “railsquickstart” (two of them) to rqsXX, where XX is your Unfuddle number:

set :repository,  "http://rqsXX.unfuddle.com/svn/rqsXX_labs/trunk/#{application}"

Your IP number is on the credentials welcome page you were handed at the seminar. Update the IP number of the Accelerator you were assigned to in the domain setting:

#
# TODO: Put your public IP here
#
set :domain, '8.17.170.221'

Also on the credentials welcome page, find your zone name. This is at the top of the paper and is part of From: line of the email. Look for the string that starts with a “Z” and then followed by a seven digit number (e.g. “z1234567”).

Update the deploy.rb file’s server name and alias lines with your zone name:

#
# TODO: Put your domain name here (zNNNNNAA.textdrive.com)
#
set :server_name, "zNNNNNAA.textdrive.com"
set :server_alias, "*.zNNNNNAA.textdrive.com"

Save the file.

d. Checkin your changes

You need to save the changes you have made into your Subversion repository. If you are working with your own code, you have a few extra steps to add files into the repository. Start by typing:

svn status

You will see a list of files that have been added (an initial question mark is displayed) or files that have been modified (an initial M is displayed):

?      Capfile
?      config/accelerator
?      config/quickstart
?      config/deploy.rb

For all files that are new (need to be added), issue this command (substituting “filename” below with the full path/name string shown above):

svn add filename

Once you have added all files, issue the svn status command again and be certain no question marks show up.

Now, check-in your files with:

svn ci -m "Deployment files"

and you will see something akin to:

Sending        config/deploy.rb
Transmitting file data ...
Committed revision 2.	

You should now be all set. If you issue another svn status at this point, no files should be shown.

3. Setting up the server

Before starting the deployment process, you need to tweak a few things on your production server.

a. Logging in to the server shell

Its time to switch over to your Accelerator and make sure you can log in. Using your IP address, fire up your secure shell program and log in (substitute your IP number for the XXX):

ssh deploy@8.17.170.XXX
Password: 
Last login: Wed Mar  5 18:22:49 2008 from 76.14.mmm.nnn
                                __                       __ 
                       __      / /___  __  _____  ____  / /_
                    __/ /___  / / __ \/ / / / _ \/ __ \/ __/
                   /_  __/ /_/ / /_/ / /_/ /  __/ / / / /_  
                    /_/  \____/\____/\__, /\___/_/ /_/\__/  
                                    /____/ Accelerators
[z1234567:~] deploy$

You will need to use the deploy account’s default password (see the Files are of the Google group if you can’t remember what it is). You will want to change it once you have set things up. See the follow-up section at the end of this article.

b. Database setup

If you are not using labs as your application (and database) name, or are not using the default database credentials (username and password: seminar), you need to configure a production database now. From the server’s shell do the following:

  1. mysql -p -u root
  2. create database myapp_production;
  3. grant all on myapp_production.* to ’username’@’localhost’ identified by ‘password’;

When asked for the password, use the password supplied for MySQL root access on your Accelerator welcome paper. Instead of _myapp_production_, replace myapp with the name of the application you specified in the deploy.rb file and your database.yml file, and replace “username” and “password” with whatever you want to use. Remember that these need to match the username and password specified in your database.yml file for the production database.

Here is what my commands looked like:

[z1234567:~] deploy$ mysql -p -u root
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.0.37-log Source distribution

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> create database myapp_production;
Query OK, 1 row affected (0.00 sec)

mysql> grant all on myapp_production.* to 'seminar'@'localhost' identified by 'seminar';
Query OK, 0 rows affected (0.00 sec)

mysql> exit
Bye
[z1234567:~] deploy$ 

c. Update gems

The Accelerators are not currently completely up-to-date with the versions of Ruby gems we need for our projects. Let’s update them now.

While still logged in to your private Accelerator issue this command:

sudo gem install -f gem_plugin rails RedCloth

After a while, you should see results similar to the this:

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.

Password:
Updating metadata for 335 gems from http://gems.rubyforge.org
...............................................................................................................................................................................................................................................................................................................................................
complete
Successfully installed gem_plugin-0.2.3
Successfully installed rake-0.8.1
Successfully installed activesupport-2.0.2
Successfully installed activerecord-2.0.2
Successfully installed actionpack-2.0.2
Successfully installed actionmailer-2.0.2
Successfully installed activeresource-2.0.2
Successfully installed rails-2.0.2
Successfully installed RedCloth-3.0.4
9 gems installed
Installing ri documentation for gem_plugin-0.2.3...
Installing ri documentation for rake-0.8.1...
Installing ri documentation for activesupport-2.0.2...
Installing ri documentation for activerecord-2.0.2...
Installing ri documentation for actionpack-2.0.2...
Installing ri documentation for actionmailer-2.0.2...
Installing ri documentation for activeresource-2.0.2...
Installing RDoc documentation for gem_plugin-0.2.3...
Installing RDoc documentation for rake-0.8.1...
Installing RDoc documentation for activesupport-2.0.2...
Installing RDoc documentation for activerecord-2.0.2...
Installing RDoc documentation for actionpack-2.0.2...
Installing RDoc documentation for actionmailer-2.0.2...
Installing RDoc documentation for activeresource-2.0.2...	

Note your output may be slightly different if you have used sudo already or otherwise touched your gems.

4. Deployment setup and sanity check

Go ahead and logout out of the secure shell session and make sure you are back in your local development machine’s code directory. We are going to do a few one-time setup tasks to get your application prepared and get Capistrano primed for use.

a. Deploy setup step

Capistrano uses a particular remote directory structure for its deployments. Inside of your application area on the remote server (/var/www/apps with our default settings), Capistrano will create a directory for your application, and within that, it will create three additional directories.

The first will be a releases area. This is where Capistrano checks out each version of your application. Capistrano is smart about keeping versions separate, as well as keeping old versions of the application around. It does this so if something goes wrong with a deployment, it is possible to revert to a prior version quickly.

Second, Capistrano creates a soft link (also known as an alias) called current. Current will always point to the active application directory in the releases area (this will normally be the most recent version). Capistrano manages this link for you.

Lastly, Capistrano will make a shared directory. Shared is used for common directories and files that will be used across deployments. Your log files end up in this directory, for instance.

In addition, for our environment, Capistrano does a couple of other housekeeping tasks for us. For one, it generates an Apache VHost configuration for our application. For another, it links our application with the Solaris System Management Facility (SMF). SMF is the tool that starts and stops our application, both at system startup and shutdown as well as whenever we do a deployment.

To set this all up, issue the setup command:

cap deploy:setup

You only do this one time, and the results should look something like:

  * executing `deploy:setup'
  * executing "umask 02 && mkdir -p /var/www/apps/labs /var/www/apps/labs/releases /var/www/apps/labs/shared /var/www/apps/labs/shared/system /var/www/apps/labs/shared/log /var/www/apps/labs/shared/pids"
    servers: ["8.17.170.221"]
Password: 
    [8.17.170.221] executing command
    command finished
    triggering after callbacks for `deploy:setup'
  * executing `accelerator:setup_smf_and_vhost'
  * executing `accelerator:create_smf'
set variables
    servers: ["8.17.170.221"]
  * uploading /var/www/apps/labs/shared/labs-smf.xml
 ** uploading data to 8.17.170.221:/var/www/apps/labs/shared/labs-smf.xml
  * done uploading data to 8.17.170.221:/var/www/apps/labs/shared/labs-smf.xml
    upload finished
  * executing "sudo -p 'sudo password: ' svccfg import /var/www/apps/labs/shared/labs-smf.xml"
    servers: ["8.17.170.221"]
    [8.17.170.221] executing command
*** [err :: 8.17.170.221] 
    command finished
  * executing `accelerator:create_vhost'
  * executing "ifconfig -a | ggrep -A1 e1000g0 | grep inet | awk '{print $2}'"
    servers: ["8.17.170.221"]
    [8.17.170.221] executing command
    command finished
    servers: ["8.17.170.221"]
  * uploading /var/www/apps/labs/shared/labs-apache-vhost.conf
 ** uploading data to 8.17.170.221:/var/www/apps/labs/shared/labs-apache-vhost.conf
  * done uploading data to 8.17.170.221:/var/www/apps/labs/shared/labs-apache-vhost.conf
    upload finished
  * executing "sudo -p 'sudo password: ' cp /var/www/apps/labs/shared/labs-apache-vhost.conf /opt/csw/apache2/etc/virtualhosts/labs.conf"
    servers: ["8.17.170.221"]
    [8.17.170.221] executing command
    command finished
  * executing `accelerator:restart_apache'
  * executing "sudo -p 'sudo password: ' svcadm refresh svc:/network/http:cswapache2"
    servers: ["8.17.170.221"]
    [8.17.170.221] executing command
    command finished	

For this and future Capistrano commands, you will often need to supply a password. This is your deploy account’s password (see the Files area of the Google group if you can’t remember the default password. If you change it, remember what you changed it to!).

(Note: There is an error line in the above output. We are tracking that down, but it appears to be benign at the moment.)

b. Check setup

Let’s confirm that the environment is set up as Capistrano expects it should be:

cap deploy:check

A long list of status messages will flow by, but if you have followed all of the steps up to this point, you should get a message You appear to have all necessary dependencies installed. If so, you are ready for the first deployment. If not, go back and check to see what piece is missing.

5. Cold deployment

The very first time you deploy an application with Capistrano, you have to boot-strap the environment. For instance, your database tables don’t exist yet, so you need to be sure migrations have been run. Also, since you haven’t loaded the app yet, the application servers don’t need to be shutdown and restarted. This initial deployment is called the cold deployment. Like all other tasks, Capistrano has a command to help with this case.

a. Going from cold to warm

Like setup, cold deployment only happens once, the very first time you deploy a specific application. To get started, issue this command:

cap deploy:cold

Capistrano proceeds to check out your code from your Subversion repository, sets up the current link to the code, migrates the database, and starts the application. Here is a log of my cold deployment; yours should looks something similar to the following if you are using the seminar code:

  * executing `deploy:cold'
  * executing `deploy:update'
 ** transaction: start
  * executing `deploy:update_code'
  * executing "svn checkout -q --username deploy --password SECRET --no-auth-cache  -r1 http://rqs21.unfuddle.com/svn/rqs21_labs/trunk/labs /var/www/apps/labs/releases/20080306031255 && (echo 1 > /var/www/apps/labs/releases/20080306031255/REVISION)"
    servers: ["8.17.170.221"]
Password: 
    [8.17.170.221] executing command
    command finished
  * executing `deploy:finalize_update'
  * executing "chmod -R g+w /var/www/apps/labs/releases/20080306031255"
    servers: ["8.17.170.221"]
    [8.17.170.221] executing command
    command finished
  * executing "rm -rf /var/www/apps/labs/releases/20080306031255/log /var/www/apps/labs/releases/20080306031255/public/system /var/www/apps/labs/releases/20080306031255/tmp/pids &&\n      mkdir -p /var/www/apps/labs/releases/20080306031255/public &&\n      mkdir -p /var/www/apps/labs/releases/20080306031255/tmp &&\n      ln -s /var/www/apps/labs/shared/log /var/www/apps/labs/releases/20080306031255/log &&\n      ln -s /var/www/apps/labs/shared/system /var/www/apps/labs/releases/20080306031255/public/system &&\n      ln -s /var/www/apps/labs/shared/pids /var/www/apps/labs/releases/20080306031255/tmp/pids"
    servers: ["8.17.170.221"]
    [8.17.170.221] executing command
    command finished
  * executing "find /var/www/apps/labs/releases/20080306031255/public/images /var/www/apps/labs/releases/20080306031255/public/stylesheets /var/www/apps/labs/releases/20080306031255/public/javascripts -exec touch -t 200803060315.34 {} ';'; true"
    servers: ["8.17.170.221"]
    [8.17.170.221] executing command
    command finished
  * executing `deploy:symlink'
  * executing "rm -f /var/www/apps/labs/current && ln -s /var/www/apps/labs/releases/20080306031255 /var/www/apps/labs/current"
    servers: ["8.17.170.221"]
    [8.17.170.221] executing command
    command finished
 ** transaction: commit
  * executing `deploy:migrate'
  * executing "ls -x /var/www/apps/labs/releases"
    servers: ["8.17.170.221"]
    [8.17.170.221] executing command
    command finished
  * executing "cd /var/www/apps/labs/releases/20080306031255; rake RAILS_ENV=production  db:migrate"
    servers: ["8.17.170.221"]
    [8.17.170.221] executing command
 ** [out :: 8.17.170.221] (in /var/www/apps/labs/releases/20080306031255)
 ** [out :: 8.17.170.221] == 1 CreateContentBlocks: migrating ===========================================
 ** [out :: 8.17.170.221] -- create_table(:content_blocks)
 ** [out :: 8.17.170.221] -> 0.0218s
 ** [out :: 8.17.170.221] == 1 CreateContentBlocks: migrated (0.0220s) ==================================
 ** [out :: 8.17.170.221] 
 ** [out :: 8.17.170.221] == 2 CreateAssets: migrating ==================================================
 ** [out :: 8.17.170.221] -- create_table(:assets)
 ** [out :: 8.17.170.221] -> 0.0180s
 ** [out :: 8.17.170.221] == 2 CreateAssets: migrated (0.0181s) =========================================
 ** [out :: 8.17.170.221] 
 ** [out :: 8.17.170.221] == 3 CreateUsers: migrating ===================================================
 ** [out :: 8.17.170.221] -- create_table("users", {:force=>true})
 ** [out :: 8.17.170.221] -> 0.0031s
 ** [out :: 8.17.170.221] == 3 CreateUsers: migrated (0.0033s) ==========================================
 ** [out :: 8.17.170.221] 
 ** [out :: 8.17.170.221] == 4 CreateLinks: migrating ===================================================
 ** [out :: 8.17.170.221] -- create_table(:links)
 ** [out :: 8.17.170.221] -> 0.0069s
 ** [out :: 8.17.170.221] == 4 CreateLinks: migrated (0.0070s) ==========================================
 ** [out :: 8.17.170.221] 
 ** [out :: 8.17.170.221] == 5 CreateCategories: migrating ==============================================
 ** [out :: 8.17.170.221] -- create_table(:categories)
 ** [out :: 8.17.170.221] -> 0.0018s
 ** [out :: 8.17.170.221] == 5 CreateCategories: migrated (0.0020s) =====================================
 ** [out :: 8.17.170.221] 
 ** [out :: 8.17.170.221] == 6 AddLinkCategoryJoin: migrating ===========================================
 ** [out :: 8.17.170.221] -- create_table(:categories_links, {:id=>false})
 ** [out :: 8.17.170.221] -> 0.0014s
 ** [out :: 8.17.170.221] == 6 AddLinkCategoryJoin: migrated (0.0016s) ==================================
 ** [out :: 8.17.170.221] 
 ** [out :: 8.17.170.221] == 7 CreateContacts: migrating ================================================
 ** [out :: 8.17.170.221] -- create_table(:contacts)
 ** [out :: 8.17.170.221] -> 0.0133s
 ** [out :: 8.17.170.221] == 7 CreateContacts: migrated (0.0134s) =======================================
 ** [out :: 8.17.170.221] 
 ** [out :: 8.17.170.221] == 8 AddDefensioColumnsToContacts: migrating ==================================
 ** [out :: 8.17.170.221] -- add_column(:contacts, :spam, :boolean, {:default=>false})
 ** [out :: 8.17.170.221] -> 0.0037s
 ** [out :: 8.17.170.221] -- add_column(:contacts, :spaminess, :float)
 ** [out :: 8.17.170.221] -> 0.0034s
 ** [out :: 8.17.170.221] -- add_column(:contacts, :signature, :string)
 ** [out :: 8.17.170.221] -> 0.0036s
 ** [out :: 8.17.170.221] == 8 AddDefensioColumnsToContacts: migrated (0.0110s) =========================
 ** [out :: 8.17.170.221] 
 ** [out :: 8.17.170.221] == 9 CreateCustomers: migrating ===============================================
 ** [out :: 8.17.170.221] -- create_table(:customers)
 ** [out :: 8.17.170.221] -> 0.0027s
 ** [out :: 8.17.170.221] == 9 CreateCustomers: migrated (0.0028s) ======================================
 ** [out :: 8.17.170.221] 
 ** [out :: 8.17.170.221] == 10 CreateSubscriptions: migrating ==========================================
 ** [out :: 8.17.170.221] -- create_table(:subscriptions)
 ** [out :: 8.17.170.221] -> 0.0041s
 ** [out :: 8.17.170.221] == 10 CreateSubscriptions: migrated (0.0043s) =================================
 ** [out :: 8.17.170.221] 
    command finished
  * executing `deploy:start'
  * executing `accelerator:smf_start'
  * executing "sudo -p 'sudo password: ' svcadm enable -r /network/mongrel/labs-production"
    servers: ["8.17.170.221"]
    [8.17.170.221] executing command
*** [err :: 8.17.170.221] 
    command finished
  * executing `accelerator:restart_apache'
  * executing "sudo -p 'sudo password: ' svcadm refresh svc:/network/http:cswapache2"
    servers: ["8.17.170.221"]
    [8.17.170.221] executing command
    command finished

We are very close to testing our app out. One more thing step!

b. Warm to hot

A small quirk of the Accelerator environment and the System Management Facility requires that we restart the mongrel application server to get it going. We can start, stop, and restart our application using Capistrano, of course. For this task, issue:

cap accelerator:smf_restart

Remember to enter this in your local terminal, not in an SSH session.

You will see results something like this:

  * executing `accelerator:smf_restart'
  * executing `accelerator:smf_stop'
  * executing "sudo -p 'sudo password: ' svcadm disable /network/mongrel/labs-production"
    servers: ["8.17.170.221"]
Password: 
    [8.17.170.221] executing command
*** [err :: 8.17.170.221] 
    command finished
  * executing `accelerator:smf_start'
  * executing "sudo -p 'sudo password: ' svcadm enable -r /network/mongrel/labs-production"
    servers: ["8.17.170.221"]
    [8.17.170.221] executing command
    command finished

Again, that error in this case is Capistrano and Joyent misbehaving, and is benign at the moment.

c. Try it!

Fire up your browser and hit the URL http://8.17.170.XXX where XXX is your correct IP number.

Success!

6. Normal deployment

After the initial deployment, your work will typically fall into a pattern of incremental improvements to your code, and then deploying to move that (tested!) code into production. There are two common scenarios.

a. Deploying code only

When you need to get code into production and haven’t made any changes to your database, you use Capistrano’s standard deploy command:

cap deploy

The deploy command checks out your code into the releases directory, stops the application server, switches the current directory link, and finally restarts the application server.

b. Deploying with database changes

If you’ve made changes to your model, and you have migrations that need to be run, Capistrano has a special command for this scenario. Rather than the plain cap deploy command shown above, use:

cap deploy:migrations

Like the plain deploy command, deploy:migrations checks out your code, stops the application server, switches the current link, and starts the server again. In addition, it inserts a step to run any pending migrations after the new code is checked out and the server is stopped.

c. Dealing with slower deployment

The deployment process can be pretty quick, but there may be a small window of time in which your users would see a non-responsive application. If you need a little time to get the deployment done, Capistrano has a built in ability to display a “down for maintenance” page. As this page is served directly by Apache, it isn’t affected by the general deployment process.

To turn on the maintenance page:

cap deploy:web:disable 	

and then reenable the app:

cap deploy:web:enable 	

7. Common tasks

a. Checking the production logs

Logs are located in /var/www/apps/labs/shared/log (substitute your application name for labs if need be). You can log in to the server and run:

tail -f production.log

and watch your application in real-time. Alternatively, if you don’t want to log in, we’ve provided a Capistrano task for this case. You can use this within your application directory on your local development machine:

cap quickstart:tail_server_logs

b. Check server to see if it is running

If you are logged in to the server, you can use the SMF command svcs to see a list of server processes that are running. A process in a healthy state will be online:

online         20:18:47 svc:/network/http:cswapache2
online         20:24:58 svc:/network/mongrel/labs-production:default

You can get this list on your local development machine with:

cap accelerator:svcs

If you see an application in maintenance, something is wrong. You can try restarting it with cap accelerator:restart_apache for Apache or cap accelerator:smf_restart for mongrel.

c. Stopping and starting apps on the server

The Capistrano versions of starting or stopping mongrel are cap accelerator:smf_start and cap accelerator:smf_start.

If you need to do start or stop an application while logged in to the server, you need to first locate the SMFURL. Issue the svcs command, and look for the third column that starts with svc. Note the string. To stop an application, use:

sudo svcadm disable svc:/network/http:cswapache2

and to start an application use:

sudo svcadm enable svc:/network/http:cswapache2

Swap the svc string with the appropriate identifier for the target application.

d. Apache configuration

Apache is located in /opt/csw/apache2 in case you need to tweak the configurations. Look inside of the /opt/csw/apache2/etc directory.

If you change the apache config, restart Apache, using Capistrano: cap accelerator:restart_apache

f. Download your production database data for use in local development

We’ve written a custom Capistrano task that you can use to grab a copy of your production data from the MySQL database on the Accelerator:

cap quickstart:get_db_dump

Once you’ve downloaded your data, you can import it into your local MySQL database and use it for local testing using a command such as:

mysql -p -u root labs_development < dumpfilename

substituting the name of your database for labs_development and the actual name of the dump file for dumpfilename.

Further Exercises

  1. Change all of your passwords to make your personal servers secure:
    1. Change deployer password in shell;
    2. Change deployer password in unfuddle;
    3. Change mysql password in shell.
  2. Change the email addresses used by your app and accounts:
    1. Change email address at unfuddle;
    2. Change the addresses used by the sample app (if you are using it).
  3. Write your own Capistrano tasks. Check out the quickstart_tasks.rb for some examples.

Viewing all articles
Browse latest Browse all 27

Trending Articles