docker总结
什么是docker
Docker 使用 Google
公司推出的 Go 语言 进行开发实现,基于 Linux
内核的 cgroup,namespace,以及 OverlayFS 类的 Union FS 等技术,对进程进行封装隔离,属于 操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。最初实现是基于 LXC,从 0.7
版本以后开始去除 LXC
,转而使用自行开发的 libcontainer,从 1.11
版本开始,则进一步演进为使用 runC 和 containerd。
cgroup用来资源管控
- linux Namespace 是linux kernel 提供的资源隔离方案
- 系统可以为进程提供不同的Namespace
- 保证不同的Namespace资源独立分配、进程彼此隔离
隔离性:
- pid namespace
- 不同的用户进程通过pid namespace 隔离开,且不同的namespace可以有相同的pid
- 有了pid namespace,每个namespace中的pid都能相互隔离
- net namespace
- 网络隔离是通过net namespace 实现的,每个net namespace 有独立的 network address、IP address、routing tables、/proc/net 目录
- Docker 默认使用 veth的·1方式将container 中的虚拟网卡同host上的一个dockers bridge: docker() 连接在一起
- ipc namespace
- container中的进程交互还是采用linux中常见的 进程交互方式(interprocess communication -IPC)。包括常见的信号量、消息队列和共享内存
- container的进程间交互实际上还是host上具有相同Pid namespace 中的进程交互,因此需要在IPC资源申请时加入namespace 的信息 - 每个IPC子啊云有一个唯一的32位 ID
容器镜像本身是一个tar包
基本概念
- 镜像 image
Docker 镜像 是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像 不包含 任何动态数据,其内容在构建之后也不会被改变。
镜像构建时,会一层一层的构建,前一层是后一层的基础。
- 容器 container
镜像(image
)和容器(container
)的关系,就像是面向对象程序设计中的 类
和 实例
一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
容器的本质是进程,但与直接在宿主执行的进程不同,容器进程运行在属于自己的独立命名空间中。
因此,容器可以拥有自己的root文件系统、自己的网络配置、自己的进程空间、甚至自己的用户ID空间。
使用镜像
获取镜像
从docker中获取镜像的命令是 docker pull
1 |
|
eg:
1 |
|
运行
1 |
|
it
:这是两个参数,一个是-i
:交互式操作,一个是-t
终端。我们这里打算进入bash
执行一些命令并查看返回结果,因此我们需要交互式终端。
退出
1 |
|
列举镜像
1 |
|
删除镜像
1 |
|
1 |
|
我们可以使用长 ID
来删除,但也可也使用短 ID
来删除,一般来说只需要输入前三位即可
1 |
|
1 |
|
使用dockerfile 定制镜像
- 使用 FROM 指定基础镜像
所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。
在 Docker Hub 上有非常多的高质量的官方镜像,有可以直接拿来使用的服务类的镜像,如 nginx
、redis
、mongo
、mysql
、httpd
、php
、tomcat
等。如果没有找到对应服务的镜像,官方镜像中还提供了一些更为基础的操作系统镜像,如 ubuntu
、debian
、centos
、fedora
、alpine
等,这些操作系统的软件库为我们提供了更广阔的扩展空间。除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为 scratch
。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。
1 |
|
- 使用RUN 执行命令
RUN指令在定制镜像是是最常用的指令之一,其格式有两种
shell格式,
RUN <命令>
,其中的命令就像在命令行中输入的命令一样1
RUN echo '<h1>hello,Docker!<h1>' > a.log
exec格式,
RUN ["可执行文件","arg-1","arg-2"]
,这会比较像函数调用的格式
注意: Union FS 是有最大层数限制的,比如 AUFS,曾经是最大不得超过 42 层,现在是不得超过 127 层。所以,要注意RUN的使用,写的时候尽量写一行,之间用 &&
连接
1 |
|
构建镜像
1 |
|
在Dockerfile 执行
1 |
|
其中的 .
表示当前目录
1 |
|
这表示 复制上下文目录下的 package.json
实际上 Dockerfile
的文件名并不要求必须为 Dockerfile
,而且并不要求必须位于上下文目录中,比如可以用 -f ../Dockerfile.php
参数指定某个文件作为 Dockerfile
。
add | copy
copy 用于将上下文目录中的源文件/目录复制到新一层的镜像的目标位置中
1 |
|
1 |
|
ADD
可以自动解压缩 压缩文件,压缩的格式为 gzip,bzip2以及XZ。ADD指令会自动解压缩这个压缩文件到目标目录中
1 |
|
在 Docker 官方的 Dockerfile 最佳实践文档 中要求,尽可能的使用 COPY
,因为 COPY
的语义很明确,就是复制文件而已,而 ADD
则包含了更复杂的功能,其行为也不一定很清晰。最适合使用 ADD
的场合,就是所提及的需要自动解压缩的场合。
建议:
- 单纯的复制场景,使用 COPY
- 需要自动解压缩的场景,使用 ADD
1 |
|
其他docker build的用法
直接使用git rep
1 |
|
使用指定的压缩包
1 |
|
Docker 引擎会下载这个包,并自动解压缩,以其作为上下文,开始构建。
从标准输入中读取 Dockerfile | 压缩包 进行构建
1 |
|
1 |
|
CMD容器启动
之前有介绍过,docker不是虚拟机,容器就是进程,既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。CMD
指令就是用于指定默认的容器主进程启动的命令
CMD
指令的格式和 RUN
相似,也是两种格式:
shell
格式:`CMD <命令>``- ``exec
格式:
CMD [“可执行文件”, “参数1”, “参数2”…]参数列表格式:
CMD [“参数1”, “参数2”…]。在指定了
ENTRYPOINT指令后,用
CMD` 指定具体的参数。
错误的写法
1 |
|
然后发现容器执行后就立即退出了。甚至在容器内去使用 systemctl
命令结果却发现根本执行不了。这就是因为没有搞明白前台、后台的概念,没有区分容器和虚拟机的差异,依旧在以传统虚拟机的角度去理解容器。
对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。
而使用 service nginx start
命令,则是希望 upstart 来以后台守护进程形式启动 nginx
服务。而刚才说了 CMD service nginx start
会被理解为 CMD [ "sh", "-c", "service nginx start"]
,因此主进程实际上是 sh
。那么当 service nginx start
命令结束后,sh
也就结束了,sh
作为主进程退出了,自然就会令容器退出。
正确的做法是直接执行 nginx
可执行文件,并且要求以前台形式运行。比如:
1 |
|
ENTRYPOINT 入口点
ENTRYPOINT
的格式和 RUN
指令格式一样,分为 exec
格式和 shell
格式。
ENTRYPOINT
的目的和 CMD
一样,都是在指定容器启动程序及参数。ENTRYPOINT
在运行时也可以替代,不过比 CMD
要略显繁琐,需要通过 docker run
的参数 --entrypoint
来指定。
当指定了 ENTRYPOINT
后,CMD
的含义就发生了改变,不再是直接的运行其命令,而是将 CMD
的内容作为参数传给 ENTRYPOINT
指令,换句话说实际执行时,将变为:
1 |
|
场景一:让镜像变成像变量的命令一样使用
1 |
|
1 |
|
1 |
|
ENV 设置环境变量
格式有两种:
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
1 |
|
1 |
|
ARG 构建参数
构建参数和 ENV
的效果一样,都是设置环境变量。所不同的是,ARG
所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 ARG
保存密码之类的信息,因为 docker history
还是可以看到所有值的。
Dockerfile
中的 ARG
指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令 docker build
中用 --build-arg <参数名>=<值>
来覆盖。
灵活的使用 ARG
指令,能够在不修改 Dockerfile 的情况下,构建出不同的镜像。
ARG 指令有生效范围,如果在 FROM
指令之前指定,那么只能用于 FROM
指令中
1 |
|
VOLUME 设置匿名卷
EXPOSE暴露端口
1 |
|
expose
用来声明容器运行时提供服务的端口,这只是一个声明,在容器运行时,不会因为这个声明而去开启这个端口的服务。
用处
- 便于镜像的使用者理解这个服务镜像的守护端口号是什么
- 使用
docker run -p
时,会自动随机映射EXPOSE
的端口号
WORKDIR 指定工作目录
1 |
|
/a/b/c
HEALTHCHECK健康检查
1 |
|
1 |
|
1 |
|
ONBUILD 为他人作嫁衣裳
构建基础镜像的时候,这ONBUILD
三行并不会被执行
1 |
|
1 |
|
前基础镜像的那三行 ONBUILD
会开始执行,成功的将当前项目的代码复制进镜像、并且针对本项目执行 npm install
,生成应用镜像。
1 |
|
其他
set -eux
RUN set -eux;
是一种在 Dockerfile 中常见的用法,用于设置一些 shell 的行为,尤其是在构建过程中执行的命令。让我们逐步解释这个命令:
set -e
:这个部分的含义是设置 shell 的执行模式为 “exit immediately if a simple command exits with a non-zero status”,也就是说,如果任何一个命令返回非零状态,那么整个构建过程就会立即失败,终止构建流程。这对于构建过程的可靠性和调试是很有用的,因为它能够确保任何构建阶段的错误都会导致构建过程终止。set -u
:这个部分启用了 shell 的 “uninitialized variable check” 模式。如果你尝试使用未定义的变量,shell 会立即退出并报告错误。这可以帮助捕获一些潜在的编程错误,确保你的脚本中没有使用未赋值的变量。set -x
:这个部分启用了 shell 的 “verbose mode”,也就是在执行每个命令之前,将该命令及其参数打印到标准错误输出。这对于调试和了解构建过程中究竟执行了哪些命令是非常有用的。
将这三个选项结合在一起,set -eux
提供了一种强大的工具,能够使得构建过程更加健壮,并且在构建过程中发生错误时提供详细的信息以便于调试。当构建过程中的某个步骤失败时,容器构建过程会立即停止,并且输出的信息会显示详细的执行步骤,有助于快速定位问题。
整个命令的样式通常是在 Dockerfile 中的 RUN
指令的开始处使用,以确保在构建过程中的每个命令都遵循这些行为设置。
数据管理
数据卷
数据卷
是一个可供一个或多个容器使用的特殊目录,它绕过 UnionFS,可以提供很多有用的特性:
-
`数据卷` 可以在容器之间共享和重用
-
对 `数据卷` 的修改会立马生效
-
对 `数据卷` 的更新,不会影响镜像
-
`数据卷` 默认会一直存在,即使容器被删除
注意:
数据卷
的使用,类似于 Linux 下对目录或文件进行 mount,镜像中的被指定为挂载点的目录中的文件会复制到数据卷中(仅数据卷为空时会复制)。
- 创建数据卷
1 |
|
- 查看数据卷
1 |
|
- 查看卷的信息
1 |
|
- 启动一个挂载数据卷的容器
1 |
|
- 删除数据卷的信息
1 |
|
无主的数据卷可能会占据很多空间,要清理请使用以下命令
1 |
|
挂载主机目录
挂载一个主机目录作为数据卷
1 |
|
1 |
|
挂载一个主机文件作为数据卷
1 |
|
使用网络
Docker:网络模式详解 - Gringer - 博客园 (cnblogs.com)