大数据运维

# 0. 前置 ## 0.1 开源镜像 - jdk国内下载镜像 : https://repo.huaweicloud.com/java/jdk/ - Zookeeper国内镜像 : https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/ - Kafka国内镜像: https://mirrors.cloud.tencent.com/apache/kafka/ - Flink 国内镜像: http://mirrors.cloud.tencent.com/apache/flink/ | http://archive.apache.org/dist/flink/ - clickHouse 国内镜像 https://mirrors.tuna.tsinghua.edu.cn/clickhouse/ | 升级 https://blog.csdn.net/htmljsp/article/details/109221378 - Spark 国内镜像: https://mirrors.tuna.tsinghua.edu.cn/apache/spark/ - Hadoop 国内镜像 : https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common/ - - 镜像站: - https://mirrors.tuna.tsinghua.edu.cn/apache/ - https://mirrors.cloud.tencent.com/apache/ - https://mirrors.huaweicloud.com/home ## 0.2 最新版本 - Hadoop-3.3.4 - 2022 Aug 8 - # 1. Hadoop 大数据平台的规划与部署 ## 1.1 Hadoop 生态圈 - 对于大数据运维来说,就是要实现 Hadoop 生态圈各种软件的最优组合 - ![Hadoop生态圈](pic/Hadoop生态圈.png) - **1- HDFS(Hadoop 分布式文件系统)- Hadoop** - HDFS 是 Hadoop 生态圈中提供分布式存储支持的系统,上层的很多计算框架(Hbase、Spark 等)都依赖于 HDFS 存储。HDFS 可在低成本的通用硬件上运行。它不但解决了海量数据存储问题,还解决了数据安全问题。 - HDFS 分布式文件系统的实现原理图: - ![HDFS分布式文件系统的实现原理](pic/HDFS分布式文件系统的实现原理.png) - HDFS 主要由 NameNode 和 DataNode 两部分组成 - NameNode 是 HDFS 的管理节点,它存储了元数据(文件对应的数据块位置、文件大小、文件权限等)信息,同时负责读、写调度和存储分配; - DataNode 节点是真正的数据存储节点,用来存储数据。另外,在 DataNode 上的每个数据块会根据设置的副本数进行分级复制,保证同一个文件的每个数据块副本都不在同一个机器上。 - **2- MapReduce(分布式计算模型)离线计算 - Hadoop** - MapReduce 这种 Map 加 Reduce 的简单计算模型,解决了当时单机计算的缺陷,时至今日还有很多场景仍在使用这种计算模型,但已经慢慢不能满足我们的使用需求了。 - 大数据时代的今天,数据量都在 PB 级甚至 EB 级别,对数据的分析效率有了更高的要求。 - 第二代计算模型产生了,如 Tez 和 Spark,它们通过大量使用内存、灵活的数据交换,更少的磁盘读写来提高分析效率。 - **3- Yarn(分布式资源管理器)- Hadoop** - 在YARN中,支持CPU和内存两种资源管理,资源管理由ResourceManager(RM)、ApplicationMaster(AM)和NodeManager(NM)共同完成。其中,RM负责对各个NM上的资源进行统一管理和调度。 而NodeManager则负责资源的供给和隔离。当用户提交一个应用程序时,会创建一个用以跟踪和管理这个程序的AM,它负责向RM申请资源,并要求NM启动指定资源的任务。这就是YARN的基本运行机制。 - Yarn 作为一个通用的分布式资源管理器,它可以管理多种计算模型,如 Spark、Storm、MapReduce 、Flink 等都可以放到 Yarn 下进行统一管理。 - **4- Spark(内存计算)** - A fast and general compute engine for Hadoop data. Spark provides a simple and expressive programming model that supports a wide range of applications, including ETL, machine learning, stream processing, and graph computation. [用于Hadoop数据的快速通用计算引擎。Spark 提供了一个简单且富有表现力的编程模型,支持广泛的应用程序,包括 ETL、机器学习、流处理和图形计算。] - 以内存换效率 - 说到 Spark,不得不提 MapReduce。传统的 MapReduce 计算过程的每一个操作步骤发生在内存中,但产生的中间结果会储存在磁盘里,下一步操作时又会将这个中间结果调用到内存中,如此循环,直到分析任务最终完成。这就会产生读取成本,造成效率低下。 - 而 Spark 在执行分析任务中,每个步骤也是发生在内存之中,但中间结果会直接进入下一个步骤,直到所有步骤完成之后才会将最终结果写入磁盘。也就是说 Spark 任务在执行过程中,中间结果不会“落地”,这就节省了大量的时间。 - 如果执行步骤不多,可能看不出 MapReduce 和 Spark 执行效率的区别,但是当一个任务有**很多执行步骤时**,Spark 的执行效率就体现出来了。 - **5- HBase(分布式列存储数据库)** - A scalable, distributed database that supports structured data storage for large tables.[一个可扩展的分布式数据库,支持大型表的结构化数据存储。] - **面向行存储**和**面向列存储** - 面向行存储的数据库主要适合于事务性要求严格的场合,这种传统关系型数据库为了实现强一致性,通过严格的事务来进行同步,这就让系统在可用性和伸缩性方面大大折扣。 - 面向列存储的数据库也叫非关系型数据库(NoSQL),比如Cassandra、HBase等。这种数据库通常将不同数据的同一个属性值存在一起,在查询时只遍历需要的数据,实现了数据即是索引。 的最大优点是查询速度快,这对数据完整性要求不高的大数据处理领域,比如互联网,犹为重要。 - Hbase继承了列存储的特性,它非常适合需对数据进行随机读、写操作、比如每秒对PB级数据进行几千次读、写访问是非常简单的操作。 其次,Hbase构建在HDFS之上,其内部管理的文件全部存储在HDFS中。 这使它具有高度容错性和可扩展性,并支持Hadoop mapreduce程序设计模型。 - 如果你的应用是交易历史查询系统、查询场景简单,检索条件较少、每天有千万行数据更新、那么Hbase将是一个很好的选择。其实,行存储和列存储只是不同的维度而已,没有天生的优劣,而大数据时代大部分的查询模式决定了列式存储优于行式存储。 - **6- Hive(数据仓库)** - A data warehouse infrastructure that provides data summarization and ad hoc querying.[提供数据汇总和即席查询的数据仓库基础结构。] - Hive 定义了一种类似 SQL 的查询语言(HQL),它可以将 SQL 转化为 MapReduce 任务在 Hadoop 上执行。这样,小李就可以用更简单、更直观的语言去写程序了。 - 你不熟悉 MapReduce 程序,只要会写标准的 SQL 语句,也能对 HDFS 上的海量数据进行分析和计算。 - **7- Oozie(工作流调度器)** - 对于 Oozie 来说,工作流就是一系列的操作(如 Hadoop 的 MR,Pig 的任务、Shell 任务等),通过 Oozie 可以实现多个任务的依赖性。也就是说,一个操作的输入依赖于前一个任务的输出,只有前一个操作完全完成后,才能开始第二个。 - Oozie 工作流通过 hPDL 定义(hPDL 是一种 XML 的流程定义语言),工作流操作通过远程系统启动任务。当任务完成后,远程系统会进行回调来通知任务已经结束,然后再开始下一个操作。 - **8- Sqoop 与 Pig** - Pig: A high-level data-flow language and execution framework for parallel computation.[用于并行计算的高级数据流语言和执行框架。] - 把原来存储在 MySQL 中的数据导入 Hadoop 的 HDFS 上,是否能实现呢? - 通过 Sqoop(SQL-to-Hadoop)就能实现,它主要用于传统数据库和 Hadoop 之间传输数据。数据的导入和导出本质上是 MapReduce 程序,充分利用了 MR 的并行化和容错性。 - 通过 Hive 可以把脚本和 SQL 语言翻译成 MapReduce 程序,扔给计算引擎去计算。Pig 与 Hive 类似,它定义了一种数据流语言,即 Pig Latin,它是 MapReduce 编程的复杂性的抽象,Pig Latin 可以完成排序、过滤、求和、关联等操作,支持自定义函数。 Pig 自动把 Pig Latin 映射为 MapReduce 作业,上传到集群运行,减少用户编写 Java 程序的苦恼。 - **9- Flume(日志收集工具)** - 现在电商平台的数据是通过 rsync 方式定时从电商服务器上同步到 Hadoop 平台的某台机器,然后通过这台机器 put 到 HDFS 上,每天定时同步一次,由于数据量很大,同步一次数据在一个小时左右,并且同步数据的过程会消耗大量网络带宽。 有没有更合适的数据传输机制,一方面可以保证数据传输的实时性、完整性,另一方面也能节省网络带宽。 - Flume 是将数据从产生、传输、处理并最终写入目标路径的过程抽象为数据流,在具体的数据流中,数据源支持在 Flume 中定制数据发送方,从而支持收集各种不同协议数据。 - 同时,Flume 数据流提供对日志数据进行简单处理的能力,如过滤、格式转换等。此外,Flume 还具有能够将日志写往各种数据目标(文件、HDFS、网络)的能力。在 Hadoop 平台,我们主要使用的是通过 Flume 将数据从源服务器写入 Hadoop 的 HDFS 上。 - **10- Kafka(分布式消息队列)** - 生产者生产(Produce)各种数据、消费者(Consume)消费(分析、处理)这些数据。那么面对这些需求,如何高效、稳定的完成数据的生产和消费呢?这就需要在生产者与消费者之间,建立一个通信的桥梁,这个桥梁就是消息系统。从微观层面来说,这种业务需求也可理解为不同的系统之间如何传递消息。 - Kafka 是 Apache 组织下的一个开源系统,它的最大特性就是可以实时的处理大量数据以满足各种需求场景:比如基于 Hadoop 平台的数据分析、低时延的实时系统、Storm/Spark 流式处理引擎等。 - **11- ZooKeeper(分布式协作服务)** - A high-performance coordination service for distributed applications.[用于分布式应用程序的高性能协调服务。] - 对集群技术应该并不陌生,就拿最简单的双机热备架构来说,双机热备主要用来解决单点故障问题,传统的方式是采用一个备用节点,这个备用节点定期向主节点发送 ping 包,主节点收到 ping 包以后向备用节点发送回复信息,当备用节点收到回复的时候就会认为当前主节点运行正常,让它继续提供服务。 而当主节点故障时,备用节点就无法收到回复信息了,此时,备用节点就认为主节点宕机,然后接替它成为新的主节点继续提供服务。 - ZooKeeper 相当于一个和事佬的角色,如果两人之间发生了一些矛盾或者冲突,无法自行解决的话,这个时候就需要 ZooKeeper 这个和事佬从中进行调解,而和事佬调解的方式是站在第三方客观的角度,根据一些规则(如道德规则、法律规则),客观的对冲突双方做出合理、合规的判决。 - **12- Ambari(大数据运维工具)** - A web-based tool for provisioning, managing, and monitoring Apache Hadoop clusters which includes support for Hadoop HDFS, Hadoop MapReduce, Hive, HCatalog, HBase, ZooKeeper, Oozie, Pig and Sqoop. Ambari also provides a dashboard for viewing cluster health such as heatmaps and ability to view MapReduce, Pig and Hive applications visually alongwith features to diagnose their performance characteristics in a user-friendly manner.[一个基于Web的工具,用于配置,管理和监控Apache Hadoop集群,其中包括对Hadoop HDFS,Hadoop MapReduce,Hive,HCatalog,HBase,ZooKeeper,Oozie,Pig和Sqoop的支持。 Ambari还提供了一个用于查看集群运行状况(如热图)的仪表板,以及可视化查看MapReduce,Pig和Hive应用程序以及功能的功能,以用户友好的方式诊断其性能特征。] - Ambari 是一个大数据基础运维平台,它实现了 Hadoop 生态圈各种组件的自动化部署、服务管理和监控告警,Ambari 通过 puppet 实现自动化安装和配置,通过 Ganglia 收集监控度量指标,用 Nagios 实现故障报警。 - 目前 Ambari 已支持大多数 Hadoop 组件,包括 HDFS、MapReduce、Oozie、Hive、Pig、 Hbase、ZooKeeper、Sqoop、Kafka、Spark、Druid、Storm 等几十个常用的 Hadoop 组件。 - 作为大数据运维人员,通过 Ambari 可以实现统一部署、统一管理、统一监控,可极大提高运维工作效率。 - **13- Avro** - A data serialization system.[一种数据序列化系统。] - **14- Cassandra** - A scalable multi-master database with no single points of failure.[一个可扩展的多主数据库,没有单点故障。] - **15- Chukwa** - : A data collection system for managing large distributed systems.[用于管理大型分布式系统的数据收集系统。] - **16- Mahout** - A Scalable machine learning and data mining library.[一个可扩展的机器学习和数据挖掘库。] - **17- Ozone** - A scalable, redundant, and distributed object store for Hadoop.[用于 Hadoop 的可扩展、冗余和分布式对象存储。] - **18- Submarine** - A unified AI platform which allows engineers and data scientists to run Machine Learning and Deep Learning workload in distributed cluster.[一个统一的AI平台,允许工程师和数据科学家在分布式集群中运行机器学习和深度学习工作负载。] - **19- Tez** - A generalized data-flow programming framework, built on Hadoop YARN, which provides a powerful and flexible engine to execute an arbitrary DAG of tasks to process data for both batch and interactive use-cases. Tez is being adopted by Hive™, Pig™ and other frameworks in the Hadoop ecosystem, and also by other commercial software (e.g. ETL tools), to replace Hadoop™ MapReduce as the underlying execution engine.[一个基于Hadoop YARN 构建的通用数据流编程框架,它提供了一个强大而灵活的引擎来执行任意DAG任务,以处理批处理和交互式用例的数据。Tez正在被Hive™,Pig™和Hadoop生态系统中的其他框架以及其他商业软件(例如ETL工具)采用,以取代Hadoop™ MapReduce作为底层执行引擎。] ## 1.2 Hadoop 发行版选型和伪分布式平台的构建 ### A. Hadoop 有哪些发行版 - 与 Linux 有众多发行版类似,Hadoop 也有很多发行版本,但基本上分为两类,即开源社区版和商业付费版。 - Cloudera 的 CDH 发行版、Hortonworks 的 HDP 发行版等,所以,目前而言,不收费的 Hadoop 版本主要有三个,即 Apache Hadoop、Cloudera 的 CDH 版本、Hortonworks 的 HDP。 - Cloudera 的 CDH 版本和 Hortonworks 的 HDP 版本在大数据开源社区互为竞争,两分天下,占据了国内、外 90% 以上的大数据市场 - 很多云厂商在云端也提供了 Hadoop 服务,比如亚马逊的 Elastic MapReduce(EMR)、Microsoft Azure Hadoop、阿里云 E-MapReduce(Elastic MapReduce,EMR)等 - 最终,Cloudera 和 Hortonworks 从竞争走到了一起 ### B. Apache Hadoop 发行版本 - Apache Hadoop 是最原始的 Hadoop 发行版本,目前总共发行了三个大版本,即 Hadoop1.x、Hadoop2.x、Hadoop3.x,每个版本的功能特性如下表所示: - ![ApacheHadoop发行版](pic/ApacheHadoop发行版.png) - Apache Hadoop 发行版提供源码包和二进制包两种形式下载,对我们来说,下载二进制包更加方便,点击 https://archive.apache.org/dist/hadoop/common/ 获得下载。 ### C. Hortonworks Hadoop 发行版 - Hortonworks 的主打产品是 HDP,同样是 100% 开源的产品,它最接近 Apache Hadoop 的版本,除此之外,HDP 还包含了 Ambari,这是一款开源的 Hadoop 管理系统。它可以实现统一部署、自动配置、自动化扩容、实时状态监控等,是个功能完备的大数据运维管理平台。 - 在使用 HDP 发行版时,可以通过 Ambari 管理功能,实现 Hadoop 的快速安装和部署,并且对大数据平台的运维也有很大帮助,可以说 Ambari 实现了与 HDP 的无缝整合。 - HDP 至今也发行了三个版本,即 HDP1.x、HDP2.x 和 HDP3.x,跟 Apache Hadoop 发行的大版本遥相呼应,而 HDP 发行版的安装是基于 Ambari 实现的,通过 HDP 提供的 rpm 文件,可以在 Ambari 平台实现自动化的安装和扩容 ### D. Cloudera Hadoop 发行版 - Cloudera 是最早将 Hadoop 商用的公司,目前旗下的产品主要有 CDH、Cloudera Manager、Cloudera Data Platform(CDP)等 - ![ClouderaHadoop发行版](pic/ClouderaHadoop发行版.png) - CDH 支持 yum/apt 包、RPM 包、tarball 包、Cloudera Manager 四种方式安装,但在最新版本 CDH6 中已经不提供 tarball 方式了,这也是 Cloudera 进行产品整合的一个信号。 - Cloudera 在宣布与 Hortonworks 合并后,他们使用了类似红帽公司的开源战略,提供了订阅机制来收费,同时为开发人员和试用提供了无支援的免费版本,并向商业用户提供订阅付费的版本。至此,Cloudera 成为全球第二大开源公司(红帽第一)。 - Cloudera 承诺 CDH 和 HDP 平台将可以继续使用,直到 2022 年。 ### E. 如何选择发行版 - 对于初学入门的话,建议选择 Apache Hadoop 版本最好,因为它的社区活跃、文档、资料详实。而如果要在企业生产环境下使用的话,建议需要考虑以下几个因素: - 是否为开源产品(是否免费),这点很重要; - 是否有稳定的发行版本,开发版是不能用在生产上的; - 是否已经接受过实践的检验,看看是否有大公司在用(自己不能当小白鼠); - 是否有活跃的社区支持、充足的资料,因为遇到问题,我们可以通过社区、搜索等网络资源来解决问题。 - 在国内大型互联网企业中,使用较多的是 CDH 或 HDP 发行版本,个人推荐采用 HDP 发行版本,原因是部署简单、性能稳定。 ### F. 伪分布式安装 Hadoop 集群 - 安装规划 - 伪分布式安装 Hadoop 只需要一台机器,硬件配置最低为 **4 核 CPU、8G 内存**即可,我们采用 **Hadoop-3.2.1 版本**,此版本要求 Java 版本至少是 **JDK8**,这里以 **JDK1.8.0_171、CentOS7.6** - 根据运维经验以及后续的升级、自动化运维需要,将 Hadoop 程序安装到 **/opt/hadoop** 目录下,Hadoop 配置文件放到 **/etc/hadoop** 目录下。 - 安装过程 - 下载 Apache Hadoop 发行版本的 hadoop-3.2.1.tar.gz 二进制版本文件 ```shell [root@hadoop3server hadoop]# useradd hadoop [root@hadoop3server ~]# mkdir /opt/hadoop [root@hadoop3server ~]# cd /opt/hadoop [root@hadoop3server hadoop]# tar zxvf hadoop-3.2.1.tar.gz [root@hadoop3server hadoop]# ln -s hadoop-3.2.1 current [root@hadoop3server hadoop]# chown -R hadoop:hadoop /opt/hadoop ``` - **注意**,将解压开的 hadoop-3.2.1.tar.gz 目录软链接到 current 是为了后续运维方便,因为可能涉及 Hadoop 版本升级、自动化运维等操作,这样设置后,可以大大减轻运维工作量。 - Hadoop 程序安装完成后,还需要拷贝配置文件到 /etc/hadoop 目录下,执行如下操作: ```shell [root@hadoop3server ~]#mkdir /etc/hadoop [root@hadoop3server hadoop]#cp -r /opt/hadoop/current/etc/hadoop /etc/hadoop/conf [root@hadoop3server hadoop]# chown -R hadoop:hadoop /etc/hadoop ``` - 接着,还需要安装一个 JDK,这里使用的是 JDK 1.8.0_171,将其安装到 /usr/java 目录下,操作过程如下: ```shell [root@hadoop3server ~]#mkdir /usr/java [root@hadoop3server ~]#cd /usr/java [root@hadoop3server java]#tar zxvf jdk-8u171-linux-x64.tar.gz [root@hadoop3server java]#ln -s jdk1.8.0_171 default ``` - 这个操作过程的最后一步,做这个软连接,也是为了后续运维自动化配置、升级方便。 - 最后一步,还需要创建一个 Hadoop 用户,然后设置 Hadoop 用户的环境变量,配置如下: ```shell [root@hadoop3server ~]#useradd hadoop [root@hadoop3server ~]# more /home/hadoop/.bashrc # .bashrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi # User specific aliases and functions export JAVA_HOME=/usr/java/default export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar export PATH=$JAVA_HOME/bin:$PATH export HADOOP_HOME=/opt/hadoop/current export HADOOP_MAPRED_HOME=${HADOOP_HOME} export HADOOP_COMMON_HOME=${HADOOP_HOME} export HADOOP_HDFS_HOME=${HADOOP_HOME} export HADOOP_YARN_HOME=${HADOOP_HOME} export CATALINA_BASE=${HTTPFS_CATALINA_HOME} export HADOOP_CONF_DIR=/etc/hadoop/conf export HTTPFS_CONFIG=/etc/hadoop/conf export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin ``` - 这里创建的 Hadoop 用户,就是以后管理 Hadoop 平台的管理员用户,**所有对 Hadoop 的管理操作都需要通过这个用户来完成**,这一点需注意。 - HADOOP_HOME 是指定 Hadoop 安装程序的目录 - HADOOP_CONF_DIR 是指定 Hadoop 配置文件目录 - 配置 Hadoop 参数 - Hadoop 安装完成后,先来了解一下其安装目录下几个重要的目录和文件,这里将 Hadoop 安装在了 /opt/hadoop/current 目录下,打开这个目录,需要掌握的几个目录如下表所示: - ![配置Hadoop参数](pic/配置Hadoop参数.png) - Hadoop 的配置相当复杂,不过这些是后面要讲的内容。而在伪分布模式下,仅仅需要修改一个配置文件即可,该文件是 core-site.xml,此文件目前位于 /etc/hadoop/conf 目录下,在此文件 标签下增加如下内容: ```xml fs.defaultFS hdfs://hadoop3server ``` - 其中,fs.defaultFS 属性描述的是访问 HDFS 文件系统的 URI 加一个 RPC 端口, 不加端口的话,**默认是 8020**。另外,hadoop3server 可以是服务器的主机名,也可以是任意字符,但都需要将此标识在服务器的 **/etc/hosts** 进行解析,也就是添加如下内容: ```shell 172.16.213.232 hadoop3server ``` - 这里的 172.16.213.232 就是安装 Hadoop 软件的服务器 IP 地址。 - 启动 Hadoop 服务 - 配置操作完成后,下面就可以启动 Hadoop 服务了,虽然是伪分布模式,但 Hadoop 所有的服务都必须要启动,需要启动的服务有如下几个。 - ![启动 Hadoop 服务](pic/启动Hadoop服务.png) - 要启动 Hadoop 集群的服务,必须以 Hadoop 用户来执行,并且每个服务的启动是有先后顺序的,下面依次启动每个服务。 - **(1)启动 NameNode 服务** - 首先需要对 NameNode 进行格式化,命令如下: ```shell [root@hadoop3server ~]# su - hadoop [hadoop@hadoop3server ~]$ cd /opt/hadoop/current/bin [hadoop@hadoop3server bin]$ hdfs namenode -format ``` - 然后就可以启动 NameNode 服务了,操作过程如下: ```shell [hadoop@hadoop3server conf]$ hdfs --daemon start namenode [hadoop@hadoop3server conf]$ jps|grep NameNode 27319 NameNode ``` - 通过 **jps** 命令查看 NameNode 进程是否正常启动,如果无法正常启动,可以查看 NameNode 启动日志文件,检查是否有异常信息抛出,这里的日志文件路径是:**/opt/hadoop/current/logs/hadoop-hadoop-namenode-hadoop3server.log**。 - NameNode 启动完成后,就可以通过 Web 页面查看状态了,默认会启动一个 http 端口 9870,可通过访问地址:http://172.16.213.232:9870 查看 NameNode 服务状态,如下图所示: - ![NameNode服务状态](pic/NameNode服务状态.png) - 第一个是 Hadoop 中 namenode 的访问地址为 hdfs://hadoop3server:8020这是我们在配置文件中指定过的; - 运行模式显示“Safe mode is ON”,这表示目前 namenode 处于安全模式下了,为什么呢,其实图中已经说明原因了,Namenode 在启动时,会检查 DataNode 的状态,如果 DataNode 上报的 block 个数达到了元数据记录的 block 个数的 0.999 倍才可以离开安全模式, 否则一直运行在安全模式。安全模式也叫只读模式,此模式下,对 HDFS 上的数据无法进行写操作。因为现在还没启动 DataNode 服务,所以肯定是处于安全模式下。 - HDFS 容量,Configured Capacity 目前显示为 0,这也是因为还没启动 DataNode 服务导致的,等启动后,应该就有容量显示了。 - “Live node”及“Dead node”分别显示目前集群中活跃的 DataNode 节点和故障(死)DataNode 节点,运维经常通过监控这个页面中“Dead node”的值来判断集群是否出现异常。 - **(2)启动 secondarynamenode 服务** - 在 NameNode 服务启动完成后,就可以启动 secondarynamenode 服务了,直接执行如下命令: ```shell [hadoop@hadoop3server ~]$ hdfs --daemon start secondarynamenode [hadoop@hadoop3server ~]$ jps|grep SecondaryNameNode 29705 SecondaryNameNode ``` - 与 NameNode 类似,如果无法启动 secondarynamenode 进程,可以通过 /opt/hadoop/current/logs/hadoop-hadoop-secondarynamenode-hadoop3server.log 文件检查 secondarynamenode 启动日志中是否存在异常。 - **(3)启动 DataNode 服务** - 现在是时候启动 DataNode 服务了,直接执行如下命令: ```shell [hadoop@hadoop3server ~]$ hdfs --daemon start datanode [hadoop@hadoop3server ~]$ jps|grep DataNode 3876 DataNode ``` - 如果无法启动,可通过查看 /opt/hadoop/current/logs/hadoop-hadoop-datanode-hadoop3server.log 文件检查 datanode 启动过程是否存在异常。 - 到这里为止,分布式文件系统 HDFS 服务已经启动完成,可以对 HDFS 文件系统进行读、写操作了。现在再次通过 http://172.16.213.232:9870 查看 NameNode 服务状态页面,如图所示: - ![NameNode服务状态](pic/NameNode服务状态1.png) - 从图中可以看出,HDFS 集群中安全模式已经关闭,并且集群容量和活跃节点已经有数据了,这是因为 datanode 服务已经正常启动了。 - **(4)启动 ResourceManager 服务** - 接下来,还需要启动分布式计算服务,首先启动的是 ResourceManager,启动方式如下: ```shell [hadoop@hadoop3server ~]$ yarn --daemon start resourcemanager [hadoop@hadoop3server ~]$ jps|grep ResourceManager 4726 ResourceManager ``` - 注意,启动 resourcemanager 服务的命令**变成了 yarn,而不是 hdfs**,记住这个细节。 - 同理,如果 ResourceManager 进程无法启动,可以通过检查 /opt/hadoop/current/logs/hadoop-hadoop-resourcemanager-hadoop3server.log 日志文件来排查 ResourceManager 启动问题。 - ResourceManager 服务启动后,会默认启动一个 http 端口 8088,可通过访问 http://172.16.213.232:8088 查看 ResourceManager 的 Web 状态页面,如下图所示: - ![ResourceManager的Web状态](pic/ResourceManager的Web状态.png) - 在上图中,需要重点关注的是 ResourceManager 中可用的内存资源、CPU 资源数及活跃节点数,目前看来,这些数据都是 0,是因为还没有 NodeManager 服务启动。 - **(5)启动 NodeManager 服务** - 在启动完成 ResourceManager 服务后,就可以启动 NodeManager 服务了,操作过程如下: ```shell [hadoop@hadoop3server ~]$ yarn --daemon start nodemanager [hadoop@hadoop3server ~]$ jps|grep NodeManager 8853 NodeManager ``` - 如果有异常,可通过检查 /opt/hadoop/current/logs/hadoop-hadoop-nodemanager-hadoop3server.log 文件来排查 NodeManager 问题。 - **(6)启动 Jobhistoryserver 服务** - 等待 ResourceManager 和 NodeManager 服务启动完毕后,最后还需要启动一个 Jobhistoryserver 服务,操作过程如下: ```shell [hadoop@hadoop3server ~]$ mapred --daemon start historyserver [hadoop@hadoop3server ~]$ jps|grep JobHistoryServer 1027 JobHistoryServer ``` - 注意,启动 Jobhistoryserver 服务的命令变成了 **mapred**,而非 yarn。这是因为 Jobhistoryserver 服务是基于 MapReduce 的,Jobhistoryserver 服务启动后, 会运行一个 http 端口,默认端口号是 **19888**,可以通过访问此端口查看每个任务的历史运行情况,如下图所示: - ![启动Jobhistoryserver服务](pic/启动Jobhistoryserver服务.png) - 至此,Hadoop 伪分布式已经运行起来了,可通过 jps 命令查看各个进程的启动信息: ```shell [hadoop@hadoop3server ~]$ jps 12288 DataNode 1027 JobHistoryServer 11333 NameNode 1158 Jps 29705 SecondaryNameNode 18634 NodeManager 19357 ResourceManager ``` - 运用 Hadoop HDFS 命令进行分布式存储 - Hadoop 的 HDFS 是一个分布式文件系统,要对 HDFS 进行操作,需要执行 HDFS Shell,跟 Linux 命令很类似,因此,只要熟悉 Linux 命令,可以很快掌握 HDFS Shell 的操作。 - **执行 HDFS Shell 建议在 Hadoop 用户或其他普用用户下执行**。 - (1)查看 hdfs 根目录数据,可通过如下命令: ```shell [hadoop@hadoop3server ~]$ hadoop fs -ls / ``` - 通过这个命令的输出可知,刚刚创建起来的 HDFS 文件系统是没有任何数据的,不过可以自己创建文件或目录。 - (2)在 hdfs 根目录创建一个 logs 目录,可执行如下命令: ```shell [hadoop@hadoop3server ~]$ hadoop fs -mkdir /logs ``` - (3)从本地上传一个文件到 hdfs 的 /logs 目录下,可执行如下命令: ```shell [hadoop@hadoop3server ~]$ hadoop fs -put /data/test.txt /logs [hadoop@hadoop3server ~]$ hadoop fs -put /data/db.gz /logs [hadoop@hadoop3server ~]$ hadoop fs -ls /logs Found 2 items -rw-r--r-- 3 hadoop supergroup 150569 2020-03-19 07:11 /logs/test.txt -rw-r--r-- 3 hadoop supergroup 95 2020-03-24 05:11 /logs/db.gz ``` - 注意,这里的 /data/test.txt 及 db.gz 是操作系统下的一个本地文件,通过执行 put 命令,可以看到,文件已经从本地磁盘传到 HDFS 上了。 - (4)要查看 hdfs 中一个文本文件的内容,可执行如下命令: ```shell [hadoop@hadoop3server ~]$ hadoop fs -cat /logs/test.txt [hadoop@hadoop3server ~]$ hadoop fs -text /logs/db.gz ``` - 可以看到,在 HDFS 上的压缩文件通过“-text”参数也能直接查看,因为默认情况下 Hadoop 会自动识别常见的压缩格式。 - (5)删除 hdfs 上一个文件,可执行如下命令: ```shell [hadoop@hadoop3server ~]$ hadoop fs -rm -r /logs/test.txt ``` - 注意,HDFS 上面的文件,**只能创建和删除,无法更新一个存在的文件**,如果要更新 HDFS 上的文件,需要先删除这个文件,然后提交最新的文件即可。 - 在 Hadoop 中运行 MapReduce 程序 - 借用 Hadoop 安装包中附带的一个 mapreduce 的 demo 程序,做个简单的 MR 计算。 - 这个 demo 程序位于 $HADOOP_HOME/share/hadoop/mapreduce 路径下,这个环境下的路径为 /opt/hadoop/current/share/hadoop/mapreduce,在此目录下找到一个名为 hadoop-mapreduce-examples-3.2.1.jar 的 jar 文件 - 单词计数是最简单也是最能体现 MapReduce 思想的程序之一,可以称为 MapReduce 版“Hello World”,hadoop-mapreduce-examples-3.2.1.jar 文件中包含了一个 wordcount 功能,它主要功能是用来统计一系列文本文件中每个单词出现的次数。下面开始执行分析计算。 - (1)创建一个新文件 - 创建一个测试文件 demo.txt,内容如下: ```txt Linux Unix windows hadoop Linux spark hive hadoop Unix MapReduce hadoop Linux hive windows hadoop spark ``` - (2)将创建的文件存入 HDFS ```shell [hadoop@hadoop3server ~]$ hadoop fs -mkdir /demo [hadoop@hadoop3server ~]$ hadoop fs -put /opt/demo.txt /demo [hadoop@hadoop3server ~]$ hadoop fs -ls /demo Found 1 items -rw-r--r-- 3 hadoop supergroup 105 2020-03-24 06:02 /demo/demo.txt ``` - 这里在 HDFS 上创建了一个目录 /demo,然后将刚才创建好的本地文件 put 到 HDFS 上,这里举例是一个文件,如果要统计多个文件内容,将多个文件都上传到 HDFS 的 /demo 目录即可。 - (3)执行分析计算任务 ```shell [hadoop@hadoop3server ~]$ hadoop jar /opt/hadoop/current/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.2.1.jar wordcount /demo /output [hadoop@hadoop3server ~]$ hadoop fs -ls /output Found 2 items -rw-r--r-- 3 hadoop supergroup 0 2020-03-24 06:05 /output/_SUCCESS -rw-r--r-- 3 hadoop supergroup 61 2020-03-24 06:05 /output/part-r-00000 [hadoop@hadoop3server ~]$ hadoop fs -text /output/part-r-00000 Linux 3 MapReduce 1 Unix 2 hadoop 4 hive 2 spark 2 windows 2 ``` - 最后的两个路径都是 HDFS 上的路径,第一个路径是分析读取文件的目录,**必须存在**;第二个路径是分析任务输出结果的存放路径,**必须不存在**,分析任务会自动创建这个目录。 - 任务执行完毕后,可以查看 /output 目录下有两个文件,其中: - _SUCCESS,任务完成标识,表示执行成功; - part-r-00000,表示输出文件名,常见的名称有 part-m-00000、part-r-00001,其中,带 m 标识的文件是 mapper 输出,带 r 标识的文件是 reduce 输出的,00000 为 job 任务编号,part-r-00000 整个文件为结果输出文件。 - 通过查看 part-r-00000 文件内容,可以看到 wordcount 的统计结果。左边一列是统计的单词,右边一列是在文件中单词出现的次数。 - (4)在 ResourceManager 的 Web 页面展示运行任务 - 上面在命令行执行的 wordcount 统计任务虽然最后显示是执行成功了,统计结果也正常,但是在 ResourceManager 的 Web 页面并没有显示出来。 - 究其原因,其实很简单:这是因为那个 mapreduce 任务并没有真正提交到 yarn 上来,因为默认 mapreduce 的运行环境是 local(本地),要让 mapreduce 在 yarn 上运行,需要做几个参数配置就行了。 - 需要修改的配置文件有两个,即 mapred-site.xml 和 yarn-site.xml,在你的配置文件目录,找到它们。 - mapred-site.xml 文件 ```xml mapreduce.framework.name yarn yarn.app.mapreduce.am.env HADOOP_MAPRED_HOME=${HADOOP_HOME} mapreduce.map.env HADOOP_MAPRED_HOME=${HADOOP_HOME} mapreduce.reduce.env HADOOP_MAPRED_HOME=${HADOOP_HOME} ``` - 其中,mapreduce.framework.name 选项就是用来指定 mapreduce 的运行时环境,指定为 yarn 即可,下面的三个选项是指定 mapreduce 运行时一些环境信息。 - 最后,修改另一个文件 yarn-site.xml,添加如下内容到 标签中: ```xml yarn.nodemanager.aux-services mapreduce_shuffle ``` - 其中,yarn.nodemanager.aux-services 选项代表可在 NodeManager 上运行的扩展服务,需配置成 mapreduce_shuffle,才可运行 MapReduce 程序。 - 配置修改完成后,需要重启 ResourceManager 与 nodemanager 服务才能使配置生效。 - 现在,我们再次运行刚才的那个 mapreduce 的 wordcount 统计,所有执行的任务都会在 ResourceManager 的 Web 页面展示出来,如下图所示: - ![ResourceManager的Web页面](pic/ResourceManager的Web页面.png) - 从图中可以清晰的看出,执行任务的 ID 名、执行任务的用户、程序名、任务类型、队列、优先级、启动时间、完成时间、最终状态等信息。从运维角度来说,这个页面有很多信息都需要引起关注,比如任务最终状态是否有失败的,如果有,可以点击倒数第二列“Tracking UI”下面的 History 链接查看日志进行排查问题。 - Namenode 的 Web 页面和 ResourceManager 的 Web 页面在进行大数据运维工作中,经常会用到,这些 Web 界面主要用来状态监控、故障排查,更多使用细节和技巧 ### G. 补充 - cdh,离线安装有什么好办法 - 自己搭建个本地yum仓库就行了,后续从本地下载安装或者升级。 ## 1.3 自动化运维工具 Ansible 在部署大数据平台下的应用 ### A. 大数据环境下海量服务器如何运维 - 主流的自动化运维管理工具有 Puppet、Saltstack、Ansible 等 - Ansible 是基于 Python 语言开发的,只需要在一台普通的服务器上运行即可,不需要在客户端服务器上安装客户端。因为 Ansible 是基于 SSH 远程管理,而 Linux 服务器基本都开启了 SSH 服务,所以 Ansible 不需要为配置工作添加额外的支持。 ### B. Ansible 命令行模式的使用 - Ansible 执行自动化任务,分为以下两种执行模式: -(1)ad-hoc(单个模块),单条命令的批量执行,或者叫命令行模式; -(2)playbook,为面向对象的编程,可以把多个想要执行的任务放到一个 playbook 中,当然多个任务在事物逻辑上最好是有上下关联的,通过多个任务可以完成一个总体的目标。 - 命令行模式一般用于测试、临时应用等场景,而 playbook 方式,主用用于正式环境,通过编写 playbook 文件,可实现固定的、批量的对系统或服务进行配置以及维护工作。 - Ansible,使用时需要注意两个概念:管理机和远程主机。管理机是安装 Ansible 的机器,远程主机是 Ansible 批量操作的对象,可以是一个或一组主机。Ansible 通过管理机发出批量操作远程主机的指令,这些指令在每个远程主机上依次执行。 - 1. Ansible 的执行流程与配置文件 - Ansible 的安装非常简单,执行如下命令即可: ```shell [root@master ~]# yum install epel-release ``` - 然后即可通过 yum 工具安装 Ansible: ```shell [root@master ~]# yum install ansible ``` - 安装好的 Ansible 配置文件位于 /etc/ansible 目录下,需要重点关注的有 ansible.cfg、hosts 文件。 - (1)hosts 文件(以下 hosts 文件均指 /etc/ansible/hosts 文件) - 该文件用来定义 Ansible 批量操作的主机列表,主机列表有多种书写方式,最简单的格式如下: ```shell [webservers] ixdba1.net ixdba2.net [dbservers] db.ixdba1.net db.ixdba2.net ``` - 中括号中的名字代表组名,可以根据需求将庞大的主机分成具有标识的组。比如上面分了两个组 webservers 和 dbservers 组。 - 主机(hosts)部分可以使用域名、主机名、IP 地址表示;当然使用前两者时,需要主机能反解析到相应的 IP 地址,一般此类配置中多使用 IP 地址;**未分组的机器需保留在 hosts 的顶部**。 - 也可在 hosts 文件中,指定主机的范围,示例如下: ```shell [web] www[01:50].ixdba.net [db] db[a:f].ixdba.ent ``` - 这个配置中,web 主机组的主机为 www01.ixdba.net、www02.ixdba.net、www03.ixdba.net 等以此类推,一直到 www50.ixdba.net。下面的 db 组中的 a:f 表示从 a 到 f 的字符。 - 在 hosts 文件中,还可以使用变量,变量分为主机变量和组变量两种类型,常用的变量如下表所示: - ![ansible-hosts-变量](pic/ansible-hosts-变量.png) - 例如,在 hosts 中可以这么使用变量: ```shell [test] 192.168.1.1 ansible_ssh_user=root ansible_ssh_pass='abc123' 192.168.1.2 ansible_ssh_user=breeze ansible_ssh_pass='123456' ``` - (2)ansible.cfg 文件 - 此文件定义了 Ansible 主机的默认配置熟悉,比如默认是否需要输入密码、是否开启 sudo 认证、action_plugins 插件的位置、hosts 主机组的位置、是否开启 log 功能、默认端口、key 文件位置等。一般情况下这个文件无需修改,**保存默认即可**。 - 注意:host_key_checking 表示是否关闭第一次使用 Ansible 连接客户端时 yes/no 的连接确认提示,False 表示关闭,我们只需要去掉此选项的注释即可。这个问题其实是 SSH 连接的问题,因为 Linux 下的主机在第一次 SSH 连接到一个新的主机时, 一般会需要 yes/no 的连接确认,这在自动化运维中是不需要的,因此需要禁止这种确认。在 Ansible 中通过设置 host_key_checking 为 False 就可以避免这种情况。 - 2. commands 模块 - 命令行下执行 ansible,基本格式如下: ```shell ansible 主机或组 -m 模块名 -a '模块参数' ansible参数 ``` - 其中: - 主机或组,在 /etc/ansible/hosts 里进行指定; - 模块名,可以通过 ansible-doc -l 查看目前安装的模块,默认不指定时,使用的是 command 模块; - 模块参数,可以通过 “ansible-doc 模块名”查看具体用法。 - ansible 常用的参数如下表所示: - ![ansible常用的参数](pic/ansible常用的参数.png) - 几个使用 command 模块的例子: ```shell ansible 172.16.213.157 -m command -a 'pwd' ansible 172.16.213.157 -m command -a 'chdir=/tmp/ pwd' ansible 172.16.213.157 -m command -a 'chdir=/var/www tar zcvf /data/html.tar.gz html' ansible 172.16.213.157 -m command -a 'creates=/tmp/tmp.txt date' ansible 172.16.213.157 -m command -a 'removes=/tmp/tmp.txt date' ansible 172.16.213.157 -m command -a 'ps -ef|grep sshd' (此命令会执行失败) ``` - 上面的例子是对主机 172.16.213.157 进行的操作,在实际应用中需要替换为主机组。另外,还用到了 command 模块的几个选项: - creates,后跟一个文件名,当远程主机上存在这个文件时,该命令不执行,否则执行; - chdir,在执行指令之前,先切换到该指定的目录; - removes,后跟一个文件名,当该文件存在时,该选项执行,否则不执行。 - 注意:commands 模块的执行,在远程主机上,需有 Python 环境的支持。该模块通过在 -a 参数后面跟上要在远程机器上执行的命令即可完成远程操作,不过命令里如果带有特殊字符(“<”、“>”、“|”、“&”等),则执行不成功,也就是 commands 模块不支持这些特殊字符。上面最后那个例子无法执行成功就是这个原因。 - 3. shell 模块 - shell 模块的功能和用法与 command 模块一样,不过 shell 模块执行命令的时候使用的是 /bin/sh,该模块可以执行任何命令。看下面几个例子: ```shell ansible 172.16.213.233 -m shell -a 'ps -ef|grep sshd' (此命令可执行成功) ansible 172.16.213.233 -m shell -a 'sh /tmp/install.sh >/tmp/install.log' ``` - 最后这个例子是执行远程机器上的脚本,其路径为 /tmp/install.sh(远程主机上的脚本,非本机的),然后将执行命令的结果存放在远程主机路径 /tmp/install.log 中,注意在进行保存文件的时候,写上全路径,否则就会保存在登录之后的默认路径中。 官方文档表示 command 用起来更安全,更有可预知性,但从我使用角度来说,并没发现有多大差别。 - 4. raw 模块和 script 模块 - raw 模块功能与 command 和 shell 模块类似,shell 能够完成的操作,raw 也都能完成。不同的是,raw 模块不需要远程主机上的 Python 环境。 - Ansible 要执行自动化操作,需在管理机上安装 Ansible,客户机上安装 Python,如果客户机上没有安装,那么 command、shell 模块将无法工作,但 raw 可以正常工作。因此,若有的机器没有装 Python,或者装的版本在 2.4 以下,就可以使用 raw 模块来装 Python、python-simplejson 等。 - 若有些机器根本安装不了 Python 的话(如交换机、路由器等),那么,直接用 raw 模块是最好的选择。下面看几个例子: ```shell [root@localhost ansible]#ansible 172.16.213.107 -m raw -a "ps -ef|grep sshd|awk '{print \$2}'" [root@localhost ansible]#ansible 172.16.213.107 -m raw -a "yum -y install python26" –k ``` - script 模块是将管理端的 shell 脚本拷贝到被管理的远程主机上执行,其原理是先将 shell 复制到远程主机,再在远程主机上执行。此模块的执行,不需要远程主机上的 Python 环境。看下面这个例子: ```shell [root@localhost ansible]# ansible 172.16.213.233 -m script -a ' /mnt/install1.sh >/tmp/install1.log' ``` - 脚本 /tmp/install1.sh 在管理端本机上,script 模块执行的时候将脚本传送到远程的 172.16.213.233 主机中,然后执行这个脚本,同时,将执行的输出日志文件保存在远程主机对应的路径 /tmp/install.log 下,这里保存日志文件的时候,最好用全路径。 - 5. file 模块、copy 模块与 synchronize 模块 - file 模块功能强大,主要用于远程主机上的文件或目录操作,该模块包含如下选项: - ![file模块](pic/file模块.png) - 下面来看几个使用示例。 - (1)创建一个不存在的目录,并进行递归授权: ```shell [root@localhost ansible]# ansible 172.16.213.233 -m file -a "path=/mnt/abc123 state=directory" [root@localhost ansible]# ansible 172.16.213.233 -m file -a "path=/mnt/abc123 owner=nobody group=nobody mode=0644 recurse=yes" [root@localhost ansible]# ansible 172.16.213.233 -m file -a "path=/mnt/ansibletemp owner=sshd group=sshd mode=0644 state=directory " ``` - (2)创建一个文件(如果不存在),并进行授权: ```shell [root@localhost ansible]# ansible 172.16.213.233 -m file -a "path=/mnt/syncfile.txt mode=0444 state=touch" ``` - (3)创建一个软连接(将 /etc/ssh/sshd_config 软连接到 /mnt/sshd_config): ```shell [root@localhost ansible]#ansible 172.16.213.233 -m file -a "src=/etc/ssh/sshd_config dest=/mnt/sshd_config owner=sshd state=link" ``` - (4)删除一个压缩文件: ```shell [root@localhost ansible]#ansible 172.16.213.233 -m file -a "path=/tmp/backup.tar.gz state=absent" ``` - (5)创建一个文件: ```shell [root@localhost ansible]#ansible 172.16.213.233 -m file -a "path=/mnt/ansibletemp state=touch" ``` - 接着继续来看 copy 模块,此模块用来复制文件到远程主机,copy 模块包含的选项如下表所示: - ![copy模块](pic/copy模块.png) - 下面是几个例子。 - (1)拷贝文件并进行权限设置。 ```shell [root@localhost ansible]#ansible 172.16.213.233 -m copy -a 'src=/etc/sudoers dest=/mnt/sudoers owner=root group=root mode=440 backup=yes' ``` - copy 默认会对存在的备份文件进行覆盖,通过 backup=yes 参数可以在覆盖前,对之前的文件进行自动备份。 - (2)拷贝文件之后进行验证。 ```shell [root@localhost ansible]#ansible 172.16.213.233 -m copy -a "src=/etc/sudoers dest=/mnt/sudoers validate='visudo -cf %s'" ``` - 这里用了 validate 参数,表示在复制之前验证要拷贝的文件是否正确。如果验证通过则复制到远程主机上,%s 是一个文件路径的占位符,在文件被复制到远程主机之前,它会被替换为 src 后面的文件。 - (3)拷贝目录并进行递归设定目录的权限。 ```shell [root@localhost ansible]#ansible 172.16.213.233 -m copy -a 'src=/etc/yum dest=/mnt/ owner=hadoop group=hadoop directory_mode=644' [root@localhost ansible]#ansible 172.16.213.233 -m copy -a 'src=/etc/yum/ dest=/mnt/bak owner=hadoop group=hadoop directory_mode=644' ``` - 上面这两个命令执行是有区别的,第一个是拷贝管理机的 /etc/yum 目录到远程主机的 /mnt 目录下;第二个命令是拷贝管理机 /etc/yum 目录下的所有文件或子目录到远程主机的 /mnt/bak 目录下。 - copy 模块拷贝小文件还可以,如果拷贝大文件或者目录的话,速度很慢,不建议使用。此时推荐使用 **synchronize 模块**,此模块通过调用 rsync 进行文件或目录同步,同步速度很快,还指出增量同步,该模块常用的选项如下表所示: - ![synchronize模块](pic/synchronize模块.png) - 下面看几个例子。 - (1)同步本地的 /mnt/rpm 到远程主机 ```shell # 172.16.213.77 的 /tmp 目录下 ansible 172.16.213.77 -m synchronize -a 'src=/mnt/rpm dest=/tmp' ``` - (2)将远程主机 172.16.213.77 上 /mnt/a 文件拷贝到本地的 /tmp 目录下。 ```shell ansible 172.16.213.77 -m synchronize -a 'mode=pull src=/mnt/a dest=/tmp' ``` - 6. cron 模块、yum 模块与 service 模块 - cron 模块用于管理计划任务,常用选项含义如下表所示: - ![cron模块](pic/cron模块.png) - 下面是几个示例。 - (1)系统重启时执行 /data/bootservice.sh 脚本。 ```shell ansible 172.16.213.233 -m cron -a 'name="job for reboot" special_time=reboot job="/data/bootservice.sh" ' ``` - 此命令执行后,会在 172.16.213.233 的 crontab 中写入“@reboot /data/bootservice.sh”,通过“crontab -l ”可以查看到。 - (2)表示在每周六的 1:20 分执行"yum -y update"操作。 ```shell ansible 172.16.213.233 -m cron -a 'name="yum autoupdate" weekday="6" minute=20 hour=1 user="root" job="yum -y update"' ``` - (3)表示在每周六的 1:30 分以 root 用户执行 "/home/ixdba/backup.sh" 脚本。 ```shell ansible 172.16.213.233 -m cron -a 'backup="True" name="autobackup" weekday="6" minute=30 hour=1 user="root" job="/home/ixdba/backup.sh"' ``` - (4)会在 /etc/cron.d 创建一个 check_http_for_ansible 文件,表示每天的 12:30 分通过 root 用户执行 /home/ixdba/check_http.sh 脚本。 ```shell ansible 172.16.213.233 -m cron -a 'name="checkhttp" minute=30 hour=12 user="root" job="/home/ixdba/check_http.sh" cron_file="check_http_for_ansible" ' ``` - (5)删除一个计划任务。 ```shell ansible 172.16.213.233 -m cron -a 'name="yum update" state=absent' ``` - 接着,再看看 yum 模块的使用,此模块用来通过 yum 包管理器来管理软件包,常用选项以及含义如下表所示: - ![yum模块](pic/yum模块.png) - 下面是几个示例。 - (1)通过 yum 安装 Redis。 ```shell ansible 172.16.213.77 -m yum -a "name=redis state=installed" ``` - (2)通过 yum 卸载 Redis。 ```shell ansible 172.16.213.77 -m yum -a "name=redis state=removed" ``` - (3)通过 yum 安装 Redis 最新版本,并设置 yum 源。 ```shell ansible 172.16.213.77 -m yum -a "name=redis state=latest enablerepo=epel" ``` - (4)通过指定地址的方式安装 bash。 ```shell ansible 172.16.213.78 -m yum -a "name=http://mirrors.aliyun.com/centos/7.4.1708/os/x86_64/Packages/bash-4.2.46-28.el7.x86_64.rpm" state=present' ``` - 最后看看 service 模块,此模块用于管理远程主机上的服务,该模块包含如下选项: - ![service模块](pic/service模块.png) - 下面是几个使用示例。 - (1)启动 httpd 服务。 ```shell ansible 172.16.213.233 -m service -a "name=httpd state=started" ``` - (2)设置 httpd 服务开机自启。 ```shell ansible 172.16.213.233 -m service -a "name=httpd enabled=yes" ``` - 7. setup 模块获取 Ansible facts 信息 - Ansible facts 是远程主机上的系统信息,主要包含 IP 地址、操作系统版本、网络设备、Mac 地址、内存、磁盘、硬件等信息,这些信息根据远程主机的信息来作为执行条件操作的场景,非常有用。 比如,我们可以根据远程主机的操作系统版本,选择安装不同版本的软件包,或者收集远程主机上每个主机的主机名、IP 地址等信息。 - 那么如何获取 Ansible facts 信息呢,其实,Ansible 提供了一个 setup 模块来收集远程主机的系统信息,这些 facts 信息可以直接以变量的形式使用。 - 下面是两个使用的例子。 - (1)查看主机内存信息。 ```shell [root@localhost ~]# ansible 172.16.213.77 -m setup -a 'filter=ansible_*_mb' ``` - (2)查看接口为 eth0-2 的网卡信息。 ```shell [root@localhost ~]# ansible 172.16.213.77 -m setup -a 'filter=ansible_em[1-2]' ``` - 在后面 ansible-playbook 内容中会讲到的 playbooks 脚本中,经常会用到一个参数 gather_facts,其与该模块相关。gather_facts 默认值为 yes,也就是说,在使用 Ansible 对远程主机执行任何一个 playbook 之前, 总会先通过 setup 模块获取 facts,并将信息暂存在内存中,直到该 playbook 执行结束为止。 - 8. user 模块与 group 模块 - user 模块请求的是 useradd、userdel、usermod 三个指令;group 模块请求的是 groupadd、groupdel、groupmod 三个指令,常用的选项如下表所示: - ![user模块](pic/user模块.png) - 下面看几个使用例子。 - (1)创建一个用户 usertest1。 ```shell ansible 172.16.213.77 -m user -a "name=usertest1" ``` - (2)创建用户 usertest2,并设置附加组。 ```shell ansible 172.16.213.77 -m user -a "name=usertest2 groups=admins,developers" ``` - (3)删除用户 usertest1 的同时,删除用户根目录。 ```shell ansible 172.16.213.77 -m user -a "name=usertest1 state=absent remove=yes" ``` - (4)批量修改用户密码。 ```shell [root@localhost ~]# echo "linux123www" | openssl passwd -1 -salt $(< /dev/urandom tr -dc '[:alnum:]' | head -c 32) -stdin $1$yjJ74Wid$x0QUaaHzA8EwWU2kG6SRB1 [root@localhost ~]# ansible 172.16.213.77 -m user -a 'name=usertest2 password="$1$yjJ74Wid$x0QUaaHzA8EwWU2kG6SRB1" ' ``` - 其中: - -1 表示采用的是 MD5 加密算法; - -salt 指定 salt 值,在使用加密算法进行加密时,即使密码一样,由于 salt 不一样,所以计算出来的 hash 值也不一样,除非密码一样,salt 值也一样,计算出来的 hash 值才一样; - “< /dev/urandom tr -dc '[:alnum:]' | head -c 32”产生一个随机的 salt; - passwd 的值不能是明文,passwd 关键字后面应该是密文,密文会被保存在 /etc/shadow 文件中。 ### C. ansible-playbook 的使用 - 1. playbook 简介与文件格式 - playbook 字面意思是剧本,现实中由演员按照剧本表演,在 Ansible 中,这次由计算机进行表演,由计算机安装、部署应用,提供对外服务,以及组织计算机处理各种各样的事情。 - playbook 文件由 YMAL 语言编写。YMAL 格式类似于 JSON 的文件格式,便于理解、阅读和书写。首先学习了解一下 YMAL 的格式,对后面书写 playbook 很有帮助。以下是 playbook 常用的 YMAL 格式规则。 - 文件的第一行应该以“---”(三个连字符)开始,表明 YMAL 文件的开始; - 在同一行中,# 之后的内容表示注释,类似于 shell 、Python 和 Ruby; - YMAL 中的列表元素以“-”开头,然后紧跟着一个空格,后面为元素内容; - 同一个列表中的元素应该保持相同的缩进,否则会被当作错误处理; - play 中的 hosts、variables、roles、tasks 等对象的表示方法都是键值中间以“:”分隔表示,“:”后面还要增加一个空格。 - 首先看下面这个例子: ```yaml - apple - banana - orange ``` - 等价于 JSON 的下面这个格式: ```json [ “apple”, “banana”, “orange” ] ``` - playbook 文件是通过 ansible-playbook 命令进行解析的,该命令会根据自上而下的顺序依次执行 playbook 文件中的内容。 - 2. playbook 的组成 - playbook 是由一个或多个“play”组成的列表。play 的主要功能在于,将事先合并为一组的主机组合成事先通过 Ansible 定义好的角色。将多个 play 组织在一个 playbook 中就可以让它们联同起来,按事先编排好的机制完成一系列复杂的任务。 - playbooks 主要有以下四部分构成,分别如下: - Target 部分,定义将要执行 playbook 的远程主机组; - Variable 部分,定义 playbook 运行时需要使用的变量; - Task 部分,定义将要在远程主机上执行的任务列表; - Handler 部分,定义 task 执行完成以后需要调用的任务。 - 下面介绍下构成 playbook 的四个组成部分。 - (1)Hosts 和 Users - playbook 中的每一个 play 的目的都是为了让某个或某些远程主机以某个指定的用户身份执行任务。 - hosts:用于指定要执行任务的远程主机,每个 playbook 都必须指定 hosts,hosts 也可以使用通配符格式。主机或主机组在 inventory 清单(hosts 文件)中指定,可以使用系统默认的 /etc/ansible/hosts,也可以自己编辑,在运行的时候加上 -i 选项, 可指定自定义主机清单的位置。 - remote_user:用于指定在远程主机上执行任务的用户,可以指定任意用户,也可以使用 sudo,但是用户必须要有执行相应任务的权限。 - (2)任务列表 - play 的主体部分是 task list,其中的各任务按次序逐个在 hosts 中指定所有远程主机上的执行,即在所有远程主机上完成第一个任务后再开始第二个。在运行自上而下某 playbook 时,如果中途发生错误,则所有已执行任务都将回滚,因此在更正 playbook 后需要重新执行一次。 - task 的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行一个命令,哪怕执行一次或多次,其结果是一样的,这意味着 playbook 多次执行是安全的,因为其结果均一致。tasks 包含 name 和要执行的模块,name 是可选的,只是为了便于用户阅读,建议加上, 模块是必需的,同时也要给予模块相应的参数。 - 定义 tasks 推荐使用 module: options 格式,例如: ```json service: name=httpd state=running ``` - (3)handlers - 用于当关注的资源发生变化时采取一定的操作,handlers 和“notify”配合使用。“notify”这个动作可用于在每个 play 执行的最后被触发,这样可以避免当多次有改变发生时,每次都执行指定的操作,通过“notify”,仅在所有的变化发生完成后一次性地执行指定操作。 - 在 notify 中列出的操作称为 handler,也就是说 notify 用来调用 handler 中定义的操作。 - 注意:在 notify 中定义的内容一定要和 handlers 中定义的“- name”内容一样,这样才能达到触发的效果,否则会不生效。 - (4)tags - 用于让用户选择运行或略过 playbook 中的部分代码。Ansible 具有幂等性,因此会自动跳过没有变化的部分;但是当一个 playbook 任务比较多时,一个个的判断每个部分是否发生了变化,也需要很长时间。因此,如果确定某些部分没有发生变化,就可以通过 tags 跳过这些代码片断。 - 3. playbook 执行结果解析 - 使用 ansible-playbook 运行 playbook 文件,输出的内容为 JSON 格式,并且由不同颜色组成,便于识别。一般而言,输出内容中,每个颜色表示的含义如下: - 绿色代表执行成功,但系统保持原样; - 黄色代表系统状态发生改变,也就是执行的操作生效; - 红色代表执行失败,会显示错误信息。 - 下面是一个简单的 playbook 文件: ```json - name: create user hosts: 172.16.213.231 user: root gather_facts: false vars: user1: testuser tasks: - name: start createuser user: name="{{user1}}" ``` - 上面 playbook 实现的功能是新增一个用户,每个参数含义如下: - name 参数对该 playbook 实现的功能做一个概述,后面执行过程中,会输出 name 的值; - hosts 参数指定了对哪些主机进行操作; - user 参数指定了使用什么用户登录到远程主机进行操作; - gather_facts 参数指定了在执行 task 任务前,是否先执行 setup 模块获取主机相关信息,此参数默认值为 true,表示开启,如果在 task 中使用 facts 信息时,就需要开启此功能;否则设置为 false,这样可以加快 playbook 的执行速度; - vars 参数指定了变量,这里指定一个 user1 变量,其值为 testuser,注意,变量值一定要用引号括起来; - tasks 指定了一个任务,其下面的 name 参数同样是对任务的描述,在执行过程中会打印出来,user 是一个模块,后面的 name 是 user 模块里的一个参数,而增加的用户名调用了上面 user1 变量的值。 - 4. playbook 中 tasks 语法使用 - 在 playbook 中,task 部分是整个任务的核心,前面介绍的 ansible 常用模块,如 commands、shell、file、cron、user 等模块,在 playbook 中仍然可用,每个模块所使用的参数以及含义跟命令行模式下也完全一样,只不过写法不同而已。 - (1)playbook 示例 - 下面是一个 playbook 示例,test.yml 文件内容如下: ```json - hosts: hadoophosts remote_user: root tasks: - name: create hadoop user user: name=hadoop state=present - name: create hadoop directory and chmod/chown file: path=/opt/hadoop state=directory mode=0755 owner=hadoop group=hadoop - name: synchronize hadoop program synchronize: src=/data/hadoop/ dest=/opt/hadoop - name: Setting environment variables shell: echo "export JAVA_HOME=/usr/jdk" >> /etc/profile ``` - 在 playbook 文件中,使用了 user、file、synchronize 和 shell 模块,文件开始定义了一个主机组 hadoophosts,然后设置 root 用户在远程主机上执行操作;接着是 task 任务的开始,“- name”是描述性信息,用来标识任务执行内容和进度,第一个 task 用来创建一个 hadoop 用户,使用了 user 模块。 - 注意,上面的 user 表示 ansible 的 user 模块,而 user 后面的 name、state 是 user 模块的参数,这些参数的含义上面已经介绍过了。 - 下面还有 file、synchronize 及 shell 模块,它们的写法跟 user 模块类似,不再过多介绍。 - 从此文件可以看出,通过 playbook 模式编写的文件更加简洁、易懂,只要设置好了任务的运行策略、顺序,每次需要用到这个操作的话,直接执行就可以了。执行的方式如下: ```shell [root@server239 ansible]# ansible-playbook test.yml ``` - 除了前面已经介绍过的 ansible 模块,还有一些模块在 playbook 中也经常用到,下面再介绍一些常用的 playbook 模块。 - (2)unarchive 模块 - 该模块用来实现解压缩,也就是将压缩文件解压分发到远程不同节点上,只需记住如下几个参数即可: - src,源文件路径,这个源文件在管理机上; - dest,指定远程主机的文件路径; - mode,设置远程主机上文件权限。 - 看下面这个例子: ```shell - hosts: 172.16.213.231 remote_user: root gather_facts: false tasks: - name: unarchive spark files unarchive: src=/src/spark.tar.gz dest=/opt ``` - 这个操作是将管理机上的 /src/spark.tar.gz 文件传输到远程主机上后进行解压缩,并将解压缩后的文件放到远程主机的 /opt 目录下。注意,这个例子设置了 gather_facts 选项为 false,这是因为下面的 task 中,没有用到 facts 信息。 - (3)lineinfile、replace 模块 - 在自动化运维中,对文件进行内容替换是一个非常常见的场景,比如修改、删除、添加操作系统的某些参数等。Ansible 中虽然提供了 shell 模块结合 sed 命令来达到替换的效果,但经常会遇到需要转义的问题,并且考虑到可读性和可维护性等多方面因素,使用 Ansible 自带的替换模块是一个不错的选择。Ansible 常用的替换模块为 replace 和 lineinfile。 - replace 模块可以根据指定的正则表达式替换远程主机下某个文件中的内容,常用的参数如下表所示: - ![replace模块](pic/replace模块.png) - 看下面这个例子: ```yaml - hosts: 172.16.213.231 remote_user: root tasks: - name: modify selinux replace: path=/etc/selinux/config regexp="enforcing" replace=disabled backup=yes ``` - 这个操作是对远程主机上 /etc/selinux/config 文件中的 enforcing 字符串进行替换,替换为 disabled,替换前进行备份,其实就是关闭远程主机上 selinux 服务。 - 再介绍一下 lineinfile,此模块也可以实现 replace 的功能,但 lineinfile 功能更加强大,支持的参数也比较多,常用参数含义如下表所示: - ![lineinfile模块.png](pic/lineinfile模块.png) - 下面来看一个基于 lineinfile 的 playbook 任务: ```yaml - hosts: 172.16.213.231 remote_user: root tasks: - lineinfile: dest=/etc/profile insertafter='ulimit(.*)' line="ulimit -c unlimited" - lineinfile: dest=/etc/profile line="export JAVA_HOME=/usr/jdk" - lineinfile: dest=/etc/selinux/config regexp='SELINUX=(.*)' line='SELINUX=disabled' - lineinfile: dest=/etc/resolv.conf regexp='search(.*)' state=absent ``` - 在 playbook 任务中,调用了四次 lineinfile 替换操作,第一次是在 /etc/profile 文件中找到以 ulimit 开头的行,并在后面添加一行内容“ulimit -c unlimited”; - 第二次是在 /etc/profile 文件的最后添加一个 JAVA_HOME 路径; - 第三次是修改 /etc/selinux/config 文件中以“SELINUX=”开头的行,将其替换为“SELINUX=disabled”,其实就是关闭 selinux; - 最后一个操作是在 /etc/resolv.conf 文件找查找以 search 开头的行,然后将其删除掉。 - (4)register、set_fact、debug 模块 - Ansible 中定义变量的方式有很多种,可以将模块的执行结果注册为变量,也可以在 roles 中的文件内定义变量,还可以使用内置变量等,而 register、set_fact 都可用来注册一个变量。 - 使用 register 选项,可以将当前 task 的输出结果赋值给一个变量,看下面这个例子: ```yaml - hosts: 172.16.213.231 remote_user: root tasks: - name: ps command shell: hostname register: host_result - debug: var=host_result ``` - 此例子是将在远程主机上执行的 shell 命令“hostname”的输出结果赋值给变量 host_result,然后再将变量引用并使用 debug 模块输出,输出结果是 json 格式的。注意,此例子最后还使用了 debug 模块,此模块用于在调试中输出信息。 - 下面是 playbook 的 debug 输出结果: ```json TASK [debug] ********************************************************** ok: [172.16.213.231] => { "host_result": { "changed": true, "cmd": "hostname", "delta": "0:00:00.007228", "end": "2020-04-01 04:42:34.254587", "failed": false, "rc": 0, "start": "2020-04-01 04:42:34.247359", "stderr": "", "stderr_lines": [], "stdout": "server231.localdomain", "stdout_lines": [ "server231.localdomain" ] } } ``` - 可以看出,此输出是一段 json 格式的数据,最顶端的 key 为 host_result,大括号内还有多个二级 key,我们想要的结果是输出远程主机的主机名即可,不需要其他这些额外的二级 key 信息,如何实现这个需求呢?如果想要输出 json 数据的某二级 key 项,可以使用 "key.dict" 或 "key['dict']" 的方式引用即可。 - 从上面输出可以看到,我们需要的二级 key 是 stdout 项,所以要仅仅输出此项内容,可以将变量引用改为 host_result.stdout 即可,也就是将上面的 playbook 任务改成如下内容: ```yaml - hosts: 172.16.213.231 remote_user: root tasks: - name: hostname command shell: hostname register: host_result - debug: var=host_result.stdout - debug: 'msg="output: {{host_result.stdout}}"' ``` - 在 playbook 中,又增加了一个 debug 参数,debug 模块常用的参数有两个,即 msg 和 var,它们都可以引用变量输出信息,但有一点小区别,msg 可以输出自定义信息,并且变量需要双大括号包含起来;而 var 参数只能输出变量,并且不需要双大括号。 - 修改后的 playbook 执行 debug 输出结果如下: ```json TASK [debug] ******************************************************** ok: [172.16.213.231] => { "host_result.stdout": "server231.localdomain" } TASK [debug] ******************************************************** ok: [172.16.213.231] => { "msg": "output: server231.localdomain" } ``` - 从输出可知,这个才是我们想要的结果。 - set_fact 和 register 的功能很类似,它也可以将 task 输出赋值给变量。set_fact 更像 shell 中变量的赋值方式,可以将某个变量的值赋值给另一个变量,也可以将字符串赋值给变量。看下面这个例子: ```yaml - hosts: 172.16.213.231 remote_user: root tasks: - name: hostname command shell: hostname register: host_result - set_fact: var1="{{host_result.stdout}}" - set_fact: var2="This is a string" - debug: msg="{{var1}} {{var2}}" ``` - 这个例子是将 hostname 的输出结果赋值给 host_result 变量,然后通过 set_fact 将 host_result 变量赋值给 var1 变量,接着又将一个字符串赋值给 var2 变量,最后,通过 debug 模块输出这些变量信息。注意这些模块的使用方式和书写格式。 - 这个 playbook 的输出结果为: ```json TASK [debug] ********************************************************** ok: [172.16.213.231] => { "msg": "server231.localdomain This is a string" } ``` - (5)delegate_to、connection 和 local_action 模块 - Ansible 默认只会对远程主机执行操作,但有时候如果需要在管理机本机上执行一些操作,该如何实现呢?其实现的方法有很多,可以通过 delegate_to(任务委派)来实现,也可通过 connection:local 方法,还可通过 local_action 关键字来实现。 - 下面来看一个例子,说明它们的用法。 ```yaml - hosts: 172.16.213.231 remote_user: root gather_facts: true tasks: - name: connection shell: echo "connection . {{inventory_hostname}} $(hostname) ." >> /tmp/local.log connection: local - name: delegate_to shell: echo "delegate_to . {{inventory_hostname}} $(hostname) ." >> /tmp/local.log delegate_to: localhost - name: local_action local_action: shell echo "local_action. {{inventory_hostname}} $(hostname)" >> /tmp/local.log ``` - 这个例子依次使用了 connection、delegate_to 和 local_action 三种方式,还使用了一个变量 {{inventory_hostname}},这是 Ansible 的一个内置变量,用来获取远程主机的主机名,说到主机名,其实用到了 facts 信息,所以,需要设置 gather_facts 选项为 true。另外,$(hostname) 是 shell 里面的变量,也是用来获取主机名,此例子实现的功能是将远程主机的主机名依次输出到管理机的 /tmp/local.log 文件中。 ### D. 大数据运维环境下 ansible-playbook 应用案例 - 1. 批量更改主机名并生成本地解析 - 在大数据运维环境下,对主机名要求比较严格,所以对大数据节点的主机名要进行统一规划,然后集中设置。如果本地没有建立 DNS 解析服务器,还需要对每个节点添加本地解析,也就是将每个节点的 IP 和主机名的对应关系添加到 /etc/hosts 文件中。要解决这两个问题,只需要两个 playbook 脚本即可自动完成。 - 要批量更改每个节点的主机名,首先需要修改 ansible 中 /etc/ansible/hosts 文件内容,添加如下配置: ```shell [hostall] 172.16.213.229 hostname=namenodemaster 172.16.213.230 hostname=slave001 172.16.213.231 hostname=slave002 ``` - 这里定义了一个名为 hostall 的主机组,组中有三台主机,每个主机 IP 后面跟了一个 hostname 变量,变量后面就是定义好的主机名,而这个变量可以在 playbook 脚本中直接引用。 - 接下来就可以编写 playbook 脚本了,内容如下: ```yaml - hosts: hostall remote_user: root tasks: - name: change name shell: "echo {{hostname}} > /etc/hostname" - name: shell: hostname {{hostname}} ``` - 其中,变量 {{hostname}} 及值就是在 /etc/ansible/hosts 文件中定义的“hostname=namenodemaster”这部分内容。通过使用 shell 模块,实现将定义好的主机名添加到每个远程主机的 /etc/hostname 文件中(限于 RHEL/Centos7/8 系统),然后执行 hostname 命令使其生效。 - 每个主机名修改完毕后,还需要构建一个本地解析文件(IP 和主机名对应的文件),然后传到每个远程主机上,要实现这个功能,可以编写如下 playbook 脚本,内容如下: ```yaml - hosts: hostall remote_user: root roles: - roles tasks: - name: add localhost local_action: shell echo "127.0.0.1 localhost" > {{AnsibleDir}}/roles/templates/hosts.j2 run_once: true - set_fact: ipaddress={{hostvars[inventory_hostname].ansible_default_ipv4.address}} - set_fact: hostname={{hostvars[inventory_hostname].ansible_facts.hostname}} - name: add host record local_action: shell echo {{ipaddress}} {{hostname}} >> {{AnsibleDir}}/roles/templates/hosts.j2 - name: copy hosts.j2 to allhost template: src={{AnsibleDir}}/roles/templates/hosts.j2 dest=/etc/hosts ``` - 在 playbook 中,使用了角色中的变量,所以要了解 ansible 的默认目录结构,如下图所示: - ![ansible 的默认目录结构](pic/ansible的默认目录结构.png) - 我们的程序安装在 /etc/ansible 命令下,在这个目录中有三个子目录,分别是 files、templates 和 roles。files 目录主要存放一些要拷贝的远程主机的程序文件;templates 目录下存放了一些配置好的模板文件,该模板文件会统一拷贝到远程主机中;roles目录下创建了一个 main.yml 文件,用来定义角色变量,main.yml 中变量定义方式如下: ```shell server1_hostname: 172.16.213.229 server2_hostname: 172.16.213.230 server3_hostname: 172.16.213.231 AnsibleDir: /etc/ansible BigdataDir: /opt/bigdata hadoopconfigfile: /etc/hadoop ``` - 其中,每行内容中冒号前面的是变量名,后面的是变量的值,定义变量后,就可以在playbook中进行引用了。 - 最后,再回到上面这个 playbook 文件中,由于要使用角色变量,所以引入了 roles 关键字。接下来,在 tasks 任务中,首先使用了 local_action 模块,在管理机上生成了一个模板文件 hosts.j2,注意这里面的变量 {{AnsibleDir}} 就是在 main.yml 中定义好的,run_once 表示本地 shell 仅仅执行一次;接着通过 set_fact 定义了两个变量 ipaddress 和 hostname,这两个变量都从 ansible 内置变量中获取具体的值,然后将获取到的 ipaddress 和 hostname 值写入管理机上的 hosts.j2 文件中;最后一个操作步骤是通过 template 模块,将 hosts.j2 模板文件拷贝到远程主机的 /etc/ 目录下并重命名为 hosts 文件。 - 将此脚本放到 /etc/ansible 目录下,并命名为 hosts.yml,然后执行如下命令: ```shell [root@server239 ansible]# ansible-playbook hosts.yml ``` - 如果执行成功,会有绿色、浅黄色输出提示;如果执行失败,可以看红色输出内容,判断检查问题。 - 2. 主机自动建立 SSH 信任 - 大数据环境下,为了安装、配置和维护的方便,一般会设置管理机(安装 Ansible 的机器)和每个集群节点之间的无密码登录(单向信任),而无密码登录最简单的方式是通过设置 SSH 公私钥认证机制。 - 下面 playbook 脚本可以完成管理机到远程主机组 hostall 的无密码登录,脚本内容如下: ```yaml - hosts: hostall gather_facts: no roles: - roles tasks: - name: close ssh yes/no check lineinfile: path=/etc/ssh/ssh_config regexp='(.*)StrictHostKeyChecking(.*)' line="StrictHostKeyChecking no" - name: delete /root/.ssh/ file: path=/root/.ssh/ state=absent - name: create .ssh directory file: dest=/root/.ssh mode=0600 state=directory - name: generating local public/private rsa key pair local_action: shell ssh-keygen -t rsa -b 2048 -N '' -f /root/.ssh/id_rsa - name: view id_rsa.pub local_action: shell cat /root/.ssh/id_rsa.pub register: sshinfo - set_fact: sshpub={{sshinfo.stdout}} - name: add sshkey local_action: shell echo {{sshpub}} > {{AnsibleDir}}/roles/templates/authorized_keys.j2 - name: copy authorized_keys.j2 to all hosts template: src={{AnsibleDir}}/roles/templates/authorized_keys.j2 dest=/root/.ssh/authorized_keys mode=0600 tags: - copy sshkey ``` - 这个 playbook 稍微复杂一些,它仍然用到了角色变量,所以此脚本要放在 /etc/ansible 目录下,脚本一开始通过 lineinfile 模块对远程主机上的 sshd 配置文件 ssh_config 进行文件内容替换,这个替换是关闭 SSH 第一次登录时给出的“yes/no”提示。 - 接着在远程主机上删除 /root/.ssh 目录,并重新创建此目录,该操作的目的是确保远程主机 /root/.ssh 目录是干净的、权限正确。 - 然后通过 local_action 模块在管理机上生成一对公私钥,同时将生成的公钥文件内容作为变量 sshinfo 的值,并通过 set_fact 模块重新定义一个变量 sshpub,此变量引用 sshinfo 变量的 stdout 输出,也就是最终的公钥值,紧接着,将变量 sshpub 的内容写入管理机 authorized_keys.j2 模板文件中。 - 最后,使用 template 模块将 authorized_keys.j2 模板文件拷贝到每个远程主机的 /root/.ssh 目录下,并重命名为 authorized_keys,同时给文件授于属主读、写权限。 - 将此脚本放到 /etc/ansible 目录下,并命名为 ssh.yml,然后执行如下命令: ```shell [root@server239 ansible]# ansible-playbook ssh.yml ``` - 3. 自动化安装 JDK - 自动化安装 JDK 是大数据运维中最常见的一个场景,一般下载二进制版本解压即可使用,所以安装 JDK 的过程是把下载好的 JDK 程序拷贝到远程主机的过程,安装完成后,还要添加 JAVA_HOME 到系统环境变量中,以让系统识别安装的 JDK。 - 下面的 playbook 文件是自动化安装 JDK 的整个过程,内容如下: ```yaml - hosts: hostall remote_user: root roles: - roles tasks: - name: mkdir jdk directory file: path={{BigdataDir}} state=directory mode=0755 - name: copy and unzip jdk unarchive: src={{AnsibleDir}}/roles/files/jdk.tar.gz dest={{BigdataDir}} - name: set env lineinfile: dest=/etc/profile line="{{item.value}}" state=present with_items: - {value: "export JAVA_HOME={{BigdataDir}}/jdk"} - {value: "export PATH=$JAVA_HOME/bin:$PATH"} - name: chmod bin file: dest={{BigdataDir}}/jdk/bin mode=0755 recurse=yes - name: enforce env shell: source /etc/profile ``` - 此脚本中的 BigdataDir、AnsibleDir 都是角色变量,前面已经定义过具体的路径了,其中,jdk.tar.gz 位于管理机上,脚本最后通过 item.value 变量将 JDK 环境变量写入到了 /etc/profile 文件的最后,这个变量的定义和引用方式需要注意。 - 将此脚本放到 /etc/ansible 目录下,并命名为 jdk.yml,然后执行如下命令: ```shell [root@server239 ansible]# ansible-playbook jdk.yml ``` ## 1.4 手动模式构建双 Namenode+Yarn 的 Hadoop 集群 # 2. Hadoop 分布式架构解析 # 3. Hadoop 外围应用整合实战 # 4. Hadoop 大数据平台数据收集应用实践 # 5. 大数据平台日志传输与可视化应用实践 # 6. 大数据平台运维监控体系的构建 # 7. 大数据平台性能调优与运维经验汇总