Docker: team up to create a reference docker image for meteor

@abernix that seems like amazing progress. Especially having a CI testable image.
I’m going to experiment with it asap. Do I just run it like meteorD?

I know some people will ask about phantomjs and imagemagick dependencies (not my case).

Can you expand on the MUP issue? It’s also also not my case, but I’m sure someone would ask for it.

1 Like

There is a README that explains how to use it. But essentially, yes. Let me know how it goes for you!

Well, not really. The reason is above. :slight_smile:

In some future version of Docker (1.14, they claim now) it may not be necessary to land my PR with Meteor Up, but as it stands right now it’s not possible to run on port 80 as an unprivileged user without some problem popping up on one storage driver or another. This is the only reliable way right now. No matter what happens, it would still be better to land that PR so that Docker images with different exposed ports could be used.

If PhantomJS is necessary, the developer should use the phantomjs-prebuilt NPM in their project just like any other NPM. The binary will be available in node_modules/.bin/phantomjs and they can set PHANTOMJS_BIN in their environment to that path and most tools will use it automatically .

I find it unlikely that I will consider an option to built-in PhantomJS. It’s not necessary since it can be included at the app-level. I imagine there is something similar available for imagemagick.

@abernix,
Thanks for making great documentation in a short time ( I hadn’t seen it the first time, I accessed it).

@arunoda any opinions on the pull request for MUP.

I forked kadirahq/mup and merged @abernix’s pull request for image port and I also merged another pull request that gives unique env variable per server. It is working now with abernix/spaceglue. Here it is:

To build mup you need npm3 or install missing dependencies:

npm install --save-dev npm install nofat babel-cli babel-preset-es2015 babel-preset-stage-3

@jamesgibson14 glad to hear the patches pass.

(I made a longer announcement in another thread, crossposting since it’s relevant here, too. See the announcement for details.)

I made a project called MiniMeteor, which is an easy solution to dockerize Meteor apps, images are as small as 20MB (compressed), supports Docker Hub, doesn’t run as root, works with all versions of Meteor 1.3 and above: https://github.com/aedm/minimeteor

@aedm the file size is impressive. I’d be interested to see this effort merge with abernix/spaceglue.

@abernix, any thoughts on using alpine-linux? Would be interesting as a security measure as well, to reduce the attack surface, since there are less dependencies.

1 Like

Alpine is kind of special, it can’t run Meteor at the moment, and requires several build passes and a lot of custom code to make it work. But there are a few lower hanging fruits for SpaceGlue, like using a “slim” Debian image, or merging RUN commands and uninstalling build tools in the Dockerfile.

I never used mup myself, but I believe it should work with MiniMeteor, too. Will take a look.

@jamesgibson14 Thanks for confirming that it worked. Maybe post your findings in the PR. I think it would be best to build the tests that were requested in this pull request and get the PR merged in officially.

@aedm Great news on your image. You would need that PR to work with Meteor Up and some other changes too (as it works mainly on mounts, but it should be doable). I’m absolutely open to changing some aspects of SpaceGlue though. I realize folks are looking for a “small image”, but I think there are some considerations to make.

For example, I think it’s worth weighing out the build-speed benefits are achieved of having the cached Docker layers produced by the additional RUN commands and the use of the -builddeps image for the -onbuild image which needs most of those tools to be installed to reliably build all projects that are thrown at it.

In SpaceGlue, I chose buildpack-deps:jessie-curl since it is used by the node Docker image right now. It is a large base image though. I do think Alpine is the direction to go, but I haven’t been able to say (in other words, I don’t have time to test) that every project thrown at SpaceGlue would build properly on Alpine. I’m fairly confident in Debian right now and SpaceGlue is meant to “just work”.

I think there is a benefit to the faster image build times achieved by having the dependencies already downloaded and installed. The bulk of the size in my images is the Debian OS, and various compiler toolchain components. In practice, these layers are cached by CI servers (and container registries) and are loaded (and are docker pushed-to) fairly quickly. For example, if I do a new commit to my repo, my image is very quickly already building the app itself and not apt-get-ing various build dependencies.

In an enormous deployment I understand the benefits of the slim images. Even if I was to remove the build dependencies in the Dockerfile, unless they are all done in the same step, the higher layers hold most of weight still and aren’t freed up. Given the current setup, if a smaller image is desired, something like docker-squash can be helpful and would do a nice job of “flattening” the image created by SpaceGlue (if I actually push the commits which apt-get remove things at the end of the build, which I haven’t, yet).

I’m not sure there is a way to do everything perfectly with a single image which you reference in your app. I could imagine the most benefit in a setup which runs from outside Docker and passes work to various Docker images which do a particular portion of the workload. A three-part system, for example: 1) Which builds the bundle meteor build and outputs the tarball, 2) An Alpine distro with build dependencies which takes that tarball recompiles it and outputs another tarball, 3) An Alpine distro that just runs the final tarball.

Sheesh, the more I think about all the ways this could be done, the more I intend to use Galaxy for any future project. Running your own infrastructure can be a real time-sink. :wink:

That’s exactly how MiniMeteor builds an Alpine image. :slight_smile:

I absolutely agree with you that build times should be considered. I made a few experiments a while ago, and have some results to share (runtimes measured on GitLab CI):

  • My first, naive Dockerfile took 12-15 minutes to build. It used RUN apt-get..., RUN curl..., etc. But because RUN creates a new image layer, this approach has quite an overhead. Also, images were large, ~400M (compressed).
  • Then I made a Docker image for every Meteor release with all the build tools preinstalled, and used the appropriate version to build the bundle. (Docker Hub: aedm/meteor, new releases are still detected and built automatically). Using that I was able to decrease build times to 6-7 minutes. I believe this is similar to what you suggested, and it’s still the fastest approach I found.
  • Currently, I install, build and uninstall everything in a single RUN command. This way Docker doesn’t have to create intermediate layers. Build time is 7-10 minutes, and the image is a lot smaller.

I decided MiniMeteor should use the 3rd approach. Build time difference is about 2 minutes, but deployment of these smaller images got roughly 0.5-1 minute faster. I believe the smaller attack surface is worth the extra time if one creates a release image.

2 Likes

Nice! Sorry, I didn’t get to actually look into the project much before. I still haven’t tested it, but I submitted a couple comments on the repo itself. I do think that is the right direction though.

I’ll probably have to retract my statement about it working with Meteor Up due to the cross-platform nature of Mup (it runs on the developer’s machine and the target Docker image must be capable of recompilation).

I apologize for not chiming in here sooner. I have a very terse Dockerfile and deployment setup available at:

The .builddeploy.sh script is meant to be customized for your individual Meteor setup. The Dockerfile is purposefully very basic and meant to be a rock-solid solution for building with Docker. Hope this helps someone. I’ve been using this in production with Kubernetes for 6+ months now.

Can someone help me add cairo to the docker image. I found a prebuilt docker image (romaroma/meteord) which adds cairo but doesn’t have a visible dockerfile.

The commands needed which I use when manually building are -

sudo apt-get install -y build-essential
sudo apt-get install -y libcairo2-dev libjpeg-dev libgif-dev

Should be easy to include in the docker build but I’m new to all this and having a hard time. When I use the abernix/spaceglue image (onbuild) it fails in the ‘node-gyp’ build stage which is the error I get if I don’t install the above libs.

The goal is to build a standalone docker image to run on Kubernetes or ECS. If there is a simpler way please let me know.

I use this base Docker image for my Meteor apps: https://github.com/tozd/docker-meteor

Example how to use it for your Meteor app:

Both inspired and challenged by this forum post I came up with a slightly different solution some of you might find interesting:

1 Like

It is crazy how this thread is again an illustration of: https://xkcd.com/927/ :slight_smile:

We now have more images than at the beginning I guess :slight_smile:

I think we should get an official image with all the features we want as tags (onbuild, slim, alpine…).
But let’s get started small, and get this PRed:

So, which Dockerfile should we use and PR?
(I’d prefer one based on jessie, and then we can add alpine later)
(It has to respect https://github.com/docker-library/official-images )

3 Likes

@pierreozoux I agree. I’m glad we found some interesting contributions. My vote is for us to use @abernix fork of meteord as a starting point. Any other ideas?

2 Likes

I’m genuinely sorry to interject, but I do hope you all reach out to the folks working on the “wefork” Wekan project. The developers there are clearly very motivated and they have an open issue to push their Docker image to Docker hub : https://github.com/wefork/wekan/issues/33

Really, it would be great if the broader Meteor community could agree on a common Dockerfile. Such a project might be best housed by the wefork team, as they seem really keen on Docker best practices.

In any case, please take a look at what they’ve built : https://github.com/wefork/wekan/blob/devel/Dockerfile

Looking forward to more Meteor + Docker :heart:

@abernix Now that you are at Meteor, do you have any new input on how to promote a “reference docker image”. Thanks

It’s been mentioned before (in fact, you referenced it yourself in your opening topic on this thread), but the likeliness of a MDG-backed Docker image is low, perhaps zero. The Docker image would not used internally on any internal apps and therefore would be subject to falling out of date quickly.

Additionally, even before I started, I barely used the Docker images I’ve provided already and for my apps there’s just no simple Docker configuration that I could rely on (nor am I sure there would ever be) without focusing too much attention on them when it came to scaling, etc. I prefer a simpler approach.

I guess I’m not sure why you’re not embracing one of the many forks mentioned above as a community? There are many in play and many of them work. Sure they have their various shortcomings, but isn’t that something that the community should work through and iron out?

As far as a community “base” image suggestion, while my meteord fork is fine (and functioning) for those using MUP with Meteor >= 1.4 and my spaceglue version has what I believe to be some valuable changes, I wouldn’t “vote” for either of mine to be used as the base for a community (or even Docker “official”) image – they create extremely, extremely large images. Again, probably good for MUP users though.

Based on what I’ve seen, I’ve liked https://github.com/aedm/minimeteor the most. Maybe it’s no longer important for MUP to be supported, or maybe a new tool could come into existence, I’m not sure.