京东从OpenStack切换到Kubernetes的经验之谈

背景介绍 2016年底,京东新一代容器引擎平台JDOS2.0上线,京东从OpenStack切换到Kubernetes。到目前为止,JDOS2.0集群2w+Pod稳定运行,业务按IDC分布分批迁移到新平台,目前已迁移20%,计划Q2全部切换到Kubernetes上,业务研发人员逐渐适应从基于自动部署上线切换到以镜像为中心的上线方式。JDOS2.0统一提供京东业务,大数据实时离线,机器学习(GPU)计算集群。从OpenStack切换到Kubernetes,这中间又有哪些经验值得借鉴呢? 本文将为读者介绍京东商城研发基础平台部如何从0到JDOS1.0再到JDOS2.0的发展历程和经验总结,主要包括: 如何找准痛点作为基础平台系统业务切入点; 如何一边实践一边保持技术视野; 如何运维大规模容器平台; 如何把容器技术与软件定义数据中心结合。 集群建设历史 物理机时代(2004-2014) 在2014年之前,公司的应用直接部署在物理机上。在物理机时代,应用上线从申请资源到最终分配物理机时间平均为一周。应用混合部署在一起,没有隔离的应用混部难免互相影响。为减少负面影响,在混部的比例平均每台物理机低于9个不同应用的Tomcat实例,因此造成了物理机资源浪费严重,而且调度极不灵活。物理机失效导致的应用实例迁移时间以小时计,自动化的弹性伸缩也难于实现。为提升应用部署效率,公司开发了诸如编译打包、自动部署、日志收集、资源监控等多个配套工具系统。 容器化时代(2014-2016) 2014年第三季度,公司首席架构师刘海锋带领基础平台团队对于集群建设进行重新设计规划,Docker容器是主要的选型方案。当时Docker虽然已经逐渐兴起,但是功能略显单薄,而且缺乏生产环境,特别是大规模生产环境的实践。团队对于Docker进行了反复测试,特别是进行了大规模长时间的压力和稳定性测试。根据测试结果,对于Docker进行了定制开发,修复了Device Mapper导致crash、Linux内核等问题,并增加了外挂盘限速、容量管理、镜像构建层级合并等功能。 对于容器的集群管理,团队选择了OpenStack+nova-docker的架构,用管理虚拟机的方式管理容器,并定义为京东第一代容器引擎平台JDOS1.0(JD DataCenter OS)。JDOS1.0的主要工作是实现了基础设施容器化,应用上线统一使用容器代替原来的物理机。在应用的运维方面,兼用了之前的配套工具系统。研发上线申请计算资源由之前的一周缩短到分钟级,不管是1台容器还是1千台容器,在经过计算资源池化后可实现秒级供应。同时,应用容器之间的资源使用也得到了有效的隔离,平均部署应用密度提升3倍,物理机使用率提升3倍,带来极大的经济收益。 我们采用多IDC部署方式,使用统一的全局API开放对接到上线系统,支撑业务跨IDC部署。单个OpenStack集群最大是1万台物理计算节点,最小是4K台计算节点,第一代容器引擎平台成功地支撑了2015和2016年的618和双十一的促销活动。至2016年11月,已经有15W+的容器在稳定运行。 在完成的第一代容器引擎落地实践中,团队推动了业务从物理机上迁移到容器中来。在JDOS1.0中,我们使用的IaaS的方式,即使用管理虚拟机的方式来管理容器,因此应用的部署仍然严重依赖于物理机时代的编译打包、自动部署等工具系统。但是JDOS1.0的实践是非常有意义的,其意义在于完成了业务应用的容器化,将容器的网络、存储都逐渐磨合成熟,而这些都为我们后面基于1.0的经验,开发一个全新的应用容器引擎打下了坚实的基础。 新一代应用容器引擎(JDOS 2.0) 1.0的痛点 JDOS1.0解决了应用容器化的问题,但是依然存在很多不足。 首先是编译打包、自动部署等工具脱胎于物理机时代,与容器的开箱即用理念格格不入,容器启动之后仍然需要配套工具系统为其分发配置、部署应用等等,应用启动的速度受到了制约。 其次,线上线下环境仍然存在不一致的情况,应用运行的操作环境,依赖的软件栈在线下自测时仍然需要进行单独搭建。线上线下环境不一致也造成了一些线上问题难于在线下复现,更无法达到镜像的“一次构建,随处运行”的理想状态。 再次,容器的体量太重,应用需要依赖工具系统进行部署,导致业务的迁移仍然需要工具系统人工运维去实现,难以在通用的平台层实现灵活的扩容缩容与高可用。...

Jenkins+Ansible+Gitlab自动化部署三剑客

最近一直在学习Ansible的一些playbook的写法, 所以一直没有怎么更新, 想到目前大家对诸如saltstack, docker, Ansible等自动化部署相关的工具很感兴趣, 但又苦于没有可学习的中文实例, 这里我就把我这几个月所接触到目前国外比较流行的部署经验给大家分享一下. 首先给大家介绍的是Ansible, 恩, 重要的问题说三遍, 不是Saltstack, Ansible作为一个python写的自动化部署工具, 确实较之前我所接触的Chef, saltstack, puppet更有自己的一些优势, 首先就是agentless, 无需在Linux client安装任何服务即可无缝连接Linux default ssh端口进行部署(windows需要安装winrm 开启ssh服务), 这点其实我觉得非常重要, 可以想象很多公司本身是对network管理非常严格的, 在部署一个产品的同时你需要考虑很多时间成本, 使用其他部署工具本身非常棘手的问题就是去申请开端口,...

CentOS6.7下Ansible部署

Ansible是一种集成IT系统的配置管理, 应用部署, 执行特定任务的开源平台. 它基于Python语言实现, 部署只需在主控端部署Ansible环境, 被控端无需安装代理工具, 只需打开SSH, 让主控端通过SSH秘钥认证对其进行所有的管理监控操作. 相对于SaltStack, 它除了利用SSH安全传输, 无需在客户端进行任何配置, 而且它有一个很庞大的用户群体以及丰富的API, 相对适合部署到数量比较大且对系统软件安装要求比较严格的集群中. 更多配置参考: https://github.com/ansible 官方文档: http://docs.ansible.com/ansible 本文将帮助大家如何快速部署一个Ansible平台. 安装环境: System: Centos 6.7 x64 Master: master.example.com Minion: client01.example.com...

Dockerfile详解

Docker可以通过获取Dockerfile编写的命令自动Build出一个新的镜像,里面的Docker内建命令会帮助我们在已有的image下创建一个新的定制image. 这里我们先给大家介绍一些常用Dockerfile编写规范. Docker配置传送门: http://www.showerlee.com/archives/1758 1.FROM FROM <image>:<tag> FROM会使用当前本地或者远程Docker仓库的image, 这个要首先写到该脚本的第一行. 例: FROM centos67base/apache:apache_base 这里代表我们使用本地的centos67base/apache镜像. 查看本地缓存镜像可以使用 # docker images 2.MAINTAINER MAINTAINER <name> 这个会给生成的镜像创建一个作者名 3.RUN RUN <command> (命令行格式, 执行一段shell命令)...

是时候支持HTTPS了:免费SSL证书letsencrypt配置教程

今天抽空将 blog 增加了 HTTPS 支持,并停止了原来的 HTTP 服务。 由于证书仅网站域名需要,因此使用了免费的 Let’s Encrypt 证书服务。 根据维基百科的说明,Let’s Encrypt 是一个于2015年三季度推出的数字证书认证机构,将通过旨在消除当前手动创建和安装证书的复杂过程的自动化流程,为安全网站提供免费的SSL/TLS证书。Let’s Encrypt 是由互联网安全研究小组(ISRG,一个公益组织)提供的服务。主要赞助商包括电子前哨基金会,Mozilla 基金会,Akamai 以及思科。 2015年12月3日,该服务进入公测阶段,正式面向公众。 2016年4月12日,该项目正式离开Beta阶段。 到2016年9月9日,Let’s Encrypt 已经发放 1000 万张证书。因此对于大部分中小型网站来说,是一个值得考虑的选择。...

Kubernetes – Google分布式容器技术初体验

Kubernetes是Google开源的容器集群管理系统。前几天写的 分布式服务框架的4项特性 中提到一个良好的分布式服务框架需要实现 服务的配置管理。包括服务发现、负载均衡及服务依赖管理。 服务之间的调度及生命周期管理。 由于Kubernetes包含了上述部分特性,加上最近Google新推出的Container Engine也是基于Kubernetes基础上实现,因此最近对Kubernetes进行了一些尝试与体验。 运行环境 Kubernetes目前处于一个快速迭代的阶段,同时它的相关生态圈(比如docker,etcd)也在快速发展,这也意味没有适合新手使用非常顺畅的版本,网上的各种文档(也包括官方文档)和当前最新的发布版会有不同程度滞后或不适用的情况,因此在使用时可能会碰到各种细节的障碍,而且这些新版本碰到的问题,很有可能在网上也搜索不到解决方案。 Kubernetes设计上并未绑定Google Cloud平台,但由于以上原因,为了减少不必要的障碍,初次尝试建议使用GCE作为运行环境(尽管GCE是一个需要收费的环境)。默认的cluster启动脚本会创建5个GCE instance,测试完需要自己及时主动删除。为了避免浪费,可以将minions减少,同时instance类型选择f1-micro。费用方面一个f1-micro instance运行1个月大约50元人民币,因此用GCE来测试Kubernetes,如果仅是测试时候开启的话,并不会产生太多费用。 Pods及Replication Controller Kubernetes的基本单元是pods,用来定义一组相关的container。Kubernetes的优点是可以通过定义一个replicationController来将同一个模块部署到任意多个容器中,并且由Kubernetes自动管理。比如定义了一个apache pod,通过replicationController设置启动100个replicas,系统就会在pod创建后自动在所有可用的minions中启动100个apache container。并且轻松的是,当container或者是所在的服务器不可用时,Kubernetes会自动通过启动新的container来保持100个总数不变,这样管理一个大型系统变得轻松和简单。 Service 微服务 在解决部署问题之后,分布式服务中存在的一大难题是服务发现(或者叫寻址),用户访问的前端模块需要访问系统内部的后端资源或者其他各种内部的服务,当一个内部服务通过replicationController动态部署到不同的节点后,而且还存在前文提到的动态切换的功能,前端应用如何来发现并访问这些服务?Kubernetes的另外一个亮点功能就是service,service是一个pod服务池的代理抽象,目前的实现方法是通过一个固定的虚拟IP及端口来定义,并且通过分布在所有节点上的proxy来实现内部服务对service的访问。 Kubernetes自身的配置是保存在一个etcd(类似ZooKeeper)的分布式配置服务中。服务发现为什么不通过etcd来实现?Tim的判断更多的是为了Kubernetes上的系统和具体的配置服务解耦。由于服务发现属于各个系统内部的业务逻辑,因此如果使用etcd将会出现业务代码的逻辑中耦合了etcd,这样可能会让很多架构师望而却步。 尽管没有耦合etcd,部署在Kubernetes中的服务需要通过container中的环境变量来获得service的地址。环境变量虽然简单,但它也存在很多弊端,如存在不方便动态更改等问题。另外service目前的实现是将虚拟IP通过iptables重定向到最终的pod上,作者也提到iptables定向的局限性,不适合作为大型服务(比如上千个内部service一起运作时)的实现。 由于service定位是系统内部服务,因此默认情况下虚拟IP无法对外提供服务,但Kubernetes当前版本并没直接提供暴露公网IP及端口的能力,需要借助云服务(比如GCE)的load balancer来实现。 小结 总的看来Kubernetes提供的能力非常令人激动,pod、replicationController以及service的设计非常简单实用。但如果立即将服务迁移到Kubernetes,还需要面对易变的环境。另外尽管Kubernetes提供health...

分布式机器学习的故事:Docker改变世界

Docker最近很火。Docker实现了“集装箱”——一种介于“软件包”和“虚拟机”之间的概念——并被寄予厚望,以期革新Internet服务以及其他大数据处理系统的开发、测试、和部署流程。 为了使用Docker,需要了解不少工具及其设计思路;而这些工具的文档分布在不同的网站。为了方便大家学习,本文以开发一个极简的搜索引擎为例,展示Docker带来的革新。 说是革新,其实是Google已经用了十年的方式,只是最近才因为Docker开源项目而广为人知。Eric Brewer(Google VP of Infrastructure)在Dockercon14活动上的演讲回顾了这段历程。目前,Google每周会执行20亿个集装箱。可以说,最近十年是各互联网公司和高校都在奋力模仿Google的计算技术的十年。了解这一模仿的过程,可以帮助我们深入理解分布式系统(包括现在常说的“大数据系统”)中若干重要问题。为此,本文以技术教程为主线,穿插了一些关于Hadoop和Mesos等“模仿”项目的介绍,简要追溯它们勇敢而艰难的“邯郸学步”的历程。最后,本文会介绍Google最近公布的“正确答案”——Kubernetes——Google核心技术Borg的开源版本。 Docker Docker是一个软件系统,实现了一种称为“集装箱”的概念。集装箱类似Google机群管理系统Borg中的包(package)。 通常我们说的“包”是软件包——比如Ubuntu/Debian Linux里常见的.deb文件——安装的时候,安装程序会把被依赖的包也装上。可是执行的时候呢?得根据具体情况配置,然后依次启动互相依赖的多个程序。比如,启动一个Web服务之前,要启动Apache和MySQL;而且他们仨都得有合理的配置,确保它们能一起工作,来实现这个Web服务。 但是Docker集装箱以及Borg中的包更像虚拟机。虚拟机里包括程序和配置,所以可以被执行——也就是执行其中的程序。因为程序是配置好的,所以虚拟机可以被扔到各种环境上去执行——包括开发机、做演示用的笔记本电脑、用VirtualBox虚拟的机群、测试机群、预发布环境和产品环境。近几年随着“云计算”概念的普及,虚拟机被广泛使用,作为分布式计算的基础调度单元。 Docker作为一个软件系统,可以用来创建“集装箱镜像”(container image)和执行这些镜像。就像VirtualBox是一个软件系统,可以用来创建和执行虚拟机。但是集装箱比虚拟机“轻”——一个虚拟机包括一组虚拟硬件、操作系统,用来执行用户程序;而集装箱里没有虚拟的硬件,也没有操作系统,它用主机(host)的硬件和操作系统来执行程序。 那么在集装箱里跑程序和直接在主机上跑有什么区别呢?一个区别是,集装箱有一套网络端口空间(port space)。一个集装箱里的进程可以各自开端口,也可以连接对方的端口进行通信。但是这些端口是集装箱之外的进程看不到的。我们也可以让集装箱把某些内部端口号展示给外部,比如把集装箱内的端口5000映射到外部的8080。这样,当我们用主机上的程序(比如浏览器)访问本机(主机)的8080端口时,实际上访问的是集装箱里的5000端口。这项对外公开集装箱内部端口的技术,称为端口转发(port forwarding),和虚拟机的端口转发概念一样。另一个区别在于,集装箱里有虚拟的文件系统。这样我们可以把要执行的程序拷贝进集装箱。也可以把主机上的某些目录映射成集装箱虚拟文件系统的某些目录。 集装箱这个想法已经在深刻地改变传统分布式系统的开发、测试和部署的流程了。传统的做法是,开发者写一个Makefile(或者其他描述,比如CMakeList、POM等)来说明如何把源码编译成二进制文件。随后,开发人员会在开发机上配置并且执行二进制文件,来作测试。测试人员会在测试机群上配置和执行,来作验证。而运维人员会在数据中心里的预发布环境和产品环境上配置和执行,这就是部署。因为开发机、测试机群、和产品环境里机器的数量和质量都不同,所以配置往往很不同。加上每个新版本的软件系统,配置方式难免有所差异,所以经常造成意外错误。以至于绝大部分团队都选择趁夜深人静、用户不活跃的时候,上线新版本,苦不堪言。 而利用集装箱概念的开发流程里,开发者除了写Makefile,还要写一个Dockerfile,来描述如何把二进制文件安装进一个集装箱镜像(container image),并且做好配置。而一个镜像就像一台配置好的虚拟机,可以在机群上启动多个实例(instance),而每个实例通常称为一个集装箱(container)。在自测的时候,开发者在开发机上执行一个或者多个集装箱;在验证时,测试人员在测试机群上执行集装箱;在部署时,运维人员在产品环境执行集装箱。因为执行的都是同样地集装箱,所以不容易出错。 这种流程更合理的划分了开发者和其他角色的工作边界,也大大简化了测试和部署工作。 boot2docker 上节提到,Docker虚拟了网络地址空间和文件系统。实际上,它还虚拟了进程ID空间(pid space)等系统数据结构。这些功能是一个叫dockerd的daemon程序借助Linux内核中的control groups(又叫cgroups)功能实现的。...

64位CentOS7中静态IP,DNS的配置

我是在虚拟机中安装的CentOS7,采用的是桥接模式。起初CentOS内的地址是动态获取的,想把它固定下来。 按照网上查到的资料,通过修改/etc/sysconfig/network-scripts/下的配置文件,重启后网络服务,暂时能把IP地址修改了,但是配置中的DNS始终没有生效,这样就无法访问外部网络(实际上也不是不能访问,只是不能通过域名访问,比如你要ping一个外部公网上的ip地址是通的,但你要访问一个网址需要域名解析就不行了) 还有的问题是,这个虚拟机重启后,发现修改的配置文件中的设置还是没有生效,还是需要重启网络服务,折腾好久,一直不明白为什么。后来终于知道,是因为NetManager在捣鬼。 下面是转载的:https://Linux.cn/article-3977-1.html,有较大的参考价值,前面的第一种方法我试过了,对我的机器不管用,重启后依然设置无效。第二种方法是可以的。 如果你想要为CentOS 7中的某个网络接口设置静态IP地址,有几种不同的方法,这取决于你是否想要使用网络管理器。 网络管理器(Network Manager)是一个动态网络的控制器与配置系统,它用于当网络设备可用时保持设备和连接开启并激活。默认情况下,CentOS/RHEL 7安装有网络管理器,并处于启用状态。 使用下面的命令来验证网络管理器服务的状态: $ systemctl status NetworkManager.service 运行以下命令来检查受网络管理器管理的网络接口: $ nmcli dev status 如果某个接口的nmcli的输出结果是“已连接”(如本例中的enp0s3),这就是说该接口受网络管理器管理。你可以轻易地为某个特定接口禁用网络管理器,以便你可以自己为它配置一个静态IP地址。 下面将介绍在CentOS 7上为网络接口配置静态IP地址的两种方式,在例子中我们将对名为enp0s3的网络接口进行配置。 不使用网络管理配置静态IP地址 进入/etc/sysconfig/network-scripts目录,找到该接口的配置文件(ifcfg-enp0s3)。如果没有,请创建一个。 打开配置文件并编辑以下变量:...