-
Notifications
You must be signed in to change notification settings - Fork 31
Use multi-stage build in Dockerfile #142
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
base: main
Are you sure you want to change the base?
Conversation
docker/lnt.dockerfile
Outdated
| && apk add --no-cache libpq | ||
| && apk add --no-cache --virtual .build-deps g++ postgresql-dev yaml-dev \ | ||
| && apk add --no-cache git libpq \ | ||
| && pip install ".[server]" \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've also switched from requirements.server.txt to the dependencies in pyproject.toml in this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ack. I think that's alright, but in that case I would suggest we remove all references to requirements.server.txt, since it's basically not going to be used for anything meaningful anymore. Alternatively, we can keep using requirements.server.txt in this PR and then clean it up afterwards.
docker/lnt.dockerfile
Outdated
| COPY pyproject.toml . | ||
| COPY lnt/testing/profile lnt/testing/profile | ||
|
|
||
| # Fake a version for setuptools so we don't need to COPY .git | ||
| ENV SETUPTOOLS_SCM_PRETEND_VERSION=0.1 | ||
|
|
||
| # Install dependencies and build cperf ext-modules. | ||
| RUN apk update \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| COPY pyproject.toml . | |
| COPY lnt/testing/profile lnt/testing/profile | |
| # Fake a version for setuptools so we don't need to COPY .git | |
| ENV SETUPTOOLS_SCM_PRETEND_VERSION=0.1 | |
| # Install dependencies and build cperf ext-modules. | |
| RUN apk update \ | |
| # Install dependencies and build cperf ext-modules. | |
| # Note that we fake a version for setuptools so we don't need to COPY .git. | |
| COPY pyproject.toml . | |
| COPY lnt/testing/profile lnt/testing/profile | |
| ENV SETUPTOOLS_SCM_PRETEND_VERSION=0.1 | |
| RUN apk update \ |
I find it easier to understand if everything is grouped under the same "install dependencies" comment, since, all of these shenanigans are logically only required to install dependencies.
docker/lnt.dockerfile
Outdated
| && apk add --no-cache libpq | ||
| && apk add --no-cache --virtual .build-deps g++ postgresql-dev yaml-dev \ | ||
| && apk add --no-cache git libpq \ | ||
| && pip install ".[server]" \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ack. I think that's alright, but in that case I would suggest we remove all references to requirements.server.txt, since it's basically not going to be used for anything meaningful anymore. Alternatively, we can keep using requirements.server.txt in this PR and then clean it up afterwards.
docker/lnt.dockerfile
Outdated
| # Let setuptools_scm use git to pick the version | ||
| ENV SETUPTOOLS_SCM_PRETEND_VERSION= |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would group this with the above "dependency installation steps", since this is logically "the closing brace" for temporarily setting up SETUPTOOLS_SCM_PRETEND_VERSION=0.1.
docker/lnt.dockerfile
Outdated
| COPY . . | ||
| RUN pip install . |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would still suggesting using a bind mount. We don't actually need the LNT sources as part of the Docker image, we only need the result of the installation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried using a bind mount but couldn't get anywhere, because whatever way cp -Ring the sources ended up clobbering the cperf sources, which caused pip to rebuild it. But this fails at this stage because we've purged g++ etc.
So I've switched this to a multi-stage build, it's been a while since I've used one of these but it allows us to only copy over the installation and leave the build stuff in a separate build image. So we don't need to worry about purging dependencies etc. This article explains it quite well: https://pythonspeed.com/articles/multi-stage-docker-python/
The main savings from this are that we get rid of the .git folder in the image, so the image is down to just 88MB now:
root@bb-luke-debian:~/llvm-lnt# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
llvm-lnt-webserver latest 22cfaa9c28b0 14 minutes ago 88MB
This resolves the conversation at #117 (comment)
Currently we install the build dependencies like g++ (
RUN apk add...) in a separate layer. We try and purge them in a later step but this doesn't achieve anything because docker caches everything on a layer by layer basis, i.e. the previous layer will still contain them and hang around.This PR fixes it by using a multi-stage build which reduces the image size by ~90%:
This patch also only copies over the minimal source files required so as to make sure the dependencies layer is invalidated as infrequently as possible. E.g. here is an example of building the image after touching a regular python source file. We no longer need to rebuild or redownload the dependencies, that layer is cached:
We need to use a mock version for setuptools_scm, since it looks for a .git folder and we want to avoid copying that. That would cause the build dependency layers to be invalidated on every commit.