什么是 Jenkins? 运用Jenkins持续集成

【注】本文译自:https://www.edureka.co/blog/what-is-jenkins/
  持续集成是 DevOps 最重要的部分,用于集成各个 DevOps 阶段。Jenkins 是最著名的持续集成工具,我知道你很好奇 Jenkins 受欢迎的原因以及 Jenkins 是否容易学习。我确信阅读完本文后,您的所有问题都会得到解答。

  让我们用简要概括什么是 Jenkins。

什么是 Jenkins 以及为什么要使用它?

  Jenkins 是一个用 Java 编写的开源自动化工具,带有用于持续集成的插件。Jenkins 用于持续构建和测试您的软件项目,从而使开发人员更容易将更改集成到项目中,并使用户更容易获得新的构建。它还允许您通过与大量测试和部署技术集成来持续交付软件。
  借助 Jenkins,组织可以通过自动化来加速软件开发过程。Jenkins 集成了各种开发生命周期过程,包括构建、文档、测试、打包、模拟、部署、静态分析等等。
  Jenkins 借助插件实现了持续集成。插件允许集成各种 DevOps 阶段。如果要集成特定工具,则需要安装该工具的插件。例如 Git、Maven 2 项目、Amazon EC2、HTML 发布者等。
  下图描绘了 Jenkins 正在集成各个 DevOps 阶段:

Jenkins 的优势包括:

  • 是一个具有社区大力支持的开源工具。
  • 易于安装。
  • 拥有 1000 多个插件,可简化您的工作。如果不存在插件,则可通过编码实现并与社区共享。
  • 它是免费的。
  • 它是用 Java 构建的,因此可以移植到所有主要平台。
      Jenkins 的某些方面将其与其他持续集成工具区分开来。让我们看看这些要点。

    Jenkins 的特性

      以下是有关Jenkins的一些事实,这些事实使它比其他的持续集成工具更好:

  • 应用:Jenkins 应用非常广泛,在全球范围内有超过 147,000 个活跃安装和超过 100 万用户。
  • 插件:Jenkins 与1000 多个插件互连,从而使其可以与大多数开发、测试和部署工具集成。
      从以上几点可以看出,Jenkins 在全球范围内有很高的需求。在我们深入研究 Jenkins 之前,先了解什么是持续集成以及它的重要性。

    什么是持续集成?

      持续集成是一种开发实践,在这种实践中,要求开发人员每天多次或更频繁地对共享存储库中的源代码提交更改。然后构建存储库中进行的每个提交。这使团队可以及早发现问题。除此之外,根据持续集成工具的不同,还有其他一些功能,例如在测试服务器上部署构建应用程序,为相关团队提供构建和测试结果等。
      让我们通过用例了解它的重要性。

    持续集成示例:诺基亚

      我敢肯定,您一生中的某些时候都使用过诺基亚手机。在诺基亚的一个软件产品开发项目中,有一个名为每晚构建(Nightly builds)的过程。每晚构建可以被认为是持续集成的前身。这意味着每天晚上,自动化系统都会拉一整天添加到共享存储库中的代码并构建该代码。这个想法与持续集成非常相似,但是由于在夜间构建的代码很大,因此查找和修复错误确实很麻烦。因此,诺基亚采用了持续集成(CI)。 结果,构建了对存储库中的源代码的所有提交。 如果构建结果表明代码中存在错误,则开发人员仅需要检查该特定提交。 这大大减少了发布新软件所需的时间。

      现在是了解 Jenkins 如何实现持续集成的正确时机。

    运用 Jenkins 持续集成

      让我们想象一个场景,构建了应用程序的完整源代码,然后将其部署在测试服务器上进行测试。听起来这是开发软件的理想方法,但是这个过程存在许多缺陷。我将逐一解释:

  • 发人员必须等到开发出完整的软件才能获得测试结果。
  • 测试结果很有可能显示多个错误。开发人员很难找到这些错误,因为他们必须检查应用程序的整个源代码。
  • 这会减慢软件交付过程。
  • 关于编码或架构问题、构建失败、测试状态和文件发布上传等问题的持续反馈会导致软件质量下降。
  • 整个过程是手动的,这增加了频繁故障的风险。
      从上述问题可以明显看出,不仅软件交付过程变慢,而且软件质量也下降了。这导致了客户的不满。因此,为了克服这种混乱,迫切需要一个系统,使开发人员可以连续触发构建并测试源代码中的每个更改。这就是 CI 的全部意义所在。Jenkins 是可用的最成熟的 CI 工具,因此让我们看看运行 Jenkins 的持续集成如何克服了上述缺点。
      首先,我将向您介绍运用 Jenkins 进行持续集成的通用流程图,可以一目了然地看到 Jenkins 如何克服上述缺点。同时有助您了解 Jenkins 的工作方式。

      上图描述了以下功能:
  • 首先,开发人员将代码提交到源代码存储库。同时,Jenkins 服务器会定期检查存储库是否有更改。
  • 提交后不久,Jenkins 服务器检测到源代码存储库中发生的更改。Jenkins 将拉出这些更改,并将开始准备新的构建。
  • 如果构建失败,那么相关团队将得到通知。
  • 如果构建成功,Jenkins 将在测试服务器中部署新的版本。
  • 在测试之后,Jenkins 会生成反馈,然后通知开发人员构建和测试结果。
  • 它将继续检查源代码存储库中是否对源代码进行了更改,并且整个过程不断重复。
      您现在知道了 Jenkins 是如何克服传统 SDLC 缺点的。下表显示了“运用 Jenkins 前后”的对比。

    运用 Jenkins 前后对比

运用 Jenkins 前 运用 Jenkins 后
构建并测试了整个源代码。在构建和测试失败的情况下查找和修复错误既困难又耗时,这反过来又减慢了软件交付过程的速度。 在源代码中进行的每个提交都将被构建和测试。因此,开发人员无需检查整个源代码,而只需要专注于特定的提交即可。可频繁发布新软件。
开发人员必须等待测试结果 开发人员知道源代码中每次提交的测试结果。
整个过程是手工的 您只需要提交对源代码的更改,Jenkins 将为您自动完成其余过程。

Ansible 教程

【注】本文译自:https://www.edureka.co/blog/ansible-tutorial/
  在阅读本文之前,你应该已经知道,Ansible 构成了 DevOps 认证的关键部分,它是用于配置管理、部署和编排的工具。
  本教程的主要内容包括:

  • 学习如何编写 Ansible 剧本
  • 学习 Ansible 不同模块间的差别
  • 学习编写 Ansible Adhoc 命令
  • Ansible 动手实践

    编写 Ansible 剧本

      Ansible 中的剧本以 YAML 格式编写。它是一种人类可读的数据序列化语言。它通常用于配置文件。它也可以用于存储数据的许多应用程序中。
      对于Ansible,几乎每个 YAML 文件都以列表开头。列表中的每个项目都是键/值对的列表,通常称为“哈希”或“字典”。因此,我们需要知道如何在 YAML 中编写列表和字典。
      列表的所有成员都是以“-”(破折号和空格)开头的相同缩进级别的行。也可能有更复杂的数据结构,例如字典列表或混合字典,其值是列表或两者的混合。
      例如,有关edureka的部门列表:

departments:
- marketing
- sales
- solutions
- content writing
- support
- product

  下面是一个字典的例子:

-USA
-continent: North America
-capital: Washington DC
-population: 319 million

主机和用户:

  对于剧本中的每一项,您都可以选择基础设施中的哪个计算机作为目标,以及由哪个远程用户来完成任务。要将主机包含在 Ansible 清单中,我们将使用主机的 IP 地址。
  通常,主机是由冒号分隔的一个或多个组或主机模式的列表。远程用户只是用户帐户的名称。

变量:

  Ansible 使用预先定义的变量来使剧本和角色具有更大的灵活性。它们可用于遍历一组给定的值,访问各种信息(例如系统的主机名),并用特定值替换模板中的某些字符串。
  Ansible 已经为每个系统定义了丰富的变量集。当 Ansible 在系统上运行时,就会收集有关该系统的所有 facts 和信息并将其设置为变量。
  但是有一个命名变量的规则。变量名称应为字母,数字和下划线。变量应始终以字母开头。例如。wamp_21,port5是有效的变量名,而01_port, _server无效。

任务:

  任务允许您将配置策略分解为更小的文件。任务包括从其他文件提取。Ansible 的任务和它的英文意思差不多。
  例如: Install , update 等等。

处理程序:

  处理程序就像 Ansible 剧本中的常规任务一样,但是仅在 Task 包含 notify 指令并且还指示它已更改某些内容时才运行。例如,如果更改了配置文件,则引用该配置文件的任务可能会通知服务重新启动处理程序。
  下面是一个剧本示例,它将启动 Apache httpd 服务器程序:

---
- hosts: webservers
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum: name=httpd state=latest
- name: write the apache config file
template: src=/srv/httpd.j2 dest=/etc/httpd.conf
notify:
- restart apache
- name: ensure apache is running (and enable it at boot)
service: name=httpd state=started enabled=yes
handlers:
- name: restart apache
service: name=httpd state=restarted

  我希望该示例将使您与我上面提到的剧本组件的描述关联根活佛。如果您仍然不清楚,请不要担心,这些疑问都会在本文后面的部分得到澄清。
  这都是剧本。你也将编写这样的剧本。但是 Ansible 也为您提供了各种各样的模块,您可以使用它们。
模块
  Ansible 中的模块是幂等的。从 RESTful 服务的角度来看,要使操作(或服务调用)具有幂等性,客户端可以重复进行相同的调用,同时产生相同的结果。 换句话说,发出多个相同的请求与发出单个请求具有相同的效果。
  Ansible 中有不同类型的模块:

  • 核心模块
  • 附加模块

    核心模块

      这些是 Ansible 核心团队维护的模块,并将始终随 Ansible 一起提供。与“额外”回购中的请求相比,它们还将对所有请求获得更高的优先级。
      这些模块的源代码由 Ansible 托管在 GitHub 上的 Ansible-modules-core 中。

    附加模块

      这些模块当前随 Ansible 一起提供,但将来可能会单独提供。它们也主要由Ansible社区维护。 非核心模块仍然可以完全使用,但是对于问题和请求请求的响应率可能会略低。
      随着时间的流逝,流行的“附加”模块可能会升级为核心模块。
      这些模块的源代码由 Ansible 在 GitHub 上的 Ansible-modules-extras 中托管。
      例如:远程管理模块中的一个附加模块是 ipmi_power 模块,它是远程计算机的电源管理器。它需要 python 2.6 或更高版本以及 pyghmi 才能运行。
      您可以通过编写一个 adhoc 命令来使用此模块,就像我在下面编写的一样:

ipmi_power : name ="test.domain.com" user="localhost" password="xyz" state="on"

返回值

  Ansible 模块通常返回一个数据结构,该数据结构可以注册到变量中,或者在 Ansible 程序输出时直接看到。每个模块可以记录其自己唯一的返回值。
  返回值的一些例子有:

  • changed::每当任务进行任何更改时,都将返回一个布尔值。
  • failed:如果任务失败,返回一个布尔值。
  • msg:返回一个字符串,给用户一个能用消息。
    Adhoc 命令
      Adhoc 命令是执行某些操作的简单一行命令。 使用 Ansible 命令运行的模块是 adhoc 命令。
      如:
ansible host -m netscaler -a "nsc_host=nsc.example.com user=apiuser password=apipass"

  上面的 adhoc 命令使用 netscaler 模块来禁用服务器。Ansible 中提供了数百个模块,您可以在其中引用和编写 adhoc 命令。
  好了,所有的理论解释都讲过了,让我们通过动手实践来学习 Ansible。
动手实践
  我打算写一个剧本,在我的节点/主机上安装 Nginx。
  让我们开始吧 🙂
第 1 步: 使用 SSH 连接到主机。为此,您需要生成一个公共 SSH 密钥。
  使用以下命令:
ssh-keygen

  如您在上面的快照中看到的,命令 ssh-keygen 生成了一个 SSH 公钥。

**第 2 步:您的下一个任务是在主机上复制 SSH 公钥。为此,请使用以下命令:
ssh-copy-id -i root@<IP address of your host>

  上面的快照显示了将 SSH 公钥复制到主机。

第 3 步:列出清单中主机/节点的 IP 地址。
  使用以下命令:
vi /etc/ansible/hosts

  这将打开一个 vi 编辑器,您可以在其中列出主机的IP地址。这是您现在的清单。
第 4 步:让我们 ping 一下以确保已建立连接。

  上面的快照确认您的控制计算机和主机之间已建立连接。
第 5 步:现在让我们编写一个在主机上安装 Nginx 的剧本。您可以在 vi 编辑器中编写剧本。为此,只需使用以下命令创建您的剧本:
vi <name of your file>.yml
  下面的快照显示了我的剧本,以 YAML 格式编写的用于安装 Nginx 的剧本。

  剧本的任务在 YAML 中定义为字典列表,并自上而下执行。 如果我们有多个主机,则在继续进行下一个任务之前,将针对每个主机尝试每个任务。每个任务都定义为字典,可以具有多个键,例如“ name”或“ sudo”,它们表示任务的名称以及它是否需要 sudo 特权。
  设置一个变量 server_port 用于侦听 TCP 端口 8080 传入的用户请求。
  在这里,第一个任务是获取用于安装 Nginx 的必要软件包,然后进行安装。在内部,Ansible 将检查目录是否存在,如果不存在则创建该目录,否则将不执行任何操作。
  下一个任务是配置 Nginx。在 Nginx 中,上下文包含配置细节。
  在这里,模板是一个可以部署在主机上的文件。但是,模板文件还包含一些参考变量,这些参考变量是从定义为 Ansible 剧本的一部分的变量或从主机收集的 facts 中提取的。包含配置详细信息的 facts 将从源目录中提取,并复制到目标目录中。
  这里的处理程序定义了仅在通知任务或状态更改时才执行的动作。在这个剧本中,我们定义了以下通知:重启 Nginx 处理程序,一旦将文件和模板复制到主机,它将重新启动 Nginx。
  现在,保存文件并退出。
第 6 步:现在,使用以下命令运行此剧本:
ansible-playbook <name of your file>.yml

  我们可以在上面的屏幕截图中看到我们的任务正在执行;正在安装 Nginx。
第 7 步:让我们检查一下我的主机上是否安装了 Nginx。使用以下命令:
ps waux | grep nginx

  您可以在上面的屏幕截图中看到不同的进程 ID 3555 和 103316 正在运行,这确保 Nginx 在您的主机上运行。
  恭喜!您已经使用 Ansible 剧本在主机上成功部署了 Nginx。

什么是 Ansible – 使用 Ansible 进行配置管理

【注】本文译自:https://www.edureka.co/blog/what-is-ansible/
  Ansible 是一个开源的 IT 配置管理、部署和编排工具。它旨在为各种自动化挑战提供巨大的生产率收益。该工具使用非常简单,但功能强大,可以自动化复杂的多层 IT 应用程序环境。
  通过本文,您将学习:

  • Ansible 是什么?
  • 为什么我们需要 Ansible?
  • 使用 Ansible 的优点
  • Ansible 能做什么?
  • Ansible 架构
  • DevOps 中的 Ansible
  • NASA 对 Ansible 的实际用法
  • 一些 Ansible 术语,可以帮助您更好地理解Ansible。

    为什么我们需要 Ansible ?

      在知道什么是 Ansible 之前,有很必要了解 Ansible 出现之前所面临的问题。
      让我们稍微回顾一下:在网络计算的开始、可靠而高效地部署和管理服务器成为一项挑战之时。在那个时候,系统管理员手动管理服务器,在单个服务器上安装软件,更改配置以及管理服务。
      随着数据中心的发展以及托管应用程序的日益复杂,管理员意识到他们无法满足启用的应用程序那样快速地扩展其手动系统管理。由于开发团队是敏捷的,并且经常发布软件,但是 IT 运营花费很多时间来配置系统,从而阻碍了开发人员的工作速度。这就促进了服务器配置和配置管理工具的蓬勃发展。
      考虑一下管理服务器队列的繁琐例程。我们始终需要不断更新,推送更改,在其上复制文件等。这些任务使事情变得非常复杂且耗时。
      但是,让我告诉您,上述问题有解决方案。那就是 – Ansible
      在全面介绍 Ansible 之前, 首先让我们熟悉一些 Ansible 术语:
    Ansible 术语:

  • 控制器机器:安装 Ansible 的机器,负责在您管理的服务器上运行资源调配。
  • 库存:一个初始化文件,其中包含有关您所管理的服务器的信息。
  • 剧本:Ansible 置备的入口点,其中的自动化是通过使用 YAML 格式的任务定义的。
  • 任务:定义要执行的单个过程的块,例如安装软件包。
  • 模块:模块通常抽象一个系统任务,例如处理程序包或创建和更改文件。Ansible 具有许多内置模块,但是您也可以创建自定义模块。
  • 角色:一种预定义方法,用于组织剧本和其他文件,以便于共享和重用配置的各个部分。
  • 播放:从头到尾执行的预配称为播放。简单来说,执行剧本称为播放。
  • Fact:包含有关系统信息的全局变量,例如网络接口或操作系统。
  • 处理程序:用于触发服务状态更改,例如重新启动或停止服务。
      Ansible 是一个有用的工具,可让您创建一组机器 ,描述如何配置这些机器或应对它们采取什么操作。Ansible 从中央位置发出所有命令来执行这些任务。
      节点计算机上未安装其他客户端软件。它使用 SSH 连接到节点。Ansible 只需要安装在甚至可以是笔记本电脑的控制机器(您将在其上运行命令的机器)上。这是解决复杂问题的简单方法。
      当我说 Ansible 填补了配置管理和 IT 编排世界中的所有漏洞时,我并没有自夸。当您看看下面提到的 Ansible 的好处时,您也会知道的:

    使用 Ansible 的优点

    简单:Ansible 使用 YAML 格式的简单语法,称为剧本。 YAML是一种人类可读的数据序列化语言。 这非常简单。 因此,不需要任何特殊的编码技能,甚至您的 IT 组织中不了解 Ansible 的人都可以阅读剧本并了解正在发生的事情。 Ansible 总是按顺序执行任务。 安装也很简单。 总之,简单性确保您可以快速入门。
    无代理:最后,Ansible是完全无代理的。 您无需在要自动执行的客户端系统或主机上安装任何代理/软件或其他防火墙端口。 您不必单独设置管理基础结构,包括管理整个系统,网络和存储。 Ansible 进一步减少了团队立即开始自动化的工作量。
    强大而灵活:Ansible 具有强大的功能,可以使您对最复杂的 IT 工作流程进行建模。 在这方面,Ansible 的内置电池方法(这种理念意味着自给自足的、开箱即用,具备所需的一切),可以管理您所需要的基础设施、网络、操作系统和服务已被使用,因为 Ansible 为您提供了数百个模块来对其进行管理。 Ansible 的功能使您可以编排整个应用环境,而不管它被部署在何处。
    高效:服务器上没有额外的软件,意味着更多的应用程序资源。 另外,由于 Ansible 模块通过 JSON 进行工作,因此 Ansible 可以通过使用你熟悉的编程语言编写模块进行扩展。 Ansible 引入了模块作为软件的基本构建块。 因此,您甚至可以根据需要自定义它。 例如如果您已有一个以纯文本格式发送消息的消息发送模块,并且您也想发送图像,也可以添加图像发送功能。

    Ansible 能做什么?

      Ansible 通常与其他配置管理工具(如Puppet,Chef,SaltStack等)一起分组。嗯,让我告诉您,Ansible 不仅限于配置管理。它也可以以许多不同的方式使用。 下面我会提到一些:
    设置:您的应用程序必须位于某个地方。 如果您是 PXE(预引导执行环境)引导并启动裸机服务器或虚拟机,或者从模板创建虚拟或云实例,则 Ansible&Ansible Tower 可帮助简化此过程。 例如,如果我要测试使用 Visual C ++ 构建的应用程序的调试版本,则应该满足一些先决条件,例如拥有 Visual C ++ 库 DLL(msvcr100d.dll)。我还将需要在您的计算机中安装 Visual Studio。 这时 Ansible 会确保所需的软件已下载并安装,以便提供我的应用程序。
    配置管理:它通过记录和更新描述企业的硬件和软件的详细信息,建立并保持产品性能的一致性。此类信息通常包括已应用于已安装软件包的版本和更新以及硬件设备的位置和网络地址。例如:如果要在企业中存在的所有计算机上安装新版本的 Tomcat,那么手动更新每台计算机都是不可行的。您可以使用最简单的方式在 Ansible 剧本和清单中一次性在所有计算机上安装 Tomcat。您所要做的就是列出清单中节点的IP地址,并编写一本手册来安装Tomcat。从您的控制机器上运行该剧本,它将被安装在您的所有节点上。
    应用部署:使用 Ansible 定义应用程序并使用 Ansible Tower 管理部署时,团队可以有效地管理从开发到生产的整个应用生命周期。例如,假设我要部署默认 Servlet 引擎。部署引擎需要执行许多步骤。

  • 将 .war 应用程序从 dropins 目录移动到 apps 目录
  • 添加 server.xml 文件
  • 导航至该网页以查看您的应用。
      但是,当我们拥有 Ansible 之类的工具时,为什么还要担心一步一步地执行这些步骤。您所需要做的就是在 Ansible 剧本中列出这些任务,然后坐下来观看 Ansible 按顺序执行这些任务。
    安全性和合规性:在 Ansible 中定义安全策略时,可以将站点范围安全策略的扫描和修复集成到其他自动化过程中。而且它将在部署的所有内容中不可或缺。这意味着,您需要在控制计算机中配置一次安全详细信息,然后将其自动嵌入到所有其他节点中。此外,Ansible 中存储的所有凭据(管理员用户 ID 和密码)都无法以任何纯文本格式检索。
    编排:单独的配置并不能定义您的环境。您需要定义多个配置如何交互,并确保可以将不同的部分作为一个整体进行管理。在复杂性和混乱性中,Ansible 带来了秩序。Ansible 提供了业务请求与应用程序、数据和基础设施保持一致的编排。它通过自动化工作流、供应和变更管理来定义策略和服务级别。这将创建一个与应用程序保持一致的基础设施,可以根据每个应用程序的需求扩大或缩小规模。
      例如:考虑一下我想部署一个新网站来代替现有网站的情况。为此,我们将删除现有网站,并部署新网站,并在需要时重新启动负载均衡器或 Web 群集。现在,如果我们只是这样做,用户将注意到停机,因为我们尚未删除通过负载平衡器进入这些计算机的实时流量。因此,我们需要某种类型的预任务,在该任务中,我们告诉负载平衡器将此 Web 服务器置于维护模式,以便在升级时暂时禁止流量通过。假设我在此处添加了一个模块,它的前置任务是禁用负载均衡器中的 Web 节点。
      因此,这是我们的前置任务,在此我们禁用流量,然后在此处使用这些不同的任务升级节点。最后,我们需要某种类型的后置任务,通过使它退出维护模式,可以再次使流量到达该 Web 节点。这些任务可以写在 Ansible 剧本中,因此有助于编排环境。
      当你对 Ansible 的架构有一个清晰的了解时,你就会更好地理解 Ansible 的工作原理。

    Ansible 的架构

      Ansible架构相当简单,参考下图:

      如您所见,在上图中,Ansible 自动化引擎与编写剧本以执行 Ansible 自动化引擎的用户直接交互。它还与云服务和配置管理数据库(CMDB)进行交互。
      Ansible 自动化引擎包括:

  • 清单:Ansible 清单是需要管理的主机(节点)及其IP地址,服务器,数据库等的殂。然后,Ansible 通过传输工具采取行动 – UNIX,Linux或网络设备使用SSH,Windows 系统使用 WinRM。
  • APIs:Ansible 中的 API 用作云服务的传输,可以是公有云,也可以是私有云。
  • 模块:模块通过剧本直接在远程主机上执行。这些模块可以控制系统资源,例如服务,程序包或文件(实际上是任何东西),或执行系统命令。模块通过操作系统文件、安装软件包或对服务网络进行 API 调用来实现。 Ansible 提供的模块超过 450 个,可自动执行环境的几乎每个部分。例如:
    • 云模块(例如 cloudformation ),用于创建或删除 AWS 云组栈;
    • 诸如 mssql_db 之类的数据库模块可从远程主机中删除 MYSQL 数据库。
  • 插件:插件允许在工作构建步骤中执行 Ansible 任务。 插件是增强 Ansible 核心功能的代码片段。Ansible 附带了许多方便的插件,您可以轻松编写自己的插件。 例如:
    • Action 插件是模块的前端,可以在调用模块本身之前在控制器上执行任务。
    • Cache 插件用于保留“facts”缓存,以避免昂贵的事实收集操作。
    • Callback 插件使您可以挂钩 Ansible 事件以进行显示或记录。
      Ansible 架构中还有一些其他组件,解释如下:
  • 网络:Ansible 也可以用于自动化不同的网络。Ansible 使用的是 IT 运营和开发部门已在使用的简单、强大且无代理的自动化框架。使用与 Ansible 自动化引擎分离的数据模型(剧本或角色),该引擎可轻松跨越不同的网络硬件。
  • 主机:Ansible 架构中的主机只是由 Ansible 自动化的节点系统。它可以是任何类型的机器:Windows、Linux、RedHat 等。
  • 剧本:剧本是以 YAML 格式编写的简单文件,描述了 Ansible 要执行的任务。剧本可以声明配置,但即使包含跳转语句,它们也可以协调任何手动排序过程的步骤。他们可以同步或异步启动任务。
  • CMDB:它是一个存储库,充当 IT 安装的数据仓库。它保存与 IT 资产集合(通常称为配置项(CI))有关的数据,并描述这些资产之间的关系。
  • 云:它是由托管在 Internet 上的远程服务器网络,用于存储、管理和处理数据,而不是本地服务器。您可以在云上启动资源和实例,并连接到服务器。

    DevOps 中 Ansible

      众所周知,在 DevOps 中,开发和运营工作是集成在一起的。这种集成对于现代测试驱动的应用程序设计非常重要。因此,Ansible 通过为开发和运营提供稳定的环境用以集成,从而实现流畅的编排。请参考下图,看看 Ansible是如何融入 DevOps 的:

      现在让我们讨论 Ansible 如何管理整个 DevOps 基础设施。当开发人员开始将基础设施视为其应用程序的一部分时,即将基础设施即代码(IaC),稳定性和性能就成为规范。基础设施即代码是通过计算机可处理的定义文件(而不是物理硬件配置或使用交互式配置工具)来管理和供应计算基础架构(流程、裸机服务器、虚拟服务器等)及其配置的过程。在这方面 Ansible 自动化发挥了重要作用,并在同行中脱颖而出。
      在 DevOps 中,系统管理员与开发人员紧密合作,提高了开发速度,可以并花费更多的时间进行诸如性能调整,实验和完成工作之类的活动,而花费在解决问题上的时间却更少。 请参考下图,以了解 Ansible 如何简化 sysadmins 和其他用户的任务。

      至此,您知道了使用 Ansible 的好处。那么,现在让我们来看一个真实的例子,NASA 是如何通过 Ansible 受益的。

    Ansible 案例研究 – NASA 的真实用法

      让我们考虑一下 NASA 面临的业务挑战。

  NASA 需要将 65 个应用程序从传统的基于硬件的数据中心转移到基于云的环境中,以实现更好的敏捷性和成本节约。快速的时间表导致许多应用程序“按原样”迁移到云环境。这样就创建了一个环境,该环境跨越了多个难以轻松管理的虚拟私有云(VPC)和AWS账户。即使是简单的事情,例如确保每个系统管理员都可以访问每个服务器或简单的安全修补程序,也非常繁琐。
  解决方案是利用 Ansible Tower 来管理和调度云环境。
  因此,为了解决 NASA 缺乏集中管理和多样化环境的问题,他们评估了多种解决方案并决定实施 Ansible Tower。NASA 现在正在利用 Ansible Tower 以一种有组织、有计划的方式管理其环境。

NASA 如何使用 Ansible:

  Ansible Tower 提供了一个仪表板,该仪表板给出了所有主机和作业的状态摘要,允许 NASA 对所有内容进行分组,并管理不同部门的访问权限。它还通过关联内容和控制组的权限来帮助拆分组织。
  Ansible Tower 是一个基于 Web 的界面,用于管理 Ansible。在Ansible 的用户愿望清单中,最重要的一项是易于使用的UI,用于管理快速部署和监视其配置。Ansible 管理层提出了 Ansible Tower 作为回应。
  此外,Ansible 通过分配各种角色在团队中划分任务。它管理旧作业历史、活动流、标记为删除的数据和系统跟踪信息的清理。请参考下图,以了解 Ansible 是如何简化 NASA 的工作的。

  结果,NASA 实现了以下效率:
• 通过非常简单的 10 行 Ansible 剧本,可以通过 Ansible Tower 定期自动对 NASA Web 应用程序服务器进行修补。
• Ansible 还被用于补救安全问题,并被用于补救 OpenSSL 问题。这不仅节省了时间,而且可以快速修复一个非常棘手的安全问题。
• 每一周,都会通过 Ansible 更新 www.nasa.gov 的完整版和移动版,通常只需 5 分钟左右。
• 如果缺少任务关键人员的 OS 级用户帐户,则将对其进行连续检查和创建。现在,每个需要访问权限的人都可以访问,即使这意味着几乎立即从所有服务器中添加或删除用户。
• NASA 还将 Ansible facts 集成到其 CMDB、CloudAware 中,以提高整个 AWS 库存的管理可见性。结果,可以以一种非常细粒度的方式组织 AWS 资源的库存,这在以前是不可能的 。
• Ansible 还用于确保环境符合 FedRAMP 概述的必要联邦安全标准和其他监管要求。

结果:
  实施 Ansible 后,NASA 可以更好地管理其 AWS 环境。Ansible 使 NASA 能够为其客户提供更好的操作和安全保障。作为一个团队,它也提高了效率。
  如果我们从数字上看:
• 更新 nasa.gov 的时间从 1 小时以上缩短到 5 分钟以下
• 安全修补程序更新从多天的过程变为 45 分钟
• 实现近乎实时的 RAM 和磁盘监视(无需代理即可完成)
• 不到 10 分钟即可在整个环境中配置 OS 帐户
• 为标准 AMI(Amazon Machine Image)设定基准的过程从 1 个小时的手动配置变成了无形且无缝的后台流程
• 每个应用程序堆栈的建立时间从 1-2 小时减少到 10 分钟以下。
总结:Ansible 是一个开源软件供应、配置管理和应用程序部署工具,可将基础设施作为代码。它可以在许多类 Unix 系统上运行,并且可以配置类 Unix 系统和 Microsoft Windows。

Git教程 – Git 命令与操作

【注】本文译自:https://www.edureka.co/blog/git-tutorial/
  学习 Git 与使用该工具一样容易。这个 Git 教程的目的就是要把这个难题从您的脑海中剔除。我相信,通过这个 Git 教程,您将了解到所有的概念。
  我希望您已经了解了 Git 的基本概念和术语,并在我的 Git 教程系列的第一个博客中了解了有关版本控制的所有知识。
  在本教程中,您将学习:

  • Git 命令
  • Git 操作
  • 还有一些使用 Git 有效地管理项目的提示和技巧。
      在开始使用命令和操作之前,让我们首先理解 Git 的主要目的。
      Git 的目的是管理一个项目或一组随着时间变化的文件。Git 将这些信息存储在称为 Git 存储库的数据结构中。存储库是 Git 的核心。

    如何查看我的 GIT 存储库?

      明确地说,Git 存储库是存放所有项目文件和相关元数据的目录。
      Git 通过从索引中创建树形图来记录项目的当前状态。它通常采用有向无环图(DAG)的形式存在。
      现在您已经理解解了 Git 的目标,让我们继续讨论操作和命令。

    如何学习 Git 命令?

      Git工作原理的基本概述:

  • 使用 git 托管工具(如 Bitbucket)创建“存储库”(项目)
  • 将存储库复制(或克隆)到本地计算机
  • 将文件添加到本地存储库并“提交”(保存)更改
  • 将更改“推送”到主分支
  • 使用 git 托管工具对文件进行更改并提交
  • 将更改“拉”到本地计算机
  • 创建一个“分支”(版本),进行更改,然后提交更改
  • 打开一个“拉取请求”。
  • 将您的分支“合并”到主分支

    Git Shell 和 Git Bash 有什么区别?

      Git Bash 和 Git Shell 是两个不同的命令行程序,可让您与底层的 Gi t程序进行交互。Bash 是基于 Linux 的命令行,而 Shell 是本机 Windows 命令行。

    一些操作和命令

      Git中的一些基本操作有:

    1. Initialize (初始化)
    2. Add (添加)
    3. Commit (提交)
    4. Pull (拉取)
    5. Push (推送)
        一些高级的 Git 操作有:
    6. Branching (分支)
    7. Merging (合并)
    8. Rebasing (变基)
        首先让我简要介绍一下这些操作如何与 Git 存储库一起使用。看看下面的Git架构:

        如果您已经理解了上面的图,那很好,但是如果您不了解,则不必担心,我将在本教程中逐一解释这些操作。让我们从基本的操作开始。
        您需要先在系统上安装Git。如果您需要安装方面的帮助,请单击此处

      Git Bash 的用途是什么?

        本 Git Bash 教程重点介绍可在 Git Bash 上使用的命令和操作。

      如何浏览 Git Bash?

        在 Windows 系统中安装 Git 之后,只需打开要存储所有项目文件的文件夹/目录即可;右键单击并选择“Git Bash Here”。

        这将打开 Git Bash 终端,您可以在其中输入命令以执行各种 Git 操作。
        现在,下一个任务是初始化存储库。

      初始化(Initialize)

        为此,我们使用命令 git init。请参考下面的截图。

        git init 创建一个空的 Git 存储库或重新初始化一个现有的存储库。它基本上会创建一个带有子目录和模板文件的 .git 目录。在现有存储库中运行 git init 不会覆盖已经存在的内容。它会选择新添加的模板。
        现在我的存储库已初始化,现在让我在目录/存储库中创建一些文件。例如我创建了两个文本文件,即 edureka1.txt 和 edureka2.txt。
        让我们使用 git status 命令查看这些文件是否在我的索引中。索引保存工作树/目录的内容的快照,该快照将作为本地存储库中要进行的下一次更改的内容。

      Git status

        git status 命令列出了所有准备好添加到本地存储库的已修改文件。
        让我们输入命令,看看会发生什么:

        这表明我有两个文件尚未添加到索引中。这意味着除非在索引中显式添加了这些文件,否则无法提交对这些文件的更改。

      添加(Add)

        该命令使用在工作树中找到的当前内容来更新索引,然后在临时区域中准备下一次提交的内容。
        因此,在更改工作树之后,并且在运行 commit 命令之前,必须使用 add 命令将所有新文件或已修改的文件添加到索引中。为此,请使用以下命令:
      git add <directory>

      git add <file>
        让我为您演示 git add,以便您可以更好地理解它。
        我还创建了两个文件 edureka3.txt 和 edureka4.txt。让我们使用命令 git add -A 添加文件。此命令会将所有目录中的文件添加到索引中,但尚未在索引中更新。

        现在,新文件已添加到索引中,您可以提交它们了。

      提交(Commit)

        它指的是在给定时间记录存储库的快照。提交的快照永远不会改变,除非明确地完成。让我用下图来解释一下 commit 是如何工作的:

        这里,C1 是初始提交,即第一个更改的快照,从该更改创建另一个名为 C2 的快照。请注意,主节点指向最新的提交。
        现在,当我再次提交时,将创建另一个快照C3,现在主快照指向C3,而不是C2。
        Git 的 目标是使提交尽可能轻量。因此,它不会每次提交时都盲目复制整个目录;它包括作为一组更改的提交,或从一个版本的存储库到另一个版本的“增量”。 简单来说,它只复制在存储库中所做的更改。
        您可以使用以下命令提交:
      git commit
        这将提交暂存的快照,并将启动文本编辑器,提示您输入提交消息。
        或者您可以使用:
      git commit -m “<message>”
        让我们尝试一下。

        如您在上面看到的,git commit 命令已经提交了本地存储库中四个文件中的更改。
        现在,如果要一次提交工作目录中所有更改的快照,则可以使用以下命令:
      git commit -a
        我在工作目录 viz 中又创建了两个文本文件。edureka5.txt 和 edureka6.txt,但它们尚未添加到索引中。
        我正在使用命令添加 edureka 5.text:
      git add edureka5.txt
        我已将 edureka5.txt 显式添加到索引中,但没有将 edureka6.txt 添加到索引中,并在先前的文件中进行了更改。我想一次提交目录中的所有更改。请参考下面的快照。

        该命令将提交工作目录中所有更改的快照,但仅包括对跟踪文件的修改,即在历史记录中的某个时刻使用 git add 添加的文件。因此, edureka6.txt 尚未提交,因为尚未将其添加到索引中。但是会提交对存储库中所有先前文件的更改,即 edureka1.txt、edureka2.txt、edureka3.txt、edureka4.txt 和 edureka5.txt
        现在,我已经在本地存储库中完成了所需的提交。
        请注意,在影响对中央存储库的更改之前,应始终将更改从中央存储库拉到本地存储库,以更新在中央存储库中做出贡献的所有协作者的工作。为此,我们将使用 pull 命令。

      拉取(Pull)

        git pull 命令将更改从远程存储库获取到本地存储库。它合并了本地存储库中的上游更改,这是基于 Git 的协作中的常见任务。
        但首先,您需要使用以下命令将中央存储库设置为原始存储库:
      git remote add origin <中央存储库的链接>

        现在已经设置了原点,让我们使用 pull 从原点提取文件。 为此,请使用命令:
      git pull origin master
        此命令会将所有文件从远程存储库的 master 分支复制到本地存储库。

        由于我的本地存储库已经使用 master 分支中的文件进行了更新,因此该消息已经是最新的。请参阅上面的屏幕截图。
      注意: 也可以尝试使用以下命令从其他分支提取文件:
      git pull origin <branch-name>
        现在,您的本地 Git 存储库已使用所有最近的更改进行了更新。现在是时候使用 push 命令在中央存储库中进行更改了。

      推送(Push)

        此命令将提交从本地存储库传输到远程存储库。它与拉取操作相反。
        将导入提交到本地存储库,而将导出将提交到远程存储库。
        git push 的用途是将本地更改发布到中央存储库。积累了多个本地提交并准备与团队其他成员共享之后,可以使用以下命令将其推送到中央存储库:
      git push <远程>
      注:**该远程引用在使用 pull 命令之前设置的远程存储库。
        这将把更改从本地存储库推送到远程存储库,以及所有必要的提交和内部对象。并将在目标存储库中创建一个本地分支。
        我来为您演示一下。

        上面的文件是我们之前在 commit 部分中已经提交的文件,它们都是“push-ready”的。我将使用命令
      git push origin master 来将这些文件反映在中央存储库的 master 分支中。

        现在让我们检查这些更改是否发生在我的中央存储库中。

        是的,确实如此。 🙂
        为了防止覆盖,当Git在目标存储库中导致非快进合并时,它不允许推送。
      注意: 非快进合并是指上游合并,即与子分支的祖先或父分支合并。
        要启用这种合并,请使用以下命令:
      git push <remote> –force**
        上面的命令将强制执行推操作,即使它会导致非快进合并。
        到目前为止,我希望您已经了解了 Git 的基本命令。现在,让我们进一步学习在 Git 中进行分支和合并。

      分支(Branching)

        Git 中的分支只是指向特定提交的指针。Git通常更倾向于保持其分支尽可能轻量级。
        基本上有两种类型的分支,即本地分支远程跟踪分支
        本地分支只是您的工作树的另一条路径。另一方面,远程跟踪分支有特殊用途。 其中一些是:

  • 他们将您的工作从本地存储库链接到中央存储库上的工作。
  • 当您使用 git pull 时,它们会自动检测要从哪个远程分支获取更改。
      您可以使用以下命令检查当前分支是什么:
    git branch
      分支时您应该经常念诵的口号是“早分支,常分支”。
      要创建一个新分支,我们使用以下命令:
    git branch <branch-name>

      上图显示了创建新分支时的工作流程。当我们创建一个新分支时,它源自master分支本身。
      由于创建多个分支没有存储/内存开销,因此逻辑上划分您的工作比拥有大块的分支要容易得多。
      分支包括特定提交和所有父提交的工作。如您在上图中所看到的,newBranch 已与主服务器分离,因此将创建一条不同的路径。
      使用以下命令:
    git checkout <branch_name> 然后执行
    git commit
      现在,让我们看看如何使用提交分支。

      分支包括特定提交和所有父提交的工作。如您在上图中所看到的,newBranch 已与主服务器分离,因此将创建一条不同的路径。
      使用以下命令:
    git checkout <branch_name> 然后执行
    git commit

      在这里,我创建了一个名为“ EdurekaImages”的新分支,并使用命令 git checkout 切换到该新分支。
      上述命令的一种快捷方式是:
    git checkout -b[ branch_name]
      此命令将创建一个新分支并同时签出新分支。
      现在,当我们在分支 EdurekaImages 中时,使用以下命令添加并提交文本文件 edureka6.txt:
    git add edureka6.txt
    git commit -m "adding edureka6.txt"

    合并(Merging)

      合并是将不同分支的工作合并在一起的方法。这将允许我们进行分支,开发新功能,然后将其合并回来。

      上图为我们展示了两个不同的分支-> newBranch 和 master。现在,当我们将 newBranch 的工作合并到master 中时,它将创建一个新提交,其中包含 master 和 newBranch 的所有工作。
      现在,让我们使用下面的命令合并两个分支:
    git merge <branch_name>
      上述命令中的分支名称应该是你想要合并到当前所签出分支的分支。因此,请确保您已在目标分支中检出。
      现在,让我们将分支 EdurekaImages 的所有工作合并到 master 分支中。为此,我将首先使用 git checkout master 命令检出master分支,然后用 git merge EdurekaImages 命令合并 EdurekaImages。

      如上所示,分支名称中的所有数据都合并到了master分支中。现在,文本文件 edureka6.txt 已添加到 master 分支中。
      在 Git 中合并会创建一个特殊的提交,该提交具有两个唯一的父级。

    变基(Rebasing)

      这也是组合不同分支之间的工作的一种方式。变基接受一组提交,将其复制并存储在您的存储库外部。
      变基的优点是它可以用于制作线性的提交序列。如果完成了重新基准化,则提交日志或存储库的历史记录将保持干净。
      让我们看看它是如何发生的:

      现在,我们在 newBranch 上的工作紧随 master 之后,我们有了不错的线性提交序列。
      注意: 重新设置基准还可以防止上游合并,这意味着您不能将 master 放在newBranch之后。
      现在,要重设 master,请在 Git Bash 中键入以下命令:
    git rebase master

      此命令会将我们所有的工作从当前分支移至主节点。 它们看起来好像是顺序开发的,但是却是并行开发的。提示和技巧
      现在,您已经完成了本Git教程中的所有操作,这里是您应该知道的一些提示和技巧。 🙂

    归档存储库

      使用以下命令:
    git archive master –format=zip –output= ../name-of-file.zip
      它将所有文件和数据存储在一个 zip 文件中,而不是 .git 目录中。
      请注意,这仅会创建一个快照,从而完全忽略了版本控制。当您要将文件发送给未在计算机上安装Git的客户端进行审核时,这非常方便。

    绑定存储库

      它将存储库转换为单个文件。
      使用以下命令:
    git bundle create ../repo.bundler master
      这会将 master 分支推送到一个远程分支,该分支仅包含在文件中,而不是存储库中。
      另一种方法是:
    cd..
    git clone repo.bundle repo-copy -b master
    cd repo-copy
    git log
    cd.. /my-git-repo

    隐藏未提交的更改

      当我们要撤消临时添加功能或任何种类的数据时,可以临时“隐藏”它们。
      使用以下命令:
    git status
    git stash
    git status

      当您要重新应用“隐藏”的更改时,请使用以下命令:
    git stash apply
      我希望您喜欢这个 Git Bash 教程,并学习了 Git 中的命令和操作。

什么是 Git? – 探索分布式版本控制工具

【注】本文译自:https://www.edureka.co/blog/what-is-git/
  Git是一个免费的开源分布式版本控制系统工具,旨在快速高效地处理从小型到大型的所有项目。它是由 Linus Torvalds 在2005年创建的,用于开发 Linux 内核。Git具有大多数团队和开发人员所需的功能、性能、安全性和灵活性。它还用作重要的分布式版本控制 DevOps 工具
  在本文中,你将学到:

  • 为什么会有 Git?
  • Git 是什么?
  • Git 的特性
  • Git 如何在 DevOps 中发挥至关重要的作用?
  • 微软和其他公司如何使用Git

    Git 的来由

      我们都知道“需要是一切发明之母”。同样,Git 的发明也是为了满足开发人员在 Git 出现之前所面临的某些需求。

    Git 的目的是什么?

      Git 主要用于管理您的项目,包括一组可能会更改的代码/文本文件。
      但是在进一步讨论之前,让我们回顾一下所有有关版本控制系统(VCS)的知识,以及 Git 是如何诞生的。
      版本控制是对文档、计算机程序、大型网站和其他信息收集的变更进行管理。

    VCS 有两种类型:

  • 集中版本控制系统(CVCS)
  • 分布式版本控制系统(DVCS)

    集中式 VCS

      集中式版本控制系统(CVCS)使用中央服务器来存储所有文件并支持团队协作。 它在单个存储库上工作,用户可以直接访问该存储库。
      请参考下图,以更好地了解CVCS:

      上图中的存储库指示一个中央服务器,可以是本地的,也可以是远程的,它直接连接到每个程序员的工作站。
      每个程序员都可以使用存储库中存在的数据来提取或更新其工作站,或者可以对数据进行更改或提交到存储库中。每个操作都直接在存储库上执行。
      尽管维护单个存储库似乎很方便,但它也有一些主要缺点。其中一些是:

  • 它在本地不可用; 这意味着您始终需要连接到网络才能执行任何操作。
  • 由于所有内容都是集中式的,在任何情况下中央服务器都崩溃或损坏都将导致丢失整个项目的数据。
      分布式 VCS 就是这些问题的救星。

    分布式 VCS

      这些系统不必依赖中央服务器来存储项目文件的所有版本。
      在分布式VCS中,每个贡献者都有主存储库的本地副本或“克隆”,即每个人都维护自己的本地存储库,其中包含主存储库中存在的所有文件和元数据。
      参考下图,您会更好理解:

      如上图所示,每个程序员都自己维护一个本地存储库,它实际上是其硬盘驱动器上的中央存储库的副本或克隆。他们可以提交和更新其本地存储库,而不会受到任何干扰。
      他们可以通过“拉”操作使用来自中央服务器的新数据更新本地存储库,并通过本地存储库中的“推”操作影响对主存储库的更改。
      将整个存储库克隆到工作站以获取本地存储库的操作为您带来以下优势:

  • 所有操作(推和拉除外)都非常快,因为该工具仅需要访问硬盘驱动器,而无需访问远程服务器。因此,您并不总是需要互联网连接。
  • 可以在本地完成新变更集的提交,而无需处理主存储库上的数据。一旦准备好一组变更集,就可以一次推送所有变更集。
  • 由于每个贡献者都有项目存储库的完整副本,因此,如果他们希望在影响主存储库中的更改之前获得一些反馈,则可以彼此共享更改。
  • 如果中央服务器在任何时间崩溃,丢失的数据可以很容易地从贡献者的任何本地存储库中恢复。
      了解了分布式 VCS 之后,是时候深入了解一下什么是 Git 了。

    什么是 Git?

      Git 是一种分布式版本控制工具,它通过为开发高质量软件提供数据保证来支持分布式非线性工作流。
      Git为用户提供了前面提到的所有分布式 VCS 工具。Git仓库很容易找到和访问。当您了解以下功能时,您将知道 Git 与系统的灵活性和兼容性:

    Git 的特性

    免费和开源:
      Git是根据GPL(通用公共许可证)的开源许可证发布的。您无需购买Git。它是完全免费的。并且由于它是开源的,因此您可以根据需要修改源代码。
    速度:
      由于您不必连接到任何网络即可执行所有操作,因此它可以非常快速地完成所有任务。Mozilla 所做的性能测试表明,它比其他版本控制系统快一个数量级。从本地存储的存储库中获取版本历史记录的速度可能比从远程服务器中获取版本历史记录的速度快一百倍。Git 的核心部分是用C编写的,这避免了与其他高级语言相关的运行时开销。
    可扩展性:
      Git 具有很好的可扩展性。因此,如果将来合作者的数量增加,Git 可以轻松应对这一变化。尽管 Git 代表了一个完整的存储库,但是存储在客户端上的数据非常少,因为 Git 通过无损压缩技术压缩了所有大数据。
    可靠性:
      由于每个贡献者都有自己的本地存储库,在系统崩溃时,可以从任何本地存储库中恢复丢失的数据。您将始终拥有所有文件的备份。
    安全性:
      Git使用 SHA1(安全哈希函数)来命名和标识其存储库中的对象。在签出时,每个文件和提交都通过其校验和进行校验和并检索。Git 历史记录的存储方式使得特定版本的 ID(在 Git 术语中是提交)取决于提交之前的完整开发历史记录。一旦发布,就无法在不被注意的情况下更改旧版本。
    经济性:
      对于 CVCS,中央服务器必须足够强大以服务于整个团队的请求。对于较小的团队来说,这不是问题,但是随着团队规模的扩大,服务器的硬件限制可能会成为性能瓶颈。对于 DVCS,除非开发人员需要推送或提取更改,否则它们不会与服务器交互。所有繁重的工作都发生在客户端,因此服务器硬件实际上非常简单。
    支持非线性开发:
      Git 支持快速分支和合并,并包括用于可视化和导航非线性开发历史的特定工具。Git中的一个核心假设是,变更的合并频率要比写入的频率高,因为变更会在各个审阅人员之间传递。Git 中的分支非常轻巧。Git 中的分支只是对单个提交的引用。借助其父提交,可以构造完整的分支结构。
    易于分支:
      使用 Git 进行分支机构管理非常简单。创建、删除和合并分支仅需几秒钟。特性分支为代码库的每次更改提供了独立的环境。当开发人员想要开始做某件事时,无论大小,他们都会创建一个新的分支。 这样可以确保 master 分支始终包含生产质量代码。
    分布式开发:
      Git 为每个开发人员提供了整个开发历史的本地副本,并将更改从一个这样的存储库复制到另一个存储库。这些更改将作为其他开发分支导入,并且可以以与本地开发分支相同的方式合并。
    与现有系统或协议的兼容性:
      可以通过 http,ftp 或 Git 协议通过普通套接字或 ssh 发布存储库。Git 还具有并发版本系统(CVS)服务器仿真,它可以使用现有的 CVS 客户端和IDE 插件来访问 Git 存储库。Apache SubVersion(SVN)和 SVK 存储库可以直接与 Git-SVN 一起使用。

    Git 在 DevOps 中的作用?

      既然您知道什么是 Git,那么您应该知道 Git 是 DevOps 不可或缺的一部分。
      DevOps 是将敏捷性引入开发和运营过程的实践。这是一种全新的意识形态,席卷了全世界的It组织,促进了项目生命周期,进而增加了利润。DevOps 促进开发工程师和运营人员之间的沟通,共同参与整个服务生命周期,从设计到开发过程,再到生产支持。
      下图描述了 Devops 的生命周期,并显示了 Git 如何适合 Devops。

      上图显示了 Devops 的整个生命周期,从计划项目到部署和监视。当管理协作者为共享存储库贡献的代码时,Git 扮演着至关重要的角色。然后提取该代码以执行连续集成,以创建内部版本并在测试服务器上对其进行测试,最后将其部署在生产环境中。
      诸如Git之类的工具使开发人员与运营团队之间能够进行沟通。当您开发一个拥有大量协作者的大型项目时,在项目中进行更改时,在协作者之间进行沟通非常重要。在Git 中提交消息在团队之间的沟通中起着非常重要的作用。我们所有人部署的零碎内容都位于版本控制系统(如 Git )中。要在 DevOps 中取得成功,您需要在版本控制中进行所有通信。因此,Git 在 DevOps 的成功中起着至关重要的作用。

    使用 Git 的热门公司

      与市场上其他可用的版本控制工具(例如Apache Subversion(SVN),并发版本系统(CVS),Mercurial等)相比,Git 更受欢迎。您可以通过下面的 Google 趋势图来比较 Git 和其他版本控制工具的兴趣:

      在大型公司中,产品通常是由遍布世界各地的开发人员开发的。为了实现它们之间的通信,Git 是解决方案。
      一些使用 Git 进行版本控制的公司包括:Facebook、Yahoo、Zynga、Quora、Twitter、eBay、Salesforce、Microsoft等。
      最近,Microsoft 的所有新开发工作都已包含在 Git 特性中。微软正在迁移 .NET 和它的许多开源项目迁移到 GitHub 上,这些项目都是由 Git 管理的。
      其中一个项目是 LightGBM。 它是一种快速、分布式、高性能的基于决策树算法的梯度增强框架,用于排序、分类等许多机器学习任务。
      在这里,通过提供速度和准确性,Git 在管理 LightGBM 的分布式版本中扮演着重要角色。

使用 Puppet 进行配置管理

【注】本文译自https://www.edureka.co/blog/what-is-puppet/
  今天,配置管理最成熟的工具是 Puppet。但是,我想您一定想知道为什么 Puppet 如此受欢迎、与其他配置管理工具相比,它有什么独特之处。

什么是 Puppet?

  Puppet 是配置管理工具,用于部署、配置和管理服务器。它具有以下功能:

  • 为每个主机定义不同的配置,并持续检查和确认主机上是否存在所需的配置,是否没有修改(如果修改后的Puppet将恢复到所需的配置)
  • 动态增减机器规模
  • 可控制所有配置机器,从而集中式(基于主服务器或仓储)变更可以自动传播给其他机器

  Puppet 使用主从架构,主从之间通过 SSL 使用安全的加密通道进行通信。
  知道了什么是 Puppet,下面让我们了解 Puppet 为什么会如此受青睐。

关键指标

  下面是有关 Puppet 的关键因素:

  • 庞大的安装群体:Puppet 在全球超过 30,000 家公司中使用,包括 Google、Red Hat、Siemens 等,以及斯坦福大学和哈佛法学院等几所大学。并且每天平均有 22 个新组织首次使用 Puppet。
  • 庞大的开发人员基础:Puppet用途广泛,很多人都在为它开发。Puppet 的核心源代码有许多贡献者。
  • 长期商业使用:Puppet 2005 年已投入商业使用,并且一直在不断完善和改进。它已经部署在非常广泛的基础架构(5,000多台计算机)中,同时在这些项目中所积累的性能和可伸缩性经验为 Puppet 的发展做出了贡献。
  • 文档:Puppet 有一个大型的用户维护的 Wiki,其中包含数百页的文档以及有关语言及其资源类型的全面参考。此外,它还在多个邮件列表中进行了积极的讨论,并拥有一个非常受欢迎的 IRC 频道,因此,无论你有什么问题,都可以轻松找到答案。
  • 平台支持:Puppet Server可以在支持ruby的任何平台上运行,例如:CentOS,Microsoft Windows Server,Oracle Enterprise Linux等。它不仅支持新的操作系统,而且还可以在相对老旧的操作系统和 Ruby 版本上运行。

  现在很明显,Puppet在全球范围内有巨大的需求。但是,在深入研究 Puppet 之前,我首先解释什么是配置管理及其重要性。

配置管理

  系统管理员通常执行重复性任务,例如安装服务器,配置这些服务器等。他们可以通过编写脚本来自动执行此任务,但是在大型基础架构上工作时,会非常繁琐。
  为了解决这一问题,引入了配置管理。 配置管理是一种系统地处理变更的实践,以便系统随着时间的推移保持其完整性。配置管理(CM)确保系统的当前设计和构建状态是已知的,良好的和可信赖的;并且不依赖开发团队的隐性知识。它允许访问准确的系统状态历史记录,以进行项目管理和审计。配置管理克服了以下挑战:

  • 由于需求变更而带来的重新实现。
  • 对于新发布但有缺陷的版本,可还原到先前版本。
  • 因为无法确定组件类型而导致发布错误的组件。

  让我们通过一个用例来了解它的重要性。
  我知道的最好的例子发生在纽约证券交易所(NYSE)。一个软件“故障”使纽交所在近90分钟的时间内无法进行股票交易,造成了数百万美元的损失。这是由于安装新软件所导致,该软件已安装在其20个交易终端中的8个上,并且该系统已在前一天晚上进行了测试。但是,早晨,它在8个终端上无法正常运行。因此,必须切换回旧软件。您可能会认为这是纽约证券交易所配置管理流程的失败,但实际上这正是它的成功之处上:通过适当的配置管理流程,NYSE 在90分钟内中恢复正常,速度非常快。如果问题持续更长的时间,后果将更加严重。

  现在,希望您了解配置管理的重要性。配置管理阶段可以看作是 DevOps 的主干。它允许以最安全,最可靠的方式更频繁地发布软件。
  接下来,让我们来看看 Puppet 的一些应用。

Puppet 的应用

  让我们通过一个案例来了解 Puppet 的应用。如果您是扑克爱好者或曾经玩过在线游戏,那么您一定已经听说过 Zynga。它是世界上最大的社交游戏开发商。Zynga的基础设施在公共云和私有数据中心都使用了数以万计的服务器。早期,他们使用手动流程,包括 kickstarter 和 post 安装,以使数百台服务器上线。
  现在,我们将看到他们在此过程中面临哪些问题:

  • 可扩展性和一致性 – Zynga 经历了惊人的增长,其基础架构需要跟上行业发展的步伐。基于脚本的解决方案和手动方法不足以满足其需求。
  • 便携式基础架构 – Zynga 需要在公共云基础设施和自己的数据中心中利用一致的配置管理方法。
  • 灵活性 – 考虑到 Zynga 游戏的多样性,团队能够快速匹配适用于不同机器的配置非常重要。
  • 基础架构洞察力 – 随着组织的成熟,拥有一种可视化每台计算机属性的自动化方法变得越来越重要。

  该公司足够聪明,甚至在实现快速扩张之前就迅速意识到对自动化流程的需求,这时 Puppet 就出现了。让我们了解 Puppet 是如何为他们的组织做出贡献的。

  • 恢复速度 – 生产运营团队可以将正确的配置快速部署到正确的位置。如果对系统进行了不正确的重新配置,Puppet 将自动将其恢复为上一个稳定状态,或者提供快速手动修复系统所需的详细信息。
  • 部署速度 – Puppet 提供的服务方式为游戏工作室的运营团队节省了大量的时间。
  • 服务器的一致性 – Puppet 的模型驱动框架可确保部署的一致性。Zynga 生产运营副总裁 Mark Stockford 表示:“很明显,我们节省了时间。使用Puppet的好处在于,它允许我们在短时间内跨服务器交付一致的配置。”
  • 协作 – 采用模型驱动的方法可以轻松地在组织内共享配置,使开发人员和运营团队可以一起工作,以确保新的服务交付具有极高的质量。Zynga 团队的十多人接受了 Puppet 培训。这些知识传播到整个团队以及各个游戏工作室的运营团队中。

微服务指南

【注】本文节译自: Microservices Guide (martinfowler.com)

简而言之,微服务架构风格是一种将单个应用程序开发为一组小型服务的方法,每个小服务都在自己的进程中运行,并与轻量级机制(通常是 HTTP 资源 API)进行通信。这些服务围绕业务功能构建,并且可以通过全自动部署机制独立部署。这些服务可以用不同的编程语言编写,使用不同的数据存储技术,只要进行最小化的集中管理。
詹姆斯·刘易斯和马丁·福勒(2014)

martinfowler.com上有关微服务的材料指南。
马丁·福勒2019.8.21

2013年底,在我的圈子里听到了有关微服务的所有讨论后,我开始担心微服务的定义不明确(这种命运给SOA带来了许多问题)。因此,我和同事詹姆斯·刘易斯(James Lewis)聚在一起,他是这种风格的资深从业者之一。 我们一起写

  我们写这篇文章是为了对微服务风格提供一个明确的定义,我们通过列出我们在该领域中看到的微服务架构的共同特征来实现这一点。

  • 通过服务实现组件化
  • 围绕业务能力进行组织
  • 产品不是项目
  • 智能端点和哑管道
  • 分散治理
  • 分散数据管理
  • 基础设施自动化
  • 故障设计
  • 进化设计

  我们还研究了一些常见问题,例如“微服务的规模有多大”以及“微服务与面向服务的体系结构之间的区别是什么”。这篇文章激发了人们对微服务的兴趣。
“我们使用它,我们不使用它?
……这到底是什么呢?”

  在简短的介绍性演讲(约25分钟)中,我选择了最重要的定义特征,将微服务与整体组件进行了比较,并概述了将第一个微服务系统投入生产之前要做的重要工作。

我们什么时候应该使用微服务?

  任何架构风格都需要权衡:我们必须根据它所使用的上下文来评估其优缺点。微服务肯定是这种情况。尽管它是一种有用的体系结构,但实际上,大多数情况下,使用整体组件会更好。

微服务提供优势…

  • 强大的模块边界:微服务加强了模块化结构,这对于大型团队而言尤其重要。
  • 独立部署:简单服务更易于部署,并且由于它们是自治的,因此出错时不太可能导致系统故障。
  • 技术多样性:使用微服务,您可以混合使用多种语言、开发框架和数据存储技术。

…但要付出代价

  • 分布式:分布式系统较难编程,因为远程调用速度很慢,并且总是面临失败的风险。
  • 最终一致性:对于分布式系统而言,保持强一致性非常困难,这意味着每个人都必须管理最终一致性。
  • 运营复杂性:您需要一个成熟的运营团队来管理大量服务,这些服务会定期重新部署。

微服务高级版

在过去的一年里,微服务架构风格一直是热门话题。在最近的 O’Reilly 软件架构会议上,似乎每个会议都在谈论微服务。足以使每个人的“过度炒作检测器”启动并闪烁起来。其后果之一是,我们已经看到团队太渴望接受微服务,而没有意识到微服务会给自己带来复杂性。这给项目的成本和风险增加了额外的费用—这通常会使项目陷入严重的麻烦。
马丁·福勒(Martin Fowler)2015.5.13

整体优先


  当我听到团队使用微服务架构的故事时,我注意到了一种常见的模式。

  1. 几乎所有成功的微服务故事都始于一个庞大的整体,并且被分解了
  2. 我听说过的从头构建为微服务系统的系统都遇到了严重的麻烦。

不要从整体开始

在过去的几个月中,我反多次听到这样的说法:获得成功的微服务架构的唯一方法就是首先从整体开始。用西蒙·布朗(Simon Brown)的话来说:如果您无法构建结构良好的整体,那么为什么您认为可以构建一组结构良好的微服务呢?最近(通常是非常有说服力的)的论点来自该站点上的马丁·福勤。当我有机会对早期的草案发表评论时,我有一些时间来考虑这一点。 我之所以这样做,尤其是因为我通常会发现自己与他一致,而其他一些我通常分享的观点似乎也同意他。我坚信从整体开始通常是错误的做法。
斯蒂芬·蒂尔科夫(Stefan Tilkov)2015.6.9

微服务先决条件

当我与人们谈论使用微服务架构风格时,我听到了很多乐观情绪。开发人员喜欢使用较小的单元,并且期望比整体组件具有更好的模块化。但是,与任何架构决策一样,都需要权衡取舍。尤其是对于微服务而言,这给运营带来了严重后果,运营者现在必须处理小型服务的生态系统,而不是一个定义良好的单一整体。因此,如果你没有某些基本能力,就不应该考虑使用微服务风格。
马丁·福勒(Martin Fowler)2014.8.28

微服务和分布式对象的第一定律

在 EAA 的 P 中,我说“不要分发您的对象”。 这个建议是否与我对微服务的兴趣相矛盾?
马丁·福勒(Martin Fowler)2014.8.13

与萨姆·纽曼(Sam Newman)关于微服务的访谈

goto会议要求我对萨姆·纽曼的书《Monoliths to Microservices》进行采访。这变成了有关微服务及其何时使用它们的一般性讨论。萨姆认为它们的三个主要原因是独立的可部署性、数据的隔离性和反映组织结构。我对第一个更为怀疑,但认为数据和人员是软件开发的复杂部分。
马丁·福勒(Martin Fowler)2020.9.4

构建微服务

  微服务架构是相当新的,但我很幸运,自从最早出现以来,我们就一直在 ThoughtWorks 与它们合作。关于如何最好地与他们合作的最好描述,最好的介绍是萨姆·纽曼(Sam Newman)的书《构建微服务》,他根据我们的经验和其他已发表的经验撰写了这本书。

微服务架构中的测试策略

在过去的几年中,基于服务的架构已转向更小、更集中的“微”服务。这种方法有很多好处,例如能够独立部署、扩展和维护每个组件,并使多个团队之间的开发并行化。但是,一旦引入了这些额外的网络分区,就需要重新考虑应用于单片进程应用的测试策略。在这里,我们计划讨论一些方法,用于管理多个可独立部署的组件的额外测试复杂性,以及在多个团队各自充当不同服务的监护人的情况,如何让测试和应用保持正确。
托比·克莱姆森(Toby Clemson)2014.11.18

如何将单体应用分解为微服务

随着整体系统变得太大而无法处理,许多企业倾向于将其分解为微服务架构风格。 这是一次值得的旅程,但并不容易。 我们已经了解到,要做到这一点,我们需要从简单的服务开始,然后再基于对业务很重要并且会经常更改的垂直功能来提供服务。这些服务起初应该很大,最好不依赖于其余的整体。我们应该确保迁移的每一步都代表了整个体系结构的原子性改进。
扎马克·德加尼(Zhamak Dehghani)2018.4.24

微前端

好的前端开发很难。扩展前端开发,使许多团队可以同时处理大型复杂产品,这变得更加困难。在本文中,我们将描述最近的一种趋势,即将前端整体拆分成许多更小、更易于管理的部分,以及这种架构如何提高前端代码团队的效率。除了讨论各种收益和成本外,我们还将介绍一些可用的实现选项,并深入研究演示该技术的完整示例应用。
卡姆·杰克逊(Cam Jackson)2019.6.19

如何从整体中提取数据丰富的服务

当将整体式服务器拆分成较小的服务时,最困难的部分实际上是拆分存在于整体式数据库中的数据。要提取数据丰富的服务,遵循一系列步骤始终保持数据的单个写副本是很有用的。这些步骤首先在现有的整体中进行逻辑分离:将服务行为拆分为单独的模块,然后将数据拆分为单独的表。这些元素可以分别移动到新的自治服务中。
普拉富尔·托德卡尔(Praful Todkar)2018.8.30

基础设施即代码

基础架构即代码是通过源代码定义计算和网络基础架构的方法,然后可以像对待任何软件系统一样对待它们。可以将此类代码保留在源代码控制中,以允许可审核性和可复制的构建,服务从于测试实践,以及持续交付的完整规范。在过去的十年中,这种方法已用于应对不断增长的云计算平台,并且将成为下一个处理计算基础架构的主要方法。
马丁·福勒(Martin Fowler)2016.3.1

DevOps 文化

敏捷软件开发打破了需求分析、测试和开发之间的一些孤岛。部署、操作和维护是其他活动,它们与其余软件开发过程有着类似的分离。DevOps 运动旨在消除这些孤岛,并鼓励开发与运营之间的协作。
鲁安·威尔森纳赫(Rouan Wilsenach)2015.7.9

熔断器

对于软件系统,通常是远程调用运行在不同进程中的软件,可能是在网络中的不同计算机上。内存内调用和远程调用之间的最大区别之一是,远程调用可能会失败,或者挂起而没有响应,直到达到某个超时限制。更糟糕的是,如果您在没有响应的供应商上有许多调用者,那么您可能会耗尽关键资源,从而导致多个系统之间的级联故障。 迈克尔·尼加德(Michael Nygard)在他的优秀著作《释放它》(Release It)中推广了断路器模式,以防止这种灾难性的连锁反应。 熔断器的基本原理非常简单。将受保护的函数调用包装在熔断器对象中,该对象将监视故障。 一旦故障达到某个阈值,熔断器将跳闸,并且所有进一步的熔断器调用都会返回错误,而根本不会进行受保护的调用。通常,如果熔断器跳闸,您还需要某种监控器警报。
马丁·福勒(Martin Fowler)2014.3.

软件架构指南

【注】本文节译自: Software Architecture Guide (martinfowler.com)
  当软件行业的人们谈论“架构”时,他们指的是软件系统内部设计最重要方面的一个模糊定义概念。好的架构很重要,否则将来增加新功能会变得越来越慢,而且成本更高。

  像软件世界中的许多人一样,我一直对“架构”一词持谨慎态度,因为它通常暗示着与编程的分离和不健康的浮夸。但是,我通过强调好的架构可以支持其自身的发展,并与编程紧密地交织在一起,来解决我的担忧。我的职业生涯大部分时间都围绕着以下问题:好的架构是什么样的,团队如何创建它,以及如何最好地在我们的开发组织中培养架构思维。该页面概述了我对软件架构的看法,并在这个网站上有关为你带来更多关于架构的材料。martinfowler.com 上有关软件体系结构的材料指南。
马丁·福勒
2019年8月1日

什么是架构?

  软件界的人们长期以来一直在争论架构的定义。对于某些人来说,这就像是系统的基本组织,或者是将最高级别的组件连接在一起的方式。 我对此的想法是由与拉尔夫·约翰逊(Ralph Johnson)进行的电子邮件交流形成的,后者对这一措辞提出了质疑,认为没有客观的方法来定义基础知识或高级知识,而对架构的一个更好的视角是专家开发人员达成共识的系统设计
QCon拉尔夫·约翰逊(Ralph Johnson)在 QCon 上演讲
  架构的第二种常见定义方式是“需要在项目早期就做出设计决策”,但拉尔夫也对此表示抱怨,说这更像是你希望能够在项目的早期就做出正确的决策
  他的结论是“架构是关于重要的东西,不管是什么。” 乍一看,这听起来很老套,但我发现它带有很丰富的内涵。 这意味着从结构的角度思考软件的的核心是确定重要的东西(即什么是架构),然后花精力保持那些架构元素处于良好状态。对于要成为架构师的开发人员来说,他们需要能够识别哪些要素很重要,以及哪些元素在被控制的情况下可能会导致严重的问题。
拉尔夫的电子邮件构成了我在IEEE软件专栏的核心,该专栏讨论了软件架构的含义和架构师的角色。

为什么架构很重要?

  对于软件产品的客户和用户而言,架构是一个棘手的问题-因为这不是他们能马上感知的东西。但是,糟糕的架构是促成杂乱无章的主要因素,杂乱无章是软件的要素,阻碍了开发人员理解软件的能力。包含大量附加内容的软件难以修改,导致功能实现的速度更慢,缺陷也很多。

  这种情况与我们通常的经验背道而驰。 我们习惯了“高品质”的东西看作是价格更高的东西。对于软件的某些方面(比如用户体验),这可能是正确的。但是当涉及到架构和内部质量的其他方面时,这种关系就反过来了。高的内部质量可以更快地交付新功能,因为减少了麻烦。
  虽然我们可以在短期内牺牲质量来换取更快的交货速度,但在货物堆积产生影响之前,人们低估了货物堆积导致整体交货速度较慢的速度。虽然这不是可以客观衡量的东西,但是经验丰富的开发人员认为,关注内部质量只需要几周而不是几个月就可获得回报
在2015年的OSCON上,我作了简短的演讲(14分钟),内容涉及什么是架构及其重要性。

应用架构

  软件开发中的重要决策会随着我们所考虑的上下文规模而变化。常见的规模是应用程序的规模,因此是“应用程序架构”。
  定义应用架构的第一个问题是对应用是什么没有明确的定义。我认为应用是一种社会结构:

  • 被开发人员视为一个单元的代码体
  • 业务客户将其视为一个单元的一组功能
  • 那些有钱的人将其视为单一预算

  如此宽松的定义导致应用的潜在规模很多,开发团队的人数从几人到几百人不等。(您会注意到,我认为规模是涉及的人员数量,我认为这是衡量此类事情的最有用方法。)此架构与企业架构之间的主要区别在于,围绕社会构建有一个重要程度的统一目标。

应用边界

  软件开发中尚未解决的问题之一就是确定软件的边界是什么。(浏览器是不是操作系统的一部分?)面向服务体系结构的许多支持者认为应用将不复存在-因此,未来的企业软件开发将致力于将服务组装在一起。
  我不认为应用的消失和应用界限难以划分的原则一样的。本质上,应用是一种社会结构:
马丁 · 福勒
2003.9.11

微服务指南

微服务架构模式是一种将单个应用程序开发为一组小服务的方法,每个小服务都在自己的进程中运行并与轻量级机制(通常是HTTP资源API)进行通信。这些服务围绕业务功能构建,并且可以由完全自动的部署机制独立部署。这些服务可以用不同的编程语言编写,使用不同的数据存储技术,对这些服务可进行最基本的集中管理。尽管它们的优势使它们在最近几年非常流行,但它们却伴随着分销增加、一致性降低和需要成熟的经营管理的代价。
马丁·福勒

Serverless 架构

无服务器架构是结合第三方“后端即服务”(BaaS)服务和/或包含在“功能即服务”(FaaS)平台上的托管临时容器中运行的自定义代码的应用设计。通过使用这些思想以及诸如单页应用程序之类的相关思想,这样的架构消除了对传统的永远在线服务器组件的大量需求。无服务器架构可能会受益于显着降低的运营成本、复杂性和工程交货时间,但代价是增加对于供应商的依赖性和相对不成熟的支持服务的依赖。
迈克·罗伯茨
2018.5.22

微前端

好的前端开发很难。扩展前端开发,使许多团队可以同时从事大型复杂产品开发则更加困难。在本文中,我们将描述最近的一种趋势,即将前端整体拆分成许多更小、更易于管理的部分,以及这种体系结构如何提高处理前端代码的团队效率。除了讨论各种收益和成本外,我们还将介绍一些可用的实现选项,并且将深入研究一个演示该技术的完整示例应用。
卡姆·杰克逊
2019.6.19

GUI 架构

在 21 世纪中期,我一直在从事一些写作项目,这些项目本可以成书,但尚未完成。一个是关于用户界面的架构。作为这项工作的一部分,我起草了一份关于GUI架构演变的描述,比较了表单和控件的默认方法和模型-视图-控制器(MVC)模式。MVC 是软件世界中最难理解的模式之一,这是可以理解的,因为它没有很好的文档记录。因此,我在这里的写作试图更好地了解MVC的真正含义以及它如何通过模型-视图-表示器(Model-View-Presenter)和其他形式发展起来的。
2006.7.18

展现域数据屋

模块化一个信息丰富的程序的一种最常见方法是将其分为三层:展现(UI),域逻辑(即业务逻辑)和数据访问。因此,你经常会看到Web 应用程序被划分为Web 层(了解如何处理 HTTP 请求和呈现 HTML)、业务逻辑层(包含验证和计算),数据访问层(整理如何管理数据库或远程服务中的持久性数据) 。
马丁·福勒
2015.8.26

企业架构

  应用架构集中于某种形式的概念性应用边界内的体系结构,而企业架构看起来是跨大型企业的体系结构。这样的组织通常太大了,无法将其所有软件按任何一种有凝聚的方式进行分组,因此需要跨多个具有相互独立开发的代码库的团队进行协调,并需要资金和用户彼此独立运作。
  企业架构的大部分内容都是关于了解什么是值得集中协调的成本,以及协调应采取什么形式。一个极端是中央架构小组,它必须批准企业中每个软件系统的所有架构决策。这样的小组减慢了决策的速度,无法真正理解如此广泛的系统组合中的问题,从而导致决策不力。但是另一个极端是根本没有协调,这导致团队重复工作,不同系统无法进行互操作以及团队之间缺乏技能开发和交叉学习。
  像大多数具有敏捷心态的人一样,我更喜欢在分散化方面犯错,因此会更趋于混乱,而不是令人窒息的控制。但是,站在渠道的那一边仍然意味着我们必须避开险阻,并以要最小化实际成本的方式最大化本地决策。

企业架构师加入团队

企业架构组经常远离日常开发。这可能会导致他们对开发工作的了解过时,抱怨开发团队没有从整个公司的角度出发。我的同事(ThoughtWorks CTO)Rebecca 经常看到这种情况发生,她认为加入开发团队可以提高企业架构师的效率。
瑞贝卡·帕森斯(Rebecca Parsons)
2005.9

企业架构师在精益企业中的角色

当组织采取敏捷的思维方式时,企业架构不会消失,但是企业架构师的角色会发生变化。 企业架构师不再做出选择,而是帮助其他人做出正确的选择,然后传播这些信息。企业架构师仍然需要形成愿景,然后需要在团队之间建立桥梁,以构建学习社区。这将允许团队与企业架构师作为合作伙伴,在发展中探索新方法并相互学习。
凯文·希基
2015.11.30

产品超越项目

软件项目是一种流行的资助和组织软件开发的方式。他们将工作组织成临时的、只负责构建的团队,并由业务案例中预计的特定收益提供资金。产品模式使用持久的,由构思-构建-运行的团队来解决持续存在的业务问题。产品模式使团队能够快速重新定位,减少端到端的周期时间,并允许通过使用短周期迭代来验证实际收益,同时保持软件体系结构的完整性,以保持其长期有效性。
斯里拉姆·纳拉扬(Sriram Narayan)
2018.2.20

建筑师电梯-参观高层

许多大型组织都将其 IT 引擎与行政顶层公寓分隔开许多层,这也将业务和数字战略与执行它的重要工作区分开来。 架构师的主要作用是乘坐顶层公寓和机房之间的电梯,在任何需要的地方停下来支持这些数字工作:自动化软件制造、最小化前期决策并在技术发展的同时影响组织。
格雷戈尔·霍佩(Gregor Hohpe)
2017.5.24

使用 REST 进行企业集成

大多数内部 EST API 是为单个集成点构建的一次性API。在本文中,我将讨论非公共 API 所具有的约束和灵活性,以及在多个团队之间进行大规模 RESTful 集成的经验教训。
布兰登·拜尔斯(Brandon Byars)
2013.11.18

S.O.L.I.D: 面向对象设计的前五项原则

【注】本文节译自:https://www.digitalocean.com/community/conceptual_articles/s-o-l-i-d-the-first-five-principles-of-object-oriented-design#toc-single-responsibility-principle

  S.O.L.I.D 是 Robert C. Martin(俗称 Bob 叔叔)的前五个面向对象设计(OOD)**原则的缩写。

  将这些原则结合在一起,可使程序员轻松地开发易于维护和扩展的软件。它们还可以使开发人员轻松避免代码异味,很容易重构代码,并且还是敏捷或自适应软件开发的一部分。

S.O.L.I.D 代表:

  • S – Single-responsiblity principle(单一责任原则)
  • O – Open-closed principle(开-闭原则)
  • L – Liskov substitution principle(里斯科夫替代原则)
  • I – Interface segregation principle(接口隔离原则)
  • D – Dependency Inversion Principle(依赖倒置原则)

  让我们逐一查看每个原则,以了解为什么 S.O.L.I.D 可以帮助我们成为更好的开发人员。

单一责任原则

  简称 S.R.P — 此原则指出:

一个类应该有且只有一个改变理由,这意味着类应该只有一种职责。

  例如,假设我们有一些形状,我们想对形状的所有面积求和。好吧,这很简单吧?

class Circle {
    public $radius;

    public function construct($radius) {
        $this->radius = $radius;
    }
}

class Square {
    public $length;

    public function construct($length) {
        $this->length = $length;
    }
}

  首先,我们创建形状类,并让构造函数设置所需的参数。 接下来,我们继续创建 AreaCalculator 类,然后编写逻辑来对所提供的所有形状的面积求和。

class AreaCalculator {

    protected $shapes;

    public function __construct($shapes = array()) {
        $this->shapes = $shapes;
    }

    public function sum() {
        // logic to sum the areas
    }

    public function output() {
        return implode('', array(
            "",
                "Sum of the areas of provided shapes: ",
                $this->sum(),
            ""
        ));
    }
}

  要使用 AreaCalculator 类,我们只需实例化该类并传递一个形状数组,然后在页面底部显示输出。

$shapes = array(
    new Circle(2),
    new Square(5),
    new Square(6)
);

$areas = new AreaCalculator($shapes);

echo $areas->output();

  输出方法的问题在于 AreaCalculator 处理逻辑以输出数据。因此,如果用户希望将数据输出为 json 或其他内容怎么办?
  所有这些逻辑将由 AreaCalculator 类处理,这是 SRP 反对的。 AreaCalculator 类应仅对提供的形状的面积求和,而不管用户是否需要 json 或HTML 。
  因此,要解决此问题,您可以创建一个 SumCalculatorOutputter 类,并使用该类来处理处理所有提供的形状的总面积如何显示所需的任何逻辑。
  SumCalculatorOutputter 类是这样工作的:

$shapes = array(
    new Circle(2),
    new Square(5),
    new Square(6)
);

$areas = new AreaCalculator($shapes);
$output = new SumCalculatorOutputter($areas);

echo $output->JSON();
echo $output->HAML();
echo $output->HTML();
echo $output->JADE();

  现在,SumCalculatorOutputter 类现在可以处理将数据输出到用户所需的任何逻辑。

开-闭原则

  对象或实体应该对扩展开放,但对修改关闭。
  这只是意味着一个类应该易于扩展,而无需修改类本身。让我们看一下 AreaCalculator 类,尤其是 sum 方法。

public function sum() {
    foreach($this->shapes as $shape) {
        if(is_a($shape, 'Square')) {
            $area[] = pow($shape->length, 2);
        } else if(is_a($shape, 'Circle')) {
            $area[] = pi() * pow($shape->radius, 2);
        }
    }

    return array_sum($area);
}

  如果我们希望 sum 方法能够对更多形状的区域求和,则必须添加更多 if / else 块,这违背了Open-closed原理。
  我们可以使这种 sum 方法更好的一种方法是从 sum 方法中删除用于计算每个形状的面积的逻辑,并将其附加到形状的类中。

class Square {
    public $length;

    public function __construct($length) {
        $this->length = $length;
    }

    public function area() {
        return pow($this->length, 2);
    }
}

  对 Circle 类应该做同样的事情,应该添加一个 area 方法。 现在,要计算提供的任何形状的总和应该很简单:

public function sum() {
    foreach($this->shapes as $shape) {
        if(is_a($shape, 'Square')) {
            $area[] = pow($shape->length, 2);
        } else if(is_a($shape, 'Circle')) {
            $area[] = pi() * pow($shape->radius, 2);
        }
    }

    return array_sum($area);
}

  现在,我们可以创建另一个形状(shap)类,并在计算总和时传入它,而不会破坏我们的代码。但是,现在又出现了另一个问题,我们如何知道传递到 AreaCalculator 中的对象实际上是一个形状,或者该形状是否具有名为 area 的方法?
  基于接口的编程是 S.O.L.I.D 不可或缺的一部分,一个简单的例子是我们创建一个接口,每种形状都可以实现:

interface ShapeInterface {
    public function area();
}

class Circle implements ShapeInterface {
    public $radius;

    public function __construct($radius) {
        $this->radius = $radius;
    }

    public function area() {
        return pi() * pow($this->radius, 2);
    }
}

  在我们的 AreaCalculator sum 方法中,我们可以检查所提供的形状是否实际上是 ShapeInterface 的实例,否则我们抛出异常:

public function sum() {
    foreach($this->shapes as $shape) {
        if(is_a($shape, 'ShapeInterface')) {
            $area[] = $shape->area();
            continue;
        }

        throw new AreaCalculatorInvalidShapeException;
    }

    return array_sum($area);
}

里斯科夫替代原则

设 q(x) 是类型 T 的对象 x 可证明的属性,那么 q(y) 应该是类型 S 的对象 y 的可证明属性,其中 S 是 T 的子类型。

  所有这一切都说明,每个子类/派生类都可以替代其基类/父类。
  仍然利用 AreaCalculator 类,我们有一个 VolumeCalculator 类扩展了 AreaCalculator 类:

class VolumeCalculator extends AreaCalulator {
    public function construct($shapes = array()) {
        parent::construct($shapes);
    }

    public function sum() {
        // logic to calculate the volumes and then return and array of output
        return array($summedData);
    }
}

  在 SumCalculatorOutputter 类中:

class SumCalculatorOutputter {
    protected $calculator;

    public function __constructor(AreaCalculator $calculator) {
        $this->calculator = $calculator;
    }

    public function JSON() {
        $data = array(
            'sum' => $this->calculator->sum();
        );

        return json_encode($data);
    }

    public function HTML() {
        return implode('', array(
            '',
                'Sum of the areas of provided shapes: ',
                $this->calculator->sum(),
            ''
        ));
    }
}

  如果我们尝试运行这样的示例:

$areas = new AreaCalculator($shapes);
$volumes = new VolumeCalculator($solidShapes);

$output = new SumCalculatorOutputter($areas);
$output2 = new SumCalculatorOutputter($volumes);

  该程序不会应答,但是当我们在 $output2 对象上调用 HTML 方法时,会收到 E_NOTICE 错误,通知我们将数组转换为字符串。
  要解决此问题,不是从 VolumeCalculator 类的 sum 方法返回数组,你应该简单地:

public function sum() {
// logic to calculate the volumes and then return and array of output
return $summedData;
}

  求和后的数据为浮点,双精度或整数。

接口隔离原则

绝不应该强迫客户端实现不使用的接口,也不应该强迫客户端依赖不使用的方法。

  仍然使用形状示例,我们知道我们也有实体形状,因此由于我们还想计算形状的体积,因此可以向 ShapeInterface 添加另一个契约:

interface ShapeInterface {
    public function area();
    public function volume();
}

  我们创建的任何形状都必须实现 volume 方法,但是我们知道正方形是扁平形状并且它们没有体积,因此此接口将强制 Square 类实现一种不使用的方法。
  ISP 对此表示拒绝,相反,您可以创建另一个名为 SolidShapeInterface 的接口,该接口具有 volume 契约,那么诸如立方体这样在实体形状可以实现此接口:

interface ShapeInterface {
    public function area();
}

interface SolidShapeInterface {
    public function volume();
}

class Cuboid implements ShapeInterface, SolidShapeInterface {
    public function area() {
        // calculate the surface area of the cuboid
    }

    public function volume() {
        // calculate the volume of the cuboid
    }
}

  这是一种更好的方法,但是要注意在使用 ShapeInterfaceSolidShapeInterface 类型提示时的会出现的一个陷阱。
  你可以创建另一个接口(可能是 ManageShapeInterface),并在平面和实体形状上都实现它,这样您就可以轻松地看到它具有一个用于管理形状的 API。例如:

interface ManageShapeInterface {
    public function calculate();
}

class Square implements ShapeInterface, ManageShapeInterface {
    public function area() { /Do stuff here/ }

    public function calculate() {
        return $this->area();
    }
}

class Cuboid implements ShapeInterface, SolidShapeInterface, ManageShapeInterface {
    public function area() { /Do stuff here/ }
    public function volume() { /Do stuff here/ }

    public function calculate() {
        return $this->area() + $this->volume();
    }
}

  现在在 AreaCalculator 类中,我们可以轻松地用 calculate 替换对 area 方法的调用,还可以检查对象是否是 ManageShapeInterface 的实例,而不是 ShapeInterface 的实例。

依赖倒置原则

  最后,但并非最不重要的一点是:

实体必须依赖抽象而不依赖具体。它指出高级模块一定不能依赖于低级模块,而应该依赖于抽象。
  这听起来可能很夸张,但确实很容易理解。该原理允许去耦,这个例子似乎是解释该原理的最佳方法:


class PasswordReminder {
private $dbConnection;
public function __construct(MySQLConnection $dbConnection) {
    $this->dbConnection = $dbConnection;
}

}

  首先,**MySQLConnection** 是低级别的模块,而PasswordReminder是高级别的模块,但是根据 S.O.L.I.D 中 **D** 的定义。声明依赖于抽象而不依赖于具体内容,上面的此代码段违反了该原理,因为 **PasswordReminder** 类被强制依赖于 **MySQLConnection** 类。
  以后,如果您要更改数据库引擎,则还必须编辑 **PasswordReminder** 类,从而违反了**开-闭原则**。
  **PasswordReminder** 类不必关心你的应用程序使用什么数据库,为解决此问题,我们再次“为接口编码”,因为高级和低级模块应依赖抽象,因此我们可以创建接口:
```php
interface DBConnectionInterface {
    public function connect();
}

  该接口具有一个 connect 方法,而 MySQLConnection 类实现了此接口,并且也没有直接在 PasswordReminder 的构造函数中直接提示 MySQLConnection 类,而是改为提示该接口,无论您的应用程序使用哪种数据库类型,PasswordReminder 类可以轻松连接到数据库而不会出现任何问题,并且不会违反 OCP

class MySQLConnection implements DBConnectionInterface {
    public function connect() {
        return "Database connection";
    }
}

class PasswordReminder {
    private $dbConnection;

    public function __construct(DBConnectionInterface $dbConnection) {
        $this->dbConnection = $dbConnection;
    }
}

  根据上面的小片段,您现在可以看到高级模块和低级模块都依赖于抽象。

结论

  S.O.L.I.D 乍看起来似乎有点太抽象了,但是随着 S.O.L.I.D 原则在现实世界的每一次应用中,遵守其准则的好处将变得更加明显。遵循 S.O.L.I.D. 原则的代码可以更轻松地与协作者共享、扩展、修改、测试和重构,而不会出现任何问题。

Spring 依赖注入最佳实践

【注】本文译自:https://springframework.guru/best-practices-for-dependency-injection-with-spring/

  在本文中,我将向你展示如何在 Spring Framework 的依赖项注入中使用 Project Lombok 以获得最佳实践。
  Spring 框架本身具有多种执行依赖项注入的方式。选项的灵活性是 Spring 框架的优势。但是,并非所有的依赖项注入选项都被视为最佳实践。有些实际上不太好。

依赖注入示例

  我提供了一些设置示例,供我们查看必须使用的各种依赖项注入选项。
  让我们以 Spring Service 为例。就我们的目的而言,该服务具有一种返回字符串的方法。我们将使用“service”,并使用 Spring将其注入一些模拟控制器中。请记住,我们只是在探索如何使用 Spring Framework 进行依赖项注入。

示例 Service

public class MyService {
    public String getHello(){
        return "Hello";
    }
}

  我们的 Field 拥有一项公有属性的服务。我们可以注解该字段,Spring 将注入该服务的实例。

属性注入

Field Controller

@Controller
public class FieldController {
    @Autowired
    MyService myService;
    public String saySomething(){
        return myService.getHello();
    }
}

  这只是一个公有属性,没有 setter。显然,这不是一个好的实践,不推荐这样做。
  我们可以对此进行一些改进,将该字段的访问权限设为私有。Spring Framework 确实允许你自动装配私有字段。你确实看到有人这样做。Spring 将执行一些反射魔术来执行依赖项注入

私有 Field Controller

public class PrivateFieldController {
    @Autowired
    private MyService myService;
    public String saySomething(){
        return myService.getHello();
    }
}

  尽管只使用私有字段比较好,但是测试却成了一个令人头痛。你要么需要启动 Spring Context,要么使用一些 Spring 实用程序来执行依赖注入以进行测试。不是世界末日,但总的来说很烦人。
  我们可以通过为私有属性提供 setter 来改善这一点。Getter 和 Setter 通常被认为是面向对象编程中的最佳实践。通过注解 setter 方法,指示 Spring 使用 setter 进行依赖项注入很简单。

方法注入

Setter Controller

@Controller
public class SetterController {
    private MyService myService;
    @Autowired
    public void setMyService(MyService myService) {
        this.myService = myService;
    }
    public String saySomething(){
        return myService.getHello();
    }
}

  这是使用私有字段时的明显改进。有人会抱怨这要写太多代码。但是实际上,自 South Park 的第一季以来,此类任务已在现代 IDE 中实现了自动化。

构造函数注入

  下一个选项是使用构造函数。到目前为止,这是我们研究过的最佳方法。 使用构造函数设置注入的属性时,不必提供自动装配注释。这是一个很好的功能,可以节省一些键入时间。从 Spring Framework 版本4.2开始,用于依赖项注入的构造函数的注释是可选的。

Constructor Controller

@Controller
public class ConstructorController {
    private MyService myService;
    public ConstructorController(MyService myService) {
        this.myService = myService;
    }
    public String saySomething(){
        return myService.getHello();
    }
}

  基于构造函数的依赖注入无疑被认为是最佳实践。曾经有一段时间我个人偏爱基于 setter 的注入,但是后来又转向基于构造函数的注入。
  我们仍然可以改善我们的示例。现在有两个主要问题。 第一,我们的服务类型是具体类型。硬类型的依赖注入不是最佳实践。
  第二个问题是,我们要注入的属性未声明为final。因此,从理论上讲,该类可以在实例化注入的属性后对其进行修改。依# 赖注入最佳实践
  依赖项注入的最佳实践是利用接口,构造函数和 final 属性。
  我已经设置了“最佳实践”服务接口,并提供了服务实现—使用了 Spring Service 注解。

最佳实践服务接口

public interface BpService {
    String getHello();
}

最佳实践服务实现

@Service
public class BpServiceImpl implements BpService {
    @Override
    public String getHello() {
        return "The Best Hello!";
    }
}

使用 Project Lombok

  现在,使用 Project Lombok 进行依赖注入的最佳实践的秘诀在于:

  • 声明一个 final 属性接口
  • 为类添加 Project Lomboc 注解 @RequiredArgsConstructor

  现在,Project Lombok 将为声明为 final 的所有属性生成一个构造函数。Spring 会自动使用 Lombok 提供的构造函数来自动装配该片段。

Lombok Controller

@RequiredArgsConstructor
@Controller
public class BpFinalConstructorController {
    private final BpService bpService;
    public String saySomething(){
        return bpService.getHello();
    }
}

  这是执行此操作的真正好方法。您的代码保持非常干净。使用 Spring时,通常需要多个自动装配属性。
  当您需要添加另一个 bean 时,只需声明一个 final 属性。
  如果您重构并且不再需要 Spring 托管的依赖项,则只需删除 final 属性。
  你不再需要维护设置器或构造函数代码。Project Lombok 减轻了您的日常工作。
  我在日常编码中一直使用这种技术。绝对是节省时间。并导致更干净的代码。未使用的属性和未使用的构造函数参数已一去不复返了。重构现在不那么痛苦了!
  本文的源代码可在 GitHub 上找到。