Skip to content

Commit 9e2c1ed

Browse files
authored
Actually maybe don't use pipenv sync --system
Thanks Hynek: https://mastodon.social/@hynek/109425589715158701
1 parent cce2d66 commit 9e2c1ed

File tree

1 file changed

+31
-24
lines changed

1 file changed

+31
-24
lines changed

docker/pipenv-and-docker.md

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
I had [a Django project](https://github.com/natbat/cbwg) that used `pipenv` (in particular a `Pipfile.lock`) to manage dependencies and I wanted to build a Docker container for it.
44

5-
This worked:
5+
With the help of [this article](https://sourcery.ai/blog/python-docker/) (for the `PIPENV_VENV_IN_PROJECT` tip) I came up with the following:
66

77
```dockerfile
88
FROM python:3.6.15-slim-buster
@@ -12,27 +12,23 @@ WORKDIR /app
1212

1313
COPY . .
1414

15+
ENV PIPENV_VENV_IN_PROJECT=1
16+
1517
RUN pip install pipenv
16-
RUN pipenv sync --system
18+
RUN pipenv sync
1719

18-
RUN ./manage.py collectstatic --noinput
20+
RUN pipenv run ./manage.py collectstatic --noinput
1921

2022
EXPOSE 8000
2123

2224
CMD pipenv run gunicorn --bind 0.0.0.0:8000 --timeout 120 --workers 2 cbwg.wsgi
2325
```
2426

25-
The key trick here is using `pipenv sync --system` to install into the system Python, rather than trying to create a virtual environment.
26-
27-
(`--system` trick courtesy of [feedback on Mastodon](https://social.lol/@ryan/109424753653794299))
28-
29-
## Previous method before learning about --system
27+
Ignore the base image - the project was an emergency port from Heroku and I didn't have time to upgrade it from the ancient version of Python it was using (if you're using a `Pipfile.lock` file you need to keep your Python version stable unless you want to lock new versions).
3028

31-
With the help of [this article](https://sourcery.ai/blog/python-docker/) (for the `PIPENV_VENV_IN_PROJECT` tip) I came up with the following:
29+
The key lines here are these ones:
3230

3331
```dockerfile
34-
FROM python:3.6.15-slim-buster
35-
3632
RUN mkdir -p /app
3733
WORKDIR /app
3834

@@ -42,33 +38,44 @@ ENV PIPENV_VENV_IN_PROJECT=1
4238

4339
RUN pip install pipenv
4440
RUN pipenv sync
41+
```
42+
First we create a `/app` directory and set that as the working directory.
4543

46-
RUN pipenv run ./manage.py collectstatic --noinput
44+
`COPY . .` copies ALL files and directories from the `Dockerfile` directory into the new image, inside `/app`.
4745

48-
EXPOSE 8000
46+
`ENV PIPENV_VENV_IN_PROJECT=1` is important: it causes the resuling virtual environment to be created as `/app/.venv`. Without this the environment gets created somewhere surprising, such as `/root/.local/share/virtualenvs/app-4PlAip0Q` - which makes it much harder to write automation scripts later on.
4947

50-
CMD pipenv run gunicorn --bind 0.0.0.0:8000 --timeout 120 --workers 2 cbwg.wsgi
51-
```
48+
Then we install `pipenv` and use `RUN pipenv sync` to install all of the package versions from our `Pipfile.lock` file (which was added by `COPY . .`).
5249

53-
Ignore the base image - the project was an emergency port from Heroku and I didn't have time to upgrade it from the ancient version of Python it was using (if you're using a `Pipfile.lock` file you need to keep your Python version stable unless you want to lock new versions).
50+
## Alternative using pipenv sync --system
5451

55-
The key lines here are these ones:
52+
You can avoid creating a virtual environment in your Docker image entirely using `pipenv sync --system`, which instead installs the packages in the Docker container's system Python:
5653

5754
```dockerfile
55+
FROM python:3.6.15-slim-buster
56+
5857
RUN mkdir -p /app
5958
WORKDIR /app
6059

6160
COPY . .
6261

63-
ENV PIPENV_VENV_IN_PROJECT=1
64-
6562
RUN pip install pipenv
66-
RUN pipenv sync
63+
RUN pipenv sync --system
64+
65+
RUN ./manage.py collectstatic --noinput
66+
67+
EXPOSE 8000
68+
69+
CMD pipenv run gunicorn --bind 0.0.0.0:8000 --timeout 120 --workers 2 cbwg.wsgi
6770
```
68-
First we create a `/app` directory and set that as the working directory.
6971

70-
`COPY . .` copies ALL files and directories from the `Dockerfile` directory into the new image, inside `/app`.
72+
But this carries its own risks, as [described here by Hynek Schlawack](https://hynek.me/articles/virtualenv-lives/).
73+
74+
The key problem is that the operating system itself may have already installed specific package versions in `site-packages`, and there's a risk that these might conflict with the versions of those packages used by your own application.
75+
76+
So Hynek advises:
77+
78+
> Do isolate your application server’s OS from its host using Docker [...]
79+
> But inside of them also do isolate your Python environment using virtualenv from unexpected surprises in the system site-packages.
7180
72-
`ENV PIPENV_VENV_IN_PROJECT=1` is important: it causes the resuling virtual environment to be created as `/app/.venv`. Without this the environment gets created somewhere surprising, such as `/root/.local/share/virtualenvs/app-4PlAip0Q` - which makes it much harder to write automation scripts later on.
7381

74-
Then we install `pipenv` and use `RUN pipenv sync` to install all of the package versions from our `Pipfile.lock` file (which was added by `COPY . .`).

0 commit comments

Comments
 (0)