如何使用AWS和Rancher搭建弹性应用栈

简介:

我们曾经分享过在使用Docker、Rancher和各种开源工具时,如何确保高弹性工作负载。在这篇文章中,我将以先前内容为基础,用一些常用工具为Rancher搭好一个AWS基础环境。查看这里的仓库,你就能跟随我们的步骤、安装一个完全相同的基础设施。


我们AWS基础设施最终的输出看起来会像下面的图片:


wKioL1jROM3j8OMHAACLSTc4gMc929.jpg


现在一起动手来创建一个运行的应用栈吧!


Host VM的创建


在这一部分我们将搭建下图中底部的三个黄色部分的内容:


wKiom1jROQLzL6ZBAAEXl2VxZtI124.png

 

Golden 镜像


首先,我们需要一个创建Docker hosts的方案,该方案会将存储驱动和操作系统组合起来。当然,我们也希望将来能用不同的部分取代它们。


现在我们要建立自己的VM(它常被叫做“golden镜像”)。至于工具,我会用Packer与AWS(以及其他各类云提供商)的API通信来创建VM镜像,用Ansible以一种可读的方式描述配置步骤。如果你想跳过这些步骤的话,你可以在这里找到完整的源代码。


此次的示例我们将使用一个Ubuntu 14.04的VM,该VM使用AUFS3作为Docker存储驱动。


第一步,我们创建一个名为ubuntu_1404_aufs3.json的Packer配置文件。在这时,用source_ami_filter在AWS美国东部地区搜索最近的14.04 AMI ID,从搜索清单中返回了ami-af22d9b9。


它还创建了一个40GB的硬盘,该硬盘连接为/dev/sdb,我们将用它存储Docker数据;这里我们正在使用的是Docker 1.12.3,因为它支持最新的Rancher兼容性矩阵。

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
{
"variables" : {
"aws_access_key" "" ,
"aws_secret_key" "" ,
"docker_version" "1.12.4"
},
"builders" : [{
"type" "amazon-ebs" ,
"access_key" "{{user `aws_access_key`}}" ,
"secret_key" "{{user `aws_secret_key`}}" ,
"region" "us-east-1" ,
"source_ami_filter" : {
"filters" : {
"virtualization-type" "hvm" ,
"name" "*ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-*" ,
"root-device-type" "ebs"
},
"most_recent" true
},
"ami_virtualization_type" "hvm" ,
"instance_type" "m3.medium" ,
"ssh_username" "ubuntu" ,
"ami_name" "Docker {{user `docker_version`}} Ubuntu 14.04 AUFS3 `timestamp`" ,
"launch_block_device_mappings" : [{
"device_name" "/dev/sdb" ,
"volume_size" 40 ,
"volume_type" "gp2" ,
"delete_on_termination" true
}],
"tags" : {
"OS_Version" "Ubuntu" ,
"Release" "14.04" ,
"StorageDriver" "AUFS3" ,
"Docker_Version" "{{user `docker_version`}}"
}
}]
}
1
2
$> packer validate ubuntu_1404_aufs3.json
Template validated successfully.

现在它已通过了验证,不过如果我们真的实际运行它,Packer只会创建一个基础AMI的副本,连接40GB驱动,而这不是很有用。为了让它更有实用性,我们还需要在上面准备Docker。Packer内置的hooks可用于各种配置管理(CM)工具,如Ansible、Chef和Puppet。在我们的例子中,我们将使用Ansible provisioner。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"variables" : [ "..." ],
"builders" : [ "..." ],
"provisioners" : [
{
"type" "ansible" ,
"playbook_file" "./playbook.yml" ,
"extra_arguments" : [
"--extra-vars" ,
"docker_pkg_name='docker-engine={{user `docker_version`}}-0~ubuntu-trusty'"
]
}
]
}

playbook.yml文件的内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
- name: Install Docker on Ubuntu  14.04
hosts: all
# run as root
become:  true
become_user: root
pre_tasks:
- name: format the extra drive
filesystem:
dev: /dev/xvdb
fstype: ext4
- name: mount the extra drive
mount:
name: /secondary
# ubuntu renames the block devices to xv* prefix
src: /dev/xvdb
fstype: ext4
state: mounted
roles:
- role: angstwad.docker_ubuntu
docker_opts:  "--graph /secondary --storage-driver=aufs"

运行该工具之前,我们需要在包含ubuntu_1404_aufs3.json的根目录抓取Docker安装角色,然后运行ansible-galaxy install angstwad.docker_ubuntu -p 来下载一个预配置的Docker安装角色。颇受欢迎的angstwad.docker_ubuntu角色为在Ubuntu上的Docker安装提供了很多选项,并且它提供的安装方式大多是按照官方的Docker安装教程进行操作的。


最后,我们执行下面的脚本,等待新的基础镜像生成。最终生成的镜像将是你从现在开始要使用的基础Docker镜像。

1
2
3
4
5
6
$> packer build ubuntu_1404_aufs3.json
... output
... output
==> amazon-ebs: Creating the AMI: Docker  1.12 . 4  Ubuntu  14.04  AUFS3  1486965623
amazon-ebs: AMI: ami-1234abcd
==> amazon-ebs: Waiting  for  AMI to become ready...


AWS基础设施创建


在开始创建基础设施组件之前,先检查以下AWS上Rancher的架构模板仓库。


网络层


接下来,大多数AWS服务需要建立一个VPC来供应零错误的服务。要做到这一点,我们将用公共子网创建一个单独的VPC。下面提供的是一种安装标准模板的直接的方式。在这里检查网络模块。


在main.tf(基础设施的入口文件)中,我们引用了./database的网络配置,然后我们需要向我们的模块传递参数:

1
2
3
4
5
6
7
module  "networking"  {
source =  "./networking"
aws_region =  "${var.aws_region}"
tag_name =  "${var.tag_name}"
aws_vpc_cidr =  "${var.aws_vpc_cidr}"
aws_public_subnet_cidrs =  "${var.aws_public_subnet_cidrs}"
}

现在,你可以运行我们简单网络层的创建操作:

1
2
3
4
5
6
7
8
9
terraform plan -target= "module.networking"
... output ...
Plan:  6  to add,  0  to change,  0  to destroy.
$> terraform apply -target= "module.networking"
... output ...
module.networking.aws_subnet.rancher_ha_c: Creation complete
module.networking.aws_subnet.rancher_ha_b: Creation complete
module.networking.aws_subnet.rancher_ha_a: Creation complete
module.networking.aws_route.rancher_ha: Creation complete

应用完成!资源:6添加, 0更改, 0销毁。


HA Rancher Server


接下来,让我们开始设置我们的网络,并使用我们的AMI在Rancher上安装HA mode。首先,我们需要自动化Rancher的HA安装。


在Rancher 1.2版本之后,我们对HA进程进行了更新,Rancher不再需要一个bootstrap节点及依赖的步骤来创建HA集群。新的步骤是:


  • 创建一个外部数据库(本文使用的是RDS)

  • 创建一个HA loadbalancer 的免费SSL证书

  • 使用一个外部loadbalancer在3个节点中进行route(这里使用ELB)

  • 启动的HA节点会用附加标示--advertise-address标记起来,并在端口9345进行端口转发


去除bootstrap节点,使得HA Rancher的自动安装变得更加容易。


下面让我们开始创建我们的外部数据库吧!


创建一个外部数据库


继续在main.tf中,我们接下来要搭建RDS数据库。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
module  "database"  {
source =  "./database"
vpc_id =  "${module.networking.vpc_id}"
database_subnet_ids = [
"${module.networking.vpc_subnet_a}" ,
"${module.networking.vpc_subnet_b}" ,
"${module.networking.vpc_subnet_c}" ,
]
database_port =  "${var.database_port}"
database_name =  "${var.database_name}"
database_username =  "${var.database_username}"
database_password =  "${var.database_password}"
database_instance_class =  "${var.database_instance_class}"
}

数据库将创建安全组,安全组由在我们网络层定义的子网组成。你可以在Github上看到完整的数据库terraform模板。

1
2
3
4
5
6
7
8
$> terraform plan -target= "module.database"
... output ...
Plan:  3  to add,  0  to change,  0  to destroy.
$> terraform apply -target= "module.database"
... output ...
module.database.aws_db_instance.rancherdb: Still creating... (4m20s elapsed)
module.database.aws_db_instance.rancherdb: Creation complete
Apply complete! Resources:  3  added,  0  changed,  0  destroyed.


为我们的ELB创建免费证书


在这一步中,我们使用AWS证书管理器(ACM)为Rancher HA 证书管理SSL证书。你可以在ACM文档中查阅如何请求一个免费的SSL证书。因为从ACM请求证书的过程中需要手动验证域名,我们不对这一部分进行自动化。一旦请求完成,引用SSL证书就和下面添加数据资源一样简单,你可以在Github上看到该文件。

1
2
3
4
data  "aws_acm_certificate"  "rancher_ha_cert"  {
domain =  "${var.fqdn}"
statuses = [ "ISSUED" ]
}

 

创建HA服务器组


接下来,我们用与ELB相关的安全组搭建一个ELB。然后,我们将添加3个EC2主机驻留在Rancher上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
module  "rancher_server_ha"  {
source =  "./rancher_server_ha"
vpc_id =  "${module.networking.vpc_id}"
tag_name =  "${var.tag_name}"
# ssled domain without protocol e.g. moo.test.com
acm_cert_domain =  "${var.acm_cert_domain}"
# domain with protocol e.g. https: //moo.test.com
fqdn =  "${var.fqdn}"
# ami that you created with packer
ami = {
us-east- 1  "ami-f05d91e6"
}
subnet_ids = [
"${module.networking.vpc_subnet_a}" ,
"${module.networking.vpc_subnet_b}" ,
"${module.networking.vpc_subnet_c}" ,
]
# database variables to be passed into Rancher Server Nodes
database_port =  "${var.database_port}"
database_name =  "${var.database_name}"
database_username =  "${var.database_username}"
database_password =  "${var.database_password}"
database_endpoint =  "${module.database.endpoint}"
}

下面是HA服务器模板创建安全组、ELB和弹性伸缩组的细节。这个过程需要几分钟时间,因为我们需要等待EC2实例启动。

1
2
3
4
5
6
$> terraform plan -target= "module.rancher_server_ha"
... output ...
Plan:  11  to add,  0  to change,  0  to destroy.
$> terraform apply -target= "module.rancher_server_ha"
... output ...
Apply complete! Resources:  11  added,  0  changed,  0  destroyed.


HA实例的云配置


我们在./files/userdata.template文件中提供自己的服务器节点资源。它填充了变量,来为我们的实例创建一个cloud-init配置。Cloud init文档写了一个名为start-rancher.sh的文件,这一文件会在实例启动的时候被执行。


你可以在这里查看文件的细节。


在ELB上指向DNS


现在你可以在我们创建的Rancher ELB上指向你的DNS server。导航去ELB console,你应该能看到创建的ELB。接下来抓取ELB的DNS名并且在你的域名提供商处添加一个CNAME记录它。


比如,在这篇博客中,我在rancher.domain.com上安装了Rancher,接下来在https://rancher.domain.com访问管理员面板。


Rancher节点安装


至此,我们已经成功安装了Rancher服务器,并且可以添加自定义主机或使用Rancher-provided主机驱动了。如果我们有更多的自动化尝试,这里有一个也许可行的方法,让你可以在AWS上自动化autoscaled从属节点集群。


在Rancher UI界面,我们按照文档添加自定义主机。我们需要抓取几个变量传递到我们的集群安装模板上。


写入自定义主机时的命令是:

1
2
3
4
5
sudo docker run -d --privileged -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/rancher:/var/lib/rancher 
rancher/agent:${rancher_agent_version} ${rancher_reg_url}
# Example at the time of writing.
rancher_reg_url = https: //rancher.domain.com/v1/scripts/AAAAABBBBB123123:150000000000:X9asiBalinlkjaius91238
rancher_agent_version = v1. 2.0

在抓出这些变量后,下一步可以开始创建节点。因为与建立HA相比这是一个单独的进程,在文件中我们先为Rancher节点的创建添上注释。

1
2
3
4
5
6
$> terraform plan -target= "module.rancher_nodes"
... output ...
Plan:  3  to add,  0  to change,  0  to destroy.
$> terraform apply -target= "module.rancher_nodes"
... output ...
Apply complete! Resources:  3  added,  0  changed,  0  destroyed.

几分钟后,你应该可以看到你的Rancher主机已出现在你的Rancher UI中。


总结


这篇文章的步骤非常多,但有了这个模板,我们现在可以单独地建立Terraform组件,并在基础设施层上进行迭代。这有点像Docker镜像建立的过程。


这对所有这些不同的组件带来的最大好处是可替换性。如果你不喜欢本文中Docker Host操作系统的选择,那么你可以改变Packer的配置并在Terraform中更新AMI ID。如果你不喜欢网络层,那么只需看一眼Terraform脚本然后更新它。这个安装教程只是一个让Rancher运行起来、让你可以开始你的项目的最初模板。


当然,这并不是搭建Rancher最好的方式,但Terraform的布局是能够随着项目的持续进行而持续改进的。


进一步改进


  • 这里显示的VPC是驻留在公用子网伤的(出于简单性的考量),但如果你想保护数据库和服务器之间的网络流量,你需要更新网络(这可能需要重建)。

  • 其实你可以考虑将Rancher节点传递到一个单独的项目上,而非像本教程一下添上注释。

  • 我们应该看看如何在Terraform上做备份,以避免出现丢失文件夹的情况。所以对于想在生产环境中使用它的人来说,为S3备份中多做一些安装是一定会有很大帮助的。

  • 其实也可以将EFS添加进脚本中,来添加分布式文件系统,给我们各个节点提供支持。

  • 跨区域RDS复制:terraform-community-modules/tf\_aws\_rds

  • 使用由terrafrm社区管理的Terraform VPC模块:terraform-community-modules/tf\_aws\_vpc


一些可供参考的架构


很多社区成员和Rancher贡献者为我们创造了很多值得参考的架构。你在测试了本文的模板之后可以进一步参考一下他们提供的一些结构,来改进自己的基础设施。


Terraform


  • https://github.com/mlaccetti/terraform-aws-rancher-ha

  • https://github.com/cloudnautique/terraform-rancher


更多的网络变体可以参考这里


原文来源:Rancher Labs

本文转自 RancherLabs 51CTO博客,原文链接:http://blog.51cto.com/12462495/1909114



相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
3月前
|
消息中间件 缓存 NoSQL
Redis各类数据结构详细介绍及其在Go语言Gin框架下实践应用
这只是利用Go语言和Gin框架与Redis交互最基础部分展示;根据具体业务需求可能需要更复杂查询、事务处理或订阅发布功能实现更多高级特性应用场景。
306 86
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
304 59
|
5月前
|
存储 监控 安全
企业上网监控系统中红黑树数据结构的 Python 算法实现与应用研究
企业上网监控系统需高效处理海量数据,传统数据结构存在性能瓶颈。红黑树通过自平衡机制,确保查找、插入、删除操作的时间复杂度稳定在 O(log n),适用于网络记录存储、设备信息维护及安全事件排序等场景。本文分析红黑树的理论基础、应用场景及 Python 实现,并探讨其在企业监控系统中的实践价值,提升系统性能与稳定性。
175 1
|
5月前
|
存储 监控 算法
公司员工泄密防护体系中跳表数据结构及其 Go 语言算法的应用研究
在数字化办公中,企业面临员工泄密风险。本文探讨使用跳表(Skip List)数据结构优化泄密防护系统,提升敏感数据监测效率。跳表以其高效的动态数据处理能力,为企业信息安全管理提供了可靠技术支持。
140 0
|
6月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
136 0
栈区的非法访问导致的死循环(x64)
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。
|
11月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
550 77
|
10月前
|
算法 调度 C++
STL——栈和队列和优先队列
通过以上对栈、队列和优先队列的详细解释和示例,希望能帮助读者更好地理解和应用这些重要的数据结构。
250 11
|
10月前
|
DataX
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
11月前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
459 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】

热门文章

最新文章