Docker镜像的操作可以分为:
docker pull
命令拉取远程仓库的镜像到本地 ;docker tag
命令“重命名”镜像 ;docker image ls
或docker images
命令查看本地已经存在的镜像 ;docker rmi
命令删除无用镜像 ;docker build
命令基于 Dockerfile 构建镜像,也是我比较推荐的镜像构建方式;第二种方式是使用docker commit
命令基于已经运行的容器提交为镜像。命令格式:docker pull [Registry]/[Repository]/[Image]:[Tag]
library
为 Docker 默认的镜像仓库。latest
。以拉取busybox 镜像为例,busybox 是一个集成了数百个 Linux 命令(例如 curl、grep、mount、telnet 等)的精简工具箱,只有几兆大小
$ docker pull busybox
Using default tag: latest
latest: Pulling from library/busybox
61c5ed1cbdf8: Pull complete
Digest: sha256:4f47c01fa91355af2865ac10fef5bf6ec9c7f42ad2321377c21e844427972977
Status: Downloaded newer image for busybox:latest
docker.io/library/busybox:latest
实际执行docker pull命令,都是先从本地搜索,如果本地搜索不到busybox镜像则从 Docker Hub 下载镜像
命令:docker images或者docker image ls
# 列出本地所有的镜像
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 4bb46517cac3 9 days ago 133MB
nginx 1.15 53f3fd8007f7 15 months ago 109MB
busybox latest 018c9d7b792b 3 weeks ago 1.22MB
# 查询指定的镜像
$ docker image ls busybox
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox latest 018c9d7b792b 3 weeks ago 1.22MB
# 列出所有镜像,然后使用grep命令进行过滤
$ docker images | grep busybox
busybox latest 018c9d7b792b 3 weeks ago 1.22MB
如果想要自定义镜像名称或者推送镜像到其他镜像仓库,可以使用docker tag命令将镜像重命名。
命令:docker tag [SOURCE_IMAGE][:TAG] [TARGET_IMAGE][:TAG]
# 将busybox镜像重命名
$ docker tag busybox:latest mybusybox:latest
# 查本地看镜像
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox latest 018c9d7b792b 3 weeks ago 1.22MB
mybusybox latest 018c9d7b792b 3 weeks ago 1.22MB
busybox和mybusybox这两个镜像的 IMAGE ID 是完全一样的,实际上它们指向了同一个镜像文件,只是别名不同而已。
命令:docker rmi
$ docker rmi mybusybox
Untagged: mybusybox:latest
命令:
先介绍第一种:docker commit,格式:docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
# 使用 busybox 镜像创建一个名为 busybox 的容器并进入 busybox 容器
$ docker run --rm --name=busybox -it busybox sh
# 在容器中,执行以下命令创建一个文件并写入内容
/ # touch hello.txt && echo "I love Docker. " > hello.txt
# 新打开另一个命令行窗口,运行以下命令提交镜像
$ docker commit busybox busybox:hello
sha256:cbc6406aaef080d1dd3087d4ea1e6c6c9915ee0ee0f5dd9e0a90b03e2215e81c
# 查看镜像
$ docker image ls busybox
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox hello cbc6406aaef0 2 minutes ago 1.22MB
busybox latest 018c9d7b792b 4 weeks ago 1.22MB
再介绍第二种:docker build,格式:docker build [OPTIONS]
# 假如有一个 Dockerfile,内容如下:
FROM 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;"]
# 根据该Dockerfile构建镜像如下,其中.代表当前文件夹
docker build -t mynginx:test .
在Docker镜像构建的方法中,提到可以通过Dockerfile进行镜像的构建。这里对Dockerfile以及Dockerfile的命令进行介绍。Dockerfile 是一个包含了用户所有构建命令的文本,通过docker build命令可以从 Dockerfile 生成镜像。
Dockerfile的命令有很多,以下进行介绍。
FROM
FROM :
MAINTAINER
RUN (在 shell 终端中运行命令,即/bin/sh -c)
RUN ["executable", "param1", "param2" ... ] (exec 执行)
CMD command param1 param2
CMD ["executable","param1","param2"]
当Dockerfile指定了ENTRYPOINT,CMD提供给ENTRYPOINT 默认参数:CMD ["param1","param2"]
每个Dockerfile 中只能有一个ENTRYPOINT,当指定多个时,只有最后一个起效。
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
USER daemon
EXPOSE [...]
ENV
ADD :复制指定的到容器中的。
可以是Dockerfile所在目录的一个相对路径;也可以是一个 URL;还可以是一个 tar 文件;
是container中的绝对路径
COPY
VOLUME [""]
WORKDIR /path/to/workdir
ONBUILD
ONBUILD 指定的命令在构建镜像时并不执行,而是在它的子镜像中执行。
Docker 镜像是由一系列镜像层(layer)组成的,每一层代表了镜像构建过程中的一次提交。
以一个镜像构建的 Dockerfile 来说明镜像是如何分层的,Dockerfile 的内容如下:
# 基于 busybox 创建一个镜像层
FROM busybox
# 拷贝本机 test 文件到镜像内
COPY test /tmp/test
# 在 /tmp 文件夹下创建一个目录 testdir
RUN mkdir /tmp/testdir
以Dockerfile 为基础进行镜像的构建
docker build -t mybusybox .
如果Docker使用的是overlay2 文件驱动,进入到/var/lib/docker/overlay2目录下使用tree .命令查看产生的镜像文件:
$ tree .
# 以下为 tree . 命令输出内容
|-- 3e89b959f921227acab94f5ab4524252ae0a829ff8a3687178e3aca56d605679
| |-- diff # 这一层为基础层,对应上述 Dockerfile 第一行,包含 busybox 镜像所有文件内容,例如 /etc,/bin,/var 等目录
... 此次省略部分原始镜像文件内容
| `-- link
|-- 6591d4e47eb2488e6297a0a07a2439f550cdb22845b6d2ddb1be2466ae7a9391
| |-- diff # 这一层对应上述 Dockerfile 第二行,拷贝 test 文件到 /tmp 文件夹下,因此 diff 文件夹下有了 /tmp/test 文件
| | `-- tmp
| | `-- test
| |-- link
| |-- lower
| `-- work
|-- backingFsBlockDev
|-- bec6a018080f7b808565728dee8447b9e86b3093b16ad5e6a1ac3976528a8bb1
| |-- diff # 这一层对应上述 Dockerfile 第三行,在 /tmp 文件夹下创建 testdir 文件夹,因此 diff 文件夹下有了 /tmp/testdir 文件夹
| | `-- tmp
| | `-- testdir
| |-- link
| |-- lower
| `-- work
...
Dockerfile 的每一行命令,都生成了一个镜像层,每一层的 diff 夹下只存放了增量数据,如图所示
Docker 镜像是静态的分层管理的文件组合,镜像底层的实现依赖于联合文件系统(UnionFS)。.分层的结构使得 Docker 镜像非常轻量,每一层根据镜像的内容都有一个唯一的 ID 值,当不同的镜像之间有相同的镜像层时,便可以实现不同的镜像之间共享镜像层的效果。
容器是基于镜像创建的可运行实例,并且单独存在,一个镜像可以创建出多个容器。运行容器化环境时,实际上是在容器内部创建该文件系统的读写副本。 这将添加一个容器层,该层允许修改镜像的整个副本。
容器的生命周期是容器可能处于的状态,容器的生命周期分为 5 种:
通过不同的docker命令可以实现容器状态之间的转换,下面对容器相关的操作命令进行介绍:
命令:docker create [OPTIONS] IMAGE [COMMAND] [ARG…]
$ docker create -it --name=busybox busybox
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
61c5ed1cbdf8: Pull complete
Digest: sha256:4f47c01fa91355af2865ac10fef5bf6ec9c7f42ad2321377c21e844427972977
Status: Downloaded newer image for busybox:latest
2c2e919c2d6dad1f1712c65b3b8425ea656050bd5a0b4722f8b01526d5959ec6
有两种启动容器的方式:
docker start
命令基于已经创建好的容器直接启动 。docker run
命令直接基于镜像新建一个容器并启动,相当于先执行docker create
命令从镜像创建容器,然后再执行docker start
命令启动容器。方式一:docker start,格式:docker start [OPTIONS] CONTAINER [CONTAINER…]
$ docker start busybox
方式二:docker run,格式:docker run [OPTIONS] IMAGE [COMMAND] [ARG…],OPTIONS参照docker create命令
# -t 参数的作用是分配一个伪终端,-i 参数则可以终端的 STDIN 打开,同时使用 -it 参数可以让我们进入交互模式。
$ docker run -it --name=busybox busybox
# 交互模式下可以通过所创建的终端来输入命令
$ ps aux
PID USER TIME COMMAND
1 root 0:00 sh
6 root 0:00 ps aux
# 容器的 1 号进程为 sh 命令,在容器内部并不能看到主机上的进程信息,因为容器内部和主机是完全隔离的
# 由于 sh 是 1 号进程,意味着如果通过 exit 退出 sh,那么容器也会退出。所以对于容器来说,杀死容器中的主进程,则容器也会被杀死。
命令:docker stop,格式:docker stop [OPTIONS] CONTAINER [CONTAINER…]
该命令首先会向运行中的容器发送 SIGTERM 信号,如果容器内 1 号进程接受并能够处理 SIGTERM,则等待 1 号进程处理完毕后退出,如果等待一段时间后,容器仍然没有退出,则会发送 SIGKILL 强制终止容器。
$ docker stop busybox
busybox
# 查看停止状态的容器信息
$ docker ps -a
CONTAINERID IMAGE COMMAND CREATED STATUS PORTS NAMES
28d477d3737a busybox "sh" 26 minutes ago Exited (137) About a minute ago busybox
# 也可以通过docker start命令来重新启动
$ docker start busybox
busybox
# docker restart命令会将一个运行中的容器终止,并且重新启动它
$ docker restart busybox
busybox
处于运行状态的容器可以通过docker attach
、docker exec
等多种方式进入容器
方式一:docker attach,格式:docker attach [OPTIONS] CONTAINER
$ docker attach busybox
/ # ps aux
PID USER TIME COMMAND
1 root 0:00 sh
7 root 0:00 ps aux
/ #
当同时使用docker attach命令同时在多个终端运行时,所有的终端窗口将同步显示相同内容,当某个命令行窗口的命令阻塞时,其他命令行窗口同样也无法操作
方式二:docker exec,格式:docker exec [OPTIONS] container_name COMMAND [ARG…]
$ docker exec -it busybox sh
/ # ps aux
PID USER TIME COMMAND
1 root 0:00 sh
7 root 0:00 sh
12 root 0:00 ps aux
# 容器内有两个sh进程,这是因为以exec的方式进入容器,会单独启动一个 sh 进程
当同时使用docker exec命令同时在多个终端运行时,每个窗口都是独立且互不干扰的,docker exec命令也是使用最多的一种方式。
命令:docker rm,格式:docker rm [OPTIONS] CONTAINER [CONTAINER…]
# 删除一个停止状态的容器
docker rm busybox
# 删除正在运行中的容器
docker rm -f busybox
导出容器命令:docker export,格式:docker export [OPTIONS] CONTAINER
# 进入容器创建文件
docker exec -it busybox sh
cd /tmp && touch test
# 执行导出命令
docker export busybox > busybox.tar
执行以上命令后会在当前文件夹下生成 busybox.tar 文件,可以将该文件拷贝到其他机器上,通过导入命令实现容器的迁移。
导入容器命令:docker import,格式:docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]
docker import busybox.tar busybox:test
# 执行完docker import后会变为本地镜像
注册服务器(Registry)VS 仓库(Repository)
公共镜像仓库一般是 Docker 官方或者其他第三方组织(阿里云,腾讯云,网易云等)提供的,允许所有人注册和使用的镜像仓库。
Docker Hub 是全球最大的镜像市场,目前已经有超过 10w 个容器镜像,这些容器镜像主要来自软件供应商、开源组织和社区。大部分的操作系统镜像和软件镜像都可以直接在 Docker Hub 下载并使用。
以Docker Hub 为例,要使用Docker Hub公共镜像仓库,需要先在Docker Hub官网注册账号并创建自己的仓库,以方便后续管理镜像,具体操作此处不做赘述。
在用Docker Hub管理镜像之前,需要先登录镜像服务器,命令为docker login,Docker 会要求输入用户名和密码,输入注册的账号和密码,看到Login Succeeded表示登录成功。登录成功后就可以推送镜像到自己创建的仓库了。
$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: lagoudocker
Password:
Login Succeeded
docker login命令默认会请求 Docker Hub,如果想登录第三方镜像仓库或者自建的镜像仓库,在docker login后面加上注册服务器即可。例如想登录访问阿里云镜像服务器,则使用docker login registry.cn-beijing.aliyuncs.com,输入阿里云镜像服务的用户名密码即可。
接着就可以利用Docker Hub对镜像进行管理
# 拉取镜像
$ docker pull busybox
Using default tag: latest
latest: Pulling from library/busybox
Digest: sha256:4f47c01fa91355af2865ac10fef5bf6ec9c7f42ad2321377c21e844427972977
Status: Image is up to date for busybox:latest
docker.io/library/busybox:latest
# 镜像“重命名
$ docker tag busybox lagoudocker/busybox
# 推送镜像
$ docker push lagoudocker/busybox
The push refers to repository [docker.io/lagoudocker/busybox]
514c3a3e64d4: Mounted from library/busybox
latest: digest: sha256:400ee2ed939df769d4681023810d2e4fb9479b8401d97003c710d0e20f7c49c6 size: 527
其中,推送镜像的命令为:docker push,格式为:docker push [OPTIONS] NAME[:TAG]
Docker 官方提供了开源的镜像仓库 Distribution,并且镜像存放在 Docker Hub 的 Registry 仓库下供我们下载。
先启动一个本地镜像仓库
$ docker run -d -p 5000:5000 --name registry registry:2.7
Unable to find image 'registry:2.7' locally
2.7: Pulling from library/registry
cbdbe7a5bc2a: Pull complete
47112e65547d: Pull complete
46bcb632e506: Pull complete
c1cc712bcecd: Pull complete
3db6272dcbfa: Pull complete
Digest: sha256:8be26f81ffea54106bae012c6f349df70f4d5e7e2ec01b143c46e2c03b9e551d
Status: Downloaded newer image for registry:2.7
d7e449a8a93e71c9a7d99c67470bd7e7a723eee5ae97b3f7a2a8a1cf25982cc3
# 查看启动的容器
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d7e449a8a93e registry:2.7 "/entrypoint.sh /etc…" 50 seconds ago Up 49 seconds 0.0.0.0:5000->5000/tcp registry
# 启动的私有镜像仓库,访问地址为localhost,端口号为 5000
推送镜像到本地仓库
# 镜像"重命名"
$ docker tag busybox localhost:5000/busybox
# 推送镜像
$ docker push localhost:5000/busybox
The push refers to repository [localhost:5000/busybox]
514c3a3e64d4: Layer already exists
latest: digest: sha256:400ee2ed939df769d4681023810d2e4fb9479b8401d97003c710d0e20f7c49c6 size: 527
# 删除本地的busybox和localhost:5000/busybox镜像
$ docker rmi busybox localhost:5000/busybox
Untagged: busybox:latest
Untagged: busybox@sha256:4f47c01fa91355af2865ac10fef5bf6ec9c7f42ad2321377c21e844427972977
Untagged: localhost:5000/busybox:latest
Untagged: localhost:5000/busybox@sha256:400ee2ed939df769d4681023810d2e4fb9479b8401d97003c710d0e20f7c49c6
# 从本地镜像仓库拉取busybox镜像
$ docker pull localhost:5000/busybox
Using default tag: latest
latest: Pulling from busybox
Digest: sha256:400ee2ed939df769d4681023810d2e4fb9479b8401d97003c710d0e20f7c49c6
Status: Downloaded newer image for localhost:5000/busybox:latest
localhost:5000/busybox:latest
由于容器是无状态的,私有仓库的启动方式可能会导致镜像丢失,因为我们并没有把仓库的数据信息持久化到主机磁盘上。可以采用docker卷(后续章节进行介绍)的方式进行持久化。
$ docker run -v /var/lib/registry/data:/var/lib/registry -d -p 5000:5000 --name registry registry:2.7
-v的含义是把 Docker 容器的某个目录或文件挂载到主机上,保证容器被重建后数据不丢失。-v参数冒号前面为主机目录,冒号后面为容器内目录。
这里的镜像仓库虽然可以本地访问和拉取,但是如果在另外一台机器上是无法通过 Docker 访问到这个镜像仓库的,因为 Docker 要求非localhost访问的镜像仓库必须使用 HTTPS,这时候就需要构建外部可访问的镜像仓库,具体步骤此处不再赘述。
Docker 官方开源的镜像仓库Distribution仅满足了镜像存储和管理的功能,用户权限管理相对较弱,并且没有管理界面。如果你想要构建一个企业的镜像仓库,Harbor 是一个非常不错的解决方案。Harbor 是一个基于Distribution项目开发的一款企业级镜像管理软件,拥有 RBAC (基于角色的访问控制)、管理用户界面以及审计等非常完善的功能。后续章节会介绍如何搭建Harbor私有镜像仓库。