가상호스트 & 함수체인

M2는 기능적으로 HTTP 서버이며, 구조적으로는 Reverse Proxy 이다. 따라서 독립적인 서비스를 구성하는 단위는 가상호스트이다.

setting.json 파일의 hosting[] 영역에 가상호스트를 배열한다.

{
   "hosting": [
      {
         "name": "www.example.com",
         ...
      },
      {
         "name": "img.example.com",
         ...
      },
      {
         "name": "vod.example.com",
         ...
      }
   ]
}

See also

가상호스트 구성

가상호스트 생성

hosting[] 하위에 가상호스트 아이템을 추가한다.

{
   "hosting": [ ]
}

예를 들어 가상호스트 www.example.com , img.example.com 을 추가하려면 hosting[] 배열에 추가하고 설정을 반영한다.

{
   "hosting": [
      {
         "name": "www.example.com",
         "origin": {
            "address": [ "10.10.10.10" ]
         }
      },
      {
         "name": "img.example.com",
         "origin": {
            "address": [ "20.20.20.20" ]
         }
      }
   ]
}

nameorigin.address[] 구성만으로 즉시 동작하는 캐싱서비스를 생성했다.

Note

Windows 10 환경이라면 C:\Windows\System32\drivers\etc\hosts 파일에 다음과 같이 테스트할 도메인을 설정한다.

25.100.3.35        www.example.com

가상호스트 파괴

위 예제에서 삭제하려는 가상호스트(예를 들어 img.example.com )를 hosting[] 에서 제거한다.

{
   "hosting": [
      {
         "name": "www.example.com",
         "origin": {
            "address": [ "10.10.10.10" ]
         }
      }
   ]
}

삭제된 가상호스트의 모든 캐싱 콘텐츠는 즉시 삭제대상이 되며, 다시 추가해도 콘텐츠는 되살아나지 않는다. 삭제된 가상호스트를 다시 추가하는 것은 신규 가상호스트를 생성하는 것과 완전히 같다.

Note

삭제는 하지 않고 서비스를 중단하려면 hosting[].enable 설정을 false 로 변경한다.

가상호스트 찾기

다음은 가장 간단한 형태의 HTTP 요청이다.

GET / HTTP/1.1
Host: www.example.com

일반적인 웹 서버는 Host 헤더로 가상호스트를 찾는다. 하나의 가상호스트를 여러 이름으로 서비스하고 싶다면 aliases 를 사용한다.

{
   "hosting": [
      {
         "name": "www.example.com",
         "origin": {
            "address": [ "10.10.10.10" ]
         },
         "aliases": [
            "another.com",
            "*.sub.example.com"
         ]
      }
   ]
}

가상호스트 검색 순서는 다음과 같다.

  1. 가상호스트의 name 과 일치하는가?

  2. aliases 중 명시적인 아이템과 일치하는가?

  3. aliases 중 패턴 아이템과 일치하는가?

기본 가상호스트

클라이언트 HTTP 요청의 Host 헤더로부터 서비스할 가상호스트를 찾는다.

GET / HTTP/1.1
Host: foo.com

아래와 같이 meta.defaultHosting 이 지정되어 있지 않다면 404 Not Found 로 응답한다.

{
   "hosting": [
      {
         "name": "www.example.com",
         ...
      },
      {
         "name": "img.example.com",
         ...
      }
   ]
}

매칭되는 가상호스트가 없는 경우 해당 요청을 www.example.com 으로 라우팅하려면 다음과 같이 설정한다.

{
   "meta": {
      "defaultHosting": "www.example.com"
   },
   "hosting": [
      {
         "name": "www.example.com",
         ...
      },
      {
         "name": "img.example.com",
         ...
      }
   ]
}

가상호스트 IP/PORT 바인딩

HTTP/80 이나 HTTPS/443 가 아닌 임의의 주소를 바인딩하는 경우가 있다. 이런 경우 listen 설정을 통해 구성이 가능하다.

{
   "hosting": [
      {
         "name": "www.example.com",
         "listen": "*:80",
      }
   ]
}

{IP}:{Port} 형식으로 서비스 주소를 설정한다. *:80 표현은 모든 NIC로부터의 80포트로 오는 요청을 처리한다는 의미다.

예를 들어 특정 IP(1.1.1.1)의 90포트로 서비스하고 싶다면 다음과 같이 설정한다.

{
   "hosting": [
      {
         "name": "www.example.com",
         "listen": "1.1.1.1:90",
      }
   ]
}

basehost 사용하기

가상호스트를 setting.json 이 아닌 별도의 파일 단위로 생성/유지하는 것이 유용한 경우가 있다.

  • 가상호스트 단위로 설정파일을 분리/관리하고 싶은 경우

  • 유사한 서비스 설정을 템플릿화하고 싶은 경우

  • 정책적으로 여러 가상호스트가 백엔드 정보를 공유하는 경우

이런 경우 가상호스트 basehost 설정이 효과적이다.

See also

  • modebasehost 설정

다음은 사용 예제이다.

  1. 가상호스트를 별도의 파일로 분리하여 파일로 저장한다.

    {
       "name": "This file is the common image service settings.",
       "origin": {
          "address": [ "10.10.10.10", "11.11.11.11" ]
       },
       "functions": {
          "contents": {
             "dims": {
                "meta" : {
                   "enable": true
                }
             }
          }
       }
    }
    

    name 설정은 승계되지 않기 때문에 가상호스트의 목적을 정의하는 용도로 사용한다.

  2. 위 파일을 임의의 경로에 저장한다. 예제에서는 /usr/local/m2/commons/hosting_image.json 에 저장한다.

  3. setting.json 에서 해당파일을 basehost 로 지정한다.

    {
       "hosting": [
          {
             "name": "www.example.com",
             "mode": {
                "basehost": "/usr/local/m2/commons/hosting_image.json"
             }
          },
          {
             "name": "foo.com",
             "mode": {
                "basehost": "/usr/local/m2/commons/hosting_image.json"
             }
          },
          {
             "name": "bar.com",
             "mode": {
                "basehost": "/usr/local/m2/commons/hosting_image.json",
                "volatile": true
             },
             "origin": {
                "address": [ "10.10.10.10", "11.11.11.11", "12.12.12.12" ]
             }
          }
       ]
    }
    
  4. 설정관리자는 가상호스트 로딩시점에 hosting[].mode.basehost 를 전처리하여 다음과 같이 단일 setting.json 로 처리한다.

    {
      "hosting": [
         {
            "name": "www.example.com",
            "origin": {
               "address": [ "10.10.10.10", "11.11.11.11" ]
            },
            "functions": {
               "contents": {
                  "dims": {
                     "meta" : {
                        "enable": true
                     }
                  }
               }
            }
          },
          {
             "name": "foo.com",
             "origin": {
               "address": [ "10.10.10.10", "11.11.11.11" ]
             },
             "functions": {
                "contents": {
                   "dims": {
                      "meta" : {
                         "enable": true
                      }
                   }
                }
             }
          },
          {
             "name": "bar.com",
             "mode": {
                "volatile": true
             },
             "origin": {
                "address": [ "10.10.10.10", "11.11.11.11", "12.12.12.12" ]
             },
             "functions": {
                "contents": {
                   "dims": {
                      "meta" : {
                         "enable": true
                      }
                   }
                }
             }
          }
       ]
    }
    

위 예제를 통해 www.example.comfoo.com 은 동일한 설정을, bar.com 은 동일한 설정을 기반으로 originvolatile 설정을 재정의 했다.

함수체인

M2의 가장 강력한 기능은 검증된 기능의 제약없는 연결 이다. 예를 들어 아래와 같은 간단한 구성으로 example.com 캐싱서비스 구성이 가능하다.

{
   "hosting": [
      {
         "name": "www.example.com",
         "origin": {
            "address": [ "10.10.10.10" ]
         }
      }
   ]
}

그리고 다음과 같은 서비스 주소를 제공할 수 있다.

https://example.com/archive.zip

이 상태에서 아래의 복잡한 요구사항들을 레고블럭 조립하듯 함수체인을 이용해 구현할 수 있다.

  • 원본 파일은 압축된 형태로 평균용량이 1GB이다.

  • 원본 파일로부터 title.jpg 를 추출해야 한다.

  • 추출된 이미지를 최적화하여 S3에 백업해야 한다.

  • 추출된 이미지를 1024 x 768로 리사이즈한 뒤 암호화하여 클라이언트에게 전달한다.

각 단계에 해당하는 M2 함수를 나열하면 아래와 같다.

  • https://example.com/archive.zip 원본파일

  • /unzip/files/title.jpg 원본 이미지 추출

  • /dims/optimize 원본 이미지 최적화

  • /aws_s3/put/mybucket S3 백업

  • /dims/resize/1024x768 1024 x 768

  • /denc/denchunk 암호화

M2는 URL 함수를 이용해 단일 HTTP 트랜잭션으로 구동한다.

https://example.com/archive.zip/unzip/files/title.jpg/dims/optimize/aws_s3/put/mybucket/dims/resize/1024x768/denc/denchunk

이렇게 단계별로 검증된 기능은 자유도가 높지만 장황하다. 그래서 많은 경우 urlRewrites 을 통해 배포될 서비스 주소로 맵핑된다.

활성화

M2가 제공하는 다양한 서비스는 모두 functions 을 통해 제공된다. functions 하위 카테고리는 다음 기준으로 분류된다.

  • contents 원본 콘텐츠 실시간 가공 서비스

  • network 가상호스트 기반의 HTTP 캐싱서비스

  • operations 통계/로그 등 운영편의성 서비스

  • backend 고객사 백엔드 연동서비스

Note

콘텐츠 서비스는 별도의 서비스 매뉴얼을 통해 제공한다.

예를 들어 functions.network.cache 에 위치하는 캐싱엔진은 case 설정을 통해 대소문자를 구분한다. 레퍼런스 메뉴 구조에 따라 정확한 위치를 알 수 있다.

../../_images/setting_order.png

functions.network.cache.cachingKey.case.enable

setting.json 상의 전체 경로는 아래와 같다.

{
   "functions": {
      "network": {
         "cache": {
            "cachingKey": {
               "case": {
                  "enable": true
               }
            }
         }
      }
   }
}

앞으로 문서 표현상 위의 장황한 표현은 아래와 같이 축약하여 설명한다.

# functions.network.cache.cachingKey.case

"enable": true

함수 재정의

functions 의 모든 기능은 가상호스트를 통해 제공된다. 예를 들어 다음과 같이 설정하면 모든 가상호스트의 HTTP 응답에 Via 헤더가 명시된다.

{
   "functions": {
      "network": {
         "http": {
            "frontEnd": {
               "headers": {
                  "via": {
                     "enable": true
                  }
               }
            }
         }
      }
   },
   "hosting": [
      {
         "name": "www.example.com",
         ...
      },
      {
         "name": "img.example.com",
         ...
      },
   ]
}

functions 는 각 가상호스트 하위에서 재정의(Overriding)될 수 있다. 앞 선 예제에서 img.example.com 에 대해서만 Via 헤더를 제거하려면 다음과 같이 functions.network.http.frontEnd.headers.via.enable 값을 false 로 재정의한다.

{
   "functions": {
      "network": {
         "http": {
            "frontEnd": {
               "headers": {
                  "via": {
                     "enable": true
                  }
               }
            }
         }
      }
   },
   "hosting": [
      {
         "name": "www.example.com",
         ...
      },
      {
         "name": "img.example.com",
         "functions": {
            "network": {
               "http": {
                  "frontEnd": {
                     "headers": {
                        "via": {
                           "enable": false
                        }
                     }
                  }
               }
            }
         }
      }
   ]
}

위와 같이 설정하면 www.example.com 는 기본 값에 의해 Via 헤더를 제공하지만, img.example.comfunctions 재정의에 의해 Via 헤더를 제공하지 않는다.