Dancing on a cloud made of pearls
Thanks to a post on Hacker News, I got access to the beta test for DotCloud. In this blog post, I show how I got started and successfully deployed a small Perl Dancer web app to the service.
I was extremely pleased with how easy it was to do the above, and wanted to share it!
After creating the account on DotCloud, a quick and painless endeavour, I followed along their first steps tutorial, making sure I’d change the various steps in order to deploy a Perl Dancer webapp.
Here is the transcript of the first steps of the tutorial, which did not change for me:
$ sudo aptitude install python-setuptools
[...]
$ sudo easy_install dotcloud
[...]
$ dotcloud
Warning: /home/okram/.dotcloud/dotcloud.conf does not exist.
Enter your api key (You can find it at http://www.dotcloud.com/account/settings): XXXXXXXXXXXXXXXXXXXXXXXXX
error: usage: dotcloud [-h]
{status,info,run,logs,deploy,setup,list,alias,ssh,destroy,push,rollback,create,restart}
...
At this point I just went to the linked URL, and copy/pasted my API key. Nothing strange so far.
I then created a new namespace, “weasel”, and an endpoint “www”. Lastly, I checked it was created:
$ dotcloud deploy -t perl weasel.www
Created "weasel.www".
$ dotcloud info weasel.www
cluster: wolverine
config: {}
created_at: 1304117136.2035949
name: weasel.www
namespace: weasel
state: booting
type: perl
Time for code! I created a new Git repo, and edited some files. The full listing (heh!) will be at the end of the article.
$ mkdir -p GIT/weasel/www
$ cd !$
$ git init
Initialized empty Git repository in /home/okram/GIT/weasel/www/.git/
$ vi -p myapp.pl Makefile.PL app.psgi
3 files to edit
$ git add * ; git commit -am "Initial commit"
[...]
The Makefile.PL contained Dancer
as a prerequisite, as the myapp.pl
did not make use of any other Perl module.
It came the time to try deploying the webapp to dotcloud; easy!
Dotcloud took care of installing the Dancer
prerequisite, along with
all the dependencies, and then tried to start the app.
$ dotcloud push weasel.www .
# upload . ssh://dotcloud@uploader.dotcloud.com:1060/weasel.www
# git
Warning: Permanently added '[uploader.dotcloud.com]:1060,[174.129.15.77]:1060' (RSA) to the list of known hosts.
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 533 bytes, done.
Total 5 (delta 0), reused 0 (delta 0)
To ssh://dotcloud@uploader.dotcloud.com:1060/weasel.www
* [new branch] master -> master
Scheduling build
Fetching logs...
Warning: Permanently added '[www.weasel.dotcloud.com]:3254,[174.129.17.131]:3254' (RSA) to the list of known hosts.
-- Build started...
Makefile.PL
app.psgi
myapp.pl
Fetched code revision e4d8d81
--> Working on .
Configuring /home/dotcloud/e4d8d81 ... OK
==> Found dependencies: Dancer
--> Working on Dancer
Fetching http://search.cpan.org/CPAN/authors/id/X/XS/XSAWYERX/Dancer-1.3030.tar.gz ... OK
Configuring Dancer-1.3030 ... OK
==> Found dependencies: HTTP::Server::Simple::PSGI, HTTP::Body, MIME::Types
--> Working on HTTP::Server::Simple::PSGI
[...]
Successfully installed MIME-Types-1.31
Building Dancer-1.3030 ... OK
Successfully installed Dancer-1.3030
<== Installed dependencies for .. Finishing.
8 distributions installed
uwsgi: stopped
uwsgi: ERROR (abnormal termination)
Connection to www.weasel.dotcloud.com closed.
Oh-oh! Something went wrong! I checked the log files to see what was it:
$ dotcloud logs weasel.www
# tail -F /var/log/{supervisor,nginx}/*.log
[...]
==> /var/log/supervisor/uwsgi.log <==
[...]
Plack::Request is needed by the PSGI handler at /home/dotcloud/perl5/lib/perl5/Dancer.pm line 334
Compilation failed in require at (eval 3) line 1.
[...]
That’s it: it’s clearly missing Plack::Request
to be able to handle PSGI
requests.
No problem; just add it to the Makefile.PL
and deploy again!
This will install the new dependency, and hopefully the service will start!
$ vi Makefile.PL
$ git commit -am "Add Plack::Request as prerequisite also"
[master faa342f] Add Plack::Request as prerequisite also
1 files changed, 1 insertions(+), 0 deletions(-)
$ dotcloud push weasel.www .
# upload . ssh://dotcloud@uploader.dotcloud.com:1060/weasel.www
# git
Warning: Permanently added '[uploader.dotcloud.com]:1060,[174.129.15.77]:1060' (RSA) to the list of known hosts.
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 381 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
To ssh://dotcloud@uploader.dotcloud.com:1060/weasel.www
e4d8d81..faa342f master -> master
Scheduling build
Fetching logs...
Warning: Permanently added '[www.weasel.dotcloud.com]:3254,[174.129.17.131]:3254' (RSA) to the list of known hosts.
-- Build started...
[...]
Fetched code revision faa342f
--> Working on .
Configuring /home/dotcloud/faa342f ... OK
==> Found dependencies: Plack::Request
--> Working on Plack::Request
[...]
Successfully installed Devel-StackTrace-AsHTML-0.11
Building Plack-0.9976 ... OK
Successfully installed Plack-0.9976
<== Installed dependencies for .. Finishing.
12 distributions installed
uwsgi: started
Connection to www.weasel.dotcloud.com closed.
And so it did! Let’s see if my webapp really worked:
$ curl http://www.weasel.dotcloud.com/
Why, hello there!
$ curl http://www.weasel.dotcloud.com/test-123
Hello test123!
Indeed it did!
There you go, an easy way to deploy a Dancer webapp to the cloud!
Here are the sample files I used:
$ cat Makefile.PL
#!/usr/bin/env perl
use ExtUtils::MakeMaker;
WriteMakefile(
PREREQ_PM => {
'Dancer' => '1.3030',
'Plack::Request' => '0.9976',
},
);
$ cat myapp.pl
#!/usr/bin/env perl
use Dancer;
get '/' => sub {
return "Why, hello there!\n";
};
get '/:name' => sub {
my $name = params->{name};
$name =~ s/[^a-z0-9 ]//i;
return "Hello $name!\n";
};
dance;
$ cat app.psgi
require 'myapp.pl';
Really, really easy! Thanks Dotcloud! And, thanks CPAN and CPAN authors, without which the above certainly would not have been possible!
Nice! I copied your instructions and they worked very well :)
http://www.kaokun.dotcloud.com/
I did notice a small bug in your code:
$name =~ s/[^a-z0-9 ]//i;
Should read:
$name =~ s/[^a-z0-9 ]//ig;
- Alex