docker基础概念

Docker是一个用于开发,发布和运行应用程序的开放平台。Docker使您能够将应用程序与基础架构分开,从而可以快速交付软件。借助Docker,您可以以与管理应用程序相同的方式来管理基础架构。通过利用Docker的方法来快速交付,测试和部署代码,您可以大大减少编写代码和在生产环境中运行代码之间的延迟。

一. 什么是Docker?

Docker是一种Linux容器技术,一种高效、敏捷、和轻量级的容器解决方案,并且支持在多种主流平台(PaaS)和本地部署。Docker是基于Go语言实现的云开源项目,诞生于 2013 年,最初发起者是DotCloud公司,后来改名为Docker Inc,之后专注于Docker相关技术和产品的开发。Docker项目目前已经加入了Linux基金会,遵循Apache 2.0 开源协议,全部开源代码均在 https://github.com/docker 上进行相关维护,官网地址为:https://www.docker.com/, 有相关文档可以参考,现在docker与openstack同为最受欢迎的云计算开源项目。

docker的Logo设计为蓝色鲸鱼,拖着许多集装箱。docker的构想思想是要实现“Build, Ship and RunAny App, Anywhere”,即通过对应用的封装(Packaging)、分发(Distribution)、部署(Deployment)、运行(Runtime)生命周期进行管理,达到应用组件“一次封装,到处运行”的目的。这里的应用组件,既可以是一个Web应用、一个编译环境,也可以是一套数据库平台服务,甚至是一个操作系统或集群。

基于Linux平台上的多项开源技术,Docker提供了高效、敏捷和轻量级的容器方案,并支持部署到本地环境和多种主流云平台。可以说,Docker首次为应用的开发、运行和部署提供了“一站式”的实用解决方案。

跟大部分新兴技术的诞生一样,Docker也并非“从石头缝里蹦出来的”,而是站在前人的肩膀上,其中最重要的就是Linux容器(Linux Containers,LXC)技术。 image.png

操作系统级虚拟化的历史:

  • 1982 年:你一定会很惊讶,第一个操作系统级的虚拟化技术是什么。答案就是chroot,直到现在我们依然在使用的一个系统调用。这个系统调用会改变运行进程的工作目录,并且只能在这个目录里面工作。这种操作其实就是一种文件系统层的隔离。
  • 2000 年:FreeBSD jail,真正意义上的第一个功能完整的操作系统级虚拟化技术。所以,真正的容器化技术出现到现在已经过去了 16 年,并不是几年的时间。
  • 2005 年:OpenVZ,这是linux平台上的容器化技术实现,同时也是LXC,即docker最初使用的容器技术核心实现。
  • 2008 年:LXC发布,这是docker最初使用的具体内核功能实现。
  • 2013 年:Docker发布,可以看出,docker最初是使用了LXC,同时封装了其他的一些功能。Docker的成功,与其说是技术的创新,还不如说是一次组合式的创新。

总结:iPhone你要说有多创新,真的说不上。手机很早就有了,电脑很早就有,触摸屏很早就有,但是苹果将所有这些有机的组合到了一起,再提供极致的用户体验,就产生跨时代的产品。同样Docker所使用的技术也都不是新技术,它将这一系列技术有机的组合到一起,并提供极致的用户体验,就产生了垮时代意义的产品。

为何要使用docker?

1.Docker容器虚拟化的好处

Docker项目的发起人和Docker公司CTO Solomon Hykes曾认为,Docker在正确的地点、正确的时间顺应了正确的趋势——如何正确地构建应用。

在云时代,开发者创建的应用必须要能很方便地在网络上传播,也就是说应用必须脱离底层物理硬件的限制;同时必须是“任何时间、任何地点”可获取的。因此,开发者需要一种新型的创建分布式应用程序的方式,快速分发和部署,这正是Docker所能够提供的最大优势。

举个简单的例子,假设用户试图基于最常见的LAMP(Linux+Apache+MySQL+PHP)组合来构建一个网站。按照传统的做法,首先,需要安装Apache、MySQL和PHP以及它们各自运行所依赖的环境;之后分别对它们进行配置(包括创建合适的用户、配置参数等);经过大量的操作后,还需要进行功能测试,看是否工作正常;如果不正常,则进行调试追踪,意味着更多的时间代价和不可控的风险。可以想象,如果应用数目变多,事情会变得更加难以处理。

更为可怕的是,一旦需要服务器迁移(例如从亚马逊云迁移到其他云),往往需要对每个应用都进行重新部署和调试。这些琐碎而无趣的“体力活”,极大地降低了工作效率。究其根源,是这些应用直接运行在底层操作系统上,无法保证同一份应用在不同的环境中行为一致。而Docker提供了一种更为聪明的方式,通过容器来打包应用,解耦应用和运行平台。意味着迁移的时候,只需要在新的服务器上启动需要的容器就可以了,无论新旧服务器是否是同一类型的平台。这无疑将节约大量的宝贵时间,并降低部署过程出现问题的风险。

2.Docker在开发和运维中的优势

对开发和运维(DevOps)人员来说,可能最梦寐以求的效果就是一次创建或配置,之后可以在任意地方、任意时间让应用正常运行。而Docker恰恰是可以实现这一终极目标的“瑞士军刀”。

具体说来,Docker在开发和运维过程中,具有如下几个方面的优势:

  • 更快速的交付和部署 。使用Docker,开发人员可以使用镜像来快速构建一套标准的开发环境;开发完成之后,测试和运维人员可以直接使用完全相同环境来部署代码。只要开发测试过的代码,就可以确保在生产环境无缝运行。Docker可以快速创建和删除容器,实现快速迭代,大量节约开发、测试、部署的时间。并且,整个过程全程可见,使团队更容易理解应用的创建和工作过程。
  • 更高效的资源利用 。Docker容器的运行不需要额外的虚拟化管理程序(Virtual Machine Manager,VMM,以及Hypervisor)支持,它是内核级的虚拟化,可以实现更高的性能,同时对资源的额外需求很低。跟传统虚拟机方式相比,要提高一到两个数量级。
  • 更轻松的迁移和扩展 。Docker容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、服务器等,同时支持主流的操作系统发行版本。这种兼容性让用户可以在不同平台之间轻松地迁移应用。
  • **更简单的更新管理 **。使用Dockerfile,只需要小小的配置修改,就可以替代以往大量的更新工作。并且所有修改都以增量的方式被分发和更新,从而实现自动化并且高效的容器管理。

3.Docker与虚拟机比较

作为一种轻量级的虚拟化方式,Docker在运行应用上与传统的虚拟机方式相比具有显著优势:

  • Docker容器很快,启动和停止可以在秒级实现,而传统的虚拟机方式需要数分钟。
  • Docker容器对系统资源需求很少,一台主机上可以同时运行数千个Docker容器(在IBM服务器上已经实现同时运行10K量级的容器实例)。
  • Docker通过类似Git设计理念的操作来方便用户获取、分发和更新应用镜像,存储复用,增量更新。
  • Docker通过Dockerfile支持灵活的自动化创建和部署机制,提高工作效率,使流程标准化。
  • Docker容器除了运行其中应用外,基本不消耗额外的系统资源,保证应用性能的同时,尽量减小系统开销。传统虚拟机方式运行N个不同的应用就要起N个虚拟机(每个虚拟机需要单独分配独占的内存、磁盘等资源),而Docker只需要启动N个隔离的“很薄的”容器,并将应用放进容器内即可。应用获得的是接近原生的运行性能。
  • 当然,在隔离性方面,传统的虚拟机方式提供的是相对封闭的隔离。但这并不意味着Docker就不安全,Docker利用Linux系统上的多种防护技术实现了严格的隔离可靠性,并且可以整合众多安全工具。从1.3.0版本开始,Docker重点改善了容器的安全控制和镜像的安全机制,极大提高了使用Docker的安全性。在已知的大规模应用中,目前尚未出现值得担忧的安全隐患。

Docker容器技术与传统虚拟机技术的特性比较

特 性 容 器 虚 拟 机
启动速度 秒级 分钟级
性能 接近原生 较弱
内存代价 很小 较多
硬盘使用 一般为MB 一般为GB
运行密度 单机支持上千个容器 一般几十个
隔离性 完全隔离 完全隔离
迁移性 优秀 一般

Docker与虚拟化

虚拟化(Virtualization)技术是一个通用的概念,在不同领域有不同的理解。在计算领域,一般指的是计算虚拟化(Computing Virtualization),或通常说的服务器虚拟化。维基百科上的定义如下:“虚拟化是一种资源管理技术,是将计算机的各种实体资源,如服务器、网络、内存及存储等,予以抽象、转换后呈现出来,打破实体结构间的不可切割的障碍,使用户可以比原本的组态更好的方式来应用这些资源。”

可见,虚拟化的核心是对资源的抽象,目标往往是为了在同一个主机上同时运行多个系统或应用,从而提高系统资源的利用率,并且带来降低成本、方便管理和容错容灾等好处。

从大类上分,虚拟化技术可分为基于硬件的虚拟化和基于软件的虚拟化,基于软件的虚拟化从对象所在的层次,又可以分为应用虚拟化和平台虚拟化(通常说的虚拟机技术即属于这个范畴)。其中,前者一般指的是一些模拟设备或诸如Wine这样的软件。后者又可以细分为如下几个子类:

  • 完全虚拟化。虚拟机模拟完整的底层硬件环境和特权指令的执行过程,客户操作系统无需进行修

改。例如IBM p和z系列的虚拟化、VMware Workstation、VirtualBox、QEMU等。

  • 硬件辅助虚拟化。利用硬件(主要是CPU)辅助支持(目前x86体系结构上可用的硬件辅助虚拟化

技术包括Intel-VT和AMD-V)处理敏感指令来实现完全虚拟化的功能,客户操作系统无需修改,例如VMware Workstation、Xen、KVM。

  • 部分虚拟化 。只针对部分硬件资源进行虚拟化,客户操作系统需要进行修改。现在有些虚拟化技术

的早期版本仅支持部分虚拟化。

  • 准虚拟化(paravirtualization)。部分硬件接口以软件的形式提供给客户机操作系统,客户操作

系统需要进行修改,例如早期的Xen。 - 操作系统级虚拟化 。内核通过创建多个虚拟的操作系统实例(内核和库)来隔离不同的进程。容器相关技术即在这个范畴。可见,Docker以及其他容器技术,都属于操作系统虚拟化这个范畴,操作系统虚拟化最大的特点就是不需要额外的supervisor支持。

Docker虚拟化方式之所以有众多优势,这与操作系统虚拟化技术自身的设计和实现是分不开的。 image.png 传统方式是在硬件层面实现虚拟化,需要有额外的虚拟机管理应用和虚拟机操作系统层。Docker容器是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,因此更加轻量级。

二. Docker的体系结构

docker使用C/S 架构,docker daemon 作为 server 端接受 client 的请求,并处理(创建、运行、分发容器),他们可以运行在一个机器上,也可以使用docker客户端连接到一个远程的docker dameon,他们之间通过Unix socket或者RESTful API进行通信。 image.png

The Docker daemon

Docker守护程序(dockerd)侦听Docker API请求并管理Docker对象,例如images,containers,networks和volumes。守护程序还可以与其他守护程序通信以管理Docker服务。

The Docker client

Docker客户端(docker)是许多Docker用户与Docker交互的主要方式。当您使用诸如docker run之类的命令时,客户端会将这些命令发送到dockerd,以执行这些命令。该docker命令使用Docker API进行通信。Docker客户端可以与多个守护程序通信。

Docker registries

Docker 注册服务器存储Docker镜像。Docker Hub是任何人都可以使用的公共注册服务器,并且Docker配置为默认在Docker Hub上查找镜像,也可以运行自己的私人注册服务器。使用docker pull或docker run命令时,所需的镜像将从配置的注册服务器中查找,使用docker push命令时,会将镜像推送到配置的注册服务器上。

体系组件构成

image.png

  • Containerd: 是一个简单的守护进程,使用runC管理容器。向Docker Engine提供接口。
  • Shim: 只负责管理一个容器。
  • runC: 是一个轻量级的工具,只用来运行容器。

可以验证 :安装pstree了解一下具体docker层级结构

底层技术

# yum install psmisc -y
# docker run -d busybox ping baidu.com

image.png

docker使用Go语言编写,并利用了Linux 内核的多个特性来实现其功能。

1. Namespace 命名空间

Docker使用一种称为namespaces的技术来提供容器的隔离。运行容器时,Docker会为该容器创建一组命名空间。

这些命名空间提供了一层隔离。容器的每个方面都在单独的命名空间中运行,并且其访问仅限于该名称空间。

Docker Engine在Linux上使用以下名称空间:

  • pid namespace :进程隔离 (PID: Process ID)。不同用户的进程就是通过pid namespace隔离开的,且不同namespace中可以有相同pid。
  • net namespace : 管理网络接口(NET: Networking)。有了pid namespace,每个namespace中的pid能够相互隔离,但是网络端口还是共享host的端口。网络隔离是通过net namespace实现的,每个net namespace有独立的network devices, IP addresses, IP routing tables, /proc/net 目录。这样每个container的网络就能隔离开来。docker默认采用veth的方式将container中的虚拟网卡同host上的一个docker bridge: docker0 连接在一起。
  • ipc namespace :管理访问IPC资源 (IPC: InterProcess Communication)。container中进程交互还是采用linux常见的进程间交互方法 (interprocess communication - IPC),包括常见的信号量、消息队列和共享内存。container的进程间交互实际上还是host上具有相同pidnamespace中的进程间交互。
  • mnt namespace :管理文件系统的挂载点(MNT: Mount)。类似chroot,将一个进程放到一个特定的目录执行。mnt namespace 允许不同namespace的进程看到的文件结构不同,这样每个namespace中的进程所看到的文件目录就被隔离开了。在container里头,看到的文件系统,就是一个完整的linux系统,有/etc、/lib 等,通过chroot实现。
  • uts namespace :隔离内核和版本标识符(UTS: Unix Timesharing System)。允许每个container拥有独立的hostname和domain name, 使其在网络上可以被视作一个独立的节点而非Host上的一个进程。

2. Control groups 控制组

Linux上的Docker引擎还依赖于另一种称为控制组 (cgroups)的技术。cgroup将应用程序限制为一组特定的资源。控制组允许Docker Engine将可用的硬件资源共享给容器,并有选择地实施限制和约束。例如,您可以限制特定容器可用的内存。

顾名思义就是把进程放到一个组里面统一加以控制。官方的定义如下:cgroups是Linux内核提供的一种机制,这种机制可以根据特定的行为,把一系列系统任务及其子任务整合(或分隔)到按资源划分等级的不同组内,从而为系统资源管理提供一个统一的框架。

通俗的来说,cgroups可以限制、记录、隔离进程组所使用的物理资源(包括:CPU、memory、IO等),为容器实现虚拟化提供了基本保证,是构建Docker等一系列虚拟化管理工具的基石。

实现cgroups的主要目的是为不同用户层面的资源管理,提供一个统一化的接口。从单个进程的资源控制到操作系统层面的虚拟化。Cgroups提供了以下四大功能:

  • 资源限制(Resource Limitation):cgroups可以对进程组使用的资源总额进行限制。如设定应用

运行时使用内存的上限,一旦超过这个配额就发出OOM(Out of Memory)。

  • 优先级分配(Prioritization):通过分配的CPU时间片数量及硬盘IO带宽大小,实际上就相当于控

制了进程运行的优先级。

  • 资源统计(Accounting): cgroups可以统计系统的资源使用量,如CPU使用时长、内存用量等

等,这个功能非常适用于计费。

  • 进程控制(Control):cgroups可以对进程组执行挂起、恢复等操作。

3. Union file systems 联合文件系统

联合文件系统或UnionFS是通过创建图层进行操作的文件系统,使其非常轻便且快速。Docker Engine使用UnionFS为容器提供构建块。Docker Engine可以使用多个UnionFS变体,包括AUFS,btrfs,vfs和DeviceMapper。

4. Container format

Docker Engine将名称空间,控制组和UnionFS组合到一个称为容器格式的包装器中。默认容器格式为libcontainer。将来,Docker可以通过与BSD Jails或Solaris Zones等技术集成来支持其他容器格式。

三. Docker安装

  • docker官网:https://www.docker.com/
  • docker文档:https://docs.docker.com/
  • -Docker值得关注的特性:
    • 文件系统隔离:每个进程容器运行在一个完全独立的根文件系统里。
    • 资源隔离:系统资源,像CPU和内存等可以分配到不同的容器中,使用cgroup。
    • 网络隔离:每个进程容器运行在自己的网络空间,虚拟接口和IP地址。
    • 日志记录:Docker将会收集和记录每个进程容器的标准流(stdout/stderr/stdin),用于实时检索或批量检索。
    • 变更管理:容器文件系统的变更可以提交到新的映像中,并可重复使用以创建更多的容器。无需使用模板或手动配置。
    • 交互式shell:Docker可以分配一个虚拟终端并关联到任何容器的标准输入上。
  • 2017 年 2 月份,Docker公司发布了全新的Docker版本:V1.13.0。从 2017 年 3 月 1 号开始,Docker的版本命名发生如下变化,docker现在有两种版本:
    • 社区版CE(Community Edition)
      • dockerCE有 2 种更新:stable 和 edge
      • stable版每个季度更新一次
      • edge版每个月更新一次
    • 企业版EE(Enterprise Edition)
      • docker EE版是收费的,面向企业 image.png dockers CE和EE都支持多种平台,包括云主机,可以按照下面的来选择合适的版本 image.png image.png

安装 Docker CE

依据你的需求,安装有不同的方法:
  1. 大多数用户设置Docker库然后安装,对安装和升级任务轻松。这是推荐的方法。
  2. 有些用户下载RPM包并手动安装,并完全手动管理升级。没有互联网连接下的好方法。
  3. 在测试和开发环境,一些用户选择使用自动化脚本安装Docker。

OS要求:

  1. 需要一个维护版本的CentOS7,Archived versions或者test版不被支持;
  2. centos-extras 仓库需要激活,默认在centos7上是激活的;
  3. overlay2 存储驱动是被推荐使用;

卸载旧版本

Docker的旧版本被称为docker或docker-engine。如果这些已安装,请卸载它们以及关联的依赖关系。

$ sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-selinux \
docker-engine-selinux \
docker-engine
  • /var/lib/docker/的内容,包括镜像,容器,卷和网络都被保留。
  • Docker CE包现在称为docker-ce ,Docker EE包现在称为docker-ee。

使用docker yum仓库安装:

第一次在新主机上安装Docker CE,需要先设置Docker yum仓库,然后你可以从yum仓库安装和更新Docker。

  1. 安装需求包:安装所需的软件包 yum-utils,其提供了yum-config-manager实用程序, device-mapper-persistent-data和lvm2是devicemapper(设备映射)存储驱动程序所必需的。
$ sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
  1. 安装stable标准库:
##官方源
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
##国内源:
yum-config-manager \
--add-repo \
https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
  1. 选项:docker-ce.repo文件默认也包含edge和test仓库,默认是关闭的,你可以激活和关闭它们。
yum-config-manager --enable docker-ce-edge 开启edge版仓库
yum-config-manager --enable docker-ce-test 开启test版仓库
yum-config-manager --disable docker-ce-edge 关闭edge版仓库
  1. 安装docker-ce
##安装最新版本:
yum install docker-ce docker-ce-cli containerd.io
##这个命令会安装最新版本,安装完后,并不会启动docker,会创建docker组,但是组中没有任何用户。
##可以使用以下命令列出可用版本,选择安装不同版本。
yum list docker-ce --showduplicates | sort -r
  1. 启动docker
systemctl start docker
  1. 测试。检查docker是否正确安装并运行hello-world镜像
docker run hello-world
  1. 建立docker用户组。默认情况下,docker命令会使用Unix socket与Docker引擎通讯。而只有root用户和docker组的用户才可以访问Docker引擎的Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用root用户。因此,更好地做法是将需要使用 docker 的用户加入docker用户组。
##建立 docker 组:
$ sudo groupadd docker
##将当前用户加入docker组:
$ sudo usermod -aG docker $USER
  1. 镜像加速

鉴于国内网络问题,后续拉取Docker镜像十分缓慢,强烈建议安装 Docker 之后配置国内镜像加速。例如:

  • 阿里云加速器
  • DaoCloud 加速器
  • 灵雀云加速器

镜像加速步骤如下:

  1. 注册一个阿里的账号
  2. 进行加速器页面https://cr.console.aliyun.com/#/accelerator
  3. 复制你的加入器URL

image.png

  1. 针对Docker客户端版本大于 1.10.0 的用户,您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器。
sudo mkdir - p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://ariq8b1p.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
  1. 验证是否生效,执行如下命令:
[root@git ~]# docker info
...略
Registry Mirrors:
https://ariq8b1p.mirror.aliyuncs.com/
Live Restore Enabled: false

使用rpm包进行安装

需要到https://download.docker.com/linux/centos/7/x86_64/stable/Packages/下载软件包,然后使用命令安装即可:

##卸载docker-ce
##1. 卸载docker软件包
$ sudo yum remove docker-ce
##2. 镜像、容器、卷和自定义的配置文件不会自动删除。
$ sudo rm - rf /var/lib/docker
##必须手动删除任意的配置文件

参考资料:https://docs.docker.com/engine/installation/linux/docker-ce/centos/#uninstall-docker-ce

  • docker默认使用的是unix socket
  • 查看docker版本
[root@docker01 docker]# docker version
Client:
Version: 17.09.0-ce
API version: 1.
Go version: go1.8.
Git commit: afdb6d
Built: Tue Sep 26 22:41:23 2017
OS/Arch: linux/amd
Server:
Version: 17.09.0-ce
API version: 1.32 (minimum version 1.12)
Go version: go1.8.
Git commit: afdb6d
Built: Tue Sep 26 22:42:49 2017
OS/Arch: linux/amd
Experimental: false
[root@docker01 docker]#

安装好的docker系统有两个程序:docker服务端和docker客户端。

  • docker服务端是一个服务进程,管理着所有的容器。
  • docker客户端则扮演着Docker服务端的远程控制器,可以用来控制docker的服务端进程。
  • 大部分情况下docker服务端和客户端运行在一台机器上。
附:直接输入docker命令来查看所有的Options和Commands,查看某一个command的详细使
用方法:docker COMMAND --help

解决警告问题:

WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled
方法如下:
  1. 编辑/etc/sysctl.conf文件
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
  1. 执行sysctl -p