h2non / imaginary

Fast, simple, scalable, Docker-ready HTTP microservice for high-level image processing
https://fly.io/docs/app-guides/run-a-global-image-service/
MIT License
5.65k stars 461 forks source link

Alpine linux based image instead of ubuntu #125

Open anaganisk opened 7 years ago

anaganisk commented 7 years ago

Are there any plans to use Alpine linux, base image for docker instead of Ubuntu:14.0? According to docker file it builds on a base image of marcbachmann/libvips which is built on ubuntu. Alpine linux based image will make the container more lightweight.

sbani commented 7 years ago

Hi @anaganisk,

I just wanted to say that I tried to rebuild the marcbachmann/libvipsimage with alpine but lost the battle installing all requirements. I tried to do it ~1/2 year ago. There's a good chance that it's still hard to achieve.

Though, it's not impossible and I just wanted to clarify that it's not just a "replace ubuntu with alpine" task.

Nevertheless, we would also be really happy about a tiny container.

anaganisk commented 7 years ago

@sbani I've looked into another project which had a similar problem https://github.com/lovell/sharp/issues/242 I dint go through it completely, but may be I could do a PR if I succed.

sbani commented 7 years ago

I found that one too, but it didn't work for me as well. Thanks for your offer @anaganisk. Let's wait for @h2non's thoughts about this topic.

h2non commented 7 years ago

Sorry for the latency here. Got busy lately.

Are there any plans to use Alpine linux, base image for docker instead of Ubuntu:14.0?

No, but any help trying to make the project better and more versatile is always welcome.

According to docker file it builds on a base image of marcbachmann/libvips which is built on ubuntu. Alpine linux based image will make the container more lightweight.

I never tried compiling libvips in a hacked Linux distribution that doesn't depend on glib bindings, but this and considering the limited stack size, this is something that scares me a bit, so I don't know about the real viability of this.

It would be a nice weekend hack experiment testing it :)

sbani commented 7 years ago

I created a docker image layer comparison:

With ubuntu: 975MB. With alpine: 792MB (only when you do not have to install any additional dependencies!)

We could save ~18%. I think, when reality hits us, we need to install additional deps and that makes the alpine based image even bigger and we have less savings.

It's always a good thing to have smaller containers and I will help you where I can, but when we talk about business like ours, i think, it's not worth working on it, because there is no pain at the moment.

But it is for sure worth hacking at the weekend! :)

Dynom commented 7 years ago

I don't really care much for the image size for Imaginary, but I've spent a few to try to reduce the Docker images size as a fun exercise.

The results: Virtual size: 521MiB Download size: 196.9 MiB

So practically speaking, they're around half the size of the official Docker images.

It's not based on Alpine, but rather I've change the Dockerfile. That allowed me to reduce some steps and quite a few expensive layers. Since Docker recently got multi-stage builds we could switch over to that, making this less horrific and much more maintainable.

They work fine, feel free to try 'm out:

docker run --rm -it dynom/imaginarydocker:xenial-v1.0.3 -h
mikestead commented 7 years ago

I've had a go at piecing together an Alpine image today, more as a learning experience.

https://hub.docker.com/r/stead/imaginary-alpine

I first built a single Dockerfile which tries to clean up build dependencies, that one came out around 58mb compressed.

I then tried a multi-step Dockerfile and copied into a clean Alpine image only what seemed to be needed to work. That came out at 20mb compressed.

[Edit] Now Docker Hub supports multi stage builds I've switched over to use that method exclusively with this Dockerfile.

docker run --rm stead/imaginary-alpine -h

For that I copied over the compiled vips lib directory. Are any others binaries required e.g from vips bin folder for run time usage? I did some basic testing and all seemed good, but there's a good chance I could be missing something.

It would be great to get some more experienced eyes over both Dockerfiles. I'm a little inexperienced with vips and go.

[Edit] One question I have is around libvibs compilation. The bimg preinstall script I used as reference when writing the Dockerfile(s). However looking at the Dockerfile for Imaginary there are some obvious differences. For example

Dockerfile:

./configure --enable-debug=no --without-python

Preinstall script:

./configure \
    --disable-debug --disable-docs --disable-static \
    --disable-introspection --disable-dependency-tracking \
    --enable-cxx=yes --without-python --without-orc --without-fftw

Given bimg is the gateway for image transforms, am I correct in using its preinstall script as reference, or is the imaginary Dockerfile correct? Do we need orc and fftw?

mikestead commented 7 years ago

I've added in fftw and orc support just in case. That brings the lite image to 23mb. Would be good to get some feedback on the above when someone in the know gets some time.

tyranron commented 7 years ago

@mikestead nice work. Maybe there is a time to propose PR?

Additionally, some e2e tests may be implemented to be sure that Docker image has everything required and works OK.

h2non commented 7 years ago

That a great idea. I have been thinking for a while about the E2E functional tests. I will implement this in a near future.

jbergstroem commented 7 years ago

Reckon I could give this a go; getting comfortable with alpine - but it seems like @mikestead is pretty much on track.

mikestead commented 7 years ago

Just an update from recent refinements. There's a nice vips package for Alpine I'm using now. This has helped bring the image to 16mb compressed.

https://github.com/mikestead/docker-imaginary-alpine/blob/master/Dockerfile https://hub.docker.com/r/stead/imaginary-alpine

There's a caveat I've run into and that @h2non mentioned previously. Alpine uses musl and it has a limited amount of stack space vs glibc. I've seen this manifest as a segmentation fault if you attempt more complex transforms at any type of load, i.e. transforms requiring a deep stack.

From here it looks like disabling vips cache may avoid the issue, but I expect that would have an impact on performance and I'm not sure that option is available via bimg(?).

So from my testing if you're doing multiple expensive transforms on images e.g. resizing AND sharpening, then using a linux distro based on glibc is recommended. If you're doing more simple operations like just resizing then you should be ok. Worth running some tests if you're not sure.

If it's still seen of value I can look to open a PR for the Alpine Dockerfile into this repo.