Merge lp:~jorge/juju-core/nodeapp-example into lp:juju-core/docs

Proposed by Jorge Castro
Status: Merged
Merged at revision: 72
Proposed branch: lp:~jorge/juju-core/nodeapp-example
Merge into: lp:juju-core/docs
Diff against target: 479 lines (+455/-2)
2 files modified
htmldocs/charms-deploying.html (+2/-2)
htmldocs/howto-node.html (+453/-0)
To merge this branch: bzr merge lp:~jorge/juju-core/nodeapp-example
Reviewer Review Type Date Requested Status
charmers Pending
Review via email: mp+183230@code.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'htmldocs/charms-deploying.html'
2--- htmldocs/charms-deploying.html 2013-08-30 14:18:08 +0000
3+++ htmldocs/charms-deploying.html 2013-08-30 16:38:55 +0000
4@@ -275,7 +275,7 @@
5 <p>I should now have a second machine running both the
6 openstack-dashboard service and a second unit of the
7 rabbitmq-server service:</p>
8-<code>
9+<pre class="prettyprint">
10 $ juju status
11 machines:
12 "0":
13@@ -334,7 +334,7 @@
14 agent-version: 1.11.4
15 machine: "1"
16 public-address: 10.5.0.45
17-</code>
18+</pre>
19
20 <p>These two features make it much easier to deploy
21 complex services such as OpenStack which use a large
22
23=== added file 'htmldocs/howto-node.html'
24--- htmldocs/howto-node.html 1970-01-01 00:00:00 +0000
25+++ htmldocs/howto-node.html 2013-08-30 16:38:55 +0000
26@@ -0,0 +1,453 @@
27+<!DOCTYPE html>
28+<html>
29+ <head>
30+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
31+ <title>Juju Documentation - Charms in Action</title>
32+ <link href='https://fonts.googleapis.com/css?family=Ubuntu:400,300,300italic,400italic,700,700italic|Ubuntu+Mono' rel='stylesheet' type='text/css' />
33+ <link rel="stylesheet" type="text/css" media="screen" href="//juju.ubuntu.com/wp-content/themes/juju-website/css/reset.css" />
34+ <link rel="stylesheet" type="text/css" media="screen" href="//juju.ubuntu.com/wp-content/themes/juju-website/css/960.css" />
35+ <link rel="stylesheet" type="text/css" media="screen" href="//juju.ubuntu.com/wp-content/themes/juju-website/css/base.css" />
36+ <link rel="stylesheet" type="text/css" media="screen" href="//juju.ubuntu.com/wp-content/themes/juju-website/css/home-new.css" />
37+ <link rel='stylesheet' id='stacktack-css' href='//juju.ubuntu.com/wp-content/plugins/stacktack/css/stacktack.min.css?ver=3.4.2' type='text/css' media='all' />
38+ <link href="css/main.css?1375975745" rel="stylesheet" type="text/css"/>
39+
40+ <!--[if lt IE 9]>
41+ <script type="text/javascript" src="//html5shim.googlecode.com/svn/trunk/html5.js"></script>
42+ <![endif]-->
43+</head>
44+
45+<!-- DO NOT EDIT ABOVE THIS LINE -->
46+
47+<!-- DO NOT EDIT ABOVE THIS LINE -->
48+
49+
50+ <body class="resources">
51+ <header class="global clearfix" role="banner">
52+ <div class="header-navigation">
53+ <div>
54+ <nav role="navigation">
55+ <ul>
56+ <li class="page_item page-item-6"><a href="https://juju.ubuntu.com/">Home</a></li>
57+ <li class="page_item page-item-7"><a href="https://juju.ubuntu.com/get-started/">Get started</a></li>
58+ <li class="page_item page-item-9 current_page_item"><a href="https://juju.ubuntu.com/resources/">Resources</a></li>
59+ <li class="page_item page-item-13"><a href="https://juju.ubuntu.com/community/">Community</a></li>
60+ <li class="page_item page-item-3688"><a href="https://juju.ubuntu.com/charm-store/">Charm Store</a></li>
61+ <li class="page_item page-item-3691"><a href="https://juju.ubuntu.com/events/">Events</a></li>
62+ <li class="page_item page-item-4474"><a href="https://juju.ubuntu.com/charm-championship/">Charm Championship</a></li>
63+ <li class="page_item page-item-4249"><a href="https://juju.ubuntu.com/survey/">Survey</a></li>
64+ <li>
65+ <form id="form-search" method="get" action="https://juju.ubuntu.com/">
66+ <fieldset>
67+ <input id="input-search" type="text" name="s" value="Search" />
68+ </fieldset>
69+ </form>
70+ </li>
71+ </ul>
72+ </nav>
73+ </div>
74+ </div>
75+ <div class="header-content">
76+ <div class="clearfix">
77+ <img src="https://juju.ubuntu.com/wp-content/themes/juju-website/img/arrow-nav.png" width="9" height="5" style="left:455px; display: block;" class="arrow-nav">
78+ <div class="header-navigation-secondary"></div>
79+ <div class="header-image"></div>
80+ <h1>Resources</h1>
81+ <h2>A collection of some of the most important online references for Juju users and developers.</h2>
82+ </div>
83+ </div>
84+</header>
85+
86+ <section id="content" class="container-12">
87+ <div class="grid-12 doc-container">
88+ <div id="navlinks" class="grid-3 doc-navigation">LINKS</div>
89+ <div class="grid-9 doc-content">
90+ <article>
91+ <section id="node">
92+ <h1>
93+ Using Juju to Deploy your Node.js Application
94+ </h1>
95+ <p>
96+ One of Juju&acirc;&euro;&trade;s main use cases is to deploy your application directly out of version control and into a cloud. Since Juju supports local and remote clouds, this makes for a nice workflow that enables you to rev your app quickly on your local machine and then deploy out the cloud.
97+ </p>
98+ <p>
99+ In this tutorial we will deploy a Node.js/MongoDB application directly from github. The application will be behind an HAProxy service so that we can horizontally scale when needed.
100+ </p>
101+ <p>
102+ We will then set up a local-to-cloud workflow with our application so we can do continuous deployment. Since we deploy locally in the exact same way as we deploy to a cloud, this is a powerful method for developing your application in an environment that more closely resembles production.
103+ </p>
104+ <p>
105+ Before moving on you should have gone through the <a href="https://juju.ubuntu.com/docs/getting-started.html">Getting Started</a> section and installed and configured Juju.
106+ </p>
107+ <h2 id="basic-usage-of-the-node.js-charm">
108+ Basic Usage of the Node.js Charm
109+ </h2>
110+ <p>
111+ First, create a <code>config.yaml</code> to add info about your app pointing to your github repo:
112+ </p>
113+ <pre>
114+<code>sample-node:
115+ repo: https://github.com/yourapplication</code>
116+</pre>
117+ <p>
118+ If you have not already bootstrapped an environment, do so:
119+ </p>
120+ <pre>
121+<code>juju bootstrap</code>
122+</pre>
123+ <p>
124+ Then wait a few minutes while your cloud spins up. Then deploy some basic services:
125+ </p>
126+ <pre>
127+<code>juju deploy node-app myapp
128+juju deploy mongodb
129+juju deploy haproxy</code>
130+</pre>
131+ <p>
132+ relate them
133+ </p>
134+ <pre>
135+<code>juju add-relation mongodb myapp
136+juju add-relation myapp haproxy</code>
137+</pre>
138+ <p>
139+ open it up to the outside world
140+ </p>
141+ <pre>
142+<code>juju expose haproxy</code>
143+</pre>
144+ <p>
145+ Find the haproxy instance&acirc;&euro;&trade;s public URL from
146+ </p>
147+ <pre>
148+<code>juju status</code>
149+</pre>
150+ <p>
151+ (or attach it to an elastic IP via the AWS console) and open it up in a browser.
152+ </p>
153+ <p>
154+ scale up your app (to 10 nodes for example)
155+ </p>
156+ <pre>
157+<code>juju add-unit -n 10 myapp</code>
158+</pre>
159+ <p>
160+ and scale it back down
161+ </p>
162+ <pre>
163+<code>juju remove-unit -n9 myapp</code>
164+</pre>
165+ <h2 id="local-to-cloud-workflow">
166+ Local to Cloud Workflow
167+ </h2>
168+ <p>
169+ The previous example deploys your application quickly to the cloud, in this example we will show how to hack and test on an application locally on your laptop and then push out to the public cloud.
170+ </p>
171+ <p>
172+ We need to configure 2 environments, a local one and a public cloud one.
173+ </p>
174+ <ol style="list-style-type: decimal">
175+ <li>Configure the <a href="https://juju.ubuntu.com/docs/config-local.html">local provider</a> on your machine.
176+ </li>
177+ <li>Configure a public or private cloud on your machine.
178+ </li>
179+ </ol>
180+ <ul>
181+ <li>
182+ <a href="https://juju.ubuntu.com/docs/config-aws.html">AWS</a>
183+ </li>
184+ <li>
185+ <a href="https://juju.ubuntu.com/docs/config-hpcloud.html">HP Cloud</a>
186+ </li>
187+ <li>
188+ <a href="https://juju.ubuntu.com/docs/config-openstack.html">OpenStack</a>
189+ </li>
190+ </ul>
191+ <p>
192+ In this example the local environment is named <code>local</code> and we&acirc;&euro;&trade;ll deploy to an AWS environment called <code>amazon</code>. First let&acirc;&euro;&trade;s <code>switch</code> to the local environment and bootstrap.
193+ </p>
194+ <pre>
195+<code>juju switch local
196+juju bootstrap</code>
197+</pre>
198+ <p>
199+ Create a <code>config.yaml</code> to add info about your app pointing to your github repo:
200+ </p>
201+ <pre>
202+<code>sample-node:
203+ app_url: https://github.com/yourapplication</code>
204+</pre>
205+ <p>
206+ Then deploy some basic services:
207+ </p>
208+ <pre>
209+<code>juju deploy --config ~/myapp.yaml node-app myapp
210+juju deploy mongodb</code>
211+</pre>
212+ <p>
213+ relate them
214+ </p>
215+ <pre>
216+<code>juju add-relation mongodb myapp</code>
217+</pre>
218+ <p>
219+ Now open up your browser and go to <code>http://localhost</code> to get your application loaded in your browser.
220+ </p>
221+ <h3 id="continuous-deployment">
222+ Continuous Deployment
223+ </h3>
224+ <p>
225+ Continue to write your code, push to git as you land features and fixes. When you&acirc;&euro;&trade;re ready to test it you can tell Juju to check the git repository again:
226+ </p>
227+ <pre>
228+<code>juju set myapp app_branch=https://github.com/yourapplication</code>
229+</pre>
230+ <p>
231+ The charm will then fetch the latest code and you can refresh your browser at <code>http://localhost</code>.
232+ </p>
233+ <p>
234+ Repeat pushing to git and using the juju set command to keep a live instance of your application running in your local environment.
235+ </p>
236+ <h3 id="push-to-your-publicprivate-cloud">
237+ Push to your Public/Private Cloud
238+ </h3>
239+ <p>
240+ After you&acirc;&euro;&trade;ve repeatedly upgraded your application locally it&acirc;&euro;&trade;s time to push it out to a place where your coworkers can see your app in all it&acirc;&euro;&trade;s glory, let&acirc;&euro;&trade;s push this to AWS. Same exact commands as before, just to a different environment:
241+ </p>
242+ <pre>
243+<code>juju switch amazon
244+juju bootstrap
245+juju deploy --config ~/myapp.yaml node-app myapp
246+juju deploy mongodb
247+juju add-relation mongodb myapp</code>
248+</pre>
249+ <p>
250+ Since we&acirc;&euro;&trade;re on a public cloud and not on a local provider we need to explicitly expose the service and get its public IP:
251+ </p>
252+ <pre>
253+<code>juju expose myapp
254+juju status myapp</code>
255+</pre>
256+ <p>
257+ And put the ec2 URL in your browser. If you want to enable some horizontal scalability to your application you can do so, even after you&acirc;&euro;&trade;ve deployed!
258+ </p>
259+ <pre>
260+<code>juju deploy haproxy
261+juju add-relation haproxy myapp
262+juju expose haproxy
263+juju unexpose myapp</code>
264+</pre>
265+ <p>
266+ And then get the public IP from the haproxy instead (notice how we&acirc;&euro;&trade;ve unexposed your application so that only haproxy is serving the public internet):
267+ </p>
268+ <pre>
269+<code>juju status haproxy</code>
270+</pre>
271+ <p>
272+ Now you can <code>juju add-unit myapp</code> and <code>juju remove-unit myapp</code> based on load.
273+ </p>
274+ <h3 id="tearing-it-all-down">
275+ Tearing it all down
276+ </h3>
277+ <p>
278+ The local containers survive reboots and do not go away until you explicitly tear the environment down. Now that your coworkers have seen your great application let&acirc;&euro;&trade;s also stop spending money:
279+ </p>
280+ <pre>
281+<code>juju destroy-environment -eamazon
282+juju destroy-environment -local</code>
283+</pre>
284+ <h2 id="charm-details">
285+ Charm Details
286+ </h2>
287+ <p>
288+ This section is to explain how the charm works and is provided here as a reference.
289+ </p>
290+ <h3 id="what-the-formula-does">
291+ What the formula does
292+ </h3>
293+ <p>
294+ During the <code>install</code> hook,
295+ </p>
296+ <ul>
297+ <li>installs <code>node</code>/<code>npm</code>
298+ </li>
299+ <li>clones your node app from the repo specified in <code>app_repo</code>
300+ </li>
301+ <li>runs <code>npm</code> if your app contains <code>package.json</code>
302+ </li>
303+ <li>configures networking if your app contains <code>config/config.js</code>
304+ </li>
305+ <li>waits to be joined to a <code>mongodb</code> service
306+ </li>
307+ </ul>
308+ <p>
309+ when related to a <code>mongodb</code> service, the formula
310+ </p>
311+ <ul>
312+ <li>configures db access if your app contains <code>config/config.js</code>
313+ </li>
314+ <li>starts your node app as a service
315+ </li>
316+ </ul>
317+ <h3 id="charm-configuration">
318+ Charm configuration
319+ </h3>
320+ <p>
321+ Configurable aspects of the charm are listed in <code>config.yaml</code> and can be set by either editing the default values directly in the yaml file or passing a <code>myapp.yaml</code> configuration file during deployment
322+ </p>
323+ <pre>
324+<code>juju deploy --config ~/myapp.yaml node-app myapp</code>
325+</pre>
326+ <p>
327+ Some of these parameters are used directly by the charm, and some are passed through to the node app using <code>config/config.js</code>.
328+ </p>
329+ <h3 id="application-configuration">
330+ Application configuration
331+ </h3>
332+ <p>
333+ The formula looks for <code>config/config.js</code> in your app which starts off looking something like this
334+ </p>
335+ <pre>
336+<code>module.exports = config = {
337+ "name" : "mynodeapp"
338+ ,"listen_port" : 8000
339+ ,"mongo_host" : "localhost"
340+ ,"mongo_port" : 27017
341+}</code>
342+</pre>
343+ <p>
344+ and gets modified with contextually correct configuration information during either deployment (via the <code>install</code> hook) or relation to another service (<code>relation-changed</code> hook).
345+ </p>
346+ <p>
347+ This config can be used from within your application using snippets like
348+ </p>
349+ <pre>
350+<code>...
351+var config = require('./config/config')
352+...
353+ new mongo.Server(config.mongo_host, config.mongo_port, {}),
354+...
355+server.listen(config.listen_port);
356+...</code>
357+</pre>
358+ <p>
359+ Alternatively you could use a &acirc;&euro;&oelig;Procfile&acirc;&euro; in root directory like this:
360+ </p>
361+ <pre>
362+<code>web: node app.js</code>
363+</pre>
364+ <p>
365+ and then get the environment variables from the running environment like this:
366+ </p>
367+ <pre>
368+<code>app.set('port', process.env.PORT);</code>
369+</pre>
370+ <p>
371+ The defined environment variables are:
372+ </p>
373+ <pre>
374+<code>NAME
375+PORT
376+NODE_ENV
377+MONGO_HOST
378+MONGO_PORT
379+MONGO_REPLSET</code>
380+</pre>
381+ <h3 id="network-access">
382+ Network access
383+ </h3>
384+ <p>
385+ This charm does not open any public ports itself. The intention is to relate it to a proxy service like <code>haproxy</code>, which will in turn open port 80 to the outside world. This allows for instant horizontal scalability.
386+ </p>
387+ <p>
388+ If your node app is itself a proxy and you want it directly exposed, this can easily be done by adding
389+ </p>
390+ <pre>
391+<code>open-port $app_port</code>
392+</pre>
393+ <p>
394+ to the bottom of the <code>install</code> hook, and then once your stack is started, you expose
395+ </p>
396+ <pre>
397+<code>juju expose myapp</code>
398+</pre>
399+ <p>
400+ it to the outside world.
401+ </p>
402+ <p>
403+ By default, juju services within the same environment can talk to each other on any port over internal network interfaces.
404+ </p>
405+ <h3 id="making-this-work-with-your-node.js-app">
406+ Making this work with your node.js app
407+ </h3>
408+ <p>
409+ This charm makes some strong assumptions about the structure of the node application (<code>config/config.js</code>) that might not apply to your app. Please treat this formula as a template that you can fork and modify to suit your needs.
410+ </p>
411+ <p>
412+ 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 <code>install</code> hook), whereas some applications will not want to start up until a database has be associated (startup code goes in the <code>db-relation-joined</code> hooks).
413+ </p>
414+ </section>
415+
416+ </article>
417+ </section>
418+ <div class="shadow"></div>
419+ <footer class="global clearfix" role="contentinfo">
420+ <div class="row">
421+ <div class="inner-wrapper">
422+ <nav role="navigation" class="clearfix">
423+ <ul class="footer-a">
424+ <li class="grid-3 first-col">
425+ <h4><a href="/get-started">Get started</a></h4>
426+ <ul>
427+ <li class="page_item page-item-20"><a href="https://juju.ubuntu.com/get-started/local/">Local</a></li>
428+ <li class="page_item page-item-22"><a href="https://juju.ubuntu.com/get-started/amazon/">Amazon Web Services</a></li>
429+ <li class="page_item page-item-18"><a href="https://juju.ubuntu.com/get-started/hp-cloud/">HP Cloud</a></li>
430+ <li class="page_item page-item-16"><a href="https://juju.ubuntu.com/get-started/rackspace/">Rackspace</a></li>
431+ <li class="page_item page-item-3596"><a href="https://juju.ubuntu.com/get-started/openstack/">Openstack</a></li>
432+ <li class="page_item page-item-3600"><a href="https://juju.ubuntu.com/get-started/maas/">MAAS</a></li>
433+ </ul>
434+ </li>
435+ <li class="grid-3">
436+ <h4><a href="/resources">Resources</a></h4>
437+ <ul>
438+ <li><a href="http://juju.ubuntu.com/docs">Documentation</a></li>
439+ <li><a href="/resources/videos/">Videos</a></li>
440+ <li><a href="http://uistage.jujucharms.com:8080/">Juju GUI demo site</a></li>
441+ </ul>
442+ </li>
443+ <li class="grid-3">
444+ <h4><a href="/community">Community</a></h4>
445+ <ul>
446+ <li class="page_item page-item-28"><a href="https://juju.ubuntu.com/community/juju-blog/">Juju Blog</a></li>
447+ <li class="page_item page-item-4262"><a href="https://juju.ubuntu.com/community/weekly-charm-meeting/">Weekly Charm Meeting</a></li>
448+ <li class="page_item page-item-4036"><a href="https://juju.ubuntu.com/community/charmers/">Charmers</a></li>
449+ <li><a href="https://lists.ubuntu.com/mailman/listinfo/juju">Mailing List</a></li>
450+ <li><a href="http://webchat.freenode.net/?channels=juju">Chat</a></li>
451+ <li><a href="http://askubuntu.com/questions/tagged/juju?sort=faq&pagesize=50">FAQ</a></li>
452+ </ul>
453+ </li>
454+ <li class="grid-3 last-col">
455+ <h4><a href="https://launchpad.net/juju">Code</a></h4>
456+ <ul>
457+ <li><a href="https://launchpad.net/juju-core">Juju Core</a></li>
458+ <li><a href="https://launchpad.net/charms">Charms</a></li>
459+ </ul>
460+ </li>
461+ </ul>
462+ </nav>
463+ </div>
464+ </div>
465+ <div class="row no-border">
466+ <div class="legal inner-wrapper">
467+ <p>&copy; 2013 Canonical Ltd. Ubuntu and Canonical are registered trademarks of Canonical Ltd.</p>
468+ <p><a href="https://bugs.launchpad.net/juju-website/+filebug">Report a bug on this site</a></p>
469+ </div>
470+ </div>
471+</footer>
472+
473+ <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
474+ <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js"></script>
475+ <script src="//d38yea5fb4e2oh.cloudfront.net/jquery.stacktack.min.js"></script>
476+ <script type="text/javascript" src="js/main.js"></script>
477+ <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.js"></script>
478+ </body>
479+</html>

Subscribers

People subscribed via source and target branches