速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

以 Chef 和 Ansible 为例快速入门服务器配置

  • 2018-10-13
  • 本文字数:5339 字

    阅读完需:约 18 分钟

这篇文章讨论了如何在我们的环境中安装和配置软件,这个任务通常被称为服务器配置(Server Provisioning)。

服务器配置

在开始介绍现代化的工具之前,我们来看看最基本且经过实战考验的服务器配置工具:shell 脚本。在 Chef、Ansible 或 Puppet 出现之前,很多运营团队使用 Bash 来配置服务器(在 Windows 上则使用 PowerShell 脚本)。

例如,如果想在运行 Ubuntu 的 Amazon EC2 实例上安装 Nginx,可以使用以下脚本(install-nginx.sh):

复制代码
#!/bin/sh
ssh -t ubuntu@$1 sudo apt-get upgrade
ssh -t ubuntu@$1 sudo apt-get -y install nginx

我们可以使用 shell 脚本来配置服务器上的所有东西。据我所知,所有主流的配置工具都使用了基于安全传输层(如 SSH)的 shell 命令或 PowerShell(Chef 可能是个例外)。即使你使用了配置工具,在某些时候也需要用到脚本。因此,当你开始使用配置工具(如 Chef 或 Ansible)时,学习如何使用基本的 shell 脚本也会为你带来很多好处。

你可能会问自己,为什么在 shell 脚本已经可以完成所有工作的同时还要学习配置工具?很多环境已经使用 shell 脚本进行服务器配置,那么为什么要使用配置工具代替它们?

首先,shell 脚本通常使用的是声明性语法。shell 脚本通过运行命令序列来安装软件,而配置工具只需要指定服务器应该安装哪些软件,这样就可以使用相同的代码在不同的操作系统上、使用不同的包管理器以及指定不同的版本来安装和配置相同的软件。

其次,配置工具通常会提供用于组织基础设施的方式。虽然使用 shell 脚本也可以做到这一点,但配置工具通常会提供更简洁明了的方案。因为是行业标准,开发人员可以更轻松地找出 QA 环境中哪些服务器运行 RabbitMQ。

第三,每个主要的配置工具都有一个蓬勃发展的社区,他们构建可复用的模块来安装大多数开源软件。你可以直接在模块配置中指定内存限制,而不需要记住 Postgres 配置文件在哪里,这样可以节省很多时间。

当然,原因还有很多,这里就不一一例举了。尽管学习曲线有点陡峭,但学习配置工具仍然是值得的。与 shell 脚本相比,配置工具更容易使用,便于思考,也更容易维护

关于命名

学习使用 Chef(服务器配置工具)的前几周给我留下了深刻的印象。入门指南展示了如何创建一个“recipe”,其中包含安装或配置软件的说明,我能够理解这种比喻背后的含义。recipe 必须存在于“cookbook”中,这是有道理的。然后你在“kitchen”里测试 cookbook,但我开始有点怀疑了。

这种比喻有点令人感到困惑,于是我决定去看一下其他工具,如 Ansible。Ansible 文档的第一页介绍了“playbook”的概念,而 playbook 包含一系列“play”。

那么,这些问题很重要吗?当然很重要了,因为在学习配置工具之前,你应该知道,它们很有可能会引入大量令人费解的术语。即使是为了完成基本的任务,你也必须重新学习很多术语。如果你是刚开始学习配置工具,我强烈建议你随时写下这些术语定义,你还有很多东西要学。

每个软件开发人员都会为现有的单词创建不同的含义,他们甚至还会发明一些单词,比如“uninitialize”和“unregister”。这已经成为软件开发的一部分。

我会尽量用大家熟悉的术语来解释这些工具。

配置管理

你决定使用花哨的配置工具在远程服务器上安装 Nginx。在开始设置数据库备份节点前,一切都很顺利。你已经编写了 MySQL 主服务器的配置文件,但是你不太确定如何配置 MySQL 从服务器的内部 DNS 地址。这个时候配置管理就派上用场了。

在设置服务器时,最好可以将应用程序视为由两部分组成:不可变部分(通常是代码或编译的二进制文件)和可变部分(通常是配置文件或环境变量)。大部分由社区创建的模块默认情况下会安装二进制文件,并提供尽可能合理的配置,而且会为我们暴露出一些属性,方便对其进行覆盖。

这些属性通常包含特定于用户环境的值。大多数配置工具都为用户提供了一种机制,通过模板将特定于环境的值插入到配置文件中,或直接插入到环境变量中。

你可以使用配置工具提供的配置管理来配置 MySQL 主服务器的配置文件,然后在其中配置从服务器。

Secret 管理

这样就可以解决上述的问题,但后来发现,你必须上传 AWS 凭证才能让 MySQL 从服务器访问 S3。你知道不能直接将这些凭证提交到代码库中,因此这些凭证只能存在于你的机器和 NSA 服务器上。

这个时候你需要的是 Secret 管理。

与自动化领域的所有东西一样,你也有很多管理秘钥的可选项。谷歌提供了一项名为 KMS 的服务,AWS 也提供了一项名为 Secret Manager 的服务,Chef 提供了加密数据包,Hashicorp 提供了一款名为 Vault 的产品,Ansible 也有一款名为 Vault 的产品。除了 KMS 会对字符串进行加密之外,所有这些工具都提供了相同的功能:保护对加密秘钥的访问(这些秘钥被用在配置管理中)。

有好几次,我不小心将秘钥提交到了代码库。这类事情一直在发生,而且非常危险。

切勿以明文形式存储 API 密钥或凭证

可以使用 Secret 管理解决方案来存储这些数据,然后将其绑定到配置工具中

一个简单的例子:Chef

首先需要安装 Chef Development Kit(ChefDK)。

如前所述,我们需要一个 recipe 来安装 Nginx。出于教学的目的,我们将从头开始创建它,而不是从社区的 cookbook 中捞一个出来。

我们需要创建一个 cookbook。cookbook 通常存在于cookbooks目录中,在项目的根目录运行以下命令:

复制代码
mkdir cookbooks

现在让我们创建一个 cookbook,用于放置我们的新 recipe:

复制代码
chef generate cookbook cookbooks/application

这个命令在cookbooks/application目录中创建了很多文件,我们关心的是cookbooks/application/recipes/default.rb这个文件。这个文件包含了默认的 recipe,我们将安装 Nginx 的命令放到这个文件中。

复制代码
apt_update
package 'nginx'
cookbook_file '/var/www/html/index.html' do
source 'index.html'
owner 'www-data'
group 'www-data'
mode '0755'
action :create
end

这个文件中的前两个命令将执行你期望的操作:

  • apt\_update更新你的 aptitude 包。
  • package ‘nginx’使用操作系统默认包管理器安装nginx包(在这个示例中,它使用的是 aptitude)。

最后一个命令将cookbooks/application/files/index.html拷贝成远程服务器上的/var/www/html/index.html,并设置文件的权限,让 Nginx 服务器可以访问它。

这个文件还不存在,所以需要创建它。首先要创建文件目录:

复制代码
mkdir cookbooks/application/files

然后创建文件cookbooks/application/files/index.html,其中包含以下内容:

复制代码
<html lang="en-us">
<head>
<title>Hello, World!</title>
</head>
<body>
Chef has landed.
</body>
</html>

更新packer.json,加入 Chef 相关配置:

复制代码
{
"builders": [{
"type": "amazon-ebs",
"region": "us-east-1",
"source_ami": "ami-04169656fea786776",
"instance_type": "t2.small",
"ssh_username": "ubuntu",
"ami_name": "Ubuntu 16.04 Nginx - {{timestamp}}",
"tags": {
"Image": "application"
}
}],
"provisioners": [{
"type": "chef-solo",
"cookbook_paths": ["cookbooks"],
"run_list": ["recipe[application]"]
}]
}

我们对之前的packer.json进行了两处更改。

首先,我们为 AMI 添加了一个Image标签。我们之前从 Packer 的输出中复制 AMI ID,并粘贴到 Terraform 代码中。这不是一个可维护的解决方案,因为 AMI ID 会经常发生变化,而且我们不应该在每次发生变化时都要将更改推送到存储库中。相反,我们使用 Terraform 的data资源来动态读取 AMI ID(使用Image=application查询最新的 AMI)。

其次,我们使用chef-solo替换了shell。我们告诉它在哪里可以找到 cookbooks 目录,以及要运行哪个 recipe。默认情况下,run\_list中的recipe\[COOKBOOK\]条目将执行recipes/default.rb。我们也可以显式指定 explicity:recipe \[COOKBOOK::RECIPE\]来覆盖默认行为。由于我们的 recipe 保存在recipes/default.rb中,所以将使用默认行为。

现在开始构建我们的 AMI:

复制代码
packer build packer.json

我们的新 AMI 有一个Image标签,现在修改terraform.tf中硬编码的 AMI,让它通过标签来查找 AMI。

将以下内容添加到terraform.tf中:

复制代码
data "aws_ami" "web" {
most_recent = true
owners = ["self"]
filter {
name = "tag:Image"
values = ["application"]
}
}

现在使用aws\_ami.web resource输出的 ID 替换aws\_instance.web1aws\_instance.web2resource 中的 AMI ID:

复制代码
resource "aws_instance" "web1" {
ami = "${data.aws_ami.web.id}"
availability_zone = "us-east-1a"
instance_type = "t2.small"
vpc_security_group_ids = ["${aws_security_group.application.id}"]
subnet_id = "${aws_subnet.private1.id}"
}
resource "aws_instance" "web2" {
ami = "${data.aws_ami.web.id}"
availability_zone = "us-east-1b"
instance_type = "t2.small"
vpc_security_group_ids = ["${aws_security_group.application.id}"]
subnet_id = "${aws_subnet.private2.id}"
}

运行下面的命令创建 Chef 配置的服务器,然后启动浏览器,打开地址为负载均衡器的域名:

复制代码
terraform plan -out terraform.plan
terraform apply "terraform.plan"
open "http://$(terraform output dns)"

你应该能够在打开的浏览器页面上看到:Chef has landed!

一个简单的例子:Ansible

让我们使用 Ansible 来构建这个相同的示例。首先需要安装Ansible

Ansible 将安装和配置说明组织到tasks中,然后将tasks组织到playbook中。让我们为 playbook 创建一个目录结构。

复制代码
mkdir playbook
mkdir playbook/files

这并不是组织 Ansible playbook 的最佳实践。因为我们的用例很简单,所以使用了简化版本。如果你对 Ansible 感兴趣,应该根据官方提供的建议来构建playbook

playbook/application.yml中创建 playbook,内容如下:

复制代码
---
- hosts: all
gather_facts: False
become: yes
pre_tasks:
- name: Install Python 2.7
raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal)
- hosts: applications
become: yes
tasks:
- name: Install Nginx
apt:
name: nginx
state: present
update_cache: yes
- name: Update contents of index.html
copy:
src: index.html
dest: /var/www/html/index.html
owner: www-data
group: www-data
mode: 0755

这个 playbook 文件包含配置我们的服务器所需的所有信息。现在让我们来讨论一下它的结构。

每个 playbook 包含一个“play”列表,每个 play 包含一个“tasks”列表,task 用于安装和配置软件。我们的 playbook 包含两个 play。第一个 play 在 Ubuntu 上安装 Python 2.7(用于运行 Ansible)。第二个 play 安装和配置 Nginx。

我们在每个 play 的根节点配置了两个参数:hostsbecomehosts参数告诉 Ansible 应该在哪台机器上运行 playbook(“all”表示在所有机器上运行)。become:yes表示 Ansible 将通过 sudo 运行所有命令,否则将会出现很多权限错误。

play 的第一个 task 负责安装和配置 Nginx,它将更新 aptitude 缓存,并确保nginx包存在。如果已经安装了nginx包,这个命令将不执行任何操作。

第二个 task 将files/index.html拷贝到远程服务器上,并为其分配正确的权限。

这个文件还不存在,所以让我们创建它。将以下内容加入到playbook/files/index.html中:

复制代码
<html lang="en-us">
<head>
<title>Hello, World!</title>
</head>
<body>
Ansible has landed.
</body>
</html>

这就是我们配置 Ansible 所需的全部内容。现在让 Packer 使用这个配置。使用以下内容更新packer.json

复制代码
{
"builders": [{
"type": "amazon-ebs",
"region": "us-east-1",
"source_ami": "ami-04169656fea786776",
"instance_type": "t2.small",
"ssh_username": "ubuntu",
"ami_name": "Ubuntu 16.04 Nginx - {{timestamp}}",
"tags": {
"Image": "application"
}
}],
"provisioners": [{
"type": "ansible",
"playbook_file": "./playbook/application.yml",
"host_alias": "applications"
}]
}

我们只修改了使用 Ansible 作为配置器,需要提供一个指向 playbook 文件的路径,我们将其设置为./playbook/application.yml。我们可以看到用于安装 Nginx 的 play 顶部有一行:hosts: applications。这是我们用来告诉 Ansible 需要安装应用程序的主机别名。我们需要告诉 Packer 我们正在为其中一个主机构建映像,所以我们将host\_alias属性设置为applications

运行下面的命令来创建 Ansible 配置的服务器,然后启动浏览器,打开地址为负载均衡器的域名:

复制代码
packer build packer.json
terraform plan -out terraform.plan
terraform apply "terraform.plan"
open "http://$(terraform output dns)"

你应该可以在打开的浏览器页面上看到:Ansible has landed!

英文原文: http://stephenmann.io/post/a-brief-introduction-to-provisioning/

感谢张婵对本文的审校。

2018-10-13 06:372455
用户头像

发布了 731 篇内容, 共 451.6 次阅读, 收获喜欢 2002 次。

关注

评论 1 条评论

发布
暂无评论
发现更多内容

一个简单的产品分析模型

石云升

产品经理 产品思维 9月日更 产品分析

2021年Java面试心得,整理出这份8万字Java性能优化实战解析

Java 面试 后端

2021年互联网大厂Java笔经,Java程序员如何有效提升学习效率

Java 面试 后端

2021年互联网大厂Java笔经,Java自学宝典电子书下载

Java 面试 后端

2021年抓住金三银四涨薪好时机,腾讯Java社招面试流程

Java 面试 后端

2021年Java者未来的出路在哪里,Java开发校招面试题

Java 面试 后端

2021年Java者未来的出路在哪里,让人抓狂的Nginx性能调优

Java 面试 后端

2021年大厂Java高级面试题分享,程序员Java基础入门

Java 面试 后端

2021年抓住金三银四涨薪好时机,借花献佛

Java 面试 后端

代码检查规则背景及总体介绍

百度开发者中心

最佳实践 代码规则

【等保知识】十个等保常见问题解答汇总

行云管家

网络安全 信息安全 等级保护 过等保 数据审计

设计 | ClickHouse 分布式表实现数据同步

RadonDB

数据库 Clickhouse

2021年哔哩哔哩Java高级面试题及答案,Java实战视频下载

Java 面试 后端

2021年哔哩哔哩Java高级面试题及答案,大牛手把手教你

Java 面试 后端

2021年Java面经分享,别再说你不会JVM性能监控和调优了

Java 面试 后端

IT运维和自动化运维以及运维开发有啥不同?能解释下吗?

行云管家

互联网 运维 IT运维 自动化运维 云运维

2021年互联网大厂Java笔经,Java重点知识大全

Java 面试 后端

2021年Java面经分享,程序员必备技能:时间复杂度与空间复杂度的计算

Java 面试 后端

阿里巴巴首发:Java核心框架指导手册,1小时点击量破千万!

Java 程序员 架构 面试 计算机

2021年冲刺年薪40w,Java从基础到高级知识点汇总

Java 面试 后端

如何画UML,几种简单的模型分析

编程 架构 面试 后端

2021年一起努力应对互联网寒冬吧,Java程序员面试笔试宝典答案

Java 面试 后端

2021年一起努力应对互联网寒冬吧,字节跳动Java高级工程师

Java 面试 后端

2021年你与字节跳动只差这份笔记,大神码了2000页Spring全家桶笔记

Java 面试 后端

2021年字节跳动、阿里等大厂最全Java面试题,1个月学会Java开发

Java 面试 后端

谁是中国最受赞赏的创投机构?

创业邦

Android音频架构| 社区征文

轻口味

android 音视频 新春征文

2021年京东Java岗面试必问,我在华为做Java外包的真实经历

Java 面试 后端

2021年Java高级面试题总结,2021最新大厂高频微服务面试总结

Java 面试 后端

2021年华为Java面试真题解析,大厂面试必问

Java 面试 后端

好看视频Android重构——围绕于播放器的重构实践

百度Geek说

性能优化 大前端 好看视频 播放器

以Chef和Ansible为例快速入门服务器配置_DevOps & 平台工程_Stephen Mann_InfoQ精选文章