为什么简单的Dockerfile会给出“拒绝权限”?

时间:2019-01-19 14:39:52

标签: docker

我正在学习将Docker与ROS结合使用,并且对此错误消息感到惊讶:

FROM ros:kinetic-robot-xenial

# create non-root user
ENV USERNAME ros
RUN adduser --ingroup sudo --disabled-password --gecos "" --shell /bin/bash --home /home/$USERNAME $USERNAME
RUN bash -c 'echo $USERNAME:ros | chpasswd'
ENV HOME /home/$USERNAME
USER $USERNAME

RUN apt-get update

给出此错误消息

Step 7/7 : RUN apt-get update
 ---> Running in 95c40d1faadc
Reading package lists...
E: List directory /var/lib/apt/lists/partial is missing. - Acquire (13: Permission denied)
The command '/bin/sh -c apt-get update' returned a non-zero code: 100

4 个答案:

答案 0 :(得分:3)

apt-get通常需要以root用户身份运行,但是一旦运行了USER命令,命令就不再以root用户身份运行。

您将经常在Dockerfile的 start 上运行类似的命令:如果可能的话,您想利用Docker层缓存,并且通常会在其余部分安装依赖项。 Dockerfile的需求。同样出于层缓存的原因,一步一步运行apt-get update和其他安装步骤也很重要。因此,您的Dockerfile通常看起来像

FROM ros:kinetic-robot-xenial
# Still root
RUN apt-get update \
 && apt-get install ...
# Copy in application (still as root, won't be writable by other users)
COPY ...
CMD ["..."]
# Now as the last step create a user and default to running as it
RUN adduser ros
USER ros

如果需要,您可以显式USER root切换回root以使用后续命令,但通常更容易读取和维护Dockerfile,而用户切换较少。

还要注意,sudo和用户密码在Docker中都没有真正的用处。通常,很难在脚本中运行sudo,并且脚本中会发生很多Docker事情。容器几乎也永远不会运行可能会接受用户密码的诸如gettysshd之类的东西,而且它们对于读取docker history来说是微不足道的,因此设置一个毫无意义。相反,如果您可以在容器中放置壳,则始终可以将-u root传递给docker rundocker exec命令以获取根壳。

答案 1 :(得分:1)

尝试将这一行放在dockerfile的末尾

USER $ USERNAME(一旦此行出现在dockerfile中...您将假设此用户具有权限...在这种情况下,无需安装任何内容) 默认情况下,您是root

答案 2 :(得分:0)

您将用户ros添加到组sudo,但是您尝试使用apt-get update而不使用sudo。因此,您可以无特权地运行命令并获得permission denied

使用do运行命令(t):

FROM ros:kinetic-robot-xenial

RUN whoami
RUN apt-get update
# create non-root user
RUN apt-get install sudo
RUN echo "ros ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers
ENV USERNAME ros 
RUN adduser --ingroup sudo --disabled-password --gecos "" --shell /bin/bash --home /home/$USERNAME $USERNAME
RUN bash -c 'echo $USERNAME:ros | chpasswd'
ENV HOME /home/$USERNAME
USER $USERNAME

RUN whoami
RUN sudo apt-get update

所有这些都没有多大意义。可以用root用户准备docker镜像(例如,安装软件等)。如果您担心安全性(这是一件好事),请保留sudo的内容,并确保与无特权的用户一起执行映像(例如,创建容器)时运行的进程...

如果要将映像的准备工作与实际的可运行项目分开,还可以考虑多阶段构建:

https://docs.docker.com/develop/develop-images/multistage-build/

答案 3 :(得分:0)

通过以下方式切换到root用户:

version: "3.7"
services:
  frontend:
    build:
      context: ./client
      dockerfile: Dockerfile
    image: client
    ports:
      - "3000:3000"
    volumes:
      - ./client:/usr/src/app
  backend:
    build:
      context: ./server
      dockerfile: Dockerfile
    image: server
    ports:
      - "8000:8000"
    volumes:
      - ./server:/usr/src/app
  db:
    image: postgres
    environment:
      POSTGRES_DB: ckl
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: docker
    ports:
      - "5432:5432"

然后每个命令都应该起作用