如果你读完前面几章,应该掌握了docker的基本概念和用法,但是心里头肯定有个疑惑:docker的镜像是如何而来,此篇即将告诉你答案。

Docker镜像是容器的基础。 Image镜像是根文件系统更改的有序集合,以及在容器运行时内使用的相应执行参数。 镜像通常包含堆叠在彼此顶部的分层文件系统的并集。 它没有状态,且永远不会改变。

镜像相当于你容器的最基础的模板,镜像制作的好坏,优化的质量会决定你容器运行的性能及稳定性,所以对你的容器服务很重要。但大家也不用担心,基本上常用的软件、服务、应用都在Docker Hub上有官方镜像,但是为了满足你的自定义需求,最好学会自制镜像。

镜像的管理

1. 拉取镜像

1
2
3
4
[root@centos ~]# docker pull centos:latest
latest: Pulling from library/centos
Digest: sha256:a799dd8a2ded4a83484bbae769d97655392b3f86533ceb7dd96bbac929809f3c
Status: Downloaded newer image for centos:latest

命令同:docker image pull

冒号前为镜像名,后面为版本号,不写或latest都代表拉取最新版本。

2. 查看镜像

1
2
3
[root@centos-vm7 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest 9f38484d220f 4 months ago 202MB

命令同:docker image ls

3. 删除镜像

1
[root@centos-vm7 ~]# docker rmi centos:latest

命令同:docker image rm

后面接镜像名或ID均可。

4. 推送镜像

1
[root@centos ~]# docker push your_registry/centos:latest

命令同:docker image push

若推送的仓库需要登录验证,需要先docker login

1
docker login registry_name

5. 清理容器未使用的镜像

1
[root@centos ~]# docker image prune

6. 导出镜像

1
docker save -o image.tar centos:latest

命令同:docker image save

-o表示导出为image.tar文件

7. 导入镜像文件

1
docker load < image.tar

1
docker import image.tar image_name:version

命令同:docker image load

8. 构建镜像

1
docker build -t tengine:latest .

-t表示镜像名(标签),后面的’点’表示当前目录,此目录必须要有名称为Dockerfile

命令同:docker image build

9. 查找镜像

1
docker search nginx

10. 通过容器提交生成镜像

1
docker commit -m="update to v2" -a="yourname" e218edb10161 ubuntu:v2
  • -m:提交的描述信息

  • -a:指定镜像作者

  • e218edb10161:容器ID

  • ubuntu:v2:指定要创建的目标镜像名

11. 给镜像添加标签(相当于添加别名)

1
docker tag ubuntu:v2 centos:dev

centos:dev为新的标签名

镜像的构建

Docker提供了通过配置Dockerfile文件来构建镜像的方法,详见官网

使用Dockerfile去构建镜像好比堆积木,Docker会读取Dockerfile内容,通过分层的概念一层一层的堆积形成最终的镜像。下面介绍Dockerfile中主要的命令。

功能 Dockerfile命令
基础镜像信息 FROM
维护者信息 MAINTAINER
镜像操作指令 RUN、COPY、ADD、EXPOSE、WORKDIR、ONBUILD、USER、VOLUME、ENV、LABEL、STOPSIGNAL
容器启动指令 CMD、ENTRYPOINT

FROM

指定新镜像的基础镜像,如:

1
FROM ubuntu:14.04

MAINTAINER

指明该镜像的作者和其电子邮件,如:

1
MAINTAINER author "author@mail.com"

RUN

在新镜像内部执行的命令,比如安装一些软件、配置一些基础环境,支持shell中使用\来换行,如:

1
2
RUN echo 'hello docker!' \
&& echo 'hello world!' > /tmp/test.txt

也可以使用exec格式RUN [“executable”, “param1”, “param2”]的命令,如:

1
RUN ["yum","install","-y","nginx"]

要注意的是,executable是命令,后面的param是参数

COPY

将主机的文件复制到镜像内,如果目的位置不存在,Docker会自动创建所有需要的目录结构,但是它只是单纯的复制,并不会去做文件提取和解压工作。如:

1
COPY application.yml /etc/springboot/test/src/resources

注意:需要复制的目录一定要放在Dockerfile文件的同级目录下,因为构建环境将会上传到Docker守护进程,而复制是在Docker守护进程中进行的。任何位于构建环境之外的东西都是不可用的。COPY指令的目的的位置则必须是容器内部的一个绝对路径。

ADD

将主机的文件复制到镜像中,跟COPY一样,限制条件和使用方式都一样,如:

1
ADD application.yml /etc/springboot/test/src/resources

但是ADD会对压缩文件(tar, gzip, bzip2, etc)在镜像中做提取和解压操作,如:

1
ADD conf.tgz /etc/springboot/test/src/resources

EXPOSE

暴露镜像的端口供主机做映射,启动镜像时,使用-P参数来讲镜像端口与宿主机的随机端口做映射。使用方式(可指定多个):

1
2
EXPOSE 8080 
EXPOSE 8081

WORKDIR

在构建镜像时,指定镜像的工作目录,之后的命令都是基于此工作目录,如果不存在,则会创建目录。如

1
2
3
WORKDIR /tmp
WORKDIR web
RUN echo 'hello docker' > 1.txt

最终会在/tmp/web/目录下生成1.txt文件

ONBUILD

当一个包含ONBUILD命令的镜像被用作其他镜像的基础镜像时(比如用户的镜像需要从准备好的位置添加源代码,或者用户需要执行特定于构建镜像的环境的构建脚本),该命令就会执行。
如创建镜像image1

1
2
3
4
FROM ubuntu
...
ONBUILD ADD . /var/www
...

然后创建镜像image2,指定image1为基础镜像,如

1
2
FROM image1
...

然后在构建image2的时候,日志上显示如下:

1
2
3
4
Step 0 : FROM image1
# Execting 1 build triggers
Step onbuild-0 : ADD . /var/www
...

USER

指定该镜像以什么样的用户去执行,如:
USER www-data

VOLUME

用来向基于镜像创建的容器添加卷。比如你可以将mongodb镜像中存储数据的data文件指定为主机的某个文件。(容器内部建议不要存储任何数据)
如:

1
VOLUME /data/db /data/configdb

说明:VOLUME 主机目录 容器目录

CMD

容器启动时需要执行的命令,如:

1
CMD /bin/bash

同样可以使用exec语法,如

1
CMD ["/bin/bash"]

当有多个CMD的时候,只有最后一个生效。

ENTRYPOINT

作用和用法和CMD一样,但CMD和ENTRYPOINT有区别,一定要注意:

  • CMD的命令会被docker run的命令覆盖而ENTRYPOINT不会

如使用CMD ["/bin/bash"]或ENTRYPOINT ["/bin/bash"]后,再使用docker run -ti image启动容器,它会自动进入容器内部的交互终端,如同使用
docker run -ti image /bin/bash。

但是如果启动镜像的命令为docker run -ti image /bin/ps,使用CMD后面的命令就会被覆盖转而执行bin/ps命令,而ENTRYPOINT的则不会,而是会把docker run 后面的命令当做ENTRYPOINT执行命令的参数。

以下例子比较容易理解

1
ENTRYPOINT ["/user/sbin/nginx"]

然后通过启动构建镜像的容器

1
docker run -ti image -g "daemon off"

此时-g "daemon off"会被当成参数传递给ENTRYPOINT,最终的命令变成了

1
/user/sbin/nginx -g "daemon off"
  • CMD和ENTRYPOINT都存在时

CMD和ENTRYPOINT都存在时,CMD的指令变成了ENTRYPOINT的参数,并且此CMD提供的参数会被docker run后面的命令覆盖,如:

1
2
ENTRYPOINT ["echo","hello","i am"]
CMD ["docker"]