以Chef和Ansible为例快速入门服务器配置
Posted 架构头条
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了以Chef和Ansible为例快速入门服务器配置相关的知识,希望对你有一定的参考价值。
在开始介绍现代化的工具之前,我们来看看最基本且经过实战考验的服务器配置工具: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”。这已经成为软件开发的一部分。
我会尽量用大家熟悉的术语来解释这些工具。
在设置服务器时,最好可以将应用程序视为由两部分组成:不可变部分(通常是代码或编译的二进制文件)和可变部分(通常是配置文件或环境变量)。大部分由社区创建的模块默认情况下会安装二进制文件,并提供尽可能合理的配置,而且会为我们暴露出一些属性,方便对其进行覆盖。
这些属性通常包含特定于用户环境的值。大多数配置工具都为用户提供了一种机制,通过模板将特定于环境的值插入到配置文件中,或直接插入到环境变量中。
你可以使用配置工具提供的配置管理来配置 mysql 主服务器的配置文件,然后在其中配置从服务器。
这样就可以解决上述的问题,但后来发现,你必须上传 AWS 凭证才能让 MySQL 从服务器访问 S3。你知道不能直接将这些凭证提交到代码库中,因此这些凭证只能存在于你的机器和 NSA 服务器上。
这个时候你需要的是 Secret 管理。
与自动化领域的所有东西一样,你也有很多管理秘钥的可选项。谷歌提供了一项名为 KMS 的服务,AWS 也提供了一项名为 Secret Manager 的服务,Chef 提供了加密数据包,Hashicorp 提供了一款名为 Vault 的产品,Ansible 也有一款名为 Vault 的产品。除了 KMS 会对字符串进行加密之外,所有这些工具都提供了相同的功能:保护对加密秘钥的访问(这些秘钥被用在配置管理中)。
有好几次,我不小心将秘钥提交到了代码库。这类事情一直在发生,而且非常危险。
切勿以明文形式存储 API 密钥或凭证。
可以使用 Secret 管理解决方案来存储这些数据,然后将其绑定到配置工具中。
首先需要安装 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.web1
和aws_instance.web2
resource 中的 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}"
}
terraform plan -out terraform.plan
terraform apply "terraform.plan"
open "http://$(terraform output dns)"
你应该能够在打开的浏览器页面上看到:Chef has landed!
让我们使用 Ansible 来构建这个相同的示例。首先需要安装 Ansible(https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html#installing-the-control-machine)。
Ansible 将安装和配置说明组织到tasks
中,然后将tasks
组织到playbook
中。让我们为 playbook 创建一个目录结构。
mkdir playbook
mkdir playbook/files
这并不是组织 Ansible playbook 的最佳实践。因为我们的用例很简单,所以使用了简化版本。如果你对 Ansible 感兴趣,应该根据官方提供的建议来构建 playbook(https://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html)。
在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 的根节点配置了两个参数:hosts
和become
。hosts
参数告诉 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
。
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/
活动推荐
AIOps 是发展的必然趋势?在 AI 的学习上要做哪些储备?落地 AIOps 到底有哪些门槛?如何使用知识图谱定位故障?AIOps 时代,人才结构和团队结构应该如何升级?运维如何助力产品运营?
InfoQ 主办的第四届 CNUTCon 全球运维技术大会,邀请了 Twitter、RIOT Games、BAT、华为等国内外一线大厂,全方位、多角度向参会者阐述智能运维时代的新技术、新思想、新实践。
以上是关于以Chef和Ansible为例快速入门服务器配置的主要内容,如果未能解决你的问题,请参考以下文章