HelloPharo is a code farm for Pharo that makes small webapp deployment easy.
It is inspired by Capistrano and is built on top of Ansible. When designing this tool we preferred convention over configuration.
This code farm is a starting point. We expect you to tweak the configuration to fit your need, we just provide sensible default. When you download HelloPharo, you see the actual code used to deploy a trivial webapp.
We concentrate on the current stable release of Pharo. This means we've hardcoded the pharo version to Pharo 3.0p852.
One of the secret goal of HelloPharo is to provide a stack of tools to implement a Twelve-factor app.
Make sure the app runs on your machine before even trying on the remote server.
- Install ansible if you don't have it yet. If you're on OSX, we recommend using Homebrew. Windows user you're out of luck, Ansible does not support Windows (yet), sorry!
- Download the latest version by clicking
Download ZIP
in github and unzip it. You can rename the directory to match your project name. In these instructions we'll assume that the directory is calledhello-pharo
. - Download the latest pharo 3 image, changes and sources file. We use http://files.pharo.org/image/30/30852.zip and http://files.pharo.org/sources/PharoV30.sources.zip
- Rename the files as
pharo.image
andpharo.changes
and copy them in the newly createdhello-pharo
directory. Copy thePharoV30.sources
as well. - Open a terminal and navigate to the
hello-pharo
directory. - Avoid getting some junk in your git repository:
$ cp gitignore.example .gitignore
. Edit the gitignore file as you wish but don't include the image/changes files in the git repo. - Edit the
install.st
script to load your code. We usually put our code in thesrc/
directory but feel free to load anything from anywhere (e.g., Smalltalkhub). Do not delete the "save and quit" instruction from the script, otherwise your server will hangs when you deploy. - Edit the
start.st
script. It's a good place to start your Zinc servers or any long-running smalltalk tasks.
Check the Local Directory Structure section for more details about the directory structure you should adopt and the convention to follow.
You're now ready to go:
$ ./app install
$ ./app start
The install command can take some time as it will load all your code and its dependencies.
Test if everything runs fine. Beware that there should NOT have any GUI interaction during the install and start phase. Things will run headless on the server so you won't be able to do anything.
When you're done, you can:
$ ./app stop
This will exit the image.
We assume you use Azure but any provider should work as long as it has Ubuntu images. In a nutshell:
- Create an Azure Ubuntu VM
- Log to it using the username/password given in the administration panel
- Create a user with which you want to deploy (e.g.,
deploy
) - Make this user sudoable (so you can install packages)
- Add your SSH public key in
~/.ssh/authorized_keys
on the server for the deploy user. This will let you without entering any password. - Edit the
hosts.ini
andvars.yml
file in the ansible directory to match your setup. - Make sure, you've pushed your code in the git repository defined in the
repo
variable of theansible/vars.yml
file. - Launch automated server setup with:
$ ansible-playbook -i ansible/hosts.ini ansible/server-setup.yml
- See the troubleshooting section if something goes wrong.
- Deploy your app with:
$ ./app deploy
- Use DeployUtils to handle environment within your image (set the
pharo_env
variable in hosts definitions)
Everytime you want to deploy the master branch of your app, run
$ ./app deploy
$ ansible-playbook -i ansible/hosts.ini ansible/server-setup.yml
will install git, unzip, nginx, pharo-vm and download the base Pharo3 images.
It will also create an nginx configuration file for your project (see
ansible/templates/nginx-site.conf
for details).
HelloPharo expects a strict directoy structure for your project. This section explains it. Notice that pharo.changes
, pharo.image
and PharoV30.sources
must be in the .gitignore
file.
├── LICENSE
├── PharoV30.sources
├── README.md
├── ansible
│ ├── deploy.yml
│ ├── hosts.ini
│ ├── server-setup.yml
│ ├── templates
│ │ └── nginx-site.conf
│ └── vars.yml
├── app
├── config
│ ├── development.json
│ └── production.json
├── install.st
├── pharo.changes
├── pharo.image
├── public
│ ├── 404.html
│ ├── 500.html
│ └── assets
│ └── pharo-logo.png
├── src
│ └── # Your Pharo/Filetree code
└── start.st
By default, those three files are not there, download:
Rename the changes and image files to pharo.changes
and pharo.image
. Move them to the project directory.
List these three files in the .gitignore
or simply copy the gitignore.example
file.
The install.st
script will be used to build the image containing your application. You should load your code and all its dependencies in here. The default install.st
file shows you how it is done for the super simple example we provide. Don't forget to save & quit the image at the end of this script.
start.st
is executed when you start the app. You should start your Zinc server/Seaside adapter/database connection/whatever in here. Note that you should not save the image in start.st
This bash script is one of the central piece of HelloPharo. It can install/start/stop a project. Most useful commands:
$ ./app install
# will execute the install.st script against the image
$ ./app start
# will execute the start.st script against the image and store the PID of the process
$ ./app stop
# will kill the saved PID
Those three commands works on your development machine as well as on the remote server. We advise you to use them during development to make sure they are working well before trying to deploy.
$ ./app deploy
# will start the deployment process
This directory contains all the server administration code. You should update the vars.yml
and hosts.ini
to match your setup. Please read the Server Directory Structure for more details.
Put all your static file that should be rendered by the webserver here. Note that items in public/assets
will be gzipped before being served. It's a good place for your CSS/Javascripts files.
Nginx will render the 404.html
and 500.html
from this directory. You probably want to tune them.
Place here your environment files. Usually named production.json
, staging.json
and development.json
these files contain the configuration of your app for each environment. Use the DeployUtils smalltalk package to use them within your image.
Environment files are the right place to put the database connection information (username, port, host, password) or external API Key you use (transactional email provider for example).
$ pwd
/home/azureuser
$ tree -L 5
.
├── apps
│ └── hello-pharo
│ ├── app.pid
│ ├── base-repo
│ ├── current -> /home/azureuser/apps/hello-pharo/releases/2014-08-12.150722
│ └── releases
│ ├── 2014-07-16.135727
│ │ ├── ....
│ ├── 2014-07-16.141804
│ │ ├── ....
│ ├── 2014-07-16.141827
│ │ ├── ....
│ ├── 2014-08-09.114720
│ │ ├── ....
│ ├── 2014-08-12.094722
│ │ ├── ....
│ └── 2014-08-12.150722
│ ├── ansible
│ ├── app
│ ├── gitignore.example
│ ├── install.st
│ ├── package-cache
│ ├── pharo.changes
│ ├── pharo.image
│ ├── PharoV30.sources
│ ├── public
│ ├── README.md
│ ├── src
│ └── start.st
└── stock-images
├── 30852.zip
├── latest.zip
├── Pharo-30852.changes
├── Pharo-30852.image
├── PharoV30.sources
└── PharoV30.sources.zip
This directory structure is the one that will be generated by the current HelloPharo installation.
This is the directory where the clean images are stored. Everytime you deploy, HelloPharo will build your project from the image in this directory. You should not have to modified this.
This is where all your apps will reside. In this example, we have only one application: hello-pharo. If we had other apps, we would just have them here as well.
app_name is defined in the vars.yml
file. It contains 4 important things:
- The pid file of the version of the app that is currently running.
- a
base-repo
directory into which your code will be checkout from the git repository - a
current
symlink that points to the current version of the app. - a
releases
directory that contains all the releases of your app. releases are identified with a timestamp.
Every time you deploy your app:
- A new directory is created in the
releases
folder - The code is checked out from the git repository
- The code is copied in to the newly created directory
- A clean image from
stock-images
is copied in the directory - The
install.st
script is run against the clean image - The previous app instance is killed (with its PID file)
- The
current
symlink is redirected to the new directory - The
start.st
script is run against he newly built image and the PID of the process is stored inapp.pid
- Tadada, you've deployed a new version of your app.
- If the git repo containing your code is private, don't forget to generate a pair of SSH keys on the server and add the public key as a deployment key in the interface of your git repository provider.
- Try to install/start the app on your local machine before even trying on the remote server.
- If you're using a cloud service provider (e.g., AWS, Azure, Google), don't forget to open the port 80 in the administration interface.
- Be sure that the port on which you start the application (in
start.st
) is the same you defined inport
variable invars.yml
. If you see a mismatch and you have already run the server-setup script, you want to rerun it to update the nginx configuration file. - Are
pharo.changes
,pharo.image
andPharoV30.sources
in your `.gitignore file.
Ping me on twitter @fstephany or send an email to the pharo-users mailing list if something goes wrong.
There's little chance that we overcome the following limitations:
- Ansible does not run on Windows. You won't be able to deploy an application from a Windows machine.
- Out of the box, the script is suitable for single image application (no load balancing).
- Use git for versionning (even though your Smalltalk code can be hosted in a monticello repository)
- Right now, the server only runs on Ubuntu Linux (using the Pharo PPA)
Feel free to work on this and send a pull request to the project. If you badly want/need one the following, bounties are always possible ;)
- Add an ansible vault for productin app config file
- Use Monit for process monitoring
- Use version number. Right now we use the
master
branch of the project but we really should move to a more robust way to release. - Provide a "bootstrap" script that performs the steps 2 and 3 of the quick install section.
- Be able the choose the branch from which to deploy (currently
master
is always used) - Provide a default preference file (to have, at least, a common package-cache for all the images)
- symbolic link to
system
directory. It will contain assets generated by the app (e.g., the pictures uploaded by the users) - Implement rollback. In the meantime add a section in the README with a manual rollback procedure
- Separate deploy user with the server-setup user. The deploy user does not need sudo root.
- Download and use VMs instead of the Ubuntu PPA so we can deploy on other unix boxes.
Hello-Pharo is developed by Ta Mère SCRL. We
- build apps for clients,
- provide training/coaching,
- eat a lot of french fries.
The app
shell script is heavily inspired by st-exec.sh
from http://stfx.eu/pharo-server/ by Sven Van Caekenberghe