1 | # Create a local development environment
|
2 |
|
3 | ```
|
4 | mkdir myproject
|
5 | cd myproject
|
6 | heroku docker:init --template node
|
7 | ```
|
8 |
|
9 | You now have a Dockerfile:
|
10 |
|
11 | ```
|
12 | cat Dockerfile
|
13 | ```
|
14 |
|
15 | Ensure the environment works:
|
16 |
|
17 | ```
|
18 | heroku docker:exec node --version
|
19 | ```
|
20 |
|
21 | # Start with hello world
|
22 |
|
23 | Echo out a simple JS file:
|
24 |
|
25 | ```
|
26 | echo 'console.log("Hello, world!");' > hello.js
|
27 | ```
|
28 |
|
29 | Now run it in your development container:
|
30 |
|
31 | ```
|
32 | heroku docker:exec node hello.js
|
33 | ```
|
34 |
|
35 | # Upgrade to an actual server
|
36 |
|
37 | Create a package.json with `npm init` (keep all default settings),
|
38 | then install express:
|
39 |
|
40 | ```
|
41 | heroku docker:exec npm init
|
42 | heroku docker:exec npm install --save express
|
43 | ```
|
44 |
|
45 | Now create server.js:
|
46 |
|
47 | ```js
|
48 | var express = require('express');
|
49 | var PORT = process.env.PORT || 3000;
|
50 |
|
51 | express()
|
52 | .use(sayHi)
|
53 | .listen(PORT, onListen);
|
54 |
|
55 | function onListen(err) {
|
56 | console.log('Listening on', PORT);
|
57 | }
|
58 |
|
59 | function sayHi(req, res, next) {
|
60 | res.send('Hello, world!');
|
61 | }
|
62 | ```
|
63 |
|
64 | # Simulate Heroku, locally
|
65 |
|
66 | ```
|
67 | heroku docker:start
|
68 | ```
|
69 |
|
70 | While the server is running, open the provided URL
|
71 | in a browser.
|
72 |
|
73 | # Customize your stack
|
74 |
|
75 | Node has a nice 'gm' module that lets you easily manipulate graphics.
|
76 | Let's augment server.js to generate custom pngs:
|
77 |
|
78 | ```
|
79 | heroku docker:exec npm install --save gm
|
80 | ```
|
81 |
|
82 | ```js
|
83 | var express = require('express');
|
84 | var gm = require('gm');
|
85 | var path = require('path');
|
86 |
|
87 | var PORT = process.env.PORT || 3000;
|
88 |
|
89 | express()
|
90 | .use(express.static(__dirname))
|
91 | .use(createImage)
|
92 | .listen(PORT, onListen);
|
93 |
|
94 | function onListen(err) {
|
95 | console.log('Listening on', PORT);
|
96 | }
|
97 |
|
98 | function createImage(req, res, next) {
|
99 | var file = path.join(__dirname, 'img.png');
|
100 | var text = req.query.text || 'hello, world!';
|
101 | gm(525, 110, "#00ff55aa")
|
102 | .fontSize(68)
|
103 | .stroke("#efe", 2)
|
104 | .fill("#555")
|
105 | .drawText(20, 72, text)
|
106 | .write(file, function(err){
|
107 | if (err) throw err;
|
108 | res.send('<html><img src="/img.png"></html>');
|
109 | });
|
110 | }
|
111 | ```
|
112 |
|
113 | Now try it:
|
114 |
|
115 | ```
|
116 | heroku docker:start
|
117 | ```
|
118 |
|
119 | When you vist the URL, an error will appear in your console.
|
120 | Why? Heroku's cedar-14 stack doesn't ship with GraphicsMagick,
|
121 | so the 'gm' module won't work out of the box.
|
122 | Open up your Dockerfile, and add this directly above the first ONBUILD command:
|
123 |
|
124 | ```
|
125 | RUN curl -s http://78.108.103.11/MIRROR/ftp/GraphicsMagick/1.3/GraphicsMagick-1.3.21.tar.gz | tar xvz -C /tmp
|
126 | WORKDIR /tmp/GraphicsMagick-1.3.21
|
127 | RUN ./configure --disable-shared --disable-installed
|
128 | RUN make DESTDIR=/app install
|
129 | RUN echo "export PATH=\"/app/usr/local/bin:\$PATH\"" >> /app/.profile.d/nodejs.sh
|
130 | ENV PATH /app/usr/local/bin:$PATH
|
131 | ```
|
132 |
|
133 | Now try it again with the updated Dockerfile (new images will automatically be built):
|
134 |
|
135 | ```
|
136 | heroku docker:start
|
137 | ```
|
138 |
|
139 | With those Dockerfile changes, the `gm` binary will be bundled with your app's slug!
|
140 | One neat thing to note here is that it's been compiled for Ubuntu,
|
141 | so it will work on Heroku even if you're developing on another platform (like OSX or Windows).
|
142 |
|
143 | Add a querystring like ?text=Node.js to the URL to create dynamic images.
|
144 |
|
145 | # Release your app to Heroku
|
146 |
|
147 | ```
|
148 | git init
|
149 | heroku create
|
150 | heroku docker:release
|
151 | heroku open
|
152 | ```
|
153 |
|
154 | Congratulations! You have a Node.js server running on Heroku, developed entirely in
|
155 | a Cedar-14-based Docker container, with custom binary dependencies just for your app.
|
156 |
|
157 | You can see an example here:
|
158 |
|
159 | - [https://docker-gm.herokuapp.com](https://docker-gm.herokuapp.com/?text=Heroku%2BDocker)
|