In my team we use Docker containers to locally run our website applications while we do development on them.
Assuming I'm working on a Flask app at app.py
with dependencies in requirements.txt
, a working flow would look roughly like this:
# I am "robin" and I am in the docker group $ whoami robin $ groups robin docker # Install dependencies into a docker volume $ docker run -ti -v `pwd`:`pwd` -w `pwd` -v pydeps:/usr/local python:3-slim pip install -r requirements.txt Collecting Flask==0.12.2 (from -r requirements.txt (line 1)) # ... etc. # Run the app using the same docker volume $ docker run -ti -v `pwd`:`pwd` -w `pwd` -v pydeps:/usr/local -e FLASK_APP=app.py -e FLASK_DEBUG=true -p 5000:5000 python:3-slim flask run -h 0.0.0.0 * Serving Flask app "app" * Forcing debug mode on * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 251-131-649
Now we have a local server running our application, and we can make changes to the local files and the server will refresh as needed.
In the above example, the application end up running as the root
user. This isn't a problem unless the application writes files back into the working directory. If it does then we could end up with files (e.g. something like cache.sqlite
or debug.log
) in our working directory owned by root
. This has caused a number of problems for users in our team.
For our other applications we've solved this by running the application with the host user's UID and GID - e.g. for a Django app:
$ docker run -ti -u `id -u`:`id -g` -v `pwd`:`pwd` -w `pwd` -v pydeps:/usr/local -p 8000:8000 python:3-slim ./manage.py runserver
In this case, the application will be running as a non-existent user with ID 1000
inside the container, but any files written to the host directory end up correctly owned by the robin
user. This works fine in Django.
However, Flask refuses to run as a non-existent user (in debug mode):
$ docker run -ti -u `id -u`:`id -g` -v `pwd`:`pwd` -w `pwd` -v pydeps:/usr/local -e FLASK_APP=app.py -e FLASK_DEBUG=true -p 5000:5000 python:3-slim flask run -h 0.0.0.0 * Serving Flask app "app" * Forcing debug mode on * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! Traceback (most recent call last): ... File "/usr/local/lib/python3.6/getpass.py", line 169, in getuser return pwd.getpwuid(os.getuid())[0] KeyError: 'getpwuid(): uid not found: 1000'
Does anyone know if there's any way that I could either:
The only solution I can think of right now (super hacky) is to change the permissions of /etc/passwd
in the docker image to be globally writeable, and then add a new line to that file at runtime to assign the new UID/GID pair to a username.
When running Docker natively on Linux, you can access host services using the IP address of the docker0 interface. From inside the container, this will be your default route. This would permit access to any ports on the host from Docker containers.
The Docker daemon always runs as the root user. If you don't want to preface the docker command with sudo , create a Unix group called docker and add users to it. When the Docker daemon starts, it creates a Unix socket accessible by members of the docker group.
Using Dockerfile Docker allows you to add the User using the −u flag along with the useradd command and then using the USER instruction, you can decide which user you want to be logged in as when you start the Docker Container. Look at the Dockerfile below.
You can share the host's passwd file:
docker run -ti -v /etc/passwd:/etc/passwd -u `id -u`:`id -g` -v `pwd`:`pwd` -w `pwd` -v pydeps:/usr/local -p 8000:8000 python:3-slim ./manage.py runserver
Or, add the user to the image with useradd
, using /etc
as volume, in the same way you use /usr/local
:
docker run -v etcvol:/etc python..... useradd -u `id -u` $USER
(Both id -u
and $USER are resolved in the host shell, before docker receive the command)
Just hit this problem and found a different workaround.
From getpass.py:
def getuser(): """Get the username from the environment or password database. First try various environment variables, then the password database. This works on Windows as long as USERNAME is set. """ for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'): user = os.environ.get(name) if user: return user # If this fails, the exception will "explain" why import pwd return pwd.getpwuid(os.getuid())[0]
The call to getpwuid()
is only made if none of the following environment variables are set: LOGNAME
, USER
, LNAME
, USERNAME
Setting any of them should allow the container to start.
$ docker run -ti -e USER=someuser ...
In my case, the call to getuser()
seems to come from the Werkzeug library trying to generate a debugger pin code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With