基于配置库管理工具的电力系统容器部署研究
2017-04-08耿贞伟李少华权鹏宇
耿贞伟++李少华++权鹏宇
摘要:电力系统运行稳定性关系着千家万户电力供应的持续有效性,作为电力信息化的建设和运维主体单位,云南电网信息中心以云计算等核心技术支撑各业务系统的稳定运行。随着电力系统信息化的深入,各种应用服务需求增长迅速,原有服务部署方式呈现出资源利用率低,管理复杂,执行效率低等问题。因此对现有业务进行容器化改造,成为了一个必然的选择。另一方面,Docker本身还需要在主机上安装、管理和部署,同时主机也需要被管理起来。本文结合电网公司的实际情况提出了一种使用配置库管理工具部署容器的解决方案。
关键词:Docker;容器;电力系统;配置管理
中图分类号:TP311.5 文献标识码:A 文章编号:1007-9416(2017)02-0131-03
近年来,计算机技术飞速发展,大数据、云计算、容器化、微服务、平台战略等新技术和新概念层出不穷,电力系统为了在有限的资源下为了满足用户日益多样化的需求也不断采用新技术升级迭代,这在业务支撑、架构能力、平台扩展性等方面对旧有的烟囱式建设的业务支撑系统提出了巨大的挑战。这种情况下,容器技术因其轻量级虚拟化,标准化打包、封装、搬运,秒级快速启动,类似于积木的分层机制,简化开发版本管理等特点走入人们的视野。同时,Docker容器需要编排、管理和部署,也经常要与外部服务和工具通信,如何利用现有的配置管理工具自动化标准化配置,就成为了一个亟待解决的问题。本文首先阐明了容器技术的概念和特点,然后介绍了配置管理工具的概念及在容器部署中的作用,最后交待了如何使用Puppet来管理Docker容器。
1 容器技术
容器技术是一个在单一主机上提供多个隔离运行环境的操作系统级虚拟技术。容器是直接运行在操作系统内核之上的用户空间,只能运行与底层宿主机相同或相似的操作系统。容器运行不需要模拟层和管理层,而是使用操作系统的系统调用接口,因此相比虚拟机宿主机中可以运行更多的容器。容器概览图1所示。
容器隔离了应用,操作系统资源已经被Docker抽象隔离了,如上图右方,容器以层的概念建立,多个容器可以共享一个底层,降低资源的使用。
对于容器环境来说,需要首先安装主机操作系统,之后将容器层安装在主机操作系统之上。在安装完容器层之后,就可以从系统可用计算资源当中分配容器实例了,并且企业应用可以被部署在容器当中。每个容器化应用都会共享相同的操作系统。
容器使应用程序的跨平台移植比以往任何时候都更容易,通过允许在开发工作站上构建和测试的同一镜像运行在生产环境中,解决了开发环境与生产环境差异的问题。
2 配置管理工具
配置管理工具作为配置管理的重要组成部分,其目标是完成新上线服务器的配置和现有线上服务配置的更新等任务的标准化和自动化。配置管理工具在以下3个方面能帮到Docker用户。
(1)配置和维护Docker宿主机。这包括从带有基础操作系统的新硬件的上线到Docker服务的安装和配置,以及确保这些宿主机上安装了最新的安全补丁。(2)Docker容器和Docker镜像的管理。这涵盖了从容器镜像的整个生命周期(镜像的创建、推送等)到实际运行这些镜像的容器的运行和管理。(3)构建镜像。尽管Docker可以很便利的将软件和配置打包成镜像,很多时候在容器里运行的软件还是需要通过配置管理指令来安装和配置。通过配置管理工具,用户可以直接使用在虚拟机上安装应用软件的方式将应用软件安装到Docker容器。
3 使用puppet管理docker
Puppet官方不直接提供专用的manifest,用户可以使用Puppet的一个由Gareth Rushgrove提供的garethr-docker模块来完成Docker宿主机、镜像以及容器的安装和管理等工作。该模块在容器安装、镜像管理、容器启动、网络管理、编排、私有registry等方面為Docker提供多样化的支持。
3.1 容器安装
默认情况下Puppet会在需要时在系统上建立Docker宿主仓库,并安装Docker包。Docker守护进程会默认绑定到一个位于/var/run/docker.sock的unix套接字。我们可以使用下面的指令改变套接字,同时在需要的情况下绑定到一个tcp套接字:
class { 'docker':
tcp_bind => ['tcp://127.0.0.1:4243','tcp://10.0.0.1:4243'],
socket_bind => 'unix:///var/run/docker.sock',
ip_forward => true,
iptables => true,
ip_masq => true,
bridge => br0,
fixed_cidr => '10.20.1.0/24',
default_gateway => '10.20.0.1',
}
如果要以安全传输层协议建立连接,需要上传相关文件(如CA证书,服务器证书及密钥),并在manifest中给出它们的路径:
class{'docker':
tcp_bind => ['tcp://0.0.0.0:2376'],
tls_enable => true,
tls_cacert => '/etc/docker/tls/ca.pem',
tls_cert => '/etc/docker/tls/cert.pem',
tls_key => '/etc/docker/tls/key.pem',
}
Puppet将在第一次运行的时候默认从Docker仓库安装最新版本的Docker。可以通过下面的指令安装指定的Docker版本:
class { 'docker':
version => '0.5.5',
}
有些情况下,DNS解析不能在容器内正常运行,可以通过如下方式为Docker守护进程指定DNS服务器:
class{'docker':
dns => '8.8.8.8',
}
如果要为Docker组添加用户,可以如下传递一个数组:
class { 'docker':
docker_users => ['user1', 'user2'],
}
同样可以通过传递一个数组来添加守护标签:
class { 'docker':
labels => ['storage=ssd','stage=production'],
}
3.2 镜像管理
镜像是容器的静态体现,是一个还没有运行起来的“运行环境”,是Docker生命周期中的构建阶段,是启动容器的只读模板。Docker通过把应用的运行时环境和应用打包在一起,解决了部署环境依赖的问题。
安装镜像的时候,可以通过下面的指令拉取镜像:
docker::image { 'base': }
这条命令有可选的参数image_tag,用来选取同一仓库中多个镜像之一:
docker::image { 'ubuntu':
image_tag => 'precise'
}
还可以使用docker_file属性或docker_dir属性添加鏡像。也可以通过订阅如Dockerfile改变之类的外部事件来触发镜像重构,使镜像重构更加自动化:
docker::image { 'ubuntu':
docker_file => '/tmp/Dockerfile'
subscribe => File['/tmp/Dockerfile'],
}
file { '/tmp/Dockerfile':
ensure => file,
source => 'puppet:///modules/someModule/Dockerfile',
}
在一个镜像不再需要的时候,可以方便的及时移除:
docker::image { 'base':
ensure => 'absent'
}
3.3 容器启动
在使用Docker时,执行最多的命令莫过于run,它是Docker操作的入口。Docker在执行时会将相关进程封装到相互隔离的容器中。当执行 Docker Run时,Docker会启动一个进程,同时给这个进程分配其独占的文件系统,独占的网络资源和以此进程为根进程的进程组。在Docker启动容器时加载的镜像,或许已经定义好了默认的启动进程,需要公开的网络端口和其他在Dockerfile中定义好的资源,使用Docker Run 可以对其重新进行定义。
Puppet使用docker::run封装Docker Run。在拥有一个镜像之后,即可以使用docker::run启动容器:
docker::run { 'helloworld':
image => 'base',
command => '/bin/sh -c "while true; do echo hello world; sleep 1; done"',
}
run命令也包含许多可选参数:(1)pull_on_start:在每次容器启动前都拉取镜像;(2)before_stop:在停止容器前执行一条命令;(3)after:用于表示必须在此之前启动的容器;(4)depends:用于表示容器之间的依赖关系。依赖的容器将在此容器之前启动,在此容器之后停止;(5)depend_services:用于指定需要在容器之前启动的依赖的通用服务(非docker);(6)extra_parameters:数组中存放要传递给docker run命令的额外参数。
默认情况下,生成的初始化脚本将会在服务停止或启动后移除容器。可以通过如下修改改变此行为:
docker::run { 'helloworld':
remove_container_on_start => true,
remove_volume_on_start => false,
remove_container_on_stop => true,
remove_volume_on_stop => false,
}
3.4 网络管理
随着Docker在实际生产环境中的应用,网络功能的重要性日益突出。从Docker 1.9开始,Docker提供对网络功能的官方支持。通过对Network Namespace的操纵,Docker提供了五种容器网络模式:
(1)none:不为容器配置任何网络功能。(2)container:与另一个运行中的容器共享Network Namespace及网络视图。(3)host:与主机共享Root Network Namespace,容器有完整的权限可以操纵主机的协议栈、路由表和防火墙等。(4)bridge:Docker设计的NAT网络模型,在此模式下,Docker容器与Internet的通信,以及不同容器之间的通信,都是通过iptables规则控制的。(5)overlay:Docker原生的跨主机多子网模型,其底层需要类似consul或etcd的KV存储系统进行消息同步,核心是通过Linux网桥与vxlan隧道实现主机划分子网。
在Puppet的garethr-docker模块中,我们通过docker_network来管理网络功能:
docker_network { 'my-net':
ensure =>present,
driver =>'overlay',
subnet =>'192.168.1.0/24',
gateway =>'192.168.1.1',
ip_range =>'192.168.1.4/32',
}
其中只有ensure和name是必填项。如果不给driver赋值,Docker网络会使用默认网桥,然后定义过的网络就可以在docker::run资源中使用net参数使用了。
3.5 编排
Docker Compose是用于定义和运行复杂Docker应用的工具。用户可以在一个文件中定义一个多容器的应用,然后使用一条命令来启动应用,然后所有相关的操作都会被自动完成。
模块中包含的docker_compose类型允许使用Puppet来运行Compose。因此可以使用Puppet修复容器问题,并且结果将与Compose文件中的模型匹配。
使用docker_compose类型之前需要确保docker-compose工具已经安装:
docker_compose { '/tmp/docker-compose.yml':
ensure => present,
}
然后以如下方式定义一个指向Compose文件的docker_compose资源:
docker_compose { '/tmp/docker-compose.yml':
ensure => present,
}
在Puppet運行的时候,就会自动的执行需要的Compose。
Docker_compse可以接受伸缩规则和附加项,根据用户定义的多种策略(时间表、运行状态等)自动的实现IT资源扩展或收缩,以便在避免IT资源过度配置的情况下保持足够的性能,同时降低管理费用。下面的例子中,需要两个容器来运行,Puppet将在运行给定服务的容器的数量与提供的伸缩值不匹配的时候运行Compose。
docker_compose { '/tmp/docker-compose.yml':
ensure => present,
scale => {
'compose_test' => 2,
},
options => '--x-networking'
}
3.6 私有registry
Docker Registry是构建仓库的核心,旨在实现镜像的创建、存储、分发和更新等功能。在用户希望构建和存储不想被公开的信息或数据的镜像时,就需要利用Docker Hub上的私有仓库或者在防火墙后运行自己的registry。除非指定私有registry,模块从index.docker.io拉取和推送镜像。如果私有registry无需认证,可以完全限定镜像名称;如果私有registry要求认证,需要配置registry:
docker::registry { 'example.docker.io:5000':
username => 'user',
password => 'secret',
email => 'user@example.com',
}
在不需要registry的时候可以采用如下方式退出:
docker::registry { 'example.docker.io:5000':
ensure => 'absent',
}
4 研究结论
Docker因其技术优势正在取得越来越广泛的应用,但Docker依然存在一些问题:Dockerfile在对应用程序的运行环境的控制上不如配置文件灵活,可能需要针对不同环境编写不同的Dockerfile;Docker的安全模式也决定了中间层开发者可能会污染下层容器。另一方面,时下的配置管理工具已经在配置和维护Docker宿主机、管理Docker容器和Docker镜像、构建镜像等方面提供对Docker的支持。因此,面对微服务架构的多代码敏捷性版本更迭,通过配置管理的自动化和可视化来管理容器代码的部署是必要且可行的。
参考文献
[1]陈星宇.基于容器云平台的网络资源管理与配置系统设计与实现[D].浙江:浙江大学,2016.
[2]王飞.基于Docker的研发部署管理平台的设计与实现[D].北京:北京交通大学,2015.
[3]高飞,李勇.Docker容器资源管控配置实战[J].程序员,2014(9):96-101.
[4][美]Joe Jhonston,[西]Antonio Bathelli,[英]Justin Cormack,[美]John Fiedler,[英]Milos Gajdos. Docker生产环境实践指南[M].吴佳兴,梁晓勇.译.北京:人民邮电出版社,2016.
[5]华为Docker实践小组.Docker进阶与实战[M].北京:机械工业出版社,2016.