如何编写正确高效的Dockerfile

简介: 【2月更文挑战第17天】

镜像就是一个打包文件,里面包含了应用程序还有它运行所依赖的环境,例如文件系统、环境变量、配置参数等等。

环境变量、配置参数这些东西还是比较简单的,随便用一个 manifest 清单就可以管理,真正麻烦的是文件系统。为了保证容器运行环境的一致性,镜像必须把应用程序所在操作系统的根目录,也就是 rootfs,都包含进来。


容器镜像内部并不是一个平坦的结构,而是由许多的镜像层组成的,每层都是只读不可修改的一组文件,相同的层可以在镜像之间共享,然后多个层像搭积木一样堆叠起来,再使用一种叫“Union FS 联合文件系统”的技术把它们合并在一起,就形成了容器最终看到的文件系统。


docker inspect 来查看镜像的分层信息,比如 nginx:alpine 镜像。


通过这张截图就可以看到,nginx:alpine 镜像里一共有 6 个 Layer。


比起容器、镜像来说,Dockerfile 非常普通,它就是一个纯文本,里面记录了一系列的构建指令,比如选择基础镜像、拷贝文件、运行脚本等等,每个指令都会生成一个 Layer,而 Docker 顺序执行这个文件里的所有步骤,最后就会创建出一个新的镜像出来。


首先因为构建镜像的第一条指令必须是 FROM,所以基础镜像的选择非常关键。如果关注的是镜像的安全和大小,那么一般会选择 Alpine;如果关注的是应用的运行稳定性,那么可能会选择 Ubuntu、Debian、CentOS。

FROM alpine:3.15                # 选择Alpine镜像
FROM ubuntu:bionic              # 选择Ubuntu镜像

image.gif

RUN 通常会是 Dockerfile 里最复杂的指令,会包含很多的 Shell 命令,但 Dockerfile 里一条指令只能是一行,所以有的 RUN 指令会在每行的末尾使用续行符 \,命令之间也会用 && 来连接,这样保证在逻辑上是一行,就像下面这样:

RUN apt-get update \
    && apt-get install -y \
        build-essential \
        curl \
        make \
        unzip \
    && cd /tmp \
    && curl -fSL xxx.tar.gz -o xxx.tar.gz\
    && tar xzf xxx.tar.gz \
    && cd xxx \
    && ./config \
    && make \
    && make clean

image.gif

把这些 Shell 命令集中到一个脚本文件里,用 COPY 命令拷贝进去再用 RUN 来执行:

COPY setup.sh  /tmp/                # 拷贝脚本到/tmp目录
RUN cd /tmp && chmod +x setup.sh \  # 添加执行权限
    && ./setup.sh && rm setup.sh    # 运行脚本然后再删除

image.gif

Dockerfile 里也可以做到,需要使用两个指令 ARG 和 ENV。它们区别在于 ARG 创建的变量只在镜像构建过程中可见,容器运行时不可见,而 ENV 创建的变量不仅能够在构建镜像的过程中使用,在容器运行时也能够以环境变量的形式被应用程序使用。


因为命令行“docker”是一个简单的客户端,真正的镜像构建工作是由服务器端的“Docker daemon”来完成的,所以“docker”客户端就只能把“构建上下文”目录打包上传(显示信息 Sending build context to Docker daemon ),这样服务器才能够获取本地的这些文件。


如何编写 Dockerfile 内容?

  1. 创建镜像需要编写 Dockerfile,写清楚创建镜像的步骤,每个指令都会生成一个 Layer。
  2. Dockerfile 里,第一个指令必须是 FROM,用来选择基础镜像,常用的有 Alpine、Ubuntu 等。其他常用的指令有:COPY、RUN、EXPOSE,分别是拷贝文件,运行 Shell 命令,声明服务端口号。
  3. docker build 需要用 -f 来指定 Dockerfile,如果不指定就使用当前目录下名字是“Dockerfile”的文件。
  4. docker build 需要指定“构建上下文”,其中的文件会打包上传到 Docker daemon,所以尽量不要在“构建上下文”中存放多余的文件。
  5. 创建镜像的时候应当尽量使用 -t 参数,为镜像起一个有意义的名字,方便管理。
相关文章
|
监控 安全 Shell
【Shell 命令集合 系统管理 】Linux 查看系统上的失败登录记录 lastb命令 使用指南
【Shell 命令集合 系统管理 】Linux 查看系统上的失败登录记录 lastb命令 使用指南
445 0
|
算法 NoSQL 安全
SpringCloud Gateway 通过redis实现限流
SpringCloud Gateway 通过redis实现限流
1514 0
SpringCloud Gateway 通过redis实现限流
|
12月前
|
人工智能 弹性计算 搜索推荐
打造个性化的微信公众号AI小助手:从人设到工作流程
在数字化时代,一个有个性且功能强大的AI小助手能显著提升用户体验。本文档指导如何在微信公众号上设置AI小助手“小智”,涵盖其人设、功能规划及工作流程设计,旨在打造一个既智能又具吸引力的AI伙伴。
775 0
|
NoSQL 安全 API
如何有效提升 API 接口的安全性?
**API安全关键在于验证和防刷。通过排序参数、生成签名和MD5加密确保请求合法性。使用Redis限制请求频率,防止接口被恶意刷取。验证和防刷策略结合,保护API免受攻击和滥用。**
234 0
ly~
|
12月前
|
人工智能 自然语言处理 搜索推荐
人工智能在医学领域的应用
人工智能在医学领域的应用广泛,涵盖医学影像分析、医疗数据分析与预测、临床决策支持、药物研发、自然语言处理及智能健康管理等方面。它能提高诊断准确性,预测疾病风险与进展,优化治疗方案,加速药物研发,提升手术安全性,并实现个性化健康管理,有效推动了医疗科技的进步。
ly~
545 3
|
JavaScript Java 测试技术
基于springboot+vue.js的工作流程管理系统附带文章和源代码设计说明文档ppt
基于springboot+vue.js的工作流程管理系统附带文章和源代码设计说明文档ppt
173 0
|
12月前
|
存储 物联网 计算机视觉
|
存储 数据格式 Python
如何使用 numpy 加载 txt 文件数据?
【8月更文挑战第30天】
561 0
|
人工智能 Java API
Java中的智能语音识别与处理技术实践
Java中的智能语音识别与处理技术实践
|
弹性计算 资源调度 Cloud Native
融合云计算与分布式系统架构:拥抱数字化时代的技术进化
在当今数字化时代,云计算和分布式系统架构成为企业转型的关键工具。本文将探讨这两项技术的融合,以及它们在提升效率、降低成本和增强可扩展性方面的潜力。通过深入分析云计算和分布式系统架构的原理和优势,我们将看到如何利用这些技术推动企业的数字化转型。