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

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

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

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

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

Host VM的创建

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

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

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兼容性矩阵。

{
"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`}}"
}
}]
}

$> packer validate ubuntu_1404_aufs3.json
Template validated successfully.

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

{
"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文件的内容如下:

---
- 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镜像。

$> 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的网络配置,然后我们需要向我们的模块传递参数:

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}"
}

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

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数据库。

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模板。

$> 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上看到该文件。

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

创建HA服务器组

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

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实例启动。

$> 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界面,我们按照文档添加自定义主机。我们需要抓取几个变量传递到我们的集群安装模板上。

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

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节点的创建添上注释。

$> 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

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

相关推荐