Dockerfile 的一些实践经验
date
Mar 23, 2021
slug
practice-experience-for-dockerfile
status
Published
summary
去年一个人把公司内部分老项目和新项目添加了
Docker
支持,重新设计了 CD/CI 流程;同时由于基本是单机服务,编排容器用的 Docker Compose
,因此在这个过程中,也积累了一些经验。tags
Docker
type
Post
去年一个人把公司内部分老项目和新项目添加了
Docker
支持,重新设计了 CD/CI 流程;同时由于基本是单机服务,编排容器用的 Docker Compose
,因此在这个过程中,也积累了一些经验。一、减少镜像大小
1.1 Alpine
使用
Alpine
或者是带有 alpine
版本的镜像作为基础镜像 下图是这个博客分别用
node:14.13.0
和 node:14.13.0-alpine3.12
构建后的镜像大小对比具体关于
Alpine
的介绍可以看看这个链接1.2 多阶段构建
在构建一些运行文件和源代码分离的项目时(
Vue.js
、React.js
、Go
等),可以考虑使用多阶段构建让最后生成的镜像只含有运行文件1.2.1 Vue.js
1.3 如果希望所有容器都通过端口访问,可以考虑使用 Caddy
我个人比较偏向于所有的容器之间都通过端口访问,那么就会遇到一些服务本身没有映射功能端口的情——例如
PHP
——因此,可以考虑使用 Caddy
在容器内部代理端口Caddyfile
:Dockerfile
:二、减少 Layer 层的数量
减少层数有利于提高 Push 和 Pull 的速度,提高部署效率;在
Dockerfile
中,每一行的命令都会生成一个新层,因此可以通过命令合并的方式降低层数,比如使用 && \ 分隔运行多个命令三、提高构建速度
3.1 容易产生变动的命令放在最后执行
虽然
docker build
的过程中可以使用缓存提高速度,但是如果某一行 Dockerfile
内容发生了变动,那么它以及之后所有的命令都需要重新执行(不包括多阶段构建中的其他阶段)。3.2 多阶段构建
多阶段构建不仅能够帮助降低镜像大小,也可以在一定程度上提高构建的速度,比如说在
go build
的时候,运行镜像的基础环境已经完成了;同时,每个部分之间的缓存判断是独立的,因此就算修改了构建部分的 Dockerfile,运行部分的构建依然可以使用缓存。
3.2.1 Go
3.3 使用 BuildKit
四、成功率和稳定性
基础镜像尽量不使用类似
latest
这种非固定镜像的 Tag,尽量使用精确的版本号比如说:node:14.13.0-alpine3.12
五、时区问题
由于大部分镜像的时区都不是东八区,因此在构建成镜像时时间判断、Log 时间标记可能都会出现问题,因此时区也是需要考虑的问题
通过
Dockerfile
解决(Alpine
):运行时解决(通过同步服务器的宿主机时间):