Skip to content

Smaller docker image for production? #4112

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

Closed
nmaaiken opened this issue Sep 7, 2021 · 8 comments · Fixed by #5068
Closed

Smaller docker image for production? #4112

nmaaiken opened this issue Sep 7, 2021 · 8 comments · Fixed by #5068
Labels
feature New user visible feature

Comments

@nmaaiken
Copy link

nmaaiken commented Sep 7, 2021

Hello,
is it possible to create a smaller docker image for production purposes?
I would be happy to make a contribution.

@nmaaiken nmaaiken added the feature New user visible feature label Sep 7, 2021
@jsjoeio
Copy link
Contributor

jsjoeio commented Sep 7, 2021

I feel like this was discussed once but I can't remember what we said 🤔

Do you remember? @code-asher @jawnsy

It would be nice to see if we can optimize the size though. I haven't done that before, but would be curious to learn/help!

@code-asher
Copy link
Member

code-asher commented Sep 8, 2021 via email

@code-asher
Copy link
Member

Related: #2488

@jawnsy
Copy link
Contributor

jawnsy commented Sep 9, 2021

I looked into this a little bit, and according to the Dive CI tool, we currently waste about 200MB due to adding some release package files that are subsequently deleted:

Analyzing image...
  efficiency: 74.4829 %
  wastedBytes: 236665266 bytes (237 MB)
  userWastedPercent: 29.7167 %
Inefficient Files:
Count  Wasted Space  File Path
    2        117 MB  /tmp/code-server_3.11.1_amd64.deb
    2        115 MB  /tmp/code-server_3.11.1_arm64.deb

Unfortunately, docker buildx bake does not seem to support the --squash flag that docker buildx does. There also doesn't seem to be a way to mount /tmp as a tmpfs. So unfortunately, there doesn't seem to be an easy way to reduce the image size much, though it's certainly possible with some effort.

There's some third-party commands like docker-squash that might be able to do this, but I don't think we'd want to introduce a tool like that to our build process. Also, since the image is 915MB, reducing it by 230MB still results in a ~680MB image.

Other options are to look into UBI Micro or UBI Minimal images to have a smaller footprint, but these images are also much less usable from a development perspective due to fewer dependencies available.

@nmaaiken Can you provide more detail on your use case, and why a smaller image helps for you? We could certainly consider adding an additional image type, but this entails some long-term maintenance cost on our end, since we have to keep building that image

@nmaaiken
Copy link
Author

@jawnsy sorry for the delay on my side.
We are using code-server to implement a cloud-hosted, browse-able code-catalogue for our developers.
This involves the need for user-specific workspaces, that may result in the need for simultaneously running containers

@code-asher code-asher added this to the Backlog Candidates milestone Oct 27, 2021
@quentincaffeino
Copy link

quentincaffeino commented Nov 10, 2021

Even though switching to alpine as a base would be great there's no real need to go this far. Switching to debian-slim as a base would give you almost the same base as ubuntu but it's much smaller.

EDIT: I've checked ubuntu images now and they look also small so that is not the case. For some reason I remember them being much larger.

@PeterBennink
Copy link

PeterBennink commented Nov 17, 2021

There is at least one quick win I already successfully built locally. Replacing this:

RUN ARCH="$(dpkg --print-architecture)" && \
    curl -fsSL "https://github.com/boxboat/fixuid/releases/download/v0.5/fixuid-0.5-linux-$ARCH.tar.gz" | tar -C /usr/local/bin -xzf - && \
    chown root:root /usr/local/bin/fixuid && \
    chmod 4755 /usr/local/bin/fixuid && \
    mkdir -p /etc/fixuid && \
    printf "user: coder\ngroup: coder\n" > /etc/fixuid/config.yml

COPY release-packages/code-server*.deb /tmp/
COPY ci/release-image/entrypoint.sh /usr/bin/entrypoint.sh
RUN dpkg -i /tmp/code-server*$(dpkg --print-architecture).deb && rm /tmp/code-server*.deb

with:

RUN ARCH="$(dpkg --print-architecture)" && \
    curl -fsSL "https://github.com/boxboat/fixuid/releases/download/v0.5/fixuid-0.5-linux-$ARCH.tar.gz" | tar -C /usr/local/bin -xzf - && \
    chown root:root /usr/local/bin/fixuid && \
    chmod 4755 /usr/local/bin/fixuid && \
    mkdir -p /etc/fixuid && \
    printf "user: coder\ngroup: coder\n" > /etc/fixuid/config.yml && \
    curl -fsSL "https://github.com/cdr/code-server/releases/download/v3.12.0/code-server_3.12.0_$ARCH.deb" -o code-server.deb && \
    dpkg -i code-server.deb && \
    rm code-server.deb

COPY ci/release-image/entrypoint.sh /usr/bin/entrypoint.sh

What this does is downloading only the relevant .deb file, install it, and remove it in the same Docker RUN command. The original downloads three different .deb files in a separate COPY command, then installs one and removes all of them in a separate layer, which results in a far larger image. My proposed changes reduce the image size from 1.1GB to 736MB (uncompressed).

By the way: I hardcoded the version of code-server, but this could just as easily be an ARG that's defined in the build command.

In general my tip would be to use as little separate RUN commands as possible, since all of them add new layers (which usually results in a bigger image). While having many separate RUN commands may be useful during development (since you make use of the caching of untouched layers, resulting in less build-time) it's best to merge as many of them as possible for the release-image.

@dwahler
Copy link
Contributor

dwahler commented Apr 5, 2022

I noticed this issue as well, and came up with a slightly different version of @PeterBennink's proposed fix: #5068

Instead of downloading the .deb package from Github during the build, I retained the current approach of copying the packages from the release-packages directory in the local context. But I modified the Dockerfile to use a multi-stage build, so that the package files are never actually stored in the main build stage. This achieves the same size reduction while hopefully being a little bit more self-contained of a change.

Also, it's worth noting that excluding these files causes a disproportionate reduction in the compressed size of the image, since .deb files are relatively incompressible.

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

Successfully merging a pull request may close this issue.

7 participants