Docker(二)Docker镜像的构建

一    为什么要制作镜像

说明:可以通过'镜像仓库来下载',但是如果镜像仓库并'没有我们需要的镜像',或者下载的镜像'不能保证'别人有没有在镜像中留有'后门',都是我们需要考虑的问题,由此引入了我们'自定义构建镜像的'需求!

二    镜像构建方式

(1)方式1

镜像的构建  -->  '容器里面有新下载的东西,需要打包成一个新的环境'

docker commit 构建新镜像三部曲

1) 运行容器
2) 修改容器
3) 将容器保存为'新的镜像'

缺点:

1)效率低、可重复性弱、容易出错
2)使用者无法对镜像进行审计,存在安全隐患
3)构建的镜像不纯净,会包含当前容器中产生的新的内容!

busybox是一个基础的镜像

运行容器:修改容器 (以下命令在容器内运行)
# echo helloworld > testfile
将容器保存为新的镜像
# docker run -it --name test busybox
# docker commit test test:v1
'查看镜像'
# docker images test:v1

(2)方式2:利用Dockerfile

问题1什么是Dockerfile

官方: '镜像制作的模板' --> '就是一个描述性文件'

根据'自定义'的一个语法规则,帮我们得到我们想要的'镜像体',得到一个被'封装环境'

详细:Dockfile 是一种被 Docker 程序解释的"脚本",Dockerfile 由一条一条的指令组成,每条指令对应 Linux 下面的一条命令,Docker 程序将这些 Dockerfile 指令翻译真正的 Linux 命令。Dockerfile 有自己书写格式支持的命令,Docker 程序解决这些命令间的依赖关系,类似于Makefile,Docker 程序将读取 Dockerfile,根据指令生成定制的 image

备注重点和难点

三    Dockerfile的工作原理

docker build -t 仓库名:tag -f Dockerfile .

重点:'上下文路径 --> context path'

工作原理

 1)把文件'Dockerfile和.'上传到'Docker Daemon' -->此时'才有上下文一说 -->针对的是服务器端'

 2)然后DOcker Daemon根据'此Dockerfile的内容',从'当前上下文进行构建'

 3) 清除不需要的文件

理解: 此时'上下文'相当于构建的'根路径'

错误: COPY /mnt/ /mnt  --> '因为当前上下文就没有/mnt'

四    Dockerfile的语法规则

(1)FROM

基础镜像:基础工具的集合

1、FROM(指定base image):

(1)构建指令,必须指定且需要在 Dockerfile 其他指令的'前面'

(2)后续的指令都'依赖于'该指令指定的image

(3)FROM 指令指定的基础 image 可以是'官方远程仓库中'的,也可以位于'本地仓库'

(4)一个镜像中'有且只有'一个

举例:Apach安装需要依赖gcc(libary层级),需要Linux内核的支持,需要安装这些base image

FROM busybox

FROM rhel:7.3

说明:不指定版本默认就是'最新的latest版本'

(2)MAINTAINER

说明:用来指定镜像创建者信息

构建指令:用于将 image 的制作者相关的信息写入到 image 中,本身没有什么功能性的作用,只是一个打一个身份标签

显示:当我们对该 image 执行 docker inspect 命令时,输出中有相应的字段记录该信息

MAINTAINER wangzhijian "wzj@qq.com"

(3) RUN

作用安装软件用的构建指令

特点:RUN 可以运行任何被基础 image 支持的命令

举例:如基础 image 选择了 RHEL7.3,那么软件管理部分只能使用RHEL7.3 的包管理命令

底层:RUN 在容器中运行命令并创建新的镜像层

补充:镜像层不能超过127层!

注意:后面直接跟容器中已经存在的命令!

演示

RUN cd /tmp && curl -L
'http://archive.apache.org/dist/tomcat/tomcat-7/v7.0.8/bin/apache-tomcat-7.0.8.tar.gz'| tar -xz
RUN ["/bin/bash", "-c", "echo hello"]

# 说明:上述的必须保证所在的主机可以连接网络!

(4)CMD

特点:设置 container 启动时执行的操作(docker history 镜像 -->COMMAND命令),commit不能给我们提供的!

作用:用于 container 启动时指定的操作,该操作可以是执行自定义脚本(大型环境-->匹配设置),也可以是执行系统命令

细节:该指令只能在文件中存在一次,如果有多个,则只执行最后一条

一条理解:如果有多条需要执行(干很多事情),可以通过 &&链接多条,成为一条!

场景:只有从镜像启动成为容器,或者restart容器才会执行

CMD echo “Hello, World!”

 (5)ENTRYPOINT

特点:和CMD一样也是设置 container 启动时执行的操作设置指令

作用:指定容器启动时执行的命令,可以多次设置,但是只有最后一个有效

ENTRYPOINT ls -l

区别:CMD会被docker run后面的命令行覆盖,而ENTRYPOINT不会被忽略一定会被执行

思考:为什么有了cmd之后,还会需要entrypoint

原因:互相配合

补充

  1)该指令的使用分为两种情况,一种是独自使用,另一种和 CMD 指令配合使用

独自使用时,如果你还使用了 CMD 命令且 CMD 是一个完整的可执行的命令,那么 CMD 指令和 ENTRYPOINT 会互相覆盖

结果:只有最后一个 CMD 或者 ENTRYPOINT 有效

CMD echo “Hello, World!”

ENTRYPOINT ls -l

# 说明:认为是同一个类型,CMD 指令将不会被执行,只有 ENTRYPOINT 指令被执行

2)另一种用法和 CMD 指令配合使用

目的:来指定 ENTRYPOINT 的默认参数,这时 CMD 指令不是一个完整的可执行命令,仅仅是参数部分

注意:此时ENTRYPOINT 指令只能使用 JSON 方式指定执行命令,而不能指定参数

补充:只是有这种用法而已,不建议使用,太麻烦!

FROM rhel7
CMD ["-l"]
ENTRYPOINT ["/usr/bin/ls"]
# Shell和exec格式的区别

# cat Dockerfile
FROM busybox
ENV name world
ENTRYPOINT echo "hello, $name"

# Shell格式底层会调用/bin/sh -c来执行命令,可以解析变量,而下面的exec格式不会

# cat Dockerfile
FROM busybox
ENV name world
ENTRYPOINT ["/bin/echo", "hello, $name"]

# 官方推荐exec的执行方式!
# 需要改写成以下形式

# cat Dockerfile

FROM busybox
ENV name world
ENTRYPOINT ["/bin/sh", "-c", "echo hello, $name"]


# Exec格式时,ENTRYPOINT可以通过CMD提供额外参数,CMD的额外参数可以在容器启动时动态替换!

# 在shell格式时ENTRYPOINT会忽略,任何CMD或docker run提供的参数

# cat Dockerfile
FROM busybox
ENTRYPOINT ["/bin/echo", "hello"]
CMD ["world"]
# 看下在运行容器时的区别-->动态替换(结合上面的)

# docker run --rm busybox:v1

hello world

# docker run --rm busybox:v1 linux

hello linux

# 推荐使用exec格式书写

(6)USER

作用:设置 container 容器的用户

目的:设置启动容器的用户,默认是 root 用户

USER daemon = ENTRYPOINT ["memcached", "-u", "daemon"]

# 容器在启动的时候是memcached用户

(7)EXPOSE

作用:指定容器需要映射到宿主机器的端口,告诉用户暴露哪个端口,起到一个显示作用(ps -a可以查看)

特点:该指令会将容器中的端口映射成宿主机器中的某个端口,当你需要访问容器的时候,可以不是用容器的 IP 地址而是使用宿主机器的IP 地址和映射后的端口。

核心两个步骤:首先在 Dockerfile 使用 EXPOSE 设置需要映射的容器端口,然后在运行容器的时候指定-p 选项加上 EXPOSE 设置的端口,这样 EXPOSE 设置的端口号会被随机映射成宿主机器中的一个端口号,也可以指定需要映射到宿主机器的那个端口,这时要确保宿主机器上端口号没有被使用。EXPOSE 指令可以一次设置多个端口号,相应的运行容器的时候可以配套的多次使用-p 选项


# 如果容器中运行"应用服务",可以把服务端口暴露出去

# EXPOSE 80     -->常常就是一个声明-->端口映射可能需要!

######################

EXPOSE 22

# 相应的运行容器使用的命令

docker run -p port1 image

##############################

# 映射多个端口
EXPOSE port1 port2 port3
# 相应的运行容器使用的命令
docker run -p port1 -p port2 -p port3 image

############推荐这种方式########

# 还可以指定需要映射到宿主机器上的某个端口号

docker run -p host_port1:port1 -p host_port2:port2 -p host_port3:port3 image

# 简单的应用:80:8080(tomcat) -->3306:4000(TIDB)!

(8)ENV

作用:用于设置环境变量构建指令,在 image 中设置一个环境变量

特点:设置了后,后续的 RUN 命令都可以使用,container 启动后,可以通过 docker inspect 查看这个环境变量,也可以通过在 docker run --env key=value 时设置或修改环境变量。

应用:假如你安装了 JAVA 程序,需要设置 JAVA_HOME,那么可以在 Dockerfile 中这样书写

ENV JAVA_HOME /path/to/java/dir

ENV HOSTNAME sevrer1.example.com

# 对个数没有要求!

(9)ADD

功能:从 src 复制文件到 container 的 dest 路径

场景:构建一个镜像可能会用到源码包(基础镜像并没有),从当前的操作系统添加到基础镜像中!

ADD <src> <dest>
# <src> 是相对被构建的源目录的相对路径,可以是文件或目录的路径,也可以是一个远程的文件 url;
# url:先下载,再拿进去!
# <dest> 是 container 中的绝对路径

(10)COPY

功能:从 src 复制文件到 container 的 dest 路径

COPY <src> <dest>

对比ADD不解压,并且不支持url,只是单纯的复制不推荐

##########ADD############

# 用法与COPY类似

# 不同的是src可以是归档压缩文件,文件会被自动解压到dest,也可以自动下载URL并拷贝到镜像

#######用法案例(支持两种方式)######

ADD html.tar /var/www

ADD http://ip/html.tar /var/www

# 区别:当是tar包时前者会直接解tar包(即使容器没有tar命令)、后者直接复制进去

copy细节

FROM busybox
COPY Dockerfile /data/ # 注意:data加不加/的区别(文件,目录)
RUN echo 'hello world'

(11)VOLUME

说明:指定挂载点,数据持久化会用到

说明:设置指令,使容器中的一个目录具有持久化存储数据的功能,该目录可以被容器本身使用,也可以共享给其他容器使用。我们知道容器使用的是 AUFS这种文件系统(本身不能持久化数据),当容器关闭后,所有的更改都会丢失

应用场景:当容器中的应用有持久化数据的需求时可以在 Dockerfile 中使用该指令

FROM rhel7

# 申明数据卷,通常指定的是应用的数据挂在点--->数据的持久化!

VOLUME ["/tmp/data"]

VOLUME ["/var/www/html"]

# 注意:分清真实的环境和容器的的环境(真实数据记录的目录-->/var/lib/docker/)!

(11) WORKDIR

作用:切换工作目录

说明:如果目录不存在会自动创建

设置指令,可以多次切换(相当于 cd 命令),为RUN、CMD、ENTRYPOINT、ADD和COPY指令'设置镜像中的当前工作目录','相当于cd'

WORKDIR /p1 WORKDIR p2 RUN vim a.txt

# 相当于--->vim /p1/p2/a.txt

12、ONBUILD

特点:在子镜像中执行,ONBUILD 指定的命令在构建镜像时并不执行,新镜像转换为容器也不会执行!

有意思:当别人拿你的镜像做更新的镜像才会执行,在它的子镜像中执行!

场景:保护数据,可以做一些有意思的操作(自毁操作)

ONBUILD ADD . /app/src

ONBUILD RUN /usr/local/bin/python-build --dir /app/src

杂谈

# 镜像的导出以及导入

# 导出:docker save -o xx.xx.xx.tar
# 导入:docker load -i xx.xx.xx.tar

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值