Dockerfile 最佳实践已经出现在官方文档中,地址在 Best practices for writing Dockerfiles。如果再写一份最佳实践,倒有点关公门前耍大刀之意。因此本篇文章是对官方文档的翻译,理解,扩展与示例补充

容器应该是短暂的

通过 Dockerfile 构建的镜像所启动的容器应该尽可能短暂 (ephemeral)。短暂意味着可以很快地启动并且终止

使用 .dockerignore 排除构建无关文件

.dockerignore 语法与 .gitignore 语法一致。使用它排除构建无关的文件及目录,如 node_modules

使用多阶段构建

多阶段构建可以有效减小镜像体积,特别是对于需编译语言而言,一个应用的构建过程往往如下

  1. 安装编译工具
  2. 安装第三方库依赖
  3. 编译构建应用

而在前两步会有大量的镜像体积冗余,使用多阶段构建可以避免这一问题

这是构建 Go 应用的一个示例

FROM golang:1.11-alpine AS build

# Install tools required for project
# Run `docker build --no-cache .` to update dependencies
RUN apk add --no-cache git
RUN go get github.com/golang/dep/cmd/dep # List project dependencies with Gopkg.toml and Gopkg.lock
# These layers are only re-built when Gopkg files are updated
COPY Gopkg.lock Gopkg.toml /go/src/project/
WORKDIR /go/src/project/
# Install library dependencies
RUN dep ensure -vendor-only # Copy the entire project and build it
# This layer is rebuilt when a file changes in the project directory
COPY . /go/src/project/
RUN go build -o /bin/project # This results in a single layer image
FROM scratch
COPY --from=build /bin/project /bin/project
ENTRYPOINT ["/bin/project"]
CMD ["--help"]

这是构建前端应用的一个示例,可以参考 如何使用 docker 高效部署前端应用

FROM node:10-alpine as builder

ENV PROJECT_ENV production
ENV NODE_ENV production # http-server 不变动也可以利用缓存
WORKDIR /code ADD package.json /code
RUN npm install --production ADD . /code
RUN npm run build # 选择更小体积的基础镜像
FROM nginx:10-alpine
COPY --from=builder /code/public /usr/share/nginx/html

避免安装不必要的包

减小体积,减少构建时间。如前端应用使用 npm install --production 只装生产环境所依赖的包。

一个容器只做一件事

如一个web应用将会包含三个部分,web 服务,数据库与缓存。把他们解耦到多个容器中,方便横向扩展。如果你需要网络通信,则可以将他们至于一个网络下。

如在我的个人服务器中,我使用 traefik 做负载均衡与服务发现,所有应用及数据库都在 traefik_default 网络下,详情参考 使用 traefik 做负载均衡与服务发现

version: '3'

services:
# 该镜像会暴露出自身的 `header` 信息
whoami:
image: containous/whoami
restart: always
labels:
# 设置Host 为 whoami.docker.localhost 进行域名访问
- "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)" # 使用已存在的 traefik 的 network
networks:
default:
external:
name: traefik_default

减少镜像层数

  • 只有 RUN, COPY, ADD 会创建层数, 其它指令不会增加镜像的体积
  • 尽可能使用多阶段构建

使用以下方法安装依赖

RUN yum install -y node python go

错误的方法安装依赖,这将增加镜像层数

RUN yum install -y node
RUN yum install -y python
RUN yum install -y go

将多行参数排序

便于可读性以及不小心地重复装包

RUN apt-get update && apt-get install -y \
bzr \
cvs \
git \
mercurial \
subversion

充分利用构建缓存

在镜像的构建过程中 docker 会遍历 Dockerfile 文件中的所有指令,顺序执行。对于每一条指令,docker 都会在缓存中查找是否已存在可重用的镜像,否则会创建一个新的镜像

我们可以使用 docker build --no-cache 跳过缓存

  • ADDCOPY 将会计算文件的 checksum 是否改变来决定是否利用缓存
  • RUN 仅仅查看命令字符串是否命中缓存,如 RUN apt-get -y update 可能会有问题

如一个 node 应用,可以先拷贝 package.json 进行依赖安装,然后再添加整个目录,可以做到充分利用缓存的目的。

FROM node:10-alpine as builder

WORKDIR /code

ADD package.json /code
# 此步将可以充分利用 node_modules 的缓存
RUN npm install --production ADD . /code RUN npm run build

dockerfile 最佳实践及示例的更多相关文章

  1. 【原创】Docker实战 Dockerfile最佳实践&&容器之间通信

    官方最佳实践文档 https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#from Docker实战(三十) ...

  2. 《容器高手实战: Dockerfile最佳实践》

    Dockerfile最佳实践一个容器对应一个进程一个Docker容器应该只对应一个进程,也就是一个Docker 镜像一般只包含一个应用的制品包(比如.jar). 在需要组合多个进程的场景,使用容器组( ...

  3. Dockerfile 最佳实践

    之前 一篇文章介绍 docker 的镜像基本原理和概念 ,主要介绍在编写 docker 镜像的时候一些需要注意的事项和推荐的做法. 虽然 Dockerfile 简化了镜像构建的过程,并且把这个过程可以 ...

  4. go项目dockerfile最佳实践

    1. 前言 2. 不需要cgo情况下的最佳实践 3. 依赖cgo情况下的最佳实践 1. 前言 这几天在构建golang编写的web项目中,关于dockerfile编写的一些总结 可能是单纯我比较菜(大 ...

  5. Dockerfile最佳实践(一)

    1.使用缓存  Dockerfile的每条指令都会将结果提交为新的镜像,下一跳指令将会基于上一步指令的镜像的基础上构建,如果一个镜像存在相同的父镜像和指令(除了ADD),Docker将会使用镜像而不是 ...

  6. 编写 Dockerfile 最佳实践

    官方仓库虽然有数十万计的免费镜像,但大多数无法直接满足公司业务需求,这就需要我们自己去定制镜像了. Docker通过Dockerfile自动构建镜像,Dockerfile是一个包含用于组建镜像的文本文 ...

  7. 8、Dockerfile介绍和最佳实践

    一.Dockerfile 概念 1.Dockerfile是什么 Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序.库.资源.配置等文件外,还包含了一些为运行时准备的一些配置参数(如 ...

  8. Dockerfile 命令详解及最佳实践

    Dockerfile 命令详解 FROM 指定基础镜像(必选) 所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制.就像我们之前运行了一个 nginx 镜像的容器,再进行修改一样,基础镜像是必须指 ...

  9. 8.云原生之Docker容器镜像构建最佳实践浅析

    转载自:https://www.bilibili.com/read/cv15220861/?from=readlist 本章目录 0x02 Docker 镜像构建最佳实践浅析 1.Dockerfile ...

随机推荐

  1. Spring资源下载(官网)

    Spring 资源jar包官网下载地址: 点击Spring

  2. nyoj 70-阶乘因式分解(二)(数学)

    70-阶乘因式分解(二) 内存限制:64MB 时间限制:3000ms 特判: No 通过数:7 提交数:7 难度:3 题目描述: 给定两个数n,m,其中m是一个素数. 将n(0<=n<=2 ...

  3. 【Java】面向对象初探

    前段时间经历了一段心态浮躁期,这让我想起了自己最初的计划,要提升自己知识体系的广度.前几年一直做的是web前端这一块的工作,但我希望通过自己在学习Java这样的过程来提升自己的知识广度. 面向对象概述 ...

  4. java运算符详解

    java运算符: 定义:用来指明对于操作数的运算方式 按照操作数数目分类: 单目运算    数目运算    三目运算 a++              a+b           (a>b) ? ...

  5. PostGIS 爆管分析之找出总阀门

    这个算法算是被摒弃了,但是很多自己思考过后留下的成果,虽然不用了,留着做记录. 算法目的是为了发生爆管后找到总阀门,这里分了几个步骤: 1.找到爆管点所在管段 2.通过遍历找到爆管点所有影响的阀门 3 ...

  6. 使用最新AndroidStudio编写Android编程权威指南(第3版)中的代码会遇到的一些问题

    Android编程权威指南(第3版)这本书是基于Android7.0的,到如今已经过于古老,最新的Android版本已经到10,而这本书的第四版目前还没有正式发售,在最近阅读这本书时,我发现这本书的部 ...

  7. Chapter 05—Advanced data management(Part 1)

    一. R的数学函数,统计函数及字符处理函数 例01:一道实际应用题 一组学生其数学,科学和英语的成绩如下表: 任务:根据成绩,决定对每个学生的单独指导: 前20%的学生的成绩为A,次之为B,以此类推: ...

  8. OSI案例详解+ARP+DNS

    案例,淘宝买东西 DNS 域名的作用其实就是相对ip地址来说更好记忆和识别,DNS就是根据域名解析出ip 一次请求,DNS解析的过程 1.在浏览器输入一个域名,操作系统首先会检查自己的本地hosts文 ...

  9. Vue项目解析

    各个文件夹 node_modules:用来放环境依赖 public:用来放公共资源,里面的index.html文件,就是初始的挂载点.被app.vue给取代了. src:放各种资源的. assets: ...

  10. python迭代器生成器-迭代器和list区别

    迭代 生成 for循环遍历的原理 for循环遍历的原理就是迭代,in后面必须是可迭代对象 为什么要有迭代器 对于序列类型:字符串.列表.元组,我们可以使用索引的方式迭代取出其包含的元素.但对于字典.集 ...