Skip to content

Dockerfile: use a shell script to create a host UID/GID-based container user #27

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

Merged
merged 1 commit into from
Mar 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 8 additions & 11 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ FROM ubuntu:24.04
RUN apt-get update && apt-get install -y \
curl \
git \
gosu \
python3 \
python3-pip \
python3-venv \
Expand All @@ -18,15 +19,6 @@ RUN wget -q -O google-chrome.deb https://dl.google.com/linux/direct/google-chrom
&& apt-get install -y ./google-chrome.deb \
&& rm google-chrome.deb

# Create a new non-root user and group.
# NOTE: It is important that a non-root user is used because otherwise the
# Chrome Driver fails with: "User data directory is already in use"
# https://github.com/SeleniumHQ/selenium/issues/15327#issuecomment-2688613182
RUN groupadd -r html2print && useradd -r -m -g html2print html2print

# Grant the new user sudo privileges.
RUN echo "html2print ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/html2print

# Create a virtual environment in the user's home directory.
RUN python3 -m venv /opt/venv

Expand All @@ -47,9 +39,14 @@ RUN if [ "$HTML2PRINT_SOURCE" = "pypi" ]; then \
fi; \
chmod -R 777 /opt/venv;

USER html2print
# Remove the default 'ubuntu' user.
RUN userdel -r ubuntu 2>/dev/null || true

# Allow updating the UID/GID dynamically at runtime
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

# Set the working directory to the user's home directory.
WORKDIR /data

ENTRYPOINT ["/bin/bash"]
ENTRYPOINT ["/entrypoint.sh"]
55 changes: 55 additions & 0 deletions entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/bin/sh

# This custom entrypoint script is needed for creating a container user with
# a host's UID/GUI which enables sharing of the files between the container
# and the host.
# NOTE: It is important that a non-root user is used because otherwise the
# Chrome Driver fails with: "User data directory is already in use"
# https://github.com/SeleniumHQ/selenium/issues/15327#issuecomment-2688613182

set -e

# Ensure we have the environment variables
if [ -z "$HOST_UID" ] || [ -z "$HOST_GID" ]; then
echo "HOST_UID and HOST_GID must be set!"
exit 1
fi

echo "html2print/docker: running a Docker container entrypoint."
echo "html2print/docker: ensuring html2print user with UID=$HOST_UID and GID=$HOST_GID exists"

# Check if a user with this UID already exists (e.g., "ubuntu")
EXISTING_USER=$(getent passwd "$HOST_UID" | cut -d: -f1)

if [ -n "$EXISTING_USER" ]; then
echo "error: html2print/docker: detected a wrong user: '$EXISTING_USER'. Ensure that any default users are removed from the Dockerfile. This entrypoint script is supposed to create a new user 'html2print'."
exit 1
else
# Ensure the group exists.
EXISTING_GROUP=$(getent group "$HOST_GID" | cut -d: -f1)
if [ -z "$EXISTING_GROUP" ]; then
echo "html2print/docker: creating new group html2print with GID=$HOST_GID"
groupadd -g "$HOST_GID" html2print
else
echo "html2print/docker: group with GID=$HOST_GID already exists: $EXISTING_GROUP, reusing it."
fi

# Create the user.
echo "html2print/docker: creating new user html2print with UID=$HOST_UID"
useradd -m -u "$HOST_UID" -g "$HOST_GID" -s /bin/bash html2print

# Give the user root privileges. Useful for debugging.
echo "html2print ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/html2print
fi

echo "html2print/docker: show created user info:"
id html2print

# Run as the correct user. If no command is provided, run a shell.
if [ $# -eq 0 ]; then
echo "html2print/docker: no command provided, opening an interactive shell."
exec gosu html2print /bin/bash
else
# Otherwise, run the provided command.
exec gosu html2print "$@"
fi
7 changes: 3 additions & 4 deletions tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,6 @@ def run_docker(
command_argument = (
f'/bin/bash -c "{command}"' if command is not None else ""
)
entry_point_argument = '--entrypoint=""' if command_argument else ""

run_invoke(
context,
Expand All @@ -305,8 +304,8 @@ def run_docker(
--name html2print
--rm
-it
-v "$(pwd):/data"
{entry_point_argument}
-e HOST_UID=$(id -u) -e HOST_GID=$(id -g)
-v "$(pwd):/data:rw"
{image}
{command_argument}
""",
Expand All @@ -326,6 +325,6 @@ def test_docker(context, image: str = "html2print:latest"):
context,
image=image,
command=(
"cd tests/integration/01_hello_world && html2print print --debug index.html /data/output/index.pdf && cat /tmp/chromedriver.log"
"cd tests/integration/01_hello_world && html2print print index.html /data/output/index.pdf"
),
)