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

ask him on github.
my image is currently 905 MB

I think you were confused. I donā€™t see anything about GridFS bein abandoned

Yep, I was thinking of https://github.com/aldeed/Meteor-CollectionFS

For what itā€™s worth, as long as youā€™re using Meteor 1.4.2.1 (and not exactly Meteor 1.4.2 due to a bug in core) or Meteor 1.4.1.3, my abernix/meteord image (including the :onbuild tag) should be working once again. Iā€™ve also updated it to Node 4.6.2.

Iā€™ve also pushed out abernix/spaceglue to Docker Hub which is now a complete re-write of abernix/meteord (which was a hacked-together version of meteorhacks/meteord). This was what I had previously mentioned was in my v2 branch on abernix/meteord. It turns out the changes were significant enough to get a new name, even if there is still some similar functionality, because there is no way it could reconverge with the master branch. It has a several advantages over /meteord.

SpaceGlue:

  • Is smart enough to download the exact version of Meteor necessary when building (previously, the latest published release PLUS the version your app needed had to be downloaded ā€“ this was mainly just slow).
  • Has a smaller footprint (The base is almost half the size around ~250mb. The builddep images are bigger, but still smaller than meteord ā€“ Iā€™m sure thereā€™s room for improvement)
  • Adds a lot of tests to facilitate updates ā€“ Iā€™d have confidence in accepting a pull-request now if the tests work on CircleCi. :slight_smile:
  • Deploys new versions (of the Docker image) automatically to Docker Hub via CircleCI after tests pass successfully (does not use Dockerā€™s Build system though since it doesnā€™t support a clean nested tag dependency system)
  • Does not run node as root (long-overdue for security reasons)
  • Should re-build any binary dependencies with less problems (by providing better node-gyp build dependencies)
  • Will work with Kadiraā€™s Meteor Up if one change gets accepted (already PRā€™d). I tried to avoid this change being necessary and keep things on port 80, but due to variations in allowed kernel capabilities, I couldnā€™t. Specifically, due to ongoing, back-and-forth issues with supporting the net_bind_service cap, this isnā€™t possible. Plus, even if it was implemented, many users still use Docker 1.9 or earlier and it will take some time to update them all.

In regards to the question(s) of combining effortsā€¦ again, Iā€™m all for it, but Iā€™d want a clear plan and small actionable items to help with that. I will happily review and accept pull-requests, but I have a lot of other things Iā€™m taking care of. (Slash, sorry I just created another Docker image, but that seems to be the common theme in this issue anyhow :slight_smile:).

4 Likes

@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