Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 118
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 119
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 118
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 119
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 118
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 119
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 118
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 119
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 118
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 119
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 118
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 119
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 118
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 119
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 118
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 119
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 118
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 119
BestASPNETHostingReview.com | Best and cheap Node.js hosting. Here is the newest addition: the ability to deploy apps on Process Manager as containers, using Docker.
This post outlines challenges with Docker, especially when you are “Dockerizing” your Node applications, demonstrates some failed attempts at trimming it down, and shows how you can use StrongLoop Process Manager to containerize your Node apps with a drastically reduced footprint!
Containerizing Apps The Hard Way
Anyone who has heard of Docker has probably spent at least a few seconds at least thinking about containerizing their app. If you are like me, you probably scanned the docs and decided you didn’t have time to figure it out, and that was the end of it.
And then I went back a month later and got a little bit better idea of what this Docker thing is, but ran out of time again. And then I repeated the process a couple more times until I finally had an idea of what Docker is and how I could use it to streamline some of my app deployments.
So then I started “Dockerizing” my app. It isn’t too hard: there is an example of Dockerizing a Node.js Web App on the Docker website that covers the basic steps. Unfortunately, it uses an outdated version of Node and npm because it uses the RPMs provided by CentOS. It turns a single-file node package into a ~550MB image. Disk is cheap, as they say, but anyone who has used Docker a while knows that it really likes to fill up your hard drive.
Trimming it Down
I’ve copied the index.js, package.json, and Dockerfile from that guide and put them in a directory, then ran docker build -t node-experiment:original. to get my baseline and then ran a Docker images node-experiment to get a list of the images in the node-experiment repo:
1 2 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE node-experiment original d62cec98eff3 About a minute ago 557.9 MB |
OK, let’s trim this down a bit, and see if we can make it a little friendlier to distributing across a network, or over the Internet.
First we need to figure out what’s taking up all this space. Here are some of the larger items in the resulting image:
- 66M /var/cache/yum
- 95M /usr/lib/locale
- 11M /usr/lib/gcc
- 62M /usr/share/locale
And those are just the directories that are easy to clump together, but it’s a good start. We can do some experimenting and add the following lines to the Dockerfile from that tutorial:
1 2 3 4 | RUN rm -rf /var/cache/yum RUN rm -rf /usr/lib/locale RUN rm -rf /usr/lib/gcc RUN rm -rf /usr/share/locale |
Now we rebuild our image, docker build -t node-experiment:take-2 ..
Notice that it doesn’t take as long the second time. That’s because it is able to re-use the layers from the previous build.
Now look at the image again, with Docker images node-experiment
, and revel in our genius:
1 2 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE node-experiment take-2 77afd260f0be 32 seconds ago 557.9 MB |
Docker Images are Like Ogres
Remember how the second build went faster because it was re-using the layers from the previous build? Every line in the Dockerfile is creating one of those layers, including those rm -rf … lines we added. So those lines aren’t actually deleting anything, they’re adding another layer that applies a mask to “delete” the given files on the resulting multi-layer file system. If you’re thinking that actually uses more space than it saves, you’re right. If you’re thinking this sounds a lot like what happens when you commit a large file to Git and then later remove it, but your repo doesn’t shrink, you’re right again.
So what can we do about this?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | FROM centos:centos6 # Enable EPEL for Node.js RUN rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm # Bundle app source COPY . /src # Install Node.js and npm, install app dependencies, and remove extraneous files RUN yum install -y npm \ && cd /src; npm install \ && rm -rf /var/cache/yum \ && rm -rf /usr/lib/locale \ && rm -rf /usr/lib/gcc \ && rm -rf /usr/share/locale EXPOSE 8080 CMD ["node", "/src/index.js"] |
Notice we had to do some rearranging so that we copied the app over before installing Node. That means our speed-up from layer re-use is going to disappear since it will have to re-install Node every time. Mildly annoying, but if the image is significantly smaller, it might be worth the extra minute it takes to rebuild the image. Let’s give that a try and tag it as node-experiment:take-3
.Notice we had to do some rearranging so that we copied the app over before installing Node. That means our speed-up from layer re-use is going to disappear since it will have to re-install Node every time. Mildly annoying, but if the image is significantly smaller, it might be worth the extra minute it takes to rebuild the image. Let’s give that a try and tag it as node-experiment:take-3
.
1 2 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE node-experiment take-3 530ac86d081b About a minute ago 369.4 MB |
Not bad! Let’s take it one step further and forget about optimizing for layer re-use at all and move all the RUN commands into a single layer and tag it as node-experiment:take-4
.
1 2 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE node-experiment take-4 214481a25b18 26 seconds ago 359 MB |
So we’ve managed to hack about 200MB off the size of the image. But what’s left in our image?
- Node
- npm
- Our app
- Mangled installation of gcc
- Broken locale data
A Better Way
If you’re an avid Git user you might be wishing for a Docker rebase command right about now. Sadly, there is no such command. So what commands are there? Here’s some useful-looking lines from docker help
:
1 2 3 4 5 6 7 8 9 10 11 12 | Commands: build Build an image from a Dockerfile commit Create a new image from a container's changes cp Copy files/folders from a container's filesystem to the host path create Create a new container diff Inspect changes on a container's filesystem exec Run a command in a running container export Stream the contents of a container as a tar archive import Create a new filesystem image from the contents of a tarball load Load an image from a tar archive save Save an image to a tar archive tag Tag an image into a repository |
It looks like with sufficient scripting we could build our image without even using a Dockerfile. I’ll leave it as an exercise for the reader to come up with a way of tying these commands together to produce an image. Instead I’ll describe the general approach I took with StrongLoop’s Process Manager:
- Create a build container with Node, npm, and a complete build toolchain.
- Install strong-supervisor (for clustering, control channel, metrics, etc.)
- Import your app and install its dependencies, including binary addons.
- Create a deployment container with no Node, npm, or build tools of any kind.
- Copy Node, strong-supervisor, and your app into the deployment container.
- Commit the deployment container as an image.
I used the strong-docker-build module to build the one-file app from above for comparison:
1 2 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE node-experiment sl-docker-build 4bca9ae8ad28 About a minute ago 148.1 MB |
Looks like success! Not only is it smaller, but it has an embedded process supervisor with automatic clustering and metrics reporting, and no extra weight from compilers for languages we don’t need.
How to Use It
This is my favorite part. Now that you have some insight into the problem and how to deal with it the hard/wrong way, here’s how to solve it the easy way using StrongLoop PM:
- Install Docker on your server (same as installing the Dockerized StrongLoop PM).
- Install StrongLoop PM (same as installing a production server):
sudo sl-pm-install --driver docker
(the new hotness).
Now, whenever you deploy an app to StrongLoop PM on this server, your app will be turned into a Docker image using the approach described above and then run in a Docker container.
If you’re on a Mac and you want to experiment with the new Docker driver, fear not! While the sl-pm-install command is Linux only, the sl-pm
and slc pm
commands also accept the --driver docker
option, and it works right out of the box if you have a working boot2docker installation.
However you install it, you’ll notice the first startup takes a little longer than usual as it pulls down official Debian and Node images from Docker Hub. You can speed this up by pulling them ahead of time yourself with this command:
1 | $ docker pull debian:jessie && docker pull node:0.10 |
Docker in Docker
While it is possible to run Docker inside Docker, or connect to a Docker daemon from within a Docker container, this first release doesn’t support it. At the time of this writing, that means the --driver docker
option is not compatible with running StrongLoop PM itself as a Docker container.
Whats Next
We’ll continue to develop StrongLoop tools into a full-fledged orchestration and deployment solution for production.