docker2-镜像原理及创建新的镜像

1,镜像是什么

镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件

在docker中所有应用直接打包为镜像,下载下来就可以直接运行。

2,如何获取镜像

  • 从远程仓库下载
  • 拷贝
  • 自己制作镜像DockerFile

3,Docker镜像基本概念

3.1,UnionFS(联合文件系统)(Docker镜像分层)

一种分层、轻量级并且高性能的文件系统,支持对文件系统的修改作为提交并一层层叠加,同时可以将不同目录挂载到同一虚拟文件系统下(unite several directories into a single virtual filesystem)。Union文件系统是Docker镜像的基础,镜像可以通过分层进行继承,基于基础镜像(无父镜像),可以制作各种具体的应用镜像。

特性:一次同时加载多个文件系统,但从外面看来,只能看到一个文件系统;联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。

docker分层系统0 docker分层系统1 docker分层系统2
3.2,Docker镜像底层

在Docker镜像的最底层是bootfs(boot file system,主要包含bootloader和kernel,bootloader主要引导加载kernel,linux刚启动时就会加载bootfs文件系统),在bootfs加载完成之后整个内核就在内存中了,内存的使用权已由bootfs转交给内核,此时系统会卸载bootfs。

roofts(root file system/Base Image),在bootfs之上,包含的就是典型linux系统中的/dev, /proc, /bin, /etc等标准文件和目录。rootfs就是各种不同的操作系统的发性版,比如ubuntu、centos等。

3.3,为什么Docker镜像可以很小?

对于一个精简的docker,rootfs可以很小,只需要包含最基本的命令、工具和程序库即可。底层会直接使用宿主机(host)的kernel,镜像只需要提供rootfs,因此可以很小。由此也可看出,不同的linux发行版,bootfs基本是一致的,只是rootfs会有差别,不同的发行版可以公用bootfs。

4,Docker镜像启动过程

Docker镜像都是只读的,当容器启动时,一个新的可读写层被加载到镜像的顶层。新增层就是所谓的容器层,容器层之下的都是镜像层。所有的更改都在容器层中,镜像层不发生改变。

1、检测本地是否存在指定的镜像,不存在就从公有仓库下载

2、利用镜像创建并启动一个容器

3、分配一个文件系统,并在只读的镜像层外面挂载一层可读写层

4、从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去

5、从地址池配置一个IP地址给容器

6、执行用户指定的应用程序

7、执行完毕后终止容器

5,提交容器创建新的镜像

容器内做了修改后想要保存为新的镜像:

docker commit -m='提交的容器信息' -a='作者' 容器id 目标镜像名:tag		#git本地类似

6,Dockerfile创建新的镜像

Dockerfile就是用来构建docker镜像的构建文件,是一种命令脚本,通过此脚本可以生成镜像。

镜像是分层的,Dockerfile中的每一个命令就是一层。

docker build -f ~(dockerfile) -t ~(image名称):tag .
'''一个例子'''

'''=======================创建dockerfile文件(名字也可随意取)并输入以下内容======================='''
from centos

CMD echo '-----end-----'
CMD /bin/bash

'''=======================docker build构建镜像======================='''
docker build -f dockerfile -t zhang/centos:01 .
一个问题
'''=======================创建dockerfile文件(名字也可随意取)并输入以下内容======================='''
from centos

VOLUME ['volume10', 'volume11']

CMD echo '-----end-----'
CMD /bin/bash

生成后run的时候会报错
[root@VM-0-11-centos docker-test-volum]# docker: Error response from daemon: OCI runtime create failed: invalid mount {Destination:[volume10, Type:bind Source:/var/lib/docker/volumes/7e8b5576dee6ad0d84ab31848f12b859b6ed4e05408492477308479dcbea20c4/_data Options:[rbind]}: mount destination [volume10, not absolute: unknown.

=============================================解答===========================================
=====第一次尝试=====
通过dockerfile的 VOLUME 指令可以在镜像中创建挂载点,这样只要通过该镜像创建的容器都有了挂载点。
还有一个区别是,通过 VOLUME 指令创建的挂载点,无法指定主机上对应的目录,是自动生成的。

VOLUME ['volume10', 'volume11']	这一句的目的是在生成镜像的同时,在镜像中创建'volume01', 'volume02'并自动匿名挂载,这里说不是绝对路径不对,但是改为VOLUME ['/volume10', '/volume11']还是报错
[root@VM-0-11-centos docker-test-volum]# docker run -it zhang/centos
docker: Error response from daemon: OCI runtime create failed: invalid mount {Destination:[/volume10, Type:bind Source:/var/lib/docker/volumes/fa8716e8e78b1a9af0cfd75ac9476b6fcbecf7178b34d29d390c6ab29f19cfaf/_data Options:[rbind]}: mount destination [/volume10, not absolute: unknown.

7,dockerfile详解

7.1,使用dockerfile创建镜像的步骤:
  1. 编写一个dockerfile文件(构建文件,定义了一切的步骤,源代码)
  2. docker build构建成为一个镜像(通过dockerfile构建生成的镜像,最终发布和运行的产品)
  3. docker run运行镜像(容器,镜像运行起来提供服务)
  4. docker push发布镜像(发布到DockerHub或者其他第三方镜像仓库)
7.2,一个dockerhub官方的例子,点到版本号上会发现跳转到github
docker分层系统2 docker分层系统2

很多官方镜像都是基础包,很多功能都没有,通常需要搭建自己的镜像。

7.3,dockerfile的一些基本概念
  • Dockerfile由多条指令组成,每条指令在编译镜像时完成某些功能

  • 每条指令由指令+参数组成,以逗号分隔

  • 指令使用大写字母,参数使用小写字母,#表示注释

  • 指令从上到下执行,每一条指令都会创建提交一个新的镜像层(bootfs, rootfs(基础镜像centos/tomcat), image(jdk/tomcat…), image),在run的时候在镜像的顶层增加可写容器层(container)形成容器进行运行

    docker分层系统2
7.4,dockerfile常用指令
FROM										#基础镜像指令,一切由此开始构建(BASE IMAGE,如:centos)
MAINTAINER									#镜像是谁写的,姓名+邮箱
RUN											#镜像构建时需要运行的命令
ADD											#添加内容(IMAGE,如:emacs,apache,tomcat等)
COPY										#类似ADD,将文件拷贝到镜像中
WORKDIR										#镜像的工作目录(进入镜像所在的目录,默认是根目录/)
VOLUME										#挂载的目录
EXPOSE										#指定暴露端口
CMD											#指定容器启动时要运行的命令(如:CMD echo),只有最后一个生效
ENTRYPOINT									#指定容器启动时要运行的命令,可追加命令(追加命令是直接追加到其后的)
ONBUILD										#当构建一个被继承 dockerfile,会运行ONBUILD,触发指令
ENV											#构建时设置环境变量(构建一个键值对,常量)
7.5,一些例子(可以如7.2所述,看看别人是怎么写的)

DockerHub中99%的镜像都是从FROM scratch开始的,scratch是一个空镜像,只能用于构建其他镜像。

'''例子一,为官方的centos镜像加入vim以及ifconfig命令'''
===========dockerfile文件
FROM centos
MAINTAINER zhang<15009202810@163.com>

ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo '----end----'
CMD /bin/bash

===========生成镜像
docker build -f mydockerfile-centos -t zhang:centos:02 .

===========生成的镜像
zhang/centos          02        f86b612c2f9e   4 hours ago      295MB

===========运行
root@VM-0-11-centos dockerfile]# docker run -it f86b612c2f9e
[root@03a66e354d06 local]# pwd
/usr/local
[root@03a66e354d06 local]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.6  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:06  txqueuelen 0  (Ethernet)
        RX packets 7  bytes 586 (586.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@03a66e354d06 local]# vim

c;?;?
~                                                                                                         ~                                                                               
'''例子二,CMD和ENTRYPOINT的区别'''
'''CMD V1'''
===========dockerfile文件
FROM centos
CMD ["ls","-a"]

===========生成镜像
docker build -f dockerfile-cmd-test -t cmd-test:01 .

===========生成的镜像
REPOSITORY            TAG       IMAGE ID       CREATED         SIZE
cmd-test              01        09620dfdb9ab   3 seconds ago   209MB

===========运行
docker run 09620dfdb9ab						#可以运行
docker run 09620dfdb9ab -l					#报错(不追加,相当于运行-l)
docker run 09620dfdb9ab ls -l				#可以运行(CMD最后一个生效,相当于运行ls -l)

'''ENTRYPOINT V1'''
===========dockerfile文件
FROM centos
ENTRYPOINT ["ls","-a"]

===========生成镜像
docker build -f dockerfile-entropy-test -t entrypoint-test .

===========生成的镜像
REPOSITORY            TAG       IMAGE ID       CREATED              SIZE
entrypoint-test       latest    51d3b39d0e6a   About a minute ago   209MB

===========运行
docker run 09620dfdb9ab						#可以运行
docker run 09620dfdb9ab -l					#可以运行(追加,相当于运行ls -a -l)
docker run 09620dfdb9ab ls -l				#报错(相当于运行ls -a ls -l)

命名为Dockerfile,在build时不用指定-f,默认就是docker build -f Dockerfile

使用ADD命令添加进来的压缩包自动解压缩

'''例子三,制作tomcat镜像'''
需要准备:
tomcat压缩包https://tomcat.apache.org/download-90.cgi,apache-tomcat-9.0.48.tar.gz
jdk压缩包https://www.oracle.com/java/technologies/javase-jdk16-downloads.html,jdk-8u291-linux-x64.tar.gz

===========Dockerfile文件
FROM centos
MAINTAINER zhang<15009202810@163.com>

COPY readme.txt /usr/local/readme.txt
ADD jdk-8u291-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.48.tar.gz /usr/local/

RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk1.8.0_291
ENV CLASSPATH $JAVA_HOME/lib/dt.jar;$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.48
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.48
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080

CMD /usr/local/apache-tomcat-9.0.48/bin/startup.sh && tail -F /url/local/apache-tomcat-9.0.48/bin/logs/catalina.out

===========生成镜像
docker build -t zhang/tomcat:01 .

===========生成的镜像
REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
zhang/tomcat          01        39da52a8d285   11 seconds ago   646MB

===========运行
docker run -d -p 9090:8080 --name zhang-tomcat -v /home/tomcat-ceshi/test:/usr/local/apache-tomcat-9.0.48/webapps/test -v /home/tomcat-ceshi/logs:/usr/local/apache-tomcat-9.0.48/logs 39da52a8d285

===========访问测试
http://analysis1.space:9090/

===========发布项目(由于做了卷挂载,直接在本地编写项目即可发布)

===========发布镜像到dockerhub
https://registry.hub.docker.com/       注册账号
docker push 名字/镜像:tag		    	镜像命名时/前面的部分要与dockerhub用户名一致(不行就用tag改)
docker tag 39da52a8d285 zhangkaiyu/tomcat

Using default tag: latest
The push refers to repository [docker.io/zhangkaiyu/tomcat]
54200ad49e1d: Pushing [====>                                              ]  4.937MB/60.65MB
c93fb61e83b5: Pushing [========>                                          ]    2.7MB/15.93MB
e186d35963f1: Retrying in 4 seconds 
e32f38ca1f9e: Pushing   2.56kB
2653d992f4ef: Pushing [=>                                                 ]  4.914MB/209.3MB
7.6,python脚本打包为docker镜像

【入门】Docker练习场

【入门】Docker练习场 详细操作

docker exec -it 容器id pip install -i 镜像加速地址 三方库 		就可以下载文件了

Dockerfile中
ADD ./* / 
才是将当前目录中所有文件加入dockerfile中
不然生成镜像后 docker tun -it 镜像id /bin/bash 运行ls 发现并没有自己所写的文件

官方所给的python3镜像中没有发现数据文件,好像还是需要自己生成?
7.7,dockerfile命令汇总,详解,分类及建议

参看:

Docker实战-编写Dockerfile

docker之Dockerfile实践

必看的dockerfile禁忌与建议!

Dockerfile构建镜像

命令详解
===========================================================================================================
指令:FROM 
功能描述:设置基础镜像,一切由此开始构建
语法:FROM < image>[:< tag> | @< digest>] 
提示:镜像都是从一个基础镜像(操作系统或其他镜像)生成,可以在一个Dockerfile中添加多条FROM指令
注意:如果忽略tag选项,会使用latest镜像
===========================================================================================================
指令:MAINTAINER 
功能描述:设置镜像作者 
语法:MAINTAINER < name>
============================================================================================================
指令:RUN 
功能描述: 
语法:RUN < command> 
          RUN [“executable”,”param1”,”param2”] 
提示:RUN指令会生成容器,在容器中执行脚本,容器使用当前镜像,脚本指令完成后,Docker Daemon会将该容器提交为一个中间镜像,供后面的指令使用 
补充:RUN指令第一种方式为shell方式,使用/bin/sh -c < command>运行脚本,可以在其中使用\将脚本分为多行 
          RUN指令第二种方式为exec方式,镜像中没有/bin/sh或者要使用其他shell时使用该方式,其不会调用shell命令 
例子:RUN source $HOME/.bashrc;\ 
          echo $HOME

          RUN [“/bin/bash”,”-c”,”echo hello”]

          RUN [“sh”,”-c”,”echo”,”$HOME”] 使用第二种方式调用shell读取环境变量
============================================================================================================
指令:CMD 
功能描述:设置容器的启动命令 
语法:CMD [“executable”,”param1”,”param2”] 
          CMD [“param1”,”param2”] 
          CMD < command> 
提示:CMD第一种、第三种方式和RUN类似,第二种方式为ENTRYPOINT参数方式,为entrypoint提供参数列表 
注意:Dockerfile中只能有一条CMD命令,如果写了多条则最后一条生效
============================================================================================================
指令:LABEL 
功能描述:设置镜像的标签 
延伸:镜像标签可以通过docker inspect查看 
格式:LABEL < key>=< value> < key>=< value> … 
提示:不同标签之间通过空格隔开 
注意:每条指令都会生成一个镜像层,Docker中镜像最多只能有127层,如果超出Docker Daemon就会报错,如LABEL ..=.. <假装这里有个换行> LABEL ..=..合在一起用空格分隔就可以减少镜像层数量,同样,可以使用连接符\将脚本分为多行 
          镜像会继承基础镜像中的标签,如果存在同名标签则会覆盖
============================================================================================================
指令:EXPOSE 
功能描述:设置镜像暴露端口,记录容器启动时监听哪些端口 
语法:EXPOSE < port> < port> … 
延伸:镜像暴露端口可以通过docker inspect查看 
提示:容器启动时,Docker Daemon会扫描镜像中暴露的端口,如果加入-P参数,Docker Daemon会把镜像中所有暴露端口导出,并为每个暴露端口分配一个随机的主机端口(暴露端口是容器监听端口,主机端口为外部访问容器的端口) 
注意:EXPOSE只设置暴露端口并不导出端口,只有启动容器时使用-P/-p才导出端口,这个时候才能通过外部访问容器提供的服务
============================================================================================================
指令:ENV 
功能描述:设置镜像中的环境变量 
语法:ENV < key>=< value>…|< key> < value> 
注意:环境变量在整个编译周期都有效,第一种方式可设置多个环境变量,第二种方式只设置一个环境变量 
提示:通过${变量名}或者 $变量名使用变量,使用方式${变量名}时可以用${变量名:-default} ${变量名:+cover}设定默认值或者覆盖值 
          ENV设置的变量值在整个编译过程中总是保持不变的
============================================================================================================
指令:ADD 
功能描述:复制文件到镜像中 
语法:ADD < src>… < dest>|[“< src>”,… “< dest>”] 
注意:当路径中有空格时,需要使用第二种方式 
          当src为文件或目录时,Docker Daemon会从编译目录寻找这些文件或目录,而dest为镜像中的绝对路径或者相对于WORKDIR的路径 
提示:src为目录时,复制目录中所有内容,包括文件系统的元数据,但不包括目录本身 
          src为压缩文件,并且压缩方式为gzip,bzip2或xz时,指令会将其解压为目录 
          如果src为文件,则复制文件和元数据 
          如果dest不存在,指令会自动创建dest和缺失的上级目录
============================================================================================================
指令:COPY 
功能描述:复制文件到镜像中 
语法:COPY < src>… < dest>|[“< src>”,… “< dest>”] 
提示:指令逻辑和ADD十分相似,同样Docker Daemon会从编译目录寻找文件或目录,dest为镜像中的绝对路径或者相对于WORKDIR的路径
============================================================================================================
指令:ENTRYPOINT 
功能描述:设置容器的入口程序 
语法:ENTRYPOINT [“executable”,”param1”,”param2”] 
          ENTRYPOINT command param1 param2(shell方式) 
提示:入口程序是容器启动时执行的程序,docker run中最后的命令将作为参数传递给入口程序 
          入口程序有两种格式:exec、shell,其中shell使用/bin/sh -c运行入口程序,此时入口程序不能接收信号量 
          当Dockerfile有多条ENTRYPOINT时只有最后的ENTRYPOINT指令生效 
          如果使用脚本作为入口程序,需要保证脚本的最后一个程序能够接收信号量,可以在脚本最后使用exec或gosu启动传入脚本的命令 
注意:通过shell方式启动入口程序时,会忽略CMD指令和docker run中的参数 
          为了保证容器能够接受docker stop发送的信号量,需要通过exec启动程序;如果没有加入exec命令,则在启动容器时容器会出现两个进程,并且使用docker stop命令容器无法正常退出(无法接受SIGTERM信号),超时后docker stop发送SIGKILL,强制停止容器 
例子:FROM ubuntu <换行> ENTRYPOINT exec top -b
============================================================================================================
指令:VOLUME 
功能描述:设置容器的挂载点 
语法:VOLUME [“/data”] 
          VOLUME /data1 /data2 
提示:启动容器时,Docker Daemon会新建挂载点,并用镜像中的数据初始化挂载点,可以将主机目录或数据卷容器挂载到这些挂载点
============================================================================================================
指令:USER 
功能描述:设置RUN CMD ENTRYPOINT的用户名或UID 
语法:USER < name>
============================================================================================================
指令:WORKDIR 
功能描述:设置RUN CMD ENTRYPOINT ADD COPY指令的工作目录 
语法:WORKDIR < Path> 
提示:如果工作目录不存在,则Docker Daemon会自动创建 
          Dockerfile中多个地方都可以调用WORKDIR,如果后面跟的是相对位置,则会跟在上条WORKDIR指定路径后(如WORKDIR /A   WORKDIR B   WORKDIR C,最终路径为/A/B/C)
============================================================================================================
指令:ARG 
功能描述:设置编译变量 
语法:ARG < name>[=< defaultValue>] 
注意:ARG从定义它的地方开始生效而不是调用的地方,在ARG之前调用编译变量总为空,在编译镜像时,可以通过docker build –build-arg < var>=< value>设置变量,如果var没有通过ARG定义则Daemon会报错 
          可以使用ENV或ARG设置RUN使用的变量,如果同名则ENV定义的值会覆盖ARG定义的值,与ENV不同,ARG的变量值在编译过程中是可变的,会对比使用编译缓存造成影响(ARG值不同则编译过程也不同) 
例子:ARG CONT_IMAG_VER <换行> RUN echo $CONT_IMG_VER 
          ARG CONT_IMAG_VER <换行> RUN echo hello 
          当编译时给ARG变量赋值hello,则两个Dockerfile可以使用相同的中间镜像,如果不为hello,则不能使用同一个中间镜像
============================================================================================================
指令:ONBUILD 
功能描述:设置自径想的编译钩子指令 
语法:ONBUILD [INSTRUCTION] 
提示:从该镜像生成子镜像,在子镜像的编译过程中,首先会执行父镜像中的ONBUILD指令,所有编译指令都可以成为钩子指令

ONBUILD流程
1,编译时,读取所有ONBUILD镜像并记录下来,在当前编译过程中不执行指令
2,生成镜像时将所有ONBUILD指令记录在镜像的配置文件OnBuild关键字中
3,子镜像在执行FROM指令时会读取基础镜像中的ONBUILD指令并顺序执行,如果执行过程中失败则编译中断;当所有ONBUILD执行成功后开始执行子镜像中的指令
4,子镜像不会继承基础镜像中的ONBUILD指令
============================================================================================================
指令:STOPSIGNAL 
功能描述:设置容器退出时,Docker Daemon向容器发送的信号量 
语法:STOPSIGNAL signal 
提示:信号量可以是数字或者信号量的名字,如9或者SIGKILL,信号量的数字说明在Linux系统管理(https://blog.csdn.net/qq_29999343/article/details/78166574)中有简单介绍

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tensor_zhang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值