首页 文章 精选 留言 我的

精选列表

搜索[搭建],共10000篇文章
优秀的个人博客,低调大师

学习使用Docker、Docker-Compose和Rancher搭建部署Pipeline(一)

这篇文章是一系列文章的第一篇,在这一系列文章中,我们想要分享我们如何使用Docker、Docker-Compose和Rancher完成容器部署工作流的故事。我们想带你从头开始走过pipeline的革命历程,重点指出我们这一路上遇到的痛点和做出的决定,而不只是单纯的回顾。幸好有很多优秀的资源可以帮助你使用Docker设置持续集成和部署工作流。这篇文章并不属于这些资源之一。一个简单的部署工作流相对比较容易设置。但是我们的经验表明,构建一个部署系统的复杂性主要在于原本容易的部分需要在拥有很多依赖的遗留环境中完成,以及当你的开发团队和运营组织发生变化以支持新的过程的时候。希望我们在解决构建我们的pipeline的困难时积累下的经验会帮助你解决你在构建你的pipeline时遇到的困难。 在这第一篇文章里,我们将从头开始,看一看只用Docker时我们开发的初步的工作流。在接下来的文章中,我们将进一步介绍Docker-compose,最后介绍如何将Rancher应用到我们的工作流中。 为了为之后的工作铺平道路,假设接下来的事件都发生在一家SaaS提供商那里,我们曾经在SaaS提供商那里提供过长时间服务。仅为了这篇文章的撰写,我们姑且称这家SaaS提供商为Acme Business Company, Inc,即ABC。这项工程开始时,ABC正处在将大部分基于Java的微服务栈从裸机服务器上的本地部署迁移到运行在AWS上的Docker部署的最初阶段。这项工程的目标很常见:发布新功能时更少的前置时间(lead time)以及更可靠的部署服务。 为了达到该目标,软件的部署计划大致是这样的: 这个过程从代码的变更、提交、推送到git仓库开始。当代码推送到git仓库后,我们的CI系统会被告知运行单元测试。如果测试通过,就会编译代码并将结果作为产出物(artifact)存储起来。如果上一步成功了,就会触发下一步的工作,利用我们的代码产出物创建一个Docker镜像并将镜像推送到一个Docker私有注册表(private Docker registry)中。最后,我们将我们的新镜像部署到一个环境中。 要完成这个过程,如下几点是必须要有的: 一个源代码仓库。ABC已经将他们的代码存放在GitHub私有仓库上了。 一个持续集成和部署的工具。ABC已经在本地安装了Jenkins。 一个私有registry。我们部署了一个Docker registry容器,由Amazon S3支持。 一个主机运行Docker的环境。ABC拥有几个目标环境,每个目标环境都包含过渡性(staging)部署和生产部署。 这样去看的话,这个过程表面上简单,然而实际过程中会复杂一些。像许多其它公司一样,ABC曾经(现在仍然是)将开发团队和运营团队划分为不同的组织。当代码准备好部署时,会创建一个包含应用程序和目标环境详细信息的任务单(ticket)。这个任务单会被分配到运营团队,并将会在几周的部署窗口内执行。现在,我们已经不能清晰地看到一个持续部署和分发的方法了。 最开始,部署任务单可能看起来是这样的: 1 2 3 DEPLOY- 111 : App:JavaService1,branch "release/1.0.1" Environment:Production 部署过程是: 部署工程师用了一周时间在Jenkins上工作,对相关的工程执行”Build Now“,将分支名作为参数传递。之后弹出了一个被标记的Docker镜像。这个镜像被自动的推送到了注册表中。工程师选择了环境中的一台当前没有在负载均衡器中被激活的Docker主机。工程师登陆到这台主机并从注册表中获取新的版本。 1 dockerpullregistry.abc.net/javaservice1:release- 1.0 . 1 找到现存的容器。 1 dockerps 终止现存容器运行。 1 dockerstop[container_id] 开启一个新容器,这个容器必须拥有所有正确启动容器所需的标志。这些标志可以从之前运行的容器那里,主机上的shell历史,或者其它地方的文档借鉴。 1 dockerrun-d-p 8080 : 8080 …registry.abc.net/javaservice1:release- 1.0 . 1 连接这个服务并做一些手工测试确定服务正常工作。 1 curllocalhost: 8080 /api/v1/version 在生产维护窗口中,更新负载均衡器使其指向更新过的主机。 一旦通过验证,这个更新会被应用到环境中所有其它主机上,以防将来需要故障切换(failover)。 不可否认的是,这个部署过程并不怎么让人印象深刻,但这是通往持续部署伟大的第一步。这里有好多地方仍可改进,但我们先考虑一下这么做的优点: 运营工程师有一套部署的方案,并且每个应用的部署都使用相同的步骤。在Docker运行那一步中需要为每个服务查找参数,但是大体步骤总是相同的:Docker pull、Docker stop、Docker run。这个过程非常简单,而且很难忘掉其中一步。 当环境中最少有两台主机时,我们便拥有了一个可管理的蓝绿部署(blue-green deployment)。一个生产窗口只是简单地从负载均衡器配置转换过来。这个生产窗口拥有明显且快速的回滚方法。当部署变得更加动态时,升级、回滚以及发现后端服务器变得愈发困难,需要更多地协调工作。因为部署是手动的,蓝绿部署代价是最小的,并且同样能提供优于就地升级的主要优点。 好吧,现在看一看痛点: 重复输入相同的命令。或者更准确地说,重复地在bash命令行里敲击输入。解决这一点很简单:使用自动化技术!有很多工具可以帮助你启动Docker容器。对于运营工程师,最明显的解决方案是将重复的逻辑包装成bash脚本,这样只需一条命令就可以执行相应逻辑。如果你将自己称作一个开发-运营(devops)工程师,你可能会去使用Ansible、Puppet、Chef或者SaltStack。编写脚本或剧本(playbooks)很简单,但是这里仍有几个问题需要说明:部署逻辑到底放在那里?你怎样追踪每个服务的不同参数?这些问题将带领我们进入下一点。 即便一个运营工程师拥有超能力,在办公室工作一整天后的深夜里仍能避免拼写错误,并且清晰的思考,他也不会知道有一个服务正在监听一个不同的端口并且需要改变Docker端口参数。问题的症结在于开发者确实了解应用运行的详细信息(但愿如此),但是这些信息需要被传递给运营团队。很多时候,运营逻辑放在另外的代码仓库中或这根本没有代码仓库。这种情况下保持应用相关部署逻辑的同步会变得困难。由于这个原因,一个很好的做法是将你的部署逻辑只提交到包含你的Dockerfile的代码仓库。如果在一些情况下无法做到这点,有一些方法可以使这么做可行(更多细节将在稍后谈到)。把细节信息提交到某处是重要的。代码要比部署任务单好,虽然在一些人的脑海中始终认为部署任务单更好。 可见性。对一个容器进行一个故障检测须要登陆主机并且运行相应命令。在现实中,这就意味着登陆许多主机然后运行“docker ps”和“docker logs –tail=100”的命令组合。有很多解决方案可以做到集中登陆。如果你有时间的话,还是相当值得设置成集中登陆的。我们发现,通常情况下我们缺少的能力是查看哪些容器运行在那些主机上的。这对于开发者而言是个问题。开发者想要知道什么版本被部署在怎样的范围内。对于运营人员来说,这也是个主要问题。他们须要捕获到要进行升级或故障检测的容器。 基于以上的情况,我们开始做出一些改变,解决这些痛点。 第一个改进是写一个bash脚本将部署中相同的步骤包装起来。一个简单的包装脚本可以是这样的: 1 2 3 4 5 6 !/bin/bash APPLICATION=$ 1 VERSION=$ 2 dockerpull "registry.abc.net/${APPLICATION}:${VERSION}" dockerrm-f$APPLICATION dockerrun-d--name "${APPLICATION}" "registry.abc.net/${APPLICATION}:${VERSION}" 这样做行得通,但仅对于最简单的容器而言,也就是那种用户不需要连接到的容器。为了能够实现主机端口映射和卷挂载(volume mounts),我们须要增加应用程序特定的逻辑。这里给出一个使用蛮力实现的方法: 1 2 3 4 5 6 7 8 9 10 11 12 13 APPLICATION=$ 1 VERSION=$ 2 case "$APPLICATION" in java-service- 1 ) EXTRA_ARGS= "-p8080:8080" ;; java-service- 2 ) EXTRA_ARGS= "-p8888:8888--privileged" ;; *) EXTRA_ARGS= "" ;; esac dockerpull "registry.abc.net/${APPLICATION}:${VERSION}" dockerstop$APPLICATION dockerrun-d--name "${APPLICATION}" $EXTRA_ARGS "registry.abc.net/${APPLICATION}:${VERSION}" 现在这段脚本被安装在了每一台Docker主机上以帮助部署。运营工程师会登陆到主机并传递必要的参数,之后脚本会完成剩下的工作。部署时的工作被简化了,工程师的需要做的事情变少了。然而将部署代码化的问题仍然存在。我们回到过去,把它变成一个关于向一个共同脚本提交改变并且将这些改变分发到主机上的问题。通常来说,这样做很值得。将代码提交到仓库会给诸如代码审查、测试、改变历史以及可重复性带来巨大的好处。在关键时刻,你要考虑的事情越少越好。 理想状况下,一个应用的相关部署细节和应用本身应当存在于同一个源代码仓库中。有很多原因导致现实情况不是这样,最突出的原因是开发人员可能会反对将运营相关的东西放入他们的代码仓库中。尤其对于一个用于部署的bash脚本,这种情况更可能发生,当然Dockerfile文件本身也经常如此。 这变成了一个文化问题并且只要有可能的话就值得被解决。尽管为你的部署代码维持两个分开的仓库确实是可行的,但是你将不得不耗费额外的精力保持两个仓库的同步。本篇文章当然会努力达到更好的效果,即便实现起来更困难。在ABC,Dockerfiles最开始在一个专门的仓库中,每个工程都对应一个文件夹,部署脚本存在于它自己的仓库中。 Dockerfiles仓库拥有一个工作副本,保存在Jenkins主机上一个熟知的地址中(就比如是‘/opt/abc/Dockerfiles’)。为了为一个应用创建Docker镜像,Jenkins会搜索Dockerfile的路径,在运行”docker build“前将Dockerfile和伴随的脚本复制进来。由于Dockerfile总是在掌控中,你便可能发现你是否处在Dockerfile超前(或落后)应用配置的状态,虽然实际中大部分时候都会处在正常状态。这是来自Jenkins构建逻辑的一段摘录: 1 2 3 4 5 6 7 8 9 if [-fdocker/Dockerfile];then docker_dir=Docker elif[-f/opt/abc/dockerfiles/$APPLICATION/Dockerfile];then docker_dir=/opt/abc/dockerfiles/$APPLICATION else echo "Nodockerfiles.Can’tcontinue!" exit 1 if dockerbuild-t$APPLICATION:$VERSION$docker_dir 随着时间的推移,Dockerfiles以及支持脚本会被迁移到应用程序的源码仓库中。由于Jenkins最开始已经查看了本地的仓库,pipeline的构建不再需要任何变化。在迁移了第一个服务后,仓库的结构大致是这样的: 我们使用分离的仓库时遇到的一个问题是,如果应用源码或打包逻辑任意一个发生改变,Jenkins就会触发应用的重建。由于Dockerfiles仓库包含了许多项目的代码,当改变发生时我们不想触发所有的仓库重建。解决方法是:使用在Jenkins Git插件中一个很隐蔽的选项,叫做Included Regions。当配置完成后,Jenkins将一个变化引起的重建隔离在仓库的某个特定子集里面。这允许我们将所有的Dockerfiles放在一个仓库里,并且仍然能做到当一个改变发生时只会触发特定的构建(与当改变发生在仓库里特定的目录时构建所有的镜像相比)。 关于这个初步的工作流的另一个方面是部署工程师必须在部署前强制构建一个应用镜像。这将导致额外的延迟,尤其是构建存在问题并且开发人员需要参与其中的时候。为了减少这种延迟,并为更加持续的部署铺平道路,我们开始为熟知分支中的每一个提交构建Docker镜像。这要求每一个镜像有一个独一无二的版本标识符,而如果我们仅仅依赖官方的应用版本字符串往往不能满足这一点。最终,我们使用官方版本字符串、提交次数和提交sha码的组合作为版本标识符。 1 2 3 commit_count=$(gitrev-list--countHEAD) commit_short=$(gitrev-parse-- short HEAD) version_string= "${version}-${commit_count}-${commit_short}" 这样得到的版本字符串看起来是这样的:1.0.1-22-7e56158 在结束pipeline的Docker file部分的讨论之前,还有一些参数值得提及。如果我们不会在生产中操作大量的容器,我们很少用到这些参数。但是,它们被证明有助于我们维护Docker集群的线上运行。 重启策略(Restart Policy)-一个重启策略允许你指定当一个容器退出时,每个容器采取什么动作。尽管这个可以被用作应用错误(application panic)时的恢复或当依赖上线时保持容器再次尝试连接,但对运营人员来说真正的好处是在Docker守护进程(daemon)或者主机重启后的自动恢复。从长远来看,你将希望实现一个适当的调度程序(scheduler),它能够在新主机上重启失败的容器。在那天到来之前,节省一些工作,设置一个重启策略吧。在现阶段的ABC中,我们将这项参数默认为“–restart always”,这将会使容器始终重启。简单地拥有一个重启策略就会使计划的(和非计划的)主机重启变得轻松得多。 资源约束(Resource Constraints)-使用运行时的资源约束,你可以设置容器允许消耗的最大内存和CPU。它不会把你从一般的主机过载(over-subscription)中拯救出来,但是它可以抑制住内存泄漏和失控的容器。我们先对容器应用一个充足的内存限制(例如:–memory=”8g”) 。我们知道当内存增长时这样会产生问题。尽管拥有一个硬性限制意味着应用最终会达到内存不足(Out-of-Memory)的状态并产生错误(panic),但是主机和其它容器会保持正确运行。 结合重启策略和资源约束会给你的集群带来更好的稳定性,与此同时最小化失败的影响,缩短恢复的时间。这种类型的安全防护可以让你和开发人员一起专注于“起火”的根本原因,而不是忙于应付不断扩大的火势。 简而言之,我们从一个基础的构建pipeline,即从我们的源码仓库中创建被标记的Docker镜像开始。从使用Docker CLI部署容器一路到使用脚本和代码中定义的参数部署容器。我们也涉及了如何管理我们的部署代码,并且强调了几个帮助运营人员保持服务上线和运行的Docker参数。 此时此刻,在我们的构建pipeline和部署步骤之间仍然存在空缺。部署工程师会通过登入一个服务器并运行部署脚本的方法填补这个空缺。尽管较我们刚开始时有所改进,但仍然有进一步提高自动化水平的空间。所有的部署逻辑都集中在单一的脚本内,当开发者需要安装脚本以及应付它的复杂性时,会使本地测试会变得困难得多。此时此刻,我们的部署脚本也包含了通过环境变量处理任何环境特定信息的方法。追踪一个服务设置的环境变量以及增加新的环境变量是乏味且容易出错的。 在下一篇文章中,我们将看一看怎样通过解构(deconstructing)共同的包装脚本解决这些痛点,并使部署逻辑向使用Docker Compose的应用更近一步。 您也可以下载免费的电子书《Continuous Integration and Deployment with Docker and Rancher》,这本书讲解了如何利用容器帮助你完成整个CI/CD过程。 原文来源:Rancher Labs 本文转自 RancherLabs 51CTO博客,原文链接:http://blog.51cto.com/12462495/1933287

优秀的个人博客,低调大师

如何使用Docker、Docker-Compose和Rancher搭建部署Pipeline(三)

在这一部分,我们将一步步的走进Rancher,细致的探讨Rancher将如何解决在部署与容器管理时出现的种种的问题。回顾教程的第二部分,你会发现我们已经将应用的部署迁移至Docker Compose,并且已经建立了一系列工作步骤来部署我们的应用。这将使得开发人员能够轻松的对他们的应用部署逻辑进行修正,运维人员也可以查看应用的部署时间。当然,在上一个部分教程的一系列操作中,也存在一些显而易见的问题需要解决。 使用Docker-Compose时面临的挑战 首先,运维人员必须手动地调整所有服务的执行计划。部署人员需要决定将哪一个应用部署至哪一台主机,这意味着部署人员需要时刻对每一台主机的剩余可用资源都有了解,如果某一台主机或者容器崩溃了,部署的操作人员将需要对应用进行重新部署。实际生产中,这意味着主机常常处于负载失衡的状态,并且服务在崩溃之后需要很长时间才能得到恢复。 其次,使用Docker-Compose时,想要获得你的服务的当前状态是十分困难的。举个例子来说,我们经常会从运维人员、项目经理以及开发者口中听到这样的问题:“现在部署环境中运行的到底是XX应用程序的哪个版本?”如果我们采用的是手动调整服务的执行计划的方式,想要得到这个问题的答案通常需要询问指定的进行操作的工程师,工程师们需要登陆服务器并运行docker中的ps命令来查看容器的信息。然而面对这些问题,Rancher将会给我们提供极大的便利:每个人都可以非常容易地获取已经部署的服务的信息,而不需要临时请求运维人员的帮助。 使用Rancher之前,我们试着了解过不少其他能够管理Docker主机或集群的解决方案。然而这些解决方案都没有注意到这是对Docker主机或集群在多种环境(multi-environment)下的管理,这将成为最大的麻烦与负担之一。如果有服务以不同的负载运行在8种不同的环境下,我们需要的是一个统一的方式来管理集群,而不会想要访问8个不同的服务。并且,我们希望让重新构建环境对于我们而言,变成分分钟就能完成的任务,这样开发者就可以随意地更改开发环境。然而,对于生产环境而言,我们希望提供给他们的只是有限的只读访问权限。面对这样的需求,一个采用基于角色的访问控制(RBAC)模型的集中管理方案就显得十分必要了。我们最初决定尝试Rancher就是因为它在部署上非常简单。 当Rancher面临这些挑战 在短短半天的时间里,使用AWS ELB、Elasticache、RDS和现有的Docker主机,我们已经将Rancher部署好并成功运行。能够方便地配置认证信息也是Rancher的优点之一。 我们并不会深入Rancher本身部署的细节,Rancher部署文档中已经说的很明白了。相反,我们将从刚刚完成初始设置那一步开始,说明将如何将原有的设置(教程第一部分和第二部分中所提及的)迁移进来。 我们就从创建不同的环境开始吧,为了使得这个过程尽量简单些,我们将对开发环境(dev)、部署环境(stage)以及生产环境(prod)分别进行设置。每个环境都已有运行在Ubuntu之上的Docker主机,且这些Docker主机是由内部的Ansible配置的,Ansible安装了Docker、我们的监控代理、并进行了一些组织特定的更改。在Rancher上,你只需要运行一条命令,将Docker主机在Rancher server内部进行注册,就可以将已有的Docker主机添加至每个环境中。 添加一台Rancher主机 在大多数情况下,想要添加一台主机需要经过一系列的操作:通过鼠标在网页上完成一些点击,接下来切换至某个特定的环境,最后在终端系统上输入命令。然而,如果你使用Rancher API,我们可以在Ansible工具的帮助下使得这一系列的操作转化为完全自动化的设置。出于好奇,在下面我们截取了playbook中有关这一操作的部分内容(大多是根据 Hussein Galas的repo中的内容做出的逻辑上的修改而得到的)。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 name:installdependencies for urimodule apt:name=python-httplib2update_cache=yes name:check if therancher-agentisrunning command:dockerps–filter‘name=rancher-agent’ register:containers name:getregistrationcommandfromrancher uri: method:GET user:“{{RANCHER_API_KEY}}” password:“{{RANCHER_SECRET_KEY}}” force_basic_auth:yes status_code: 200 url:“https: //rancher.abc.net/v1/projects/{{RANCHER_PROJECT_ID}}/registrationtokens” return_content:yes validate_certs:yes register:rancher_token_url when:“‘rancher-agent’notincontainers.stdout” name:registerthehostmachinewithrancher shell:> dockerrun-d–privileged -v/var/run/docker.sock:/var/run/docker.sock {{rancher_token_url.json[‘data’][ 0 ][‘image’]}} {{rancher_token_url.json[‘data’][ 0 ][‘command’].split()|last}} when:“‘rancher-agent’notincontainers.stdout” 随着工作的一步步进行,我们已经完成了环境的创建并已经将主机在Rancher server中注册,现在就让我们来了解一下,如何将我们的部署工作流整合至Rancher中。我们知道,对于每一台Docker来说,其中都有着一些正在运行的容器,这些系统的部署是通过Ansible工具借助Jenkins完成的。Rancher提供了以下开箱即用的功能: 管理已有的容器(比如:启动、修改、查看日志、启动一个交互式的shell) 获得关于运行中的和停止运行的容器的信息(比如:镜像信息、初始化命令信息、命令信息,端口映射信息以及环境变量信息) 查看主机和容器层级上的资源使用情况(比如:CPU使用率、内存占用率、以及磁盘和网络的使用情况) 独立的容器 很快,我们就已经将Docker主机注册至Rancher Server中,现在我们可以查看容器在各种环境下的运行状态信息了。不仅如此,如果想要将这些信息分享给其他团队,我们仅仅需要针对某个环境给予他们一些有限的权限。通过以上的方式,在想要获得状态信息时我们就完全没有必要请求操作人员登录Docker主机,再通过人工的方式去查询,同时这样也减少了申请获得环境信息的请求的数目,因为我们已经将某些访问权限分配至各个团队了。举个例子来说,如果为开发团队分配环境信息的只读权限,那么将会在开发团队与部署操作团队之间架起一座沟通的桥梁,这样两个团队都会对这个环境的状态比以往更加的关心。在这个基础上,故障的排除也变成了一种小组间相互合作的过程,而不是以往的那种单向的、依赖同步信息流的解决方式,相互合作的方式也会减少解决突发事件的总时间。 到现在为止,我们已经将已有的Docker主机加入Rancher Server,并且基于已经阅读完了的教程的第一部分关于Jenkins和Rancher的内容,下一步,我们打算改进的部分是我们已有的部署流水线,我们将会对已有的部署流水线进行修改,以便于使用Rancher compose,Rancher Compose将代替之前Ansible工具提到的Docker compose。不过在我们深入下一部分之前,我们首先需要了解关于Rancher的应用、调度、Docker Compose和Rancher Compose的一些信息。 应用与服务:Rancher将每个独立的容器(指的是部署在Rancher之外的容器,或者是通过Rancher UI生成的一次性功能的容器)、应用和服务彼此分离开。简单地说,应用是一组服务,而所有容器都需要利用服务(关于应用和服务的内容之后将会由更加详细的介绍)以构建一个应用。独立的容器需要手动地进行调度。 调度:在之前的部署技术中,运维人员需要决定容器应当在哪一台主机上运行。如果使用的是部署脚本,那么意味着运维人员需要决定部署脚本在哪一台或哪几台主机上运行;如果使用Ansible,这将意味着运维人员需要决定哪些主机或组需要到Jenkins中工作。不论是哪一种方式,都需要运维人员去做一些决定,但是在大多数情况下,他们做出的决定都缺乏一些可靠的依据,这对我们的部署工作很是不利(比如说某一台主机的CPU使用率高达100%)。很多解决方案,比如像Docker Swarm、Kubernetes、Mesos和Rancher都采用了调度器来解决这类问题。对于需要执行的某个操作,调度器将会请求获得一组主机的信息,并判断出哪几台是适合执行这个操作的。调度器会根据默认的需求设定或者用户定义的特定需求,比如CPU使用率高低、亲和性或反亲和性规则(比如:禁止在同一台主机上部署两个相同容器)等类似的需求,以逐渐缩小主机选择的范围。如果我是一个负责部署的运维人员,调度器将会极大的减少我的工作负担(尤其是我在深夜加班忙于部署时),因为调度器对以上信息的计算比我快的多,也准的多。Rancher在我们通过应用部署服务的时候能够提供一个开箱即用调度器。 Docker compose:Rancher使用Docker compose来创建应用并定义服务。由于我们已经将服务转化为Docker compose的文件,我们在此基础上创建应用就变得容易了许多。应用可以手动的从UI界面中创建,也可以通过Rancher compose在命令行(CLI)下快速的创建。 Rancher compose:Rancher compose是一种通过命令行(CLI)让我们得以对Rancher中的每一种环境的应用和服务进行方便的管理的工具。同时,通过rancher-compse.yml文件,Rancher compose还能允许对Rancher工具进行一些其他访问。这是一个纯粹的附加的文件,将不会取代原有的docker-compose.yml文件。在rancher-compose.yml文件中,你可以定义以下内容,比如说: 每种服务的升级策略信息 每种服务的健康检查信息 每种服务的需求规模信息 这些都是Rancher中非常实用的亮点,如果你使用Docker Compose或者Docker daemon,这些内容你都是获取不到的。如果想要查看Rancher Compose能提供的所有特性,你可以查看这个文档 通过将已有的部署工作交给Rancher Compose来替代之前的Ansible工具,我们能够很轻松的将服务迁移并部署为Rancher应用的形式。之后,我们就能够去除DESTINATION参数了,但我们依然保留VERSION参数,因为我们在插入docker-compose.uml文件的时候还要使用它。以下是使用Jenkins部署时,部署逻辑的shell片段: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 exportRANCHER_URL=http: //rancher.abc.net/ exportRANCHER_ACCESS_KEY=… exportRANCHER_SECRET_KEY=… if [-fdocker/docker-compose.yml];then docker_dir=docker elif[-f/opt/abc/dockerfiles/java-service- 1 /docker-compose.yml];then docker_dir=/opt/abc/dockerfiles/java-service- 1 else echo“Nodocker-compose.ymlfound.Can’t continue !” exit 1 fi if ![-f${docker_dir}/rancher-compose.yml];then echo“Norancher-compose.ymlfound.Can’t continue !” exit 1 fi /usr/local/bin/rancher-compose–verbose\ -f${docker_dir}/docker-compose.yml\ -r${docker_dir}/rancher-compose.yml\ up-d–upgrade 阅读完代码段,我们可以发现其主要包括以下内容: 我们定义了以环境变量的方式如何访问我们的Rancher server。 需要找到docker-compose.yml文件,否则将会任务将会报错退出。 需要找到rancher-compose.yml文件,否则任务将会报错退出。 运行Rancher-compose,并告诉它不要block并且使用-d命令输出日志,使用-upgrade命令更新一个已经存在的服务。 也许你已经发现了,在绝大部分,代码的逻辑都是相同的,而最大的区别就是使用rancher-compose代替使用Ansible工具完成部署,并对每一个服务添加了rancher-compose.yml文件。具体到我们的java-service-1应用,docker-compose文件和rancher-compose文件现在是这样的: 1 2 3 4 5 6 7 8 9 10 11 docker-compose.yml java-service- 1 : image:registry.abc.net/java-service- 1 :${VERSION} container_name:java-service- 1 expose: – 8080 ports: – 8080 : 8080 rancher-compose.yml java-service- 1 : scale: 3 在开始部署工作之前,我们先回顾一下部署工作的流程: 开发人员将代码的修改推送至git上 使用Jenkins对代码进行单元测试,在测试工作结束之后触发下游工作 下游工作采用新的代码构建一个docker镜像,并将其推送至我们自己的Docker镜像仓库中 创建包含应用名、版本号、部署环境的deployment ticket 1 2 3 DEPLOY- 111 : App:JavaService1,branch“release/ 1.0 . 1 ” Environment:Production 部署工程师针对应用运行Jenkins的部署工作,运行时需要将版本号作为参数。 Rancher compose开始运行,对于某个环境创建或更新应用,并且当达到所需规模的时候,结束这个工作 部署工程师以及开发工程师分别手动地对服务进行校验 部署工程师在Rancher UI中确认完成升级 关键点 使用Rancher进行我们的服务部署时,我们从Rancher内建的调度、弹性伸缩、还原、升级、和回滚等工具中获得极大的便利,使得我们在部署过程中没有花太大的力气。同时我们发现,在将部署工作从Ansible工具中迁移至Rancher的工作量也是很小的,仅仅需要在原有的基础上增加rancher-compose.yml文件。然而,使用Rancher来处理我们容器的调度意味着我们将难以确认我们的应用到底是在哪台主机上运行的。比方说,之前我们并没有决定java-service-1应用在哪里运行,对于后端,在进行负载均衡相关操作时,该应用就没有一个静态的IP。我们需要找到一种办法,使得我们的各种应用之间能够相互察觉到对方。最终,对于我们的java-service-1应用,我们将明确地将应用容器所在的docker主机的8080端口与应用绑定,不过,如果有其他服务与应用绑定为相同的端口,它将会启动失败。通常负责调度决策的工程师将会对以上的事务进行处理。然而,我们最好将这些信息通知调度器以避免这样的事情发生。 在本教程的最后一个部分,我们将继续探索一些方案来解决在使用亲和性规则、主机标签、服务探索以及智能升级和回滚等特性时出现的问题。 原文来源:Rancher Labs 9月27日,北京海航万豪酒店,容器技术大会Container Day 2017即将举行。 CloudStack之父、海航科技技术总监、华为PaaS部门部长、恒丰银行科技部总经理、阿里云PaaS工程总监、民生保险CIO······均已加入豪华讲师套餐! 11家已容器落地企业,15位真·云计算大咖,13场纯·技术演讲,结合实战场景,聚焦落地经验。免费参会+超高规格,详细议程及注册链接请戳 本文转自 RancherLabs 51CTO博客,原文链接:http://blog.51cto.com/12462495/1958622

优秀的个人博客,低调大师

如何使用Docker、Docker-Compose和Rancher搭建部署Pipeline(四)

在这篇文章中,我们将讨论如何用Rancher实现consul的服务发现。 如果你还没有准备好,推荐你阅读本系列中先前的文章: 第一篇:CI /CD和Docker入门 第二篇:使部署逻辑向使用Docker Compose更进一步 第三篇:借力Rancher完成容器编排 在这构建部署流水线系列的最后一篇文章中,我们将探讨在转换到Rancher进行集群调度时面临的一些挑战。在之前的文章中,我们通过使用Rancher执行调度,让运维人员无须再负责选择每一次容器运行的位置。要使用这个新方案,我们必须让环境的其他部分知道调度程序放置这些服务的位置,以及如何访问它们。我们还将讨论如何使用标签来操作调度程序,以调整容器放置位置,并避免端口绑定冲突。最后,我们将通过利用Rancher的回滚功能优化我们的升级过程。 在引入Rancher之前,我们的环境是一个相当静态的环境。我们总是将容器部署到相同的主机上,而部署到不同的主机则意味着我们需要更新一些配置文件以反映新位置。例如,如果我们要添加'java-service-1'应用程序的一个附加实例,我们还需要更新load balancer以指向附加实例的IP。使用调度器让我们无法预测容器部署的位置,并且我们需要动态配置环境,使其能自动适应变化。为此,我们需要使用服务注册和服务发现。 服务注册表为我们提供了应用程序在环境中的位置的单一来源。和硬编码服务位置不同,我们的应用程序可以通过API查询服务注册表,并在我们的环境发生变化时自动重新配置。Rancher使用Rancher的DNS和元数据服务提供了开箱即用的服务发现。然而,混合使用Docker和非Docker应用程序时,我们不能完全依赖Rancher来处理服务发现。我们需要一个独立的工具来跟踪我们所有服务的位置,consul就符合这个要求。 我们不会详细说明如何在您的环境中设置Consul,但是,我们将简要描述我们在ABC公司使用Consul的方式。在每个环境中,我们都有一个部署为容器的Consul集群。我们在环境中的每个主机上都部署一个Consul代理,如果主机正在运行Docker,我们还会部署一个注册器容器。注册器监视每个守护进程的Docker事件API,并在生命周期事件期间自动更新Consul。例如,在新容器被部署后,注册器会自动在Consul中注册该服务。当容器被删除时,注册器撤销它的注册。 Consul服务列表 在Consul中注册所有服务后,我们可以在负载均衡器中运行consul-template,根据Consul中存储的服务数据动态填充上游列表。对于我们的NGINX负载均衡器,我们可以创建一个模板来填充’java-service-1’应用程序的后端: 1 2 3 4 5 6 #upstreams.conf upstreamjava-service- 1 { {{range_,$element:=service "java-service-1" }} server``.`Address`:``.`Port`; ` else ` server 127.0 . 0.1 : 65535 ;#forcea 502 `end`} 此模板在Consul中查找注册为“java-service-1”的服务的列表。然后它将循环该列表,添加具有该特定应用程序实例的IP地址和端口的服务线。如果在Consul中没有注册任何“java-service-1”应用程序,我们默认抛出502以避免NGINX中的错误。 我们可以在守护进程模式下运行consul-template,使其监控Consul的更改,在发生更改时重新渲染模板,然后重新加载NGINX以应用新配置。 1 2 3 4 TEMPLATE_FILE=/etc/nginx/upstreams.conf.tmpl RELOAD_CMD=/usr/sbin/nginx-sreload consul-template-consulconsul.stage.abc.net: 8500 \ -template "${TEMPLATE_FILE}:${TEMPLATE_FILE//.tmpl/}:${RELOAD_CMD}" 通过使用我们的负载均衡器设置来动态地改变其余的环境变化,我们可以完全依赖Rancher调度器来做出我们的服务应该在哪里运行的复杂的决定。但是,我们的“java-service-1”应用程序在Docker主机上绑定TCP端口8080,如果在同一主机上调度了多个应用程序容器,则会导致端口绑定冲突并最终失败。为了避免这种情况,我们可以通过调度规则来操作调度器。 通过在docker-compose.yml文件中使用容器标签来提出条件,是Rancher给我们的一种操作调度器的方法。条件可以包括亲和规则、否定、至“软”强制(意味着尽可能地避免)。在我们使用'java-service-1'应用程序的情况下,我们知道在给定时间只有一个容器可以在主机上运行,因此我们可以基于容器名称设置反关联性规则。这将使调度程序查找一个未运行名称为“java-service-1”的容器的Docker主机。我们的docker-compose.yml文件看起来像下面这样: 1 2 3 4 5 6 7 java-service- 1 : image:registry.abc.net/java-service- 1 :${VERSION} container_name:java-service- 1 ports: - 8080 : 8080 labels: io.rancher.scheduler.affinity:container_label_ne:io.rancher.stack_service.name=java-service- 1 注意“标签”键的引入。所有调度规则都作为标签被添加。标签可以被添加到Docker主机和容器。当我们在Rancher注册我们的主机时,我们可以将它们与标签关联,以后就可以切断调度部署。例如,如果我们有一组使用SSD驱动器进行存储优化的Docker主机,我们可以添加主机标签storage=ssd。 Rancher主机标签 需要利用优化存储主机的容器可以添加标签来强制调度程序仅在匹配的主机上部署它们。我们将更新我们的“java-service-1”应用程序,以便只部署在存储优化的主机上: 1 2 3 4 5 6 7 8 java-service- 1 : image:registry.abc.net/java-service- 1 :${VERSION} container_name:java-service- 1 ports: - 8080 : 8080 labels: io.rancher.scheduler.affinity:container_label_ne:io.rancher.stack_service.name=java-service- 1 io.rancher.scheduler.affinity:host_label:storage=ssd 通过使用标签,我们可以根据所需的容量,而不是个别主机运行特定的容器集,来精细地调整我们的应用程序部署。切换到Rancher进行集群调度,即使您仍然有必须在特定主机上运行的应用程序。 最后,我们可以利用Rancher的回滚功能优化我们的服务升级。在我们的部署工作流中,通过调用rancher-compose来指示Rancher在该服务堆栈上执行升级以部署服务。升级过程大致如下: 通过拉取一个新的镜像来启动升级 逐一地,现有容器被停止并且新容器被启动 部署程序登录到UI并选择“完成升级”时,升级完成, 已停止的旧服务容器被删除 Rancher升级 当给定服务的部署非常少时,此工作流就好了。但是,当某个服务处于“升级”状态(在部署者选择“完成升级”之前)时,在执行“完成升级”或是“回滚”操作之前,你都不能对它进行任何新的升级”。rancher-compose实用程序让我们可以选择以编程方式选择要执行的操作,以部署程序者的身份执行操作。例如,如果您对服务进行自动测试,则可以在rancher-compose升级返回后调用此类测试。根据这些测试的状态,rancher-compose可以被再次调用,这次我们告诉堆栈“完成升级”或“回滚”。我们部署Jenkins作业的一个原始示例可能如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # for thefulljob,seepart 3 of this series /usr/local/bin/rancher-compose--verbose\ -f${docker_dir}/docker-compose.yml\ -r${docker_dir}/rancher-compose.yml\ up-d--upgrade JAVA_SERVICE_1_URL=http: //java-service-1.stage.abc.net:8080/api/v1/status if curl-s${JAVA_SERVICE_1_URL}|grep-q "OK" ;then #looksgood,confirmor "finish" theupgrade /usr/local/bin/rancher-compose--verbose\ -f${docker_dir}/docker-compose.yml\ -r${docker_dir}/rancher-compose.yml\ up--confirm-upgrade else #lookslikethere'sanerror,rollbackthecontainers #tothepreviouslydeployedversion /usr/local/bin/rancher-compose--verbose\ -f${docker_dir}/docker-compose.yml\ -r${docker_dir}/rancher-compose.yml\ up--rollback fi 这个逻辑将调用我们的应用程序端点来执行简单的状态检查。如果输出显示的是‘OK’,那么我们完成升级,否则我们需要回滚到以前部署的版本。如果您没有自动测试,另一个选择是简单地总是完成或“确认”升级。 1 2 3 4 5 # for thefulljob,seepart 3 of this series /usr/local/bin/rancher-compose--verbose\ -f${docker_dir}/docker-compose.yml\ -r${docker_dir}/rancher-compose.yml\ up-d--upgrade--confirm-upgrade 如果不久以后,您确定需要回滚,就使用相同的部署作业简单地重新部署以前的版本。这确实不像Rancher的升级和回滚功能那么友好,但它通过使堆栈不处于“升级”的状态来解锁将来的升级。 当服务在Rancher中回滚时,容器将被重新部署到以前的版本。当使用通用标记如“latest”或“master”部署服务时,可能会出现意外的后果。例如,让我们假设'java-service-1'应用程序以前被部署了标签'latest'。对图像进行更改,推送到注册表,Docker标签“latest”被更新为指向此新映像我们使用标签“latest”继续升级,在测试后决定应用程序需要回滚。使用Rancher滚动堆栈仍然会重新部署最新的映像,因为标签“latest”尚未被更新为指向上一个映像。回滚可以在纯技术术语中实现,但是部署最近的工作副本的预期效果完全无法实现。在ABC公司,我们通过始终使用与应用程序版本相关的特定标记来避免这种情况。因此,不要使用标记latest”部署我们的“java-service-1”应用程序,我们可以使用版本标签“1.0.1-22-7e56158”。这保证回滚将始终指向我们的应用程序在环境中的最新工作部署。 我们希望我们分享的经验对你们有所帮助。这有助于我们有条不紊地采用Docker,稳步改进我们的流程,并让我们的团队能熟悉这些概念。对更自动化的部署工作流进行增量更改,使组织能够更快地实现自动化的优势,部署团队可以更加务实地决定他们在流水线中需要什么。我们的经历证明Rancher在可行性、自动化、甚至团队协作方面都是成功的。我们希望分享这些我们在Docker应用过程中获得的经验教训将有助于您自己的应用过程。 欢迎关注Rancher官方微信公众号(RancherLabs),获取第一手技术干货推送;欢迎添加客服微信(RancherLabsChina)为好友,加入Rancher官方技术交流群,获取免费技术支持,与数千Docker/Rancher使用者互动。 原文来源:Rancher Labs 9月27日,北京海航万豪酒店,容器技术大会Container Day 2017即将举行。 CloudStack之父、海航科技技术总监、华为PaaS部门部长、恒丰银行科技部总经理、阿里云PaaS工程总监、民生保险CIO······均已加入豪华讲师套餐! 11家已容器落地企业,15位真·云计算大咖,13场纯·技术演讲,结合实战场景,聚焦落地经验。免费参会+超高规格,详细议程及注册链接请戳 本文转自 RancherLabs 51CTO博客,原文链接:http://blog.51cto.com/12462495/1961896

优秀的个人博客,低调大师

如何使用Docker、Docker-Compose和Rancher搭建部署Pipeline(二)

在这一系列文章的第一篇中,我们分享了只用Docker时我们开发的初步的工作流,如何创建一个基础的构建和部署流水线。容器的部署方式不再是在登陆server的时候从内存中输入Docker命令。我们已经通过Jenkins server实现了镜像的自动化构建。我们使用脚本将Docker命令进行封装,将其存储到GitHub中并且设置版本。目前我们正采取措施,通过逐步改善现有过程来实现持续部署。然而,仍有一些痛点需要我们去解决。在这篇文章中,我们将看看如何使用Docker Compose 和 Ansible来改善此设计。 在部署镜像时,工程师需要登录到服务器,并从shell运行我们的Docker wrapper脚本。这不是很好的解决方法,因为它也需要开发者进行等待。没有任何一方会从在这种方式中获益(作为一个工程师,当你去做某件你很了解并且很容易自动化的事情时,你有多少次被打断了?)由于每一次部署都是通过操作者电脑中的SSH会话来执行的,因此部署过程是不可见的。 如果你对我们的部署脚本还有印象,你会发现它看起来像下面的代码段: 实际上,我们做的是将Docker run命令语句进行抽象,由此工程师将不需要知道每个图像成功运行时所需要的确切的参数。虽然这改善了必须全部记住并且手动输入所有Docker参数的现状,但同时也会带来新的问题: 每个容器的逻辑都存储在同一文件中,这使得对应用程序部署逻辑的更改更难追踪; 当开发者需要测试或者修改参数时,需要被迫理清脚本中的逻辑,而不是能够在某一特定的程序中轻松地阅读和修改参数。 在我们的工作流中,Docker Compose是一个更适合使用的工具,它同样可以将部署参数进行编码,并且在YAML文件中指定,此文件就是docker-compose.yml。Docker Compose不仅帮助我们解决了上面提到的难点,而且也可以使我们从社区未来的工作中获益。下面让我们理清部署脚本,并且为我们的JAVA程序示例创建一个Compose文件。首先,我们需要基于原来的部署逻辑创建一个docker-compose.yml文件: 现在,部署容器只需要在与docker-compose.yml文件相同目录下输入以下命令: 1 docker-composeup 它将根据compose文件中设置的参数启动一个容器。在compose文件中一个重要的变量是${VERSION} 。Docker Compose可以从当前的shell环境中插入compose文件里所列出的参数。我们可以通过简单地运行以下语句来设置参数: 1 VERSION= 1.0 . 0 docker-composeup 它将从我们的私有镜像仓库挑出标记1.0.0的镜像,以此启动java-service-1程序。如果没有设置VERSION变量,Docker Compose将产生一条警告信息,并且用空字符串代替变量值,由此,具有最新版本标签的镜像将会被挑出。因此,正确地设置变量是相当重要的。 作为开发过程的一部分,我们希望开发人员能够在本地建立服务并且测试他们的服务。然而,由于docker-compose.yml指向私有镜像仓库的镜像,运行docker-compose将从最近构建的镜像中开启服务而不是从本地资源中开启。理想情况下,开发者可以通过运行以下代码使用典型的docker-compose工作流: Docker Compose能在不修改docker-compose.yml文件的情况下,让我们做到这一点。我们可以使用多个文件来覆盖我们在本地测试中想要改变的任何参数。在docker-compose.override.yml中,我们指定一个key而不是一个镜像,并且移除了对VERSION变量的需求。由于这是一个覆盖文件,我们不需要复制任何额外的设置,如端口设置: 使用Docker Compose而非部署脚本之后,我们可以: 在源代码中存储每个compose文件,这与Dockerfile类似; 不再需要复杂的部署脚本; 允许开发人员在本地轻松地测试并修改应用程序。 现在我们有了java-service-1程序的compose文件,我们可以将它从我们的部署脚本中删除,因此文件组织与下面的结构类似: 此时,我们仍然没有解决镜像构建和部署之间的问题。在docker-compose.yml文件中包含了所有的部署逻辑,但是它如何在环境中运行直至结束的呢?正好现在我们在运行与UNIX和TPC socket相关的Docker守护进程,是时候讨论一些与安全有关的问题了。 我们的情况是,工程师登录到服务器上,手动运行每个服务器所需容器的部署脚本。默认情况下,当在局部运行Docker命令时,它将使用UNIX socket /var/run/docker.sock连接Docker守护进程;或者让守护进程监听TCP socket,这允许用户远程连接到每个Docker守护进程,使得工程师能够像登录到主机一样运行命令。这为连接方式提供了更大的灵活性,但是没有考虑到一些开销和安全问题: 通过网络连接增加了安全隐患; 增加了对于基于主机或者基于网络的ACLs需求; 保护守护进程需要分布式CA和客户端认证。 另一种可能的方法是不使用基于UNIX socket的方式运行Docker守护进程,而使用SSH来运行命令。已经建立的ACLs将保护SSH端口,并且它只允许通过SSH授权的特定的用户才能使用Docker守护进程。虽然这不是最简洁的方法,但是它有助于保持较低的运行开销,并且使安全隐患降到最低。这点是非常重要的,尤其是对于细粒度的稀疏的任务队列而言。 为了有利于通过SSH运行Docker命令,我们可以使用Ansible——一个流行的编排和配置管理工具。它是无代理的,并且允许通过SSH连接运行“剧本”(服务器任务集合)。一个运行docker-compose命令的简单的剧本如下所示: 如果你对Ansible没有过多了解,你也许可以通过上面的剧本大致了解到我们想做什么。它们按顺序一步步执行,具体如下所示: Ansible将通过SSH连接到目标服务器(允许通过使用DESTINATION变量来指定主机) 在每个服务器中,Ansible会通过执行shell命令登录到公司私有的镜像仓库 Ansible将位于Jenkins(运行ansible剧本的服务器)中的docker-compose.yml文件复制到每个目标服务器中的/tmp/docker-compose.yml下 在每个目标服务器中运行docker-compose命令 通过删除远程的/tmp/docker-compose.yml文件进行清理 一个shell脚本可以被运用在同一个事件中。然而在Ansible中,我们将很容易的使任务并行化并且得到经过良好测试的模块,通过使Ansible与新的部署剧本相结合,我们可以远程启动容器,相较于工程师登录到主机、人工运行命令,这是一个重要的进步。为了在部署过程和状态中提供更大的可视性,我们将建立Jenkins任务来运行Ansible代码。通过使用Jenkins,在未来我们可以轻松地将构建和部署任务集成起来,从而得到额外的好处。 Jenkins任务需要两个参数:目标主机(传递给剧本中的DESTINATION变量)和部署镜像的版本(在docker-compose.yml文件中插入VERSION变量)。大多数任务的构建部分是一个shell构建器,它将试图找到程序中的docker-compose.yml文件,然后通过传递变量(用-e)到剧本中,运行ansible-playbook命令: 虽然看起来我们似乎只对工作流做了微小的变化,但是我们正一步一步地向构建一个持续部署模型迈进: 部署是可以被审查的。我们使用日志来记录输出什么、何时输出、以及哪些主机是目标主机等信息,这一切都归功于Jenkins。 程序部署逻辑已经从一个单一的脚本分散到存储在程序源代码中的单独的docker-compose.yml文件中,这意味着我们可以轻松地通过git更改程序部署逻辑。在程序源文件或者部署文件发生变化时,我们也可以容易地进行构建和部署。 虽然这些改进解决了某些问题,但是它们所带来的新的问题也成为了焦点: 哪个容器的哪个版本会被部署到何地? 容器在被部署后会处于哪种状态? 我们如何确定哪个主机成为程序的目标主机? 在这一系列接下来的文章中,我们将探讨怎样运行Rancher以及使用它的原因,尤其是它如何解决上述的问题。与此同时,我们也讨论它在业务和开发团队中所起到的意想不到的桥梁作用。 原文来源:Rancher Labs 9月27日,北京海航万豪酒店,容器技术大会Container Day 2017即将举行。 CloudStack之父、海航科技技术总监、华为PaaS部门部长、恒丰银行科技部总经理、阿里云PaaS工程总监、民生保险CIO······均已加入豪华讲师套餐! 11家已容器落地企业,15位真·云计算大咖,13场纯·技术演讲,结合实战场景,聚焦落地经验。免费参会+超高规格,详细议程及注册链接请戳 本文转自 RancherLabs 51CTO博客,原文链接:http://blog.51cto.com/12462495/1956623

优秀的个人博客,低调大师

hadoop-2.7.4+hbase-1.3.1+zookeeper-3.4.9搭建分布式集群环境

# 系统信息 3台系统: centos6.8内核:4 内存:4G 硬盘:50G #主机名称,ip地址 master: 192.168.1.110 slave1: 192.168.1.111 slave2: 192.168.1.112 ########################软件下载地址######################## 链接:https://pan.baidu.com/s/1dFuBnKt 密码:rhwu ######################## 基础初始配置 ######################## # 版本选择 jdk-8u77-linux-x64.rpm zookeeper-3.4.9.tar.gz hbase-1.3.1-bin.tar.gz hadoop-2.7.4.tar.gz # 配置hosts文件,三台机器都需要 [root@master ~]# cat /etc/hosts 192.168.1.110 master 192.168.1.111 slave1 192.168.1.112 slave2 # 配置用户 1 2 groupadd-g4000hadoop useradd -g4000-u4001hadoop # 所有的主机 hbase,zookeeper 安装目录都在此处 1 2 mkdir /opt/hadoop chown hadoop.hadoop /opt/hadoop/ -R ######################## 时间配置 ######################## # 双机互信 主要有三步: ①生成公钥和私钥 ②导入公钥到认证文件 ③更改权限 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 [root@master~] #ssh-keygen-trsa Generatingpublic /private rsakeypair. Enter file in which tosavethekey( /root/ . ssh /id_rsa ): Enterpassphrase(empty for nopassphrase): Entersamepassphraseagain: Youridentificationhasbeensaved in /root/ . ssh /id_rsa . Yourpublickeyhasbeensaved in /root/ . ssh /id_rsa .pub. Thekeyfingerprintis: ee:15:03:c7:3a:a2:8e:6a:c1:0c:74:d3:97:34:77:04root@master Thekey'srandomartimageis: +--[RSA2048]----+ |..o.Eoo| |.o.oo..| |.....o| |.+| |+.So| |+.o.o| |....| |.o..| |o....| +-----------------+ [root@master~] #cat~/.ssh/id_rsa.pub>>~/.ssh/authorized_keys [root@master~] #chmod700~/.ssh&&chmod600~/.ssh/* # 主机与从机之间必须可以双向无密码登陆,从机与从机之间无限制 1 2 scp ~/. ssh /authorized_keys slave1: /root/ . ssh / scp ~/. ssh /authorized_keys slave2: /root/ . ssh / # 同步时间 1 2 [root@masterzookeeper] #ansiblehbase-mcron-a"name='ntpdate'hour='*/1'job='/usr/sbin/ntpdate192.168.1.110&>/dev/null'" [root@masterzookeeper] #ansiblehbase-mshell-a"crontab-l" # 时间一定要保持一致 ######################## 防火墙配置 ######################## # 防火墙配置 所有的主机上都得配置,或者开放 (2181,2888:3888端口,这部分端口是zookeeper端口) 1 2 3 [root@slave2zookeeper] #iptables-IINPUT-s192.168.1.0/24-jACCEPT [root@slave2zookeeper] #serviceiptablessave [root@slave2zookeeper] #serviceiptablesrestart ######################## JDK配置 ######################## # 安装jdk,并配置环境变量,三台机器都需要安装 # 设置环境变量 1 2 3 [root@slave2~] #cat/etc/profile.d/java.sh export JAVA_HOME= /usr/java/default export PATH=$JAVA_HOME /bin :$PATH # 重新加载配置文件使之生效 [root@slave2 ~]# source /etc/profile.d/java.sh # 查看是否配置完成,3台机器都需要测试 [root@slave2 ~]# java -version java version "1.8.0_77" Java(TM) SE Runtime Environment (build 1.8.0_77-b03) Java HotSpot(TM) 64-Bit Server VM (build 25.77-b03, mixed mode) ######################## zookeeper集群配置 ######################## # 参考文档: http://blog.csdn.net/reblue520/article/details/52279486 # 注意:zookeeper因为有主节点和从节点的关系,所以部署的集群台数最好为奇数个,否则可能出现脑裂导致服务异常 # 下载地址: http://archive.apache.org/dist/zookeeper/zookeeper-3.4.9/zookeeper-3.4.9.tar.gz # 注意三台机器都需要安装,如果对ansible熟悉的话 可以直接使用它 1 2 mkdir /opt/hadoop chown hadoop.hadoop /opt/hadoop/ -R # 安装zookeeper 1 2 3 4 [root@master~] #cd/opt/hadoop/ [root@masterhadoop] #ls zookeeper-3.4.9. tar .gz [root@masterhadoop] #tarxfzookeeper-3.4.9.tar.gz # 弄一个软链接,配置文件直接指向这个地址,未来方便更新版本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [root@masterhadoop] #ln-svzookeeper-3.4.9zookeeper "zookeeper" -> "zookeeper-3.4.9" [root@masterconf] #cd/opt/hadoop/zookeeper/conf [root@masterconf] #cpzoo_sample.cfgzoo.cfg [root@masterconf] #catzoo.cfg tickTime=2000 initLimit=10 syncLimit=5 dataDir= /opt/hadoop/zookeeper/data dataLogDir= /opt/hadoop/zookeeper/logs clientPort=2181 server.1=master:2888:3888 server.2=slave1:2888:3888 server.3=slave2:2888:3888 # 创建数据以及日志目录,将设置属主属组权限 1 2 [root@masterconf] #mkdir/opt/hadoop/zookeeper/data [root@masterconf] #mkdir/opt/hadoop/zookeeper/logs # 在zoo.cfg中的dataDir指定的目录下,新建myid文件。 # 例如:$ZK_INSTALL/data下,新建myid。在myid文件中输入1。表示为server.1。 echo "1" > data/myid 这里表示的是server.1 如果是第二个机器那么表示server.2 启动:在集群中的每台主机上执行如下命令 bin/zkServer.sh start 查看状态,可以看到其中一台为主节点,其他两台为从节点: bin/zkServer.sh status # 启动zookeeper集群 1 2 3 4 [root@masterzookeeper] #bin/zkServer.shstatus ZooKeeperJMXenabledbydefault Usingconfig: /opt/hadoop/zookeeper/bin/ .. /conf/zoo .cfg Mode:leader # 从节点 1 2 3 4 [root@slave1zookeeper] #bin/zkServer.shstart ZooKeeperJMXenabledbydefault Usingconfig: /opt/hadoop/zookeeper/bin/ .. /conf/zoo .cfg Startingzookeeper...STARTED # 启动报错 说明没有配置myid文件, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 2017-12-0411:56:21,306[myid:]-INFO[main:QuorumPeerConfig@124]-Readingconfigurationfrom: /opt/hadoop/zookeeper/bin/ .. /conf/zoo .cfg 2017-12-0411:56:21,323[myid:]-INFO[main:QuorumPeer$QuorumServer@149]-Resolved hostname :slave2toaddress:slave2 /192 .168.1.112 2017-12-0411:56:21,324[myid:]-INFO[main:QuorumPeer$QuorumServer@149]-Resolved hostname :slave1toaddress:slave1 /192 .168.1.111 2017-12-0411:56:21,324[myid:]-INFO[main:QuorumPeer$QuorumServer@149]-Resolved hostname :mastertoaddress:master /192 .168.1.110 2017-12-0411:56:21,325[myid:]-INFO[main:QuorumPeerConfig@352]-Defaultingtomajorityquorums 2017-12-0411:56:21,326[myid:]-ERROR[main:QuorumPeerMain@85]-Invalidconfig,exitingabnormally org.apache.zookeeper.server.quorum.QuorumPeerConfig$ConfigException:Errorprocessing /opt/hadoop/zookeeper/bin/ .. /conf/zoo .cfg atorg.apache.zookeeper.server.quorum.QuorumPeerConfig.parse(QuorumPeerConfig.java:144) atorg.apache.zookeeper.server.quorum.QuorumPeerMain.initializeAndRun(QuorumPeerMain.java:101) atorg.apache.zookeeper.server.quorum.QuorumPeerMain.main(QuorumPeerMain.java:78) Causedby:java.lang.IllegalArgumentException: /opt/hadoop/zookeeper/data/myid file ismissing atorg.apache.zookeeper.server.quorum.QuorumPeerConfig.parseProperties(QuorumPeerConfig.java:362) atorg.apache.zookeeper.server.quorum.QuorumPeerConfig.parse(QuorumPeerConfig.java:140) ...2 more Invalidconfig,exitingabnormally # 这里是因为防火墙开着,没有开放端口的原因 1 2 3 4 5 2016-03-2603:48:07,957[myid:1]-WARN[QuorumPeer[myid=1] /0 :0:0:0:0:0:0:0:2181:QuorumCnxManager@400]-Cannot open channelto3atelectionaddressS2/这里是地址 java.net.ConnectException:主机无法连接 atjava.net.PlainSocketImpl.socketConnect(NativeMethod) atjava.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339) atjava.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200) ######################## hbase 与hadoop的版本需要对应 ######################## http://blog.csdn.net/shuaigexiaobo/article/details/78114221 低版本与高版本会安不上,还需要注意jdk版本 ######################## hadoop 集群配置 ######################## # 软件放置路径为初级配置的路径 /opt/hadoop 1 2 3 [root@masterhadoop] #tarxfhadoop-2.7.4.tar.gz [root@masterhadoop] #ln-svhadoop-2.7.4hadoop "hadoop" -> "hadoop-2.7.4" # 配置属主属组权限 1 [root@masterhadoop] #chownhadoop.hadoop/opt/hadoop/hadoop-2.7.4-R # 环境变量设置 1 2 3 4 5 6 7 8 9 10 vim /etc/profile .d /hadoop .sh export HADOOP_HOME= /opt/hadoop/hadoop export HADOOP_INSTALL=$HADOOP_HOME export HADOOP_MAPRED_HOME=$HADOOP_HOME export HADOOP_COMMON_HOME=$HADOOP_HOME export HADOOP_HDFS_HOME=$HADOOP_HOME export YARN_HOME=$HADOOP_HOME export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME /lib/native export PATH=$PATH:$HADOOP_HOME /sbin :$HADOOP_HOME /bin #exportHADOOP_SSH_OPTS="-p22" # 复制到其它主机中 1 2 [root@masterhadoop] #scp/etc/profile.d/hadoop.shslave1:/etc/profile.d/ [root@masterhadoop] #scp/etc/profile.d/hadoop.shslave2:/etc/profile.d/ # 加载环境变量 1 [root@masterhadoop] #soure/etc/profile.d/hadoop.sh # 查看是否生效 1 2 3 [root@masterhadoop] #hadoopversion Hadoop2.7.4 Subversionhttps: //shv @git-wip-us.apache.org /repos/asf/hadoop .git-rcd915e1e8d9d0131462a0b7301586c175728a282 # hadoop配置文件在放置于/opt/hadoop/hadoop/etc/hadoop 1 2 3 4 5 6 7 vimcore-site.xml #添加如下内容 <configuration> <property> <name>fs.default.name< /name > <value>hdfs: //master :9000< /value > < /property > < /configuration > 1 2 3 vimhadoop- env .sh #exportJAVA_HOME=${JAVA_HOME} export JAVA_HOME= /usr/java/default 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 vimhdfs-site.xml #配置hdfs文件数据节点以及名称节点 <configuration> <property> <name>dfs.name. dir < /name > <value> /opt/hadoop/hadoop/name < /value > < /property > <property> <name>dfs.data. dir < /name > <value> /opt/hadoop/hadoop/data < /value > < /property > <property> <name>dfs.replication< /name > <value>3< /value > < /property > < /configuration > mkdir /opt/hadoop/hadoop/name mkdir /opt/hadoop/hadoop/data 1 2 3 4 5 6 7 8 [root@masterhadoop] #cpmapred-site.xml.templatemapred-site.xml [root@masterhadoop] #vim!$ <configuration> <property> <name>mapred.job.tracker< /name > <value>master:9001< /value > < /property > < /configuration > # 配置从节点 先删除localhost 1 2 3 /opt/hadoop/hadoop/etc/hadoop/slaves slave1 slave2 # 三台机器都是一样的配置,放置相同的路径 1 2 [root@masterhadoop] #scp-rhadoop-2.7.4slave1:/opt/hadoop/ [root@masterhadoop] #scp-rhadoop-2.7.4slave2:/opt/hadoop/ # 使用ansible或者手动直接软链接过去就行 1 [root@masterhadoop] #ansiblehbase-mshell-a'ln-sv/opt/hadoop/hadoop-2.7.4/opt/hadoop/hadoop' # 配置属主属组文件 1 [root@masterhadoop] #ansiblehbase-mshell-a'chownhadoop.hadoop/opt/hadoop/hadoop-R' # 进入master的/opt/hadoop/hadoop目录,执行以下操作 1 #bin/hadoopnamenode-format #格式化namenode,第一次启动服务前执行的操作,以后不需要执行 # 启动hadoop服务 1 2 3 4 5 [root@masterlogs] #sbin/start-all.sh ThisscriptisDeprecated.Insteadusestart-dfs.shandstart-yarn.sh 17 /12/04 15:56:51WARNutil.NativeCodeLoader:Unabletoloadnative-hadooplibrary for yourplatform...using builtin -javaclasseswhereapplicable Startingnamenodeson[master] master:startingnamenode,loggingto /opt/hadoop/hadoop-2 .7.4 /logs/hadoop-root-namenode-master .out # 查看进程 会发现多了资源名称节点以及namanode 1 2 3 4 5 6 [root@masterlogs] #jps 5057ResourceManager 4900SecondaryNameNode 4709NameNode 5208Jps 2734QuorumPeerMain # 登陆其它节点 会发现多了一个数据节点 1 2 3 4 5 [root@slave2hadoop] #jps 2624QuorumPeerMain 3489NodeManager 3378DataNode 3603Jps ######################## hbase集群配置 ######################## # 软件放置路径为初级配置的路径 /opt/hadoop 1 2 3 [root@masterhadoop] #tarxfhbase-1.3.1-bin.tar.gz [root@masterhadoop] #ln-svhbase-1.3.1hbase "hbase" -> "hbase-1.3.1" # 配置文件目录 /opt/hadoop/hbase/conf vim hbase-env.sh 1 2 3 export JAVA_HOME= /usr/java/default/ export HBASE_CLASSPATH= /opt/hadoop/hadoop/etc/hadoop export HBASE_MANAGES_ZK= false #不使用自带的zk,使用独立的zookeeper vim hbase-site.xml # 配置站点信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <configuration> <property> <name>hbase.rootdir< /name > <value>hdfs: //master :9000 /hbase < /value > < /property > <property> <name>hbase.master< /name > <value>master< /value > < /property > <property> <name>hbase.cluster.distributed< /name > <value> true < /value > < /property > <property> <name>hbase.zookeeper.property.clientPort< /name > <value>2181< /value > #这里指的是zook的端口 < /property > <property> <name>hbase.zookeeper.quorum< /name > #主机名一定要对应上 <value>master,slave1,slave2< /value > < /property > <property> <name>zookeeper.session.timeout< /name > #zook的session超时时长 <value>60000000< /value > < /property > <property> <name>dfs.support.append< /name > <value> true < /value > < /property > < /configuration > vim regionservers# 配置从节点 一定要对应上 1 2 slave1 slave2 # 设置软链接,方便未来升级 [root@master hadoop]# ansible hbase -m shell -a "ln -sv /opt/hadoop/hbase-1.3.1 /opt/hadoop/hbase" # 设置属主属组权限 [root@master hadoop]# ansible hbase -m shell -a "chown hadoop.hadoop /opt/hadoop/hbase-1.3.1 -R" # 启动三台机器上的 hbase服务 [root@master hadoop]# ansible hbase -m shell -a "/opt/hadoop/hbase-1.3.1/bin/start-hbase.sh" # 只需要启动master上的,其它机器上会自动启动 [root@master hadoop]# /opt/hadoop/hbase/bin/start-hbase.sh # 查看master上的服务 1 2 3 4 5 6 7 [root@masterhadoop] #jps 5057ResourceManager 4900SecondaryNameNode 6516HMaster 4709NameNode 6809Jps 2734QuorumPeerMain # 查看slave上的从节点服务 1 2 3 4 5 6 7 [root@slave1~] #jps 3510NodeManager 3399DataNode 2680QuorumPeerMain 5464Jps 5049HMaster 4730HRegionServer # 进入hbase shell进行验证 /opt/hadoop/hbase/bin/hbase shell 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 2017-12-0416:20:28,690WARN[main]util.NativeCodeLoader:Unabletoloadnative-hadooplibrary for yourplatform...using builtin -javaclasseswhereapplicable SLF4J:ClasspathcontainsmultipleSLF4Jbindings. SLF4J:Foundbinding in [jar: file : /opt/hadoop/hbase-1 .3.1 /lib/slf4j-log4j12-1 .7.5.jar! /org/slf4j/impl/StaticLoggerBinder .class] SLF4J:Foundbinding in [jar: file : /opt/hadoop/hadoop-2 .7.4 /share/hadoop/common/lib/slf4j-log4j12-1 .7.10.jar! /org/slf4j/impl/StaticLoggerBinder .class] SLF4J:Seehttp: //www .slf4j.org /codes .html #multiple_bindingsforanexplanation. SLF4J:Actualbindingisof type [org.slf4j.impl.Log4jLoggerFactory] HBaseShell;enter 'help<RETURN>' for listofsupportedcommands. Type "exit<RETURN>" toleavetheHBaseShell Version1.3.1,r930b9a55528fe45d8edce7af42fef2d35e77677a,ThuApr619:36:54PDT2017 hbase(main):001:0> hbase(main):002:0*list TABLE 0row(s) in 0.2350seconds =>[] hbase(main):003:0>create 'scores' , 'grade' , 'course' 0row(s) in 2.4310seconds =>Hbase::Table-scores hbase(main):004:0>list TABLE scores 1row(s) in 0.0080seconds =>[ "scores" ] #### 此处打开的地址都是 master的IP , 192.168.1.110 本文转自812374156 51CTO博客,原文链接:http://blog.51cto.com/xiong51/2047261,如需转载请自行联系原作者

优秀的个人博客,低调大师

一脸懵逼学习HBase的搭建(注意HBase的版本)

1:Hdfs分布式文件系统存的文件,文件存储。 2:Hbase是存储的数据,海量数据存储,作用是缓存的数据,将缓存的数据满后写入到Hdfs中。 3:hbase集群中的角色: (1)、一个或者多个主节点,Hmaster; (2)、多个从节点,HregionServer; 1:由于HBase依赖hdfs,所以下载的时候注意HBase的版本: 注:我使用的是hadoop2.4版本的,所以HBase选择支持2版本的:hbase-0.96.2-hadoop2-bin.tar.gz 2:上传hbase安装包,上传到一台机器即可: 建议:自己规划一下自己的机器,最好是独立的,再搞两台机器最好, 如果不想搞更多的机器,这里放到启动yarn进程的机器上: 如我的slaver5,slaver6(master节点,slaver1节点,slaver2节点安装Region Server,slaver5,slaver6安装Master ), 这样负载比较好点,自己电脑吃得消; 过程省略,上传结果如下所示; 2:解压缩刚才上传的hbase-0.96.2-hadoop2-bin.tar.gz: [root@slaver5 hadoop]# tar -zxvf hbase-0.96.2-hadoop2-bin.tar.gz 3:配置HBase集群,要修改3个文件(首先Zookeeper集群已经安装好了哟): 注意:要把hadoop的hdfs-site.xml和core-site.xml 放到HBase/conf下; [root@slaver5 conf]# cp /home/hadoop/hadoop-2.4.1/etc/hadoop/{core-site.xml,hdfs-site.xml} ./ 开始修改配置文件: 3.1:修改hbase-env.sh: 修改如下所示: //自己的jdk路径 export JAVA_HOME=/usr/java/jdk1.7.0_55//hadoop配置文件的位置export HBASE_CLASSPATH=/home/hadoop/hadoop-2.4.1/conf //告诉hbase使用外部的zk,export HBASE_MANAGES_ZK=true #如果使用独立安装的zookeeper这个地方就是false export HBASE_MANAGES_ZK=false 演示操作如下所示: 可以使用命令查看jdk的路径: [root@slaver6 hadoop]# echo $JAVA_HOME/home/hadoop/jdk1.7.0_65[root@slaver6 hadoop]# 按ESC进入命令行模式: 搜索内容如下所示: 改成如下内容,使用外部的Zookeeper管理HBase: 3.2:修改hbase-site.xml,vim hbase-site.xml: 修改内容如下所示: <configuration> <!-- 指定hbase在HDFS上存储的路径 --> <property> <name>hbase.rootdir</name> <value>hdfs://ns1/hbase</value> </property> <!-- 指定hbase是分布式的 --> <property> <name>hbase.cluster.distributed</name> <value>true</value> </property> <!-- 指定zk的地址,多个用“,”分割 --> <property> <name>hbase.zookeeper.quorum</name> <value>master:2181,slaver1:2181,slaver2:2181</value> </property> </configuration> 配置或如下所示,下面的配置仅仅做一下参考,不是此篇博客配置的: 1 <configuration> 2 <property> 3 <!--hbasemaster的主机和端口--> 4 <name>hbase.master</name> 5 <value>master1:60000</value> 6 </property> 7 <property> 8 <!--时间同步允许的时间差--> 9 <name>hbase.master.maxclockskew</name> 10 <value>180000</value> 11 </property> 12 <property> 13 <name>hbase.rootdir</name> 14 <!--hbase共享目录,持久化hbase数据--> 15 <value>hdfs://hadoop-cluster1/hbase</value> 16 </property> 17 <property> 18 <!--是否分布式运行,false即为单机--> 19 <name>hbase.cluster.distributed</name> 20 <value>true</value> 21 </property> 22 <property> 23 <!--zookeeper地址--> 24 <name>hbase.zookeeper.quorum</name> 25 <value>slave1, slave2,slave3</value> 26 </property> 27 <property> 28 <!--zookeeper配置信息快照的位置--> 29 <name>hbase.zookeeper.property.dataDir</name> 30 <value>/home/hadoop/hbase/tmp/zookeeper</value> 31 </property> 32 </configuration> 修改操作如下所示: [root@slaver5 conf]# vim hbase-site.xml 演示操作如下所示: 3.3:修改regionservers,vim regionservers: 因为master节点,slaver1节点,slaver2节点安装Region Server,所以这里配置一下,slaver5,slaver6安装Master就可以找到Region Server了; 4:然后将部署好的HBase传到其他几个节点上面(拷贝里面有html文档,拷贝起来有点慢,可以删除doc文档): 注:将配置好的HBase拷贝到每一个节点并同步时间。 [root@slaver5 hadoop]# scp -r hbase-0.96.2-hadoop2/ master:/home/hadoop/[root@slaver5 hadoop]# scp -r hbase-0.96.2-hadoop2/ slaver1:/home/hadoop/[root@slaver5 hadoop]# scp -r hbase-0.96.2-hadoop2/ slaver2:/home/hadoop/[root@slaver5 hadoop]# scp -r hbase-0.96.2-hadoop2/ slaver6:/home/hadoop/ 5:现在可以启动HBase了,不过启动HBase之前需要将HDFS启动起来(hdfs启动过程省略,之前启动好多次了),因为HBase在hdfs下面创建一个目录叫做hbase,自己配置的: 注:如果浏览器访问不了,记得关防火墙:service iptables stop,service iptables status; 启动所有的hbase 1:分别启动zk ./zkServer.sh start 2:启动hbase集群 start-dfs.sh 3:启动hbase,在主节点上运行: start-hbase.sh 启动完hdfs之后启动HBase: 可以查看这几个节点的进程的启动情况: 现在呢,一个HBase已经启动起来了,如果想启动两个HBase,第一个HBase启动不会自动启动第二个HBase,所以现在手动启动第二个HBase,操作如下所示: 注:为保证集群的可靠性,要启动多个HMaster 6:通过浏览器访问hbase管理页面 192.168.3.134:60010 可以看到三台master节点,slaver1节点,slaver2节点安装Region Server;slaver6是安装的备份的Master; 7:自己可以测试一下,杀死一个HMaster(slaver5节点的),另一个HMaster立马顶上去了,很强悍,依赖着Zookeeper,爽到爆啊。(kill -9 进程号,-9是强制杀死): 1 添加Hbase节点,删除的话直接kill: 2 [root@slaver6 hadoop]# hbase-daemon.sh start regionserver 8:使用HBase的命令行客户端操作一下HBase(测试使用,真实环境使用Java操作): 1 进入hbase的shell:hbase shell 2 退出hbase的shell:quit 3 页面:http://ip地址:60010/ 由于HBase是非关系型数据库,可以查看一下help看看都有啥命令,然后再操作: 可以查看一些基本的命令: HBase的一些基本命令(如果在hbase shell客户端,打错了,可按ctrl+BackSpace进行删除): #创建HBase数据表create 'myTables',{NAME => 'base_info',VERSIONS => 3},{NAME => 'extra_info'} hbase(main):016:0> create 'user','info01','info02' #查看有什么表list#查看表结构describe 'myTables'#禁用表disable 'myTables'#删除表,删除之前要先禁用表drop 'myTables'#插入数据,插入一个表的一行的一列的一个值,最后一个字段不带#不带分号#put '表名称','行','base_info/extra_info:列名称','列值'put 'myTables','0001','base_info:name','张三'put 'myTables','0001','base_info:age','22'put 'myTables','0001','base_info:sex','男'put 'myTables','0001','extra_info:addr','河南省'#查询数据,查询某一行。get 'myTables','0001'get 'myTables','0001',{COLUMN => 'base_info:name',VERSION => 10}scan 'myTables'#修改值操作,默认不显示历史值put 'myTables','0001','base_info:name','李四' 可以去Zookeeper查看hbase的一些信息: 1 [root@master sbin]# cd /home/hadoop/zookeeper-3.4.5/ 2 [root@master zookeeper-3.4.5]# ls 3 bin conf dist-maven ivy.xml NOTICE.txt recipes zookeeper-3.4.5.jar.asc 4 build.xml contrib docs lib README_packaging.txt src zookeeper-3.4.5.jar.md5 5 CHANGES.txt data ivysettings.xml LICENSE.txt README.txt zookeeper-3.4.5.jar zookeeper-3.4.5.jar.sha1 6 [root@master zookeeper-3.4.5]# cd bin/ 7 [root@master bin]# ls 8 README.txt zkCleanup.sh zkCli.cmd zkCli.sh zkEnv.cmd zkEnv.sh zkServer.cmd zkServer.sh zookeeper.out 9 [root@master bin]# ./zkCli.sh 10 Connecting to localhost:2181 11 2017-12-18 17:08:22,357 [myid:] - INFO [main:Environment@100] - Client environment:zookeeper.version=3.4.5-1392090, built on 09/30/2012 17:52 GMT 12 2017-12-18 17:08:22,383 [myid:] - INFO [main:Environment@100] - Client environment:host.name=master 13 2017-12-18 17:08:22,383 [myid:] - INFO [main:Environment@100] - Client environment:java.version=1.7.0_65 14 2017-12-18 17:08:22,383 [myid:] - INFO [main:Environment@100] - Client environment:java.vendor=Oracle Corporation 15 2017-12-18 17:08:22,385 [myid:] - INFO [main:Environment@100] - Client environment:java.home=/home/hadoop/jdk1.7.0_65/jre 16 2017-12-18 17:08:22,385 [myid:] - INFO [main:Environment@100] - Client environment:java.class.path=/home/hadoop/zookeeper-3.4.5/bin/../build/classes:/home/hadoop/zookeeper-3.4.5/bin/../build/lib/*.jar:/home/hadoop/zookeeper-3.4.5/bin/../lib/slf4j-log4j12-1.6.1.jar:/home/hadoop/zookeeper-3.4.5/bin/../lib/slf4j-api-1.6.1.jar:/home/hadoop/zookeeper-3.4.5/bin/../lib/netty-3.2.2.Final.jar:/home/hadoop/zookeeper-3.4.5/bin/../lib/log4j-1.2.15.jar:/home/hadoop/zookeeper-3.4.5/bin/../lib/jline-0.9.94.jar:/home/hadoop/zookeeper-3.4.5/bin/../zookeeper-3.4.5.jar:/home/hadoop/zookeeper-3.4.5/bin/../src/java/lib/*.jar:/home/hadoop/zookeeper-3.4.5/bin/../conf: 17 2017-12-18 17:08:22,385 [myid:] - INFO [main:Environment@100] - Client environment:java.library.path=/usr/java/packages/lib/i386:/lib:/usr/lib 18 2017-12-18 17:08:22,386 [myid:] - INFO [main:Environment@100] - Client environment:java.io.tmpdir=/tmp 19 2017-12-18 17:08:22,387 [myid:] - INFO [main:Environment@100] - Client environment:java.compiler=<NA> 20 2017-12-18 17:08:22,396 [myid:] - INFO [main:Environment@100] - Client environment:os.name=Linux 21 2017-12-18 17:08:22,397 [myid:] - INFO [main:Environment@100] - Client environment:os.arch=i386 22 2017-12-18 17:08:22,397 [myid:] - INFO [main:Environment@100] - Client environment:os.version=2.6.32-358.el6.i686 23 2017-12-18 17:08:22,398 [myid:] - INFO [main:Environment@100] - Client environment:user.name=root 24 2017-12-18 17:08:22,428 [myid:] - INFO [main:Environment@100] - Client environment:user.home=/root 25 2017-12-18 17:08:22,470 [myid:] - INFO [main:Environment@100] - Client environment:user.dir=/home/hadoop/zookeeper-3.4.5/bin 26 2017-12-18 17:08:22,472 [myid:] - INFO [main:ZooKeeper@438] - Initiating client connection, connectString=localhost:2181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@1238fa5 27 Welcome to ZooKeeper! 28 2017-12-18 17:08:22,994 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@966] - Opening socket connection to server localhost/0:0:0:0:0:0:0:1:2181. Will not attempt to authenticate using SASL (unknown error) 29 JLine support is enabled 30 2017-12-18 17:08:23,281 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@849] - Socket connection established to localhost/0:0:0:0:0:0:0:1:2181, initiating session 31 2017-12-18 17:08:24,145 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@1207] - Session establishment complete on server localhost/0:0:0:0:0:0:0:1:2181, sessionid = 0x16068706a9b0008, negotiated timeout = 30000 32 33 WATCHER:: 34 35 WatchedEvent state:SyncConnected type:None path:null 36 [zk: localhost:2181(CONNECTED) 0] ls / 37 [hadoop-ha, hbase, admin, zookeeper, consumers, config, 20171011, storm, yarn-leader-election, brokers, controller_epoch] 38 [zk: localhost:2181(CONNECTED) 3] get /hbase 39 40 cZxid = 0xc00000007 41 ctime = Wed Oct 25 17:29:19 CST 2017 42 mZxid = 0xc00000007 43 mtime = Wed Oct 25 17:29:19 CST 2017 44 pZxid = 0xf0000004a 45 cversion = 23 46 dataVersion = 0 47 aclVersion = 0 48 ephemeralOwner = 0x0 49 dataLength = 0 50 numChildren = 15 51 [zk: localhost:2181(CONNECTED) 4] ls / 52 [hadoop-ha, hbase, admin, zookeeper, consumers, config, 20171011, storm, yarn-leader-election, brokers, controller_epoch] 53 [zk: localhost:2181(CONNECTED) 5] ls /hbase 54 [meta-region-server, backup-masters, region-in-transition, draining, table, table-lock, running, master, namespace, hbaseid, online-snapshot, replication, recovering-regions, splitWAL, rs] 55 [zk: localhost:2181(CONNECTED) 6] ls /hbase/table 56 [hbase:meta, hbase:namespace, user] 57 [zk: localhost:2181(CONNECTED) 7] 待续......

优秀的个人博客,低调大师

Python+大数据计算平台,PyODPS架构手把手教你搭建

数据分析和机器学习 大数据基本都是建立在Hadoop系统的生态上的,其实一个Java的环境。很多人喜欢用Python和R来进行数据分析,但是这往往对应一些小数据的问题,或者本地数据处理的问题。如何将二者进行结合使其具有更大的价值?Hadoop现有的生态系统和现有的Python环境如上图所示。 MaxCompute MaxCompute是面向离线计算的大数据平台,提供TB/PB级的数据处理,多租户、开箱即用、隔离机制确保安全。MaxCompute上主要分析的工具就是SQL,SQL非常简单、容易上手,属于描述型。Tunnel提供数据上传下载通道,不需要经过SQL引擎的调度。 Pandas Pandas是基于numpy的数据分析的工具,里面最重要的结构是DataFrame,提供一系列绘图的API,背后是matplotlib的操作,非常容易和Python第三方库交互。 PyODPS架构 PyODPS即利用Python进行大数据分析,其架构如上图所示。底层是基础API,可以利用其操作MaxCompute上的表、函数或者资源。再上面是DataFrame框架,DataFrame包括两部分,一部分是前端,定义了一套表达式的操作,用户写的代码会转化成表达式树,这与普通的语言是一样的。用户可以自定义函数,也可以进行可视化,与第三方库进行交互。后端最下面是Optimizer,其作用是对表达式树进行优化。ODPS和pandas都是通过compiler和analyzer提交到Engine来执行。 背景 为什么要做DataFrame框架? 对于任何一个大数据分析工具,都会面临三个维度上的问题:表达力,API、语法、编程语言是否简单、符合直觉?数据,存储、元数据是否能压缩、有效?引擎,计算的性能是否足够?所以就会面临pandas和SQL两个选择。 如上图所示,pandas的表达力非常好,但是其数据只能放在内存中,引擎是单机的,受限于本机的性能。SQL的表达力有限,但是可以用于大量的数据,数据量小的时候没有引擎的优势,数据量大的时候引擎会变得很有优势。ODPS的目标是综合这两者的优点。 PyODPS DataFrame PyODPS DataFrame是使用Python语言写的,可以使用Python的变量、条件判断、循环。可以使用pandas类似的语法,定义了自己的一套前端,有了更好的表达力。后端可以根据数据来源来决定具体执行的引擎,是visitor的设计模式,可扩展。整个执行是延迟执行,除非用户调用立即执行的方法,否则是不会直接执行的。 从上图中可以看出,语法非常类似于pandas。 表达式和抽象语法树 从上图可以看出,用户从一个原始的Collection来进行GroupBy操作,再进行列选择的操作,最下面是Source的Collection。取了两个字段species,这两个字段是做By操作的,pental_length是进行聚合的操作取聚合值。Species字段是直接取出来,shortest字段是进行加一的操作。 Optimizer(操作合并) 后端首先会使用Optimizer对表达式树进行优化,先做GroupBy,然后在上面做列选择,通过操作合并可以去除petal_length做聚合操作,再加一,最终形成了GroupBy的Collection。 Optimizer(列剪枝) 用户join了两个data frame,再取来自data frame 的两个列的时候,如果提交到一个大数据的环境,这样一个过程是非常低下的,因为不是每个列都用到了。所以要对joined下的列进行剪枝操作。比如,data frame1我们只用到了其中的一个字段,我们只需要将字段截取出来做一个projection来形成新的Collection,data frame2也类似。这样,对这两部分进行校验操作的时候就能极大的减少数据的输出量。 Optimizer(谓词下推) 如果对两个data frame进行joined然后再分别进行过滤的话,这个过滤操作是应该下推到下面来执行的,这样就能减少joined 的输入的量。 可视化 提供了visualize()来方便用户进行可视化。在右边的例子中可以看到,ODSP SQL后端会compile成一条SQL执行。 后端 从上图中可以看出,计算后端是非常灵活的。用户甚至可以joined一个pandas的data frame和maxcompute上一个表的数据。 Analyzer Analyzer的作用是针对具体的后端,将一些操作进行转化。比如: 有些操作比如value_counts,pandas本身支持,因此对于pandas后端,无需处理;对于ODPS SQL后端,没有一个直接的操作来执行,所以在analyzer执行的时候,会被改写成groupby + sort的操作; 还有一些算子,在compile到ODPS SQL时,没有内建函数能完成,会被改写成自定义函数。 ODPS SQL后端 ODPS SQL后端怎么进行SQL编译再执行的操作?编译器可以从上到下遍历表达式树,找到Join或者Union。对于子过程,进行递归compile。再到Engine来具体执行时,会使用Analyzer对表达式树进行改写,compile自上而下的子过程,自底向上compile成SQL子句,最终得到完整的SQL语句,提交SQL并返回任务。 pandas后端 首先访问这个表达式树,然后对每个表达式树节点对应到pandas操作,整个表达式树遍历完之后就会形成DAG。Engine执行按DAG拓扑顺序执行,不断地把它应用到pandas操作,最终得到一个结果。对于大数据环境来说,pandas后端的作用是做本地DEBUG;当数据量很小时,我们可以使用pandas进行计算。 难点+坑 后端编译出错容易丢失上下文,多次optimize和analyze,导致难以查出是之前哪处visit node导致。解决:保证每个模块独⽴立性、测试完备; bytecode兼容问题,maxcompute只支持Python2.7的自定义函数的执行; SQL的执行顺序。 ML机器学习 机器学习是输入输出一个data frame。比如,有一个iris的data frame,先用name字段来做一个分类字段,调用split方法将其分成60%的训练数据和40%的测试数据。然后初始化一个RandomForests,其里面有一棵决策树,调用train方法训练训练数据,调用predict方法形成一个预测数据,调用segments[0]就可以看到可视化结果。 本文作者:佚名 来源:51CTO

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册