This is an example juju charm to deploy a user-defined node app directly from revision control.
This charm will be maintained with a general set of hooks for various services that can be used with node apps (like mongodb).
First, edit config.yaml
to add info about your app.
Then deploy some basic services
juju deploy node-app myapp
juju deploy mongodb
juju deploy haproxy
relate them
juju add-relation mongodb myapp
juju add-relation myapp haproxy
scale up your app (to 10 nodes for example)
juju add-unit -n 10 myapp
open it up to the outside world
juju expose haproxy
Find the haproxy instance's public URL from
juju status
(or attach it to an elastic IP via the aws console) and open it up in a browser.
During the install
hook,
- installs
node
/npm
- clones your node app from the repo specified in
app_repo
- runs
npm
if your app containspackage.json
- configures networking if your app contains
config/config.js
- waits to be joined to a
mongodb
service
when related to a mongodb
service, the formula
- configures db access if your app contains
config/config.js
- starts your node app as a service
Configurable aspects of the charm are listed in config.yaml
and can be set by either editing the default values directly
in the yaml file or passing a myapp.yaml
configuration
file during deployment
juju deploy --config ~/myapp.yaml node-app myapp
Some of these parameters are used directly by the charm,
and some are passed through to the node app using config/config.js
.
The formula looks for config/config.js
in your app which
starts off looking something like this
module.exports = config = {
"name" : "mynodeapp"
,"listen_port" : 8000
,"mongo_host" : "localhost"
,"mongo_port" : 27017
}
and gets modified with contextually correct configuration information during
either deployment (via the install
hook) or relation to another service
(relation-changed
hook).
This config can be used from within your application using snippets like
...
var config = require('./config/config')
...
new mongo.Server(config.mongo_host, config.mongo_port, {}),
...
server.listen(config.listen_port);
...
Alternatively you could use a "Procfile" in root directory like this:
web: node app.js
and then get the environment variables from the running environment like this:
app.set('port', process.env.PORT);
The defined environment variables are:
NAME
PORT
NODE_ENV
MONGO_HOST
MONGO_PORT
MONGO_REPLSET
This charm does not open any public ports itself.
The intention is to relate it to a proxy service like
haproxy
, which will in turn open port 80 to the outside world.
This allows for instant horizontal scalability.
If your node app is itself a proxy and you want it directly exposed, this can easily be done by adding
open-port $app_port
to the bottom of the install
hook, and then once your stack
is started, you expose
juju expose myapp
it to the outside world.
By default, juju services within the same environment can talk to each other on any port over internal network interfaces.
This charm makes some strong assumptions
about the structure of the node application
(config/config.js
) that might not apply to your app.
Please treat this formula as a template that
you can fork and modify to suit your needs.
The biggest difference between how the charm
behaves for different kind of apps is application
startup. A simple application will want to start
upon install (startup code goes in the install
hook),
whereas some applications will not want
to start up until a database has be associated
(startup code goes in the db-relation-joined
hooks).
lp:charm/node-app