Mac에서 컨테이너 네트워킹이 작동하는 방식
macOS는 Linux 컨테이너를 직접 실행할 수 없으므로 Mac의 모든 컨테이너 앱은 Linux 환경에서 컨테이너를 실행하고 Mac과의 트래픽을 중계합니다. 세 가지 경로가 중요합니다.
- 인바운드: Mac에 게시된 포트가 컨테이너로 전달합니다.
- 아웃바운드: 컨테이너가 인터넷, 회사 네트워크 또는 Mac의 서비스에 연결합니다.
- 이름: 컨테이너가 호스트 이름을 조회합니다.
이 경로가 Mac 자체의 네트워킹을 우회하면 VPN 경로가 적용되지 않고 내부 호스트 이름을 확인할 수 없으며 방화벽도 어떤 앱이 통신하는지 알 수 없습니다. Oxcart는 이런 일이 없도록 설계되었습니다.
아웃바운드: VPN, DNS, 방화벽이 그대로 적용됩니다
Oxcart는 컨테이너와 빌드 단계의 IPv4 및 IPv6 아웃바운드 TCP를 Mac으로 리디렉션하고, Mac은 자체 소켓으로 연결을 엽니다. VPN 클라이언트가 추가한 경로를 포함해 Mac의 라우팅 테이블이 경로를 결정합니다. Oxcart는 Mac 경로, VPN 설정, 방화벽 환경설정을 변경하지 않습니다.
주소 조회(A 및 AAAA)는 /etc/hosts와 VPN이 구성한 리졸버 선택을 포함한 macOS 시스템 리졸버를 사용하므로 회사 호스트 이름이 브라우저와 같은 방식으로 컨테이너에서도 확인됩니다. 컨테이너 이름은 해당 Docker 네트워크 범위에 유지되며 DNS는 UDP와 TCP 모두에서 작동합니다.
Little Snitch, LuLu, 엔드포인트 에이전트
네트워크 필터는 새 프로그램의 첫 연결에 대해 사용자에게 묻는 동안 약 2초간 연결을 보류하는 경우가 많습니다. Oxcart는 기다리지 않습니다. 주 연결이 확인될 때까지 대체 경로를 사용하고, 느리거나 실패한 연결은 자동으로 대체 경로로 전환하며, 세 번 연속 실패하면 연결을 30초간 중단한 뒤 다시 확인합니다. 필터에서 Oxcart를 한 번 승인하면 이후에는 해당 규칙이 적용됩니다.
인바운드: 게시된 포트
일반 Docker 구문으로 포트를 게시하세요.
# Mac loopback only (recommended for development)
docker run -d -p 127.0.0.1:8080:80 nginx
# Ephemeral host port, UDP
docker run -d -p 127.0.0.1::9000/udp my-udp-service
# IPv4 and IPv6 listeners on the Mac
docker run -d -p "[::]:8080:80" nginx 주소를 지정하지 않은 바인딩은 Mac의 모든 IPv4 주소에서 수신하므로 macOS 방화벽이 차단하지 않으면 같은 네트워크의 다른 머신에서 접근할 수 있습니다. TCP와 UDP는 같은 호스트 포트 번호를 사용할 수 있습니다. 게시된 리스너는 컨테이너가 중지되면 해제됩니다.
게시된 포트는 엔진 자체의 localhost에서도 응답하므로 컨테이너에서 실행하는 레지스트리를 푸시 대상으로 사용할 수 있습니다.
docker run -d -p 127.0.0.1:5000:5000 --name registry registry:2
docker tag my-app localhost:5000/my-app
docker push localhost:5000/my-app Ports 보기: 포트가 응답하지 않는 이유
Oxcart의 Ports 보기는 Mac의 모든 리스너와 컨테이너 포트를 저장소, 작업 트리, 브랜치별로 묶어 같은 프로젝트의 두 체크아웃을 구분합니다. 각 바인딩은 준비됨, 대기 중, 오류 상태와 함께 원인을 표시합니다.
- Mac에서 해당 주소를 이미 사용 중입니다.
- 컨테이너 내부 서버가
127.0.0.1에서만 수신합니다. - 아직 해당 포트에서 수신하는 서비스가 없습니다.
다른 머신에서 접근 가능한 포트에는 표시가 붙습니다. 코딩 에이전트도 Oxcart의 MCP ports 도구를 통해 같은 정보를 볼 수 있습니다. AI 코딩 에이전트를 위한 Docker를 참고하세요.
컨테이너에서 Mac에 접근하기
host.docker.internal은 컨테이너와 빌드 단계에서 확인되며 TCP를 통해 Mac의 127.0.0.1에 바인딩된 서비스에 접근합니다. 컨테이너를 Mac에서 네이티브로 실행 중인 데이터베이스나 개발 서버로 연결하세요.
docker run --rm curlimages/curl http://host.docker.internal:3000/health 이를 의도적으로 열린 접근 경로로 취급하세요. 실행하는 모든 컨테이너가 이 방식으로 Mac의 루프백 서비스에 접근할 수 있으므로 신뢰하지 않는 컨테이너를 실행할 때는 127.0.0.1에 인증 없는 관리 서비스를 두지 마세요.
Mac과 엔진 사이의 암호화된 연결
Mac과 Linux 사이의 트래픽은 macOS가 같은 Mac의 다른 가상화 소프트웨어와 공유하는 가상 네트워크를 통과합니다. Oxcart는 이 연결의 게시된 포트 및 아웃바운드 TCP 트래픽을 TLS 1.3(TLS_AES_128_GCM_SHA256) 안에서 전송하며, 엔진 시작마다 새로 생성한 인증서에 고정하고 시작별 256비트 bearer 토큰을 사용합니다. 유효하지 않은 토큰은 연결을 종료하며, Linux 쪽은 Mac 주소에서 오지 않은 연결을 TLS 시작 전에 닫습니다.
이 방식은 공유 네트워크의 다른 소프트웨어가 주소를 위조해 트래픽을 읽거나 주입하거나 컨테이너에 새 연결을 여는 위협에 대응합니다. 게스트 방화벽도 해당 소프트웨어가 게시되지 않은 컨테이너 포트와 내부 리졸버에 접근하지 못하게 합니다. 이 연결의 암호화에는 비용이 들며, 이는 의도적으로 선택한 비용입니다. Docker API 자체는 네트워크를 통과하지 않고 전용 Unix 소켓을 사용합니다. 게시된 포트가 없으면 Oxcart는 Mac에서 TCP나 UDP 소켓을 유지하지 않습니다.
현재 제한 사항
- 호스트 네트워크 모드(
--network host)와 IPv6 컨테이너 네트워킹은 구현되지 않았으며 컨테이너는 IPv4 주소를 사용합니다. host.docker.internal은 TCP를 전달하며 호스트 게이트웨이로의 UDP는 구현되지 않았습니다.- 게시된 TCP와 UDP는 클라이언트 주소를 보존하지 않으며 컨테이너에는 Linux 쪽이 연결 상대방으로 보입니다.
- 주소가 아닌 DNS 레코드(SRV, TXT 등)는 macOS 분할 DNS 대신 네트워크의 DHCP 리졸버를 사용합니다.
문제 해결
| 증상 | 가능한 원인 | 해결 방법 |
|---|---|---|
localhost:PORT에서 연결이 거부됨 | 서버가 컨테이너 내부의 127.0.0.1에서 수신함 | 0.0.0.0에서 수신하도록 설정하세요. Ports 보기에 이 원인이 표시됩니다 |
| "port is already allocated" | 다른 프로세스나 컨테이너가 호스트 포트를 사용 중 | 다른 호스트 포트를 선택하세요. Ports 보기에서 점유자를 확인할 수 있습니다 |
| 컨테이너에서 내부 호스트 이름을 확인할 수 없음 | 이름이 VPN의 DNS에만 존재함 | Mac에서 VPN에 연결하세요. 주소 조회는 Mac의 리졸버를 따릅니다 |
| 컨테이너에서 Mac의 개발 서버에 접근할 수 없음 | 컨테이너 내부에서 localhost를 사용함 | host.docker.internal을 사용하세요 |
| 첫 이미지 가져오기가 몇 초간 멈춤 | 네트워크 필터가 새 연결에 대한 승인을 요청 중임 | Oxcart를 한 번 승인하세요. 그동안 연결은 대체 경로를 사용합니다 |
| 팀원이 개발 포트에 접근할 수 있음 | 주소 없이 게시됨 | 127.0.0.1에 게시하세요 |
질문
Mac의 Docker 컨테이너도 제 VPN을 사용하나요?
Oxcart에서는 그렇습니다. 컨테이너의 아웃바운드 연결을 Mac 자체에서 열므로 Mac의 경로, VPN, 주소 조회용 분할 DNS, 앱별 방화벽이 적용됩니다. Oxcart는 Mac 경로, VPN 설정, 방화벽 환경설정을 변경하지 않습니다.
컨테이너에서 Mac의 서비스에 어떻게 접근하나요?
host.docker.internal을 사용하세요. Oxcart에서는 컨테이너와 빌드 단계에서 TCP를 통해 Mac의 127.0.0.1에 바인딩된 서비스에 접근합니다. --add-host mac:host-gateway로 같은 주소에 다른 이름을 지정할 수 있습니다.
컨테이너가 실행 중인데 왜 포트에 접근할 수 없나요?
보통 컨테이너 내부 서버가 게시된 포트로 접근할 수 없는 127.0.0.1에서 수신하기 때문입니다. 0.0.0.0에서 수신하도록 설정하세요. 호스트 포트를 이미 사용 중이거나 아직 수신하는 서비스가 없는 경우도 있습니다. Oxcart의 Ports 보기가 구체적인 원인을 표시합니다.
Oxcart는 Little Snitch, LuLu와 함께 작동하나요?
네. 네트워크 필터가 승인을 요청하며 Oxcart의 첫 연결을 보류하면 연결이 확인될 때까지 대체 경로를 사용하므로 동작이 중단되거나 답변을 기다리지 않습니다. 느리거나 실패한 연결은 자동으로 대체 경로로 전환됩니다.
Mac에서 컨테이너 트래픽이 암호화되나요?
Mac과 Oxcart 엔진 사이의 게시된 포트 및 아웃바운드 TCP는 TLS 1.3 안에서 전송되며 엔진 시작마다 생성한 인증서에 고정되고 시작별 256비트 토큰을 사용합니다. 이 연결을 Mac의 공유 네트워크에 있는 다른 가상화 소프트웨어로부터 보호합니다. 인터넷으로 나가는 트래픽은 HTTPS 등 앱 자체가 사용하는 방식으로 보호됩니다.
같은 네트워크의 다른 머신에서 게시된 포트에 접근할 수 있나요?
주소 없이 게시한 포트는 Mac의 모든 IPv4 주소에서 수신하므로 macOS 방화벽이 차단하지 않으면 다른 머신에서 접근할 수 있습니다. Mac 내부로 제한하려면 127.0.0.1에 게시하세요. Oxcart는 다른 머신에서 접근 가능한 포트를 표시합니다.
Oxcart는 컨테이너의 호스트 네트워킹이나 IPv6를 지원하나요?
아니요. 호스트 네트워크 모드와 IPv6 컨테이너 네트워킹은 구현되지 않았습니다. 컨테이너는 IPv4 주소를 사용하지만 "[::]:8080:80"로 IPv6에 포트를 게시할 수는 있습니다.
출처와 방법
여기에 설명된 네트워크 동작은 2026년 10월 10일 Oxcart에서 테스트했으며, 아웃바운드 TCP, DNS, 게시된 포트, 호스트 접근, Mac과 컨테이너 사이의 TLS를 포함합니다.