• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
导航菜单
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • windows
  • 服务器硬件
  • 服务器运维
  • 云计算
  • 虚拟化
  • IIS教程
  • Linux
  • Apache
  • Ftp
  • DNS
  • Nginx
您的位置:首页 > 服务器 >虚拟化 > 编写最佳的Dockerfile的方法

编写最佳的Dockerfile的方法

作者:fundebug 字体:[增加 减小] 来源:互联网

本文主要包含dockerfile编写,如何编写dockerfile,dockerfile,编写工具等服务器相关知识,fundebug 希望可以进行参考

Dockerfile的语法非常简单,然而如何加快镜像构建速度,如何减少Docker镜像的大小却不是那么直观,需要积累实践经验。这篇博客可以帮助你快速掌握编写Dockerfile的技巧。

为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。

我已经使用Docker有一段时间了,其中编写Dockerfile是非常重要的一部分工作。在这篇博客中,我打算分享一些建议,帮助大家编写更好的Dockerfile。

目标:

  1. 更快的构建速度
  2. 更小的Docker镜像大小
  3. 更少的Docker镜像层
  4. 充分利用镜像缓存
  5. 增加Dockerfile可读性
  6. 让Docker容器使用起来更简单

总结

  1. 编写.dockerignore文件
  2. 容器只运行单个应用
  3. 将多个RUN指令合并为一个
  4. 基础镜像的标签不要用latest
  5. 每个RUN指令后删除多余文件
  6. 选择合适的基础镜像(alpine版本最好)
  7. 设置WORKDIR和CMD
  8. 使用ENTRYPOINT (可选)
  9. 在entrypoint脚本中使用exec
  10. COPY与ADD优先使用前者
  11. 合理调整COPY与RUN的顺序
  12. 设置默认的环境变量,映射端口和数据卷
  13. 使用LABEL设置镜像元数据
  14. 添加HEALTHCHECK

示例

示例Dockerfile犯了几乎所有的错(当然我是故意的)。接下来,我会一步步优化它。假设我们需要使用Docker运行一个Node.js应用,下面就是它的Dockerfile(CMD指令太复杂了,所以我简化了,它是错误的,仅供参考)。

FROM ubuntu

ADD . /app

RUN apt-get update 
RUN apt-get upgrade -y 
RUN apt-get install -y nodejs ssh mysql 
RUN cd /app && npm install

# this should start three processes, mysql and ssh
# in the background and node app in foreground
# isn't it beautifully terrible? <3
CMD mysql & sshd & npm start 

构建镜像:

docker build -t wtf .

1. 编写.dockerignore文件

构建镜像时,Docker需要先准备context ,将所有需要的文件收集到进程中。默认的context包含Dockerfile目录中的所有文件,但是实际上,我们并不需要.git目录,node_modules目录等内容。 .dockerignore 的作用和语法类似于 .gitignore,可以忽略一些不需要的文件,这样可以有效加快镜像构建时间,同时减少Docker镜像的大小。示例如下:

.git/
node_modules/  

2. 容器只运行单个应用

从技术角度讲,你可以在Docker容器中运行多个进程。你可以将数据库,前端,后端,ssh,supervisor都运行在同一个Docker容器中。但是,这会让你非常痛苦:

非常长的构建时间(修改前端之后,整个后端也需要重新构建)
非常大的镜像大小
多个应用的日志难以处理(不能直接使用stdout,否则多个应用的日志会混合到一起)
横向扩展时非常浪费资源(不同的应用需要运行的容器数并不相同)
僵尸进程问题 - 你需要选择合适的init进程
因此,我建议大家为每个应用构建单独的Docker镜像,然后使用 Docker Compose 运行多个Docker容器。

现在,我从Dockerfile中删除一些不需要的安装包,另外,SSH可以用docker exec替代。示例如下:

FROM ubuntu

ADD . /app

RUN apt-get update 
RUN apt-get upgrade -y

# we should remove ssh and mysql, and use
# separate container for database 
RUN apt-get install -y nodejs # ssh mysql 
RUN cd /app && npm install

CMD npm start 

3. 将多个RUN指令合并为一个

Docker镜像是分层的,下面这些知识点非常重要:

Dockerfile中的每个指令都会创建一个新的镜像层。
镜像层将被缓存和复用
当Dockerfile的指令修改了,复制的文件变化了,或者构建镜像时指定的变量不同了,对应的镜像层缓存就会失效
某一层的镜像缓存失效之后,它之后的镜像层缓存都会失效
镜像层是不可变的,如果我们再某一层中添加一个文件,然后在下一层中删除它,则镜像中依然会包含该文件(只是这个文件在Docker容器中不可见了)。
Docker镜像类似于洋葱。它们都有很多层。为了修改内层,则需要将外面的层都删掉。记住这一点的话,其他内容就很好理解了。

现在,我们将所有的RUN指令合并为一个。同时把apt-get upgrade删除,因为它会使得镜像构建非常不确定(我们只需要依赖基础镜像的更新就好了)

FROM ubuntu

ADD . /app

RUN apt-get update \ 
  && apt-get install -y nodejs \
  && cd /app \
  && npm install

CMD npm start 

记住一点,我们只能将变化频率一样的指令合并在一起。将node.js安装与npm模块安装放在一起的话,则每次修改源代码,都需要重新安装node.js,这显然不合适。因此,正确的写法是这样的:

FROM ubuntu

RUN apt-get update && apt-get install -y nodejs 
ADD . /app 
RUN cd /app && npm install

CMD npm start 

4. 基础镜像的标签不要用latest
当镜像没有指定标签时,将默认使用latest 标签。因此, FROM ubuntu 指令等同于FROM ubuntu:latest。当时,当镜像更新时,latest标签会指向不同的镜像,这时构建镜像有可能失败。如果你的确需要使用最新版的基础镜像,可以使用latest标签,否则的话,最好指定确定的镜像标签。

示例Dockerfile应该使用16.04作为标签。

FROM ubuntu:16.04 # it's that easy!

RUN apt-get update && apt-get install -y nodejs 
ADD . /app 
RUN cd /app && npm install

CMD npm start 

5. 每个RUN指令后删除多余文件
假设我们更新了apt-get源,下载,解压并安装了一些软件包,它们都保存在/var/lib/apt/lists/目录中。但是,运行应用时Docker镜像中并不需要这些文件。我们最好将它们删除,因为它会使Docker镜像变大。

示例Dockerfile中,我们可以删除/var/lib/apt/lists/目录中的文件(它们是由apt-get update生成的)。

FROM ubuntu:16.04

RUN apt-get update \ 
  && apt-get install -y nodejs \
  # added lines
  && rm -rf /var/lib/apt/lists/*

ADD . /app 
RUN cd /app && npm install

CMD npm start 

6. 选择合适的基础镜像(alpine版本最好)

在示例中,我们选择了ubuntu作为基础镜像。但是我们只需要运行node程序,有必要使用一个通用的基础镜像吗?node镜像应该是更好的选择。

FROM node

ADD . /app 
# we don't need to install node 
# anymore and use apt-get
RUN cd /app && npm install

CMD npm start 

更好的选择是alpine版本的node镜像。alpine是一个极小化的Linux发行版,只有4MB,这让它非常适合作为基础镜像。

FROM node:7-alpine

ADD . /app 
RUN cd /app && npm install

CMD npm start 

apk是Alpine的包管理工具。它与apt-get有些不同,但是非常容易上手。另外,它还有一些非常有用的特性,比如no-cache和 --virtual选项,它们都可以帮助我们减少镜像的大小。

7. 设置WORKDIR和 CMD

WORKDIR指令可以设置默认目录,也就是运行RUN / CMD / ENTRYPOINT指令的地方。

CMD指令可以设置容器创建是执行的默认命令。另外,你应该讲命令写在一个数组中,数组中每个元素为命令的每个单词(参考官方文档)。

FROM node:7-alpine

WORKDIR /app 
ADD . /app 
RUN npm install

CMD ["npm", "start"] 

8. 使用ENTRYPOINT (可选)

ENTRYPOINT指令并不是必须的,因为它会增加复杂度。ENTRYPOINT是一个脚本,它会默认执行,并且将指定的命令错误其参数。它通常用于构建可执行的Docker镜像。entrypoint.sh如下:

#!/usr/bin/env sh
# $0 is a script name, 
# $1, $2, $3 etc are passed arguments
# $1 is our command
CMD=$1

case "$CMD" in 
 "dev" )
  npm install
  export NODE_ENV=development
  exec npm run dev
  ;;

 "start" )
  # we can modify files here, using ENV variables passed in 
  # "docker create" command. It can't be done during build process.
  echo "db: $DATABASE_ADDRESS" >> /app/config.yml
  export NODE_ENV=production
  exec npm start
  ;;

  * )
  # Run custom command. Thanks to this line we can still use 
  # "docker run our_image /bin/bash" and it will work
  exec $CMD ${@:2}
  ;;
esac 

示例Dockerfile:

FROM node:7-alpine

WORKDIR /app 
ADD . /app 
RUN npm install

ENTRYPOINT ["./entrypoint.sh"] 
CMD ["start"] 

可以使用如下命令运行该镜像:

# 运行开发版本
docker run our-app dev 


  


 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • 编写最佳的Dockerfile的方法

相关文章

  • Docker 自动部署tomcat详解
  • VMware 12中CentOS 6.5 64位安装配置教程
  • 基于Docker 搭建WordPress的方法
  • Docker安装常用组件(mysql,redis)的方法
  • Docker Machine创建Azure虚拟主机
  • docker挂载NVIDIA显卡运行pytorch的方法
  • DOCKERFILE学习及使用注意事项
  • KVM虚拟机的创建、管理与迁移介绍
  • 详解Docker 端口映射与容器互联
  • Windows使用docker打开新窗口error解决办法

文章分类

  • windows
  • 服务器硬件
  • 服务器运维
  • 云计算
  • 虚拟化
  • IIS教程
  • Linux
  • Apache
  • Ftp
  • DNS
  • Nginx

最近更新的内容

    • Docker中的镜像详细介绍
    • Dockerfile中CMD和ENTRYPOINT命令详解
    • 详解Docker 端口映射与容器互联
    • linux 详解useradd 命令基本用法
    • cURL操作Openstack对象存储的ReST API详解
    • win7下docker安装与报错问题的解决方法
    • 详解CentOS下VMware用桥接模式,静态ip上外网
    • Docker 网络命令详解
    • virtualbox安装增强功能时【未能加载虚拟光盘】的问题解决
    • VMware12和CentOS7共享文件夹问题解析

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有