Rackspace 云指南

    本节的目的是说明在 Rackspace Cloud 的环境下如何使用 Ansible 模块(和使用 inventory scripts).

    使用其他模块的先决条件是最少的. 除 Ansible 之外, 所有的模块依赖 pyrax 1.5 或更高版本. 你需要将这个 Python 模块安装在执行主机上.

    pyrax 在一些操作系统的包仓库中是不存在的, 所以你可能需要通过 pip 安装:

    下面的步骤将会一直从控制机器通过 Rackspace Cloud API 执行, 所以将 localhost 添加到 inventory 文件中是有意义的. (在未来 Ansible 可能不在依赖这一步):

    1. [localhost]
    2. localhost ansible_connection=local

    在 playbook 中, 我们将会使用下面典型的模式:

    1. - hosts: localhost
    2. connection: local
    3. gather_facts: False
    4. tasks:

    凭证文件

    这个 rax.py inventory 脚本和所有 rax 模块均支持一种标准的 pyrax 凭证文件, 它看起来像这样:

    1. [rackspace_cloud]
    2. username = myraxusername
    3. api_key = d41d8cd98f00b204e9800998ecf8427e

    设置环境变量 RAX_CREDS_FILE 到凭证文件的路径, 这将帮助 Ansible 找到它并加载这些信息.

    更多关于凭证文件的信息可以参考这里

    大多数用户不喜欢使用虚拟环境, 但是有些用户喜欢, 特别是一些 Python 开发者.

    当 Ansible 被安装到 Python 的虚拟环境时, 相比较默认安装到全局环境中, 需要有一些特殊考虑. Ansible 假定, 除非有其他明确的指定, python 二进制可执行文件为 /usr/bin/python. 这是通过模块中解释器一行确定的, 然而可以使用 inventory 变量 ‘ansible_python_interpreter’ 来重新指定, Ansible 将使用指定的路径去寻找 Python. 使用 Python 虚拟环境解析器, 这可能是模块在 ‘localhost’ 运行或者通过 ‘local_action’ 来运行的原因. 通过设置 inventory, 模块将会在虚拟环境中执行并且拥有单独的虚拟包, 特别是 pyrax. 如果使用虚拟环境, 你可能需要修改你本地 inventory 来定义这个虚拟位置, 像下面一样:

    1. [localhost]
    2. localhost ansible_connection=local ansible_python_interpreter=/path/to/ansible_venv/bin/python

    现在到了有趣的部分.

    这个 ‘rax’ 模块在 Rackspace Cloud 中具有提供 instances 的能力. 典型的配置任务将通过你的 Ansible 控制服务器(在我们的例子中, localhost)请求 Rackspace cloud API. 这是因为这几个原因:

    下面是一个在 ad-hoc 模式下配置 instance 的简单实例:

    1. $ ansible localhost -m rax -a "name=awx flavor=4 image=ubuntu-1204-lts-precise-pangolin wait=yes" -c local

    这些内容转换成 playbook 像下面一样, 假设参数定义在变量中:

    rax 模块返回节点创建 instance 的数据, 像 IP 地址, 主机名, 和登陆密码. 通过注册返回值的步骤, 可以使用它动态添加到主机的 inventory 中(临时在内存中). 这有利于在新建的 instance 上进行配置操作. 在下面的示例中, 将会使用上面成功创建的服务器的信息, 通过每个节点的主机名, IP 地址, 和 root 密码动态添加到一个名为 raxhosts 组中.

    1. - name: Add the instances we created (by public IP) to the group 'raxhosts'
    2. local_action:
    3. module: add_host
    4. hostname: "{{ item.name }}"
    5. ansible_ssh_host: "{{ item.rax_accessipv4 }}"
    6. ansible_ssh_pass: "{{ item.rax_adminpass }}"
    7. groups: raxhosts
    8. with_items: rax.success
    9. when: rax.action == 'create'

    现在使用已经创建的主机组, 接下来将会使用下面的 playbook 配置 raxhosts 组中的服务器

    1. - name: Configuration play
    2. hosts: raxhosts
    3. user: root
    4. roles:
    5. - ntp
    6. - webserver

    上面的方法将提供的主机配置在一起. 这并不总是你想要了, 那么让我们进入下一章节.

    主机 Inventory

    一旦你的节点被创建启动, 你很可能会多次和他们进行通讯. 最好的方法是通过 “rax” inventory 插件, 动态查询 Rackspace Cloud 告诉 Ansible 哪些节点需要被管理. 你可能会使用 Ansible 启动的这些 event 来管理其他的工具, 包含 Rackspace 云用户接口. 这个 inventory 插件可以通过元数据, 区域, OS, 配置等来进行分组. 在 “rax” 中高度推荐使用元数据, 它可以很容易的在主机组和 roles 之间排序. 如果你不想使用 “rax.py” 这个动态 inventory 脚本, 你仍然可以选择手动管理你的 INI inventory 文件, 尽管这是不被推荐的.

    Ansible 可以使用多个动态 inventory 插件和 INI 数据文件. 仅仅需要将他们放在一个目录下, 并确保脚本添加了执行权限, INI 文件则不需要.

    rax.py

    使用 rackspace 动态 inventory 脚本, 复制 到你的 inventory 目录下并且赋予执行权限. 你可以为 rax.py 指定一个凭证文件利用 RAX_CREDS_FILE 环境变量.

    当使用 , 你将不需要在 inventory 中定义 ‘localhost’.

    正如前面所提到的, 你将经常在主机循环之外运行这些模块, 并且需要定义 ‘localhost’. 这里推荐这样做, 创建一个 inventory 目录, 并且将 rax.py 和包含 localhost 的文件放在这个目录下.

    执行 ansible 或 并且指定一个包含 inventory 的目录而不是一个文件, ansible 将会读取这个目录下的所有文件.

    让我们测试下我们的 inventory 脚本是否可以和 Reckspace Cloud 通信.

    1. $ RAX_CREDS_FILE=~/.raxpub ansible all -i inventory/ -m setup

    假设所有的属性配置都是正确的, 这个 rax.py inventory 脚本将会输入类似于下面的信息, 这些将会被用作 inventory 和变量.

    1. {
    2. "ORD": [
    3. "test"
    4. ],
    5. "_meta": {
    6. "hostvars": {
    7. "test": {
    8. "ansible_ssh_host": "1.1.1.1",
    9. "rax_accessipv4": "1.1.1.1",
    10. "rax_accessipv6": "2607:f0d0:1002:51::4",
    11. "rax_addresses": {
    12. "private": [
    13. {
    14. "addr": "2.2.2.2",
    15. "version": 4
    16. }
    17. ],
    18. "public": [
    19. {
    20. "addr": "1.1.1.1",
    21. "version": 4
    22. },
    23. {
    24. "addr": "2607:f0d0:1002:51::4",
    25. "version": 6
    26. }
    27. ]
    28. },
    29. "rax_config_drive": "",
    30. "rax_created": "2013-11-14T20:48:22Z",
    31. "rax_flavor": {
    32. "id": "performance1-1",
    33. "links": [
    34. {
    35. "href": "https://ord.servers.api.rackspacecloud.com/111111/flavors/performance1-1",
    36. "rel": "bookmark"
    37. }
    38. ]
    39. },
    40. "rax_hostid": "e7b6961a9bd943ee82b13816426f1563bfda6846aad84d52af45a4904660cde0",
    41. "rax_human_id": "test",
    42. "rax_id": "099a447b-a644-471f-87b9-a7f580eb0c2a",
    43. "rax_image": {
    44. "id": "b211c7bf-b5b4-4ede-a8de-a4368750c653",
    45. "links": [
    46. {
    47. "href": "https://ord.servers.api.rackspacecloud.com/111111/images/b211c7bf-b5b4-4ede-a8de-a4368750c653",
    48. "rel": "bookmark"
    49. }
    50. ]
    51. },
    52. "rax_key_name": null,
    53. "rax_links": [
    54. {
    55. "href": "https://ord.servers.api.rackspacecloud.com/v2/111111/servers/099a447b-a644-471f-87b9-a7f580eb0c2a",
    56. "rel": "self"
    57. },
    58. {
    59. "href": "https://ord.servers.api.rackspacecloud.com/111111/servers/099a447b-a644-471f-87b9-a7f580eb0c2a",
    60. "rel": "bookmark"
    61. }
    62. ],
    63. "rax_metadata": {
    64. "foo": "bar"
    65. },
    66. "rax_name": "test",
    67. "rax_name_attr": "name",
    68. "rax_networks": {
    69. "private": [
    70. "2.2.2.2"
    71. ],
    72. "public": [
    73. "1.1.1.1",
    74. "2607:f0d0:1002:51::4"
    75. ]
    76. },
    77. "rax_os-dcf_diskconfig": "AUTO",
    78. "rax_os-ext-sts_power_state": 1,
    79. "rax_os-ext-sts_task_state": null,
    80. "rax_os-ext-sts_vm_state": "active",
    81. "rax_progress": 100,
    82. "rax_tenant_id": "111111",
    83. "rax_updated": "2013-11-14T20:49:27Z",
    84. "rax_user_id": "22222"
    85. }
    86. }
    87. }
    88. }

    当使用标准的 ini 格式的 inventory文件(相对于 inventory 插件), 它仍然可以从 Rackspace API 检索和发现 hostvar 信息.

    这可以使用像下面 inventory 格式来实现类似于 rax_facts 的功能:

    1. [test_servers]
    2. hostname1 rax_region=ORD
    3. hostname2 rax_region=ORD

    虽然你不需要知道它是如何工作的, 了解返回的变量这也将是有趣的.

    这个 rax_facts 模块提供像下面内容的 facts, 这将匹配 inventory 脚本:

    1. .. code-block:: json
    {
    “ansible_facts”: {

    “rax_accessipv4”: “1.1.1.1”,“rax_accessipv6”: “2607:f0d0:1002:51::4”,“rax_addresses”: {

    “private”: [
    {
    “addr”: “2.2.2.2”,“version”: 4

    }

    ],“public”: [

    {
    “addr”: “1.1.1.1”,“version”: 4

    },{

    }

    ]

    },“rax_config_drive”: “”,“rax_created”: “2013-11-14T20:48:22Z”,“rax_flavor”: {

    “id”: “performance1-1”,“links”: [

    ]

    },“rax_hostid”: “e7b6961a9bd943ee82b13816426f1563bfda6846aad84d52af45a4904660cde0”,“rax_human_id”: “test”,“rax_id”: “099a447b-a644-471f-87b9-a7f580eb0c2a”,“rax_image”: {

    ]

    },“rax_key_name”: null,“rax_links”: [

    {
    “href”: “”,“rel”: “self”

    },{

    }

    ],“rax_metadata”: {

    “foo”: “bar”

    },“rax_name”: “test”,“rax_name_attr”: “name”,“rax_networks”: {

    },“rax_os-dcf_diskconfig”: “AUTO”,“rax_os-ext-sts_power_state”: 1,“rax_os-ext-sts_task_state”: null,“rax_os-ext-sts_vm_state”: “active”,“rax_progress”: 100,“rax_status”: “ACTIVE”,“rax_tenant_id”: “111111”,“rax_updated”: “2013-11-14T20:49:27Z”,“rax_user_id”: “22222”

    },“changed”: false

    }

    本节涵盖了一些特定案例外及额外的使用案例.

    网络和服务器

    创建一个独立的云网络并且创建一台服务器

    1. - name: Build Servers on an Isolated Network
    2. hosts: localhost
    3. connection: local
    4. gather_facts: False
    5. tasks:
    6. - name: Network create request
    7. local_action:
    8. module: rax_network
    9. credentials: ~/.raxpub
    10. label: my-net
    11. cidr: 192.168.3.0/24
    12. region: IAD
    13. state: present
    14.  
    15. - name: Server create request
    16. local_action:
    17. module: rax
    18. credentials: ~/.raxpub
    19. name: web%04d.example.org
    20. flavor: 2
    21. image: ubuntu-1204-lts-precise-pangolin
    22. disk_config: manual
    23. networks:
    24. - public
    25. - my-net
    26. region: IAD
    27. state: present
    28. count: 5
    29. exact_count: yes
    30. group: web
    31. wait: yes
    32. wait_timeout: 360
    33. register: rax

    使用服务器建立一个完整的 web 服务环境, 自定义网络和负载均衡, 安装 nginx 并且创建自定义的 index.html

    1. ---
    2. - name: Build environment
    3. hosts: localhost
    4. connection: local
    5. gather_facts: False
    6. tasks:
    7. - name: Load Balancer create request
    8. local_action:
    9. module: rax_clb
    10. credentials: ~/.raxpub
    11. name: my-lb
    12. port: 80
    13. protocol: HTTP
    14. algorithm: ROUND_ROBIN
    15. type: PUBLIC
    16. timeout: 30
    17. region: IAD
    18. wait: yes
    19. state: present
    20. meta:
    21. app: my-cool-app
    22. register: clb
    23.  
    24. - name: Network create request
    25. local_action:
    26. module: rax_network
    27. credentials: ~/.raxpub
    28. label: my-net
    29. cidr: 192.168.3.0/24
    30. state: present
    31. region: IAD
    32. register: network
    33.  
    34. - name: Server create request
    35. local_action:
    36. module: rax
    37. credentials: ~/.raxpub
    38. name: web%04d.example.org
    39. flavor: performance1-1
    40. image: ubuntu-1204-lts-precise-pangolin
    41. disk_config: manual
    42. networks:
    43. - public
    44. - private
    45. - my-net
    46. region: IAD
    47. state: present
    48. count: 5
    49. exact_count: yes
    50. group: web
    51. wait: yes
    52. register: rax
    53.  
    54. - name: Add servers to web host group
    55. local_action:
    56. module: add_host
    57. hostname: "{{ item.name }}"
    58. ansible_ssh_host: "{{ item.rax_accessipv4 }}"
    59. ansible_ssh_pass: "{{ item.rax_adminpass }}"
    60. ansible_ssh_user: root
    61. groups: web
    62. with_items: rax.success
    63. when: rax.action == 'create'
    64.  
    65. - name: Add servers to Load balancer
    66. local_action:
    67. module: rax_clb_nodes
    68. credentials: ~/.raxpub
    69. load_balancer_id: "{{ clb.balancer.id }}"
    70. address: "{{ item.rax_networks.private|first }}"
    71. port: 80
    72. condition: enabled
    73. type: primary
    74. wait: yes
    75. region: IAD
    76. with_items: rax.success
    77. when: rax.action == 'create'
    78.  
    79. - name: Configure servers
    80. hosts: web
    81. handlers:
    82. - name: restart nginx
    83. service: name=nginx state=restarted
    84.  
    85. tasks:
    86. apt: pkg=nginx state=latest update_cache=yes cache_valid_time=86400
    87. notify:
    88. - restart nginx
    89.  
    90. - name: Ensure nginx starts on boot
    91. service: name=nginx state=started enabled=yes
    92.  
    93. - name: Create custom index.html
    94. copy: content="{{ inventory_hostname }}" dest=/usr/share/nginx/www/index.html
    95. owner=root group=root mode=0644

    RackConnect 和 Managed Cloud

    当使用 RackConnect version 2 或者 Rackspace Managed Cloud, Rackspace 将在成功创建的服务器上自动执行这些任务. 如果你在 RackConnect 或 Managed Cloud 自动执行之前执行了, 你可能会获得错误或者不可用的服务器.

    这些例子展示了创建服务器并且确保 Rackspace 自动执行完成之前将会继续执行这些任务.

    为了简单, 这些例子将会被连接起来, 但是都只需要使用 RackConnect. 当仅使用 Managed Cloud, RackConnect 将会忽略这部分.

    RackConnect 部分只适用于 RackConnect 版本 2.

    使用一台控制服务器

    1. - name: Create an exact count of servers
    2. hosts: localhost
    3. connection: local
    4. gather_facts: False
    5. tasks:
    6. - name: Server build requests
    7. local_action:
    8. module: rax
    9. credentials: ~/.raxpub
    10. name: web%03d.example.org
    11. flavor: performance1-1
    12. image: ubuntu-1204-lts-precise-pangolin
    13. disk_config: manual
    14. region: DFW
    15. state: present
    16. count: 1
    17. exact_count: yes
    18. group: web
    19. wait: yes
    20. register: rax
    21.  
    22. - name: Add servers to in memory groups
    23. local_action:
    24. module: add_host
    25. hostname: "{{ item.name }}"
    26. ansible_ssh_host: "{{ item.rax_accessipv4 }}"
    27. ansible_ssh_pass: "{{ item.rax_adminpass }}"
    28. ansible_ssh_user: root
    29. rax_id: "{{ item.rax_id }}"
    30. groups: web,new_web
    31. with_items: rax.success
    32. when: rax.action == 'create'
    33.  
    34. - name: Wait for rackconnect and managed cloud automation to complete
    35. hosts: new_web
    36. gather_facts: false
    37. tasks:
    38. - name: Wait for rackconnnect automation to complete
    39. local_action:
    40. module: rax_facts
    41. credentials: ~/.raxpub
    42. id: "{{ rax_id }}"
    43. region: DFW
    44. register: rax_facts
    45. until: rax_facts.ansible_facts['rax_metadata']['rackconnect_automation_status']|default('') == 'DEPLOYED'
    46. retries: 30
    47. delay: 10
    48.  
    49. - name: Wait for managed cloud automation to complete
    50. local_action:
    51. module: rax_facts
    52. credentials: ~/.raxpub
    53. id: "{{ rax_id }}"
    54. region: DFW
    55. register: rax_facts
    56. until: rax_facts.ansible_facts['rax_metadata']['rax_service_level_automation']|default('') == 'Complete'
    57. retries: 30
    58. delay: 10
    59.  
    60. - name: Base Configure Servers
    61. hosts: web
    62. roles:
    63. - role: users
    64.  
    65. - role: openssh
    66. opensshd_PermitRootLogin: "no"
    67.  
    68. - role: ntp

    利用 Ansible Pull

    1. ---
    2. - name: Ensure Rackconnect and Managed Cloud Automation is complete
    3. hosts: all
    4. connection: local
    5. tasks:
    6. - name: Check for completed bootstrap
    7. stat:
    8. path: /etc/bootstrap_complete
    9. register: bootstrap
    10.  
    11. - name: Get region
    12. command: xenstore-read vm-data/provider_data/region
    13. register: rax_region
    14. when: bootstrap.stat.exists != True
    15.  
    16. - name: Wait for rackconnect automation to complete
    17. uri:
    18. url: "https://{{ rax_region.stdout|trim }}.api.rackconnect.rackspace.com/v1/automation_status?format=json"
    19. return_content: yes
    20. register: automation_status
    21. when: bootstrap.stat.exists != True
    22. until: automation_status['automation_status']|default('') == 'DEPLOYED'
    23. retries: 30
    24. delay: 10
    25.  
    26. - name: Wait for managed cloud automation to complete
    27. wait_for:
    28. path: /tmp/rs_managed_cloud_automation_complete
    29. delay: 10
    30. when: bootstrap.stat.exists != True
    31.  
    32. - name: Set bootstrap completed
    33. file:
    34. path: /etc/bootstrap_complete
    35. state: touch
    36. owner: root
    37. group: root
    38. mode: 0400
    39.  
    40. - name: Base Configure Servers
    41. hosts: all
    42. connection: local
    43. roles:
    44. - role: users
    45.  
    46. - role: openssh
    47. opensshd_PermitRootLogin: "no"
    48.  
    49. - role: ntp

    利用 Ansible 拉取 XenStore

    高级用法

    中包含一个非常好的功能 自动伸缩. 在这种模式下, 一个简单的 curl 脚本可以调用定义的 URL, 通过这个请求, 服务器将会被 “dial out” 或者配置一个新的服务器并启动. 这对于临时节点的控制是非常伟大的. 查看 Tower 文档获取更多细节.

    Rackspace Cloud 中的流程

    Ansible 是一个强大的编排工具, 搭配 rax 模块使你有机会完成复杂任务的部署和配置. 这里的关键是自动配置的基础设施, 就像一个环境中任何的服务软件. 复杂的部署以前可能需要手动配置负载均衡器或手动配置服务器. 利用 Ansible 和 rax 模块, 可以使其他节点参照当前运行的一些节点来部署, 或者一个集群的应用程序依赖于具有公共元数据的节点数量. 例如, 人们可以完成下列情况:

    • 将服务器从云负载均衡器中一个一个的删除, 更新, 验证并且返回一个负载均衡池
    • 对一个已存在的线上环境进行扩展, 哪些节点需要提供软件, 引导, 配置和安装
    • 关于服务器在负载均衡器中的 DNS 记录的创建和销毁