Launched 3 sites very quickly. Spent some time working on platform, making it very robust. Tools. Going back to site mode soon.
Almost everyone starts out with Django writing a Blog.
Webserver: Use Apache, mod_wsgi, daemon mode. Threads more efficient, but make sure your code is thread safe. If in doubt, use processes.
put nginx in front of apache. nginx serves media directory. forwards app requests to apache. load balancing becomes easy
Probably need data storage, probably a relational DB: PostgreSQL or MySQL For tips on tuning, visit Frank Wiles @revsys for PostgreSQL or Percona (mysqlperformanceblog.com) for MySQL.
Do yourself a favor and run Memcached. Having a small server, even as little as 16MB will help tremendously with Django's Cache middleware.
With a single server, you're able to get away with simple deployment. Manual copy of files via SCP or Rsync. Manual restart the web server or touch the wsgi file. Manual DB migrations.
Moving beyond a single server. Move the database to it's own box. Lots of RAM. As much as you can afford. If you do a lot of writes, get fast disks, too. SCSI 15k RPM. Take advantage of RAID if you can afford it. Tune your DB setup.
Add more web servers. Your app will either be CPU or memory bound. Characteristics different per app. Use a tool like Munin to visualize and understand your app's resource usage.
All sorts of additional boxes that need some or all of your code base to operate.
Basic deployment isn't so basic anymore.
More deployment requirements - deploy media to S3/Cloudfront or your favorite CDN - splash page to indicate site maintenance - db migrations - add a new web server to the cluster - install/upgrade python package dependencies - execution of arbitrary commands (invoke) for easy sys-admin tasks
Two options... Capistrano or Fabric Capistrano more mature. + Out of the box support for a number of common tasks. + Before / After hooks built in for each task to allow for extending. + Interfaces for all common source control mgmt systems + Supports simultaneous deployment to all hosts at once. - It's in Ruby
Fabric is rather new, not nearly as mature. Doesn't have a lot of stuff built in besides command invocation. Everyone's deployment needs vary because everyone has slightly different production architectures. Not the end of the world that Fabric doesn't have everything built in.
Core functions: local() run() sudo()
Fabric's auth model is based on the underlying SSH model.
Fabric stores config info in it's environment object. just a dictionary, can add any info you want
Use env.roledefs dictionary to configure roles-to-hosts. Since it's just a dictionary, you can store whatever config data you want
The nuts and bolts of the command execution model. Essentially you invoke one or more tasks. Tasks can in turn invoke other tasks. Tasks are just Python functions. Any function within fabfile.py that doesn't begin with an _ is considered a task. TIP: If you're importing functions into your fabfile.py for use, import the module they're contained in instead. That way they don't show up as tasks.
Decorators
There's some problems with Fabric's role system out of the box. Attempting to override the defaults from the command line don't really work well. The maintainers acknowledge this -- and they're waiting on a fix until they nail down the syntax. But they're easy enough to fix now by writing our own decorators. These decorators extend Fabric's built in @roles and @hosts. With these, If you don't specify a host or role on the command line, the tasks will be executed with whatever the default is provided in the decorator. This is how the docs suggest Fabric is supposed to work -- but I didn't have luck with it.
Once we have a sane execution model, we can continue writing some tasks.
List of Whiskey's Fabric tasks
Chaining of tasks is as simple as one Python function calling another. Each function being referenced here is a separate Fabric task, each of which could be called independently. 95% of the time, this function is used.