了解Docker

Docker是什么

Docker是指容器化技术,用于支持创建和使用 Linux 容器,同时Docker也是软件容器平台。

什么是容器(container)

容器是主机上与其他进程隔离的一个进程。这种隔离利用了内核对象命名空间(kernel namespaces)和控制组群(CGroup)。这些都是linux早已经存在的技术。Docker的作用就是将这些技术变得更易用。

什么是容器镜像(container image)

当运行容器时,它使用一个独立的文件系统,这个文件系统由容器镜像(container image)所提供。镜像包含了要运行容器需要的一切,包括依赖、配置、脚本、二进制文件等等。同时还包含了容器需要的其他配置,如环境变量和其他元数据。

简单理解Docker、Docker容器、Docker容器镜像

Docker可以简单理解为一个虚拟机平台,就类似于VMware,而容器当然就相当于一台台的虚拟机,所以容器镜像就类似于虚拟机的镜像啦。

为什么使用容器而不是虚拟机(VM)

容器比虚拟机更加"轻量",容器是一个应用层的抽象,多个容器运行时共享操作系统内核,只是作为独立的进程,占用空间少,启动快。而虚拟机是一个硬件层的抽象,多个虚拟机运行时,每个虚拟机都包含独立的操作系统,占用空间大,启动较慢。

Docker的其他优点

  • 模块化

    Docker 容器化方法注重在不停止整个应用的情况下,单独截取部分应用进行更改的能力,所以容器天然适合微服务。

  • 易于跨平台

    能简单的将一个平台上的应用迁移到另一个平台。

  • 快速部署

    启动运行新硬件、实施部署并投入使用往往需要大量的时间。基于 Docker 的容器的部署时间只需几秒不等。因此你可以高效的创建或销毁容器。

简单试试Docker

我们已经知道了Docker是什么了,接下来试试用用它,首先我们知道要创建一个Docker容器,就要先获取一个Docker镜像,这就用到了我们的第一个命令。

docker pull

  1. docker pull [options] name[:tag|@digest]

tag

要获取的image的tag

这个命令会从Docker的默认镜像仓库中获取你想要的镜像,你可以从镜像仓库中选择你需要的tag,下图以 docker hub 中的ubuntu的镜像为例

镜像仓库

用于存放 docker 镜像的地址,官方默认的仓库是 Docker Hub,当然你也使用国内的镜像仓库 阿里云网易云时速云DaoCloud ,又或者你也可以使用自己搭建的私有仓库。

我们如果想获取它,只需要使用以下命令

  1. docker pull ubuntu:20.04

我们可以看到以上有很多的"层",每一层都是可以可以被重用的。

你也许注意到了,我们还可以使用digest的方法拉取image,而刚刚我们拉取完后输出了它的digest,也就是说我们还可以以下方法拉取同样的image。

  1. docker pull ubuntu@sha256:3c9c713e0979e9bd6061ed52ac1e9e1f246c9495aa063619d9d695fb8039aa1f

docker run

  1. docker run [options] IMAGE[:tag|@digest] [command] [arg...]

在拉取后我们就应该运行容器了,而 docker run 指令应该是Docker最复杂的命令了,我们先试着使用刚刚拉取的image

  1. docker run -it ubuntu:20.04 /bin/bash

当运行以上的命令后会发现命令行发生了变化

  1. [root@VM-0-3-centos ~]# docker run -it ubuntu:20.04 /bin/bash
  2. root@b4cc8facbeb7:/#

这就进入了我们创建的ubuntu容器

然后再来看看我们刚才做了什么,-i 的意思是保持输入,-t 的意思是分配一个tty终端,如果难以理解的话,只需知道对于交互式进程,需要带上 -it 。而我们刚刚的使用的 /bin/bash 当然属于交互式进程,对于输入的这条命令,docker会将它作为容器的内部的第一个进程(也就是pid为1)。同时 docker 会监控pid为1的进程,当它退出时,容器也会退出。

现在我们使用 exit 退出终端,使用 docker ps 指令查看所有正在运行的容器(如果还要查看其他状态的容器需要加上 -a ),会发现容器的 status 处于exit状态了。这是因为bash为第一个进程,当docker发现到它退出时便会退出容器。

  1. root@b4cc8facbeb7:/# exit
  2. exit
  3. [root@VM-0-3-centos ~]# docker ps -a
  4. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  5. b4cc8facbeb7 ubuntu:20.04 "/bin/bash" 11 minutes ago Exited (0) 5 seconds ago magical_meninsky
  6. [root@VM-0-3-centos ~]#

如果希望exit后自动删除它,可以带上 --rm 标签。

以及如果我们希望容器能在退出的时候,重新启动的话,就要用 --restart 更改重启策略。重启策略主要有以下几种

  1. no

    不重启

  2. on-failure[:max-retries]

    退出码非为0时重启,最多重启失败"max-retries"次

  3. always

    总是重启

在某些时候我们并不希望容器在前台运行,例如Redis、Nginx之类的应用在后台运行就可以了,我们只需要加上 -d 标签,就能在后台运行应用。

--name 能帮助我们为容器命名。不过即使没有命名,Docker也会生成uuid来为唯一标识容器。

在需要设置环境变量的场景下可以使用 -e 指令设置, -e var="var 1"

除了这些必要的标签外,还有其他的标签,我们在后面再讨论。

docker 容器的状态转换

docker create

根据image创建一个容器,但是并不实际启动,使用形式与 run 相似

  1. docker create -it --name my_ubuntu ubuntu:20.04 /bin/bash

docker start

将一个处于 createexited 状态的容器切换为 running 状态

  1. docker start b4cc8facbeb7

等一下,我们似乎没有创建过叫做"b4cc8facbeb7"的容器?

实际上,我们之前说过Docker会生成uuid作为容器的id,当你使用 docker ps 查看容器时,就会发现container id这一列的存在,大部分可以能使用容器名称的场所也可以用容器id代替。

同时你并不需要完整的输入容器id,只需要能够唯一确认一个容器即可。所以在这里你甚至可以使用 docker start b

docker pause/unpause

你可以使用 pauseunpause 对容器进行冻结解冻,冻结状态下的容器中的所有进程会暂停

  1. docker pause my_ubuntu

docker stop/kill

stopkill 都是让容器退出主进程(即pid为1的进程)。但 stopkill 更加优雅。

stop 会通知所在的容器即将退出,而 kill 会直接关闭容器。而容器会对 stop 传入的信号量进行响应然后退出(根据主程序的设置,也可能不退出),如果程序对信号量不做处理或没有退出才做强制退出。

实际上,在使用了 stopkill 后并不是一定退出了,需要用 docker ps 命令查看来确保退出。

这是因为执行 stop 的时候容器会先对主进程发送sigterm信号,如果主进程没有对sigterm信号做出处理,就不会退出。这样的话就必须等待到stop的超时时间,然后docker引擎会用 kill 关闭。

kill 指令也可能不能立刻杀死主进程,因为它发送的是sigkill信号。而原因属于《操作系统》的内容,所以这里简单略过。

docker rm

删除一个容器,如果要删除镜像的话就是 docker image rm 。这个容器必须要 exit 状态才能删除,否则的话需要带上 -f (--force)才能删除。

docker push

在执行push之前需要在对应的仓库 docker login,docker默认的仓库为docker hub

docker attach

用于进入正在运行的容器。例如使用了以下命令:

  1. docker run -it -d --name my_ubuntu ubuntu:20.04 /bin/bash

此时后台运行后要再次进入只需要:

  1. docker attach my_ubuntu
docker inspect

获取有关Docker对象的信息

  1. docker inspect my_ubuntu
docker exec

在正在运行中的容器中执行命令

  1. docker exec [options] container command [arg...]

需要注意的是,command必须是可执行文件,要执行命令需要:

  1. docker exec -it my_ubuntu sh -c "echo hello"
docker cp

交换容器与宿主机上的文件或文件夹

  1. docker cp [options] 容器名称:容器中的地址 宿主机上的目标地址
  2. docker cp [options] 宿主机上的目标地址 容器名称:容器中的地址

用例:

把主机上/data/fileA放到容器test下的/home/fileA

  1. docker cp /data/fileA test:/home/fileA
docker diff

跟踪容器创建以来更改的文件和目录

用例:

  1. $ docker diff myNginx # 容器名称
  2. # C -> 更改、A -> 添加、D -> 删除
  3. C /dev
  4. C /dev/console
  5. A /run/nginx.pid
  6. C /var/lib/nginx/tmp
  7. A /var/lib/nginx/tmp/client_body
docker 导入和导出

导出容器到压缩文件

  1. docker export myNginx > latest.tar

从压缩文件或网络或输入流流导入

  1. docker import [options] file|url|- [repository[:tag]]
  1. docker import ./lastest.tar

同样可以做导入和导出的命令还有 saveload ,他们在使用上和 exportimport 相同。

而他们的区别在于:

  1. save 用来持久化image,export 用来持久化容器
  2. load 用来恢复image,import 恢复容器(但两者最后都会恢复为image)
  3. export 只会导出文件系统。也就是说任何元数据,如映射端口、 CMD 和 ENTRYPOINT 配置将会丢失。

基于以上的区别,export 的使用场景更偏向于制作基础镜像,save 的使用场景更偏向于打包复制镜像。

docker logs

查看容器的控制台的输出

先启动一个容器

  1. docker run --name my_ubuntu -itd ubuntu:20.04 echo "hello world"

然后使用 docker logs 命令查看控制台

  1. [root@VM-0-3-centos ~]# docker logs my_ubuntu
  2. hello world

你还可以用 -t 标签输出时间戳和用 -f 跟踪控制台输出

docker stats

监控一个或多个容器的实时数据

  1. [root@VM-0-3-centos ~]# docker stats
  2. CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
  3. 5ff9b00bdc08 competent_payne 0.12% 1.461MiB / 1.795GiB 0.08% 13.2kB / 0B 27.4MB / 0B 5
  4. 805ebe155e4f clever_turing 0.12% 60.95MiB / 1.795GiB 3.32% 72.9MB / 43.6MB 1.29GB / 2.01MB 32
  5. 6fbdf2516b99 mysql 0.13% 94.53MiB / 1.795GiB 5.14% 16.3MB / 27.1MB 2.42GB / 968MB 47
docker top

展示容器的进程

容器间的网络通信

首先,我们可以使用 link 命令

  1. docker --link <container>:<alias>

示例:

  1. docker run -it --link redis:myRedis --name my_ubuntu ubuntu /bin/bash

这个命令创建了一个 ubuntu 的容器,然后连接到已经存在的 redis 容器中。连接后就能在 ubuntu 的容器用 myRedis:3306 直接访问另一个容器中的 redis。

不过需要注意的是,使用这种方式的时候需要考虑容器的启动顺序,如一个 redis 集群的搭建使用

  1. 首先启动 redis-master 容器节点
  2. 然后在两个 redis-slave 容器节点启动时使用 --link 连接到 master 节点中
  3. 最后在 APP 容器节点启动时连接到 redis-master 上

link命令的连接方式的缺点非常明显,当容器的数量巨大的时候则需要使用多个link标签,其管理复杂,所以在官方的示例中使用的是network的方法,并且 link 的方式即将被废弃

network和link的方法差不多

  1. docker network create myNetwork

然后我们可以查看我们创建的network

  1. $ docker network ls
  2. NETWORK ID NAME DRIVER SCOPE
  3. a106580bca09 bridge bridge local
  4. c68edd500b5c host host local
  5. f8ea00182e3a myNetwork bridge local
  6. c120edcc6e0e none null local

除了我们创建的 myNetwork 外,还有三个内置的network,我们会在后面的文章中讨论这三个network

要连接到该网络的容器需要在创建容器时使用 --network 标签选择要添加的network,然后在同一个network下的容器就可以像是在同一个容器中进行连接

容器中的数据管理

  1. 数据卷(volume)

    最常用的方式

  2. 绑定挂载(bind mounts)

    不能跨平台,所以并非首选

  3. tmpfs

    不常用

数据卷的解释

数据卷是一个或多个容器中专门指定的目录,它能够绕过联合文件系统,也就是说数据卷的本质是容器中一个特殊的目录。

创建数据卷

  1. docker volume create --name "要创建的数据卷名称"

当然你也可以在创建新容器的时候同时创建数据卷,就像这样

  1. docker run -d -v /data ubuntu /bin/bash

这条命令使用"-v"标签添加一个随机名字的数据卷并挂载到了容器中的"/data"目录下,不过你也可以使用指定名字的数据卷

  1. docker run -d -v myVolumn:/data ubuntu /bin/bash

这下我们成功创建了一个数据卷,不过被创建的数据卷被放到哪了呢?我们可以使用以下命令查看我们创建的数据卷,在执行结果中我们从 Mountpoint 中看到数据卷的放置位置

  1. $ docker volume inspect myVolume
  2. [
  3. {
  4. "CreatedAt": "2021-04-08T21:08:01+08:00",
  5. "Driver": "local",
  6. "Labels": {},
  7. "Mountpoint": "/var/lib/docker/volumes/myVolume/_data",
  8. "Name": "myVolume",
  9. "Options": {},
  10. "Scope": "local"
  11. }
  12. ]

创建完后就应该投入使用了,我们可以使用 --volumes-from 标签指定要共享的容器的名称

  1. docker run --name test1 -d -v /data ubuntu /bin/bash

我们先创建一个新的容器,然后再新建一个共享的volume的容器

  1. docker run -it --volumes-from test1 ubuntu /bin/bash

这样就完成了数据卷的共享

但是数据卷有时候是需要要删除的,不过简单的删除数据卷挂载的容器并不会删除数据卷,所以你需要手动的删除

  1. docker volume rm <数据卷名称>

需要注意的是,这必须在没有容器挂载该数据卷的情况下才能成功

但是如果在创建时没有指定名称怎么办?我们可以这样

  1. docker rm -v <容器名称>

使用上面这条命令可以在删除容器的同时顺便删除它所挂载的数据卷,并且你还可以在 docker run 的时候加上 --rm 标签,这样的话在容器停止运行时会删除容器和它的数据卷,当然,以上两条命令只会删除没有指定名称的数据卷 ,也就是说如果你已为数据卷命名,那就只能被第一种方法删除。

在某些时候我们也可以不创建数据卷,而直接挂载宿主机的目录

  1. docker run -v /data/myData:/data/yourData ubuntu /bin/bash

这似乎和用数据卷的方式没多大区别。在这条命令中,我们将宿主机上的 /data/myData 文件夹绑定到了容器上的 /data/yourData 文件夹。

同时需要注意的是:

  • 文件夹必须使用绝对路径
  • 如果 /data/myData 不存在,则会创建一个空文件夹
  • 而容器中的 /data/yourData 如果已经存在,则原有内容会被隐藏

当然你也可以直接挂载单个文件

  1. docker run
  2. -v /data/configA.conf:/data/configA.conf
  3. -v /data/configB.conf:/data/configB.conf
  4. ubuntu /bin/bash

当文件夹或文件被挂载时,可以用 :ro 来标记只读,和用 :z 来标记共享,:Z 来标记私有

  1. docker run
  2. -v /data/configA.conf:/data/configA.conf:ro
  3. -v /data/configB.conf:/data/configB.conf:Z
  4. ubuntu /bin/bash

最后我们还可以对数据卷备份和恢复

数据卷备份:

  1. docker run
  2. --rm
  3. --volumes-from
  4. -v $(pwd):/backup
  5. ubuntu
  6. tar cvf /backup/data.tar /data

数据卷恢复:

  1. docker run
  2. -it
  3. --name vol_bck
  4. -v /data
  5. ubuntu /bin/bash
  6. docker run
  7. --rm
  8. --volumes-from vol_bak
  9. -v $(pwd):/backup
  10. ubuntu
  11. tar xvf /backup/data.tar -C /

简明教程 | Docker篇 · 其一:基础入门的更多相关文章

  1. 简明教程 | Docker篇 · 其二:Dockerfile的编写

    Dockerfile是什么 一个包含用于组合 image 的命令的文本文件,docker 通过 dockerfile 和构建环境的上下文来构建 image . 编写Dockerfile FROM 首先 ...

  2. ArcGIS Pro 简明教程(2)基础操作和简单制图

    ArcGIS Pro 简明教程(2)基础操作和简单制图 By 李远祥 本章主要介绍ArcGIS Pro如何加载数据并进行简单的地图制作,以基本的操作为主. 上一章节介绍过,ArcGIS Pro是可以直 ...

  3. 【Python教程】《零基础入门学习Python》(小甲鱼)

    [Python教程]<零基础入门学习Python>(小甲鱼) 讲解通俗易懂,诙谐. 哈哈哈. https://www.bilibili.com/video/av27789609

  4. docker容器技术基础入门

    目录 docker容器技术基础入门 容器(Container) 传统虚拟化与容器的区别 Linux容器技术 Linux Namespaces CGroups LXC docker基本概念 docker ...

  5. Docker 系列之 基础入门

    安装 Docker Windows 10 专业版以上版本 Docker for Windows Installer 在安装前,需要确保目标机器已经开启了硬件虚拟化和 HyperV :在安装的过程中建议 ...

  6. Python 简明教程 --- 3,Python 基础概念

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 控制复杂性是计算机编程的本质. -- Brian Kernighan 了解了如何编写第一个Pytho ...

  7. 推荐csdn里的几篇activiti基础入门及提高的博客

    昨天有个网友加qq询问我有没有非maven搭建的activiti项目的demo,因为我博客中写了一个用maven,我当时没有,于是晚上回家尝试了一下,结果比较容易就实现了. 之后和那个网友聊了一下,他 ...

  8. 1、docker容器技术基础入门

    Docker和传统虚拟机的区别               参考文章: https://lwn.net/Articles/531114/    操作中的命名空间详解 https://blog.yadu ...

  9. Python unittest第一篇:基础入门+命令行编译

    unittest单元测试框架最初受JUnit启发,与其他语言的主要单元测试框架具有相似的风格. 它支持测试自动化,支持开启或关闭某个测试,支持结合测试.另外它可以生成各个单元测试的报告.为了实现以上功 ...

随机推荐

  1. JS015. 数据存储方式与位置(堆内存、栈内存、指针)

    数据 - 基本类型 Undefined  ,  Null  ,  String  ,  Number  ,  Boolean  ,  Symbol (ES 6)  , 基本数据类型存储在栈内存中. 数 ...

  2. (2)java Spring Cloud+Spring boot+mybatis企业快速开发架构之SpringCloud-Spring Cloud是什么?Spring Cloud版本介绍

    ​ Spring Cloud 是一系列框架的有序集合.它利用 Spring Boot 的开发便利性,巧妙地简化了分布式系统基础设施的开发,如服务注册.服务发现.配置中心.消息总线.负载均衡.断路器.数 ...

  3. io流-缓冲流

    单独去数据时,数据按块读入缓冲区,其后的操作则直接访问缓冲区 但是用 BufferedInputStream读取字节文件时,

  4. 如何获取PHP命令行参数

    使用 PHP 开发的同学多少都会接触过 CLI 命令行.经常会有一些定时任务或者一些脚本直接使用命令行处理会更加的方便,有些时候我们会需要像网页的 GET . POST 一样为这些命令行脚本提供参数. ...

  5. PHP中命名空间是怎样的存在(一)?

    命名空间其实早在PHP5.3就已经出现了.不过大部分同学可能在各种框架的使用中才会接触到命名空间的内容,当然,现代化的开发也都离不开这些能够快速产出的框架.这次我们不从框架的角度,仅从简单的代码角度来 ...

  6. mysql5.7执行sql语句提示Expression #1 of ORDER BY clause is not in GROUP BY

    mysql 新版本出现group by 语句不兼容问题 [Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause ...

  7. 创建一个 Orchard Core CMS 站点

    本文通过引用项目模板的方式创建Orchard CMS站点. 创建项目有不同的方式可以为Orchard Core创建站点和模块.你可以在这里了解更多关于它们的信息.在本指南中,我们将使用我们的" ...

  8. disruptor笔记之一:快速入门

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  9. Shell系列(7)- 通配符

    通配符 通配符 作用 ? 匹配一个任意字符 * 匹配0个或任意多个任意字符,也就是可以匹配任何内容 [] 匹配中括号中任意一个字符.例如:[abc]代表一定匹配一个字符,或者是a,或者是b,或者是c. ...

  10. centos虚拟机中挂新硬盘

    配置一台centos7,主硬盘20G装系统:副硬盘20G作为数据盘(格式:XFS)挂载到根目录:/vdir/ ,XFS是高性能文件系统. 外层vm硬盘添加好后,执行下面 1.fdisk -l //查看 ...