모바일 네트워크, 기업 Wi-Fi 또는 통신사 테스트 환경이 IPv6-only로 전환된 뒤 가장 흔히 발생하는 문제는 ‘인터넷이 완전히 끊기는 현상’이 아닙니다. 로그인은 성공하지만 이미지 업로드가 실패하거나, 첫 요청은 정상적으로 처리되지만 재연결 시 시간 초과가 발생하거나, 오래된 인터페이스의 설정에 IPv4 주소가 하드코딩되어 있는 경우가 더 일반적입니다. 클라우드 Mac을 사용하면 이러한 간헐적 문제를 일관된 게이트로 전환할 수 있습니다. 병합할 때마다 주소 리터럴을 스캔하고, DNS64 확인 조건을 검증하며, 네트워크 테스트를 실행한 뒤 실패 당시의 증거를 보관할 수 있습니다.
먼저 게이트의 범위 정의하기
IPv6-only 호환성이 서버에서 AAAA 레코드만 제공해야 한다는 뜻은 아닙니다. 테스트 네트워크에 DNS64/NAT64가 구성되어 있다면, 도메인 이름을 사용하고 시스템 리졸버에 처리를 맡기는 클라이언트는 IPv4만 제공하는 서비스에도 계속 접근할 수 있습니다. 실제로 위험한 경우는 클라이언트가 시스템 확인 절차를 우회할 때입니다. 예를 들어 확인된 IPv4 주소를 캐시하거나, AF_INET 사용을 강제하거나, 192.0.2.10 같은 주소를 비즈니스 설정에 직접 입력하는 경우입니다.
게이트는 다음 세 계층으로 나누는 것이 좋습니다.
| 계층 | 검사 항목 | 실패 시 보관할 항목 |
|---|---|---|
| 정적 검사 | IPv4 리터럴, 주소 패밀리 상수, 직접 작성한 소켓 | 파일 이름과 줄 번호 |
| 환경 사전 검사 | DNS, 기본 경로, 대상 도메인 확인 | scutil 출력과 확인 결과 |
| 동작 테스트 | 로그인, 업로드, 재시도, 장기 연결 복구 | 테스트 로그와 결과 번들 |
ping성공 여부를 비즈니스 승인 기준으로 사용하지 마세요. 실제 애플리케이션은 HTTPS, WebSocket 또는 파일 업로드를 사용하며, 요청 경로와 시간 초과 정책, 연결 재사용 방식에 따라 결과가 달라질 수 있습니다.
저장소의 IPv4 가정 스캔하기
먼저 CI 작업 공간에서 보수적으로 스캔합니다. 아래 표현식은 후보를 찾기 위한 용도일 뿐이며, 모든 검색 결과를 곧바로 결함으로 판단해서는 안 됩니다. 테스트 픽스처, 문서, 루프백 주소는 정상적인 콘텐츠일 수 있기 때문입니다.
set -euo pipefail
mkdir -p artifacts/ipv6
rg -n \
--glob '*.{swift,m,mm,h,plist,json,yaml,yml,xcconfig}' \
'([0-9]{1,3}\.){3}[0-9]{1,3}|AF_INET([^6]|$)|sockaddr_in([^6]|$)' \
. | tee artifacts/ipv6/ipv4-candidates.txt
if rg -n \
--glob 'Sources/**' \
--glob 'Config/**' \
'https?://([0-9]{1,3}\.){3}[0-9]{1,3}' .; then
echo "Production configuration contains an IPv4 URL" >&2
exit 1
fi
후보 목록은 한 번 수동으로 분류한 뒤, 허용할 항목을 설명이 포함된 허용 목록에 추가해야 합니다. Tests 디렉터리 전체를 제외해서는 안 됩니다. 테스트 도우미 코드가 실제 네트워크 계층으로 복사될 수도 있기 때문입니다. C 또는 Objective-C 래퍼에서는 getaddrinfo의 ai_family가 AF_UNSPEC을 사용하는지 중점적으로 확인합니다. 단일 주소 패밀리가 명시적으로 필요한 경우에만 값을 고정해야 합니다.
잘못된 수정 피하기
IPv4 주소를 기계적으로 IPv4-mapped IPv6 주소로 바꾸거나 NAT64 접두사를 직접 조합하지 마세요. 접두사는 현재 네트워크에 따라 결정되므로 하드코딩하면 다른 네트워크에서 작동하지 않습니다. 올바른 방법은 도메인 이름을 유지하고 연결할 때 시스템 리졸버가 현재 사용 가능한 주소를 반환하도록 하는 것입니다.
DNS64 조건을 사전 검사로 만들기
테스트를 시작하기 전에 네트워크 상태를 기록하여 환경 자체가 조건을 충족하지 못할 때 대량의 오탐이 발생하지 않도록 합니다. 클라우드 Mac의 실행 노드는 팀에서 미리 준비한 통제된 DNS64/NAT64 네트워크를 사용해야 합니다. CI 스크립트는 조건만 검증하며, 작업 도중 시스템 네트워크 설정을 임시로 변경하지 않습니다.
set -euo pipefail
OUT="artifacts/ipv6"
mkdir -p "$OUT"
scutil --dns > "$OUT/scutil-dns.txt"
route -n get default > "$OUT/default-route.txt" 2>&1 || true
dscacheutil -q host -a name api.test.example \
> "$OUT/target-resolution.txt"
if ! grep -Eq 'ipv6_address|ip_address' "$OUT/target-resolution.txt"; then
echo "Target hostname did not resolve in the test environment" >&2
exit 2
fi
테스트 도메인은 팀이 직접 관리하는 통제된 환경에 속해야 하며, 민감한 정보가 없는 안정적인 상태 확인 응답을 반환해야 합니다. 공개 웹페이지를 게이트의 의존 대상으로 사용하지 마세요. 외부 요청 제한, 인증서 변경 또는 지역별 정책 때문에 빌드 결과의 결정성이 훼손될 수 있습니다.
URLSession으로 실제 동작 검증하기
네트워크 테스트는 ‘첫 시도 성공’과 ‘실패 후 복구’라는 두 경로를 모두 다뤄야 합니다. 요청에는 유한한 시간 초과를 설정하고, 기본 URL은 의존성 주입으로 전달하여 테스트 코드에 주소가 다시 하드코딩되지 않도록 해야 합니다.
import XCTest
final class IPv6ReadinessTests: XCTestCase {
func testHealthEndpointReturnsExpectedStatus() async throws {
let value = try XCTUnwrap(
ProcessInfo.processInfo.environment["TEST_BASE_URL"]
)
let baseURL = try XCTUnwrap(URL(string: value))
let url = baseURL.appending(path: "health")
let configuration = URLSessionConfiguration.ephemeral
configuration.timeoutIntervalForRequest = 15
configuration.timeoutIntervalForResource = 30
let session = URLSession(configuration: configuration)
let (_, response) = try await session.data(from: url)
let http = try XCTUnwrap(response as? HTTPURLResponse)
XCTAssertEqual(http.statusCode, 200)
}
}
실행할 때는 테스트 계획, 시뮬레이터 모델, 결과 디렉터리를 고정합니다.
set -o pipefail
xcodebuild test \
-workspace App.xcworkspace \
-scheme AppNetworkTests \
-testPlan IPv6Readiness \
-destination 'platform=iOS Simulator,name=iPhone 16' \
-resultBundlePath artifacts/ipv6/IPv6Readiness.xcresult \
TEST_BASE_URL='https://api.test.example/' \
| tee artifacts/ipv6/xcodebuild.log
서비스에 업로드와 장기 연결 기능이 포함되어 있다면 작은 파일 업로드, 연결 중단 후 지수 백오프, 전경과 백그라운드 전환 후 복구 테스트도 추가합니다. 단언은 비즈니스 결과를 기준으로 해야 하며, 현지화된 오류 문구에 의존해서는 안 됩니다.
실패 시 진단 가능한 증거 보관하기
게이트가 실패하면 최소한 정적 스캔 결과, DNS 상태, 대상 확인 결과, xcodebuild 로그, xcresult를 보관해야 합니다. 로그에는 토큰, 요청 본문 또는 전체 인증 헤더를 기록하지 마세요. 요청 정보를 출력해야 한다면 메서드, 민감 정보가 제거된 경로, 상태 코드, 재시도 횟수, 오류 도메인만 기록합니다.
문제 해결 순서는 다음과 같이 고정할 수 있습니다.
- 환경 사전 검사를 통과했는지, 대상 도메인이 시스템에서 확인되었는지 점검합니다.
- 실패한 요청이 확인 후 캐시된 주소가 아니라 도메인 이름을 사용하는지 확인합니다.
- 하위 라이브러리가
AF_INET으로 제한되어 있거나 IPv4 소켓을 직접 생성하는지 확인합니다. - 최초 연결 경로와 재연결 경로를 비교하여 두 경로가 동일한 확인 전략을 사용하는지 점검합니다.
- 통제된 DNS64/NAT64 네트워크에 연결된 실제 기기에서 핵심 흐름을 다시 검증합니다.
시뮬레이터 게이트는 빈번한 회귀 검사를 담당하고, 실제 기기는 출시 전 최종 확인을 담당합니다. 두 역할을 분리하면 일상적인 빌드가 수동 작업에 의존하지 않아도 되며, 네트워크 팀도 보관된 증거를 바탕으로 문제가 이름 확인, 연결 또는 비즈니스 재시도 계층 중 어디에 있는지 판단할 수 있습니다. VPSGit의 실행 노드는 도구 체인, 테스트 계획, 환경 변수를 일관되게 유지하기만 하면 됩니다. 그러면 사용자 신고가 접수된 뒤 현장을 임시로 재현하는 대신 이 검사를 지속적으로 반복할 수 있습니다.
자주 묻는 질문
도메인 이름만 사용하면 IPv6-only 네트워크와 자동으로 호환되나요?
아닙니다. 서버가 DNS64/NAT64 경로에서 접근 가능해야 하며, 앱이 IPv4 주소를 캐시하거나 AF_INET을 강제하거나 시스템 이름 해석을 우회해서도 안 됩니다.
iOS 시뮬레이터 테스트만으로 충분한가요?
시뮬레이터는 지속 회귀에 적합하지만 출시 전에는 통제된 DNS64/NAT64 네트워크의 실제 기기에서 로그인, 업로드, 콜백과 장기 연결 복구를 확인해야 합니다.
다음 빌드 또는 추론 작업을 위한 클라우드 Mac 구성
세 가지 Apple Silicon 구성, 여섯 개 노드와 고정 대여 기간 중에서 선택할 수 있으며, 실제 사용 가능 여부는 콘솔에서 실시간으로 확인됩니다.