Docker 29에서 사라진 inspect 최상위 IPAddress 필드
컨테이너를 하나 띄우면 그 IP 로 DNS A레코드를 잡아 두는 구조입니다. 사용자는 그 이름으로 자기 환경에 접속합니다.
보안 인증 요건 때문에 이 환경을 다른 클라우드에 새로 구축하면서 Docker 를 29 로 올렸는데, 그 직후부터 컨테이너 생성이 매번 실패하고 롤백됐습니다. 컨테이너는 실제로 만들어졌다가 2~3초 뒤에 자동으로 지워집니다.
증상 — 빈 IP로 DNS 등록 실패
DNS 등록이 3번 다 실패하면 컨테이너를 롤백하게 돼 있는데, 로그를 보니 등록 API 가 “IP 가 빈 문자열” 이라며 거절하고 있었습니다.
컨테이너의 IP 를 직접 확인해 봤습니다.
$ docker inspect <container> --format '{{.NetworkSettings.IPAddress}}'
template parsing error: map has no entry for key "IPAddress"
값이 비어 있는 게 아니라 키 자체가 없습니다.
원인 — 29부터 제거된 최상위 IPAddress
Docker 29(API 1.55)부터 컨테이너 inspect 응답에서 레거시 최상위 필드인
NetworkSettings.IPAddress / Gateway / MacAddress 가 완전히 제거됐습니다.
이제 IP 는 네트워크별 맵 안에만 있습니다.
NetworkSettings.Networks["bridge"].IPAddress ← 여기에만 있음
문제를 키운 건 클라이언트 쪽이었는데, 오래된 go-dockerclient 로 응답을
역직렬화하면 없어진 필드가 에러가 아니라 빈 문자열로 채워집니다. 그러니
코드는 아무 문제 없이 돌면서 빈 IP 를 그대로 DNS 등록에 넘겼고, 등록만 조용히
실패한 겁니다. “필드가 사라졌다” 는 신호가 어디에도 안 뜹니다.
해결 — 데몬 버전 보고 backfill
없어진 최상위 필드를, 네트워크 맵에서 끌어와 채워 넣었습니다. 처음엔 “비어 있으면 채운다” 는 조건만 뒀는데, 어느 버전부터 이 처리가 필요한지 코드만 봐서는 알 수 없습니다. 그래서 데몬의 메이저 버전을 직접 조회해서 분기하게 했습니다.
const DOCKER_MAJOR_VERSION_CHANGED = 29
// 데몬 버전은 최초 1회만 조회해서 캐시(sync.Once).
// 조회·파싱 실패 시 안전한 쪽(29 이상으로 취급 → backfill 수행)으로 폴백.
func (c *Container) Inspect(id string) (*docker.Container, error) {
// ... docker inspect ...
if c.dockerMajorVersion() >= DOCKER_MAJOR_VERSION_CHANGED {
if bridge, ok := container.NetworkSettings.Networks["bridge"]; ok {
if container.NetworkSettings.IPAddress == "" {
container.NetworkSettings.IPAddress = bridge.IPAddress
}
}
}
return container, nil
}
Docker 29 미만에서는 이 분기를 아예 안 타므로 기존 동작이 그대로 유지되고,
29 이상에서만 backfill 이 돕니다. client.Version() 으로 데몬에 물어본 버전
문자열(“29.6.1” 등)의 메이저 숫자만 떼어 비교합니다.
사라진 필드와 빈 값 — 메이저 업그레이드에서 걸리는 지점
메이저 버전 업그레이드는 API 응답에서 필드를 조용히 빼기도 합니다. 그리고
느슨하게 역직렬화하는 오래된 클라이언트는 사라진 필드를 에러가 아니라 빈
값으로 받아서, 문제가 훨씬 뒤에서(여기선 DNS 등록 실패로) 터집니다. 원인을
값이 비어서 실패하는 것 같으면 --format 으로 그 키가 응답에 있기는 한지부터
확인합니다. “값이 비었다” 와 “키가 없다” 는 원인이 완전히 다릅니다.
그리고 버전에 따라 응답 구조가 바뀌는 의존성은, 필드가 비었는지로 분기하지 말고 데몬 버전을 직접 물어보고 분기합니다. 그래야 어느 버전부터 이 처리가 필요한지가 코드에 남습니다.
댓글 0