65.9K
CodeProject 正在变化。 阅读更多。
Home

自动化 Amazon VPC 的网络主控场景

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2016年2月29日

MIT

5分钟阅读

viewsIcon

14680

本文档介绍了“基础设施即代码”概念,用于自动化 Amazon VPC 的创建。

引言

长期以来,Amazon Web Services 一直是部署和运行新项目最常用的平台之一。对于更复杂的项目,您通常会从掌握网络基础设施开始,幸运的是,Amazon 提供了关于最常用网络拓扑的权威指南。您可以在 http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Scenarios.html 上查看一些示例。

出于某些原因,在我见过的大多数客户案例中,他们总是手动配置设置,然后在项目 wiki 中用屏幕截图记录步骤。之后,原始知识会丢失,迁移或重新部署应用程序会导致小心翼翼的手动操作。

在本文中,我将演示如何根据项目要求,使用 Ansible 为应用程序自动化网络创建,并将网络创建逻辑与项目一起存储。通过这种方式,您的项目基础设施可以随着您的应用程序发布而发展和发布。

背景

为了演示,让我们选择一个更复杂的设置,如这里所述 带有公共和私有子网 (NAT) 的 VPC

让我们看一下定义和网络拓扑图。

此场景的配置包括一个带有公共子网和私有子网的虚拟私有云 (VPC)。如果您想运行面向公众的 Web 应用程序,同时维护不面向公众的后端服务器,我们建议采用此场景。一个常见的例子是多层网站,Web 服务器位于公共子网中,数据库服务器位于私有子网中。您可以设置安全性和路由,以便 Web 服务器能够与数据库服务器通信。

公共子网中的实例可以直接接收来自 Internet 的入站流量,而私有子网中的实例则不能。公共子网中的实例可以直接向 Internet 发出出站流量,而私有子网中的实例则不能。相反,私有子网中的实例可以通过位于公共子网中的网络地址转换 (NAT) 网关访问 Internet。数据库服务器可以通过 NAT 网关连接到 Internet 以下载软件更新,但 Internet 无法发起连接到数据库服务器。

让我们实现一个更复杂的示例:通过将应用程序服务器放置在多个子网中来使应用程序高可用。因此,在公共子网中我们将有一个 Elastic Load Balancer,它将链接到我们创建的几个子网。

在我们的场景中,我们将使用 Ansible AWS 模块的所有功能,以及直接的 awscli 命令,因为 Ansible 尚不支持某些功能。

最初,我们的账户上将没有任何 VPC。

先决条件

由于区域的可用于性区域集不同,让我们创建两个常量,以固定可用可用区域名称进行预配,并为环境提供一个合理的名称。

---
  vpc_availability_zone_t1: b
  vpc_availability_zone_t2: c

  readable_env_name: "app-{{env}}" 

结构

让我们根据场景 2 图定义 VPC。为了尽可能接近 Amazon 的示例,我将使 0.0 和 2.0 子网公开,1.0 和 3.0 子网私有;正如您在 VPC 配置中所见,我们已经提供了易于阅读的命名和标签。对于两个公共网络,我们指定了默认路由表。

vpc_cidr_block: 10.0.0.0/16
vpc_subnets:
  - cidr: 10.0.0.0/24
    az: "{{aws_region}}{{vpc_availability_zone_t1}}"
    resource_tags: {"Name": "{{readable_env_name}}-sb-pub-{{aws_region}}-{{vpc_availability_zone_t1}}",  "Environment":"{{readable_env_name}}", "AZ" : "{{vpc_availability_zone_t1}}" }
  - cidr: 10.0.2.0/24
    az: "{{aws_region}}{{vpc_availability_zone_t2}}"
    resource_tags: { "Name": "{{readable_env_name}}-sb-pub-{{aws_region}}-{{vpc_availability_zone_t2}}", "Environment":"{{readable_env_name}}", "AZ" : "{{vpc_availability_zone_t2}}" }
  - cidr: 10.0.1.0/24
    az: "{{aws_region}}{{vpc_availability_zone_t1}}"
    resource_tags: {"Name": "{{readable_env_name}}-sb-priv-{{aws_region}}-{{vpc_availability_zone_t1}}",  "Environment":"{{readable_env_name}}", "AZ" : "{{vpc_availability_zone_t1}}" }
  - cidr: 10.0.3.0/24
    az: "{{aws_region}}{{vpc_availability_zone_t2}}"
    resource_tags: { "Name": "{{readable_env_name}}-sb-priv-{{aws_region}}-{{vpc_availability_zone_t2}}", "Environment":"{{readable_env_name}}", "AZ" : "{{vpc_availability_zone_t2}}" }

vpc_internet_gateway: "yes"
vpc_route_tables_public:
    - subnets:
       - 10.0.0.0/24
       - 10.0.2.0/24
      routes:
       - dest: 0.0.0.0/0
         gw: igw

创建 VPC

要创建 VPC,我们使用已有的 Ansible 模块 ec2_vpc;在运行时,我们使用上述设置向其提供参数。

- name: NETWORK | Create the VPC
  ec2_vpc:
    state: present
    region: "{{ aws_region }}"
    resource_tags:
        Environment: "{{ readable_env_name }}"
        Name: "{{ readable_env_name }}-vpc-{{aws_region}}"
    cidr_block: "{{ vpc_cidr_block }}"
    subnets: "{{ vpc_subnets }}"
    dns_support: true
    dns_hostnames: true
    internet_gateway: "{{ vpc_internet_gateway|string }}"
    route_tables: "{{ vpc_route_tables_public }}"
    wait: yes
  register: vpc

此部分执行完毕后,我们将创建 VPC 和子网。

看看创建的 NAT 网关 - 正如您所见,每个公共子网都有一个 NAT 网关。

看看创建的路由表,正如您所见 - 公共子网设置了 Internet 网关,

而私有子网有一个路由条目,通过 NAT 转发出站请求。

NAT 实例的魔力

如今,Amazon 建议创建 NAT 网关,而不是 NAT 实例。要掌握 NAT 网关,我们需要

  • 分配弹性 IP
  • 创建 NAT 网关并将 NAT 网关与子网关联
  • 等待 NAT 网关部分可用,以创建私有子网的路由表。
  • 为私有子网创建路由表并为出站流量设置 NAT 网关

要分配弹性 IP,我们将使用 Ansible 中的现有模块:ec2_eip。请注意,默认情况下,每个账户每个区域最多只能有 5 个弹性 IP。

  - name: NETWORK | allocate a new elastic IP without associating it to anything - 1
    ec2_eip: in_vpc=yes reuse_existing_ip_allowed=yes state=present region="{{aws_region}}"

为了创建 NAT 网关,在 Ansible v1 中我们必须使用 awscli。

  - name: NETWORK | Create NAT instance for subnet 1
    shell: "aws ec2 create-nat-gateway --region {{aws_region}} --subnet-id {{aws_vpc_pubsubnet1_runtime}} --allocation-id {{aws_vpc_privsubnet1_allocation}}"

这里有一个小技巧:如果您需要立即使用 NAT 网关,例如创建自定义路由表,请给 AWS 一些时间使其部分初始化和注册。

现在我们可以创建自定义路由表了。

  - name: NETWORK | Create new route table for the private subnet 1
    shell: "aws ec2 create-route-table --region {{aws_region}} --vpc-id {{aws_vpc_id_runtime}}"

  - name: NETWORK | Associate route table with private subnet 1
    shell: "aws ec2 associate-route-table --region {{aws_region}} --route-table-id {{routetable_private_1}} --subnet-id {{aws_vpc_privsubnet1_runtime}}"

  - name: NETWORK | Create NAT route record for  private subnet 1
    shell: "aws ec2 create-route --region {{aws_region}} --route-table-id {{routetable_private_1}} --destination-cidr-block '0.0.0.0/0' --nat-gateway-id {{nat_instance1}}"

安全组

我们可以与防火墙规则一起定义安全组的要求。请注意下面的示例,如何为 CIDR 块和特定安全组创建规则。

我想要四个安全组。

第一个用于负载均衡器,接受 HTTP 和 HTTPS。

第二个用于公共子网中的跳转服务器 (jump box),这样我就可以 SSH 到该服务器,并通过 ping、登录和排查我的应用程序实例。因此,我需要从该服务器打开到应用程序服务器的 SSH 和 ICMP。

第三个用于跳转服务器本身,因为我只想限制从我的办公室 IP 访问跳转服务器(假设网关具有公共 IP 地址 1.2.3.4)。

第四个用于我的数据库服务器,通常是 RDS。假设我们使用 MySQL - 我需要从应用程序服务器打开 3306 端口。

vpc_security_groups:
  - name: "{{readable_env_name}}-public-LOADBALANCER"
    desc: "security group for public access"
    rules:
      - proto: tcp
        from_port: 80
        to_port: 80
        cidr_ip: 0.0.0.0/0
      - proto: tcp
        from_port: 443
        to_port: 443
        cidr_ip: 0.0.0.0/0

  - name: "{{readable_env_name}}-public-JUMPBOX"
    desc: "security group that allows access from dedicated jump box in public network to internal resources"
    rules:
      - proto: tcp
        from_port: 22
        to_port: 22
        cidr_ip: "1.2.3.4/32" #Your office private ip

  - name: "{{readable_env_name}}-private-APP"
    desc: "Network for internal app servers"
    rules:
      - proto: tcp
        from_port: 22
        to_port: 22
        group_id: "{{readable_env_name}}-public-JUMPBOX"
      - proto: tcp
        from_port: 80
        to_port: 80
        group_id: "{{readable_env_name}}-public-LOADBALANCER"
      - proto: tcp
        from_port: 443
        to_port: 443
        group_id: "{{readable_env_name}}-public-LOADBALANCER"
      - proto: icmp
        from_port: -1 # icmp type, -1 = any type
        to_port:  -1 # icmp subtype, -1 = any subtype
        group_id: "{{readable_env_name}}-public-JUMPBOX"

  - name: "{{readable_env_name}}-private-DATABASE"
    desc: "resources that are private"
    rules:
      - proto: tcp
        from_port: 3306  # MYSQL
        to_port: 3306
        group_id: "{{readable_env_name}}-private-APP"

您不觉得从定义中就可以清晰地看出设置吗?我认为是的。

让我们检查一下创建的设置。

已创建的安全组列表。

具有入站规则的公共安全组。

具有入站规则的私有应用程序服务器组。

具有入站规则的数据库访问安全组。

具有入站规则的跳转服务器安全组。

运行预配

运行 Ansible 预配就像执行下面结构的 shell 文件一样简单。

正如您所见,我们指定了环境名称 (demo),要在其中创建 VPC 的区域 (us-east-1),并将您的安全 AWS 凭证设置为预配的环境变量。

#!/bin/sh

# Static parameters
WORKSPACE=$PWD
BOX_PLAYBOOK=$WORKSPACE/bin/network_create.yml
BOX_NAME=awsnetwork

echo $BOX_NAME

prudentia local <<EOF
unregister $BOX_NAME
register
$BOX_PLAYBOOK
$BOX_NAME

verbose 4

set env demo
set aws_region us-east-1

envset AWS_ACCESS_KEY_ID THISISVERYSECUREKEYID
envset AWS_SECRET_ACCESS_KEY ANDTHISISTHISISVERYSECUREKEYACCESSKEY

provision $BOX_NAME

unregister $BOX_NAME
EOF

想知道需要多长时间?不到 1 分钟。与手动设置相比……

PLAY RECAP ********************************************************************
127.0.0.1                  : ok=42   changed=12   unreachable=0    failed=0  

最后,您将获得有关创建的网络的所有信息,因此您可以存储它,或者将其模板化到某个配置文件中。

关注点

我建议将部署和预配配方与您的应用程序代码一起存储和维护。相信我,当您知道您可以在 10-40 分钟内从头开始搭建环境时,您的客户会不那么焦虑。

如果您使用这种方法来实现不同类型的网络设置,我很乐意听取您的经验分享。如果您需要在项目中实现持续集成,欢迎您。

可与 Ansible v1 (1.9.4) 一起使用的示例可以在 https://github.com/Voronenko/ansible_vpc_ppsubnet_wnat/tree/master/v1 上查看或 fork。

可与 Ansible v2 (2.0.2.0) 一起使用的示例可以在 https://github.com/Voronenko/ansible_vpc_ppsubnet_wnat/tree/master/v2 上查看或 fork。

© . All rights reserved.