惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
The Last Watchdog
The Last Watchdog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Troy Hunt's Blog
L
LINUX DO - 最新话题
C
Check Point Blog
T
Threat Research - Cisco Blogs
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
罗磊的独立博客
V
Vulnerabilities – Threatpost
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
J
Java Code Geeks
Apple Machine Learning Research
Apple Machine Learning Research
大猫的无限游戏
大猫的无限游戏
S
Security @ Cisco Blogs
IT之家
IT之家
T
The Exploit Database - CXSecurity.com
The GitHub Blog
The GitHub Blog
D
Docker
Engineering at Meta
Engineering at Meta
AWS News Blog
AWS News Blog
S
Security Affairs
U
Unit 42
P
Palo Alto Networks Blog
V
Visual Studio Blog
Y
Y Combinator Blog
D
DataBreaches.Net
Forbes - Security
Forbes - Security
阮一峰的网络日志
阮一峰的网络日志
美团技术团队
Security Latest
Security Latest
aimingoo的专栏
aimingoo的专栏
Simon Willison's Weblog
Simon Willison's Weblog
A
Arctic Wolf
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
H
Hacker News: Front Page
博客园 - 司徒正美
博客园 - Franky
宝玉的分享
宝玉的分享
TaoSecurity Blog
TaoSecurity Blog
Latest news
Latest news
Scott Helme
Scott Helme
MongoDB | Blog
MongoDB | Blog
量子位
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
C
Cisco Blogs
P
Privacy International News Feed
Application and Cybersecurity Blog
Application and Cybersecurity Blog

陈少文的网站

巨变与机遇的未来十年 Kubernetes 平台管理软件压力测试方案 使用镜像部署 Hexo 静态页面 终于等到你 - GitHub 镜像仓库服务(ghcr.io) 一起来学 Go --(6)Interface 一起来学 Go --(5)Goroutine 和 Channel 什么是函数式编程 如何在 Kubernetes 集群集成 Kata 柯里化与偏函数 使用 PyGithub 自动创建 Label 软件产品是团队能力的输出 Helm 2 、Helm 3 比较 IoT 变现 Kubernetes 中的 DNS 服务 国内的 Helm 镜像源 Harbor 使用自签证书支持 Https 访问 DevOps 工具链之 Prow 如何使用 kfctl 安装 Kubeflow VS Code 无法下载 Go 插件的工具包 工程师更应具有服务精神 你不知道的 Docker 使用技巧 使用 Docker 运行 Tensorflow 论中国 什么是左移 如何清空 Git 仓库全部历史记录 一禅小和尚 有风吹过厨房 时间的玫瑰 如何在 CentOS 安装 GPU 驱动 开发 Tips(19) 使用 Velero 备份 Kubernetes 集群 Kubernetes Cheat Sheet 开发 Tips(18) 如何构建一个 Java 工程 开发 Tips(17) KubeSpray 安装 Kubernetes 报错 ip in ansible_all_ipv4_addresses 基于 Kubernetes 和 Jenkins 搭建自动化测试系统 在 Kubernetes 上动态创建 Jenkins Slave 使用 Jenkins 进行服务拨测 开发 Tips(16) Kubernetes 签发 Ingress 证书及日常故障运维 Kubernetes 中 Deployment 的基本操作 Kubernetes 中的证书 如何使用 KubeBuilder 开发一个 Operator Kubernetes 1.6.0 安装问题汇总 镜像管理工具 -- Harbor 开发 Tips(15) Docker 如何拉取镜像 开发 Tips(14) 使用 Helm 安装 harbor 开发 Tips(13) 使用 S2I 构建云原生应用 在 Kubernetes 中使用 emptyDir、hostPath、localVolume 开发 Tips(12) 开发 Tips(11) 代码质量分析工具 SonarQube 使用 Kubeadm 安装 Kubernetes 集群 一起来学 Go --(4)常用函数 Kubernetes 中的 Ceph Kubernetes 之 Volumes Kubernetes 之 Labels、Selectors 开发 Tips(10) 开源正在重构商业模式 Kubernetes 之网络 Kubernetes 之 API 使用 Helm 和 Operator 快速部署 Prometheus Kubernetes 复杂有状态应用管理框架 -- Operator Kubernetes 的包管理器 -- Helm 一起来学 Go --(3)Go Modules 如何一步一步地优化博客方案 kubectl 实用指南 Kubernetes 中的基本概念 搭建远程 Kubernetes 开发环境 大公司和小公司的 ToB 思路 开发 Tips(9) Go 入门指南 一起来学 Go --(2)数据与逻辑结构 如何预防 Web 富文本中的 XSS 攻击 django-xss-cleaner 云工作时代 一起来学 Go --(1)背景与特点 SaaS 开发团队的不同阶段 你不知道的 Git 使用技巧 输出既服务 微服务设计 继续奔跑 开发 Tips(8) 从账户安全到二次验证 Django 性能之数据库查询优化 Django 性能之分库分表 敏捷开发之研发流程 打造一致性的团队 开发 Tips(7) Pytest 进阶学习之 Mock PaaS 部署之 buildpack Go 开发配置 领域输出才是 PaaS 的核心竞争力 Pytest 入门学习 开发 Tips(6) 如何使用 Jenkins、Docker、GitLab 搭建 Django 自动化部署流程
从零开始使用 Docker 打包 Django 开发环境 (2) Dockerfile
微信公众号 · 2017-09-23 · via 陈少文的网站

1. 基本概念

Dockerfile 是一些列构建 Docker 镜像的指令集合。Docker 通过读取 Dockerfile 指令自动构建镜像。Dockerfile 类似于 Makefile,都是一种文本文件,按照构建镜像顺序组织所有的指令。

Docker 镜像的构建命令:

这条命令中,Docker CLI 的处理流程如下:

  • 把当前目录及子目录当做上下文传递给 Docker Daemon
  • 从当前目录(不包括子目录)中找到 Dockerfile 文件
  • 检查 Dockerfile 的语法
  • 依次执行 Dockerfile 中的指令,根据指令生成中间过渡镜像(存储在本地,为之后的指令或构建作缓存)

2. Docker 文件组成

Dockerfile 一般包含下面几个部分:

  • 基础镜像,以哪个镜像作为基础进行制作,用法是 FROM 基础镜像名称
  • 维护者信息,需要写下该 Dockerfile 编写人的姓名或邮箱,用法是MANITAINER 名字/邮箱
  • 镜像操作命令,对基础镜像要进行的改造命令,比如安装新的软件,进行哪些特殊配置等,常见的是 RUN 命令
  • 容器启动命令,当基于该镜像的容器启动时需要执行哪些命令,常见的是 CMD 命令或 ENTRYPOINT 命令

3. Dockerfile 命令

3.1 FROM

语法:FROM image[:tag]

解释:设置要制作的镜像基于哪个镜像,FROM 指令必须是整个 Dockerfile 的第一个指令,如果指定的镜像不存在默认会自动从 Docker Hub 上下载。如果不指定 tag,默认是 latast。

3.2 MAINTAINER

语法:MAINTAINER name

解释:MAINTAINER 指令允许你给将要制作的镜像设置作者信息

3.3 RUN

语法:

  • RUN command #将会调用/bin/sh -c command
  • RUN [“executable”, “param1”, “param2”] #将会调用exec执行,以避免有些时候shell方式执行时的传递参数问题,而且有些基础镜像可能不包含/bin/sh

解释:RUN指令会在一个新的容器中执行任何命令,然后把执行后的改变提交到当前镜像,提交后的镜像会被用于Dockerfile中定义的下一步操作,RUN中定义的命令会按顺序执行并提交,这正是Docker廉价的提交和可以基于镜像的任何一个历史点创建容器的好处,就像版本控制工具一样。

3.4 CMD

语法:

  • CMD [“executable”, “param1”, “param2”] #将会调用exec执行,首选方式
  • CMD [“param1”, “param2”] #当使用ENTRYPOINT指令时,为该指令传递默认参数
  • CMD command [ param1|param2 ] #将会调用/bin/sh -c执行

解释:CMD 指令中指定的命令会在镜像运行时执行,在 Dockerfile 中只能存在一个,如果使用了多个 CMD指令,则只有最后一个 CMD 指令有效。当出现 ENTRYPOINT 指令时,CMD 中定义的内容会作为 ENTRYPOINT 指令的默认参数,也就是说可以使用 CMD 指令给 ENTRYPOINT 传递参数。

注意:RUN 和 CMD 都是执行命令,他们的差异在于 RUN 中定义的命令会在执行 docker build 命令创建镜像时执行,而 CMD 中定义的命令会在执行docker run命令运行镜像时执行,另外使用第一种语法也就是调用 exec 执行时,命令必须为绝对路径。

3.5 EXPOSE

语法:EXPOSE port [ …]

解释:EXPOSE 指令用来告诉 Docker 这个容器在运行时会监听哪些端口,Docker 在连接不同的容器(使用–link参数)时使用这些信息。

3.6 ENV

语法:ENV key value

解释:ENV 指令用于设置环境变量,在 Dockerfile 中这些设置的环境变量也会影响到 RUN 指令,当运行生成的镜像时这些环境变量依然有效,如果需要在运行时更改这些环境变量可以在运行 docker run 时添加–env key=value参数来修改。

注意:最好不要定义那些可能和系统预定义的环境变量冲突的名字,否则可能会产生意想不到的结果。

3.7 ADD

语法:ADD src dest

解释:ADD 指令用于从指定路径拷贝一个文件或目录到容器的指定路径中,是一个文件或目录的路径,也可以是一个 url,路径是相对于该 Dockerfile 文件所在位置的相对路径, 是目标容器的一个绝对路径,例如 /home/yooke/Docker/Dockerfile 这个文件中定义的,那么 ADD /data.txt /db/指令将会尝试拷贝文件从 /home/yooke/Docker/data.txt 到将要生成的容器的 /db/data.txt,且文件或目录的属组和属主分别为 uid 和 gid 为0的用户和组,如果是通过 url 方式获取的文件,则权限是600。

注意:

  • 如果执行 docker build somefile 即通过标准输入来创建时,ADD 指令只支持 url 方式,另外如果 url 需要认证,则可以通过 RUN wget … 或 RUN curl … 来完成,ADD 指令不支持认证。
  • src 路径必须与 Dockerfile 在同级目录或子目录中,例如不能使用ADD ../somepath,因为在执行docker build时首先做的就是把 Dockerfile 所在目录包含子目录发送给 docker 的守护进程。
  • 如果 src 是一个 url 且 dest 不是以 ‘/’ 结尾,则会下载文件并重命名为 dest 。
  • 如果 src 是一个 url 且 dest 以 ‘/’ 结尾,则会下载文件到 dest filename,url 必须是一个正常的路径形式,‘http://example.com’ 像这样的 url 是不能正常工作的。
  • 如果 src 是一个本地的压缩包且 dest 是以 ‘/’ 结尾的目录,则会调用 ’tar -x’ 命令解压缩,如果 dest 有同名文件则覆盖,但 src 是一个 url 时不会执行解压缩。

3.8 COPY

语法:COPY src dest

解释:用法与 ADD 相同,不过 src 不支持使用url,所以在使用 docker build somefile 时该指令不能使用。

3.9 ENTRYPOINT

语法:

  • ENTRYPOINT [’executable’, ‘param1’, ‘param2’] #将会调用exec执行,首选方式
  • ENTRYPOINT command param1 param2 #将会调用/bin/sh -c执行

解释:ENTRYPOINT 指令中指定的命令会在镜像运行时执行,在 Dockerfile 中只能存在一个,如果使用了多个 ENTRYPOINT 指令,则只有最后一个指令有效。ENTRYPOINT 指令中指定的命令(exec执行的方式)可以通过 docker run 来传递参数,例如 docker run images -l 启动的容器将会把 -l 参数传递给 ENTRYPOINT 指令定义的命令并会覆盖 CMD 指令中定义的默认参数(如果有的话),但不会覆盖该指令定义的参数,例如 ENTRYPOINT [’ls’,’-a’],CMD [’/etc’],当通过 docker run image 启动容器时该容器会运行 ls -a /etc 命令,当使用 docker run image -l 启动时该容器会运行 ls -a -l 命令,-l 参数会覆盖 CMD 指令中定义的/etc参数。

注意:

  • 当使用 ENTRYPOINT 指令时生成的镜像运行时只会执行该指令指定的命令。
  • 当出现 ENTRYPOINT 指令时 CMD 指令只可能(当 ENTRYPOINT 指令使用 exec 方式执行时)被当做 ENTRYPOINT 指令的参数使用,其他情况则会被忽略。

3.10 VOLUME

语法:VOLUME [‘samepath’]

解释:VOLUME 指令用来设置一个挂载点,可以用来让其他容器挂载以实现数据共享或对容器数据的备份、恢复或迁移。

3.11 USER

语法:USER [username|uid]

解释:USER指令用于设置用户或uid来运行生成的镜像和执行 RUN 指令。

3.12 WORKDIR

语法:WORKDIR /path/to/workdir

解释:WORKDIR 指令用于设置 Dockerfile 中的 RUN、CMD 和 ENTRYPOINT 指令执行命令的工作目录(默认为/目录),该指令在 Dockerfile 文件中可以出现多次,如果使用相对路径则为相对于 WORKDIR 上一次的值,例如 WORKDIR /data,WORKDIR logs,RUN pwd 最终输出的当前目录是 /data/logs。

4. 最佳实践

4.1 使用 .dockerignore 文件

在 docker 构建镜像的第一步,docker CLI 会先在上下文目录中寻找 .dockerignore 文件,根据 .dockerignore 文件排除上下文目录中的部分文件和目录,然后把剩下的文件和目录传递给 docker 服务。.dockerignore 语法同 .gitignore。

4.2 避免安装不必要的包

为了减小复杂度、依赖、文件大小和创建的时间,应该避免安装额外或者不必要的包。例如,我们不必在一个数据库镜像中包含一个文本编辑器。

4.3 对于多行参数要做字典序排序

只要有可能,通过对多行参数进行字母数字排序来缓解后续变更。这将帮助你避免重复的包并且更容易更新。在反斜线( \ )前添加一个空格是个好习惯。

1
2
3
RUN apt-get update && apt-get install -y \
  bzr \
  cvs

4.4 尽量利用 build 镜像的缓存

在创建镜像过程中,Docker 将按照 Dockerfile 指定步骤执行每个指令。

一般情况下,对于每条命令,docker 都会生成一层镜像。如果在构建某个镜像层的时候,发现这个镜像层已经存在了,就直接使用,而不是重新构建。

大部分指令是通过与缓存进行对比该指令、执行指令的基础镜像,判断是否使用缓存。除了 ADD 和 COPY,这两个指令会复制文件内容到镜像内,docker 还会检查每个文件内容校验和(不包括最后修改时间和最后访问时间),如果校验和不一致,则不会使用缓存。

4.5 每个镜像只有一个功能

不要在容器里运行多个不同功能的进程,每个镜像中只安装一个应用的软件包和文件,需要交互的程序通过 pod(kubernetes 提供的特性) 或者容器之间的网络进行通信。这样可以保证模块化,不同的应用可以分开维护和升级,也能减小单个镜像的大小。

4.6 不要在构建中升级版本

更新将发生在基础镜像里,不要在你的容器内来apt-get upgrade更新。因为在隔离情况下,如果更新时试图修改 init 或改变容器内的设备,更新可能会经常失败。它还可能会产生不一致的镜像,因为你不再有你的应用程序该如何运行以及包含在镜像中依赖的哪种版本的正确源文件。

5. 参考