0%

Docker相关知识再整理(1)

[TOC]

镜像

Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

个人理解为是创建容器的基础,类似于安装系统是所需的ISO文件,镜像就是生成容器所需的ISO。

镜像

获取镜像

1
docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]

列出镜像

列出镜像-不显示中间层镜像
1
2
3
☁  ~  docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 42b4762643dc 5 days ago 109MB

列表包含了 仓库名标签镜像 ID创建时间 以及 所占用的空间

为了加速镜像构建、重复利用资源,Docker 会利用 中间层镜像

所有镜像:
1
☁  ~  docker image ls -a
特定格式显示镜像列表
1
2
☁  ~  docker image ls -q
42b4762643dc
1
2
docker image ls --format "{{.ID}}: {{.Repository}}"
5f515359c7f8: redis

查看镜像、容器、数据卷所占用的空间

1
2
3
4
5
6
☁  ~  docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 14 13 1.347GB 211.8MB (15%)
Containers 23 22 4.962kB 0B (0%)
Local Volumes 0 0 0B 0B
Build Cache 0 0 0B 0B

悬浮镜像清理

无标签镜像也被称为 虚悬镜像(dangling image) ,可以用下面的命令专门显示这类镜像:

1
2
3
$ docker image ls -f dangling=true
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 00285df0df87 5 days ago 342 MB
1
2
3
4
☁  ~  docker image prune
WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N] y
Total reclaimed space: 0B

删除镜像

1
docker image rm [选项] <镜像1> [<镜像2> ...]

其中,<镜像> 可以是 镜像短 ID镜像长 ID镜像名 或者 镜像摘要

1
2
# 删除所有镜像
docker image rm $(docker image ls -q)

保存容器为镜像

运行一个容器的时候(如果不使用卷的话),我们做的任何文件修改都会被记录于容器存储层里

1
docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]

Demo:

1
2
3
4
5
6
docker commit \
--author "Nanme <Email>" \
--message "Description" \
webserver \
nginx:v2
sha256:07e33465974800ce65751acc279adc6ed2dc5ed4e0838f8b86f0c87aa1795214

其中 --author 是指定修改的作者,而 --message 则是记录本次修改的内容、

使用 docker commit 意味着所有对镜像的操作都是黑箱操作,生成的镜像也被称为黑箱镜像,换句话说,就是除了制作镜像的人知道执行过什么命令、怎么生成的镜像,别人根本无从得知

容器

容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样

镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

仓库

一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。

一个 Docker Registry 中可以包含多个仓库Repository);每个仓库可以包含多个标签Tag);每个标签对应一个镜像

通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。

Dockerfile

Dockerfile 是一个文本文件,其内包含了一条条的**指令(Instruction)**,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。

构建镜像

1
docker build [选项] <上下文路径/URL/->

Dockerfile 文件所在目录执行:

1
docker build -t nginx:v3 .

###FROM

FROM 就是指定基础镜像,因此一个 DockerfileFROM 是必备的指令,并且必须是第一条指令。

RUN 执行命令

RUN 指令是用来执行命令行命令的。由于命令行的强大能力,RUN 指令在定制镜像时是最常用的指令之一,

其格式有两种:

  • shell 格式:RUN <命令>,就像直接在命令行中输入的命令一样。刚才写的 Dockerfile 中的 RUN 指令就是这种格式。

  • ```Dockerfile
    RUN echo ‘

    Hello, Docker!

    ‘ > /usr/share/nginx/html/index.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

    - *exec* 格式:`RUN ["可执行文件", "参数1", "参数2"]`,这更像是函数调用中的格式。

    ### COPY 复制文件

    格式:

    - `COPY [--chown=<user>:<group>] <源路径>... <目标路径>`
    - `COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]`

    和 `RUN` 指令一样,也有两种格式,一种类似于命令行,一种类似于函数调用。

    `COPY` 指令将从构建上下文目录中 `<源路径>` 的文件/目录复制到新的一层的镜像内的 `<目标路径>` 位置。



    `<源路径>` 可以是多个,甚至可以是通配符,其通配符规则要满足 Go 的 [`filepath.Match`](https://golang.org/pkg/path/filepath/#Match) 规则,如:

    ```Dockerfile
    COPY hom* /mydir/
    COPY hom?.txt /mydir/

使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等

ADD 更高级的复制文件

ADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。

如果 <源路径> 为一个 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,ADD 指令将会自动解压缩这个压缩文件到 <目标路径> 去。

在 Docker 官方的 Dockerfile 最佳实践文档 中要求,尽可能的使用 COPY,因为 COPY 的语义很明确,就是复制文件而已,而 ADD 则包含了更复杂的功能,其行为也不一定很清晰。最适合使用 ADD 的场合,就是所提及的需要自动解压缩的场合。

在使用该指令的时候还可以加上 --chown=<user>:<group> 选项来改变文件的所属用户及所属组。

1
ADD --chown=55:mygroup files* /mydir/

CMD 容器启动命令

CMD 指令的格式和 RUN 相似,也是两种格式:

  • shell 格式:CMD <命令>
  • exec 格式:CMD ["可执行文件", "参数1", "参数2"...]
  • 参数列表格式:CMD ["参数1", "参数2"...]。在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数。

之前介绍容器的时候曾经说过,Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。CMD 指令就是用于指定默认的容器主进程的启动命令的。

VOLUME 定义匿名卷

格式为:

  • VOLUME ["<路径1>", "<路径2>"...]
  • VOLUME <路径>

EXPOSE 声明端口

格式为 EXPOSE <端口1> [<端口2>...]

要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口> 区分开来。-p,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。

ENV 设置环境变量

格式有两种:

  • ENV <key> <value>
  • ENV <key1>=<value1> <key2>=<value2>...

这个指令很简单,就是设置环境变量而已,用法如下面的格式$KEY

ARG 构建参数

格式:ARG <参数名>[=<默认值>]

构建参数和 ENV 的效果一样,都是设置环境变量,ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。不要因此就使用 ARG 保存密码之类的信息,因为 docker history 还是可以看到所有值的。

Dockerfile 中的 ARG 指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令 docker build 中用 --build-arg <参数名>=<值> 来覆盖。