Docker镜像原理
镜像分层.png-
base 镜像
base镜像又2层含义:- 不依赖其他镜像,从stratch构建
- 其他镜像可以已之为基础进行扩展
base镜像一般是各种linux发行版,比如Ubuntu,centos。
-
镜像的分层结构
为什么要采用分层的结构,其中之一的好处就是:共享资源。
有多个镜像都从相同的base镜像构建而来,那么Docker host只需要在磁盘上保存一份base镜像,同时在内存种也只需要加载一份base镜像,就可以为所有的镜像服务。而且,镜像的每一层都可以被共享。那么,这时也许会问另一个问题了:如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,那么会影响到其他的容器吗?
答案是不会,因为容器利用了copy-on-write技术。当容器启动时,一个新的可写层会被加载到镜像的顶部。这一层叫做"容器层","容器层"之下都称作镜像层。所有对容器的改动都只会发生在容器层,只有容器层是可写的,容器层下面都是可读的。
相关命令
-
列出镜像
# docker images # 列出镜像 REPOSITORY TAG IMAGE ID CREATED SIZE docker.io/python 3.7 db1c801f1c06 3 months ago 926 MB docker.io/mysql latest 102816b1ee7d 3 months ago 486 MB docker.io/ubuntu latest ea4c82dcd15a 5 months ago 85.8 MB
本地镜像都保存在 Docker 宿主机的
/var/lib/docker
目录下。镜像从仓库中下载下来,镜像保存在仓库中,而仓库存在于 Registry 中,默认的 Registry 是由 Dokcer 公司来运营的公共 Registry 服务,即 Docker Hub。
Docker Hub 中有2种类型的仓库,用户仓库和顶层仓库,用户仓库的镜像都是由Docker用户创建的,而顶层仓库是由Docker内部的人来管理。
用户仓库名的命名由用户名和仓库名两部分组成的。如 jamtur01/puppet。
每个镜像仓库都可以存放很多镜像。为了区分同一仓库的不同镜像,Docker提供了标签的功能,通过在仓库名后面加上一个冒号和标签名来指定该仓库中的某一镜像。如果没有指定标签,那么Docker会自动下载
latest
标签的镜像。# docker run -ti --name new_container ubuntu:12.04 /bin/bash # 使用ubuntu:12.04镜像
-
拉取镜像
# docker pull ubuntu:12.04
通过pull命令先将镜像拉取到本地,可以节省用一个新镜像启动一个容器的所需的时间(用Docker run命令从镜像启动一个容器时,如果该镜像不在本地,Docker会先从Docker Hub下载该镜像)
-
查找镜像
# docker search ubuntu INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED docker.io docker.io/ubuntu Ubuntu is a Debian-based Linux operating s... 9369 [OK] ....
可以利用该命令来查找所有Docker Hub上公共的可用镜像。
-
删除镜像
# docker rmi ubuntu:12.04
-
导出镜像
docker save -o ubuntu_img.tar ubuntu
-
导入镜像
docker load -i ubuntu_img.tar
构建镜像
前面是拉取已经构建好的带有定制内容的 Docker 镜像,那么如何修改和管理自己的镜像,并且更新和管理这些镜像呢?有以下2种方法:
- 使用
docker commit
命令 - 使用
docker build
命令 和 Dockerfile文件
-
用Docker的commit命令创建镜像
- 运行容器
- 修改容器
- 将容器保存为新的镜像
# docker run -i -t ubuntu /bin/bash # 创建一个容器 # apt-get -yqq update && apt-get -y install apache2 # 安装apache2软件包(容器内的shell) # docker commit jack/apche2:webserver # 提交定制容器
-
用Dockerfile构建镜像
并不推荐使用docker commit的方法来构建镜像,相反,推荐使用Dcokerfile的定义文件和docker build
命令来构建镜像。FROM ubuntu RUN apt-get update && apt-get install -y vim
Dockerfile 由一系列的指令和参数组成。每条指令,如
FROM
,都必须为大写字母。Dockerfile 中的指令会按顺序从上到下执行,所以应该更具需要合理安排指令的顺序。
每条指令都会创建一个新的镜像层并对镜像进行提交。Docker 大体上按照如下流程执行
Dockerfile
中的指令:- Docker 从基础镜像运行一个容器
- 执行一条指令,对容器做出修改
- 执行类似
docker commit
操作,提交一个新的镜像层 - Docker 再基于刚提交的镜像运行一个新的容器
- 执行Dockerfile中的下一条指令,直到所有指令都执行完毕
- 构建镜像
# docker build -t ubuntu-with-vim . Sending build context to Docker daemon 2.048kB 1 Step 1/2 : FROM ubuntu ---> ccc6e87d482b 2 Step 2/2 : RUN apt-get update && apt-get install -y vim 2a ---> Running in 31978802f893 ... 2b Setting up vim (2:8.0.1453-1ubuntu1.1) ... ... ---> aa94ecc262e6 2c Removing intermediate container 31978802f893 Successfully built aa94ecc262e6 Successfully tagged ubuntu-with-vim:lates
- 执行FROM,将ubuntu作为base镜像,ubuntu镜像ID为ccc6e87d482b
- 执行RUN,安装vim
2a. 启动ID为31978802f893的临时容器,在容器种安装vim
2b. 安装成功后,将容器保存为镜像,其ID为aa94ecc262e6
2c. 删除临时容器31978802f893,镜像aa94ecc262e6构建成功
1.jpg
可以用docker history
查看镜像的分层构建历史。
````
docker build --no-cache -t="Jack/static_web:v1"
````
`-t`标志为新镜像设置了仓库和名称。
Dockerfile 中的常用命令
-
FROM
Dockerfile文件的第一条指令必须是FROM,其后可以是各种镜像的操作指令,最后是CMD或ENTRYPOINT指定容器启动时执行的命令。 -
MAINTAINER
-
CMD 和 ENTRYPOINT
CMD指令和ENTRYPOINT指令的作用都是为镜像指定容器启动后的命令。-
CMD
支持三种格式:-
CMD ["executable", "param1", "param2"]
使用 exec 执行,推荐方式。 -
CMD command param1 param2
在 /bin/sh 中执行,提供给需要交互的应用。 -
CMD ["param1", "param2"]
提供给 ENTRYPOINT 的默认参数。
启动容器时执行的命令,每个 Dockerfile 只能有一条 CMD 命令,如果指定了多条命令,只有最后一条会被执行。
如果用户启动容器时候指定了运行的命令,则会覆盖掉 CMD 指定的命令。 -
-
ENTRYPOINT
支持两种格式:ENTRYPOINT ["executable", "param1", "param2"]
-
ENTRYPOINT command param1 param2
(shell中执行)
配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖,而是将docker run指定的参数当做ENTRYPOINT指定命令的参数。
每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效。 -
测试1
- test.sh
#!/bin/bash echo "args: ${@}"
- Dockerfile
FROM ubuntu MAINTAINER 123@123.com ADD test.sh / RUN chmod +x /test.sh CMD ["/test.sh"]
- 测试结果
可见docker run命令启动容器时指定的运行命令可以覆盖Dockerfile文件中CMD指令指定的命令。# docker build -t=test1:latest . # docker run --rm -ti test1 args: # docker run --rm -ti test1 /bin/bash -c "echo hello world" hello world
- test.sh
-
测试2
- Dockerfile
FROM ubuntu MAINTAINER 123@123.com ADD test.sh / RUN chmod +x /test.sh ENTRYPOINT ["/test.sh"]
- 测试结果
docker run命令指定的容器运行命令不能覆盖Dockerfile文件中ENTRYPOINT指令指定的命令,反而被当做参数传递给ENTRYPOINT指令指定的命令。# docker build -t=test2:latest . # docker run --rm -ti test2 args: # docker run --rm -ti test2 /bin/bash -c "echo hello world" args: /bin/bash -c echo hello world
- Dockerfile
-
测试3
- Dockerfile
FROM ubuntu MAINTAINER 123@123.com ADD test.sh / RUN chmod +x /test.sh ENTRYPOINT ["/test.sh", "arg1"] CMD ["arg2"]
- 测试结果
上面第一个容器的运行结果可以看出CMD指令为ENTRYPOINT指令设置了默认参数;从第二个容器的运行结果看出,docker run命令指定的参数覆盖了CMD指令指定的参数。# docker build -t=test3:latest . # docker run --rm -ti test3 args: arg1 arg2 # docker run --rm -ti test3 arg3 args: arg1 arg3
- Dockerfile
-
注意:
CMD指令为ENTRYPOINT指令提供默认参数是基于镜像层次结构生效的,而不是基于是否在同个Dockerfile文件中。意思就是说,如果Dockerfile指定基础镜像中是ENTRYPOINT指定的启动命令,则该Dockerfile中的CMD依然是为基础镜像中的ENTRYPOINT设置默认参数。
-
-
COPY 和 ADD
-
EXPOSE
-
VOLUME
-
ENV
-
LABEL
分发镜像
利用Dockerfile制作镜像
- centos
FROM centos
RUN yum update -y
RUN yum install -y vim tcpdump iproute iproute-doc nc
- 构建镜像
docker build --no-cache -t="centos_net" ./
网友评论