Skip to content
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

Add instructions to make a docker file that doesn't use root at runtime #10047

Open
danieltalsky opened this issue Dec 20, 2024 · 3 comments
Open
Labels
documentation Improvements or additions to documentation

Comments

@danieltalsky
Copy link

danieltalsky commented Dec 20, 2024

I really appreciate this example:
https://github.com/astral-sh/uv-docker-example/blob/main/Dockerfile

But sometimes people need to install uv and switch to a non-root user at runtime.

I could NOT get it to work. Here's a somewhat commented out example of what I tried but not everything. I tried installing uv to a non-root folder and giving the web user access to the cache, install directory, and virtual environment but I couldn't get ANYTHING to work. We're talking about two determined devs collaborating for multiple hours. Is there any way y'all could produce a version of the uv docker example that allows installation and package installation during the build but still allows another user to run the uv entrypoint? We can't be the only people trying to do this.

FROM python:3.12

ENV DEBIAN_FRONTEND noninteractive

RUN apt-get update && apt-get install -y apt-utils
RUN apt-get update && apt-get install -y --upgrade \
    ca-certificates \
    curl \
    git \
    nginx \
    gettext \
    locales \
    supervisor \
    vim

# Install supervisord conf
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

# Setup nginx
RUN rm /etc/nginx/sites-enabled/default
RUN ln -s /code/nginx.conf /etc/nginx/sites-enabled/tungsten.conf

# Localization / terminal UTF-8 handling
RUN locale-gen en_US.UTF-8
RUN update-locale en_US.UTF-8
ENV LANG=en_US.UTF-8

# Create and use web-user
RUN groupadd web-user --gid 2001
RUN useradd --uid 2001 --gid 2001 -d /code web-user

# nginx and gunicorn setup
COPY . /code

# Download uv installer
ADD https://astral.sh/uv/install.sh /code/uv-installer.sh

RUN chown -R 2001:2001 /code
RUN chown -R 2001:2001 /var/lib/nginx
RUN chown -R 2001:2001 /var/log/nginx

RUN mkdir /logs
RUN chown 2001:2001 /logs

RUN mkdir /logs/nginx
RUN chown 2001:2001 /logs/nginx

RUN mkdir /logs/gunicorn
RUN chown 2001:2001 /logs/gunicorn

USER 2001:2001

# Configure Django project

# Install uv
RUN mkdir -p /code/uv-cache/uv
ENV UV_CACHE_DIR=/code/uv-cache
RUN sh /code/uv-installer.sh && rm /code/uv-installer.sh
ENV PATH="/root/.cargo/bin/:$PATH"
mkdir -p /code/uv-cache/uv
ENV PATH="/code/.cargo/uv/:$PATH"

# Enable bytecode compilation
ENV UV_COMPILE_BYTECODE=1
# Copy from the cache instead of linking since it's a mounted volume
ENV UV_LINK_MODE=copy

ENV DJANGO_PRODUCTION=true
ENV DJANGO_SETTINGS_MODULE=tungsten.settings

# Set workdir
WORKDIR /code
ENV PATH="/code/.venv/bin:$PATH"

# Install dependencies
# we did try this with /code/
RUN --mount=type=cache,target=/root/.cache/uv \
    uv sync

# Place executables in the environment at the front of the path
RUN chmod ug+x /code/setup_cert.sh
RUN chmod ug+x /code/initialize.sh

## Create a registry of static files
RUN uv run /code/manage.py collectstatic --noinput

# Still using a local memory database for a few things
RUN uv run /code/manage.py migrate --noinput

# Compile translation files
RUN uv run /code/manage.py compilemessages

# Expose ports
# 80 = Nginx
# 8000 = Gunicorn
# 3306 = postgres
EXPOSE 80 8000 3306

# Run Supervisor (i.e., start postgres, nginx, and gunicorn)
ENTRYPOINT ["uv", "run", "/code/initialize.sh"]
@danieltalsky danieltalsky changed the title Add instructions to make a docker file that doesn't use root Add instructions to make a docker file that doesn't use root at runtime Dec 20, 2024
@zed
Copy link

zed commented Dec 20, 2024

you could prefix RUN --mount=type=cache,target=${UV_CACHE_DIR} to any command that works with $UV_CACHE_DIR (not just uv sync). For example:

# workaround "Permission denied (os error 13)" error in
#    "RUN --mount=type=cache" in `uv sync` below
RUN --mount=type=cache,target=${UV_CACHE_DIR}                     \
    [ -d "${UV_CACHE_DIR}" ] && chown -R "${UID}:${UID}" "${UV_CACHE_DIR}"

Then

# install the project's dependencies
RUN --mount=type=cache,target=${UV_CACHE_DIR}                     \
    --mount=type=bind,source=uv.lock,target=uv.lock               \
    --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
     uv sync --frozen --no-install-project

succeeds.

Alternatively, you could use uid:

RUN --mount=type=cache,target=${UV_CACHE_DIR},uid=${UID}                     \
...

no chown is necessary for the cache dir in this case.

btw, COPY accepts --chown option too:

COPY --chown="${UID}:${UID}" . . 

@danieltalsky
Copy link
Author

Thank you for pointing me in the right direction! Any chance you would consider adding a fully working example recommendation to your dockerfile example repo?

@zanieb
Copy link
Member

zanieb commented Dec 21, 2024

@zed doesn't work here, they're just being helpful :)

Yes it seems reasonable to add an example to our repositories. I'd review a contribution doing so.

@zanieb zanieb added the documentation Improvements or additions to documentation label Dec 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

3 participants