返回顶部
首页 > 资讯 > 服务器 >使用Dockerfile脚本定制镜像的方法
  • 714
分享到

使用Dockerfile脚本定制镜像的方法

2024-04-02 19:04:59 714人浏览 泡泡鱼
摘要

目录前言一、Dockerfile介绍二、FROM指定基础镜像三、RUN执行命令四、构建镜像五、镜像构建上下文(Context)六、迁移镜像前言 镜像的定制实际上就是定制每⼀层所添加的

前言

镜像的定制实际上就是定制每⼀层所添加的配置、⽂件等信息。

但是命令毕竟只是命令,一般用 docker commit 每次定制都得去重复执⾏这个命令,⽽且还不够直观,如果我们可以把每⼀层修改、安装、构建、操作的命令都写⼊⼀个脚本,⽤这个脚本来构建、定制镜像,那么这些问题就迎刃而解了,而这个脚本就是我们今天要说的 Dockerfile

一、Dockerfile介绍

Dockerfile 是⼀个⽂本⽂件,其内包含了⼀条条的指令(Instruction),每⼀条指令构建⼀层,因此每⼀条指令的内容,就是描述该层应当如何构建。

还以之前定制 Nginx 镜像为例,这次我们使⽤ Dockerfile 来定制。在⼀个空⽩⽬录中,建⽴⼀个⽂本 ⽂件,并命名为 Dockerfile: 

$ mkdir mynginx 
$ cd mynginx 
$ touch Dockerfile

其内容为:

FROM nginx 
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

 这个 Dockerfile 很简单,⼀共就两⾏。涉及到了两条指令,FROM 和 RUN。

二、FROM指定基础镜像

所谓定制镜像,那⼀定是以⼀个镜像为基础,在其上进⾏定制。就像我们之前运⾏了⼀个 nginx 镜像 的容器,再进⾏修改⼀样,基础镜像是必须指定的。⽽ FROM 就是指定基础镜像,因此⼀个 Dockerfile 中 FROM 是必备的指令,并且必须是第⼀条指令。

在Docker Store上有⾮常多的⾼质量的官⽅镜像,有可以直接拿来使⽤的服务类的镜像,如 nginx、 Redis、monGoMysqlHttpd、PHPTomcat 等;也有⼀些⽅便开发、构建、运⾏各种语⾔应⽤的镜 像,如 node、openjdkpython、ruby、golang 等。可以在其中寻找⼀个最符合我们最终⽬标的镜像 为基础镜像进⾏定制。

如果没有找到对应服务的镜像,官⽅镜像中还提供了⼀些更为基础的操作系统镜像,如 ubuntu、 debian、Centos、fedora、alpine 等,这些操作系统的软件库为我们提供了更⼴阔的扩展空间。

除了选择现有镜像为基础镜像外,Docker 还存在⼀个特殊的镜像,名为 scratch 。这个镜像是虚拟的 概念,并不实际存在,它表示⼀个空⽩的镜像。

FROM scratch 
...

如果你以 scratch 为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第 ⼀层开始存在。有的同学可能感觉很奇怪,没有任何基础镜像,我怎么去执⾏我的程序呢,其实对于 linux 下静态编译的程序来说,并不需要有操作系统提供运⾏时⽀持,所需的⼀切库都已经在可执⾏⽂ 件⾥了,因此直接 FROM scratch 会让镜像体积更加⼩巧。使⽤ Go 语⾔ 开发的应⽤很多会使⽤这种⽅ 式来制作镜像,这也是为什么有⼈认为 Go 是特别适合容器微服务架构的语⾔的原因之⼀。

三、RUN执行命令

RUN 指令是⽤来执⾏命令⾏命令的。由于命令⾏的强⼤能⼒, RUN 指令在定制镜像时是最常⽤的指令 之⼀。其格式有两种:
shell 格式:RUN <命令>,就像直接在命令⾏中输⼊的命令⼀样。刚才写的 Dockerfile 中的 RUN 指令就是这种格式。

RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

exec 格式:RUN ["可执⾏⽂件", "参数1", "参数2"],这更像是函数调⽤中的格式。 既然 RUN 就像 Shell 脚本⼀样可以执⾏命令,那么我们是否就可以像 Shell 脚本⼀样把每个命令对应⼀个 RUN 呢?⽐如这样:

FROM debian:jessie 
RUN apt-get update 
RUN apt-get install -y GCc libc6-dev make 
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" 
RUN mkdir -p /usr/src/redis 
RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 
RUN make -C /usr/src/redis 
RUN make -C /usr/src/redis install

之前说过,Dockerfile 中每⼀个指令都会建⽴⼀层,RUN 也不例外。每⼀个 RUN 的⾏为,就和刚才 我们⼿⼯建⽴镜像的过程⼀样:新建⽴⼀层,在其上执⾏这些命令,执⾏结束后,commit 这⼀层的修改,构成新的镜像。 

⽽上⾯的这种写法,创建了 7 层镜像。这是完全没有意义的,⽽且很多运⾏时不需要的东⻄,都被装 进了镜像⾥,⽐如编译环境、更新的软件包等等。结果就是产⽣⾮常臃肿、⾮常多层的镜像,不仅仅 增加了构建部署的时间,也很容易出错。 这是很多初学 Docker 的⼈常犯的⼀个错误。

UNIOn FS 是有最⼤层数限制的,⽐如 AUFS,曾经是最⼤不得超过 42 层,现在是不得超过 127 层。

 上⾯的 Dockerfile 正确的写法应该是这样:

FROM debian:jessie 
RUN buildDeps='gcc libc6-dev make' \ 
&& apt-get update \ 
&& apt-get install -y $buildDeps \ 
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \ 
&& mkdir -p /usr/src/redis \ 
&& tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \ 
&& make -C /usr/src/redis \ 
&& make -C /usr/src/redis install \
&& rm -rf /var/lib/apt/lists/* \ 
&& rm redis.tar.gz \ 
&& rm -r /usr/src/redis \ 
&& apt-get purge -y --auto-remove $buildDeps

⾸先,之前所有的命令只有⼀个⽬的,就是编译、安装 redis 可执⾏⽂件。因此没有必要建⽴很多层, 这只是⼀层的事情。因此,这⾥没有使⽤很多个 RUN 对⼀⼀对应不同的命令,⽽是仅仅使⽤⼀个 RUN 指令,并使⽤ && 将各个所需命令串联起来。将之前的 7 层,简化为了 1 层。在撰写 Dockerfile 的时候,要经常提醒⾃⼰,这并不是在写 Shell 脚本,⽽是在定义每⼀层该如何构建。

并且,这⾥为了格式化还进⾏了换⾏。Dockerfile ⽀持 Shell 类的⾏尾添加 \ 的命令换⾏⽅式,以及 ⾏⾸ # 进⾏注释的格式。良好的格式,⽐如换⾏、缩进、注释等,会让维护、排障更为容易,这是⼀ 个⽐较好的习惯。

此外,还可以看到这⼀组命令的最后添加了清理⼯作的命令,删除了为了编译构建所需要的软件,清 理了所有下载、展开的⽂件,并且还清理了 apt 缓存⽂件。这是很重要的⼀步,我们之前说过,镜像 是多层存储,每⼀层的东⻄并不会在下⼀层被删除,会⼀直跟随着镜像。因此镜像构建时,⼀定要确 保每⼀层只添加真正需要添加的东⻄,任何⽆关的东⻄都应该清理掉。 很多⼈初学 Docker 制作出了 很臃肿的镜像的原因之⼀,就是忘记了每⼀层构建的最后⼀定要清理掉⽆关⽂件。

四、构建镜像

好了,让我们再回到之前定制的 nginx 镜像的 Dockerfile 来。现在我们明⽩了这个 Dockerfile 的内 容,那么让我们来构建这个镜像吧。在 Dockerfile ⽂件所在⽬录执⾏:

$ docker build -t nginx:v3 . 
Sending build context to Docker daemon 2.048 kB 
Step 1 : FROM nginx 
---> e43D811ce2f4 
Step 2 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html 
---> Running in 9cdc27646c7b 
---> 44aa4490ce2c 
Removing intermediate container 9cdc27646c7b 
Successfully built 44aa4490ce2c

从命令的输出结果中,我们可以清晰的看到镜像的构建过程。在 Step 2 中,如同我们之前所说的那 样,RUN 指令启动了⼀个容器 9cdc27646c7b,执⾏了所要求的命令,并最后提交了这⼀层 44aa4490ce2c,随后删除了所⽤到的这个容器 9cdc27646c7b。这⾥我们使⽤了 docker build 命令 进⾏镜像构建。其格式为:

$ docker build [选项] <上下⽂路径/URL/->

在这⾥我们指定了最终镜像的名称 -t nginx:v3,构建成功后,我们可以像之前运⾏ nginx:v2 那样来运 ⾏这个镜像,其结果会和 nginx:v2 ⼀样。

五、镜像构建上下文(Context)

如果注意,会看到 docker build 命令最后有⼀个 . 。 . 表示当前⽬录,⽽ Dockerfile 就在当前⽬录, 因此不少初学者以为这个路径是在指定 Dockerfile 所在路径,这么理解其实是不准确的。如果对应上⾯的命令格式,你可能会发现,这是在指定上下⽂路径。那么什么是上下⽂呢?

⾸先我们要理解 docker build 的⼯作原理。Docker 在运⾏时分为 Docker 引擎(也就是服务端守护进 程)和客户端⼯具。Docker 的引擎提供了⼀组 REST api,被称为 Docker Remote API,⽽如 docker 命令这样的客户端⼯具,则是通过这组 API 与 Docker 引擎交互,从⽽完成各种功能。因此,虽然表 ⾯上我们好像是在本机执⾏各种 docker 功能,但实际上,⼀切都是使⽤的远程调⽤形式在服务端 (Docker 引擎)完成。也因为这种 C/S 设计,让我们操作远程服务器的 Docker 引擎变得轻⽽易举。

当我们进⾏镜像构建的时候,并⾮所有定制都会通过 RUN 指令完成,经常会需要将⼀些本地⽂件复制 进镜像,⽐如通过 COPY 指令、ADD 指令等。⽽ docker build 命令构建镜像,其实并⾮在本地构建, ⽽是在服务端,也就是 Docker 引擎中构建的。那么在这种客户端/服务端的架构中,如何才能让服务 端获得本地⽂件呢?

这就引⼊了上下⽂的概念。当构建的时候,⽤户会指定构建镜像上下⽂的路径,docker build 命令得知 这个路径后,会将路径下的所有内容打包,然后上传给 Docker 引擎。这样 Docker 引擎收到这个上下 ⽂包后,展开就会获得构建镜像所需的⼀切⽂件。如果在 Dockerfile 中这么写:

COPY ./package.JSON /app/

这并不是要复制执⾏ docker build 命令所在的⽬录下的 package.json,也不是复制 Dockerfile 所在⽬录下的 package.json,⽽是复制 上下⽂(context) ⽬录下的 package.json。

因此, COPY 这类指令中的源⽂件的路径都是相对路径。这也是初学者经常会问的为什么 COPY ../package.json /app 或者 COPY /opt/xxxx /app ⽆法⼯作的原因,因为这些路径已经超出了上下⽂的 范围,Docker 引擎⽆法获得这些位置的⽂件。如果真的需要那些⽂件,应该将它们复制到上下⽂⽬录 中去。

现在就可以理解刚才的命令 docker build -t nginx:v3 . 中的这个 . ,实际上是在指定上下⽂的⽬ 录,docker build 命令会将该⽬录下的内容打包交给 Docker 引擎以帮助构建镜像。

如果观察 docker build 输出,我们其实已经看到了这个发送上下⽂的过程:

$ docker build -t nginx:v3 . 
Sending build context to Docker daemon 2.048 kB 
...

理解构建上下⽂对于镜像构建是很重要的,可以避免犯⼀些不应该的错误。⽐如有些初学者在发现 COPY /opt/xxxx /app 不⼯作后,于是⼲脆将 Dockerfile 放到了硬盘根⽬录去构建,结果发现 docker build 执⾏后,在发送⼀个⼏⼗ GB 的东⻄,极为缓慢⽽且很容易构建失败。那是因为这种做法是在让 docker build 打包整个硬盘,这显然是使⽤错误。

⼀般来说,应该会将 Dockerfile 置于⼀个空⽬录下,或者项⽬根⽬录下。如果该⽬录下没有所需⽂ 件,那么应该把所需⽂件复制⼀份过来。如果⽬录下有些东⻄确实不希望构建时传给 Docker 引擎,那 么可以⽤ .gitignore ⼀样的语法写⼀个 .dockerignore ,该⽂件是⽤于剔除不需要作为上下⽂传递给 Docker 引擎的。

那么为什么会有⼈误以为 . 是指定 Dockerfile 所在⽬录呢?这是因为在默认情况下,如果不额外指定 Dockerfile 的话,会将上下⽂⽬录下的名为 Dockerfile 的⽂件作为 Dockerfile。

这只是默认⾏为,实际上 Dockerfile 的⽂件名并不要求必须为 Dockerfile,⽽且并不要求必须位于上下 ⽂⽬录中,⽐如可以⽤ -f ../Dockerfile.php 参数指定某个⽂件作为 Dockerfile。

当然,⼀般⼤家习惯性的会使⽤默认的⽂件名 Dockerfile,以及会将其置于镜像构建上下⽂⽬录中。

六、迁移镜像

Docker 还提供了 docker load 和 docker save 命令,⽤以将镜像保存为⼀个 tar ⽂件,然后传输到另 ⼀个位置上,再加载进来。这是在没有 Docker ReGIStry 时的做法,现在已经不推荐,镜像迁移应该直 接使⽤ Docker Registry,⽆论是直接使⽤ Docker Hub 还是使⽤内⽹私有 Registry 都可以。

使⽤ docker save 命令可以将镜像保存为归档⽂件。⽐如我们希望保存这个 alpine 镜像。

$ docker image ls alpine 
REPOSITORY TAG IMAGE ID CREATED SIZE 
alpine latest baa5d63471ea 5 weeks ago 4.803 MB

保存镜像的命令为:

$ docker save alpine | gzip > alpine-latest.tar.gz

然后我们将 alpine-latest.tar.gz ⽂件复制到了到了另⼀个机器上,可以⽤下⾯这个命令加载镜像:

$ docker load -i alpine-latest.tar.gz 
Loaded image: alpine:latest

如果我们结合这两个命令以及 ssh 甚⾄ pv 的话,利⽤ Linux 强⼤的管道,我们可以写⼀个命令完成从 ⼀个机器将镜像迁移到另⼀个机器,并且带进度条的功能:

docker save <镜像名> | bzip2 | pv | ssh <⽤户名>@<主机名> 'cat | docker load'

到此这篇关于使用Dockerfile脚本定制镜像的文章就介绍到这了,更多相关Dockerfile定制镜像内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 使用Dockerfile脚本定制镜像的方法

本文链接: https://lsjlt.com/news/164481.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 使用Dockerfile脚本定制镜像的方法
    目录前言一、Dockerfile介绍二、FROM指定基础镜像三、RUN执行命令四、构建镜像五、镜像构建上下文(Context)六、迁移镜像前言 镜像的定制实际上就是定制每⼀层所添加的...
    99+
    2024-04-02
  • 如何使用Dockerfile定制Java Web镜像
    本篇内容介绍了“如何使用Dockerfile定制Java Web镜像”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、前言对使用 Docke...
    99+
    2023-06-19
  • Docker中Dockerfile制作镜像的方法步骤
    目录1.基于容器制作2. 基于Dockerfile制作镜像2.1 Dockerfile命令2.2 简单示例docker 镜像的制作,可以基于容器创建镜像,也可基于 dockerfil...
    99+
    2024-04-02
  • 如何使用Dockerfile创建自定义镜像
    要使用Dockerfile创建自定义镜像,请按照以下步骤: 创建一个新的文件夹,并在文件夹中创建一个名为Dockerfile的文...
    99+
    2024-04-02
  • docker通过Dockerfile构建mysql镜像的方法
    构建Dockerfile ,路径 /docker/mysql FROM hub.c.163.com/library/mysql:5.7 #作者信息 MAINTAINER hu "**...
    99+
    2024-04-02
  • Docker入门系列之二:使用dockerfile制作包含指定web应用的镜像
    在前一篇文章:Docker入门系列之一:在一个Docker容器里运行指定的web应用 里,我们已经成功地将我们在本地开发的一个web应用部署到Docker容器里运行。本文将介绍如何制作一个包含了这个web应用的Docker镜像。镜...
    99+
    2023-06-04
  • 从docker镜像里提取dockerfile的两种方法
    目录前言从镜像中提取dockerfile的两种方法1、history参数2、dfimage补充:如何设置永久的别名总结前言 hello,大家好,今天在玩docker的时候发现了很好用的东西,他就是用来提取镜像中的dockerfile的。这个...
    99+
    2024-04-02
  • 怎么用docker Dockerfile文件制作自己的镜像
    本文小编为大家详细介绍“怎么用docker Dockerfile文件制作自己的镜像”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么用docker Dockerfile文件制作自己的镜像”文章能帮助大家解...
    99+
    2024-04-02
  • Docker镜像的使用方法
    这篇文章将为大家详细讲解有关Docker镜像的使用方法,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。当运行容器时,使用的镜像如果在本地中不存在,docker 就会自动从 docker 镜像仓...
    99+
    2023-06-06
  • Docker本地导入镜像/保存镜像/载入镜像/删除镜像的方法
    本篇内容介绍了“Docker本地导入镜像/保存镜像/载入镜像/删除镜像的方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读...
    99+
    2024-04-02
  • Dockerfile基本使用方法有哪些
    本篇内容主要讲解“Dockerfile基本使用方法有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Dockerfile基本使用方法有哪些”吧!Dockerfile的组成Dockerfile分...
    99+
    2023-06-28
  • Docker使用镜像仓库的方法
    为什么用镜像仓库 核心的原因是足够方便和不容易出错。 操作流程是这样的:首先在本地docker完成镜像配置和部署等操作,测试无误后将本地镜像推到镜像仓库。需要部署到服务器时,只需要在...
    99+
    2024-04-02
  • 制作centos基础镜像的方法
    前言 现在我所在的公司使用的操作系统都是centos7.4版本的, 当然应用也是部署在centos上面, 那么如果使用docker部署的话, 也自然而然的想到基于centos镜像来构建自己的应用镜像; 但是centos基...
    99+
    2022-06-04
    制作centos基础镜像 centos 制作镜像
  • 详解Docker镜像的基本操作方法
    目录一、获取镜像二、运行镜像三、列出镜像四、镜像大小五、删除本地镜像一、获取镜像 之前我们提到过 Docker 官⽅提供了⼀个公共的镜像仓库:Docker Hub,我们就可以从这上⾯获取镜像,获取镜像的命令:docker pull,格式为:...
    99+
    2024-04-02
  • Dockerfile Maven 插件的使用方法
    本篇内容介绍了“Dockerfile Maven 插件的使用方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Dockerfile Mave...
    99+
    2023-06-19
  • docker官方mysql镜像自定义配置的方法
    这篇“docker官方mysql镜像自定义配置的方法”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看...
    99+
    2024-04-02
  • 使用Dockerfile构建自定义jdk镜像,在使用jdk镜像创建一个容器来外部访问(一步一步来哦~好简单的呢)
    文章主人公:帅哥BUG😎  文章路人: 路人 🤨  路人 😛 🤨:什么是dockerfile 😎:Dockerfile 是一个文本...
    99+
    2023-10-26
    运维 服务器 容器 docker 云原生
  • Docker镜像的基本操作方法是什么
    今天小编给大家分享一下Docker镜像的基本操作方法是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、获取镜像之前我们...
    99+
    2023-07-02
  • PHP中shell脚本的使用方法
    今天就跟大家聊聊有关PHP中shell脚本的使用方法,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。我们都知道,在计算机科学中,SHELL类似于DOS下的command.com。它接收...
    99+
    2023-06-17
  • 如何使用Dockerfile创建支持ssh服务自启动的容器镜像
    本文小编为大家详细介绍“如何使用Dockerfile创建支持ssh服务自启动的容器镜像”,内容详细,步骤清晰,细节处理妥当,希望这篇“如何使用Dockerfile创建支持ssh服务自启动的容器镜像”文章能帮...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作