私のチームでは、Dockerコンテナを使用して、Webサイトアプリケーションの開発中にローカルでWebサイトアプリケーションを実行しています。
app.py
に依存関係があるrequirements.txt
のFlaskアプリで作業していると仮定すると、作業フローはおおよそ次のようになります。
# 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
など)ができてしまいます。これにより、チームのユーザーに多くの問題が発生しました。
他のアプリケーションでは、HostユーザーのUIDとGIDでアプリケーションを実行することでこれを解決しました-例: 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
この場合、アプリケーションは、コンテナ内でID 1000
を持つnon-existentユーザーとして実行されますが、ホストディレクトリは、最終的に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'
誰かが私ができる方法があるかどうか知っていますか:
私が今考えることができる唯一の解決策(超ハッキング)は、Dockerイメージ内の/etc/passwd
のアクセス許可をグローバルに書き込み可能に変更し、実行時にそのファイルに新しいUID/GIDとユーザー名のペア。
ホストの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
または、/etc
を使用するのと同じように、/usr/local
をボリュームとして使用して、useradd
でユーザーを画像に追加します。
docker run -v etcvol:/etc python..... useradd -u `id -u` $USER
(id -u
と$ USERの両方が、ホストシェルで、dockerがコマンドを受信する前に解決されます)
この問題を見つけて、別の回避策を見つけただけです。
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]
_
getpwuid()
の呼び出しは、次の環境変数が設定されていない場合にのみ行われます:LOGNAME
、USER
、LNAME
、USERNAME
それらのいずれかを設定すると、コンテナーを開始できるようになります。
_$ docker run -ti -e USER=someuser ...
_
私の場合、getuser()
への呼び出しは Werkzeug デバッガーのピンコードを生成しようとしているライブラリから来ているようです。
別のPythonパッケージを使用してコンテナを起動してもよい場合は、私のPython package https:// github .com/boon-code/docker-inside エントリポイントを上書きし、コンテナ内にユーザーをその場で作成します...
docker-inside -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
Docker CLIを使用したい場合は、コマンドラインでエントリポイントをオーバーライドし、ユーザーを作成するスクリプトを渡すことでも問題ありません。