dockerfile 最佳实践及示例
Dockerfile 最佳实践已经出现在官方文档中,地址在 Best practices for writing Dockerfiles。如果再写一份最佳实践,倒有点关公门前耍大刀之意。因此本篇文章是对官方文档的翻译,理解,扩展与示例补充
容器应该是短暂的
通过 Dockerfile
构建的镜像所启动的容器应该尽可能短暂 (ephemeral)。短暂意味着可以很快地启动并且终止
使用 .dockerignore 排除构建无关文件
.dockerignore
语法与 .gitignore
语法一致。使用它排除构建无关的文件及目录,如 node_modules
使用多阶段构建
多阶段构建可以有效减小镜像体积,特别是对于需编译语言而言,一个应用的构建过程往往如下
- 安装编译工具
- 安装第三方库依赖
- 编译构建应用
而在前两步会有大量的镜像体积冗余,使用多阶段构建可以避免这一问题
这是构建 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
跳过缓存
ADD
和COPY
将会计算文件的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 最佳实践及示例的更多相关文章
- 【原创】Docker实战 Dockerfile最佳实践&&容器之间通信
官方最佳实践文档 https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#from Docker实战(三十) ...
- 《容器高手实战: Dockerfile最佳实践》
Dockerfile最佳实践一个容器对应一个进程一个Docker容器应该只对应一个进程,也就是一个Docker 镜像一般只包含一个应用的制品包(比如.jar). 在需要组合多个进程的场景,使用容器组( ...
- Dockerfile 最佳实践
之前 一篇文章介绍 docker 的镜像基本原理和概念 ,主要介绍在编写 docker 镜像的时候一些需要注意的事项和推荐的做法. 虽然 Dockerfile 简化了镜像构建的过程,并且把这个过程可以 ...
- go项目dockerfile最佳实践
1. 前言 2. 不需要cgo情况下的最佳实践 3. 依赖cgo情况下的最佳实践 1. 前言 这几天在构建golang编写的web项目中,关于dockerfile编写的一些总结 可能是单纯我比较菜(大 ...
- Dockerfile最佳实践(一)
1.使用缓存 Dockerfile的每条指令都会将结果提交为新的镜像,下一跳指令将会基于上一步指令的镜像的基础上构建,如果一个镜像存在相同的父镜像和指令(除了ADD),Docker将会使用镜像而不是 ...
- 编写 Dockerfile 最佳实践
官方仓库虽然有数十万计的免费镜像,但大多数无法直接满足公司业务需求,这就需要我们自己去定制镜像了. Docker通过Dockerfile自动构建镜像,Dockerfile是一个包含用于组建镜像的文本文 ...
- 8、Dockerfile介绍和最佳实践
一.Dockerfile 概念 1.Dockerfile是什么 Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序.库.资源.配置等文件外,还包含了一些为运行时准备的一些配置参数(如 ...
- Dockerfile 命令详解及最佳实践
Dockerfile 命令详解 FROM 指定基础镜像(必选) 所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制.就像我们之前运行了一个 nginx 镜像的容器,再进行修改一样,基础镜像是必须指 ...
- 8.云原生之Docker容器镜像构建最佳实践浅析
转载自:https://www.bilibili.com/read/cv15220861/?from=readlist 本章目录 0x02 Docker 镜像构建最佳实践浅析 1.Dockerfile ...
随机推荐
- TRANK和VTP
需求:因为公司规模逐渐扩大,出现相同部门不同办公室的情况,老板提出新的要求:相同部门可以通信,不同部门不能通信. 利用vlan: 缺点:浪费材料,应用技术手段把两条交叉线变成一条. 因此,引进trun ...
- ReentrantLock 如何实现非公平锁?和公平锁实现有什么区别
reentrant 英[riːˈɛntrənt] 美[ˌriˈɛntrənt] 先学会读.单词原意是可重入的 考察显示锁的使用.可延伸知识点 独占锁 & 共享锁 独占锁 - 悲观锁(不能同时被 ...
- java编程思想第四版第七章总结
1. 实现类的复用通常有两种方式 组合:在新的类中产生现有类的对象 继承:按照现有类的类型来创造新类 2. 一个特殊的方法toString() 在非基本类型的对象中, 都有toString()方法 当 ...
- Python文件写入时的编码问题解决
如下代码: import sys import os import django root_dir = os.path.join(os.path.dirname(os.path.abspath(__f ...
- PHP 向数组头部插入数据
PHP 向数组头部插入数据 函数: array_unshift() 示例: $s = array('a' => 0, 'b' => 3); array_unshift($s, '5'); ...
- java 中的 shuffle()用于打乱list中的元素
题目描述: 数组里面有{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},请随机打乱顺序生成新的数组: import java.util.ArrayList; import java.ut ...
- 使用iis反向代理.net core应用程序
.net core 其实是自宿主性质的web应用程序,而不再是web网站,所以.net core是可以直接单独作为系统服务部署.但是实际情况中,为了同个一个端口能支持多个web应用和统一管理,还是应该 ...
- 堡垒机的核心武器:WebSSH录像实现
WebSSH终端录像的实现终于来了 前边写了两篇文章『Asciinema:你的所有操作都将被录制』和『Asciinema文章勘误及Web端使用介绍』深入介绍了终端录制工具Asciinema,我们已经可 ...
- 精通awk系列(8):awk划分字段的3种方式
回到: Linux系列文章 Shell系列文章 Awk系列文章 详细分析awk字段分割 awk读取每一条记录之后,会将其赋值给$0,同时还会对这条记录按照预定义变量FS划分字段,将划分好的各个字段分别 ...
- [ch03-02] 交叉熵损失函数
系列博客,原文在笔者所维护的github上:https://aka.ms/beginnerAI, 点击star加星不要吝啬,星越多笔者越努力. 3.2 交叉熵损失函数 交叉熵(Cross Entrop ...