Writing production-worthy Dockerfiles is, unfortunately, not as simple as you would imagine. Most Docker images in the wild fail here, and even professionals often[1] get[2] this[3] wrong[4].
This repository has best-practices for writing Dockerfiles that I (@slimsag) have quite painfully learned over the years both from my personal projects and from my work @sourcegraph. This is all guidance, not a mandate - there may sometimes be reasons to not do what is described here, but if you don't know then this is probably what you should be doing.
Copy the Dockerfile into your own project and follow the comments to create your Dockerfile.
The following are included in the Dockerfile in this repository:
latest
, pin your image tagstini
as your ENTRYPOINTCMD
Running containers as a non-root user substantially decreases the risk that container -> host privilege escalation could occur. This is an added security benefit. (Docker docs, Bitnami blog post)
UIDs below 10,000 are a security risk on several systems, because if someone does manage to escalate privileges outside the Docker container their Docker container UID may overlap with a more privileged system user's UID granting them additional permissions. For best security, always run your processes as a UID above 10,000.
Eventually someone dealing with your container will need to manipulate file permissions for files owned by your container. If your container does not have a static UID/GID, then one must extract this information from the running container before they can assign correct file permissions on the host machine. It is best that you use a single static UID/GID for all of your containers that never changes. We suggest 10000:10001
such that chown 10000:10001 files/
always works for containers following these best practices.
latest
, pin your image tagsWe suggest pinning image tags using a specific image version
using major.minor
, not major.minor.patch
so as to ensure you are always:
latest
means your build can arbitrarily break in the future, whereas major.minor
should mean this doesn't happen)SHA pinning gives you completely reliable and reproducable builds, but it also likely means you won't have any obvious way to pull in important security fixes from the base images you use. If you use major.minor
tags, you get security fixes by accident when you build new versions of your image - at the cost of builds being less reproducable.
Consider using docker-lock: this tool keeps track of exactly which Docker image SHA you are using for builds, while having the actual image you use still be a major.minor
version. This allows you to reproduce your builds as if you'd used SHA pinning, while getting important security updates when they are released as if you'd used major.minor
versions.
If you're a large company/organization willing to spin up infrastructure like image security scanners, automated dependency updating, etc. then consider this approach as well.
tini
as your ENTRYPOINTWe suggest using tini as the ENTRYPOINT in your Dockerfile, even if you think your application handles signals correctly. This can alter the stability of the host system and other containers running on it, if you get it wrong in your application. See the tini docs for details and benefits:
Using Tini has several benefits:
- It protects you from software that accidentally creates zombie processes, which can (over time!) starve your entire system for PIDs (and make it unusable).
- It ensures that the default signal handlers work for the software you run in your Docker image. For example, with Tini, SIGTERM properly terminates your process even if you didn't explicitly install a signal handler for it.
- It does so completely transparently! Docker images that work without Tini will work with Tini without any changes.
CMD
By having your ENTRYPOINT
be your command name:
ENTRYPOINT ["/sbin/tini", "--", "myapp"]
And CMD
be only arguments for your command:
CMD ["--foo", "1", "--bar=2"]
It allows people to ergonomically pass arguments to your binary without having to guess its name, e.g. they can write:
docker run yourimage --help
If CMD
includes the binary name, then they must guess what your binary name is in order to pass arguments etc.
If you want your Dockerfile to run on old/legacy Linux systems and Docker for Mac versions and wish to avoid DNS resolution issues, install bind-tools.
For additional details see here.
(Applies to Alpine Linux base images only)
tini
still required in 2020? I thought Docker added it natively?tini
still required in 2020? I thought Docker added it natively?Unfortunately, although Docker did add it natively, it is optional (you have to pass --init
to the docker run
command). Additionally, because it is a feature of the runtime and e.g. Kubernetes will not use the Docker runtime but rather a different container runtime it is not always the default so it is best if your image provides a valid entrypoint like tini
instead.
It depends. We advise major.minor
pinning here because we believe it is the most likely thing that the average developer creating a new Docker image can effectively manage day-to-day that provides the most security. If you're a larger company/organization, you might consider instead however:
However, this obviously requires much more work and infrastructure so we don't advise it here with the expectation that most people would pin a SHA and likely never update it again - thus never getting security fixes into their images.
1、dockerfile是什么? dockerfile是用来构建docker镜像的文本文件,记录了镜像构建的所有步骤 2、构建的的三个步骤 1、编写dockerfile文件 2、docker build 命令构建镜像 3、docker run 以镜像运行容器 4、dockerfile特性 镜像缓存特性:如果某镜像层已经存在,就直接使用,无需重新构建。 dockerfil中的每个指令都会创建一个镜像
本文向大家介绍Dockerfile指令详解,包括了Dockerfile指令详解的使用技巧和注意事项,需要的朋友参考一下 什么是Dockerfile Dockerfile是由一系列命令和参数构成的脚本,这些命令应用于基础镜像并最终创建一个新的镜像。它们简化了从头到尾的流程并极大的简化了部署工作。Dockerfile从FROM命令开始,紧接着跟随者各种方法,命令和参数。其产出为一个新的可以用于创建容器
问题内容: 我想在docker上运行jenkins并更改用户访问权限,以便可以读取SSH密钥并访问git。这是dockerfile的示例 生成时输出成功,访问已更改! 但是,当我进入访问设置为默认时,chmod无法正常工作 知道为什么这种行为吗? 问题答案: 发生这种情况是因为在基本映像中进行了定义。您可以通过3种方式中的任何一种来解决此问题 您可以在构建之前在主机上修复权限,它应该可以工作。 您
问题内容: 我正在使用声明性管道语法在Docker容器中执行一些CI工作。 我注意到,用于Jenkins的Docker插件使用主机中jenkins用户的用户ID和组ID运行一个容器(即,如果jenkins用户具有用户ID 100和组ID 111,它将运行管道以创建带有命令)。 我遇到了一些问题,因为该容器将以不存在的用户运行(特别是我遇到了用户没有主目录的问题)。所以我想到了创建一个Dockerf
问题内容: 有了Jenkins Docker映像,我想向该映像添加完整的’npm’环境。因此,在构建了Dockerfile之后,我同时拥有Jenkins和’npm’环境的映像。 目的是让詹金斯(Jenkins)作业运行shell命令“ npm”。因此,’npm’应该在$ PATH上(在Ubuntu中)。 我已经有了一个包含很多东西的Dockerfile,例如Jenkins和Maven。 这篇文章描
问题内容: 我有以下内容: 该映像已在本地成功构建。 我正在尝试配置Jenkins管道,并尝试使用以下步骤构建映像: 但是在Jenkins控制台中,我得到了错误: 未知标志:来自 我应该如何编辑我的,尤其是标签,以便能够在本地和通过Jenkins管道构建图像? 更新: 我已经将Docker更新为18.06.1-ce版本。仍然有同样的错误。 詹金斯版 2.89.4 Docker Pipeline插件
问题内容: 我添加了在“ docker-compose”期间安装软件包。但是,当我运行时发生了以下错误。我发现程序包保存在中。 运行docker-compose并进行构建 docker-compose.yml Docker文件 main.go 更新1 我注意到以下目录之间的巨大差异。 更新2 正如@aerokite所说,“卷”正在覆盖下载的软件包。我像以下内容进行了更改,并且有效。 Docker文
问题内容: 我有2个Dockerfile,1个用于dev,1个用于prod: 产品: 和DEV: 我想将这两个合并为一个,因为维护2个Dockerfile是一个坏习惯 主要区别在于,在开发人员中,我从事实用的图像工作,而在产品中,我从事图像工作,这大大减少了二进制文件的大小。 看来我可以在Dockerfile中使用多个阶段,并在构建时指定阶段名称: 但是,如果这样做,我不知道如何在第一阶段有条件地
本文向大家介绍通过Dockerfile构建Docker镜像的方法步骤,包括了通过Dockerfile构建Docker镜像的方法步骤的使用技巧和注意事项,需要的朋友参考一下 Dockerfile是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建. Dockerfile支持Shell类的行尾添加"\"的命令换行方式,以及