Merge lp:~jorge/juju-core/nodeapp-example into lp:juju-core/docs
- nodeapp-example
- Merge into 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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
charmers | Pending | ||
Review via email:
|
Commit message
Description of the change
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’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’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’ll deploy to an AWS environment called <code>amazon</code>. First let’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’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’ve repeatedly upgraded your application locally it’s time to push it out to a place where your coworkers can see your app in all it’s glory, let’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’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’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’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’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 “Procfile†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>© 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> |