1. 为什么在离线环境里死磕本地源搭建 CDH 6.3.0大数据平台搭建这件事在线环境和离线环境完全是两个世界。在线环境下你敲一条yum install或者apt-get install系统自己去仓库拉包顺畅得像点外卖。但一旦进了内网、机房隔离区或者客户现场那种连外网出口都没有的环境事情就完全变了——所有依赖包、所有 RPM、所有 Parcel 文件都得你自己提前准备好一个都不能少。CDH 6.3.0 这个版本在大数据圈子里地位比较特殊。它是 Cloudera 和 Hortonworks 合并之后推出的一个相对成熟的发行版集成了 Hadoop 3.0、Hive 2.1、Spark 2.4、HBase 2.1、Impala 3.2 等一大批组件版本兼容性经过官方充分测试。很多企业内部的存量集群至今还跑在这个版本上新项目做 POC 或者扩容的时候也经常需要复现一套一模一样的 6.3.0 环境。问题在于Cloudera 后来把免费版的下载入口收得很紧很多包已经不那么容易从公开渠道拿到了这就逼着我们必须把本地源这套流程彻底吃透。所谓本地源说白了就是在内网自己搭一个 YUM 仓库和一个 Parcel 仓库让 Cloudera Manager后面简称 CM和集群里的每一台机器都从这个内网仓库拉包而不是去访问外网。这件事听起来简单但真正动手的时候坑一个接一个RPM 依赖缺失、Parcel 校验失败、CM 的 Agent 找不到仓库地址、cloudera-scm-server 起不来、数据库初始化报错……每一个都能让你卡上半天。这篇文章适合谁看如果你手头有一批内网机器需要从零搭一套 CDH 6.3.0或者你之前用在线方式装过、现在要迁移到离线环境那这篇内容基本能覆盖你 90% 的场景。我会把整个流程拆成准备工作、搭 YUM 源、搭 Parcel 源、装 CM、分发 Parcel、初始化集群这几大块每一块都讲清楚为什么这么做、参数怎么算、哪里容易翻车。全程基于我实际在几套内网环境里反复搭过的经验不是照抄官方文档。先说一个总的原则离线搭建的核心矛盾是依赖完整性和版本一致性。你准备的每一个 RPM、每一个 Parcel版本号必须和 CM 期望的完全对得上差一个小版本都可能让整个流程卡死。所以后面所有步骤我都会强调先确认版本再动手。2. 动手之前必须锁死的版本清单与机器规划2.1 组件版本对应关系错一个都不行CDH 6.3.0 不是一个孤立的版本号它背后有一整套配套的组件版本矩阵。你在准备安装包的时候必须把下面这几样东西的版本全部对齐组件版本说明Cloudera Manager6.3.0管理端版本必须和 CDH 大版本一致CDH Parcel6.3.0-1.cdh6.3.0.p0.1279813Parcel 的完整版本号后面那串 build 号很关键JDK1.8.0_181 及以上CDH 6.3 官方推荐 Oracle JDK 8OpenJDK 也能跑但要注意操作系统CentOS 7.6 / RHEL 7.67.x 系列都行但 7.6 最稳数据库MySQL 5.7 / PostgreSQL 9.6存 CM 的元数据MySQL 用得最多Python2.7.xCM Agent 依赖 Python 2别装 Python 3 覆盖系统默认这里重点说 Parcel 的版本号。很多人从别处拷来一个 Parcel 文件文件名是CDH-6.3.0-1.cdh6.3.0.p0.1279813-el7.parcel但 CM 界面上期望的可能是另一个 build 号。一旦对不上CM 就会一直显示正在下载或者直接报校验失败。正确的做法是先装好 CM进到 CM 界面看它到底期望哪个版本的 Parcel然后按那个版本号去准备文件。或者反过来你手头有什么版本的 Parcel就去找对应版本的 CM 安装包。两者必须成对出现。2.2 机器角色划分与资源估算一套最小可用的 CDH 6.3.0 集群至少需要三台机器。我一般这样规划管理节点1 台跑 cloudera-scm-server、MySQL、本地 YUM 源、本地 Parcel 源。这台机器是核心内存建议 16GB 起步因为 CM Server 本身吃内存加上 MySQL 和 HTTP 服务8GB 会很紧张。数据/计算节点2 台起跑 cloudera-scm-agent 和各个大数据组件。每台至少 16GB 内存、4 核 CPU、100GB 磁盘。如果要跑 Spark 或者 Impala内存往 32GB 以上走。磁盘规划上有个经验Parcel 解压后的体积大约是压缩包的两倍多。CDH 6.3.0 的 Parcel 包大概 2GB 左右解压后接近 5GB。再加上各个组件的日志、数据目录/opt和/var这两个分区一定要留足空间。我见过有人/opt只给了 10GB结果 Parcel 分发到一半就满了排查半天才发现是分区不够。网络方面所有机器必须在同一内网段主机名要能互相解析。强烈建议提前把/etc/hosts写好不要依赖 DNS因为内网 DNS 经常不稳定CM 对主机名解析非常敏感。每台机器的主机名要用 FQDN 格式比如node1.bigdata.local不要用简单的node1否则后面 CM 添加主机的时候会各种报错。2.3 系统层面的预处理别跳过在正式装任何东西之前这几件事必须做完否则后面一定会出问题关闭防火墙和 SELinux。内网环境虽然相对安全但 CM 组件之间通信端口非常多一个个开防火墙规则太累直接关掉最省事。SELinux 必须设成 disabled否则 Parcel 解压和文件权限会出各种诡异问题。配置时间同步。集群里所有机器时间必须一致差几秒钟都可能让 Kerberos如果后面要开或者 CM 的心跳检测出问题。内网没有 NTP 服务器的话就选一台机器做时间源其他机器跟它同步。调大文件句柄数和进程数。大数据组件对这两个参数很敏感默认的 1024 根本不够。在/etc/security/limits.conf里把nofile和nproc都调到 65536。关闭透明大页THP。这个对 Hadoop 性能影响很大虽然不影响安装但装完跑起来会明显感觉慢。在启动参数里加上transparent_hugepagenever。这些预处理看起来琐碎但每一条都是踩过坑之后总结出来的。尤其是 SELinux我遇到过好几次 Parcel 分发失败最后查出来就是 SELinux 在拦。3. 搭建本地 YUM 源让 CM 安装包有处可寻3.1 准备 CM 的 RPM 包CM 的安装包主要分两类cloudera-manager-server相关的一堆 RPM以及cloudera-manager-agent相关的一堆 RPM。这些包在 Cloudera 的官方仓库里是以 RPM 形式提供的你需要提前下载好。下载的时候有个技巧不要只下载 server 和 agent 这两个主包要把它们依赖的所有包一起下下来。因为离线环境里没有外网缺一个依赖就装不上。最稳妥的办法是找一台能联网的、和目標机器操作系统版本完全一致的机器用yumdownloader把依赖树整个拉下来# 在联网机器上执行把 CM 6.3.0 相关的包和依赖全部下载到本地目录 mkdir -p /tmp/cm_rpms cd /tmp/cm_rpms yumdownloader --resolve --destdir/tmp/cm_rpms cloudera-manager-server cloudera-manager-daemons cloudera-manager-agent--resolve这个参数是关键它会把所有依赖包一并下载。下载完之后你会得到一堆 RPM 文件把它们全部拷到内网的管理节点上。注意联网机器和目标机器的操作系统版本、架构必须完全一致都是 CentOS 7.6 x86_64。如果一个是 7.6 一个是 7.9依赖版本可能对不上装的时候会报冲突。3.2 用 createrepo 生成仓库元数据RPM 包准备好之后它们还只是一堆散落的文件YUM 不认识。你需要用createrepo工具把它们变成一个标准的 YUM 仓库。先把所有 RPM 放到一个目录里比如/var/www/html/cm6/然后执行# 安装 createrepo 工具如果管理节点本身能装的话或者从别处拷 rpm 过来装 yum install -y createrepo # 生成仓库元数据 createrepo /var/www/html/cm6/执行完之后目录里会多出一个repodata文件夹里面是 YUM 需要的索引文件。这时候这个目录就已经是一个可用的本地仓库了。接下来要让其他机器能访问这个仓库。最简单的方式是用 HTTP 服务。管理节点上装个 httpd或者 nginx把/var/www/html作为网站根目录yum install -y httpd systemctl start httpd systemctl enable httpd然后在每一台集群机器上配置 YUM 源指向这个地址。在/etc/yum.repos.d/下新建一个cm6.repo文件[cm6] nameCloudera Manager 6.3.0 baseurlhttp://node1.bigdata.local/cm6/ enabled1 gpgcheck0gpgcheck0是关掉 GPG 校验内网环境自己做的包没有官方签名关掉最省事。配好之后执行yum clean all yum repolist如果能看到cm6这个仓库说明源配好了。3.3 一个容易忽略的细节仓库路径和权限这里有个坑我踩过httpd 默认以apache用户运行如果/var/www/html/cm6/目录的权限不对其他机器访问的时候会返回 403。解决办法是确保目录对所有人可读chmod -R 755 /var/www/html/cm6/另外createrepo生成的repodata目录里如果有中文文件名或者特殊字符也可能导致解析失败。所以 RPM 包的文件名尽量保持原始英文名不要手动改名。还有一点如果你后面要加新的 RPM 包到这个仓库记得每次加完都要重新执行一次createrepo /var/www/html/cm6/否则新包不会被索引到。这个操作叫更新仓库元数据很多人加了包忘了更新然后纳闷为什么yum install找不到。4. 搭建本地 Parcel 源CDH 组件分发的命脉4.1 Parcel 到底是什么为什么不能用 RPM 装 CDH很多人第一次接触 CDH 会疑惑既然 CM 是 RPM 装的为什么 CDH 的组件Hadoop、Hive 这些不用 RPM而要用 Parcel原因在于 CDH 的组件太多了而且版本组合非常灵活。如果用 RPM 装每个组件都要维护一套 RPM 依赖关系升级和回滚会变得极其复杂。Parcel 本质上是一个自包含的压缩包里面包含了某个组件在特定操作系统上的所有二进制文件和配置模板。CM 把 Parcel 分发到各个节点解压到指定目录然后通过软链接的方式激活对应版本。这样升级的时候只需要换一个 Parcel回滚也只需要切回旧版本非常干净。所以离线搭建 CDHParcel 源是绕不开的。你需要准备三个文件CDH-6.3.0-1.cdh6.3.0.p0.1279813-el7.parcel主 Parcel 包大约 2GBCDH-6.3.0-1.cdh6.3.0.p0.1279813-el7.parcel.sha1SHA1 校验文件manifest.json描述所有可用 Parcel 的清单文件这三个文件缺一不可。.sha1文件用于校验 Parcel 完整性manifest.json告诉 CM 有哪些 Parcel 可用。4.2 生成 manifest.json 的正确姿势manifest.json这个文件是最容易出问题的。它不是一个随便写的 JSON而是有固定格式的CM 会解析它来获取 Parcel 的元信息。如果你从官方渠道拿到了原始的manifest.json那最好直接用。但很多时候你只有 Parcel 文件没有 manifest这时候就需要自己生成。格式大概是这样{ lastUpdated: 1600000000000, parcels: [ { parcelName: CDH-6.3.0-1.cdh6.3.0.p0.1279813-el7.parcel, components: [ { name: cdh, version: 6.3.0, pkg_version: 6.3.0 } ], hash: 生成的sha1值, parcelSize: 文件字节数 } ] }hash字段就是.sha1文件里的内容parcelSize是 Parcel 文件的字节大小。这两个值必须准确否则 CM 会认为文件损坏。生成.sha1文件很简单sha1sum CDH-6.3.0-1.cdh6.3.0.p0.1279813-el7.parcel | awk {print $1} CDH-6.3.0-1.cdh6.3.0.p0.1279813-el7.parcel.sha1注意.sha1文件里只放哈希值不要带文件名。有些教程说要把sha1sum的完整输出写进去那是错的CM 只读第一段哈希值带了文件名反而可能解析失败。4.3 配置 HTTP 服务暴露 Parcel 目录Parcel 文件准备好之后同样要通过 HTTP 暴露出去。在管理节点上建一个目录比如/var/www/html/cdh6/把三个文件放进去然后确保 httpd 能访问到。CM 默认会去http://server/cdh/这个路径找 Parcel。你可以在 CM 的配置里改这个路径但最省事的做法就是按默认路径来。具体来说CM 期望的 Parcel 仓库地址格式是http://node1.bigdata.local/cdh6/然后在 CM 界面里进入主机 - Parcel点击配置按钮把远程 Parcel 存储库 URL改成上面这个地址。改完之后 CM 会去这个地址拉manifest.json解析出可用的 Parcel 列表。提示如果你改了 Parcel 仓库地址记得把原来的官方地址删掉否则 CM 会同时去两个地方找可能造成混乱。4.4 Parcel 分发的底层逻辑与常见失败原因CM 分发 Parcel 的过程是这样的CM Server 从仓库下载 Parcel 到本地然后通过 Agent 把 Parcel 推送到各个节点的/opt/cloudera/parcel-cache/目录解压到/opt/cloudera/parcels/最后创建软链接。这个过程中最常见的失败原因有三个磁盘空间不足。前面说过Parcel 解压后体积翻倍/opt分区一定要够大。SHA1 校验失败。说明 Parcel 文件在传输过程中损坏了或者.sha1文件内容不对。重新下载或者重新生成校验文件。Agent 无法连接 Server。检查 Agent 的配置文件/etc/cloudera-scm-agent/config.ini里的server_host是否指向正确的管理节点。排查的时候Agent 的日志在/var/log/cloudera-scm-agent/cloudera-scm-agent.logServer 的日志在/var/log/cloudera-scm-server/cloudera-scm-server.log。这两个日志是定位问题的关键遇到报错先看日志不要瞎猜。5. 安装 Cloudera Manager Server 与 Agent 的实操链路5.1 安装 CM Server 并初始化数据库YUM 源配好之后在管理节点上装 CM Serveryum install -y cloudera-manager-daemons cloudera-manager-server装完之后先别急着启动CM Server 需要一个数据库来存元数据。以 MySQL 为例先建库建用户CREATE DATABASE scm DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; GRANT ALL ON scm.* TO scm% IDENTIFIED BY YourPassword123; FLUSH PRIVILEGES;然后运行 CM 自带的数据库初始化脚本/opt/cloudera/cm/schema/scm_prepare_database.sh mysql scm scm YourPassword123这个脚本会往scm库里建表。执行成功的话会输出All done, your SCM database is configured correctly!。如果报错大概率是数据库连接信息不对或者 MySQL 的 JDBC 驱动没放对位置。驱动文件要放在/usr/share/java/mysql-connector-java.jarCM 默认去这个路径找。数据库初始化完成之后启动 CM Serversystemctl start cloudera-scm-server启动过程比较慢第一次启动要建表、初始化大概需要一两分钟。用tail -f /var/log/cloudera-scm-server/cloudera-scm-server.log盯着日志看到Started Jetty server就说明起来了。然后浏览器访问http://node1.bigdata.local:7180默认账号密码都是admin。5.2 Agent 安装与主机纳管CM Server 起来之后接下来要把其他节点纳管进来。在每台数据/计算节点上装 Agentyum install -y cloudera-manager-daemons cloudera-manager-agent然后修改 Agent 配置把server_host指向管理节点# /etc/cloudera-scm-agent/config.ini server_hostnode1.bigdata.local启动 Agentsystemctl start cloudera-scm-agent回到 CM 界面进入主机 - 添加主机输入要纳管的机器主机名CM 会通过 SSH 去这些机器上做检查。这里有个前提管理节点必须能免密 SSH 到其他节点。提前配好 SSH 免密登录否则添加主机会失败。添加主机的过程中CM 会检查一堆东西JDK 版本、Python 版本、磁盘空间、时间同步、SELinux 状态等等。任何一项不通过都会卡住。所以前面第 2 章说的预处理这时候就体现出价值了。5.3 一个高频报错Agent 心跳丢失Agent 装好启动之后CM 界面上有时候会显示主机状态不良或者心跳丢失。这个问题我遇到过很多次原因通常有这几个主机名解析问题。Agent 上报的主机名和 CM 里配置的不一致。检查/etc/hosts和hostname命令的输出是否匹配。端口不通。Agent 和 Server 之间通过 7182 端口通信检查防火墙是否关了。Agent 进程没起来。看/var/log/cloudera-scm-agent/cloudera-scm-agent.log常见的是 Python 版本问题或者配置文件语法错误。排查这类问题的顺序是先看 Agent 进程在不在再看日志有没有报错最后检查网络连通性。不要一上来就重启重启解决不了根本问题。6. 集群初始化与 Parcel 激活的完整流程6.1 在 CM 界面完成 Parcel 分发与激活主机纳管完成之后进入 CM 的Parcel页面。如果前面的 Parcel 源配好了这里应该能看到CDH 6.3.0这个 Parcel状态是已下载或者可下载。点击下载CM 会从你配置的本地源拉取 Parcel。下载完成后点击分发CM 会把 Parcel 推送到所有 Agent 节点。分发完成后点击激活CM 会在所有节点上解压 Parcel 并创建软链接。这三个步骤下载、分发、激活是串行的每一步都要等所有节点完成才能进行下一步。如果某个节点卡住了先看那个节点的 Agent 日志。激活成功后/opt/cloudera/parcels/目录下会出现CDH-6.3.0-1.cdh6.3.0.p0.1279813这个目录同时会有一个CDH软链接指向它。这个软链接很重要后面所有组件都通过它来引用 Parcel 路径。6.2 集群安装向导里的关键选择Parcel 激活之后就可以进入集群安装向导了。CM 会引导你一步步选择要安装的组件、分配角色、配置参数。这里有几个关键选择需要说明集群名称随便起但建议用有意义的名称比如prod-cluster或者test-cluster。组件选择根据你的需求勾选。最小化安装一般选 Core HadoopHDFS YARN ZooKeeper如果要跑 SQL 就加 Hive要跑 Spark 就加 Spark。角色分配CM 会自动推荐角色分配方案但小集群里建议手动调整把 NameNode 和 ResourceManager 放在内存大的机器上。数据库配置Hive、Oozie 这些组件需要自己的数据库提前在 MySQL 里建好库和用户在向导里填进去。向导走完之后CM 会自动启动所有服务。第一次启动会比较慢因为要格式化 HDFS、初始化各种元数据。全部服务变成绿色状态就说明集群搭好了。6.3 验证集群可用性的几个必做检查集群起来之后不要急着交付先做几个基本检查HDFS 健康检查。在 CM 界面看 HDFS 服务状态有没有块丢失、副本不足的告警。也可以手动跑一个hdfs dfsadmin -report看 DataNode 是否都注册上了。YARN 资源检查。跑一个简单的 MapReduce 或者 Spark 任务确认 YARN 能正常分配资源。Hive 连通性。用beeline连一下 HiveServer2跑个show databases看看。时间同步检查。在所有节点上跑date确认时间一致。这些检查看起来简单但能提前发现 80% 的配置问题。我见过太多集群装完看着是绿的一跑任务就各种报错最后发现是某个基础配置没弄对。7. 离线搭建过程中最耗时的几个坑与排查思路7.1 Parcel 版本号不匹配导致的死循环这是离线搭建里最恶心的问题。现象是CM 界面上 Parcel 一直显示正在下载进度条不动或者下载完了但状态是未激活点激活没反应。根本原因通常是 Parcel 的 build 号和 CM 期望的不一致。CM 内部有一个期望的 Parcel 版本列表这个列表在 CM 的某个配置文件里。如果你提供的 Parcel 版本不在这个列表里CM 就不会认。解决办法有两个一是找到 CM 期望的版本号去准备对应版本的 Parcel二是修改 CM 的配置让它接受你手头的版本。第二种方法比较 hack不推荐。最稳妥的还是第一种先确认 CM 版本再找对应的 Parcel。怎么确认 CM 期望哪个版本在 CM 界面的 Parcel 页面把鼠标悬停在 Parcel 名称上或者看页面源码通常能看到完整的版本号。另一个办法是看 CM Server 的日志里面会打印它去仓库请求的 Parcel 文件名。7.2 数据库连接池耗尽与元数据锁CM Server 和 MySQL 之间的连接池如果配置不当在集群规模稍大的时候会出现连接耗尽。现象是 CM 界面操作变慢日志里报Could not get a connection。解决办法是调大 MySQL 的max_connections同时调整 CM 的数据库连接池配置。CM 的数据库配置在/etc/cloudera-scm-server/db.properties里可以调整com.cloudera.cmf.db.maxActive这个参数。另一个相关的问题是元数据锁。如果多个 CM 操作同时进行可能会在数据库层面产生锁等待。这种情况一般等一会儿就好但如果频繁出现就要考虑优化操作节奏不要同时触发多个重操作。7.3 Agent 端 Python 环境冲突CM Agent 是用 Python 2 写的如果目标机器上装了 Python 3 并且把python命令指向了 Python 3Agent 启动就会报语法错误。检查方法python --version如果输出是 Python 3.x就需要把python命令改回 Python 2或者修改 Agent 的启动脚本显式指定 Python 2 的路径。CentOS 7 默认自带 Python 2.7一般不会有这个问题但如果有人手动装过 Python 3 并改了软链接就会踩这个坑。7.4 主机名大小写与 FQDN 的坑CM 对主机名非常敏感。如果一台机器hostname输出是Node1但/etc/hosts里写的是node1.bigdata.localCM 就可能认为这是两台不同的机器。统一规范是所有机器的主机名都用小写 FQDN/etc/hosts里也用小写hostnamectl set-hostname设置的时候也用小写。不要混用大小写不要用短主机名和 FQDN 混着来。这个坑的隐蔽性在于它不会立刻报错而是在某些特定操作比如添加主机、分发 Parcel的时候才暴露出来排查起来很费时间。8. 一些让离线搭建更顺手的个人经验搭过几套之后我总结出几个能明显提升效率的做法分享出来。第一把所有安装包和配置文件提前整理成一个离线包。包括 CM 的 RPM、CDH 的 Parcel、MySQL 的 RPM、JDK 的 RPM以及所有配置文件的模板。这样下次再搭的时候直接拷过去就能用不用重新找包。我一般会建一个目录结构offline-cdh6/ ├── rpms/ │ ├── cm6/ │ ├── mysql/ │ └── jdk/ ├── parcels/ │ ├── CDH-6.3.0-....parcel │ ├── CDH-6.3.0-....parcel.sha1 │ └── manifest.json └── configs/ ├── hosts-template ├── limits.conf └── cm6.repo第二写一个预处理脚本。把关闭防火墙、关闭 SELinux、配置 hosts、调优内核参数这些操作写成一个 shell 脚本每台新机器上跑一遍。这样能避免手工操作遗漏。第三Parcel 分发之前先手动验证 SHA1。在管理节点上跑一遍sha1sum和.sha1文件对比确认文件没损坏再分发。这个检查只要几秒钟但能省掉后面几十分钟的排查。第四CM 的日志级别可以临时调高。遇到疑难问题时把 CM Server 的日志级别从 INFO 调到 DEBUG能看到更详细的内部流程。调完之后记得调回来否则日志会涨得很快。第五数据库一定要提前优化。MySQL 的innodb_buffer_pool_size建议设成物理内存的 50% 到 70%max_connections至少 500。CM 的元数据操作比较频繁数据库性能直接影响 CM 的响应速度。最后说一个心态上的经验离线搭建 CDH 这件事第一次做大概率会卡在某个地方这是正常的。关键是要养成看日志、查版本、验依赖的习惯不要凭感觉瞎试。每一个报错背后都有明确的原因找到它解决它下次就不会再踩了。