RGW域名訪問(wèn)bucket

背景

RGW處理的報(bào)文本質(zhì)上是一個(gè)HTTP報(bào)文,通常情況下使用http://<rgw-ip>:<rgw-port>/<bucket-name>的方式來(lái)訪問(wèn)一個(gè)bucket。實(shí)際應(yīng)用尤其是公有云環(huán)境中,通常要在rgw前架設(shè)Haproxy等負(fù)載均衡設(shè)備,且將Haproxy的ip:port映射成一個(gè)域名,方便用戶使用,這個(gè)域名也叫Endpoint

在擁有Endpoint后,訪問(wèn)一個(gè)bucket的url變成了http://<endpoint>/<bucket-name>形式。不過(guò)這也只是一個(gè)ip到域名映射,和RGW關(guān)系不大,但后面要說(shuō)的功能就和RGW密切相關(guān)了。

使用url方式訪問(wèn)bucket主要用于靜態(tài)網(wǎng)站托管,既然是網(wǎng)站,當(dāng)然就要盡量滿足常規(guī)網(wǎng)站訪問(wèn)形式。為此出現(xiàn)了兩個(gè)需求:

需求1:bucket-domain方式訪問(wèn)

bucket-domain方式是指以http://<bucket-name>.<endpoint>形式訪問(wèn)bucket。
如果用戶在公有云上托管了一個(gè)網(wǎng)站,以http://<myblog>.aws-s3.com形式訪問(wèn)肯定要好于http://aws-s3.com/myblog,前者域名看起來(lái)更像是一個(gè)獨(dú)立網(wǎng)站。

需求2:private-domain

private-domain方式是指使用自己的域名訪問(wèn)特定bucket。
如果用戶自己已經(jīng)有了現(xiàn)成的域名,那直接使用肯定是更接地氣,而且訪問(wèn)者完全不知道這個(gè)網(wǎng)站到底是托管在公有云上還是使用的獨(dú)立主機(jī)。

細(xì)說(shuō)

bucket-domain方式代碼實(shí)現(xiàn)

首先,對(duì)象存儲(chǔ)服務(wù)提供方需要設(shè)置DNS,將<endpoint>下的子域解析到RGW或其前端的負(fù)載均衡設(shè)備。
當(dāng)HTTP請(qǐng)求到達(dá)RGW后,請(qǐng)求中會(huì)攜帶初始host請(qǐng)求信息,即<bucket-name>.<endpoint>,RGW會(huì)根據(jù)配置的domain信息,將這個(gè)host信息解析成subdomain和domain兩部分,分別對(duì)應(yīng)bucket-name和endpoint,隨后重新構(gòu)造一個(gè)request url path,格式為/<bucket-name>,至此,整個(gè)邏輯回到了最原始的以http://<endpoint>/<bucket-name>訪問(wèn)時(shí)的狀態(tài)。

int RGWREST::preprocess(struct req_state *s, RGWClientIO* cio)
{
  req_info& info = s->info;  //info中存有此次請(qǐng)求相關(guān)的信息
...
  if (info.host.size()) {        // info.host中存放的就是用戶請(qǐng)求的url domain部分
    ldout(s->cct, 10) << "host=" << info.host << dendl;
    string domain;
    string subdomain;
    bool in_hosted_domain_s3website = false;
    bool in_hosted_domain = rgw_find_host_in_domains(info.host, &domain, &subdomain, hostnames_set);
...
    if (in_hosted_domain && !subdomain.empty()) {  //重新構(gòu)建request uri
      string encoded_bucket = "/";
      encoded_bucket.append(subdomain);
      if (s->info.request_uri[0] != '/')
        encoded_bucket.append("/");
      encoded_bucket.append(s->info.request_uri);
      s->info.request_uri = encoded_bucket;
    }
...

private-domain方式代碼實(shí)現(xiàn)

首先,用戶需要將自己的域名配置一條CNAME,使對(duì)域名的請(qǐng)求跳轉(zhuǎn)到<bucket-name>.<endpoint>
當(dāng)HTTP請(qǐng)求到達(dá)RGW后,請(qǐng)求中攜帶當(dāng)host信息是<private-domain>,RGW首先查詢自己的domain配置信息,如果沒(méi)有找到和這個(gè)域名相關(guān)的內(nèi)容,則向DNS服務(wù)器請(qǐng)求,期待返回一個(gè)自己能使用的CNAME domain。

int RGWREST::preprocess(struct req_state *s, RGWClientIO* cio)
{
  req_info& info = s->info;
...
/* 這一段和bucket-domain一樣,首先嘗試在rgw已配置的domain信息中進(jìn)行解析 */
  if (info.host.size()) {
    ldout(s->cct, 10) << "host=" << info.host << dendl;
    string domain;
    string subdomain;
    bool in_hosted_domain_s3website = false;
    bool in_hosted_domain = rgw_find_host_in_domains(info.host, &domain, &subdomain, hostnames_set);

    string s3website_domain;
    string s3website_subdomain;

    if (s3website_enabled) {
      in_hosted_domain_s3website = rgw_find_host_in_domains(info.host, &s3website_domain, &s3website_subdomain, hostnames_s3website_set);
      if (in_hosted_domain_s3website) {
    in_hosted_domain = true; // TODO: should hostnames be a strict superset of hostnames_s3website?
        domain = s3website_domain;
        subdomain = s3website_subdomain;
      }
    }
...
/*解析失敗后嘗試請(qǐng)求DNS,得到CNAME后使用CNAME重新解析*/
    if (g_conf->rgw_resolve_cname
    && !in_hosted_domain
    && !in_hosted_domain_s3website) {
      string cname;
      bool found;
      int r = rgw_resolver->resolve_cname(info.host, cname, &found);
      if (r < 0) {
    ldout(s->cct, 0)
      << "WARNING: rgw_resolver->resolve_cname() returned r=" << r
      << dendl;
      }

      if (found) {
    ldout(s->cct, 5) << "resolved host cname " << info.host << " -> "
             << cname << dendl;
    in_hosted_domain =
      rgw_find_host_in_domains(cname, &domain, &subdomain, hostnames_set);
...
/* 解析成功后,后面的邏輯就又回到了bucket-domain上,即重新構(gòu)建request uri,然后就進(jìn)入了常規(guī)處理階段。*/
...

配置RGW domain信息

前面提到RGW會(huì)根據(jù)自己配置的domain信息對(duì)用戶的host進(jìn)行解析,這個(gè)domain信息是一個(gè)域名列表,列表包括RGW可以識(shí)別的domain,由于存在常規(guī)s3和s3website兩種訪問(wèn)方式,因此會(huì)有兩個(gè)domain信息配置列表

//file: src/rgw/rgw_rest.cc
static set<string> hostnames_set;
static set<string> hostnames_s3website_set;

列表初始化時(shí)會(huì)加載rgw_dns_name配置項(xiàng),但此配置項(xiàng)只能配置一條domain,因此如果需要增加多條domain(比如使用private-domain方式,但RGW又無(wú)法和解析private-domain的DNS通信的情況下),需要修改zonegroup的hostnames和hostnames_s3website配置。

radosgw-admin zonegroup get > zonegroup.conf
按需修改 zonegroup.conf文件中的hostnames和hostnames_s3website
radosgw-admin zonegroup set --infile=zonegroup.conf

總結(jié)

域名訪問(wèn)分三個(gè)方式

  • 初級(jí)方式:http://<public-cloud-domain>/<bucket-name>
  • 中級(jí)方式:http://<bucket-name>.<public-cloud-domain>
  • 高級(jí)方式:http://<private-domain>

前兩種方式比較簡(jiǎn)單,無(wú)需用戶進(jìn)行額外操作。

第三種方式需要用戶配置DNS CNAME,將請(qǐng)求轉(zhuǎn)發(fā)到http://<bucket-name>.<public-cloud-domain>上。這種場(chǎng)景需要注意的是,RGW要能夠訪問(wèn)到用戶配置了CNAME的DNS服務(wù)器,否則只能通過(guò)增加RGW domain配置信息的方式來(lái)進(jìn)行彌補(bǔ)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,973評(píng)論 19 139
  • 1. 概述 在網(wǎng)絡(luò)環(huán)境中一般用戶只需要在瀏覽器中輸入url如www.sunny.com就可以到對(duì)應(yīng)服務(wù)器獲取相應(yīng)的...
    ghbsunny閱讀 2,975評(píng)論 0 7
  • DNS(Domain Name System,域名系統(tǒng)),因特網(wǎng)上作為域名和IP地址相互映射的一個(gè)分布式數(shù)據(jù)庫(kù),能...
    一直在努力hard閱讀 4,704評(píng)論 3 19
  • 域名(Domain Name),是由一串用 點(diǎn) 分隔的名字 組成的 Internet 上某一臺(tái)計(jì)算機(jī)或計(jì)算機(jī)組的名...
    茉上心弦閱讀 2,174評(píng)論 1 11
  • 14.1 引言 域名系統(tǒng)(DNS)是一種用于TCP/IP應(yīng)用程序的分布式數(shù)據(jù)庫(kù),它提供主機(jī)名字和IP地址之間的轉(zhuǎn)換...
    張芳濤閱讀 1,929評(píng)論 0 8