docker

第1章 Docker原理介绍

本章主要介绍容器的基本原理。在了解基础原理,并且对容器有一些认识之后,掌握容器相关的一些基本操作。

1.1容器原理介绍

什么是容器技术

容器技术是轻量级虚拟化技术。利用该技术能够将应用打包发布到不同的容器化服务器上运行。在此过程中,可以减少繁琐的应用环境构建,大大加快从源码到应用上线的过程。

原理

容器技术最近很火,是各大公司争先使用的技术,首先整体来看容器是什么。 

图1-1 容器及其ID

从图1-1可以看出,运行了一个容器,而且这个容器中运行的父进程的ID为2483。


图1-2 容器ID及其父子进程

从图1-2中可以看出,容器2483进程的父进程是2243,是以daemon运行的docker engine。同时它还派生了一个子进程2494。

通过上面的介绍可以得到一个简单的概念:容器是受到资源限制的进程及其子进程。

这是从微观上来看容器的定义,从操作系统宏观上来看容器所处的位置则是图1-3 
 
图1-3 容器层次

图13中实际是包含容器A和容器B,每个容器都包含了Bins或Libs(必要的保证应用运行的库文件)。而容器之下是Docker Engine,保证每个容器都运行在独立的名字空间中。其中还存在另外一个概念:容器镜像,App+Bins/Libs 构成容器的镜像。这个是在容器运行前的一种状态。当然,容器在运行时也可以添加参数,实际运行比现在复杂。

因为大家对虚拟机比较熟悉,做一个容器跟虚拟机在操作系统上所处层次的对比: 

图 1-4 容器 vs VM层次对比

从图1-4中可以看出,虚拟机比容器多一层Guest OS层,这样是容器能够快速启停,性能上比虚拟机好的一个因素。

Docker组成

  • registry:Docker镜像库,制作好的Docker镜像存储的地方,方便拉取、推送。registry能够分层存储,类似于git对代码的管理。
  • image:将App和Libs打包之后的格式,类似于虚拟机的镜像文件。
  • container:image启动运行后的一种状态。

 
图1-5 registry、image和container的关系

从图1-5上可以很清楚看到registry、image和container三者之间的关系。而且registry、image和container三个组件构成了整个容器工具栈,实现了迭代打包镜像,镜像推送发布,对象快速部署的功能,使得对于应用的持续集成发布成为可能。

本节参考 
http://dockone.io/article/76 
http://coolshell.cn/articles/17010.html 
http://coolshell.cn/articles/17029.html

1.2 容器操作

Ubuntu 系列安装Docker

Ubuntu 14.04 版本系统中自带了Docker二进制包,可以直接安装

$ sudo apt-get update
$ sudo apt-get install -y docker.io
$ sudo ln -sf /usr/bin/docker.io /usr/local/bin/docker
$ sudo sed -i '$acomplete -F  _docker docker' /etc/bash_completion.d/docker.io

目前从Ubuntu官方系统带的二进制包比较老是1.6.2版本,有些新特性不一定能够使用到,稳定性上也存在一些问题,建议安装最新版容器技术包。

从Docker官方源安装

$ sudo apt-get install apt-transport-https
$ sudo apt-key  adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D857
$ sudo bash -c "echo deb https://get.docker.io/ubuntu docker main" > /etc/apt/sources.list.d/docker.li
$ sudo apt-get update
$ sudo apt-get install lxc-docker

或者采用Docker官方使用的安装脚本

# curl -sSL https://get.docker.com/ |sh

当前的最新版本是1.2.0,可以使用到Docker 的很多新特性,方便我们的快速上手和开发使用。

在实际操作容器时,需要明确三个概念:

  • 镜像
  • 容器
  • 仓库

镜像

类比虚拟机机中镜像,但是比虚拟机镜像要轻量很多,容器镜像只需要libs+app就行。对于特定的app,只需要此app使用的动态库即可,通常镜像只有几百兆。

镜像是容器在没有运行时的一种状态,镜像制作可以遵循Docker官方的DockerFile语法进行。

图1-6 容器镜像 
从图1-6中可以看到镜像的几个属性,repository、tag、image ID、created、size。利用这些信息可以很好的区分不同的镜像,有利于发布不同的应用。

容器

容器是镜像在运行时的一种状态。镜像在打包好之后,放到镜像库中,当需要运行时,采用Docker的特定指令加上一些额外的参数就能够运行起来。镜像一旦运行起来就进入容器状态。

在容器状态,存在生命周期管理的概念。容器可以start,stop,restart和destroy。

图1-7 容器

图1-7显示了一个正在运行的容器。

仓库

存储镜像有两种方式,一是本地镜像存储,二是中心库存储。当使用Dockerfile制作好镜像后,存储在本地镜像库中。之后可以将本地镜像库中的镜像推送到远程中心仓库中存储。同理,可以从中心仓库拉取镜像到本地仓库。实现镜像的制作,存储,分发。

Docker有官方镜像库,也允许在使用Docker的公司或者个人搭建私用仓库。可以利用发布的registry代码搭建私有中心仓库,存储私有镜像。

图1-8 镜像库 
图1-8显示了自建的私有仓库信息。可以查看到每个使用的镜像,以及镜像的tag(版本)信息。

实战

镜像管理

显示所有镜像
docker images
查询镜像
docker search ubuntu:14.04
拉取镜像
docker pull ubuntu:14.04
推送镜像到库中
docker push
删除镜像
docker rmi
制作镜像
docker build
需要编写Dockerfile文件,虽然比较简单,需要另外讲解。

容器生命控制

获取帮助
docker --help
展示所有镜像
docker images
运行镜像 
docker run
显示所有容器
docker ps
显示容器详细信息
docker inspect containerid
停止容器
docker stop containerid
开启容器
docker start containerid
删除容器
docker rm -f containerid

第2章 容器管理系统

本章主要介绍容器管理系统要使用到的接口、管理系统概要设计和详细设计。通过本章的学习将认识到管理系统的重要性,也将了解到怎样设计这个管理系统。

2.1 概要设计

系统背景

容器使用的不同阶段:

  • 手工阶段:全部靠手工来启停创建容器。对于单个应用来说没有问题,简单的一行命令就能够操作容器。(例如:用容器启动一个nginx服务)

  • 半自动阶段:对于大量需要部署的应用。编写大量的脚本来编排容器,完成比较复杂的应用的发布。只需要编写相对复杂的脚本就能够完成工作。(例如:使用容器部署nginx和java服务)

  • 规模阶段:一次对多个节点(3个以上服务器节点)进行应用高可用部署。需要在编写编排脚本的基础上,运用自动化工具来推送容器镜像,管理容器的启停。(例如:部署10套nginx和java服务)

  • 自动化规模阶段:大规模阶段,需要有大的管理系统来管理整个集群的应用部署,而且能够同时对多个应用操作。管理的容器达到几百上千。(例如:部署多个应用的多套nginx和java服务)

  • 最终目的:将日常大量的手工工作自动化,最大的节约人力成本。将有限的人力放置在更加广阔的服务上。

组成

容器管理系统由前端页面、后端操作和数据库表组成,即所谓的view、control和model。

  • 前端页面用来展示被管理的节点,展示管理节点上的容器,并且保证用户能够对管理的容器进行生命周期管理。
  • 后端操作,除了对接web请求外,还需要对web请求做二次包装,转化为能够调用Docker容器python接口的代码,并做一些容错处理,保证在容器管理过程中的稳定可靠。
  • 数据库表用来实现用户管理、记录管理节点和管理容器用途。

总体设计


图2-1 整体架构图

从图2-1中可以看出,用户跟UI做交互,所有动作都会到Handler做过滤,在handler阶段对各个url做解释,调用MySwarm或者Docker-py,将操作最终落地到被管理的各个Docker engine上。从而实现容器的生命管理操作。

图2-1中没有加入调度模块,不能够实现程序资源的自动分配,而是由管理者根据资源统计情况人工调度。这是该系统需要进一步演化的一个重点。

如果需要添加资源自动调度模块,只需要在MySwarm层做进一步开发Scheduler即可。资源调度和管理是容器管理中相对比较核心和困难的地方,可以参考社区Mesos和Marathon方案。当前,已经有比较成熟的解决方案。

登录界面

 
图2-2 登录界面

图2-2是从Bootstrap上获取的登录界面,简单实用。在登录界面主要实现对用户的认证和权限控制。用户认证解决是否可以访问该平台;权限控制解决可以访问该平台的那些部分。用户登录需要跟数据库做交互,有数据库表需求。

用户表有四个字段:id、name、password、user_group。id为关键字int型,name、password和user_group都是字符串字段。

管理界面

管理界面采用左右分栏方式,左边为管理栏,右边为展示栏,比较符合实际管理操作系统的风格。


图2-3 管理界面

图2-3 管理界面上分为两个部分,上部分为资源管理,下部分为容器生命周期的实际操作。

容器节点管理

容器节点管理主要是需要管理的节点做增加和删除操作,添加到管理系统中的节点,其节点上的容器就添加到了管理系统中。


图2-4 节点管理

节点管理中有增加和删除节点操作,需要在后面的开发中添加功能。

容器用途管理

由管理系统创建的容器,需要对使用情况做记录,该部分即是完成这部分工作,保证容器用途和使用人可查。


图2-5 容器用途管理

容器生命周期控制

容器生命周期管理包括容器的创建、启动、停止、删除四个操作,这是整个管理系统中的核心部分。 

图2-6 容器创建


图2-7 容器生命周期控制

图2-6是容器的创建部分,主要用来设置容器创建过程中的各个系统资源参数。图2-7是对创建后的容器的操作,包括启动、停止、重启和销毁。

实战 展示管理系统

2.2 容器接口

Docker的Python接口

Docker 的官方Python接口是用python编写的,对容器操作命令做了封装后的接口。本质还是Docker engine的Restful接口的调用。只是用Python封装后,操作起来更加方面简洁。 
可以采用源码安装,

wget https://github.com/docker/docker-py/archive/1.8.1.zip
cd 1.8.1
python setup.py

也可以使用pip install来安装

     pip install dokcer-py

安装后,直接使用import命令即可使用

import docker

引入Docker模块之后,就可以利用Docker模块提供的方法。

实战 利用python api创建容器

import docker

client_ins = docker.Client(base_url='tcp://127.0.0.1:2375', version='1.20', timeout=10)
print ("      Create the container......")
container_ret = client_ins.create_container(image=conf['Image'],
                            stdin_open=conf['OpenStdin'],
                            tty=conf['Tty'],
                            command=conf['Cmd'],
                            name=conf['Name'],
                            hostname=conf['Hostname'],
                            host_config=conf['HostConfig'])

以上代码中可以看出,引入Docker模块之后,需要初始化Client对象,然后可以调用Client对象中的方法。 
这些方法跟Docker cli的方法相差不大,包括我们要用到的各种方法。

增加各个方法的详细解释(或者将不用到的删掉,详细的介绍要使用的方法)


    docker ps 功能,列举所有的容器
    containers(self, quiet=False, all=False, trunc=False, 
              latest=False, since=None, before=None, limit=-1,
              size=False, filters=None)

    docker cp 功能,从容器中拷贝数据
    copy(self, resource_id=None, *args, **kwargs)

    创建容器,之后可以使用start命令启动容器
    create_container(self, image, command=None, hostname=None,
                     user=None, detach=False,
                     stdin_open=False,tty=False,mem_limit=None, 
                     ports=None, environment=None,
                     dns=None,volumes=None,volumes_from=None,
                     network_disabled=False, name=None,
                     entrypoint=None,cpu_shares=None,working_dir=None,
                     domainname=None, memswap_limit=None,
                     cpuset=None,host_config=None,mac_address=None,
                     labels=None, volume_driver=None, stop_signal=None,
                     networking_config=None)

    重启容器
    restart(self, resource_id=None, *args, **kwargs)

    启动容器
    start(self, resource_id=None, *args, **kwargs)

    查看容器运行数据
    stats(self, *args, **kwargs)

    停止容器
    stop(self, resource_id=None, *args, **kwargs)

    展示容器中运行的进程
    top(self, resource_id=None, *args, **kwargs)

    启动容器中所有的进程
    unpause(self, resource_id=None, *args, **kwargs)

    更新容器配置
    update_container(self, *args, **kwargs)

    阻塞直到容器停止,进入exit状态
    wait(self, resource_id=None, *args, **kwargs)  

具体可以上https://docker-py.readthedocs.io/en/latest/api/查看各个方法的介绍。 
以上代码块中的方法,基本都是比较常用的方法,对Docker的开发有很大的帮助。 
另外,有些性能或者监控相关的数据,在Docker官方提供的接口中并没有很好的实现,需要我们直接从Docker engine中获取数据,此时就可以使用Docker engine提供的原生Restful接口了。
如以下代码:

def _container_list_more(self, node_ip, node_port, containers_id):
        url = ('http://' + node_ip + ":" + node_port + "/containers/" +
                  containers_id + "/json")
        container_more_url = Curl(url)
        ret_json = container_more_url.get_value()
        return ret_json

以上代码块用来获得某个节点上的容器的详细信息。该方法没有调用Docker 的python接口,而是直接从Docker engine获取。

关于docker engine提供的restful 接口可以参考官方文档。

实战 操作docker engine的restful接口

图2-8 docker restful接口

图2-8是利用docker engine restful来查看其中一个被管理节点的信息。返回的全部为json格式数据,可以方便之后的操作。

2.3 详细设计

web框架

选择tornado作为管理系统的Web框架。跟Django比起来,tornado更加简单,灵活性也更大。 
tornado有两种安装方式:

pip install tornado

或者采用ubuntu内部工具apt-get来安装:

apt-get install python-tornado

前端选择

前端使用jquery和bootstrap框架,样式和表格等全部采用bootstrap风格,比较适合当前流行色,同时也能够自适应手机模式,方便在手机上操作容器。

数据库表

后端数据库采用mysql,数据库表一共有四个,分别是节点表、IP资源表、容器用途表和用户表。 
四个表的设计如下:

详细的介绍每个表字段。

节点表

class NodeDB(Base):
    __tablename__ = 'node'
    id         = Column(Integer, primary_key=True)  //自增关键字
    name       = Column(String(32))                  //节点的hostname
    ip         = Column(String(32))                        //节点IP地址
    port       = Column(String(32))                     //节点的管理端口
    cpus       = Column(String(32))                    //节点CPU个数
    mem        = Column(String(32))                  //节点内存数
    images     = Column(String(32))                 //节点上的镜像数
    state      = Column(String(32))                     //节点状态
    node_group = Column(String(32))           //节点所在的组 
    containers = Column(String(32))              //节点上的容器数
    os_version = Column(String(32))              //节点操作系统版本
    kernel_version = Column(String(32))       //节点内核版本
    docker_version = Column(String(32))      //节点上Docker engine版本

容器用途表

class ConUsageDB(Base):
    __tablename__ = 'con_usage'
    id        = Column(Integer, primary_key=True)  //自增关键字
    con_id    = Column(String(64))           //容器ID
    con_addr  = Column(String(32))       //容器IP地址
    node_ip   = Column(String(32))         //容器所在节点IP
    user_name = Column(String(32))     //容器用户名
    con_app   = Column(String(32))        //容器上运行app
    con_desc  = Column(String(256))     //容器其他描述

用户表

class UserDB(Base):
    __tablename__ = 'user'
    id         = Column(Integer, primary_key=True)  //自增关键字
    name       = Column(String(32))         //用户名
    password   = Column(String(64))     //用户密码
    user_group = Column(String(32))    //用户所在组

节点表、容器用途表和用户表组成整个管理系统的数据库表。对这三个表的操作,构成整个系统的40%功能,剩下的数据展示和操作是管理系统直接对节点操作完成。

第3章 管理系统开发

本章详细的介绍系统的实际编码过程。

3.1 构建环境

IDE选择

初步使用Pycharm作为python开发的IDE环境,目前有付费版和社区版,都能够提高开发效率。同时结合python的虚拟环境,对系统自由环境影响较小,也能够快速重建开发环境。

代码结构

代码初步采用MVC架构,分为handlers,model,static,templates 4个目录,4个目录的功能分别如下:

  • handlers:负责处理url逻辑,保证指定url展示正确
  • model:负责跟数据交互,并且格式化数据
  • static:负责存储css,js,images
  • templates: 负责存储静态html文件模板

容器环境

容器环境采用已经做好的虚拟机镜像的方式发送,简化大家安装容器,下载镜像的操作,快速构建开发对应的应用环境。在实际生产中,这部分工作可以由系统工程师来完成。虚拟化环境软件为virtualbox,可以根据官网来安装。虚拟机为ubuntu server 14.04 lts版本,具有很好的稳定性和易用性。容器版本为最新的1.11版,docker在1.9版本后并没有发行2.0版,而是采用了1.10版,预示着1.x将是长期版本。

3.2 用户管理

用户管理主要使用了tornado的安全认证方式。不仅解决了权限的控制,而且节约了大量的认证开发的时间。

整体访问流程如下:

User--------> '/'(已经认证)--------->WelcomeHandler(展示欢迎页面)
                     |
                     |
             没有认证或cookie超时------->login(登录页面登录)

从流程图上可以看见,tornado的认证系统主要是使用cookie来识别用户和做安全保护。当用户首次登录页面或者用户cookie过期后,将需要重新登录系统。 
整个过程中涉及到的方法和函数有:

import tornado.web

class BaseHandler(tornado.web.RequestHandler):
    def get_current_user(self):
        return self.get_secure_cookie("username")

class LoginHandler(BaseHandler):
    def get(self):
        self.render('login.html')

    def post(self):
        self.set_secure_cookie("username", self.get_argument("username"))
        self.redirect("/")

//调用tornado.web.authenticated装饰器来完成认证,保证在做get方法的时候先验证用户的cookie
class WelcomeHandler(BaseHandler):
    @tornado.web.authenticated
    def get(self):
        self.render('index.html', user=self.current_user)

class LogoutHandler(BaseHandler):
    def get(self):
        if (self.get_argument("logout", None)):
            self.clear_cookie("username")
            self.redirect("/")

跟url相关的代码:

application = tornado.web.Application([
    (r'/', WelcomeHandler),
    (r'/login', LoginHandler),
    (r'/logout', LogoutHandler)

实战:利用tornado的安全认证来编写登录 
整个编码过程以tornado框架为基础,实际展示

3.3 节点管理

节点管理

节点管理的整个流程图:


图3-1 节点管理的整个流程图

节点添加

这部分功能放到myswarm.py单独的模块中实现,在之后的很多操作中都要用到,便于重用。 
涉及到几个关键点

  • 页面展示的信息是从数据库获得保证节点信息能够长期存储
  • 添加节点直接插入到数据库
  • 检查添加节点是否有效并且刷新数据库信息 
    使用多线程来后台刷新节点信息,并且将节点信息写入数据库,保证页面能够快速返回数据

    节点添加-------->采集节点信息---->update DB------->展示节点信息

采集节点信息后,需要将所有信息update到数据库中,然后从数据库中获得节点信息展示给前端页面。这样流程上保证每次都能够获得节点的最新信息,特别实在节点镜像和容器数得到更新后。

节点删除

采集节点信息-------->update DB--------->展示节点-------->删除节点--------->删除成功

删除节点时,首先是对节点信息刷新,然后利用提供的删除按钮删除节点。

此外,管理系统在登录时会自动刷新节点信息,保证每次登录到系统后看到最新的节点统计信息(包括节点是否可以接通,节点上的镜像数,节点上容器数)

实战:编写节点操作代码

3.4 容器创建启动

容器创建启动

容器创建启动的整个流程: 

图3-2 容器创建启动

图3-2中简单的展示了容器创建和启动2个过程,首先容器的创建,之后是容器的启动。创建的过程中需要传输一定限定参数,而启动则是直接从创建完成的容器开始的。

容器创建

容器在创建过程中,首先选择容器的规格,包括容器的CPU、内存、运行命令和容器镜像选择。

CPU值:      包括CPU时间,CPU配额,CPU相对值
CPU时间:    相对值,基准值
CPU配额:   CPU时间的倍数,表示在基准时间上的时间数,用来表示逻辑CPU核数
CPU相对值:  CPU出现竞争时占用CPU的比例
内存大小:    容器占用内存的上限
运行命令:    容器启动时运行的命令
容器镜像:    运行时基准镜像

选择了以上这些值之后,将这些参数传递到后台进行处理。创建容器的过程如下:

user--------handler--------myswarm----------docker engine

用户发送容器创建的参数给容器engine,容器engine拿到了这些参数后创建好容器,等待下一步操作。 
实战: 容器创建编码

容器启动

容器启动操作相对比较简单,仅仅是给创建的容器发送运行命令,让创建后的容器启动起来。容器启动之后将创建后的容器插入到数据库中,保证后续的操作能够顺利进行。

user--------handler--------myswarm(DB)----------docker engine

容器启动是在容器创建之后进行的,得到了容器的ID之后,发送启动指令给容器engine启动容器。容器启动之后将从启动的容器中获得容器分配的桥接IP。

实战:容器启动编码

3.5 容器关闭删除

容器关闭和删除

图3-3 容器关闭和删除 
图3-3是容器的关闭和删除流程图。容器的关闭和删除实际操作过程比较相似,都是容器生命周期控制中的操作,主要区别是删除操作需要将容器用途中的容器信息删掉。

容器关闭

容器关闭相对比较简单,仅仅需要将关闭命令发送给容器 engine。该命令同样可以利用容器的python api。整个过程如下:

user-----------handler---------myswarm--------------docker engine

实战:容器关闭

容器删除

容器删除过程同样是发送关闭命令给容器engine,也是利用容器的python api。整个过程如下:

user------------handler---------myswarm(DB)-------------docker engine

删除操作需要额外的读写数据库操作,需要将容器用途中对应的容器删掉,保证容器用途表中的数据完整性。

实战:容器删除

3.6 用途管理

容器用途

图3-4 容器用途修改

图3-4 容器修改过程中需要修改数据库,将指定容器的用途信息存储到数据库中,方便日后对信息的查询。

添加容器信息

在容器创建后,容器相关信息需要记录下来,记录的信息包括容器使用者,容器用途,容器描述。整个过程只需要读写数据库,没有其他操作。

实战:添加容器信息 
此操作实际在容器创建过程中已经完成。

修改容器信息

先搜索到指定容器,然后修改容器相关信息,最后提交到数据库表中

实战:修改容器信息

posted on 2017-04-08 10:25  R_e  阅读(266)  评论(0)    收藏  举报

导航