[ 英语 | 印度尼西亚语 | 俄语 ]

使用基于域名(或路径)的端点代替基于端口的端点

默认情况下,OpenStack-Ansible 使用基于端口的端点。这意味着每个服务将在其自己的唯一端口上提供公共和内部端点。例如,Keystone 将被添加为 https://domain.com:5000/v3,Nova 作为 https://domain.com:8774/v2.1,依此类推。

虽然这是最简单的方法,因为它不需要额外的配置并且易于上手,但它也有一些缺点。例如,某些客户端或组织可能不允许连接到自定义端口,这完全禁用了在这些部署中使用它们的能力。

为了解决这些限制,从 2023.1 (Antelope) 版本开始,可以使用基于域名或基于路径的端点。

警告

切换到基于域名或基于路径的端点后,所有内部和公共端点必须覆盖有效的 TLS 证书。否则,OpenStack 组件之间的通信可能会中断。如果您的部署中不使用 TLS 进行内部流量,请确保 HAProxy 已配置为内部请求不会重定向到 HTTPS。这必须由操作员手动调整。

配置基于路径的端点

基于路径的端点意味着在相同的 FQDN 上提供服务,但根据 URI 对它们进行区分。

例如,Keystone 可以配置为 https://domain.com/identity/v3,而 Nova 可以配置为 https://domain.com/compute/v2.1

警告

请注意,Horizon 利用 /identity 用于其 Keystone 面板,因此,如果您在 /(默认值)上提供 Horizon 并使用 /identity 将流量转发到 Keystone 后端,由于冲突,Horizon 内部的用户、角色、项目管理将中断。

虽然基于路径的端点可能看起来很有吸引力,因为它们使用 FQDN,因此不需要通配符 TLS,但它们更难维护且设置更复杂。还值得注意的是,尽管这种方法在 devstack 中使用,但并非所有服务都准备好支持基于路径的端点。

目前不支持基于路径的端点的异常示例包括 VM 的 VNC 控制台(将在 蓝图 中实现)、Magnum(错误报告 <https://launchpad.net/bugs/2083168>)和 Ceph Rados Gateway。

HAProxy 配置

与基于域名的端点类似,我们依赖 HAProxy map 功能。但是,我们使用 map_reg 代替 map_dom

因此,我们需要定义要使用的 map 文件以及解析它的方法。为此,我们需要对“基础”服务应用覆盖。

haproxy_base_service_overrides:
  haproxy_maps:
    - 'use_backend %[path,map_reg(/etc/haproxy/base_regex.map)]'

如果您需要拥有 Ceph RGW 或想要组合基于域名和基于路径的方法,可以通过定义两个 map 文件来做到这一点

注意

如果对 haproxy_base_service_overrides 变量进行任何更改,您需要重新运行 openstack-ansible openstack.osa.haproxy --tags haproxy-service-config

haproxy_base_service_overrides:
  haproxy_maps:
    - 'use_backend %[req.hdr(host),map_dom(/etc/haproxy/base_domain.map)] if { req.hdr(host),map_dom(/etc/haproxy/base_domain.map) -m found }'
    - 'use_backend %[path,map_reg(/etc/haproxy/base_regex.map)]'

如果未匹配任何域,HAProxy 将继续使用基于路径的端点。

接下来,我们需要确保每个 HAProxy 服务配置都包含带有相应条件的 HAProxy map 填充,例如

注意

haproxy_<service>_service_overrides 变量进行更改后,您需要使用 haproxy-service-config 标签重新运行特定于服务的 playbook,例如 openstack-ansible openstack.osa.keystone --tags haproxy-service-config

haproxy_keystone_service_overrides:
  haproxy_backend_only: true
  haproxy_map_entries:
    - name: base_regex
      entries:
        - "^/identity keystone_service-back"

haproxy_nova_api_compute_service_overrides:
  haproxy_backend_only: true
  haproxy_map_entries:
    - name: base_regex
      entries:
        - "^/compute nova_api_os_compute-back"

服务配置

与基于域名的端点类似,我们需要覆盖每个服务的端点定义。通常使用以下变量定义端点

  • <service>_service_publicuri

  • <service>_service_internaluri

  • <service>_service_adminuri

以下是定义 Keystone 和 Nova 端点的示例

keystone_service_publicuri: "{{ openstack_service_publicuri_proto }}://{{ external_lb_vip_address }}/identity"
keystone_service_internaluri: "{{ openstack_service_internaluri_proto }}://{{ internal_lb_vip_address }}/identity"
keystone_service_adminuri: "{{ openstack_service_adminuri_proto }}://{{ internal_lb_vip_address }}/identity"

nova_service_publicuri: "{{ openstack_service_publicuri_proto }}://{{ external_lb_vip_address }}/compute"
nova_service_internaluri: "{{ openstack_service_internaluri_proto }}://{{ internal_lb_vip_address }}/compute"
nova_service_adminuri: "{{ openstack_service_adminuri_proto }}://{{ internal_lb_vip_address }}/compute"

但是,配置中还有另一个重要的部分,这与基于域名的设置不同。所有服务都假定它们在根路径(即 /)上提供服务,而在基于路径的方法中,我们为每个服务使用唯一的路径。

因此,现在我们需要使服务尊重该路径并正确响应它。一种方法是在 uWSGI 中使用重写机制,例如

警告

以下示例不代表如何为大多数服务配置基于路径的端点的正确方法

keystone_uwsgi_ini_overrides:
  uwsgi:
    route: '^/identity(.*)$ rewrite:$1'

但是,这种方法不正确,并且会导致某些客户端或用例出现问题,尽管该服务看起来完全正常。上述方法的问题与服务在被询问时如何返回“self”URL 相关。大多数服务将使用其当前微版本和该微版本的 URI 作为回复。

如果您使用像上面显示的那样的 uWSGI 重写,您将得到如下回复

curl https://cloud.com/identity/ | jq
{
"versions": {
    "values": [
    {
        "id": "v3.14",
        "status": "stable",
        "updated": "2020-04-07T00:00:00Z",
        "links": [
        {
            "rel": "self",
            "href": "https://cloud.com/v3/"
        }
        ],
        "media-types": [
        {
            "base": "application/json",
            "type": "application/vnd.openstack.identity-v3+json"
        }
        ]
    }
    ]
}
}

如您所见,href 指向的位置不正确。虽然某些客户端可能不参考服务提供的 href 链接,但其他客户端可能会将其用作事实来源,这将导致失败。

一些服务,例如 keystone,具有可以控制如何定义 href 的配置选项。例如,keystone 具有 [DEFAULT]/public_endpoint 选项,但这种方法在所有服务中并不一致。此外,keystone 将为所有端点(包括 admin 和 internal)返回提供的 public_endpoint

因此,唯一的正确方法是调整每个服务的 api-paste.ini。但是,Keystone 特别地,不支持 api-paste.ini 文件。因此,唯一的解决方法实际上是 uWSGI 重写并在 keystone.conf 中定义 public_endpoint

keystone_keystone_conf_overrides:
  DEFAULT:
    public_endpoint: "{{ keystone_service_publicuri }}"

对于其他服务,应用 api-paste.ini 可以通过变量来完成,但每个服务的具体内容都非常独特,因此无法轻松概括该方法。以下是为某些服务进行的覆盖示例

_glance_api_paste_struct:
    /: {}
    /healthcheck: {}
    /image: api
    /image/healthcheck: healthcheck
glance_glance_api_paste_ini_overrides:
  composite:glance-api: "{{ _glance_api_paste_struct }}"
  composite:glance-api-caching: "{{ _glance_api_paste_struct }}"
  composite:glance-api-cachemanagement: "{{ _glance_api_paste_struct }}"
  composite:glance-api-keystone: "{{ _glance_api_paste_struct }}"
  composite:glance-api-keystone+caching: "{{ _glance_api_paste_struct }}"
  composite:glance-api-keystone+cachemanagement: "{{ _glance_api_paste_struct }}"

neutron_api_paste_ini_overrides:
  composite:neutron:
    /: {}
    /v2.0: {}
    /network/: neutronversions_composite
    /network/v2.0: neutronapi_v2_0

nova_api_paste_ini_overrides:
  composite:osapi_compute:
    /: {}
    /v2: {}
    /v2.1: {}
    /v2/+: {}
    /v2.1/+: {}
    /compute: oscomputeversions
    /compute/v2: oscomputeversion_legacy_v2
    /compute/v2.1: oscomputeversion_v2
    /compute/v2/+: openstack_compute_api_v21_legacy_v2_compatible
    /compute/v2.1/+: openstack_compute_api_v21

我们建议参考每个服务的 api-paste.ini 以获取有关如何正确配置覆盖的更多详细信息。