在开始本次课题之前,我首先想分享一下我的学习方法论即”3W法”,也有叫”2W1H”,即What(什么是?)、Why(为什么会有?解决了什么问题?)、How(如何使用?)。本次我们也将会从这三个方面学习Docker。

Docker简介

Docker是一种 操作系统层面的虚拟化技术, 是Linux 内核的 cgroupnamespace,以及 AUFS 类的 Union FS 等技术的集合。我们可以把它看作是一个轻量级的虚拟机。这里我们需要了解的是Docker并没有创造什么新的技术,而是对传统的Linux技术的重新整合。
但是与传统虚拟机不同的是:传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
点击查看源网页.png

为什么要使用 Docker

作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。

更高效的利用系统资源

由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。

更快速的启动时间

传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。

一致的运行环境

开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 「这段代码在我机器上没问题啊」 这类问题。

持续交付和部署

对开发和运维(DevOps)人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。
使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 Dockerfile 来进行镜像构建,并结合 持续集成(Continuous Integration) 系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 持续部署(Continuous Delivery/Deployment) 系统进行自动部署。
而且使用 Dockerfile 使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。

更轻松的迁移

由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。

更轻松的维护和扩展

Docker 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,Docker 团队同各个开源项目团队一起维护了一大批高质量的 官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。

Docker容器 VS 传统虚拟机

特性 容器 虚拟机
启动 秒级 分钟级
硬盘使用 一般为 MB 一般为 GB
性能 接近原生 弱于
系统支持量 单机支持上千个容器 一般几十个

Docker系统架构

Docker 使用客户端-服务器 (C/S) 架构模式,使用远程 API 来管理和创建 Docker 容器。
Docker 引擎组件的流程如下图所示:
620140640_31678.png

  • docker daemon是docker server的守护进程。
  • REST API是docker客户端与守护进程通信的接口,通过REST-API可以对docker server发出指令。
  • Docker命令行界面 (CLI)的客户端工具。

    Docker基本概念

    Docker 包括三个基本概念

  • 镜像(Image

  • 容器(Container
  • 仓库(Repository

理解了这三个概念,就理解了 Docker 的整个生命周期。

Docker镜像(Image)

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

分层存储

因为镜像包含操作系统完整的 root 文件系统,其体积往往是庞大的,因此在 Docker 设计时,就充分考虑到这点,将其设计为分层存储的架构。
镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。类比Java语言就相当于类的继承,子类继承父类之后就拥有了父类的特性和功能。
分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。
关于的分层存储,将会在构建Docker镜像时详细说明。

Docker容器(Container

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
容器的实质是进程,但与直接在宿主执行的进程不同,容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。
但是有一点要注意:容器存储层的生命周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。所以 Docker 最佳实践的要求,不应该向容器存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。

Docker仓库(Repository

Docker仓库(Repository),顾名思义就是一个集中的存储、分发镜像的服务。当镜像构建完成后,我们可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,就需要先将镜像推送至镜像仓库,再从其他服务器上将其拉取下来。

Docker的使用流程

262150629_86976.png

Docker 安装

Docker安装很简单,但是有几点需要注意:

  • Docker 在 1.13 版本之后,从 2017 年的 3 月 1 日开始,同时 Docker 划分为 CE 版(社区版)免费,支持周期三个月 和 EE版(企业版)强调安全,需要付费使用。所以,如果需要安装新版本时需要先把docker的老版本删除。
  • Docker运行是基于Linux内核,所以Docker CE 要求Linux内核版本不低于 3.10。 CentOS 7 满足最低内核的要求,但由于内核版本比较低,部分功能(如 overlay2 存储层驱动)无法使用,并且部分功能可能不太稳定。

CentOS 安装 Docker

Docker常用命令

镜像命令

  1. # 拉取镜像
  2. $ docker pull hello-world:TAG
  3. # 查看镜像
  4. $ docker images
  5. # 查询镜像
  6. $ docker search [镜像名]
  7. # 构建镜像
  8. $ docker build -t demo-web:v1 .
  9. # 查看虚悬镜像
  10. $ docker image ls -f dangling=true
  11. # 删除虚悬镜像
  12. $ docker image prune

容器命令

  1. # 查看正在运行的容器
  2. $ $ docker ps
  3. # 运行容器
  4. $ docker run
  5. # 获取容器的日志
  6. $ docker logs
  7. $ docker container exec -it [容器名/容器ID] /bin/bash
  8. # 获取镜像的元信息。
  9. $ docker inspect [容器名/容器ID]
  10. # docker cp 用于容器与主机之间的数据拷贝
  11. # 将容器96f7f14e99ab的/www目录拷贝到主机的/tmp目录中。
  12. $ docker cp 96f7f14e99ab:/www /tmp/
  13. # 将主机/www/目录拷贝到容器96f7f14e99ab的/www目录下。
  14. $ docker cp /www 96f7f14e99ab:/www/

系统命令

  1. # 查看磁盘占用
  2. $ docker system df

参考资料:菜鸟教程

扩展知识点

数据卷(DataVolumes)

数据卷 是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:

  • 数据卷 可以在容器之间共享和重用
  • 数据卷 的修改会立马生效
  • 数据卷 的更新,不会影响镜像
  • 数据卷 默认会一直存在,即使容器被删除

    注意:数据卷 的使用,类似于 Linux 下对目录或文件进行 mount,镜像中的被指定为挂载点的目录中的文件会隐藏掉,能显示看的是挂载的 数据卷

  1. # 创建一个数据卷
  2. $ docker volume create my-vol
  3. # 查看所有的 数据卷
  4. $ docker volume ls
  5. # 在主机里使用以下命令可以查看指定 数据卷 的详细信息
  6. $ docker volume inspect my-vol
  7. [
  8. {
  9. "Driver": "local",
  10. "Labels": {},
  11. "Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
  12. "Name": "my-vol",
  13. "Options": {},
  14. "Scope": "local"
  15. }
  16. ]
  17. # 删除数据卷
  18. $ docker volume rm my-vol
  19. # 清理无主的数据卷
  20. $ docker volume prune
  21. #启动一个挂载数据卷的容器
  22. $ docker run -d -P \
  23. --name web \
  24. # -v my-vol:/wepapp \
  25. --mount source=my-vol,target=/webapp \
  26. training/webapp \
  27. python app.py

网络(NetWork)

桥接模式(bridge)(默认)

当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。
从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过brctl show命令查看。
bridge模式是docker的默认网络模式,不写—net参数,就是bridge模式。使用docker run -p时,docker实际是在iptables做了DNAT规则,实现端口转发功能。可以使用iptables -t nat -vnL查看。

  1. $ docker run --name t1 --network bridge -h huaan --dns 8.8.8.8 --rm buybox
  2. # 修改主机名 -h huaan
  3. # 修改dns --dns 8.8.8.8
  4. # 添加host --add-host [hostname]:[ip]
  5. # 端口映射选项 -p
  6. -p 8080 容器端口为8080 宿主机使用随机端口
  7. -p 80:8080 主机端口80端口映射到容器8080端口
  8. -p www.zhuky.com::8080 将容器的8080端口映射至主机固定域名的随机端口,若主机对应多个域名则其他域名无法访问;
  9. -p www.zhuky.com:80:8080 将容器的8080端口映射至主机固定域名的80端口,若主机对应多个域名则其他域名无法访问;

主机模式(Host)

如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。
使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行NAT,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好。

容器模式(Container)

这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。

无网络(None)

使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。
这种网络模式下容器只有lo回环网络,没有其他网卡。none模式可以在容器创建时通过—network=none来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。

Docker与图形管理工具Portainer

语雀内容

操作实例

语雀内容