TT Bigdata TT Bigdata
首页
  • 部署专题

    • 常规安装
    • 一键部署
  • 组件安装

    • 常规&高可用
  • 版本专题

    • 更新说明
  • Ambari-Env

    • 环境准备
    • 开始使用
  • 组件编译

    • 专区—Ambari
    • 专区—Bigtop
  • 报错解决

    • 专区—Ambari
    • 专区—Bigtop
  • 其他技巧

    • Maven镜像加速
    • Gradle镜像加速
    • Bower镜像加速
    • 虚拟环境思路
    • R环境安装+一键安装脚本
    • Ivy配置私有镜像仓库
    • Node.js 多版本共存方案
    • Ambari Web本地启动
    • Npm镜像加速
    • PostgreSQL快速安装
    • Temurin JDK 23快速安装
  • 成神之路

    • 专区—Ambari
    • 专区—Bigtop
  • 集成案例

    • Redis集成教学
    • Dolphin集成教学
    • Doris集成教学
    • 持续整理...
  • 模板代码

    • 各类组件
    • 通用模板
  • 国产化&其他系统

    • Centos系列
    • Kylin系列
    • OpenEuler系列
    • Rocky系列
    • Ubuntu系列
  • 生产调优

    • 组件调优指南
    • 1v1指导调优
  • 定制开发

    • 组件版本定制
    • 样式风格定制
  • 蓝图愿景
  • 技术支持
  • 合作共建
GitHub (opens new window)

JaneTTR

数据酿造智慧,每一滴都是沉淀!
首页
  • 部署专题

    • 常规安装
    • 一键部署
  • 组件安装

    • 常规&高可用
  • 版本专题

    • 更新说明
  • Ambari-Env

    • 环境准备
    • 开始使用
  • 组件编译

    • 专区—Ambari
    • 专区—Bigtop
  • 报错解决

    • 专区—Ambari
    • 专区—Bigtop
  • 其他技巧

    • Maven镜像加速
    • Gradle镜像加速
    • Bower镜像加速
    • 虚拟环境思路
    • R环境安装+一键安装脚本
    • Ivy配置私有镜像仓库
    • Node.js 多版本共存方案
    • Ambari Web本地启动
    • Npm镜像加速
    • PostgreSQL快速安装
    • Temurin JDK 23快速安装
  • 成神之路

    • 专区—Ambari
    • 专区—Bigtop
  • 集成案例

    • Redis集成教学
    • Dolphin集成教学
    • Doris集成教学
    • 持续整理...
  • 模板代码

    • 各类组件
    • 通用模板
  • 国产化&其他系统

    • Centos系列
    • Kylin系列
    • OpenEuler系列
    • Rocky系列
    • Ubuntu系列
  • 生产调优

    • 组件调优指南
    • 1v1指导调优
  • 定制开发

    • 组件版本定制
    • 样式风格定制
  • 蓝图愿景
  • 技术支持
  • 合作共建
GitHub (opens new window)
  • 方法论

  • 代码生命周期-metainfo

  • 架构剖析

    • server与agent协作详解[一]
    • server与agent协作详解[二]
    • ambari install逻辑详解[一]
    • ambari install逻辑详解[二]
    • ambari install逻辑详解[三]
      • 4. 最佳实践与技巧 💡
        • 4.1 优化配置技巧
      • 5. 总结与延伸学习 🚀
        • 5.1 内容回顾
        • 5.2 后续学习方向
    • stack-hooks逻辑详解[一]
    • stack-hooks逻辑详解[二]
    • distro-select逻辑详解
    • java 请求过程解读[一]
    • java 请求过程解读[二]
    • java 请求过程解读[三]
    • java 请求过程泛化及补充[一]
    • java 请求过程泛化及补充[二]
  • UI样式

  • GOD-Ambari
  • 架构剖析
JaneTTR
2025-06-02
目录

ambari install逻辑详解[三]

# 3.2.3 install 过程详细解析

在 execute() 方法中,当命令名称为 install 时,会调用组件的 install 方法。下面我们逐步解析 install 过程的执行机制。


# 3.2.3.1 install 方法的调用逻辑

首先在 execute() 中,通过以下逻辑选择了 install 方法:

method = self.choose_method_to_execute(self.command_name)
1

假设 command_name 是 "install",那么 method 将会对应到 self.install()。

在 choose_method_to_execute 方法中,它会根据传入的 command_name 从当前类中动态获取到 install 方法并返回供后续调用。

然后,在 execute() 方法中:

with Environment(self.basedir, tmp_dir=Script.tmp_dir) as env:
    if not self.is_hook():
        self.execute_prefix_function(self.command_name, 'pre', env)

    method(env)

    if not self.is_hook():
        self.execute_prefix_function(self.command_name, 'post', env)
1
2
3
4
5
6
7
8

通过 method(env),调用了实际的 install 方法,并且在调用之前和之后分别执行了 pre_install 和 post_install 钩子。

提示

这种写法确保每次调用 install 都自动带上前置检查与后置收尾,方便企业场景下插入环境自检、自动校验、后置通知等一系列业务流程。


# 3.2.3.2 组件中的 install 方法

以 Kafka 为例,kafka_broker.py 中的 install 方法代码如下:

class KafkaBroker(Script):
    def install(self, env):
        self.install_packages(env)
1
2
3

可以看到,KafkaBroker 类中的 install 方法直接调用了父类 Script 中的 install_packages 方法。

笔记

  • 绝大多数 Ambari 组件的 install 方法都采用这种设计,调用 install_packages 可以统一支持包列表下发、操作系统适配、参数透传等全流程。
  • 这种封装简化了各类组件 install 代码,也减少了维护成本。

# 3.2.3.3 Script 类的 install_packages 方法

Script 类中的 install_packages 负责处理安装任务:

  def install_packages(self, env):
    """
    List of packages that are required by service is received from the server
    as a command parameter. The method installs all packages from this list
    
    exclude_packages - list of regexes (possibly raw strings as well), the
    packages which match the regex won't be installed.
    NOTE: regexes don't have Python syntax, but simple package regexes which support only * and .* and ?
    """
    config = self.get_config()

    if 'host_sys_prepped' in config['ambariLevelParams']:
      # do not install anything on sys-prepped host
      if config['ambariLevelParams']['host_sys_prepped'] is True:
        Logger.info("Node has all packages pre-installed. Skipping.")
        return
      pass
    try:
      package_list_str = config['commandParams']['package_list']
      agent_stack_retry_on_unavailability = bool(config['ambariLevelParams']['agent_stack_retry_on_unavailability'])
      agent_stack_retry_count = int(config['ambariLevelParams']['agent_stack_retry_count'])
      if isinstance(package_list_str, basestring) and len(package_list_str) > 0:
        package_list = json.loads(package_list_str)
        for package in package_list:
          if self.check_package_condition(package):
            name = self.format_package_name(package['name'])
            # HACK: On Windows, only install ambari-metrics packages using Choco Package Installer
            # TODO: Update this once choco packages for hadoop are created. This is because, service metainfo.xml support
            # <osFamily>any<osFamily> which would cause installation failure on Windows.
            if OSCheck.is_windows_family():
              if "ambari-metrics" in name:
                Package(name)
            else:
              Package(name,
                      retry_on_repo_unavailability=agent_stack_retry_on_unavailability,
                      retry_count=agent_stack_retry_count)
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
31
32
33
34
35
36

核心逻辑:

  1. 读取 package_list:从 commandParams 中提取 package_list,这是由 ambari-server 传递给 ambari-agent 的安装包列表。package_list 通常包含一个 JSON 字符串,列出需要安装的软件包。
  2. 解析和检查:使用 json.loads 将 package_list 解析为实际的 Python 列表,并通过 check_package_condition 方法来判断该包是否符合安装条件。
  3. 调用 Package 资源:对于每个符合条件的软件包,调用 Package 资源类来执行安装。

提示

这种机制支持了:

  • 按需选择性安装(可插入条件检查)
  • 支持 agent 自带重试机制
  • 兼容 Windows/类 Unix 跨平台场景
  • 支持未来自动跳过 sys-prepped 已装环境,灵活适配多云和镜像场景

# 3.2.3.4 Package 资源类解析

Package 类是一个资源管理类,它专门用于处理软件包的安装过程。它被设计为通过环境自动调用合适的安装逻辑:

image-20241025170735690

但是实例化是父类Resource的方法

 def __new__(cls, name, env=None, provider=None, **kwargs):
    if isinstance(name, list):
      names_list = name[:]
      while len(names_list) != 1:
        cls(names_list.pop(0), env, provider, **kwargs)
        
      name = names_list[0]
    
    env = env or Environment.get_instance()
    provider = provider or getattr(cls, 'provider', None)
    
    r_type = cls.__name__
    if r_type not in env.resources:
      env.resources[r_type] = {}

    obj = super(Resource, cls).__new__(cls)
    env.resources[r_type][name] = obj
    env.resource_list.append(obj)
    return obj

  def __init__(self, name, env=None, provider=None, **kwargs):
    if isinstance(name, list):
      name = name[-1]
    
    if hasattr(self, 'name'):
      return

    self.env = env or Environment.get_instance()
    self.name = name
     
    self.provider = provider or getattr(self, 'provider', None)

    self.arguments = {}
    for key, value in kwargs.items():
      try:
        arg = self._arguments[key]
      except KeyError:
        raise Fail("%s received unsupported argument %s" % (self, key))
      else:
        try:
          self.arguments[key] = arg.validate(value)
        except InvalidArgument, exc:
          raise InvalidArgument("%s %s" % (self, exc))
    
    if not self.env.test_mode:
      self.env.run()
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

详细解析:

  • Package 继承自 Resource 类,默认的 action 被设置为 install,表示此资源的主要功能就是安装软件包。
  • 当 Package 被实例化时,env.run_action(self, self.action) 会被调用,这意味着它会执行 install 这一操作。
  • 通过这种抽象,将具体的安装操作交由 Environment 类和 Provider 来完成,从而实现了更强的扩展性。

image-20241025171029755

笔记

这种资源化/自动分派机制一方面兼容 Python 领域最佳实践(类似 Ansible Resource),另一方面也为未来的资源二次开发、平台迁移(如 Kubernetes CRD)留足了空间。


# 3.2.3.5 使用 Environment 来调用 find_provider

在 Environment 类中,run_action 方法用于根据资源类型选择并执行对应的 Provider:

image-20241025171205070

逻辑解读:

  • find_provider 会找到与资源对应的 Provider 类,例如 PackageProvider。
  • 然后,利用 getattr 获取 Provider 中对应的 action 方法(例如 action_install),并调用执行。
  • 这种机制允许根据环境动态地调整执行逻辑,使代码更加灵活。

提示

所以用户无需关心底层是 apt/yum 还是 zypper,Provider 系统自动适配本地平台,极大降低维护和扩展成本。


# 3.2.3.6 find_provider 函数详解

find_provider 方法的作用是根据当前系统的操作环境,动态选择合适的 Provider 类来执行操作(比如安装软件包)。:

image-20241025171459862

主要步骤:

  1. 输入检查:

    • 接收三个参数:env(系统环境)、resource(资源类型),和一个可选的 class_path(指定 Provider 路径)。
  2. 查找 Provider:

    • 如果没有明确的 class_path,方法会在 PROVIDERS 和 LIBRARY_PROVIDERS 中查找。
    • 根据系统的 os_family(比如 RedHat 或 Debian),找到与资源类型对应的 Provider 类。
  3. 动态加载:

    • 找到 class_path 后,通过动态导入的方式加载对应的 Provider 类,确保可以在不同系统上执行正确的操作。

笔记

这一步确保了不同 Linux 发行版甚至 Windows 也能用同一套安装脚本,实现一套代码、多端适配。


# 3.2.3.7 PackageProvider 和实际的安装执行

文件位置:ambari-common/src/main/python/resource_management/core/providers/packaging.py

接下来的 action_install 会实际调用操作系统的命令行工具完成安装:


class PackageProvider(Provider):
  def __init__(self, *args, **kwargs):
    super(PackageProvider, self).__init__(*args, **kwargs)
    self._pkg_manager = ManagerFactory.get()

  def action_install(self):
    package_name = self.get_package_name_with_version()
    self._pkg_manager.install_package(package_name, self.__create_context())

  def action_upgrade(self):
    package_name = self.get_package_name_with_version()
    self._pkg_manager.upgrade_package(package_name, self.__create_context())

  def action_remove(self):
    package_name = self.get_package_name_with_version()
    self._pkg_manager.remove_package(package_name, self.__create_context())

  def __create_context(self):
    """
    Build RepoCallContext from Resource properties
    """
    return RepoCallContext(
      ignore_errors=self.resource.ignore_failures,
      use_repos=self.resource.use_repos,
      skip_repos=self.resource.skip_repos,
      log_output=True if self.resource.logoutput is None or self.resource.logoutput is True else False,
      retry_count=self.resource.retry_count,
      retry_sleep=self.resource.retry_sleep,
      retry_on_repo_unavailability=self.resource.retry_on_repo_unavailability,
      retry_on_locked=self.resource.retry_on_locked
    )

  def get_package_name_with_version(self):
    if self.resource.version:
      return self.resource.package_name + '-' + self.resource.version
    else:
      return self.resource.package_name


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
31
32
33
34
35
36
37
38
39
40

Manager 会进行统一管理

image-20241025172353534

对于具体实现,例如 YumManager:

image-20241025172815144

功能说明:

  • PackageProvider 的 action_install 会利用 _pkg_manager 的 install_package 方法。
  • _pkg_manager 可能是 YumManager 或者 AptManager,它们封装了系统命令行工具(如 yum 或 apt-get)的具体调用。

image-20241025173149015

提示

无论环境是 RHEL/CentOS/Ubuntu/SLES,最终安装动作都交给本地包管理器执行,实现了平台无关的“一键式”体验。

# 4. 最佳实践与技巧 💡

# 4.1 优化配置技巧

在设计和编写 Ambari 组件的 Python 脚本时,我们经常需要在安装、启动、停止等关键任务之前或之后执行额外的业务逻辑。

提示

为此,Ambari 提供了 pre_ 和 post_ 方法机制,让你可以灵活地在主流程前后插入自定义逻辑,实现自动化、企业级的流程控制。

例如:

  • 在组件安装前执行系统检查,提前终止不合规安装,避免浪费资源;
  • 在安装完成后自动清理临时文件、初始化数据或生成报告,让组件上线更自动化;
  • 升级前后执行兼容性检查或配置变更,保证平滑升级体验。

实践场景举例:

  • 安装前验证配置
    • 在 pre_install 方法中,验证依赖包、必要配置,发现问题立即终止,提升安装的安全性与成功率。
  • 安装后自动化任务
    • 在 post_install 中触发数据迁移、初始化操作或环境收尾,无需人工介入,效率更高。
  • 跨版本升级处理
    • 通过 pre_upgrade、post_upgrade 方法处理版本冲突、兼容性检查、配置平滑切换等,保障升级过程稳定。

笔记

这些 pre_ 和 post_ 方法不仅适用于 install 操作,也可以扩展到 start、stop、restart 等所有生命周期节点。借助这种自定义机制,你可以让集群部署和管理流程变得更细致、更安全、更契合业务场景。

# 5. 总结与延伸学习 🚀

# 5.1 内容回顾

本篇文章系统梳理了 Ambari 组件的执行逻辑,尤其是通过自定义 Python 脚本实现多种运维自动化任务的方法,内容包括:

  1. 执行流程解析:

    • 从 Ambari install 命令切入,分析了核心的 execute 函数;
    • 解析了命令参数、环境初始化、组件主流程以及 pre_ 和 post_ 方法的自动化逻辑插入点。
  2. 安装过程详解:

    • 以 Kafka 组件为例,详细剖析了如何通过 Script 类的 install_packages 实现包的自动化安装;
    • 拆解了 Package 资源执行原理,以及如何动态选取 Provider(如 YumManager/AptManager)来适配不同操作系统。
  3. 代码执行链路梳理:

KafkaBroker.install(env)
↓
Script.install_packages(env)
↓
Environment.run_action(self, action)  # action 为 "install"
↓
find_provider(self, resource, provider)  # 找到相应的 PackageProvider 类
↓
PackageProvider.action_install()
↓
YumManager.install_package(name) 或 AptManager.install_package(name)
1
2
3
4
5
6
7
8
9
10
11
  1. 代码逻辑分层:

    • 各关键节点都配有分层代码示例和详细解读,让执行机制、扩展点一目了然;
    • 通过 pre 和 post 方法介绍,帮助读者在各操作阶段插入定制化运维逻辑。
  2. 自定义 pre_ 和 post_ 方法:

    • 展示了如何用这些方法进行前置检查、日志目录准备、版本兼容等一站式操作,大幅提升了脚本自动化能力。
  3. find_provider 函数解析:

    • 详细说明了根据操作系统与资源类型,如何自动定位最优 Provider,实现平台无关的包管理操作。

# 5.2 后续学习方向

通过本章内容,你已经初步掌握了 Ambari 组件的执行逻辑和自定义自动化脚本的设计思路。 为了进一步深化对 Ambari 运维体系的理解,建议继续关注以下进阶主题:

提示

深入学习 stack-hooks 的最佳实践:

  • 例如,如何通过公用 stack-hooks 实现 distro-select 的版本标记、批量环境自定义等运维场景。
#Ambari#install#hook#组件运维#自动化#最佳实践
ambari install逻辑详解[二]
stack-hooks逻辑详解[一]

← ambari install逻辑详解[二] stack-hooks逻辑详解[一]→

最近更新
01
Pandoc 缺失导致 SparkR 构建失败
06-08
02
Cyrus SASL/GSASL 缺失解决
06-07
03
Hadoop_3.3.4 编译实战 1.0.0+
06-06
更多文章>
Theme by Vdoing | Copyright © 2017-2025 JaneTTR | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式