Plone on WSGI sprint report
Two laptops, two sprinters and two bottles of whiskey. What could possibly go wrong?
This is my attempt to document what I can only describe as the “Plone on Whisk-gi” sprint… As part of the Plone deployment sprint at the recent Plone Conference in Bristol, Reed O’Brien and I decided to try to get Plone 4 working on WSGI.
Why is this important? Hanno Schlichting (current Zope2 release manager) tells us on his blog post about the recent Zope 2.13 release:
Zope 2.13 comes with native WSGI support. First pioneered in the repoze.zope2 project, this capability finally found its way back into the core and obsoletes the externally managed project. With WSGI, Zope 2 can natively talk to a variety of web servers and isn’t restricted to its own ZServer anymore. It also opens up new possibilities for writing or reusing middleware in Zope 2 or factoring out capabilities into WSGI endware. It’s expected that this new deployment model will over time become the default and the old ZServer implementation will be deprecated. There’s no concrete timeline for this yet.
What is Hanno saying here? Basically, it means that Zope 2.13 (and subsequently Plone) can run on a server without the added complexity of a long-running process (ZServer). Just as PHP-based applications enjoy ease of deployment since Apache already has mod_php enabled, so too could Zope-based applications be easily deployed if mod_wsgi were enabled.
In thinking about how Plone and Zope can be more accessible to systems administrators and hosting companies, moving to a scenario in which Zope does not require a separate long-running process, and can be deployed essentially at the Apache layer is a step in the right direction.
As Hanno alludes to above, with the WSGI deployment model, Zope/Plone are able to tap into a whole ecosystem of 3rd party WSGI middleware tools. Repoze is an initiative to extract many of the core Zope technologies into reusable WSGI middleware components, that can be used in other Python web application frameworks. More WSGI components can be found on PyPi by searching for “wsgi”.
Also, by adopting a more typical deployment method, Zope will not seem so exotic to developers coming to Zope from other Python web frameworks. For example, the official Django documentation recommends deploying Django using mod_wsgi, so Django developers will likely already be familiar with this way of deploying Python web applications. Incidentally, if you’re doing Django development, check out twod.wsgi which makes WSGI a first-class citizen in Django applications.
How does Plone fit in this picture?
Plone, arguably being the most popular Zope2 application on the market, can stand to benefit from the WSGI deployment strategy. There have already been some efforts to do so with repoze.plone and repoze.zope2 (now deprecated with the release of Zope 2.13).
Calvin Hendrix Parker blogged about deploying Plone and Zine together with Deliverance using Repoze, and Wojciech Lichota blogged about his buildout for Plone 3 with Deliverance on WSGI. Nathan Van Gheem has also written a couple blog posts about his experiences running Plone 4 with a Zope2 WSGI and running Plone 4b4 with Zope 2.13.0a1.
Now that Plone 4 is officially out and Zope 2.13 has had a final release, the instructions for getting this working are considerably easier.
Here are the steps required to get Plone 4 running under WSGI using paster.
1. Create a buildout.cfg file with the following:
[buildout]
extends =
http://dist.plone.org/release/4.0.1/versions.cfg
http://download.zope.org/zopetoolkit/index/1.0/zopeapp-versions.cfg
http://download.zope.org/Zope2/index/2.13.0/versions.cfg
parts =
instance
paster
versions = versions
eggs +=
roman
Products.ZSQLMethods
[versions]
Zope2=2.13.0
Products.ZSQLMethods = 2.13.3
[instance]
recipe = plone.recipe.zope2instance
user = admin:admin
eggs +=
${buildout:eggs}
Plone
Paste
PasteScript
PasteDeploy
repoze.tm2
repoze.retry
[paster]
recipe = repoze.recipe.egg
scripts = paster
eggs = ${instance:eggs}
2. Create a zope2.ini file:
[DEFAULT]
debug = True
[app:zope]
use = egg:Zope2#main
zope_conf = %(here)s/parts/instance/etc/zope.conf
[pipeline:main]
pipeline =
egg:paste#evalerror
egg:repoze.retry#retry
egg:repoze.tm2#tm
zope
[server:main]
use = egg:paste#http
host = localhost
port = 8080
3. Run the buildout and modify the zope.conf file:
Run the buildout which will generate the paster script in the bin dir and the zope.conf file in parts/instance/etc. You then need to comment out the <http-server> part in this file. If you don’t comment out these lines, then paster will complain that there is already a server running on port 8080.
#<http-server> # valid keys are "address" and "force-connection-close" # address 8080# #</http-server>
4. Start up paster using the zope2.ini file:
$ paster serve zope2.ini Starting server in PID 4666. serving on http://127.0.0.1:8080
You can now go to http://127.0.0.1:8080 to see your Plone site served up by Zope on WSGI!
In the next blog post, we will describe how to get this semi-working in a production environment using mod_wsgi. For a sneak preview you can check out this buildout that Reed put together at the sprint. Note that there are a few patches that must be applied to Zope2, and hopefully Tres Seaver is reading this and will respond to them.
What’s the official word on WSGI support for Plone 4?
Plone 4.1 will ship with Zope 2.13, but as Hanno states in PLIP #10776:
While Zope 2.13 provides native WSGI functionality, it is outside of this PLIP to make use of this in any way. There’s a large number of open questions around WSGI and the changes it requires to instance creation and setup, which warrant their own PLIP. A good number of those will also have an impact on the Zope 2 codebase itself, which is going to be already past a beta release by the time this PLIP gets started and thus will have to wait for Zope 2.14. I expect to see more community experimentation being done with WSGI once the capability is there. We might see a PLIP for Plone 4.2 to see those experimentations being solidified into good practice, standards and documentation.
So in other words, it’s still on the bleeding edge to try to use it, and probably not advised for production use just yet. As Hanno mentions, it’s expected that there will be more experimentation around WSGI, and as a community, we can come up with some best practices and documentation for how to do it in a sane way. Please let me know if you have done any experimentation with WSGI already, or if you’re interested in getting involved in these efforts.
Easily launch Plone sites on Amazon EC2 with mr.awsome
While we’ve been promoting our Plone 3 and Plone 4 AMIs which are really great to evaluate Plone on Amazon EC2 quickly, I want to tell you about another way you can get started with Amazon EC2 that gives you more control over where you launch the EC2 instances and what specific commands get executed on the server the first time it boots up. I mentioned this during my Scalable Plone hosting with Amazon EC2 talk at the Plone conference, but in this blog post, I want to go into more details about how to actually get it set up.
Here’s an example of a very simple set up of mr.awsome. You can either add this to an existing buildout (in which case you would name this file aws.cfg instead of buildout.cfg), or you can make a separate buildout as we have done here:
buildout.cfg:
[buildout]
parts = aws
[aws]
recipe = zc.recipe.egg
eggs = mr.awsome
entry-points =
aws=mr.awsome:aws
assh=mr.awsome:aws_ssh
arguments = configpath="${buildout:directory}/etc"
Then you put a config file in the /etc directory of your buildout, that might look something like this:
etc/aws.conf:
[securitygroup:demo-server]
description = Demo Server
connections =
tcp 22 22 0.0.0.0/0
tcp 80 80 0.0.0.0/0
tcp 8080 8080 0.0.0.0/0
[instance:demo-server] keypair = demo-server-keypair securitygroups = demo-server region = us-east-1 placement = us-east-1c instance_type = t1.micro image = ami-480df921 startup_script = startup-demo-server.sh fabfile = fabfile.py
There are a few things to note about this configuration:
- We open port 8080 in the firewall so that we can access our Plone site directly without making an Apache vhost, but for a production server you would not want to do this. We leave it as an exercise to the reader to extend the startup-demo-server.sh script to create the Apache vhost config file and activate it.
-
You’ll need to have created a keypair in the AWS Management Console or using ElasticFox, that has the name “demo-server-keypair”. You’ll want to save the keypair file someplace safe on your computer, as you will need this in order to SSH into the server.
- We specify the “demo-server” security group that we defined at the top of the config file. This is important not only for defining the ports to be open, but also for identifying which EC2 instance is the demo server, since Amazon doesn’t provide any other way to “tag” a server with such an identifier, so we use the security groups for that.
- You might have to play around with the settings for the region, placement, instance type and AMI image ID. Not all instance types are available in all regions, and the AMI ID must match the architecture (32-bit or 64-bit) and the region (us-east, us-west, eu-west, ap-southeast). We use the Ubuntu 10.04 LTS AMIs provided by Canonical.
- If you choose an AMI that uses EBS as it’s root store (also known as EBS bootable instances), then you will be able to stop the EC2 instance, restart it later and not lose all the data in the meantime. The other advantage is that you don’t pay for the instance while it’s in the stopped state. If you use the “instance store”, then your only option is to terminate the instance at which time you lose all the data, unless you’ve attached an EBS volume and have stored all data you want to persist there.
- If you are a new AWS customer, you qualify for free AWS hosting for one year with the smallest t1.micro instance. This is probably enough horsepower to run a very low traffic Plone 4 site, but I wouldn’t recommend trying to run Plone 3, or any site that has a significant amount of traffic. The t1.micro instance size is great for making demo sites or test instances, but should not be considered ideal for a production site.
- The startup script is the script that will be run the first time the EC2 instance starts up. This makes it possible to use a very generic AMI, and then use the startup script to bootstrap the server with all the dependencies needed to run Plone. This is also where you can customize the script to take care of things specific to your Plone site, such as importing data.
Here is an example of an atypical startup script, but one that I think we’ll be making more use of in the future. I found out about this at the Plone Conference when Alan Runyan mentioned on a discussion list that his company Enfold Systems had come up with an Ubuntu package for Plone. This means that to install Plone, you literally can type: apt-get install plone-default, which will install Plone 4 and a default Plone site. This startup script makes use of this Ubuntu package to bootstrap the server.
etc/startup-demo-server.sh:
#!/bin/bash set -e -x export DEBIAN_FRONTEND=noninteractive wget http://www.enfoldsystems.com/pubkey.gpg apt-key add ./pubkey.gpg echo "deb http://dist.clients.enfoldsystems.com/ubuntu lucid universe" >> /etc/apt/sources.list apt-get update && apt-get upgrade -y --force-yes apt-get install plone-default -y --force-yes /etc/init.d/plone-default
What this script does it essentially add the plone-default and plone4 packages to your apt sources.list file, and then installs Plone 4 on the server and sets up a default Plone site, and starts it up. What’s great about this way of installing Plone is that it’s very fast since all the eggs are already pre-compiled for your platform (no need to install gcc), and you don’t have to run buildout on the server which can often be very error-prone and risky.
The last thing that you need to do is set up your AWS key and secret key. The way I do this is by making a simple bash script with the following:
setkeys.sh
#!/bin/bash export AWS_ACCESS_KEY_ID="<your_access_key_id>" export AWS_SECRET_ACCESS_KEY="<your_secret_access_key>"
Obviously, you need to replace the <your_access_key_id> and <your_secret_access_key> with your actual keys which you can find by logging into aws.amazon.com, and clicking on the Security Credentials tab.
Then to set these environment variables:
$ source setkeys.sh
Once your keys are set, and you have the aws.conf file and startup-demo-server.sh script in place, then you can run your buildout and try starting up a demo-server on Amazon:
$ ./bin/buildout -v ... $ ./bin/aws start demo-server
INFO: Instance 'demo-server' unavailable INFO: Creating instance 'demo-server' INFO: Instance created, waiting until it's available .... INFO: Instance 'demo-server' available INFO: Instance running. INFO: Instances DNS name ec2-50-16-25-92.compute-1.amazonaws.com INFO: Instances public DNS name ec2-50-16-25-92.compute-1.amazonaws.com
Your site is now running at http://ec2-50-16-25-92.compute-1.amazonaws.com:8080. You’ll need to substitute the domain name that is returned when you run this command, and remember to put the port :8080 at the end, since we haven’t set up an Apache vhost to proxy requests from port 80 to 8080.
Within a few minutes you should see the Welcome to Plone screen!
Please note that if you are not a new AWS customer, or you already have a t1.micro instance running, you will be charged by Amazon for every hour that this instance is running, so when you’re done evaluating it, you should either stop it (if you used an EBS bootable instance), or terminate it (if you used an instance store).
$ ./bin/aws stop demo-server $ ./bin/aws terminate demo-server
You can also stop the instance from the AWS console or using ElasticFox. That’s it! Hope you’ve found this little tutorial useful, and let me know if you have any questions about how mr.awsome or Amazon EC2 works for hosting Plone sites.

