coder / code-server

VS Code in the browser
https://coder.com
MIT License
67.99k stars 5.58k forks source link

Smaller docker image for production? #4112

Closed nmaaiken closed 2 years ago

nmaaiken commented 3 years ago

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

jsjoeio commented 3 years ago

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 commented 3 years ago

I also feel like we might have talked about it but I do not recall any specifics.

The reason we have the image we have now is because it is a familiar environment for developers (Ubuntu with all the stuff you would expect like curl).

Maybe what we can do is have a minimal image with code-server then extend that to make our main image and you can choose which to use. Unless we want to use something like Alpine for the smaller image in which case it would need to be separate.

code-asher commented 3 years ago

Related: https://github.com/cdr/code-server/issues/2488

jawnsy commented 3 years ago

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 commented 3 years ago

@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

quentincaffeino commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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.