在Docker容器中作为主机用户运行

Rob*_*low 14 linux sudo development-environment flask docker

在我的团队中,我们使用Docker容器来本地运行我们的网站应用程序,同时我们对它们进行开发.

假设我正在app.py使用依赖项的Flask应用程序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
Run Code Online (Sandbox Code Playgroud)

现在我们有一个运行我们的应用程序的本地服务器,我们可以更改本地文件,服务器将根据需要刷新.

在上面的示例中,应用程序最终以root用户身份运行.除非应用程序将文件写回工作目录,否则这不是问题.如果确实如此,那么我们可能会在我们的工作目录中拥有文件(例如cache.sqlite或者类似的东西debug.log)root.这给我们团队中的用户带来了许多问题.

对于我们的其他应用程序,我们通过使用主机用户的 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
Run Code Online (Sandbox Code Playgroud)

在这种情况下,应用程序将作为容器内具有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'
Run Code Online (Sandbox Code Playgroud)

有谁知道我有没有办法:

  • 让Flask不用担心未分配的用户ID,或者
  • 以某种方式在运行时动态地将用户ID分配给用户名,或
  • 否则,允许docker应用程序在主机上创建文件作为主机用户?

现在(超级哈克),我能想到的唯一的解决办法是改变的权限/etc/passwd泊坞窗图像中是全局可写的,然后一个新的生产线在运行时添加到该文件指定新的UID/GID对一个用户名.

Rob*_*ert 22

您可以共享主机的passwd文件:

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
Run Code Online (Sandbox Code Playgroud)

或者,将用户添加到与图像useradd,使用/etc音量,你用同样的方法/usr/local:

docker run -v etcvol:/etc python..... useradd -u `id -u` $USER
Run Code Online (Sandbox Code Playgroud)

(id -u在docker收到命令之前,在主机shell中解析了两个和$ USER)

  • 如果时间允许的话,我会在 13 小时内给你赏金 (3认同)

cod*_*key 6

刚刚遇到这个问题并找到了不同的解决方法。

来自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]
Run Code Online (Sandbox Code Playgroud)

getpwuid()当未设置以下环境变量时才会调用:LOGNAME, USER, LNAME,USERNAME

设置其中任何一个都应该允许容器启动。

$ docker run -ti -e USER=someuser ...
Run Code Online (Sandbox Code Playgroud)

就我而言,对 的调用getuser()似乎来自Werkzeug库,试图生成调试器 pin 代码。

  • 谢谢。这几乎肯定是最“正确”的回应。特别是当您查看 Werkzeug 实际使用用户名的用途时,这是非常微不足道的,并且完全不依赖于“正确”的值。读者应避免绑定安装 `/etc/passwd` 或在 Docker 容器内创建用户。这些都是黑客解决方案。 (4认同)