文章目录
镜像是一个只读的 Docker 容器模板,包含启动容器所需要的所有文件系统结构和内容。简单来讲,镜像是一个特殊的文件系统,它提供了容器运行时所需的程序、软件库、资源、配置等静态数据。即镜像不包含任何动态数据,镜像内容在构建后不会被改变。
镜像操作
从图中可知,镜像的操作可分为:
-
拉取镜像,使用docker pull命令拉取远程仓库的镜像到本地
-
重命名镜像,使用docker tag命令“重命名”镜像
-
查看镜像,使用docker image ls或docker images命令查看本地已经存在的镜像
-
删除镜像,使用docker rmi命令删除无用镜像
-
构建镜像,构建镜像有两种方式。第一种方式是使用docker build命令基于 Dockerfile 构建镜像,也是我比较推荐的镜像构建方式;第二种方式是使用docker commit命令基于已经运行的容器提交为镜像。
1. 拉取镜像
Docker 镜像的拉取使用docker pull命令, 命令格式一般为 docker pull [Registry]/[Repository]/[Image]:[Tag]。
-
Registry 为注册服务器,Docker 默认会从 docker.io 拉取镜像,如果你有自己的镜像仓库,可以把 Registry 替换为自己的注册服务器。
-
Repository 为镜像仓库,通常把一组相关联的镜像归为一个镜像仓库,library为 Docker 默认的镜像仓库。
-
Image 为镜像名称。
-
Tag 为镜像的标签,如果你不指定拉取镜像的标签,默认为latest。
例如我现在要拉取一个redis的镜像,这里替换为网易的镜像仓库
docker pull hub.c.163.com/library/redis:4.0
4.0: Pulling from library/redis
3d59d0c51bb7: Pull complete
fa7bbc6b37ad: Pull complete
e945d1598847: Pull complete
9092a5d0a502: Pull complete
a088f4159516: Pull complete
4156899232a5: Pull complete
Digest: sha256:43b3d87808f5c038c89d12355718798b85c4408a5c0b9c345c355c8a67c3d40e
Status: Downloaded newer image for hub.c.163.com/library/redis:4.0
实际上执行docker pull hub.c.163.com/library/redis:4.0命令,都是先从本地搜索,如果没有则在远程仓库下载
2. 查看镜像
使用docker images 或 docker image ls 查看镜像
- 下面使用docker images 列出所有镜像:
[root@docker daemon] docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hub.c.163.com/cloudpri/kafka 2.11-1.1.1 cede66ae8787 10 months ago 486MB
hub.c.163.com/cloudpri/zookeeper 3.5.3 79d9360a25f6 2 years ago 639MB
hub.c.163.com/library/tomcat 8.5 72d2be374029 3 years ago 292MB
hub.c.163.com/library/redis 4.0 d4f259423416 3 years ago 106MB
hub.c.163.com/library/mysql 5.7.18 9e64176cd8a2 3 years ago 407MB
hub.c.163.com/public/nginx 1.2.1 2dc68ff797db 4 years ago 172MB
[root@docker daemon]#
- 查询指定镜像 docker image ls
镜像名称
或 docker images | grep镜像名称
3. 重命名镜像
使用docker tag 命令,格式为 docker tag [SOURCE_IMAGE][:TAG] [TARGET_IMAGE][:TAG]
- SOURCE_IMAGE:需要修改的镜像
- TARGET_IMAGE:修改后的镜像
- TAG:标签
4. 删除镜像
使用docker rmi 或 docker image rm 删除镜像
格式: docker rmi [镜像:tag] 或 docker rmi [镜像ID]
5. 构建镜像
构建镜像主要有两种方式:
- 使用 docker commit 命令 从运行中的容器提交为新的镜像
- 使用 docker build 从 dockerfile中构建镜像
1. 使用docker commit(以busybox镜像为例)
-
拉取新的镜像,docker pull hub.c.163.com/library/busybox:latest
-
运行容器,并进入到容器,新建一个hello.txt文件
- docker run --name=busybox -it hub.c.163.com/library/busybox sh
- touch hello.txt && echo "hello Docker. " > hello.txt
-
退出容器(输入exit命令)
-
使用commit命令开始构建修改好的镜像
2. 使用dockerfile构建镜像
使用 Dockerfile 构建镜像具有以下特性:
-
Dockerfile 的每一行命令都会生成一个独立的镜像层,并且拥有唯一的 ID;
-
Dockerfile 的命令是完全透明的,通过查看 Dockerfile 的内容,就可以知道镜像是如何一步步构建的;
-
Dockerfile 是纯文本的,方便跟随代码一起存放在代码仓库并做版本管理。
Dockerfile 常用的指令:
Dockerfile 指令 | 指令简介 |
---|---|
FROM | Dockerfile 除了注释第一行必须是 FROM ,FROM 后面跟镜像名称,代表我们要基于哪个基础镜像构建我们的容器。 |
RUN | RUN 后面跟一个具体的命令,类似于 Linux 命令行执行命令。 |
ADD | 拷贝本机文件或者远程文件到镜像内 |
COPY | 拷贝本机文件到镜像内 |
USER | 指定容器启动的用户 |
ENTRYPOINT | 容器的启动命令 |
CMD | CMD 为 ENTRYPOINT 指令提供默认参数,也可以单独使用 CMD 指定容器启动参数 |
ENV | 指定容器运行时的环境变量,格式为 key=value |
ARG | 定义外部变量,构建镜像时可以使用 build-arg = 的格式传递参数用于构建 |
EXPOSE | 指定容器监听的端口,格式为 [port]/tcp 或者 [port]/udp |
WORKDIR | 为 Dockerfile 中跟在其后的所有 RUN、CMD、ENTRYPOINT、COPY 和 ADD 命令设置工作目录。 |
一个栗子
-
创建Dockerfile文件
- mkdir /usr/local/mydocker
- cd /usr/local/mydocker/
- vim Dockerfile
-
创建需要的文件
- vim nginx.repo
- 输入以下内容
[nginx] name=nginx repo baseurl=http://nginx.org/packages/centos/$releasever/$basearch/ gpgcheck=0 enabled=1
-
编写Dockerfile,输入以下内容
FROM hub.c.163.com/library/centos:7
COPY nginx.repo /etc/yum.repos.d/nginx.repo
RUN yum install -y nginx
EXPOSE 80
ENV HOST=mynginx
CMD ["nginx","-g","daemon off;"]
开始构建 命令 docker build -t [repositoty]:[tag] .
- wen.com/library/mynginx:1.0 .
- 后面的"." 代表Dockerfile的所在路径
好,来逐行分析一下上述的 Dockerfile。
-
第一行表示我要基于 centos:7 这个镜像来构建自定义镜像。这里需要注意,每个 Dockerfile 的第一行除了注释都必须以 FROM 开头。
-
第二行表示拷贝本地文件 nginx.repo 文件到容器内的 /etc/yum.repos.d 目录下。这里拷贝 nginx.repo 文件是为了添加 nginx 的安装源。
-
第三行表示在容器内运行yum install -y nginx命令,安装 nginx 服务到容器内,执行完第三行命令,容器内的 nginx 已经安装完成。
-
第四行声明容器内业务(nginx)使用 80 端口对外提供服务。
-
第五行定义容器启动时的环境变量 HOST=mynginx,容器启动后可以获取到环境变量 HOST 的值为 mynginx。
-
第六行定义容器的启动命令,命令格式为 json 数组。这里设置了容器的启动命令为 nginx ,并且添加了 nginx 的启动参数 -g ‘daemon off;’ ,使得 nginx 以前台的方式启动。
镜像的原理
其实 Docker 镜像是由一系列镜像层(layer)组成的,每一层代表了镜像构建过程中的一次提交。下面以一个镜像构建的 Dockerfile 来说明镜像是如何分层的。
FROM busybox
COPY test /tmp/test
RUN mkdir /tmp/testdir
上面的 Dockerfile 由三步组成:
第一行基于 busybox 创建一个镜像层;
第二行拷贝本机 test 文件到镜像内;
第三行在 /test 文件夹下创建一个目录 testdir。
为了验证镜像的存储结构,我们使用docker build命令在上面 Dockerfile 所在目录构建一个镜像:
$ docker build -t mybusybox .
这里我的 Docker 使用的是 overlay2 文件驱动,进入到/var/lib/docker/overlay2目录下使用tree .命令查看产生的镜像文件:
$ tree .
# 以下为 tree . 命令输出内容
|-- cceffac0c87f
| |-- diff # 这一层为基础层,对应上述 Dockerfile 第一行,包含 busybox 镜像所有文件内容,例如 /etc,/bin,/var 等目录
... 此次省略部分原始镜像文件内容
| `-- link
|-- 9b0c6ab7bbc2
| |-- diff # 这一层对应上述 Dockerfile 第二行,拷贝 test 文件到 /tmp 文件夹下,因此 diff 文件夹下有了 /tmp/test 文件
| | `-- tmp
| | `-- test
| |-- link
| |-- lower
| `-- work
|-- backingFsBlockDev
|-- d20ae45477cb
| |-- diff # 这一层对应上述 Dockerfile 第三行,在 /tmp 文件夹下创建 testdir 文件夹,因此 diff 文件夹下有了 /tmp/testdir 文件夹
| | `-- tmp
| | `-- testdir
| |-- link
| |-- lower
| `-- work
...
通过上面的目录结构可以看到,Dockerfile 的每一行命令,都生成了一个镜像层,每一层的 diff 夹下只存放了增量数据
层的结构使得 Docker 镜像非常轻量,每一层根据镜像的内容都有一个唯一的 ID 值,当不同的镜像之间有相同的镜像层时,便可以实现不同的镜像之间共享镜像层的效果。