在Dockerfile中以non-root身份运行Container
Introduction
本文假设读者已有一定的Docker相关基本概念的知识。否则,请先参阅官方文档。
在Dockerfile中,如果我们不显示的表明用户,进行权限处理,那么默认的Dockerfile生成的镜像,在运行时会以root
身份进入ENTRYPOINT
,进而执行CMD
。然而,以root
身份启动container是一件很危险的事情。尽管,docker容器内的root
与宿主host本身的root
并不一定具有一样的权限,但是如果已priviledge的方式运行container,那么两者将会一样,从而产生巨大的安全隐患。
因此,在Dockerfile的ENTRYPOINT
之前,也就是运行application之前,进行用户切换。本文就如何在Dockerfile中创建普通用户,附属的pip
、git
、ssh
中可能遇到的问题,以及给出Best Practice的demo。
How To
Basic
首先看一个最简单的Dockerfile
在这个例子里,该Dockerfile使用了官方Docker Hub中的Python3.6镜像,把当前上下文context
的项目代码拷贝到目标镜像的/code
下,并把这个目录作为工作目录的上下文基址。
这个例子中,并没有显示的声明用户,所以最后是默认以root
身份运行的。
Create a User
放一个例子,
这个例子展示了如何创建普通用户app,并在ENTRYPOINT
之前切换到app用户。
这里需要注意的问题是:
- Python虚拟环境:我推荐的做法是: 秉承一个项目一个解释环境的原则。以一个Web应用来说,通常包含不止一个container,App,db等分别有各自的container,所以,单独的运行项目的容器内,可以直接使用Python环境进行pip install操作
- 如果你使用私有Docker Hub:如果你要使用公司自有的Docker Hub,最好的操作是在基础镜像中,就配置好
Python
、Git
和ssh
,避免在对项目进行容器化封装时候,手动从本地封装进去这些配置文件。 - 关于新用户目录: Linux中新建用户其实默认会帮用户在
/home/
下新建一个用户目录,并分配所属和权限。在Dockerfile中,我们一般通过环境变量ENV
的方式来操作这个上下文目录。但是,环境变量名称请勿使用保留字,比如ENV HOME=/home/app
,这是因为这个$HOME
会覆盖掉基础镜像本身的home,从而引起各种权限配置文件丢失的问题。
Running on Server with Gunicorn
上面的例子使用Python
跑起来的,但是当运行在服务器上时,我们应该以Gunicorn
启动。