Docker Pull 실패 트러블슈팅: 스페인 축구 중계권 Cloudflare IP 차단 사례

·

서론

금요일 저녁, 프로덕션 배포 파이프라인이 갑자기 멈췄다. GitLab Runner가 Docker 이미지를 pull하지 못하고 TLS 인증서 오류를 뱉어내기 시작했다. 로컬에서 직접 docker pull을 실행해도 같은 에러. Tailscale 네트워크 문제인 줄 알고 VPN 설정을 만지고, DNS 설정을 바꿔보고, Docker 데몬을 재시작해봤지만 소용없었다.

에러 메시지는 명확했다:

1
tls: failed to verify certificate: x509: certificate is not valid for any names

하지만 원인은 전혀 예상치 못한 곳에 있었다. 바로 스페인 프로축구 리그(La Liga) 경기 중계 시간이었다.

이 글에서는 스페인 법원 명령으로 인해 Docker Registry의 Cloudflare R2 스토리지 IP가 차단되면서 발생한 장애 사례를 분석하고, 유사한 네트워크 차단 이슈를 어떻게 진단하고 우회할 수 있는지 실무 관점에서 살펴본다.

본론

문제 발생 구조

GitLab CI/CD 파이프라인이 실패하는 과정을 다이어그램으로 확인해보자:

1
2
3
4
5
6
7
8
9
graph TD
    A[Git Push] --> B[GitLab Runner 실행]
    B --> C[Docker Pull 시도]
    C --> D[DNS 해석: *.r2.cloudflarestorage.com]
    D --> E[ISP 라우팅]
    E --> F{법원 차단 IP 대역?}
    F -->|Yes| G[TLS 인증서 오류 반환]
    F -->|No| H[정상 이미지 다운로드]
    G --> I[파이프라인 실패]

스페인 인터넷 서비스 제공자(ISP)는 법원 명령에 따라 특정 IP 대역을 차단한다. 문제는 Docker Hub가 이미지 메타데이터를 저장하는 Cloudflare R2 스토리지의 IP가 이 차단 대상에 포함되었다는 점이다.

에러 메시지 분석

실제 발생한 에러 메시지를 단계별로 분해해보자:

1
2
3
4
5
6
7
8
9
# 1단계: GitLab Runner 로그 확인
$ gitlab-runner exec docker my-job
ERROR: Job failed: failed to pull image "alpine:latest"

# 2단계: 직접 docker pull 실행
$ docker pull alpine:latest
error pulling image configuration: download failed after attempts=6: 
tls: failed to verify certificate: x509: certificate is not valid for any names, 
but wanted to match docker-images-prod.6aa30f8b08e16409b46e0173d6de2f56.r2.cloudflarestorage.com

이 에러의 핵심 포인트:

항목설명
에러 유형TLS 인증서 검증 실패
대상 호스트docker-images-prod.*.r2.cloudflarestorage.com
재시도 횟수6회 실패 후 포기
근본 원인ISP 수준 IP 차단으로 인한 중간자 프록시 응답

일반적인 TLS 오류라면 인증서 만료나 DNS 하이재킹을 의심하겠지만, 이 경우 ISP가 법원 명령으로 IP를 차단하면서 반환하는 차단 페이지의 인증서와 충돌하는 것이다.

원인 상세: 스페인 법원 명령의 기술적 영향

2024년 12월 18일 바르셀로나 상업법원 판결에 따라, La Liga와 Telefónica Audiovisual Digital은 불법 스트리밍 차단을 위해 특정 IP 대역 차단을 요청했다.

차단 메시지 원문:

1
2
3
El acceso a la presente dirección IP ha sido bloqueada en cumplimiento 
de lo dispuesto en la Sentencia de 18 de diciembre de 2024, dictada por 
el Juzgado de lo Mercantil nº 6 de Barcelona

번역하면: “바르셀로나 상업법원 제6부의 2024년 12월 18일 판결에 따라 해당 IP 접근이 차단되었습니다.”

문제의 심각성:

조건상황
발생 시간축구 경기 시간에만 (간헐적)
차단 방식IP 대역 전체 차단
영향 범위해당 IP를 사용하는 모든 서비스
Docker 영향이미지 메타데이터 다운로드 불가

트러블슈팅 스텝바이스텝

유사한 문제를 겪었을 때 진단하는 순서를 정리했다:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Step 1: DNS 해석 확인
$ dig docker-images-prod.6aa30f8b08e16409b46e0173d6de2f56.r2.cloudflarestorage.com

# Step 2: 해당 IP로 직접 curl 테스트
$ curl -v https://docker-images-prod.6aa30f8b08e16409b46e0173d6de2f56.r2.cloudflarestorage.com

# Step 3: TLS 인증서 정보 확인
$ openssl s_client -connect docker-images-prod.6aa30f8b08e16409b46e0173d6de2f56.r2.cloudflarestorage.com:443

# Step 4: traceroute로 차단 지점 확인
$ traceroute docker-images-prod.6aa30f8b08e16409b46e0173d6de2f56.r2.cloudflarestorage.com

curl 명령으로 차단 메시지를 직접 확인할 수 있다:

1
2
$ curl -k https://<차단된-IP> 2>&1 | head -20
# 스페인어 법원 차단 안내 페이지가 반환됨

우회 및 해결 방안

프로덕션 환경에서 이런 문제에 대응하는几种 방법을 정리했다:

방안 1: Mirror Registry 사용

1
2
3
4
5
6
7
# /etc/docker/daemon.json
{
  "registry-mirrors": [
    "https://mirror.gcr.io",
    "https://registry.docker.jp.proxy.cekit.net"
  ]
}
1
2
# daemon.json 수정 후 Docker 재시작
$ sudo systemctl restart docker

방안 2: GitLab Container Registry 프록시

1
2
3
4
5
6
# gitlab-runner config.toml
[[runners]]
  [runners.docker]
    image = "alpine:latest"
    pull_policy = ["if-not-present"]
    allowed_images = ["registry.example.com/*"]

방안 3: VPN 또는 프록시 경로 변경

1
2
3
4
5
6
7
# WireGuard VPN 설정 예시
$ wg-quick up vpn-tunnel

# 또는 HTTP 프록시 설정
$ export HTTP_PROXY=http://proxy.example.com:8080
$ export HTTPS_PROXY=http://proxy.example.com:8080
$ docker pull alpine:latest

해결 방안 비교

방안장점단점적용 시나리오
Mirror Registry투명한 우회, 설정 간편미러 동기화 지연 가능장기적 해결책
Container Registry 프록시내부 캐싱, 빠른 pull스토리지 비용 발생엔터프라이즈 환경
VPN/프록시즉시 적용 가능모든 트래픽 경로 변경임시 대응
이미지 캐싱네트워크 의존성 감소디스크 공간 필요CI/CD 안정성 향상

근본적 교훈: 인프라는 정치의 영향권 안에 있다

이 사건은 기술적 문제를 넘어선 중요한 시사점을 준다:

  1. 법적 조치의 기술적 부작용: 법원이 이해하지 못하는 인프라 의존성
  2. 간헐적 장애의 위험성: “경기 시간에만” 발생하면 원인 파악이 극도로 어려움
  3. 글로벌 서비스의 로컬 법률 영향: 클라우드 서비스가 특정 국가의 법적 제재를 받을 수 있음

결론

핵심 요약

  • 스페인 법원의 축구 불법 중계 차단 명령이 Docker Registry에서 사용하는 Cloudflare R2 스토리지 IP를 차단
  • 결과적으로 Docker pull 시 TLS 인증서 오류 발생, GitLab CI/CD 파이프라인 실패
  • 간헐적 발생(경기 시간에만)으로 원인 파악이 특히 어려웠던 특이한 장애

전문가 인사이트

이 사례는 SRE에게 몇 가지 중요한 교훈을 준다:

1. 장애 원인의 범위를 넓혀라

TLS 오류가 발생하면 보통 인증서 만료, DNS 문제, 네트워크 설정 오류만 의심한다. 하지만 ISP 수준의 법적 차단, 정부 검열, 클라우드 제공자의 규정 준수 등 외부 요인도 고려해야 한다.

2. 의존성 매핑이 필수다

Docker 이미지 pull 하나에 얽힌 의존성 체인을 파악하고 있어야 빠르게 원인을 좁힐 수 있다:

1
2
3
4
5
6
graph LR
    A[docker pull] --> B[Docker Hub API]
    B --> C[이미지 메타데이터]
    C --> D[Cloudflare R2 스토리지]
    D --> E[ISP 네트워크]
    E --> F[최종 사용자]

3. 다중 경로 확보가 생존 전략이다

단일 레지스트리, 단일 네트워크 경로에 의존하면 통제 불가능한 외부 요인에 무방비 상태가 된다. Mirror registry, 프라이빗 레지스트리 캐시, 대체 네트워크 경로를 미리 준비해야 한다.

참고 자료


이 글은 실제 HackerNews에 게시된 사례를 바탕으로 작성되었습니다. “Thank you, Spain"이라는 원작자의 탄식이 기술 커뮤니티의 공감을 얻은 이유는, 통제할 수 없는 외부 요인이 프로덕션 시스템에 미치는 영향을 모든 DevOps 엔지니어가 두려워하기 때문일 것이다.


출처: https://news.ycombinator.com/item?id=47738883