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

Reduce Docker image size further using "multi-stage builds" in Docker CE 17.06 #3730

Closed
anthonyfok opened this Issue Jul 23, 2017 · 6 comments

Comments

Projects
None yet
2 participants
@anthonyfok
Contributor

anthonyfok commented Jul 23, 2017

Thanks to @ellerbrock's optimization effort in #3666 and #3674, the Hugo Docker image generated using the Dockerfile was greatly reduced from 428MB to 277MB, but it still looks a bit big.

It turns out that about 250MB is taken up by /usr/local/go, which is needed for building Hugo, but not needed for running Hugo. So, that got me wondering: Could we build the Hugo Docker image with golang:alpine3.6 (258 MB) like we do now, but use the much smaller alpine:latest (3.96 MB) for the running image?

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
golang              alpine3.6           9f687d7d2a96        3 weeks ago         258 MB
alpine              latest              7328f6f8b418        3 weeks ago         3.96 MB

That way, perhaps future Hugo Docker images could be smaller than 25 MB!

It turns out that it was not a trivial thing to do before, but with the hot new Docker CE 17.06 (released 2017-06-28) and its "Multi-stage Builds" feature, it looks like this goal is within reach:

@ellerbrock, could you please look into this when you are free? (No hurries though, as I am sure it will take a while for Docker CE 17.06 to propagate, e.g. Debian is still at Docker 1.13.1 released in February 2017.) Many thanks!

@ellerbrock

This comment has been minimized.

Show comment
Hide comment
@ellerbrock

ellerbrock Jul 23, 2017

Contributor

Hi @anthonyfok, good idea.
There are a few ways how we could archive this till the new feature is official supported in Docker:

1.) In most cases i currently build and cleanup inside the container. In that case its isolated without any further outside dependencies. The important part here is to install and cleanup in one RUN command to avoid hitting the cache layer to keep the container size small.

2.) Another solution is to setup a proper CI pipeline (https://docs.travis-ci.com/user/languages/go/) and just copy the executable inside the container. I would only use such a solution if all steps are transparent to ensure that no malicious stuff finds a way inside the container and my network (with Travis which you use anyway this is possible).

3.) We could also setup a Automatic Build Task on Docker Hub and define a branch which will trigger a new build with each code push. This also keep it transparent. You can find examples on my Docker Hub Account @ellerbrock, all my containers are build this way. I could help with the setup an and automation it if you like. Would be nice anyway to have an official Hugo Docker Container available.

Let me know which of those solutions you and your team would prefer to use ...

[Update] Here is an interesting article which describes how to start FROM scratch and just add the statically linked go binary file.

Cheers Maik

Contributor

ellerbrock commented Jul 23, 2017

Hi @anthonyfok, good idea.
There are a few ways how we could archive this till the new feature is official supported in Docker:

1.) In most cases i currently build and cleanup inside the container. In that case its isolated without any further outside dependencies. The important part here is to install and cleanup in one RUN command to avoid hitting the cache layer to keep the container size small.

2.) Another solution is to setup a proper CI pipeline (https://docs.travis-ci.com/user/languages/go/) and just copy the executable inside the container. I would only use such a solution if all steps are transparent to ensure that no malicious stuff finds a way inside the container and my network (with Travis which you use anyway this is possible).

3.) We could also setup a Automatic Build Task on Docker Hub and define a branch which will trigger a new build with each code push. This also keep it transparent. You can find examples on my Docker Hub Account @ellerbrock, all my containers are build this way. I could help with the setup an and automation it if you like. Would be nice anyway to have an official Hugo Docker Container available.

Let me know which of those solutions you and your team would prefer to use ...

[Update] Here is an interesting article which describes how to start FROM scratch and just add the statically linked go binary file.

Cheers Maik

@anthonyfok

This comment has been minimized.

Show comment
Hide comment
@anthonyfok

anthonyfok Jul 23, 2017

Contributor

There are a few ways how we could archive this till the new feature is official supported in Docker:

Thanks @ellerbrock! I'd say we just wait until Multi-Stage Builds official lands in Docker Hub, which should happen really soon now, I guess some time this August? See docker/hub-feedback#1039

We are in no real hurry to shrink the Docker image size to < 25MB, so let's just take our time, wait, and do it properly once and for all when it is supported officially in Docker Hub infrastructure where we can use a very clean and straightforward Dockerfile. No need for intermediate hacks that we'd have to throw away in a month or two anyway.

1.) In most cases i currently build and cleanup inside the container. In that case its isolated without any further outside dependencies. The important part here is to install and cleanup in one RUN command to avoid hitting the cache layer to keep the container size small.

Yes, I see you are already doing that very diligently. :-)

2.) Another solution is to setup a proper CI pipeline (https://docs.travis-ci.com/user/languages/go/) and just copy the executable inside the container. I would only use such a solution if all steps are transparent to ensure that no malicious stuff finds a way inside the container and my network (with Travis which you use anyway this is possible).

Nah. I prefer what you currently have in Dockerfile, i.e. building from source, for maximum compatibility and security.

3.) We could also setup a Automatic Build Task on Docker Hub and define a branch which will trigger a new build with each code push. This also keep it transparent. You can find examples on my Docker Hub Account @ellerbrock, all my containers are build this way. I could help with the setup an and automation it if you like. Would be nice anyway to have an official Hugo Docker Container available.

That's a nice idea! What do you think, bep and @spf13?

Contributor

anthonyfok commented Jul 23, 2017

There are a few ways how we could archive this till the new feature is official supported in Docker:

Thanks @ellerbrock! I'd say we just wait until Multi-Stage Builds official lands in Docker Hub, which should happen really soon now, I guess some time this August? See docker/hub-feedback#1039

We are in no real hurry to shrink the Docker image size to < 25MB, so let's just take our time, wait, and do it properly once and for all when it is supported officially in Docker Hub infrastructure where we can use a very clean and straightforward Dockerfile. No need for intermediate hacks that we'd have to throw away in a month or two anyway.

1.) In most cases i currently build and cleanup inside the container. In that case its isolated without any further outside dependencies. The important part here is to install and cleanup in one RUN command to avoid hitting the cache layer to keep the container size small.

Yes, I see you are already doing that very diligently. :-)

2.) Another solution is to setup a proper CI pipeline (https://docs.travis-ci.com/user/languages/go/) and just copy the executable inside the container. I would only use such a solution if all steps are transparent to ensure that no malicious stuff finds a way inside the container and my network (with Travis which you use anyway this is possible).

Nah. I prefer what you currently have in Dockerfile, i.e. building from source, for maximum compatibility and security.

3.) We could also setup a Automatic Build Task on Docker Hub and define a branch which will trigger a new build with each code push. This also keep it transparent. You can find examples on my Docker Hub Account @ellerbrock, all my containers are build this way. I could help with the setup an and automation it if you like. Would be nice anyway to have an official Hugo Docker Container available.

That's a nice idea! What do you think, bep and @spf13?

anthonyfok added a commit that referenced this issue Jul 26, 2017

Dockerfile: Reduce image size from 277MB to 27MB
"xtrem" awesome container size optimization
by using alpine:3.6 as base image
and by installing Go at build time.

See #3730 and #3738
@anthonyfok

This comment has been minimized.

Show comment
Hide comment
@anthonyfok

anthonyfok Jul 26, 2017

Contributor

Hi @ellerbrock,

Thank you for drastically shrink the image from 277MB to 27MB! "Extreme" indeed!

You might like to consider applying this small change to further shrink the image to 20.5MB with the use of -ldflags '-s -w', see commit 9ed48c1

  -s	disable symbol table
  -w	disable DWARF generation

(I initially ran strip on it, but it turns out Go can omit those symbol table and DWARF all by itself.)

Cheers,
Anthony

Contributor

anthonyfok commented Jul 26, 2017

Hi @ellerbrock,

Thank you for drastically shrink the image from 277MB to 27MB! "Extreme" indeed!

You might like to consider applying this small change to further shrink the image to 20.5MB with the use of -ldflags '-s -w', see commit 9ed48c1

  -s	disable symbol table
  -w	disable DWARF generation

(I initially ran strip on it, but it turns out Go can omit those symbol table and DWARF all by itself.)

Cheers,
Anthony

@stale

This comment has been minimized.

Show comment
Hide comment
@stale

stale bot Dec 6, 2017

This issue has been automatically marked as stale because it has not had recent activity. The resources of the Hugo team are limited, and so we are asking for your help.
If this is a bug and you can still reproduce this error on the master branch, please reply with all of the information you have about it in order to keep the issue open.
If this is a feature request, and you feel that it is still relevant and valuable, please tell us why.
This issue will automatically be closed in the near future if no further activity occurs. Thank you for all your contributions.

stale bot commented Dec 6, 2017

This issue has been automatically marked as stale because it has not had recent activity. The resources of the Hugo team are limited, and so we are asking for your help.
If this is a bug and you can still reproduce this error on the master branch, please reply with all of the information you have about it in order to keep the issue open.
If this is a feature request, and you feel that it is still relevant and valuable, please tell us why.
This issue will automatically be closed in the near future if no further activity occurs. Thank you for all your contributions.

@stale stale bot added the Stale label Dec 6, 2017

@ellerbrock

This comment has been minimized.

Show comment
Hide comment
@ellerbrock

ellerbrock Dec 6, 2017

Contributor

hi @anthonyfok,

i would say we could close this issue, what do you think?

cheers maik

Contributor

ellerbrock commented Dec 6, 2017

hi @anthonyfok,

i would say we could close this issue, what do you think?

cheers maik

@stale stale bot removed the Stale label Dec 6, 2017

@stale

This comment has been minimized.

Show comment
Hide comment
@stale

stale bot Mar 6, 2018

This issue has been automatically marked as stale because it has not had recent activity. The resources of the Hugo team are limited, and so we are asking for your help.
If this is a bug and you can still reproduce this error on the master branch, please reply with all of the information you have about it in order to keep the issue open.
If this is a feature request, and you feel that it is still relevant and valuable, please tell us why.
This issue will automatically be closed in the near future if no further activity occurs. Thank you for all your contributions.

stale bot commented Mar 6, 2018

This issue has been automatically marked as stale because it has not had recent activity. The resources of the Hugo team are limited, and so we are asking for your help.
If this is a bug and you can still reproduce this error on the master branch, please reply with all of the information you have about it in order to keep the issue open.
If this is a feature request, and you feel that it is still relevant and valuable, please tell us why.
This issue will automatically be closed in the near future if no further activity occurs. Thank you for all your contributions.

@stale stale bot added the Stale label Mar 6, 2018

@stale stale bot closed this Mar 20, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment