Dockerfile详解及优化技巧

简介: Dockerfile详解及优化技巧

写在前面

  • Dockerfile的默认相对路径是Dockerfile所在的目录;
  • Dockerfile中的每一行会被视为一层镜像

一、Dockerfile 原理

1.1 镜像定义

首先我们先来回顾一下 Docker 镜像,它由多个只读层堆叠到一起,每一层是上一层的增量修改。基于镜像创建新容器时,将在基础层的顶部添加一个新的可写层。该层通常称为“容器层”。下图展示了一个基于 docker.io/centos 基础镜像构建的应用镜像,创建出容器时的视图。

1.2 镜像来源

镜像主要是 Docker 通过读取、运行 Dockerfile 的指令来生成。我们将上篇文章中的Dockerfile拿过来

FROM gcc
MAINTAINER panda  
COPY ./hello.c ./
RUN pwd
LABEL myhello 1.0.0
LABEL env prod
RUN gcc  hello.c -o hello
CMD ["./hello"]

Dockerfile的核心逻辑就是先定义引用的基础镜像(FROM base image),然后再COPY或ADD上下文到容器,然后再RUN执行用户自定义脚本构建,最后定义容器的CMD或ENTRYPOINT。

1.3 Dockerfile 关键字

FROM

设置镜像使用的基础镜像,必须是第一条指令。如果不以任何镜像为基础镜像,则可以不写,但是,接下来的第一条指令会被作为镜像的第一层使用。

用法:FROM image:tag 其中 tag 是可选项,如果不写,默认为最新latest。

FROM nginx
MAINTAINER

设置镜像的作者。

用法:MAINTAINER name

MAINTAINER   panda
RUN

编译镜像时,要执行的命令,经常被用来安装软件包、拉取和编译代码。

RUN apt-get install python3
RUN git clone https://github.com/golang/example
RUN gcc  hello.c -o hello
RUN pwd
LABEL

设置镜像标签,一个Dockfile中可以有多个LABEL。

LABEL helloc 1.0.0
LABEL env prod
EXPOSE

设置镜像运行时对外暴露的端口

ENV

设置容器的环境变量

ENV env1=v1
ENV env2=v2
COPY 和 ADD

都是复制上下文中的文件到镜像中

COPY  ./hello.c  ./
ADD   ./nginx.tar.gz  ./
ADD   http://www.panda.com/nginx.tar.gz

区别:

  1. COPY 只能复制本地文件
  2. ADD 在复制压缩文件的同时会解压该文件,COPY不能解压
  3. ADD + 网址,会从执行网址下载文件(注意,如果下载的是压缩包,此时不会解压
补充:Exec和 Shell 格式

在学习CMD 和 ENTRYPOINT 之前,我们先来了解下Exec和 Shell 这两种格式。

Exec格式,当指令执行时,会直接调用 ,不会被 shell 解析

# <instruction> ["executable", "param1", "param2", ...]
RUN ["apt-get", "install", "gcc"]  
CMD ["echo", "Hello,world!"]  
ENTRYPOINT ["echo", "Hello,world!"]

Shell 格式,当指令执行时,shell 格式底层会调用 /bin/sh -c

RUN apt-get install gcc
CMD echo "Hello,world!"
ENTRYPOINT echo "Hello,world!"
CMD

设置容器的启动执行的命令和参数,但是会被 docker run 后面的命令行参数替换掉,忽略掉CMD。

CMD ["./hello"]  # 运行hello程序
CMD ["echo", "hello,world"] # 等价于在命令行执行 echo hello,world

案例1(Exec格式):

#Dockerfile部分
ENV name panda
CMD ["echo", "hello, $name"] # 输出 hello, $name 注意name没被解析为panda

如果希望name被解析,可以做以下修改

CMD ["/bin/sh", "-c", "echo hello, $name"] # 输出 hello, panda

案例2(Shell 格式):

#Dockerfile部分
ENV name panda
CMD echo "hello, $name"  # 输出 hello, panda 

小结

CMD命令有三种格式:

  1. Exec格式:CMD [“executable”,“param1”,“param2”],推荐使用这种格式
  2. Shell 格式:CMD command param1 param2
  3. CMD [“param1”,“param2”] 为 ENTRYPOINT 提供额外的参数,此时 ENTRYPOINT 必须使用 Exec 格式。
ENRYPOINT

设置容器的入口程序。

ENTRYPOINT 用法与 CMD 很像,它们都可以指定要执行的命令及其参数。不同的地方在于 ENTRYPOINT 不会被忽略,一定会被执行,即使运行 docker run 时指定了其他命令。

VOLUME

设置容器的挂载卷,可以将宿主机目录挂载到容器中,用来持久化容器中的重要数据。

VOLUME ["/var/log/"]
VOLUME /var/log
USER

设置 RUN CMD ENTRYPOINT 的用户名,使用前需要保证USER 有相应的权限。

WORKER

设置RUN CMD ENTRYPOINT COPY ADD 指令的工作目录,如果该目录不存在会自动创建。

ARG

设置编译镜像时加入的参数。ARG命令定义了一个变量,在docker build镜像的时候,需要加 --build-arg arg=val 来指定参数. 可以同时定义多个变量。

#Dockerfile 部分
ARG work_dir code_addr
RUN git clone $code_addr
docker build -t helloc --build-arg work_dir=hello --build-arg code_addr=https://github.com/golang/example .
ONBUILD

ONBUILD影响的是下游的镜像构建,本次不会执行。比如,镜像S0的Dockerfile如下:

#Dockerfile 部分
ONBUILD RUN ls -a

则在构建镜像S0的时候,不会执行。另一个镜像S1是基于S0的,那么在构建镜像S1的时候会执行RUN ls -a

STOPSIGNAL

设置容器退出时候的信号量,默认退出信号量是15. nginx 修改了退出信号量为3.

二、Dockerfile优化技巧

  1. 使用国内的基础镜像,加速构建;
  2. 使用尽量小的、够用的基础镜像即可;
  3. 减少上下文关联目录文件
  4. 减少层的数量、控制层的大小
  5. 将不变层放到前面,可变层放到后面
  6. 使用多阶段来分离 build 和 runtime


推荐一个零声学院免费教程,个人觉得老师讲得不错,分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,点击立即学习:

相关文章
|
安全 数据安全/隐私保护 芯片
简单认识加扰与解扰
简单认识加扰与解扰
710 0
|
运维 算法 Linux
LVS详解(四)——LVS安装与配置命令
LVS详解(四)——LVS安装与配置命令
530 2
|
4月前
|
缓存 NoSQL 关系型数据库
MySQL 与 Redis 如何保证双写一致性?
我是小假 期待与你的下一次相遇 ~
501 7
|
9月前
|
人工智能 测试技术 API
Apifox对比Apipost:2025年推荐的API协作工具
Apifox与Apipost这两大国产API平台的全方位较量,助你在2025年做出最明智的选择。
|
存储 Linux Android开发
Rockchip系列之VendorStorage uboot/kernel/user space 阶段接口使用介绍(2)
Rockchip系列之VendorStorage uboot/kernel/user space 阶段接口使用介绍(2)
1467 0
|
移动开发 前端开发 数据可视化
React 拖拽布局组件 Drag & Drop Layout
本文介绍了如何在React中构建拖拽布局组件,涵盖基础知识、常见问题及解决方案。首先解释了拖拽操作的三个阶段:开始、过程中和结束。接着推荐了几个常用的拖拽库,如`react-beautiful-dnd`,并详细展示了如何使用该库创建基础拖拽组件,包括安装依赖、初始化容器和处理拖拽结束事件。文章还探讨了常见问题,如拖拽不生效、性能优化、嵌套拖拽和跨浏览器兼容性,并提供了进阶技巧,如自定义样式、多列布局和集成其他UI组件。通过这些内容,读者可以掌握构建高效拖拽布局的方法。
910 16
|
安全 Unix Linux
Windows如何远程连接服务器?服务器远程连接图文教程
服务器操作系统可以实现对计算机硬件与软件的直接控制和管理协调,任何计算机的运行离不开操作系统,服务器也一样,服务器操作系统主要分为四大流派:Windows Server、Netware、Unix和Linux。今天驰网飞飞将和你分享Windows server远程连接图文教程,希望可以帮助到你
6063 4
Windows如何远程连接服务器?服务器远程连接图文教程
|
JSON Java Shell
Dockerfile中RUN、CMD、ENTRYPOINT、SHELL命令的区别
理解这些指令的差异和应用场景,有助于构建高效、灵活且易于管理的Docker镜像。在实际应用中,根据需要选择合适的指令,可以有效地控制镜像构建和容器运行的行为。
803 0
|
SQL 关系型数据库 MySQL
阿里云数据库使用教程、购买、价格、连接数据库全流程
阿里云数据库使用涉及购买、创建及登录步骤。支持MySQL、SQL Server等引擎。购买时选择所需配置、地域和可用区。创建数据库和账号后,通过DMS登录。在同一地域内,ECS需将IP加入RDS白名单以实现内网连接。详细流程见阿里云官方文档。
1842 2
|
存储 关系型数据库 MySQL
面试题15: Mysql 数据存储原理
面试题15: Mysql 数据存储原理
439 0