一.Docker镜像的简单概述

Docker镜像是一个只读的Docker容器模板,含有启动Docker容器所需的文件系统结构及其内容,因此是启动一个Docker容器的基础。

Docker镜像的文件内容以及一些运行Docker容器的配置文件组成了Docker容器的静态文件系统运行环境–rootfs。可以这么理解,Docker镜像是Docker容器的静态视角,Docker容器是Docker镜像的运行状态

二.镜像的分层结构

特点

1.共享宿主机的内核
2.base镜像提供的是最小的linux发行版
其实就是linux的根/文件系统
3.同一docker主机支持运行多种linux发行版
4.采用分层结构的做大好处是“共享资源”
不同的镜像使用同一个镜像层的时候,文件系统便可以实现资源共享,只需要备份一次,节省空间。

查看分层结构的命令

docker load -i 镜像名 #拉取镜像

[root@toto6 images]# docker load -i ubuntu.tar # 拉取本地第一个镜像
56abdd66ba31: Loading layer 196.8MB/196.8MB
9468150a390c: Loading layer 208.9kB/208.9kB
11083b444c90: Loading layer 4.608kB/4.608kB
5f70bf18a086: Loading layer 1.024kB/1.024kB
Loaded image: ubuntu:latest
[root@toto6 images]# docker load -i rhel7.tar # 拉取本地的第二个镜像
e1f5733f050b: Loading layer 147.1MB/147.1MB
[root@toto6 images]# docker load -i busybox.tar # 拉取本地的第三个镜像
8a788232037e: Loading layer 1.37MB/1.37MB
Loaded image: busybox:latest
[root@toto6 images]#
1
2
3
4
5
6
7
8
9
10
11
12
docker images #查看所有已经拉取的镜像

[root@toto6 images]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox latest 59788edf1f3e 9 months ago 1.15MB
game2048 latest 19299002fdbe 2 years ago 55.5MB
ubuntu latest 07c86167cdc4 3 years ago 188MB
rhel7 latest 0a3eb3fde7fd 5 years ago 140MB
1
2
3
4
5
6
dcoker history 镜像名称 # 查看特定进行的构造,一层一层

[root@toto6 images]# docker history ubuntu:latest
IMAGE CREATED CREATED BY SIZE COMMENT
07c86167cdc4 3 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
3 years ago /bin/sh -c sed -i 's/^#\s*(deb.*universe)$… 1.9kB
3 years ago /bin/sh -c echo ‘#!/bin/sh’ > /usr/sbin/poli… 195kB
3 years ago /bin/sh -c #(nop) ADD file:b9504126dc5590898… 188MB
1
2
3
4
5
6
使用镜像开启并运行一个容器

镜像作为开启容器的模板。使用镜像创建并且运行一个容器,就是在镜像层的最上层添加一层容器层。所有的镜像层都是只读的容器层是可写的,容器开启之后,所有的修改该作都保存在可写的容器层。

容器以下所有镜像曾都是只读的,docker查找文件时是从上往下依次查找;容器层用来保存镜像变化的部分,并不会对镜像本身进行任何修改;一个镜像最多可以有127层

docker容器进行可写时,是在可写容器层进行可写动作,经底层镜像层的文件会先复制到可写层再执行删除、创建等动作

使用镜像创建并运行一个容器:

[root@toto6 images]# docker run -it --name vm1 ubuntu
#-it 交互式 --name 容器名称
root@927ae4d1dca7:/# uname -r # 查看容器的内核版本
3.10.0-514.el7.x86_64 # 显示
root@927ae4d1dca7:/# touch /mnt/file{1…5} # 在容器中创建文件。写入内容
root@927ae4d1dca7:/# ls /mnt/
file1 file2 file3 file4 file5 #成功创建5个文件
1
2
3
4
5
6
7
退出该容器查看系统的内核版本

[root@toto6 images]# uname -r
3.10.0-514.el7.x86_64 # 容器使用的是该宿主机的内核
1
2
清除非活跃的容器:
docker container prune

[root@toto6 images]# docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
927ae4d1dca7b75ef588328803b20c2eab9ca2d22102a57fba51621a1b53503c

Total reclaimed space: 40B
1
2
3
4
5
6
7
再次使用上次使用镜像创建并运行一个容器

[root@toto6 images]# docker run -it --name vm2 ubuntu
root@5c69f6454acb:/# ls /mnt/
root@5c69f6454acb:/#

这里并没有上次创建的文件,是因为上次的操作全部写在容器层,镜像层的内容只读。

当上次的容器释放之后,写在容器层的内容也会随之消失。
1
2
3
4
5
将创建的容器重新打包为一个镜像

在容器中进行创建文件:

root@5c69f6454acb:/# touch /mnt/file{1…5}
root@5c69f6454acb:/# ls /mnt/
file1 file2 file3 file4 file5
root@5c69f6454acb:/# exit
1
2
3
4
将该容器重新打包成一个镜像:

[root@toto6 images]# docker ps -a # 查看容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5c69f6454acb ubuntu “/bin/bash” 5 minutes ago Exited (0) 23 seconds ago vm2
[root@toto6 images]# docker commit vm2 ubuntu:v2 # 将该才的容器打包成一个新的镜像
sha256:ceff04ff5225ffcda3f5f1ce7c08d25d13c67bf6c4bcccec1c57b90994b8b2de
[root@toto6 images]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu v2 ceff04ff5225 11 seconds ago 188MB # 新生成的镜像
busybox latest 59788edf1f3e 9 months ago 1.15MB
game2048 latest 19299002fdbe 2 years ago 55.5MB
ubuntu latest 07c86167cdc4 3 years ago 188MB
rhel7 latest 0a3eb3fde7fd 5 years ago 140MB
1
2
3
4
5
6
7
8
9
10
11
12
使用容器创建镜像。容器就是在镜像层的最上方存在一个可写的容器层。将容器打包镜像,就是将该可写的容器层,变成一个只读的镜像层,和下层的所有镜像层一起作为新镜像的镜像层。

以上例子中镜像ubuntu:v2 是在ubuntu镜像打开容器的基础上生成的。查看他们的镜像分层。

[root@toto6 images]# docker history ubuntu:v2
IMAGE CREATED CREATED BY SIZE COMMENT
ceff04ff5225 7 minutes ago /bin/bash 41B
07c86167cdc4 3 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
3 years ago /bin/sh -c sed -i 's/^#\s*(deb.*universe)$… 1.9kB
3 years ago /bin/sh -c echo ‘#!/bin/sh’ > /usr/sbin/poli… 195kB
3 years ago /bin/sh -c #(nop) ADD file:b9504126dc5590898… 188MB

[root@toto6 images]# docker history ubuntu
IMAGE CREATED CREATED BY SIZE COMMENT
07c86167cdc4 3 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
3 years ago /bin/sh -c sed -i 's/^#\s*(deb.*universe)$… 1.9kB
3 years ago /bin/sh -c echo ‘#!/bin/sh’ > /usr/sbin/poli… 195kB
3 years ago /bin/sh -c #(nop) ADD file:b9504126dc5590898… 188MB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
ubuntu:v2 是在ubuntu镜像基础上多添加了一层。

删除容器:

[root@toto6 images]# docker rm vm2
vm2
1
2
删除镜像:

[root@toto6 images]# docker image rm ubuntu:v2
Untagged: ubuntu:v2
Deleted: sha256:ceff04ff5225ffcda3f5f1ce7c08d25d13c67bf6c4bcccec1c57b90994b8b2de
Deleted: sha256:16686d7c5eec38ab61dde622a52e0598e8406b5cc220c6a089756dd8f076f6ab

构建镜像的两种方式

docker commit :将运行的容器保存成镜像
Dockerfile:自动构建

docker commit

使用docker commit 创建镜像分为三步:

运行容器
修改容器
将容器保存为镜像
特点:
效率低、可重复性弱、容易出错
使用者无法对镜像进行审计(看不到镜像中的操作),会存在安全隐患

以镜像busybox为例进行说明:

运行容器:
[root@toto6 images]# docker run -it --name test busybox
/ # ls
bin dev etc home proc root sys tmp usr var
1
2
3
修改容器:
/ # echo “hello toto” > testfile
/ # ls
bin etc proc sys tmp var
dev home root testfile usr
1
2
3
4
将容器保存为新的镜像:
[root@toto6 images]# docker commit test busybox:v2
sha256:0cdf20286e297b35345970340031e9ec0ad49128f790e82ec348f22470c8cd0e
1
2
查看新生成的镜像:无法看新镜像层的操作
IMAGE CREATED CREATED BY SIZE COMMENT
0cdf20286e29 About a minute ago sh 46B
59788edf1f3e 9 months ago /bin/sh -c #(nop) CMD [“sh”] 0B
9 months ago /bin/sh -c #(nop) ADD file:63eebd629a5f7558c… 1.15MB
1
2
3
4
直接运行新生成的镜像容器:

[root@toto6 images]# docker run -it --name test busybox:v2
/ # ls
bin etc proc sys tmp var
dev home root testfile usr # 里面保存了之前操作的数据。
1
2
3
4
Dockerfile 创建镜像

根据Dockerfile中的内容,通过使用docker bulid指令,自动创建镜像,也是基于docker commit的层层构建得出。

Dockerfile文件名称,是docker默认的,在u不特殊指定的情况下,一般都是从该文件中读取创建信息。并且在创建的过程中,docker会将该文件所在目录中的所有内容发送给docker引擎。所以建创建一个空来目录来存放Dockerfile文件。

使用Dockerfile创建镜像

查看已经存在的镜像

[root@toto6 images]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox latest 59788edf1f3e 9 months ago 1.15MB
game2048 latest 19299002fdbe 2 years ago 55.5MB
ubuntu latest 07c86167cdc4 3 years ago 188MB
rhel7 latest 0a3eb3fde7fd 5 years ago 140MB
1
2
3
4
5
6
创建空目录以及Dockerfile文件

[root@toto6 images]# mkdir /docker
[root@toto6 images]# cd /docker/
[root@toto6 docker]# vim Dockerfile
FROM busybox # 以已经存在的busybox进行为base镜像
RUN echo ‘hello world’ # 新加的操作,每一个RUN产生一个新的镜像层
RUN echo ‘westos linux’
1
2
3
4
5
6
创建新的镜像:. 表示Dockerfile所在的路径

[root@toto6 docker]# docker build -t busybox:v2 .
Sending build context to Docker daemon 2.048kB # 将目录中的所有内容发送给docker引擎
Step 1/3 : FROM busybox #第一层
—> 59788edf1f3e
Step 2/3 : RUN echo ‘hello world’ # 第二层
—> Running in 9e201f6f8641
hello world
Removing intermediate container 9e201f6f8641
—> 4dc2056e315e
Step 3/3 : RUN echo ‘westos linux’ # 第三层
—> Running in d957a3a99acf
westos linux
Removing intermediate container d957a3a99acf
—> 8fed8fc9f3f2
Successfully built 8fed8fc9f3f2
Successfully tagged busybox:v2 # 创建成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
成功之后再次查看镜像,已经成功生成镜像

[root@toto6 docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox v2 8fed8fc9f3f2 59 seconds ago 1.15MB
busybox latest 59788edf1f3e 9 months ago 1.15MB
game2048 latest 19299002fdbe 2 years ago 55.5MB
ubuntu latest 07c86167cdc4 3 years ago 188MB
rhel7 latest 0a3eb3fde7fd 5 years ago 140MB
1
2
3
4
5
6
7
查看新生成的镜像分层结构:
能清楚的看到每一层镜像进行的操作,使用者可以对镜像进行审计

[root@toto6 docker]# docker history busybox:v2
IMAGE CREATED CREATED BY SIZE COMMENT
8fed8fc9f3f2 9 minutes ago /bin/sh -c echo ‘westos linux’ 0B
4dc2056e315e 9 minutes ago /bin/sh -c echo ‘hello world’ 0B
59788edf1f3e 9 months ago /bin/sh -c #(nop) CMD [“sh”] 0B
9 months ago /bin/sh -c #(nop) ADD file:63eebd629a5f7558c… 1.15MB
1
2
3
4
5
6
当不修改刚才的Dockerfile的基础上再次添加内容创建镜像的时候

[root@toto6 docker]# vim Dockerfile
FROM busybox
RUN echo ‘hello world’
RUN echo ‘westos linux’
RUN echo toto > totofile # 添加一条新的语句
1
2
3
4
5
再上一次的基础上构建新的镜像

[root@toto6 docker]# docker build -t busybox:v3 .
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM busybox
—> 59788edf1f3e
Step 2/4 : RUN echo ‘hello world’
—> Using cache # 和上一次一致,使用存在的cache
—> 4dc2056e315e
Step 3/4 : RUN echo ‘westos linux’
—> Using cache # 和上一次一致,使用存在的cache
—> 8fed8fc9f3f2
Step 4/4 : RUN echo toto > totofile
—> Running in d611a8f1892c # 打开一个新的容器运行新加的操作
Removing intermediate container d611a8f1892c # 运行完成之后释放自己新建的容器
—> 41b1abbffebf #提交新建的镜像层
Successfully built 41b1abbffebf
Successfully tagged busybox:v3 # 镜像创建成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
查看新生成的镜像分层结构:
在Dockerfile文件中,每一个RUN语句都会生成一个新的镜像层。

[root@toto6 docker]# docker history busybox:v3
IMAGE CREATED CREATED BY SIZE COMMENT
41b1abbffebf 4 minutes ago /bin/sh -c echo toto > totofile 5B
8fed8fc9f3f2 31 minutes ago /bin/sh -c echo ‘westos linux’ 0B
4dc2056e315e 31 minutes ago /bin/sh -c echo ‘hello world’ 0B
59788edf1f3e 9 months ago /bin/sh -c #(nop) CMD [“sh”] 0B
9 months ago /bin/sh -c #(nop) ADD file:63eebd629a5f7558c… 1.15MB
1
2
3
4
5
6
7
Dockerfile的详细介绍

dickerfile 常用指令:

1 、FROM:
用于指定base镜像,本地不存在会从远程仓库进行下载

2、MAINTAINER
MAINTAINER:设置镜像的作者,如用户邮箱等(不是必须的)

3、COPY
把文件从build context复制到镜像
支持两种形式:COPY src dest和COPY [" src" ,"dest "]
src必须指定build context中的文件或目录
dest为容器中的路径

[root@toto6 docker]# vim Dockerfile
FROM busybox
CPOY Dockerfile /mnt
[root@toto6 docker]# docker run -it --name vm1 test:v1
/ # ls
bin dev etc home mnt proc root sys tmp usr var
1
2
3
4
5
6
4 、ADD

用法与COPY类似,不同的是src可以是归档压缩文件,文件会被自动解压到dest,也可自动下载URL并拷贝到镜像
DD html.tar /var/www##解压
ADD http://ip/html.tar /var/www ##下载

[root@toto6 docker]# ls
backup.tar.gz Dockerfile
[root@toto6 docker]# vim Dockerfile
FROM rhel7
Add backup.tar.gz /mnt
[root@toto6 docker]# docker build -t test:v3 .
Sending build context to Docker daemon 3.072kB
Step 1/2 : FROM rhel7
—> 0a3eb3fde7fd
Step 2/2 : Add backup.tar.gz /mnt
—> d8b34bccc29a
Successfully built d8b34bccc29a
Successfully tagged test:v3
[root@toto6 docker]# docker run -it --name vm3 test:v3
docker: Error response from daemon: No command specified.
See ‘docker run --help’.
[root@toto6 docker]# docker run -it --name vm3 test:v3 bash
bash-4.2# ls /mnt
usr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
5 EXPOSE
如果容器中运行应用服务,则可以包服务端口暴露出去

[root@toto6 docker]# vim Dockerfile
FROM rhel7
Add backup.tar.gz /mnt
EXPOSE 80

[root@toto6 docker]# docker history test:v4
IMAGE CREATED CREATED BY SIZE COMMENT
125f2a6e4982 10 seconds ago /bin/sh -c #(nop) EXPOSE 80 0B
d8b34bccc29a 4 minutes ago /bin/sh -c #(nop) ADD file:a6708d65f40d03475… 0B
0a3eb3fde7fd 5 years ago 140MB Imported from -
1
2
3
4
5
6
7
8
9
10
6 、VOLUME
声明数据卷,通常指定应用数据挂载点
VOLUME [ “/var/www/html”] :该路径为容器中的路径。如果路径不存在,启动容器的时候会自动创建

一般VOLUME指定挂载点,没有此路径就会新建路径。
在运行docker宿主机上,可以根据命令docker inspect 容器名的具体信息,可以查看封装容器,声明的数据卷,Source会存在此容器目录挂接到本地_data目录。
由于自动挂载的路径很长,不太方便记,也可以在运行的时候指定挂载路径
[root@toto6 docker]# vim Dockerfile
FROM rhel7
EXPOSE 80
VOLUME ["/data"] # 声明数据卷
[root@toto6 docker]# docker build -t test:v1 .
[root@toto6 docker]# docker run -it --name vm2 test:v1 bash
bash-4.2# ls
bin data etc lib mediaopt root sbin sys usr
boot dev home lib64 mntproc run srv tmp var # 容器中生成了data目录

#使用ctrl + pq 保证容器正常运行退出交互式界面。

[root@toto6 docker]# docker inspect vm2 # 查看运行容器的信息
“Mounts”: [
{
“Type”: “volume”,
“Name”: “280eb155e5ef61cfaf300b8d597f057005cc66fb9af39361b9f1b4e53d5ca2a0”,
“Source”: “/var/lib/docker/volumes/280eb155e5ef61cfaf300b8d597f057005cc66fb9af39361b9f1b4e53d5ca2a0/_data”,

Source为容器中声明的数据卷在宿主机上的挂载路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
在宿主机上在该挂载目录中创建文件,可以在容器中相应的目录中看到:

[root@toto6 docker]# cd /var/lib/docker/volumes/280eb155e5ef61cfaf300b8d597f057005cc66fb9af39361b9f1b4e53d5ca2a0/_data
[root@toto6 _data]# ls
[root@toto6 _data]# touch file1
[root@toto6 _data]# ls
file1
#再次连接容器:
[root@toto6 _data]# docker attach vm2
bash-4.2# ls /data
file1
1
2
3
4
5
6
7
8
9
上面声明数据卷,并没有指定在宿主机上的挂载点。该挂载点由docker自动分配。还可以自己指定数据卷的挂载。

docker run -it --name vm3 -v /opt/data:/data test:v1 ##:前为物理机挂载目录,:后为docker挂载目录
1
7 、WORKDIR
为RUN、CMD、ENTRYPOINT、ADD和COPY指令设置镜像中的当前工作目录,如果目录不存在也会自动创建

8 、RUN
RUN 在容器中运行命令并创建新的镜像层,常用于安装软件包:每个run 都会多一层

9 、ENV:
设置环境变量,变量可以被后续的指令使用

10 、CMD 与 ENTRYPOINT

设置容器启动后执行的命令,但是CMD会被docker run 后面的命令覆盖,但ENTRYPOINT不会
Dockerfile中只能指定一个ENTRYPOINT,如果指定过多则只有最后一个有效
docke run后面的参数可以传递给ENTRYPOINT指令当作参数;

shell模式:

[root@toto6 docker]# vim Dockerfile
FROM busybox
ENV name toto # 定义变量
ENTRYPOINT echo “hello,$name” # 设置输出(shell命令行)

[root@toto6 docker]# docker build -t test:v2 . # 创建镜像

[root@toto6 docker]# docker run --rm test:v2 # 运行容器
hello,toto # 直接输出,同时对变量进行解析
1
2
3
4
5
6
7
8
9
exec模式

[root@toto6 docker]# vim Dockerfile
FROM busybox
ENV name toto
ENTRYPOINT ["/bin/echo",“hello,$name”]

[root@toto6 docker]# docker build -t test:v3 . # 创建镜像

[root@toto6 docker]# docker run --rm test:v3 # 运行容器
hello,$name # 输出并没有进行变量解析
1
2
3
4
5
6
7
8
9
原因:

这是由于shell格式底层会调用/bin/sh -C执行命令,可以解析变量。但是exec模式不会,

[root@toto6 docker]# docker history test:v2
IMAGE CREATED CREATED BY SIZE COMMENT
b7801a7de9d6 7 minutes ago /bin/sh -c #(nop) ENTRYPOINT ["/bin/sh" “-c… 0B
c3ee45017cfb 7 minutes ago /bin/sh -c #(nop) ENV name=toto 0B
59788edf1f3e 9 months ago /bin/sh -c #(nop) CMD [“sh”] 0B
9 months ago /bin/sh -c #(nop) ADD file:63eebd629a5f7558c… 1.15MB
[root@toto6 docker]# docker history test:v3
IMAGE CREATED CREATED BY SIZE COMMENT
57b3bcebd5b4 2 minutes ago /bin/sh -c #(nop) ENTRYPOINT [”/bin/echo" "… 0B
c3ee45017cfb 7 minutes ago /bin/sh -c #(nop) ENV name=toto 0B
59788edf1f3e 9 months ago /bin/sh -c #(nop) CMD [“sh”] 0B
9 months ago /bin/sh -c #(nop) ADD file:63eebd629a5f7558c… 1.15MB
1
2
3
4
5
6
7
8
9
10
11
12
处理办法:

所以只要指定/bin/sh -C指令解析命令。如下:

[root@toto6 docker]# vim Dockerfile
FROM busybox
ENV name toto
ENTRYPOINT ["/bin/sh","-c",“echo hello,$name”]

[root@toto6 docker]# docker build -t test:v4 .

[root@toto6 docker]# docker run --rm test:v4
hello,toto
1
2
3
4
5
6
7
8
9
Exec格式时,ENTRYPOINT可以通过CMD提供额外参数,CMD的额外参数可以在容器启动时动态替换,在shell格式时ENTRYPOINT会忽略任何CMD和docker run 提供的参数

[root@toto6 docker]# docker run --rm test:v2 lala # shell 模式
hello,toto
[root@toto6 docker]# docker run --rm test:v3 lala # exec模式
hello,$name lala
1
2
3
4
CMD命令在前,会被docker run后存在参数会被覆盖

[root@toto6 docker]# vim Dockerfile
FROM busybox
ENTRYPOINT ["/bin/echo",“hello”]
CMD [“WORLD”]

[root@toto6 docker]# docker build -t test:v5 . # 创建镜像

[root@toto6 docker]# docker run --rm test:v5 # 运行容器
hello WORLD

[root@toto6 docker]# docker run --rm test:v5 toto # 运行容器 后面加参数
hello toto # 显示CMD 指令被后面的参数覆盖

07-18 05:08