如何 运行 仅以 root 用户身份执行特定命令,而在 docker-compose 中使用默认用户执行其他命令
How to run only specific command as root and other commands with default user in docker-compose
这是我的 Dockerfile。
FROM python:3.8.12-slim-bullseye as prod-env
RUN apt-get update && apt-get install unzip vim -y
COPY requirements.txt /app
RUN pip install -r requirements.txt
USER nobody:nogroup
这就是docker-compose.yml的样子。
api_server:
build:
context: .
target: prod-env
image: company/server
volumes:
- ./shared/model_server/models:/models
- ./static/images:/images
ports:
- 8200:8200
command: gunicorn -b 0.0.0.0:8200 --threads "8" --log-level info --reload "server:gunicorn_app(command='start', project='app_server')"
我想添加对共享目录的读取、写入和执行权限。
并且还需要 运行 作为 root 的几个其他命令。
所以我每次构建镜像后都必须用root执行这个命令。
docker exec -it -u root api_server_1 bash -c "python copy_stuffs.py; chmod -R a+rwx models; chmod -R a+rwx /images"
现在,我希望 docker-compose 执行这些行。
但如您所见,docker-compose 中的用户 为Dockerfile[=40 指定的nobody
=].那么如何在 docker-compose 文件中执行 root 命令?
我一直在考虑的选项:
从 Dockerfile 安装 sudo 命令并使用 sudo
有没有更好的方法?
在 docker-compose.yml
中使用相同的映像和卷创建另一个服务。
使用 user: root:root
、command: your_command_to_run_as_root
为这个新服务覆盖用户,并在启动常规工作容器之前添加对 运行 这个新服务的依赖。
api_server:
build:
context: .
target: prod-env
image: company/server
volumes:
- ./shared/model_server/models:/models
- ./static/images:/images
ports:
- 8200:8200
command: gunicorn -b 0.0.0.0:8200 --threads "8" --log-level info --reload "server:gunicorn_app(command='start', project='app_server')"
# This make sure that startup order is correct and api_server_decorator service is starting first
depends_on:
- api_server_decorator
api_server_decorator:
build:
context: .
target: prod-env
image: company/server
volumes:
- ./shared/model_server/models:/models
- ./static/images:/images
# No ports needed - it is only decorator
# Overriding USER with root:root
user: "root:root"
# Overriding command
command: python copy_stuffs.py; chmod -R a+rwx models; chmod -R a+rwx /images
还有其他可能性,例如通过删除用户限制来更改 Dockerfile,然后您可以使用入口点脚本以 root 身份作为特权用户执行您想要的操作,并且 运行ning su - nobody
或更好 exec gosu
以保留 PID=1 和适当的信号处理。
在我看来,赋予容器 root 权限的方法非常危险。
如果你想,例如删除容器写入的文件,您还需要在主机上拥有 root 权限。
如果你想让容器访问主机文件系统上的文件,只需 运行 具有适当用户的容器。
api_server:
user: my_docker_user:my_docker_group
然后在主机上授予该组的权限
sudo chown -R my_docker_user:my_docker_group models
你应该将你需要的所有内容构建到图像本身中,特别是如果你有这种偶尔需要 运行 更新它的过程的用例(你没有尝试使用隔离工具比如 Docker 来模拟本地开发环境)。在你的Docker文件中,COPY
将这些目录放入镜像
COPY shared/model_server/models /models
COPY static/images /images
不要不要使这些目录可写,并且不要使目录中的单个文件可执行。目录通常是模式 0755 和文件模式 0644,由 root 拥有,这很好。
在 Compose 设置中,也不要在这些目录上装载主机内容。你应该只有:
services:
api_server:
build: . # use the same image in all environments
image: company/server
ports:
- 8200:8200
# no volumes:, do not override the image's command:
现在,当您想要更新文件时,可以重建映像(无需中断 运行ning 应用程序,无需 docker exec
,也无需备用用户)
docker-compose build api_server
然后相对快速地重新启动,运行在更新后的映像上创建一个新容器
docker-compose up -d
这是我的 Dockerfile。
FROM python:3.8.12-slim-bullseye as prod-env
RUN apt-get update && apt-get install unzip vim -y
COPY requirements.txt /app
RUN pip install -r requirements.txt
USER nobody:nogroup
这就是docker-compose.yml的样子。
api_server:
build:
context: .
target: prod-env
image: company/server
volumes:
- ./shared/model_server/models:/models
- ./static/images:/images
ports:
- 8200:8200
command: gunicorn -b 0.0.0.0:8200 --threads "8" --log-level info --reload "server:gunicorn_app(command='start', project='app_server')"
我想添加对共享目录的读取、写入和执行权限。
并且还需要 运行 作为 root 的几个其他命令。
所以我每次构建镜像后都必须用root执行这个命令。
docker exec -it -u root api_server_1 bash -c "python copy_stuffs.py; chmod -R a+rwx models; chmod -R a+rwx /images"
现在,我希望 docker-compose 执行这些行。
但如您所见,docker-compose 中的用户 为Dockerfile[=40 指定的nobody
=].那么如何在 docker-compose 文件中执行 root 命令?
我一直在考虑的选项: 从 Dockerfile 安装 sudo 命令并使用 sudo
有没有更好的方法?
在 docker-compose.yml
中使用相同的映像和卷创建另一个服务。
使用 user: root:root
、command: your_command_to_run_as_root
为这个新服务覆盖用户,并在启动常规工作容器之前添加对 运行 这个新服务的依赖。
api_server:
build:
context: .
target: prod-env
image: company/server
volumes:
- ./shared/model_server/models:/models
- ./static/images:/images
ports:
- 8200:8200
command: gunicorn -b 0.0.0.0:8200 --threads "8" --log-level info --reload "server:gunicorn_app(command='start', project='app_server')"
# This make sure that startup order is correct and api_server_decorator service is starting first
depends_on:
- api_server_decorator
api_server_decorator:
build:
context: .
target: prod-env
image: company/server
volumes:
- ./shared/model_server/models:/models
- ./static/images:/images
# No ports needed - it is only decorator
# Overriding USER with root:root
user: "root:root"
# Overriding command
command: python copy_stuffs.py; chmod -R a+rwx models; chmod -R a+rwx /images
还有其他可能性,例如通过删除用户限制来更改 Dockerfile,然后您可以使用入口点脚本以 root 身份作为特权用户执行您想要的操作,并且 运行ning su - nobody
或更好 exec gosu
以保留 PID=1 和适当的信号处理。
在我看来,赋予容器 root 权限的方法非常危险。 如果你想,例如删除容器写入的文件,您还需要在主机上拥有 root 权限。 如果你想让容器访问主机文件系统上的文件,只需 运行 具有适当用户的容器。
api_server:
user: my_docker_user:my_docker_group
然后在主机上授予该组的权限
sudo chown -R my_docker_user:my_docker_group models
你应该将你需要的所有内容构建到图像本身中,特别是如果你有这种偶尔需要 运行 更新它的过程的用例(你没有尝试使用隔离工具比如 Docker 来模拟本地开发环境)。在你的Docker文件中,COPY
将这些目录放入镜像
COPY shared/model_server/models /models
COPY static/images /images
不要不要使这些目录可写,并且不要使目录中的单个文件可执行。目录通常是模式 0755 和文件模式 0644,由 root 拥有,这很好。
在 Compose 设置中,也不要在这些目录上装载主机内容。你应该只有:
services:
api_server:
build: . # use the same image in all environments
image: company/server
ports:
- 8200:8200
# no volumes:, do not override the image's command:
现在,当您想要更新文件时,可以重建映像(无需中断 运行ning 应用程序,无需 docker exec
,也无需备用用户)
docker-compose build api_server
然后相对快速地重新启动,运行在更新后的映像上创建一个新容器
docker-compose up -d