暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

五、定制Docker镜像

大数据开发笔记 2021-10-02
529

一、定制Docker镜像

当我们从docker镜像仓库中下载的镜像不能满足我们的需求时,我们可以通过以下两种方式对镜像进行更改。

  1. 从已经创建的容器中更新镜像,并且提交这个镜像

  2. 使用Dockerfile指令来创建—个新的镜像

    好处

    1、对于开发人员,可以为开发团队提供一个完全一致的开发环境

    2、对于测试人员,可以直接拿开发时所构建的镜像测试。

    3、对于运维人员,在部署时,可以实现快速部署、移值。

镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是Dockerfile。

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

二、tomcat定制

因为官方镜像优化了很多不必要的功能,例如tomcat的index.html页面,下面通过定制docker镜像来实现index.html

2.1.拉取tomcat

docker pull tomcat:10

2.2. dockerdfile常用命令

FROM

指定基础镜像
基础镜像不存在会在Docker Hub上拉去(一般会是文件的第一个指令)使用格式:
FROM<镜像>:[tag]!
FROM<镜像>@digest[校验码]
当前主机没有此镜像时,会自动去官网HUB下载

MAINTAINER

--提供Dockerfile制作者提供本人信息
[逐渐废弃]
LABLE--替代MAINTANIER具体使用:
LABLE maintainer="作者信息"
使用格式:
MAINTANIER "xiaominmg <123456@qq.com>"
LABEL maintainer= " guoweixin@aliyun .com"
LABEL "com. example.vendor"=" ACME Incorporated"
LABEL com.example.label-with-value= "foo"
LABEL version="1.8"
LABEL description="This text illustrates lthat label-values can span multiple lines."


ENV

ENV指令可以用于为docker容器设置环境变量ENV设置的环境变量,可以使用docker inspect命令来查看。同时
还可以使用docker run --env <key>=<value>来修改环境变量。
具体用法:
ENV JAVA_HOME /usr / local/jdk
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/ :$JRE_HOME/1ib/
ENV PATH $PATH : $JAVA_HOME/bin/

WORKDIR

WORKDIR用来切换工作目录的。
Docker默认的工作目录是/,只有 RUN能执行cd命令切换目录,而且还只作用在当下下的 RUN,也就是说每—个RUN都是独立进行的。
如果想让其他指令在指定的目录下执行,就得靠WORKDIR。WORKDIR动作的目录改变是持久的,不用每个指令前都使用一次WORKDIR。
WORKDIR /usr/local/tomcat/

RUN

RUN:用于执行后面跟着的命令行命令。有以下俩种格式:

shell 格式:

RUN <命令行命令>
<命令行命令> 等同于,在终端操作的 shell 命令。

exec 格式:

RUN ["可执行文件", "参数1", "参数2"]
例如:
RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline

Dockerfile中每一个指令都会建立一层,RUN也不例外。每一个RUN的行为,和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束后,commit这一层的修改,构成新的镜像。而上面的这种写法,创建了多层镜像。这是完全没有意义的,而且很多运行时不需要的东西,都被装进了镜像里,比如编译环境、更新的软件包等等。结果就是产生非常臃肿、非常多层的镜像,不仅仅增加了构建部署的时间,也很容易出错。这是很多初学Docker的人常犯的一个错误。Union FS是有最大层数限制的,比如AUFS,曾经是最大不得超过42层,现在是不得超过127层。上面的Dockerfile 正确的写法应该是这样:

ROM centos
RUN apt-get update \
&& apt-get install -y gcc libc6-dev make \
&& wget http://download.redis.io/releases/redis-4.0.1.tar.gz \
&& tar xzf redis-4.0.1.tar.gz \
&& cd redis-4.0.1

首先,之前所有的命令只有一个目的,就是编译、安装 redis 可执行文件。因此没有必要建立很多层,这只是一层的事情。因此,这里没有使用很多个 RUN 对一一对应不同的命令,而是仅仅使用一个 RUN 指令,并使用 && 将各个所需命令串联起来。将之前的 7 层,简化为了 1 层。

首先,之前所有的命令只有一个目的,就是编译、安装 redis 可执行文件。因此没有必要建立很多层,这只是一层的事情。因此,这里没有使用很多个 RUN 对一一对应不同的命令,而是仅仅使用一个 RUN 指令,并使用 && 将各个所需命令串联起来。将之前的 7 层,简化为了 1 层。

在撰写 Dockerfile 的时候,要经常提醒自己,这并不是在写Shell 脚本,而是在定义每一层该如何构建且,这里为了格式化还进行了换行。Dockerfile 支持 Shell 类的行尾添加 \ 的命令换行方式,以及行首 # 进行注释的格式。良好的格式,比如换行、缩进、注释等,会让维护、排障更为容易,这是一个比较好的习惯。

EXPOSE

为容器打开指定要监听的端口以实现与外部通信
使用格式:
EXPOSE 80/tcp 23/udp I
不加协议默认为tcp
使用-P选项可以暴露这里指定的端口!
但是宿主的关联至这个端口的端口是随机的!

COPY

把宿主机中的文件复制到镜像中去文件要在Dockerfile工作目录
COPY [--chown=<user>:<group>] <源路径1>...  <目标路径>
COPY
[--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]

[--chown=<user>:<group>]:可选参数,用户改变复制到容器内文件的拥有者和属组。

<源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:

COPY hom* /mydir/
COPY hom
?.txt /mydir/

<目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。

ADD

类似COPY命令ADD将文件从路径<src>复制添加到容器内部路径<dest>。<src>必须是想对于源文件夹的一个文件或目录,也可以是一个远程的url。<dest>是目标容器中的绝对路径。所有的新文件和文件夹都会创建UID和GID。事实上如果<src>是一个远程文件URL,那么目标文件的权限将会是600。

VOLUME

创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。--卷只能定义docker管理的卷:VOLUME /data/mysql运行的时候会随机在宿主机的目录下生成一个卷目录!

CMD

启动容器时执行的Shell命令,例如:

CMD ["-C", "/start.sh"]
CMD ["/usr/sbin/sshd", "-D"]
CMD /usr/sbin/sshd -D

三、案例

需求:创建一个镜像(基于tomcat)里面要有一个index.html,

1、在宿主机创建一空白目录

mkdir -p /usr/local/docker/demo1cd /usr/local/docker/demo1

2、在该目录下,创建一文件Dockerfile

vim Dockerfile

3、其内容为:

FROM tomcat
RUN mkdir -p /usr/local/tomcat/webapps/ROOT/
RUN echo 'He1lo Docker' > /usr/loca1/tomcat/webapps/ROOT/index.htm1
WORKDIR /usr/local/tomcat/webapps/

4、构建镜像

docker build -t demo1 .

5、运行镜像所在容器

docker run --rm–name demo1-8080 -p 8088:8080 -d demo1

访问浏览器即可成功该问

基于上一个镜像(基于tomcat)外部复制一个文件(图片),并复制到容器中并能访问1基于如上修改Dockerfile

FROM tomcatWORKDIR /usr/local/tomcat/webapps/ROOT/
RUN rm -rf *
COPY 1.png /usr/local/tomcat/webapps/R00T/
RUN echo 'Hello Docker' > /usr/local/tomcat/webapps/ROOT/index.html

WORKDIR用来切换工作目录的。而不是用RUN。

构建镜像

docker build -t 镜像名﹒ //Dockerfile上下文路径

COPY 格式:

COPY<源路径>…<目标路径>

COPY ["<源路径1>"… “<目标路径>”]

和RUN指令一样,也有两种格式,一种类似于命令行,一种类似于函数调用。

COPY指令将从构建上下文目录中〈源路径>的文件/目录复制到新的一层的镜像内的〈<目标路径〉位置。比

如:COPY 1. png /usr/ local/tomcat/webapps/ROOT/

<目标路径>可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用WORKDIR指令来指定)。目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。

此外,还需要注意一点,使用COPY指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。这个特性对于镜像定制很有用。特别是构建相关文件都在使用Git进行管理的时候。

docker run --rm--name demo1-8080 -p 8088:8080 -d demo1

docker build命令进行镜像构建。其格式为:

docker build[选项] <上下文路径/URL/>

docker build -t demo1 . ﹒代表Dockerfile上下文路径

-t︰指定要创建的目标镜像名

.: Dockerfile文件所在目录,可以指定Dockerfile的绝对路径
在这里我们指定了最终镜像的名称-t demo1,构建成功后,我们可以像之前运行 tomcat 那样来运行这个镜像,其结果会和tomcat一样。(如果有版本号名称: demo1:01)

虚悬镜像

镜像列表中,还可以看到一个特殊的镜像,这个镜像既没有仓库名,也没有标签,均为这个镜像原本是有镜像名和标签的,原来为tomcat:8.0,随着官方镜像维护,发布了新版本后,重新dockerpull tomcat:8.0时, tomcat:8.0这个镜像名被转移到了新下载的镜像身上,而旧的镜像上的这个名称则被取消,从而成为了。除了docker pull 可能导致这种情况,docker build也同样可以导致这种现象。由新旧镜像同名,旧镜像名称被取消,从而出现仓库名、标签均为的镜像。这类无标签镜像也被称为虚悬镜像(dangling image)。
一般来说,虚悬镜像已经失去了存在的价值,是可以随意删除的,可以用下面的命令删除:

docker image prune


文章转载自大数据开发笔记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论