소개
지원 API 가 다른 Worker 가 소유한 카탈로그를 사용해야 합니다. 공개 API 를 제공된 내부 카탈로그에 연결하고, 누락된 바인딩을 재현하고 수정한 다음, 공개 엔드포인트 없이 두 서비스를 배포합니다.
본인의 Cloudflare 학습 계정과 이전 실습에서 익힌 인증, 구성 및 배포 지식을 사용합니다. 이 독립 VM 은 Node.js 22.22.0, 프로젝트 로컬 Wrangler 4.131.1, 테스트용 카탈로그 데이터가 준비된 /home/labex/project/service-binding에서 시작합니다. 이전 VM 이나 리소스는 재사용하지 않습니다. 유료 도메인, 데이터베이스 또는 유료 업그레이드는 필요하지 않으며, 소규모 요청은 일반 계정 사용량에 포함됩니다.
터미널 하나를 계속 열어 둡니다. 두 개의 로컬 프로세스를 사용하고, 이름이 고유한 임시 클라우드 Worker 두 개를 만든 뒤 연결을 확인합니다. 그런 다음 호출자와 종속 서비스를 삭제하고, VM 을 종료하기 전에 로그아웃합니다.
누락된 서비스 바인딩 재현
이 단계에서는 카탈로그 종속성이 의도적으로 구성되지 않은 공개 API 를 만듭니다. 별도로 제공된 Worker 가 테스트용 카탈로그 항목 두 개를 소유합니다. 지금은 두 프로세스 모두 이 VM 에서만 실행합니다.
cd /home/labex/project/service-binding
node --version
npx wrangler --version
cat catalog/index.js
Node 버전은 v22.22.0, Wrangler 버전은 4.131.1 이어야 합니다. 설정 과정에서 프로젝트 로컬 종속성을 설치했습니다. 다른 시스템에서 실행할 때는 이 프로젝트의 lockfile 을 사용해 npm ci를 실행합니다. 테스트용 데이터는 공개 서비스 레이블, 항목 두 개, 요청을 추적할 수 있는 선택적 테스트용 probe 쿼리 값을 반환합니다. 아무것도 저장하지 않습니다.
임시로 사용할 기본 이름을 하나 생성하고 두 리소스의 식별자를 일반 구성 파일에 기록합니다. WORKER_NAME을 계속 사용할 수 있도록 이 터미널을 열어 둡니다. 카탈로그의 main은 카탈로그 자체 구성 디렉터리를 기준으로 한 상대 경로입니다.
WORKER_NAME="labex-binding-$(openssl rand -hex 6)"
cat > wrangler.jsonc <<CONFIG
{
"name": "$WORKER_NAME",
"main": "src/index.js",
"compatibility_date": "2026-09-14",
"workers_dev": true,
"preview_urls": false,
"services": []
}
CONFIG
cat > catalog/wrangler.jsonc <<CONFIG
{
"name": "$WORKER_NAME-catalog",
"main": "index.js",
"compatibility_date": "2026-09-14",
"workers_dev": false,
"preview_urls": false,
"routes": [],
"vars": {"SERVICE_ID": "$WORKER_NAME-catalog"}
}
CONFIG
카탈로그는 workers.dev 와 Preview URL 을 모두 비활성화하고, 라우트도 설정하지 않습니다. 로컬 개발에서는 테스트를 위해 loopback 포트가 열리지만, 이것이 공개 클라우드 엔드포인트를 생성하지는 않습니다. 공개 API 의 비어 있는 services 목록이 이번 단계에서 진단할 결함입니다.
공개 핸들러를 작성합니다. /health는 다른 기능과 독립적으로 동작합니다. /catalog은 내부 호출을 수행하기 전에 바인딩이 존재하는지 확인합니다. catalog.internal은 완전한 형식의 임시 URL 이며 등록해야 하는 DNS 이름이 아닙니다. env.CATALOG이 대상 Worker 를 선택합니다. 임의의 클라이언트 헤더를 전달하지 않고, 필요한 쿼리 값만 사용해 새로운 GET 요청을 만듭니다.
cat > src/index.js <<'JS'
export default {
async fetch(request, env) {
const url = new URL(request.url);
if (url.pathname === '/health' && request.method === 'GET') {
return Response.json({status: 'ok'});
}
if (url.pathname !== '/catalog') return Response.json({error: 'not_found'}, {status: 404});
if (request.method !== 'GET') {
return Response.json({error: 'method_not_allowed'}, {status: 405, headers: {Allow: 'GET'}});
}
if (!env.CATALOG) return Response.json({error: 'catalog_binding_missing'}, {status: 503});
// This hostname completes the Request URL. The binding selects the target Worker.
const target = new URL('https://catalog.internal/catalog');
target.searchParams.set('probe', url.searchParams.get('probe') || '');
try {
return await env.CATALOG.fetch(new Request(target, {method: 'GET'}));
} catch {
return Response.json({error: 'catalog_unavailable'}, {status: 502});
}
}
};
JS
제공된 카탈로그와 API 를 서로 다른 HTTP 포트와 Inspector 포트를 사용하는 별도의 백그라운드 작업으로 시작합니다. 로그를 통해 시작 상태를 확인할 수 있으며, &를 사용하면 셸 프롬프트로 돌아옵니다.
npx wrangler dev --config catalog/wrangler.jsonc --ip 127.0.0.1 --port 8081 --inspector-port 9230 > catalog.log 2>&1 &
npx wrangler dev --config wrangler.jsonc --ip 127.0.0.1 --port 8080 --inspector-port 9231 > api.log 2>&1 &
cat catalog.log
cat api.log
두 로그에 준비 완료 메시지가 나타날 때까지 필요하면 cat 명령을 반복한 후 응답을 확인합니다.
curl -i http://127.0.0.1:8081/catalog
curl -i http://127.0.0.1:8080/health
curl -i http://127.0.0.1:8080/catalog
카탈로그는 200 상태 코드와 두 항목을 반환해야 합니다. health 요청은 200 과 {"status":"ok"}를 반환해야 하며, API 의 카탈로그 라우트는 503 과 {"error":"catalog_binding_missing"}를 반환해야 합니다. 종속 서비스는 실행 중이지만 호출자에는 종속 서비스에 접근할 수 있는 구성이 없습니다. 이 누락된 바인딩 상태에서 검증을 수행합니다.
내부 연결 선언 및 테스트
이 단계에서는 API 코드를 변경하지 않고 구성을 수정합니다. 실제 백그라운드 작업을 확인한 다음 API 프로세스만 중지합니다. 아래 예에서는 API 가 작업 2 라고 가정합니다.
jobs
kill %2
cat > wrangler.jsonc <<CONFIG
{
"name": "$WORKER_NAME",
"main": "src/index.js",
"compatibility_date": "2026-09-14",
"workers_dev": true,
"preview_urls": false,
"services": [{"binding": "CATALOG", "service": "$WORKER_NAME-catalog"}]
}
CONFIG
binding은 env.CATALOG로 사용할 수 있는 속성 이름입니다. service는 대상 Worker 에 구성된 정확한 이름입니다. 두 부분 중 하나라도 잘못 입력하면 다른 문제가 발생합니다. 속성이 없으면 명시적인 503 응답이 발생하고, 대상 서비스를 사용할 수 없으면 502 응답이나 시작/배포 오류가 발생할 수 있습니다. 바인딩 호출을 공개 fetch URL 로 바꾸지 않습니다.
npx wrangler dev --config wrangler.jsonc --ip 127.0.0.1 --port 8080 --inspector-port 9231 > api.log 2>&1 &
cat api.log
준비 완료를 확인한 뒤 바인딩 표를 살펴봅니다. Wrangler 는 이름으로 실행 중인 카탈로그를 찾고 연결 상태를 표시합니다. 연결되지 않은 경우 카탈로그 프로세스와 두 구성 이름을 확인한 다음 다시 시도합니다.
curl -i "http://127.0.0.1:8080/catalog?probe=local-check"
curl -i -X POST http://127.0.0.1:8080/catalog
curl -i http://127.0.0.1:8080/missing
첫 번째 응답은 200 이어야 하며, 카탈로그의 정확한 서비스 레이블, 두 항목, probe: local-check를 포함해야 합니다. 메서드 확인 요청은 405 를 반환하고, 존재하지 않는 라우트는 404 를 반환합니다. 두 서버가 모두 실행 중인 상태에서 검증합니다. 이 검증은 공개 API 를 통해 새 테스트 요청을 전달하고 전체 계약을 확인합니다.
바인딩은 구성 환경에 속합니다. 나중에 --env preview를 사용한다면 env.preview 아래에 완전한 services 배열을 선언하고 의도한 배포 대상에 연결해야 합니다. 서비스 바인딩은 최상위 구성에서 상속되지 않습니다. 이 실습에서는 이름이 지정되지 않은 환경 하나만 사용하며 --env를 전달하지 않습니다. 자세한 내용은 Wrangler environments와 HTTP service binding interface를 참조합니다.
내부 서비스와 공개 API 배포
이 단계에서는 동일한 연결을 본인의 학습 계정에 배포합니다. jobs에 표시된 실제 로컬 작업 두 개를 모두 중지합니다. 아래 예에서는 작업 1 과 2 라고 가정합니다.
jobs
kill %1 %2
npx wrangler login --device --browser=false --scopes account:read user:read workers_scripts:write workers_tail:read
표시된 디바이스 링크를 로그인된 브라우저에서 열고 현재 코드를 입력합니다. Wrangler 의 권한과 Background Access 를 검토한 다음, 앞에서 배운 대로 본인의 학습 계정만 선택합니다. 터미널 명령이 완료될 때까지 기다립니다.
npx wrangler whoami --json
loggedIn: true와 실제 계정 이름 및 ID 를 확인합니다. 계정이 하나만 표시되더라도 확인해야 합니다. 아래 두 명령의 YOUR_ACCOUNT_ID를 동일한 ID 로 바꾸고, 처음 생성된 이름과 바인딩은 그대로 유지합니다.
cat > catalog/wrangler.jsonc <<CONFIG
{
"name": "$WORKER_NAME-catalog",
"main": "index.js",
"compatibility_date": "2026-09-14",
"account_id": "YOUR_ACCOUNT_ID",
"workers_dev": false,
"preview_urls": false,
"routes": [],
"vars": {"SERVICE_ID": "$WORKER_NAME-catalog"}
}
CONFIG
cat > wrangler.jsonc <<CONFIG
{
"name": "$WORKER_NAME",
"main": "src/index.js",
"compatibility_date": "2026-09-14",
"account_id": "YOUR_ACCOUNT_ID",
"workers_dev": true,
"preview_urls": false,
"services": [{"binding": "CATALOG", "service": "$WORKER_NAME-catalog"}]
}
CONFIG
공개 Worker 가 선언한 종속성이 이미 존재하도록 먼저 대상 서비스를 배포합니다. 두 배포는 하나의 원자적 릴리스가 아니라 서로 독립적인 배포입니다.
npx wrangler deploy --config catalog/wrangler.jsonc
npx wrangler deploy --config wrangler.jsonc
카탈로그에는 공개 라우트가 없어야 합니다. API 는 workers.dev URL 과 CATALOG 바인딩을 출력합니다. 표시된 API URL 을 그대로 아래 변수에 입력합니다. 계정에서 이미 사용 중인 workers.dev 서브도메인을 재사용합니다. 계정을 처음 사용하는 경우 기존 서브도메인을 변경하지 않고 Wrangler 가 표시하는 사용 가능한 서브도메인 안내를 따릅니다.
API_URL="https://YOUR_WORKER.YOUR_SUBDOMAIN.workers.dev"
curl -i "$API_URL/health"
curl -i "$API_URL/catalog?probe=remote-check"
health 요청은 200 을 반환하고, 카탈로그 응답에는 probe: remote-check가 포함되어야 합니다. 최초 배포 또는 호스트 이름 전파에는 잠시 후 재시도가 필요할 수 있습니다. 503 또는 502 가 계속 발생하면 바인딩 구성과 대상 서비스의 배포 상태를 확인합니다.
동일한 학습 계정으로 Dashboard 를 열고 Compute → Workers & Pages로 이동한 다음 두 개의 정확한 이름을 찾습니다. 공개 API 의 Bindings 탭을 엽니다. 다이어그램에서 CATALOG 바인딩을 확인합니다. 아래 표에서 Name(CATALOG) 과 Value(일치하는 -catalog Worker) 를 비교합니다. 핸들러에서는 바인딩 이름이 env.CATALOG가 되고, 값은 배포된 종속 서비스를 식별합니다.

표에서 카탈로그 Worker 링크를 따라간 다음 Domains 탭을 선택합니다. 상단 breadcrumb 가 -catalog로 끝나는지 확인합니다. Worker URL 아래에서 Production 및 Preview 스위치가 모두 꺼져 있어야 합니다. Custom Domains and Routes 아래에는 다음 이미지처럼 항목이 없어야 합니다.

위 이름은 예시이므로 생성된 접미사와 계정 서브도메인을 사용합니다. 스위치가 꺼져 있다는 것은 표시된 주소가 활성화된 공개 진입점이 아니라는 의미입니다. 앞에서 성공한 API 요청은 서비스 바인딩을 통해 이 Worker 에 도달합니다. 이 확인은 읽기 전용으로 수행합니다. 내부 호출을 작동시키기 위해 공개 엔드포인트를 활성화하거나, 라우트를 추가하거나, 바인딩을 복제하지 않습니다. 검증은 계정 소유권, 배포된 서비스 바인딩, 엔드포인트 설정, 새로운 테스트 값을 사용한 원격 응답을 독립적으로 확인합니다. 이러한 엔드포인트를 비활성화해도 권한이 있는 계정 운영자가 서비스에 바인딩하거나 변경하는 것은 막지 않습니다. 이는 사용자 로그인 시스템이 아닙니다.
종속 서비스보다 먼저 호출자 삭제
이 단계에서는 인증이 유지되는 동안 임시 클라우드 Worker 두 개를 삭제합니다. 구성 파일이 리소스 목록 역할을 합니다. 삭제하기 전에 생성된 이름과 계정 ID 를 확인합니다.
cat wrangler.jsonc
cat catalog/wrangler.jsonc
먼저 공개 호출자를 삭제한 다음 내부 카탈로그를 삭제합니다. 이렇게 하면 삭제된 서비스를 가리키는 배포된 호출자가 남지 않습니다. 각 확인 메시지에서 정확한 실습 이름을 확인하고 단일 키 y를 누릅니다.
npx wrangler delete --config wrangler.jsonc
npx wrangler delete --config catalog/wrangler.jsonc
Wrangler 4.131.1 은 스크립트를 삭제한 후 레거시 Workers Sites KV 인증 오류를 보고할 수 있습니다. 권한을 확대하거나 해당 진단 메시지를 삭제 성공의 증거로 간주하지 않습니다. Workers & Pages 를 새로 고치고 검증을 수행합니다. 인증된 리소스 목록에 두 정확한 이름이 모두 없어야 합니다. 네트워크 또는 인증 오류만으로는 삭제 여부를 판단할 수 없습니다. 다른 Worker, 계정, 기존 서브도메인은 그대로 유지합니다.
실습 VM 연결 해제
이 단계에서는 두 클라우드 리소스의 삭제를 확인한 후 VM 의 인증을 제거합니다.
npx wrangler logout
npx wrangler whoami --json
명시적인 "loggedIn": false가 표시되어야 합니다. 인증되지 않은 상태에서 실행하는 명령은 0 이 아닌 종료 코드를 반환할 수 있지만, 구조화된 결과가 중요한 증거입니다. 검증을 완료한 다음 VM 을 종료합니다. Dashboard 브라우저 로그인은 별개이므로 다른 실습을 위해 로그인 상태로 유지할 수 있습니다. VM 종료만으로는 클라우드 리소스 삭제나 로그아웃을 대신할 수 없습니다.
요약
호출자의 바인딩에 등록되지 않은 실행 중인 종속 서비스를 진단하고, 정확한 서비스 이름을 선언한 다음 env.CATALOG.fetch()를 통해 요청을 전달했습니다. 로컬 및 배포 환경의 테스트 요청에서 카탈로그 식별자와 데이터를 반환했습니다. 배포된 연결을 확인하고 내부 서비스의 공개 엔드포인트를 비활성화된 상태로 유지한 뒤, 종속 서비스보다 먼저 호출자를 삭제하고 VM 연결을 해제했습니다.
서비스 바인딩을 사용하면 Worker 간 내부 연결을 명시적으로 구성할 수 있습니다. 이름이 지정된 환경은 자체 바인딩 선언이 필요하며, 로컬 연결이 된다고 해서 원격 소유권이나 엔드포인트 구성이 자동으로 확인되는 것은 아닙니다.

