讲到Docker不得不说下虚拟化

在计算机术语中虚拟化技术或虚拟技术(Virtualization)是一种资源管理技术,它虚拟的是整个PC硬件。也就是将计算机的各种实体资源(CPU、内存、磁盘空间、网络适配器等),予以抽象、转换后呈现出来并可供分割、组合为一个或多个计算机配置环境。来由此打破实体结构间的不可切割的障碍,使用户可以比原本的配置更好的方式来应用这些计算机硬件资源。这些资源的新虚拟部分是不受现有资源的架设方式,地域或物理配置所限制(摘自 wikipedia)

容器与虚拟化

  • 虚拟化: 虚拟化技术有多种比如CPU、网络、主机、存储、服务器、应用虚拟化等,而常见的虚拟化技术即通过Hypervisor将OS运行在物理设备或是宿主OS上。Hypervisor 是一种运行在物理服务器和操作系统之间的中间软件层,可允许多个操作系统和应用共享一套基础物理硬件,因此也可以看作是虚拟环境中的“元”操作系统,它可以协调访问服务器上的所有物理设备和虚拟机,也叫虚拟机监视器。
  • 常见的 Hypervisor 分两类:裸机型与宿主型
    • 裸机型:裸机型虚拟机是直接运行在系统硬件上,创建硬件全仿真实例,被称为“裸机”型。裸机型在虚拟化中Hypervisor直接管理调用硬件资源,不需要底层操作系统,也可以将Hypervisor看作一个很薄的操作系统。这种方案的性能处于主机虚拟化与操作系统虚拟化之间。
    • 宿主型:宿主型虚拟机运行在传统操作系统上,同样创建的是硬件全仿真实例,被称为“托管(宿主)”型。托管型/主机型Hypervisor运行在基础操作系统上,构建出一整套虚拟硬件平台(CPU/Memory/Storage/Adapter),使用者根据需要安装新的操作系统和应用软件,底层和上层的操作系统可以完全无关化,如Windows运行Linux操作系统。
  • 容器化: 容器化技术即用户空间虚拟化技术,也就是将用户空间分割多个,多个用户空间都将在一个内核中运行。容器虚拟化技术依赖Linux技术的名称空间服务即(NameSpace)。常见的技术有lxc(Linux Container)、OpenVZ等。 而Docker就属于软件虚拟化技术中的操作系统层虚拟化技术,它是基于LXC实现的一个应用容器引擎。Docker的出现可以让开发者打包他们的应用及依赖环境到一个可移植的容器中,然后可以将这个容器快速应用部署开发测试生产等。

容器虚拟化之 Docker

Docker的初始版本是在2013年开发出来的,使用的是Go语言开发并且遵循Apache2.0协议,是一个开放源代码软件项目。让应用程序部署在容器化下的工作可以自动化进行,借此在Linux操作系统上提供一个额外的软件抽象层,以及操作系统层虚拟化的自动管理机制。更多的Docker周边请浏览 Docker官网Docker Hub Docker利用Linux核心中的资源分离机制,CGroup及Linux核心名称空间(NameSpace),来创建独立的容器(containers)。这可以在单一Linux实体下运作,避免启动一个虚拟机造成的额外负担。Linux核心对名称空间的支持完全隔离了工作环境中应用程序的视野,包括进程树、网络、用户ID与挂载文件系统。而核心的cgroup提供资源隔离,包括CPU、存储器、block I/O与网络。从0.9版本起Dockers在使用抽象虚拟是经由libvirt的LXC与systemd - nspawn提供界面的基础上,开始包括libcontainer库做为以自己的方式开始直接使用由Linux核心提供的虚拟化的设施(摘自 wikipedia)。

容器的PID NameSpace(名空间)

在Docker中进程管理的基础就是Linux内核中的PID名空间技术,在不同PID名空间中进程ID是独立的,即在两个不同名空间下的进程可以有相同的PID。 Linux内核为所有的PID名空间维护了一个树状结构。最顶层的是系统初始化时创建的root namespace(根名空间),再创建的新PID namespace就称之为child namespace(子名空间),而原先的PID名空间就是新创建的PID名空间的parent namespace(父名空间)。通过这种方式,系统中的PID名空间会形成一个层级体系。父节点可以看到子节点中的进程,并可以通过信号等方式对子节点中的进程产生影响。反过来,子节点不能看到父节点名空间中的任何内容,也不可能通过kill或ptrace影响父节点或其他名空间中的进程。 在Docker中,每个Container都是Docker Daemon的子进程,每个Container进程缺省都具有不同的PID名空间。通过名空间技术,Docker实现容器间的进程隔离。另外Docker Daemon也会利用PID名空间的树状结构,实现了对容器中的进程交互、监控和回收。下面是Docker利用名空间技术所使用到的各种资源隔离方法,关于它是做什么的可自行Google这里不在阐述,只讲它的功能;

Docker容器级技术依赖于 NameSpace,CGroup,AUFS,Device Mapper

  • NameSpace:即在内核级完成环境隔离的技术方法
  • NameSpace:进程编号(PID)隔离,使每个用户空间所看到进程数都是独立且彼此互不干扰;
  • Network NameSpace:实现网络运行用户环境隔离,网络设备,网络栈,端口等网络资源隔离;
  • User NameSpace:用来完成用户隔离(用户和用户组隔离),Linux 3.8成熟起来;
  • IPC NameSpace:进程间通信技术也需要隔离,信号量、消息队列、共享内存的隔离,2.6.19引入;
  • UTS NameSpace:主机名和域名的隔离,Linux 2.6.19开始引入;
  • Mount NameSpace:实现已挂载文件系统隔离,Linux 2.4.19开始引入;

注意:为了能够向NameSpace发起调用,让NameSpace完成某些操作,其API有 clone(),setns(),unshare()

  • CGroup:Linux Control Group,控制组内核级功能,收入于Linux 2.6.24
  • 实践中CGroup主要作用:隔离一个进程集合,为进程分配足够内存、带宽而后限制其访问有哪些设备,并恢复完成资源限制机制;
  • CGroup基础作用:来限制、控制与分离一个进程组群的资源,CPU、内存、IO;

所实现的功能: Resource limitation:资源限制 Prioritization:优先级控制 Accounting:审计和统计,主要是计费 Control:挂起进程,恢复进程

  • CGroup子系统
    • blkio:实现限制跨设备IO能力而设定的一个子系统;
    • cpu:使用调度程序对CPU的任务访问;
    • cpuaccount:主要实现cpu使用时长统计;
    • cpuset:cpu集合,为CGroup任务进程分配独立的cpu核心和内存节点,真正实现资源指派;
    • memory:在cgroup当中设定内存的使用限制,按段分配;
    • devices:主要用来控制cgroup中的任务对设备的访问能力;
    • freezer:主要用来实现挂起进程或恢复某个指定的cgroup中的进程任务;
    • net_cls:(classid)主要使用等级级别标识符来标记网络数据包,限制数率来实现流量控制(基于tc完成对不同的cgroup中产生的流量控制 tc命令)
    • perf_event:实现对每个用户空间当中的任务所运行时的性能本身分别所产生的事件进行归类统计;
    • hugetlb:转换后援缓冲器,主要对HugeTLB系统进行限制;
  • CGroup术语:
  • task(任务):进程或线程;
  • cgroup:每一个cgroup就是一个独立的资源分配控制单位,可包含一个多个子系统;
  • subsystem:子系统,需要关联到cgroup中来完成指派;
  • hierarchy:资源层级结构;

------ 多个子系统参考路径 ls /sys/fs/cgroup ------

  • AUFS:如您使用的是红帽系列发行版系统,建议使用Overlay
  • UnionFS:把不同的物理位置的目录合并(挂载)到同一个目录中,最上层可写,下层只读;
  • UnionFS是内核原生技术,Docker强依赖AUFS,但Linux内核不支持AUFS,替代品Device mapper;
  • 多数Linux发行版都对AUFS提供了支持,但Linux内核和红帽就牛逼,咋说都不用;
  • Overlay与AUFS的对比 Overlay与AUFS对比AUFS简单参考
  • Device Mapper
  • Linux 2.6内核引入,为底层跨设备提供抽象设备,用于在内核中支持逻辑卷管理的通用设备映射机制;
  • Device mapper 在内核中作为一个块设备驱动被注册,它包含三个重要的对象概念;

mapped device:被映射的设备 mapping table:被映射的表 target device:源设备

Docker的核心组件

  • docker client:是用户使用docker主要接口,docker client与docker daemon通信并将结果返回给客户;
  • docker daemon:运行于宿主机上,是docker的守护进程,用户可通过docker client与其交互;
  • docker image:镜像文件且只读,是用来创建container,一个镜像可运行多个container。镜像文件可通过Dockerfile文件创建也可从docker仓库下载;
  • docker repository
  • 公共仓库:docker hub or docker registry
  • 私有仓库:docker registry
  • docker link:网络组件
  • docker volume:持久化数据存储组件
  • dockerfile:用于docker镜像构建

Docker的用途

  • 简单将就是提供 隔离应用、维护镜像、创建易于分发的应用及快速扩展等功能;
  • 提供一次性的环境。比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境;
  • 提供弹性的云服务。因为 Docker 容器可以随开随关,很适合动态扩容和缩容;
  • 组建微服务架构。通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构;

Docker的基础使用

  • 怎么安装
  • 环境是CentOS 7.4
[root@192_168 ~]# yum install -y docker
[root@192_168 ~]# systemctl enable docker
[root@192_168 ~]# systemctl start docker
[root@192_168 ~]# systemctl status docker
  • 简单使用
  • docker -h //docker 帮助
  • docker help daemon //docker 的子命令帮助
  • docker search centos //从互联网搜索相关服务镜像
  • docker pull centos //从互联网pull镜像到本地
  • 相关子命令
  • 跟环境信息相关子命令:
[root@192_168 ~]# docker info
[root@192_168 ~]# docker version
  • 跟系统维护相关子命令:
[root@192_168 ~]# docker images/inspect
[root@192_168 ~]# docker build/commit
[root@192_168 ~]# docker pause/unpause
[root@192_168 ~]# docker rm/rmi
[root@192_168 ~]# docker top/kill
[root@192_168 ~]# docker run/start
[root@192_168 ~]# docker stop/restart
[root@192_168 ~]# docker ps/ps -a	
[root@192_168 ~]# docker rm
  • 跟日志相关子命令:
 [root@192_168 ~]# docker events
 [root@192_168 ~]# docker history
 [root@192_168 ~]# docker logs
  • docker hub服务相关子命令:
[root@192_168 ~]# docker login/logout
[root@192_168 ~]# docker pull/search
  • docker镜像的启停
    • 通过镜像启动一个容器 docker run
    • 启动一个已停止的容器 docker start
[root@192_168 ~]# docker run -it --rm busybox:latest /bin/sh
  • 容器运行中创建自有container
[root@192_168 ~]# docker commit bb1954ab1978 centos:base-tools
  • docker简单架构
  • Docker 使用客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器;
  • Docker 容器通过 Docker 镜像来创建;
  • 容器与镜像的关系类似于面向对象编程中的对象与类;

Docker的相关组件

  • docker镜像与docker存储位置关系: **容器镜像:**即包含了启动docker容器所需的文件系统层级及其内容,基于UnionFS采用分层结构实现; 存储仓库: registry:保存docker镜像及镜像层次结构和元数据,一个registry包含多个repository一个repository内包含多个镜像; repository:由具有某个功能的镜像的所有相关版本构成的集合; index:管理用户的账号、权限、镜像及镜像标签等等相关信息的检索库 docker search; graph:从registry中下载的docker镜像需要保存在本地,此功能既由graph来完成/var/lib/docker/graph; 镜像相关命令: docker images/search/pull/push/login/logout/docker rmi及docker commit/build 等;
  • 容器:即独立运行的一个或一组应用,以及它们运行时所需要的环境 相关命令: run、kill、stop、start、restart、logs、attach、import、export 启动容器: 通过镜像创建一个新的容器 run 启动一个处于停止状态的容器 start run 命令: --name 给容器起一个名字,在后续的命令执行中可直接调用; -i 保持一个打开的STDIN状态,通常与-t结合使用; -t 关联一个终端; --net=default 启动一个容器关联到哪个桥上去,默认启动在docker0桥上; -d --detach=false 在后台(守护进程)方式运行docker; 注意:在交互式模式下启动的容器,关闭时可使用exit命令或Ctrl+d键;
~]# docker run -it --name busybox --net=default -d busybox:latest 

Docker私有仓库构建(Docker Registry)

安装: 环境是CentOS 7.4 [root@192_168 ~]# yum install -y docker docker-distribution 启动: [root@192_168 ~]# systemctl start docker [root@192_168 ~]# systemctl start docker-distribution [root@192_168 ~]# systemctl status docker docker-distribution 如果需要监听在80端口,可以用iptables转发实现 [root@192_168 ~]# iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 5000 构建本地镜像 [root@192_168 ~]# docker images [root@192_168 ~]# docker tag 1e1148e4cc2c localhost:5000/centos:1.0.1 [root@192_168 ~]# docker push localhost:5000/centos:1.0.1 [root@192_168 ~]# docker images [root@192_168 ~]# docker rmi localhost:5000/centos:1.0.1 [root@192_168 ~]# docker pull localhost:5000/centos:1.0.1 修改docker配置文件,默认使用内网仓库 修改文件/etc/sysconfig/docker #添加内网仓库 ADD_REGISTRY='--add-registry localhost:5000' #禁用官方仓库docker.io(可选) BLOCK_REGISTRY='--block-registry docker.io' 配置文件: #INSECURE_REGISTRY='--insecure-registry localhost:5000' #ADD_REGISTRY='--add-registry localhost:5000' #BLOCK_REGISTRY='--block-registry docker.io'

Docker 数据卷

  • 数据卷的特性: (1) 数据卷是提供一个或多个容器使用的文件或目录,有多种特性 (2) 可共享于多个容器之间 (3) 对数据卷的修改会立即生效 (4) 对数据卷的更新与镜像无关 (5) 数据卷会一直存在
  • 容器使用数据卷的方式: -v --volume=[ ] 绑定挂载一个数据卷,默认存储路径:/var/lib/docker/volumes/
  • 容器运行中挂载示例: ~]# docker run -it --name busybox --rm -v /data busybox:latest
  • 容器退出重挂使用原存储卷示例: ~]# docker run -it --name busybox -v /var/lib/docker/volumes/a8c7da4dcc16e757303b6358e3d4dc50cb1adfa38118216cb5f9a55331b2107d/_data/:/data busybox:latest
  • 提示:冒号前是宿主机路径,冒号后容器主机路径

Dockerfile 构建

  • dockerfile是由一系列用于根据基础镜像构建新的镜像文件的专用指令序列组成;
  • 指令有:选定基础镜像、安装必要程序、复制配置文件和数据文件自动运行的服务及要暴露的端口等
  • 命令是:docker build
  • docker build语法
  • 指令行:由指令及指令参数构成,字符不区分大小写
  • 注释行:#开头的行,必须单独位于一行当中
  • 空白行:会被忽略
  • 相关指令:
  • FROM指令:必须是第一非注释行,用于指定所用到的基础镜像
语法格式:FROM <image>[:<tag>] 或 FROM <image>@<digest>

简单示例:FROM busybox:latest or FROM centos:1.0 注意事项:一个file文件可多个from指令,但尽量不在一个dockerfile文件中使用多个from指令

  • MAINTAINER指令:提供信息让著作者提供本人信息,不限制出现位置,建议在FROM指令后
语法格式:MAINTAINER <author's detail>

简单示例:MAINTANIER Aliyun.com <admin@aliyun.com>

  • ONBUILD指令:定义触发器。用于在当前dockerfile构建出的镜像被用作基础镜像去构建其它镜像时,ONBUILD指令指定的操作才会被执行
语法格式:ONBUILD <INSTRUCTION> ONBUILD 后面跟的是dockerfile的指令

简单示例:ONBUILD ADD my.cnf /etc/mysql/my.cnf 注意事项:ONBUILD不能自我嵌套,且不会触发FROM和MAINTANIER等指令

  • EXPOSE指令:用于为容器指定要暴露的端口
语法格式:EXPOSE <Port>[/<protocol>] <Port>[/<protocol>] ...

简单示例:EXPOSE 11211/tcp 11211/udp

  • CMD指令:类似于RUN指令用于运行程序,但二者的运行的时间点不同。不是在docker build 是在docker run中运行。Docker Run 的CMD指令优于dockerfile中已定义的指令,会覆盖dockerfile中指令,如不想覆盖就使用ENTRYPOINT指令
语法格式:
CMD <command> 
CMD ["<executeable>","<param1>","<param2>",...]  
CMD RUN ["<param1>","<param2>",...] 此指令为ENTRYPOINT指令指定的程序提供默认参数

简单示例:CMD ["/usr/sbin/httpd","-c","/etc/httpd/conf/httpd.conf"] 注意事项:如果dockerfile中存在多个CMD指令,仅最后一个生效

  • RUN指令:用于指定docker build过程中要运行的命令,而不是docker run
语法格式:
RUN <COMMAND> 即shell命令会启动shell进程运行它,此进程UID不为1
RUN ["<executeable>","<param1>","<param2>",...] executeable运行的命令向命令传参param1,不启动shell进程不支持通配
简单示例:
run yum install -y net-tools
run ["/bin/bash","-c","<executeable>","<param1>","<param2>",...]

注意事项:每个RUN都会启动一个新层

[root@192_168 ~]# mkdir httpd-dockerfile && cd httpd-dockerfile [root@192_168 httpd-dockerfile]# vim httpd.df [root@192_168 httpd-dockerfile]# cat docker-httpd.df

FROM centos:latest
MAINTAINER Hehehuyu '<admin@aliyun.com>'
RUN yum install -y httpd php php-mysql php-mbstring
RUN echo -e '<?php\n\tphpinfo();\n?>' > /var/www/html/info.php
EXPOSE 80/tcp
CMD ["/usr/sbin/httpd","-f","/etc/httpd/conf/httpd.conf","-DFOREGROUND"]

[root@192_168 httpd-dockerfile]# docker build -f docker-httpd.df -t httpd:2.4 ./ [root@192_168 httpd-dockerfile]# docker images [root@192_168 httpd-dockerfile]# docker run --rm --name httpd -P httpd:2.4 [root@192_168 httpd-dockerfile]# docker port httpd (http://172.10.10.101:32768/info.php) [root@192_168 httpd-dockerfile]# docker kill httpd [root@192_168 httpd-dockerfile]# docker run -d --name httpd -p 80:80 httpd:2.4

更多的关于docker的周边

  • 更多Docker的容器互联,网络模型,容器间依赖等实现方法请参考官方帮助文档 docs