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

Dockerfile that builds with poetry #493

Merged
merged 7 commits into from
Feb 10, 2022
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
64 changes: 36 additions & 28 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,53 +1,61 @@
# This Dockerfile installs Sydent from source, which is assumed to be in the current
# working directory. The resulting image contains a single "sydent" user, and populates
# their home area with "src" and "venv" directories. The entrypoint runs Sydent,
# listening on port 8090.
#
# Step 1: Build sydent and install dependencies
#
FROM docker.io/python:3.8-slim as builder
# Users must provide a persistent volume available to the container as `/data`. This
# will contain Sydent's configuration and database. A blank configuration and database
# file is created the first time Sydent runs.

# Install dev packages
RUN apt-get update && apt-get install -y \
build-essential
# Step 1: install dependencies
FROM docker.io/python:3.8-slim as builder

# Add user sydent
RUN addgroup --system --gid 993 sydent \
&& adduser --disabled-password --home /sydent --system --uid 993 --gecos sydent sydent \
&& echo "sydent:$(dd if=/dev/random bs=32 count=1 | base64)" | chpasswd
&& adduser --disabled-login --system --uid 993 --gecos sydent sydent
USER sydent:sydent

# Install poetry
RUN pip install --user poetry==1.1.12

# Copy resources
COPY --chown=sydent:sydent ["res", "/sydent/res"]
COPY --chown=sydent:sydent ["scripts", "/sydent/scripts"]
COPY --chown=sydent:sydent ["sydent", "/sydent/sydent"]
COPY --chown=sydent:sydent ["README.rst", "setup.cfg", "setup.py", "/sydent/"]
# Copy source code and resources
WORKDIR /home/sydent/src
COPY --chown=sydent:sydent ["res", "res"]
COPY --chown=sydent:sydent ["scripts", "scripts"]
COPY --chown=sydent:sydent ["sydent", "sydent"]
COPY --chown=sydent:sydent ["README.rst", "pyproject.toml", "poetry.lock", "./"]

# Install dependencies
USER sydent
WORKDIR /sydent
RUN pip install --user --upgrade pip setuptools sentry-sdk prometheus_client \
&& pip install --user . \
&& rm -rf /sydent/.cache \
&& find /sydent -name '*.pyc' -delete
RUN python -m poetry install --no-dev --no-interaction

#
# Step 2: Reduce image size and layers
#
# Record dependencies for posterity
RUN python -m poetry export -o requirements.txt

# Make the virtualenv accessible for the final image
RUN ln -s $(python -m poetry env info -p) /home/sydent/venv

# Nuke bytecode files to keep the final image slim.
RUN find /home/sydent/venv -type f -name '*.pyc' -delete

# Step 2: Create runtime image
FROM docker.io/python:3.8-slim

# Add user sydent and create /data directory
RUN addgroup --system --gid 993 sydent \
&& adduser --disabled-password --home /sydent --system --uid 993 --gecos sydent sydent \
&& echo "sydent:$(dd if=/dev/random bs=32 count=1 | base64)" | chpasswd \
&& adduser --disabled-login --home /sydent --system --uid 993 --gecos sydent sydent \
&& mkdir /data \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realise this isn't yours, but on the line above, why are we creating a password for the sydent user?
It originally has a disabled password. There's no reason to set a static password ... is there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wondered about this too. I removed this from the builder step (see line -13).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to have been added in #290; wasn't present in #80. No clues in either PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reckon we just remove it here as well. A password that is the same for every Sydent container doesn't seem to afford any security anyway.
I also notice --disabled-login is an option rather than --disabled-password

Excerpt from /etc/shadow:

dpass:*:19033:0:99999:7:::
dlogin:!:19033:0:99999:7:::

If the password field contains some string that is not a valid result of crypt(3), for instance ! or *, the user will not be able to use a unix password to log in (but the user may log in the system by other means).

man shadow

--disabled-login sounds like it (!) will also prevent SSH login using authorised keys. I guess we're not running an SSH daemon anyway, so it probably doesn't matter which one we use.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A password that is the same for every Sydent container doesn't seem to afford any security anyway.

The password comes from /dev/random so I would expect it to be different every time you run build this container. I still think it's odd though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But if it gets uploaded to Docker Hub or something, everyone can then pull that and even crack the password hash if they're so keen. I'd pull it out — the password isn't even being given to anyone so I can't see how it's useful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see---good point. Yes, let's excise it

&& chown sydent:sydent /data

# Copy sydent
COPY --from=builder ["/sydent", "/sydent"]
# Copy sydent and the virtualenv
COPY --from=builder ["/home/sydent/src", "/home/sydent/src"]
COPY --from=builder ["/home/sydent/venv", "/home/sydent/venv"]

ENV SYDENT_CONF=/data/sydent.conf
ENV SYDENT_PID_FILE=/data/sydent.pid
ENV SYDENT_DB_PATH=/data/sydent.db

WORKDIR /sydent
WORKDIR /home/sydent
USER sydent:sydent
VOLUME ["/data"]
EXPOSE 8090/tcp
CMD [ "python", "-m", "sydent.sydent" ]
CMD [ "venv/bin/python", "-m", "sydent.sydent" ]
6 changes: 2 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,11 @@ Docker
A Dockerfile is provided for sydent. To use it, run ``docker build -t sydent .`` in a sydent checkout.
To run it, use ``docker run --env=SYDENT_SERVER_NAME=my-sydent-server -p 8090:8090 sydent``.

Caution: All data will be lost when the container is terminated!

Persistent data
---------------

By default, all data is stored in ``/data``.
The best method is to put the data in a Docker volume.
By default, all data is stored in ``/data``. To persist this to disk, bind `/data` to a
Docker volume.

.. code-block:: shell

Expand Down
1 change: 1 addition & 0 deletions changelog.d/493.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Update Dockerfile to use a fixed poetry environment, rather than `pip install`ing the latest dependencies.