Docker基础


Docker基础知识

Docker的基本组成

  • 镜像(image):

    docker镜像就好比是一个模板,可以通过这个模板来创建容器对外提供服务,如通过tomcat镜像创建一个tomcat容器,容器内的tomcat运行我们的war包对外提供服务,而一个镜像可以创建多个容器,我们不需要像传统部署一样每次都手动部署war,修改端口配置等。

  • 容器(container):

    Docker利用容器技术,独立运行一个或者一组应用,容器通过镜像来创建。对容器的基本操作有启动,停止,删除等,可以把这个容器理解为就是一个简易的Linux系统。

  • 仓库(repository):

    仓库就是存放镜像的地方,仓库分为公有仓库和私有仓库,类似GitHub,DockerHub便是镜像仓库。

Docker如何工作

Docker是一个Client-Server结构的系统,Docker的守护进程运行在主机上。通过Socket从客户端访问!Docker-Server接收到Docker-Client的指令并执行。

为什么Docker比VM快

  1. docker有着比虚拟机更少的抽象层。由于docker不需要Hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。

  2. docker利用的是宿主机的内核,而不需要Guest OS。

当docker新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核,避免了引导、加载操作系统内核返个比较费时费资源的过程。VM新建一个虚拟机时,虚拟机软件需要加载GuestOS,而docker由于直接利用宿主机的操作系统,则省略了这个复杂的过程

  • Hypervisor:虚拟机监视器(virtual machine monitor,缩写为 VMM),是用来建立与执行虚拟机器的软件、固件或硬件。
  • GuestOS: VM(虚拟机)里的的系统(OS)
  • HostOS:物理机里的系统(OS)

Docker安装

Docker的安装要求Linux在内核3.0以上

官方安装文档:https://docs.docker.com/engine/install/

帮助命令

1
2
3
4
5
6
# 显示docker版本
docker version
# 查看镜像容器数量等信息
dcoker info
# 帮助命令,查看某个命令如何使用
docker <命令> --help

docker全部命令官方文档:https://docs.docker.com/reference/

操作镜像

docker images

作用:查看镜像

  • docker images查看当前系统的镜像(默认隐藏中间的镜像)

  • docker images -a查看全部镜像,包括中间层的镜像

  • docker images -q查看镜像,仅显示镜像id

  • docker images -f <key=valu>查看镜像,根据条件过滤

    key的范围:

    • dangling:显示标记为<none>的镜像,取值范围:true | false,如:docker images -f dangling=true
    • label:根据标签进行过滤,其中lable的值,是docker在编译的时候配置的或者在Dockerfile中配置的
    • before:根据某个镜像的构建时间进行过滤,before的value表示某个镜像构建时间之前的镜像列表,如:docker images -f before=mysql
    • since:跟before正好相反,表示的是在某个镜像构建之后构建的镜像
    • reference:添加正则进行匹配,如:docker images -f reference="*:latest"(查询版本为最新版本的镜像)

作用:搜索远程仓库的镜像

如:docker search mysql -f STARS=3000(查询远程仓库镜像,查询mysql的镜像,且stars数量大于等于3000)

docker pull

作用:从远程仓库拉取镜像

格式docker pull <镜像名[:版本]>,等价于docker image pull <镜像名[:版本]>,如docker pull mysql(拉取mysql镜像,默认拉取最新版,latest),docker pull mysql:5.7(拉取mysql5.7镜像)

docker rmi

作用:删除镜像

格式:docker rmi <镜像名或镜像ID> ,等价于docker image rm <镜像名或镜像ID> 。镜像删除时,docker默认不允许删除正在运行的容器所引用的镜像,除非指定-f选项。

  • docker rmi mysql(删除mysql的镜像)
  • 删除时可通过镜像名:tag指定版本(标签)。如:docker rmi mysql:5.7这实际上只会删除mysql镜像为5.7的标签,除非该镜像仅有此标签,那么镜像就真的被删除
  • docker rmi -f mysql:强制删除镜像
  • docker rmi -f $(docker images -aq) (强制删除全部镜像,先查出id后删除)
  • docker images -q|xargs docker rmi:使用管道符传参进行删除
  • docker rmi -no-prune:不移除该镜像的过程镜像,默认移除
  • 同一镜像有多个tag情况下,执行 docker rmi <镜像ID> 指令无法删除

操作容器

扫盲:容器通过镜像创建而来,镜像与容器为1对多的关系。

docker run

作用:新建并运行容器

docker run等价于docker container run

常见命令格式:docker run [option1][option2] <镜像id或名称>,如:docker run --name=mysql-test mysql:5.7(使用mysql5.7镜像新建并运行一个容器,容器名为“mysql-test”)。

docker run 命令支持的option非常多,介绍部分option:

  • –name:指定容器名称
  • -i:以交互模式运行容器,通常与 -t 同时使用
  • -t:为容器重新分配一个伪终端,通常与 -i 使用
  • -d:以后台模式运行容器,并返回容器id,即启动守护式容器
  • -v:挂载卷(此处不展开讲,见下文)
  • -P:随机映射宿主机一个端口到容器内的一个端口
  • -p:指定端口映射,模式如下:
    • ip:<宿主机端口>:<容器端口>:宿主机IP+端口映射到容器内端口(如多网卡时)
    • ip::<容器端口>:自动选择宿主机端口(包含宿主机所有IP)映射到容器内端口
    • <宿主机端口>:<容器端口>:宿主机端口映射到容器内端口
  • –rm:容器停止时删除容器

docker create

作用:新建容器,但不启动

常见命令格式:docker create[option1][option2] <镜像id或名称>,option选项参数含义与run类似但不是全都支持

docker ps

作用:查看容器的运行状况,类似linux的ps命令查看进程的运行状态

docker ps等价于docker container list等价于docker container ls

  • docker ps:列出正在运行的容器
  • docker ps -a:列出全部容器,包括历史记录中已经停止的容器
  • docker ps -q:列出正在运行的容器,仅显示容器id
  • docker ps -n=?:列出最近创建的?个容器
  • docker ps -l:列出最近创建的上个容器,即docker ps -n=1

docker stop

作用:停止正在运行的容器

常见命令格式:docker stop <容器id或容器名>,如:

  • docker stop mysql-test:停止容器名为mysql-test的容器
  • docker stop d29f876f66d5:停止容器id为d29f876f66d5的容器

docker kill

作用:强制停止正在运行的容器,类似linux的kill命令

常见命令格式:docker kill <容器id或容器名>,如:

  • docker kill mysql-test:强制停止容器名为mysql-test的容器

docker start

作用:启动容器

常见命令格式:docker start <容器id或容器名>,如:

  • docker start mysql-test:启动容器名为mysql-test的容器

docker restart

作用:重启容器

常见命令格式:docker restart <容器id或容器名>,如:

  • docker restartmysql-test:重启容器名为mysql-test的容器

docker rm

作用:删除容器

正常情况下正在运行的容器不可删除。

常见命令格式:docker rm <容器id或容器名>,如:

  • docker rm mysql-test:删除容器名为mysql-test的容器
  • docker rm -f mysql-test:强制删除容器名为mysql-test的容器,即使该容器正在运行

与容器交互

docker attach

常见命令格式:docker attach <容器id或容器名>,此命令将进入容器正在执行的终端,如容器启动的前台进程是SpringBoot的jar(以前台模式启动),那么此方式进入容器后看到的就是SpringBoot应用的控制台打印的日志。

docker exec

常见命令格式:docker exec [option] <容器id或容器名>,进入当前容器后开启一个新的终端,option选项常用有:

  • -i:即使没有附加也保持STDIN(标准输入)打开
  • -t:分配一个伪终端
  • -d:分离模式: 在后台运行

选项意义与run命令的选项类似,如:

  • docker exec -it mysql-test /bin/bash:我们想进入容器,执行任何命令,就像平时使用linux那样,可同时指定-it选项。
  • docker exec -t mysql-test ls /:我们想查看某一目录下的文件信息,可以仅指定-t选项来进行回显,执行完毕后就退出了容器。
  • docker exec -i mysql-test /bin/bash:当使用-i选项执行/bin/bash时,由于标准输入打开,我们可以输入其它命令,但是此时是没有回显的。正常情况下只能用Ctr+C结束与之的交互,此时容器内由”/bin/bash”命令创建的进程不会被结束。
  • docker exec mysql-test ls:不带option,有回显,命令执行完毕后,docker发现没有前台进程,退出容器。

单独使用-i的场景不多,更多使用的是-t-it。笔者这里对这几个选项的描述可能并不是特别准确,心里明白但无法用文字完美诠释,读者还是自己实操理解会好些。

退出容器

  • docker attach方式进入容器:按下Ctrl+P+Q退出,如果使用exit退出终端或Ctrl+c方式结束当前前台进程,会导致容器停止!如果使用docker attach --sig-proxy=false <容器id或容器名>进入容器,则可以使用Ctrl+c方式退出
  • docker exec方式进入容器:按下Ctrl+P+Q退出,或以exit命令退出当前终端以退出容器。

两种进入容器的方式使用Ctrl+P+Q退出时,容器不会停止,因为此种方式会保留进入容器时的执行该命令的进程,容器不会退出,如果一个容器已经后台运行,我们以docker exec -it进入容器时,最好以exit命令退出,容器不会保留终端进程。如果是以docker attach方式进入,此时我们来到了容器守护的前台进程,一定要以Ctrl+P+Q方式退出,否则容器会停止。

容器内外的文件传输

docker cp

作用:从容器内拷贝文件(文件夹也是文件)到宿主机上

常见命令格式:docker cp [option] <srcPath> <destPath>

  • option选项:-L,以保持源目标中的链接
  • srcPath与destPath分两种情况:
    • 容器内拷贝文件到容器外:docker cp <容器id或容器名>:<容器内路径> <主机路径>
    • 容器外拷贝文件到容器内:docker cp <主机目的路径> <容器id或容器名>:<容器内路径> ,容器内的路径不存在则创建,即重命名

容器数据卷

《Docker容器数据卷》篇

容器内外的网络连通

端口映射

使用run命令时指定端口映射,前文提到过,见docker run命令的-p-P选项。

Docker网络

《Docker网络》篇

容器的日志

docker logs

作用:查看容器运行产生的日志

命令格式:docker logs [oprion1][option2] <容器id或容器名> ,常用option:

  • docker logs mysql-test :查看容器名为mysql-test的日志
  • docker logs -f mysql-test :查看且跟踪容器名为mysql-test的日志
  • docker logs -f mysql-test :查看且跟踪容器名为mysql-test的日志
  • docker logs -n=100 mysql-test :查看容器名为mysql-test的最后100行日志
  • docker logs --since=2021-02-01 mysql-test:查看容器名为mysql-test自2021年2月1日以来的日志
  • docker logs --since=2021-02-01T00:00 mysql-test:查看容器名为mysql-test自2021年2月1日00:00以来的日志
  • docker logs --since=2021-02-01T00:00:00 mysql-test:查看容器名为mysql-test自2021年2月1日00:00:00以来的日志

查看镜像或容器元数据

镜像或容器元数据:镜像或容器的详细信息,镜像元数据包括镜像完整id、构建时间等,容器元数据包括数据卷、网络等信息。

docker inspect

  • docker inspect <镜像名或镜像ID>(查看镜像元数据)

    • docker inspect java:查看java(latest版本)的镜像元数据
    • docker inspect java:7:查看java7的镜像元数据
  • docker inspect <容器名或容器ID>(查看容器元数据)

    • docker inspect mysql-test:查看容器名为mysql-test的容器元数据

Docker镜像原理

镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时库、环境变量和配置文件。

镜像加载原理

UnionFS(联合文件系统)

复制粘贴一下概念:Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,他支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。Union文件系统是 Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。

UFS可以类比git的commit进行理解。

docker的镜像实际上由一层一层的联合文件系统组成。

boots(boot file system):主要包含 bootloader和 Kernel, bootloader主要是引导加 kernel, Linux刚启动时会加bootfs文件系统,在Docker镜像的最底层是 boots。这一层与我们典型的Linux/Unix系统是一样的,包含boot加載器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由 bootfs转交给内核,此时系统也会卸载bootfs。
rootfs(root file system):在 bootfs之上。包含的就是典型 Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件。 rootfs就是各种不同的操作系统发行版,比如 Ubuntu, Centos等等。

平时我们安装进虚拟机的CentOS都是好几个G,为什么Docker这里才200M?

对于个精简的OS,rootfs可以很小,只需要包合最基本的命令,工具和程序库就可以了,因为底层直接用宿主机的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的Linux发行版, boots基本是一致的,rootfs会有差別,因此不同的发行版可以公用bootfs。

镜像的分层

基于UFS的特点,大多数docker镜像都是由多层镜像“叠加”而来的,所有的 Docker镜像都起始于一个基础镜像层,当进行修改或培加新的内容时,就会在当前镜像层之上,创建新的镜像层,为什么Docker镜像要采用这种分层的结构呢?

最大的好处,莫过于资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。类似于面向对象多态的体现之一:类的继承。

镜像与容器的联系

Docker 镜像都是只读的,当容器启动时,一个新的可写层加载到镜像的顶部,这一层就是我们通常说的容器层,容器之下的都叫镜像层。

如果想要保存当前容器的状态,就可以通过docker commit来提交(此处不将commit命令),获得一个镜像,就好比我们我们使用虚拟机的快照。


本文参考B站UP主“狂神说Java”https://space.bilibili.com/95256449/的docker教学视频进行整理。

感谢成长路上为在下传道受业解惑之人