Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Leaner Docker Image #5

Closed
wants to merge 3 commits into from
Closed

Conversation

captn3m0
Copy link

@captn3m0 captn3m0 commented Jan 1, 2019

Still a WIP. Planning to switch this to a 2-stage docker build, similar to what https://github.com/fornwall/rust-static-builder/ suggests.

Need help with converting this to a completely static binary.

Ideally, the ssl certs should not be built into the image. With Docker based setups, either of these two is the norm:

  1. TLS termination is handled by another service, which proxies over HTTP. You can use something like https://gilyes.com/docker-nginx-letsencrypt/ to proxy across.
  2. Terminate TLS, but instead of using insecure certificate, rely on a volume mount for administrators to mount the SSL key and certificate.

@izderadicka
Copy link
Owner

@captn3m0 Thanks for looking into this - I already looked a bit around and found that my docker knowledge is really outdated. For now I changed base image to debian:stretch-slim, which decreased image by 1G.

I think two stage docker file is definitely the way to go. I've made too many useless layer, so just efficiently reorganizing Docker file in this way could help a lot.

For completely static build I looked at this builder image

Completely static build in Rust looks bit complicated as it need musl libc as base, which means everything else needs to be recompiled. So above mentioned builder image needs at least taglib and taglibc. Considering that I never tested with musl libc, I think this should be probably only optional solution now for people really in need of small image.

By using good two stage build with debian slim we can get to 100s MB with gcc libc and few other libs, shell, etc., which would be good progress. Then we can look at fully static build.

@captn3m0
Copy link
Author

captn3m0 commented Jan 1, 2019

Debian Slim should work great!

I'll still keep this open for the other improvements (fewer layers, cleaner entrypoint etc)

I tried going with Alpine for musl, but I couldn't find libtag1 packaged.

@izderadicka
Copy link
Owner

And re: SSL termination - I agree, I'm using nginx as rev proxy. And mounting ssl dir sounds reasonable.

@mpatton125
Copy link
Contributor

mpatton125 commented Jan 1, 2019

@captn3m0 Thanks for looking into this - I already looked a bit around and found that my docker knowledge is really outdated. For now I changed base image to debian:stretch-slim, which decreased image by 1G.

I looked into this too, but unfortunately for me my complete lack of rust knowledge is a hindrance. :)
Also, in regards to your latest build image - it appears to be much larger than my previous build? It shows on my system as 2.64GB compared to previous 1.99GB?

@izderadicka
Copy link
Owner

izderadicka commented Jan 2, 2019

@mpatton125 - I added some more dependencies to be able to compile with new feature libavformat too (replacement for taglib - it's from ffmpeg package support matroska, webm etc. basically everything what exists). But this increased size to 2.7G. Later in evening I just changed from ubuntu to debian slim and it reduces size back to 1.9GB (when build locally - for some reason on Docker Hub it's bigger). I'll try 2 stage Dockerfile with Debian to see now it can be reduced without static compilation.

@izderadicka
Copy link
Owner

izderadicka commented Jan 2, 2019

I pushed new version of Dockerfile to master. I think it's not final, but at least builds significantly smaller image ( ~ 200MB). It's based on debian:stretch-slim and is using two stages. Also it's now using statically build ffmpeg (which itself is of considerable size ~ 60MB).

Next step could be complete static build and alpine based image? But as I was thinking about it there are other thing to consider. audioserve now needs ffmpeg - so it should be also in the image (and available static build is against gcc libc - rebuilding against musl can be a challenge, so it's probably not worst to try, just use it as it is). And we're using also shell script to start the program - but shell is simple I guess busybox can handle it?

@captn3m0
Copy link
Author

captn3m0 commented Jan 2, 2019

Separating out the node and rust builds into different stages (build gets faster). Working on the remaining changes as well.

I think 200MB image size is decent enough for now.

As per rust documentation, lockfiles should be committed
for binary applications.
@mpatton125
Copy link
Contributor

Agreed. A ~200Mb build is inline with a lot of other container images out there and a significant improvement.

Well done guys. 😀

COPY audioserve.sh .

CMD ./audioserve.sh
ENTRYPOINT ["/audioserve/audioserve"]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to keep wrapper script - for demo/testing purposes it's invaluable as one can play with command line args. $PORT is for instance needed if one wants to try on heroku.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docker allows passing command line args to the entrypoint, I was relying on that

Will keep PORT, but it might be better handled at the app itself. (instead of reading it as env and passing it as a argument)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see now - that could be easier solution then script unless we would need to mess with args - like $PORT or $USE_UNSECURE_CERT

ENV SECRET=mypass
ENV SSLKEY=./ssl/audioserve.p12
ENV SSLPASS=mypass
ENV DIRS=/audiobooks
ENV PORT=3000
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If wrapper script is not use it does not make sense, as audioserve will then always run on port 3000

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since Docker supports port mappings, having a standard port for your application (while running using Docker) is not a bad idea. All the linuxserver.io docker containers use one: booksonic, radarr for eg.

Still WIP, will take this into account, and maybe read it directly in code instead?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes - but I've seen on Heroku that it requires that image use $PORT container listening port. But can be added to app as you noted.

Dockerfile Show resolved Hide resolved
Cargo.toml Show resolved Hide resolved
@izderadicka
Copy link
Owner

izderadicka commented Feb 28, 2019

Hi,
@captn3m0 - any plans to finish this PR?
I already took some ideas from your PR, thanks for that.
If not planning to finish I'll close it as current Dockerfile provides leaner image. Better results could be achieved only with static build, which is now stucked on compilation of libtag, as I've explained in emk/rust-musl-builder#65

@captn3m0
Copy link
Author

captn3m0 commented Mar 1, 2019

Yeah, closing this as current is quite lean already. 👍

@captn3m0 captn3m0 closed this Mar 1, 2019
@izderadicka
Copy link
Owner

@captn3m0 OK closing, thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants