-
Notifications
You must be signed in to change notification settings - Fork 0
Feat: Buildkit caching for Docker builds #56
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?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,56 +1,87 @@ | ||
# declare default build args for later stages | ||
ARG PYTHON_VERSION=3.12 \ | ||
PYTHONDONTWRITEBYTECODE=1 \ | ||
PYTHONUNBUFFERED=1 \ | ||
USER=calitp \ | ||
USER_UID=1000 \ | ||
USER_GID=1000 | ||
|
||
FROM python:3.12 | ||
|
||
ENV PYTHONDONTWRITEBYTECODE=1 \ | ||
PYTHONUNBUFFERED=1 \ | ||
USER=calitp | ||
# renew top-level args in this stage | ||
ARG PYTHON_VERSION \ | ||
PYTHONDONTWRITEBYTECODE \ | ||
PYTHONUNBUFFERED \ | ||
USER \ | ||
USER_UID \ | ||
USER_GID | ||
|
||
# set env vars for the user, including HOME | ||
ENV PYTHONUNBUFFERED=${PYTHONUNBUFFERED} \ | ||
PYTHONDONTWRITEBYTECODE=${PYTHONDONTWRITEBYTECODE} \ | ||
HOME=/home/${USER} \ | ||
USER=${USER} \ | ||
PATH="/home/${USER}/.local/bin:$PATH" \ | ||
# update env for local pip installs | ||
# see https://docs.python.org/3/using/cmdline.html#envvar-PYTHONUSERBASE | ||
# since all `pip install` commands are in the context of $USER | ||
# $PYTHONUSERBASE is the location used by default | ||
PYTHONUSERBASE="/home/${USER}/.local" \ | ||
# where to store the pip cache (use the default) | ||
# https://pip.pypa.io/en/stable/cli/pip/#cmdoption-cache-dir | ||
PIP_CACHE_DIR="/home/${USER}/.cache/pip" \ | ||
GUNICORN_CONF="/$USER/run/gunicorn.conf.py" | ||
|
||
EXPOSE 8000 | ||
|
||
# create non-root $USER and home directory | ||
RUN useradd --create-home --shell /bin/bash $USER && \ | ||
USER root | ||
# install apt packages using the archives and lists cache | ||
RUN --mount=type=cache,id=apt-archives,sharing=locked,target=/var/cache/apt/archives \ | ||
--mount=type=cache,id=apt-lists,sharing=locked,target=/var/lib/apt/lists \ | ||
groupadd --gid ${USER_GID} ${USER} 2>/dev/null || true && \ | ||
useradd --uid ${USER_UID} --gid ${USER_GID} --create-home --shell /bin/bash ${USER} && \ | ||
# pip cache dir must be created and owned by the user to work with BuildKit cache | ||
mkdir -p ${PIP_CACHE_DIR} && \ | ||
# own the parent directory of PIP_CACHE_DIR | ||
chown -R ${USER}:${USER} /home/${USER}/.cache && \ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we could use Bash parameter expansion There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm definitely a Bash noob! I was reading about parameter expansion and this section seems relevant to your comment:
Yikes, that is a mouthful! I think I am understanding that your suggestion:
Follows the
So the result is that Is this correct? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, that's correct! That's what I also understood about how parameter expansion works. I used these other docs (the section under But yep, we are basically left with what you had hardcoded 😅 I was thinking that parameter expansion could make the script a bit safer in case There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh I totally agree with you! I just didn't understand your bash-fu and wanted to make sure! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 😄 that sounds good! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On second thought after discussion, we decided to leave it as-is to be more explicit. |
||
# setup $USER permissions for nginx | ||
mkdir -p /var/cache/nginx && \ | ||
chown -R $USER /var/cache/nginx && \ | ||
chown -R $USER:$USER /var/cache/nginx && \ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just curious what the purpose of this change is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This sets ownership for both the The group happens to be the same name as the user. |
||
mkdir -p /var/lib/nginx && \ | ||
chown -R $USER /var/lib/nginx && \ | ||
chown -R $USER:$USER /var/lib/nginx && \ | ||
mkdir -p /var/log/nginx && \ | ||
chown -R $USER /var/log/nginx && \ | ||
chown -R $USER:$USER /var/log/nginx && \ | ||
touch /var/log/nginx/error.log && \ | ||
chown $USER /var/log/nginx/error.log && \ | ||
chown $USER:$USER /var/log/nginx/error.log && \ | ||
touch /var/run/nginx.pid && \ | ||
chown -R $USER /var/run/nginx.pid && \ | ||
chown -R $USER:$USER /var/run/nginx.pid && \ | ||
# setup directories and permissions for gunicorn, (eventual) app | ||
mkdir -p /$USER/app && \ | ||
mkdir -p /$USER/run && \ | ||
chown -R $USER /$USER && \ | ||
chown -R $USER:$USER /$USER && \ | ||
# install server components | ||
apt-get update && \ | ||
apt-get install -qq --no-install-recommends build-essential nginx gettext && \ | ||
python -m pip install --upgrade pip | ||
apt-get install -y --no-install-recommends build-essential nginx gettext && \ | ||
# this cleanup is still important for the final image layer size | ||
# remove lists from the image layer, but they remain in the BuildKit cache mount | ||
rm -rf /var/lib/apt/lists/* | ||
|
||
# enter run (gunicorn) directory | ||
WORKDIR /$USER/run | ||
|
||
# copy gunicorn config file | ||
COPY appcontainer/gunicorn.conf.py gunicorn.conf.py | ||
# overwrite default nginx.conf | ||
COPY appcontainer/nginx.conf /etc/nginx/nginx.conf | ||
|
||
# switch to non-root $USER | ||
USER $USER | ||
|
||
# update env for local pip installs | ||
# see https://docs.python.org/3/using/cmdline.html#envvar-PYTHONUSERBASE | ||
# since all `pip install` commands are in the context of $USER | ||
# $PYTHONUSERBASE is the location used by default | ||
ENV PATH="$PATH:/$USER/.local/bin" \ | ||
PYTHONUSERBASE="/$USER/.local" | ||
|
||
# install python dependencies | ||
COPY appcontainer/requirements.txt requirements.txt | ||
RUN pip install --no-cache-dir -r requirements.txt | ||
|
||
# copy gunicorn config file | ||
COPY appcontainer/gunicorn.conf.py gunicorn.conf.py | ||
ENV GUNICORN_CONF "/$USER/run/gunicorn.conf.py" | ||
|
||
# overwrite default nginx.conf | ||
COPY appcontainer/nginx.conf /etc/nginx/nginx.conf | ||
RUN --mount=type=cache,id=pipcache,target=${PIP_CACHE_DIR},uid=${USER_UID},gid=${USER_GID} \ | ||
python -m pip install --user --upgrade pip && \ | ||
pip install --user -r requirements.txt | ||
|
||
# enter app directory | ||
WORKDIR /$USER/app | ||
|
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.
At first I thought
PATH
andPYTHONUSERBASE
should just be set to/$USER/.local/bin
and/$USER/.local
respectively, but prefixing withhome
works too 👍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.
They in fact need to be in the
/home
directory!Although we have the
WORKDIR
directly under/$USER
for the final image, during build timepip
was having trouble using a cache when it was not inside/home
.pip
expects to do--user
installs, well, inside the user's home directory! All the overriding in the world wasn't working, but this did 😀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.
Ah that's good to know! 👍