본문으로 바로가기 본문 바로가기
WIKI 기술 지식 베이스

앱 서비스에 연결하기

원문 보기 위키 갱신

Fly Machine에서 실행 중인 프로세스와 통신하는 방법은 크게 두 가지가 있어요. 하나는 로드 밸런싱을 처리하는 Fly.io 구성 요소인 Fly Proxy를 통한 방법으로, 공개 웹 서비스라면 반드시 필요해요. 다른 하나는 앱이 속한 WireGuard IPv6 프라이빗 네트워크("6PN")를 통한 방법으로, 예를 들어 Fly App에 프라이빗 지원 서비스를 제공할 때 유용해요. 이 문서에서는 각 통신 수단으로 앱을 구성하는 방법과 문제 해결 방법을 설명해 드릴게요.

출처: 문서

본문

Fly Machine에서 실행 중인 프로세스와 통신하는 기본적인 방법은 두 가지예요:

  1. 로드 밸런싱을 처리하는 Fly.io 구성 요소인 Fly Proxy를 통한 방법 — 공개 웹 서비스라면 반드시 필요해요.
  2. 앱이 속한 WireGuard IPv6 프라이빗 네트워크("6PN")를 통한 방법 — 예를 들어 Fly App에 프라이빗 지원 서비스를 제공할 때 유용할 수 있어요.

TL;DR

각 수단으로 앱이 접근 가능하도록 구성하는 치트 시트예요:

Fly Proxy 내부(6PN)
바인딩 0.0.0.0:<port> (UDP 아님) fly-local-6pn:<port>
구성에 services 또는
http_service 필요?
YES NO
앱에 IP 필요? YES (Fly-Replay는 아님) NO

전체 그림에는 더 많은 내용이 있어서 이 문서의 나머지가 존재해요.

Fly Proxy로 라우팅되는 서비스

Fly App의 글로벌 Anycast 주소를 통해 공개 인터넷에서 접근할 수 있는 모든 서비스는 Fly Proxy가 라우팅해요.

Fly Proxy는 Fly App의 VM들 사이에서 공개 및 프라이빗(Flycast) 서비스 모두에 대한 요청을 로드 밸런싱할 수 있어요. Fly Proxy로 서비스에 라우팅하면 요청 트래픽의 변동에 따라 Machine을 자동으로 시작·중지하는 것 같은 다른 Fly Proxy 기능도 활성화돼요.

VM 안의 올바른 주소에서 서비스가 수신하게 하기

Fly Proxy는 각 VM의 프라이빗 IPv4 주소를 통해 서비스에 도달하므로, 프로세스는 0.0.0.0:<port>에서 수신해야 해요. (IPv4 및 IPv6 와일드카드에 대한 참고 참고)

UDP는 특별해요

UDP 서비스는 우리의 UDP 프록시 로직 작동 방식 때문에 VM에서 fly-global-services라는 다른 특정 주소에서 수신해야 해요.

Fly Proxy가 도달할 수 있도록 서비스 구성하기

공개 앱

fly.toml에서 서비스를 정의해요.(Fly Launch에 속하지 않는 독립 Machine의 경우 개별 Machine 구성에서) 서비스 정의의 internal_port가 VM 안에서 프로세스가 바인딩된 포트와 같은지 확인하세요. 이 구성이 없으면 Fly Proxy는 서비스를 인식하지 못해 라우팅할 수 없어요.

프라이빗(Flycast) 앱

공개 앱처럼 서비스를 구성하되, 추가로: Flycast는 HTTPS를 지원하지 않으므로 non-HTTPS 서비스를 정의했는지 확인하고, HTTP 서비스 정의에 force_https = true가 포함되지 않도록 하세요.

앱에 공개 또는 프라이빗 IP 할당하기

공개 앱

Fly Proxy가 공개 인터넷에서 앱으로 요청을 라우팅하게 하려면, 앱에 공개 Anycast IP를 최소 하나 프로비저닝하세요. HTTP와 HTTPS 서비스가 정의된 앱은 fly deploy의 첫 실행 시 공개 IP가 자동으로 할당돼요. fly ips list로 확인할 수 있어요.

프라이빗(Flycast) 앱

Fly Proxy가 공개가 아닌 앱의 VM들 사이에서 로드 밸런싱하게 하려면, fly ips allocate-v6 --private로 프라이빗(Flycast) IPv6 주소를 할당하고, fly ips release <address>로 앱에서 공개 IP를 제거하세요. Flycast IP는 그것이 할당된 프라이빗 네트워크 안에서만 도달할 수 있으며, 그 네트워크는 가리키는 Fly App과 같은 Fly Organization에 속해야 해요.

구성에 Fly Proxy가 라우팅할 서비스가 있고 앱에 공개 IP가 있다면, 그 서비스는 전체 인터넷에 노출돼요.

Fly App IP와 Fly-Replay 라우팅에 대한 참고

앱 전체 IP 주소(공개와 프라이빗)는 Fly Proxy에게 요청을 어떤 앱에 전달할지 알려줘요. 서비스가 Fly-Replay 응답 헤더 처리에서 Fly Proxy에 의해서만 도달 가능하면 되고, 앱의 IP는 필요하지 않아요. 앱 정보는 헤더에 직접 포함되기 때문이에요.

6PN의 프라이빗 서비스(직접 WireGuard 연결)

로드 밸런싱이나 다른 Fly Proxy 기능이 필요 없다면, VM의 6PN 주소(즉, IPv6 프라이빗 WireGuard 네트워크의 주소)로 직접 연결할 수 있어요.

기본적으로 조직의 모든 Fly App은 같은 프라이빗 네트워크에 살아요. 하지만 서로를 격리하기 위해 앱을 다른 프라이빗 네트워크에 만들 수도 있어요. 예를 들어 고객별로 별도 앱을 운영한다면 이렇게 하는 게 좋아요.

VM 안의 올바른 주소에서 서비스가 수신하게 하기

각 VM은 자체 /etc/hosts 파일에서 호스트네임 fly-local-6pn이 자신의 6PN 주소에 매핑되어 있어요. 따라서 프라이빗 네트워크를 통해 서비스를 접근 가능하게 하려면 fly-local-6pn:<port>에 바인딩하세요. IPv6 와일드카드 "주소"([::]:<port>)의 포트에 바인딩해도 작동해요.(IPv4 및 IPv6 와일드카드에 대한 참고 참고)

정말 그게 전부예요. fly.toml에서 서비스를 정의할 필요도 없고, 앱에 IP를 프로비저닝할 필요도 없어요.

서비스가 공개적으로는 작동하는데 WireGuard를 통해 직접 도달되지 않는다면, IPv6에서 수신하지 않는 것이 문제일 수 있어요.

Fly.io 내부 DNS와 6PN 주소

Fly.io는 VM의 6PN 주소를 찾기 위한 특수한 내부 DNS 서비스를 운영해요. 다양한 .internal 이름에 대한 쿼리는 6PN 주소의 AAAA 레코드 또는 앱, 네트워크, Machine에 대한 정보가 담긴 TXT 레코드를 반환해요.

내부 DNS는 요청을 타겟팅하기 위한 유용한 프리셋을 제공해요. 예를 들어 <region>.<appname>.internal 주소에 대한 DNS 쿼리는 리전 <region>에 있는 앱 <appname>의 VM 6PN 주소를 반환해요. <region>.<appname>.internal 주소로 요청을 보내면 그 VM 중 하나로 전달돼요.

프라이빗 네트워킹 문서에는 .internal 이름과 각각에 대해 DNS 쿼리가 반환하는 정보의 종류가 나열돼 있어요.

IPv4 및 IPv6 와일드카드에 대한 참고

Fly Proxy로 라우팅될 서비스는 IPv4 주소에 바인딩하고, 6PN을 통해 도달할 서비스는 위에서 설명한 대로 IPv6에 바인딩해야 해요. 하지만 우리가 지정한 주소를 사용하지 않아도 서비스가 작동하는 것을 발견할 수 있어요. VM에서 IPv4-매핑 IPv6 주소가 활성화되어 있다면, [::]에 바인딩된 서비스에 IPv4(따라서 Fly Proxy) 연결이 허용될 수 있어요. 게다가 [::] 또는 0.0.0.0 같은 와일드카드 구문은 언어, 라이브러리, 애플리케이션에 따라 IPv4와 IPv6를 모두 커버하기도 해요.

서비스 연결 문제 해결

VM 안에서 프로세스에 연결하기

VM 안에서 프로세스가 생각한 대로 동작하는지 확인하고 싶을 수 있어요. 내부적으로 실행 중인 서비스가 있어야 한다면, VM 안에서 cURL로 연결해 볼 수 있어요.(fly ssh console로 셸을 띄우세요; 아래 표의 주석 \[2] 참고) 앱의 Docker 이미지에 curl이 설치되어 있지 않다면 설치할 수 있어요. 다음에 VM이 재시작될 때(예: 다음 fly deploy 때) 지워질 거예요.

HEAD 요청(curl -I)이면 응답이 오는지 확인하기에 충분해요:

```bash cmd # curl -I http://localhost:80 ```
HTTP/1.1 200 OK
Server: nginx/1.23.4
Date: Tue, 02 May 2023 20:32:32 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 28 Mar 2023 15:01:54 GMT
Connection: keep-alive
ETag: "64230162-267"
Accept-Ranges: bytes

그 200 OK는 서비스(nginx)가 실행 중이고 예상대로 포트 80에서 수신하고 있다는 뜻이에요.

curl http://localhost:<port>로(-I를 빼고) 올바른 HTML이 서빙되는지 더 확인할 수 있어요.

cURL은 서비스가 있어야 할 곳에서 도달 가능한지 확인하는 유용한 도구예요. 네트워킹 문제를 이해하는 데 도움이 되는 몇 가지 추가 테스트가 있어요. HTTP 앱의 예제를 계속 사용할게요.

공개 또는 Flycast 서비스에 연결하기

확인할 항목 어디서 명령
예상된 주소와
포트에서 수신 중 \[1]
VM 안에서 \[2] curl -I http://0.0.0.0:<port> \[3]
Anycast로 도달 가능 \[4] 어디서나 curl -I https://<app-name>.fly.dev:443
또는
curl -IL http://<app-name>.fly.dev:80 \[5]
Flycast로 도달 가능 \[6] Flycast IP의 6PN 안에서 \[7] curl -I http://<app-name>.flycast:80
또는
curl -I 'http://[<app-flycast-ip>]:80'

프라이빗 6PN 서비스에 연결하기

확인할 항목 어디서 명령
예상된 주소와
포트에서 수신 중 \[8]
VM 안에서 \[2] curl -I http://fly-local-6pn:<port>
내부 DNS를 통해 앱에서
도달 가능
앱의 6PN 안에서 curl -I http://<app-name>.internal:<port>
특정 VM에서 도달 가능 앱의 6PN 안에서 curl -I 'http://[<vm-6pn-address>]:<port>'

\[1] 실패하면(즉 서비스에서 예상된 응답을 얻지 못하면) (a) 서비스가 예상대로 작동하지 않거나 (b) cURL이 가리킨 포트에 바인딩되지 않았거나 (c) Fly Proxy가 VM에 도달하기 위해 사용하는 IPv4 주소에 바인딩되지 않아 Fly Proxy가 라우팅할 수 없는 것입니다.

\[2] 이 서비스를 실행해야 하는 VM에서 fly ssh console로 대화형 셸을 띄우세요. fly console 명령을 사용하지 마세요. 이 명령은 앱의 Docker 이미지에서 임시 VM을 띄우지만 같은 프로세스(들)를 시작하지 않으므로 서비스가 거기서 실행되지 않아요.

\[3] UDP 서비스 제외.

\[4] 실패했지만 로컬 체크는 성공했다면, 다음으로 앱 또는 Machine 구성에 internal_port가 이 테스트에서 사용하는 <port>와 일치하는 제대로 구성된 services 또는 http_service 섹션이 있는지 확인하세요. fly ips list도 확인하세요: 앱에 IPv6 주소만 있다면 IPv4 전용 네트워크에서 도달할 수 없어요. fly ips allocate-v4 --shared로 무료 공유 IPv4 주소를 할당할 수 있어요.

\[5] Fly Proxy가 HTTP 연결을 HTTPS로 업그레이드하므로 HTTP URL은 항상 301 리다이렉트를 유발해요. cURL이 리다이렉트를 따라 무언가가 있는지 확인하게 하려면 -L 플래그를 사용하세요. 이 예제는 서비스가 관례적인 포트 80과 443에서 각각 HTTP와 HTTPS 요청을 처리하도록 구성되어 있어요. 다른 포트를 사용한다면 그걸로 대체하세요.

\[6] VM 안의 체크가 성공했는데 이 단계가 실패하면 주석 \[5]의 모든 것을 확인하고, 추가로: HTTP 서비스가 구성되어 있고 force_https가 true로 설정되지 않았는지 확인하세요. Flycast는 HTTPS 위에서는 작동하지 않아요.

\[7] Flycast IP는 두 네트워크가 같은 조직에 속한다면 가리키는 앱과 다른 프라이빗 네트워크에 할당될 수 있어요. 서비스가 Flycast를 통해 제공되도록 구성되어 있다면 앱이 다른 6PN의 서비스에 도달할 수 있게 해줘요.

\[8] 실패하면(즉 서비스에서 예상된 응답을 얻지 못하면) (a) 서비스가 예상대로 작동하지 않거나 (b) cURL이 가리킨 포트에 바인딩되지 않았거나 (c) 6PN 주소에 바인딩되지 않아 프라이빗 WireGuard 네트워크(.internal 주소 포함)에서 도달할 수 없는 것입니다.

더 알아보기 (Learn more)