在我的团队中,我们使用Docker容器在本地运行网站应用程序,同时进行开发。
假设我正在开发一个 Flask 应用程序,并在 app.py 中使用了 requirements.txt 中的依赖项,则工作流大致如下:
# 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
现在我们有一个本地服务器运行我们的应用程序,我们可以对本地文件进行更改,当需要时服务器将刷新。
在上面的示例中,应用程序最终以root
用户身份运行。这不是问题,除非应用程序将文件写回工作目录。如果确实如此,我们可能会在工作目录中拥有由root
拥有的文件(例如cache.sqlite
或debug.log
)。这给我们团队的用户造成了许多问题。
对于我们的其他应用程序,我们通过使用主机用户的UID和GID来运行应用程序来解决这个问题 - 例如,对于Django应用程序:
$ 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
在这种情况下,应用程序将作为容器内ID为1000
、不存在的用户运行,但任何写入主机目录的文件都将正确归属于robin
用户。在Django中可以正常使用。然而,在Flask中,以不存在的用户身份运行会被拒绝(在调试模式下)。
$ 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'
请问有没有方法可以让Flask不担心未分配的用户ID,或者在运行时将用户ID动态分配给用户名,又或者允许Docker应用作为主机用户创建文件?
- 我目前只想到了一个超级hacky的解决方案:更改docker镜像中
/etc/passwd
文件的权限为全局可写,然后在运行时向该文件添加一行以将新的UID/GID对分配给用户名。
/etc/passwd
中的ID相符。如果它们不匹配(通常我会这样期望),那么解决方法也不会是安全的。我们应该了解以相同用户身份运行的吸引力,以及如何通过抽象化用户名称来内化这种冲动。 - eel ghEEzdocker run -v "${HOME}:/root" -w "/root" SERVER/IMAGE:VERSION env HOME="/root" COMMAND
。但是,运行后需要进行清理,因为 docker 守护进程将作为root
写入${HOME}
。 - eel ghEEzpasswd
和shadow
,就像这样:-v /etc/passwd:/etc/passwd -v /etc/shadow:/etc/shadow
。 - pestophagous