본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 11. 26. · 2 Views
Docker 네트워크 기초 완벽 가이드
Docker 컨테이너들이 서로 통신하는 방법을 알아봅니다. 네트워크 드라이버의 종류부터 실제 컨테이너 간 통신 설정까지, 초보자도 쉽게 따라할 수 있도록 설명합니다.
목차
1. Docker 네트워크 드라이버 종류
김개발 씨는 오늘 처음으로 여러 개의 컨테이너를 동시에 띄워야 하는 프로젝트를 맡았습니다. 웹 서버와 데이터베이스를 각각 컨테이너로 실행했는데, 문제가 생겼습니다.
웹 서버에서 데이터베이스에 접속이 안 되는 것입니다. "분명히 둘 다 잘 실행되고 있는데, 왜 서로 통신이 안 되는 거지?"
Docker 네트워크 드라이버는 컨테이너들이 서로 통신하는 방식을 결정하는 핵심 요소입니다. 마치 도시의 도로망처럼, 어떤 도로를 선택하느냐에 따라 목적지까지 가는 방법이 달라지는 것과 같습니다.
Docker는 bridge, host, none, overlay, macvlan 등 다양한 네트워크 드라이버를 제공하며, 각각의 용도와 특성이 다릅니다.
다음 코드를 살펴봅시다.
# 현재 Docker에 존재하는 네트워크 목록 확인
docker network ls
# 출력 예시:
# NETWORK ID NAME DRIVER SCOPE
# a1b2c3d4e5f6 bridge bridge local
# g7h8i9j0k1l2 host host local
# m3n4o5p6q7r8 none null local
# 특정 네트워크의 상세 정보 확인
docker network inspect bridge
# 새로운 네트워크 생성 (기본 bridge 드라이버 사용)
docker network create my-network
김개발 씨는 입사 6개월 차 백엔드 개발자입니다. 오늘 팀장님이 새로운 미션을 주셨습니다.
"이번 프로젝트는 Docker로 개발 환경을 구축해야 해요. 웹 서버, API 서버, 데이터베이스를 각각 컨테이너로 띄워주세요." 김개발 씨는 열심히 각 컨테이너를 실행했습니다.
그런데 이상한 일이 벌어졌습니다. 각 컨테이너는 잘 실행되는데, 서로 통신이 되지 않는 것입니다.
localhost로 접속해도 안 되고, IP 주소를 직접 입력해도 연결이 끊기기 일쑤였습니다. 선배 개발자 박시니어 씨가 다가와 물었습니다.
"혹시 네트워크 설정 확인해봤어요? Docker 컨테이너들은 네트워크 드라이버에 따라 통신 방식이 완전히 달라져요." 그렇다면 네트워크 드라이버란 정확히 무엇일까요?
쉽게 비유하자면, 네트워크 드라이버는 마치 아파트 단지의 통신 시스템과 같습니다. 어떤 아파트는 인터폰으로만 통화할 수 있고, 어떤 아파트는 외부 전화도 바로 연결됩니다.
또 어떤 아파트는 아예 전화선이 없는 경우도 있습니다. Docker 네트워크 드라이버도 마찬가지로, 컨테이너가 어떤 방식으로 다른 컨테이너나 외부 세계와 소통할지를 결정합니다.
Docker는 기본적으로 세 가지 네트워크를 자동으로 생성합니다. bridge, host, 그리고 none입니다.
bridge 네트워크는 가장 많이 사용되는 기본 네트워크입니다. 컨테이너를 실행할 때 별도로 네트워크를 지정하지 않으면 자동으로 이 bridge 네트워크에 연결됩니다.
마치 아파트 단지 내부의 내선 전화망과 같습니다. 같은 단지 내에서는 자유롭게 통화할 수 있지만, 외부와 통화하려면 별도의 설정이 필요합니다.
host 네트워크는 컨테이너가 호스트 머신의 네트워크를 그대로 사용합니다. 별도의 네트워크 격리 없이, 마치 호스트 머신에서 직접 프로그램을 실행한 것처럼 동작합니다.
none 네트워크는 말 그대로 네트워크가 없는 상태입니다. 완전히 격리된 환경이 필요할 때 사용합니다.
위의 코드에서 docker network ls 명령어를 실행하면 현재 Docker에 존재하는 모든 네트워크 목록을 확인할 수 있습니다. DRIVER 컬럼에서 각 네트워크가 어떤 드라이버를 사용하는지 알 수 있습니다.
docker network inspect 명령어를 사용하면 특정 네트워크의 상세 정보를 JSON 형태로 확인할 수 있습니다. 어떤 컨테이너가 이 네트워크에 연결되어 있는지, IP 대역은 어떻게 되는지 등의 정보를 볼 수 있습니다.
실제 현업에서는 프로젝트의 요구사항에 따라 적절한 네트워크 드라이버를 선택해야 합니다. 대부분의 경우 bridge 네트워크로 충분하지만, 성능이 중요한 경우 host 네트워크를, 보안이 중요한 경우 사용자 정의 네트워크를 고려해야 합니다.
박시니어 씨의 설명을 들은 김개발 씨는 고개를 끄덕였습니다. "아, 그래서 그냥 컨테이너만 띄워서는 안 되는 거였군요.
네트워크 구조를 먼저 이해해야 하는 거네요!"
실전 팁
💡 - docker network ls 명령어로 현재 네트워크 상태를 항상 먼저 확인하세요
- 프로젝트 시작 전에 어떤 네트워크 구조가 필요한지 미리 설계하는 것이 좋습니다
2. Bridge 네트워크 이해
김개발 씨가 docker network ls를 실행해보니 bridge라는 네트워크가 기본으로 있었습니다. "이 bridge 네트워크가 뭐길래 모든 컨테이너가 여기에 연결되는 거지?" 궁금증이 생긴 김개발 씨는 bridge 네트워크에 대해 더 깊이 파고들기로 했습니다.
Bridge 네트워크는 Docker의 기본 네트워크 드라이버입니다. 마치 회사 내부의 사설 네트워크처럼, 같은 bridge 네트워크에 연결된 컨테이너들은 서로 자유롭게 통신할 수 있습니다.
Docker는 가상의 네트워크 브릿지(docker0)를 만들고, 각 컨테이너에 고유한 IP 주소를 할당합니다.
다음 코드를 살펴봅시다.
# 기본 bridge 네트워크 상세 정보 확인
docker network inspect bridge
# 컨테이너 실행 시 자동으로 bridge 네트워크에 연결됨
docker run -d --name web nginx
# 컨테이너의 IP 주소 확인
docker inspect web --format '{{.NetworkSettings.IPAddress}}'
# 출력 예시: 172.17.0.2
# 다른 컨테이너에서 해당 IP로 통신 가능
docker run --rm alpine ping -c 3 172.17.0.2
# 호스트에서 docker0 인터페이스 확인 (Linux)
ip addr show docker0
김개발 씨는 bridge 네트워크의 정체가 궁금해졌습니다. 인터넷에서 검색해보니 "가상 브릿지", "docker0 인터페이스" 같은 용어들이 나왔지만, 솔직히 무슨 말인지 잘 이해가 되지 않았습니다.
박시니어 씨에게 다시 도움을 요청했습니다. "선배님, bridge 네트워크가 정확히 뭔가요?
왜 이름이 bridge인 거죠?" 박시니어 씨가 화이트보드에 그림을 그리며 설명을 시작했습니다. "bridge라는 이름은 실제 네트워크 장비에서 따온 거예요.
네트워크 브릿지는 여러 네트워크 세그먼트를 하나로 연결해주는 장치거든요." 쉽게 비유하자면, bridge 네트워크는 마치 아파트 단지 내의 내선 전화 교환기와 같습니다. 각 세대(컨테이너)에는 고유한 내선 번호(IP 주소)가 부여됩니다.
같은 단지 내에서는 내선 번호만 누르면 바로 통화가 가능합니다. 하지만 외부와 통화하려면 교환기를 거쳐 외부 회선으로 연결해야 합니다.
Docker를 설치하면 docker0라는 가상 네트워크 인터페이스가 자동으로 생성됩니다. 이것이 바로 bridge 역할을 합니다.
컨테이너가 실행되면 Docker는 이 docker0에 연결되는 가상 네트워크 인터페이스를 컨테이너 내부에 만들어줍니다. 위 코드에서 nginx 컨테이너를 실행하면 자동으로 bridge 네트워크에 연결됩니다.
docker inspect 명령어로 확인해보면 172.17.0.2 같은 IP 주소가 할당된 것을 볼 수 있습니다. Docker의 기본 bridge 네트워크는 보통 172.17.0.0/16 대역을 사용합니다.
같은 bridge 네트워크에 있는 다른 컨테이너에서는 이 IP 주소로 직접 통신할 수 있습니다. alpine 컨테이너에서 ping을 실행해보면 정상적으로 응답이 오는 것을 확인할 수 있습니다.
하지만 여기서 주의할 점이 있습니다. 기본 bridge 네트워크에서는 컨테이너 이름으로 통신할 수 없습니다.
오직 IP 주소로만 통신이 가능합니다. 이것은 기본 bridge 네트워크의 중요한 제한사항입니다.
왜 이것이 문제가 될까요? 컨테이너를 재시작하면 IP 주소가 바뀔 수 있기 때문입니다.
오늘 172.17.0.2였던 컨테이너가 내일은 172.17.0.5가 될 수도 있습니다. IP 주소를 하드코딩해놓으면 언젠가 문제가 생길 수밖에 없습니다.
실무에서는 이 문제 때문에 기본 bridge 네트워크보다 사용자 정의 bridge 네트워크를 더 많이 사용합니다. 사용자 정의 네트워크에서는 컨테이너 이름으로 DNS 조회가 가능하기 때문입니다.
이 내용은 뒤에서 더 자세히 다루겠습니다. 김개발 씨가 물었습니다.
"그러면 기본 bridge 네트워크는 왜 존재하는 거예요?" 박시니어 씨가 대답했습니다. "빠르게 테스트할 때는 편하거든요.
하지만 실제 서비스에서는 반드시 사용자 정의 네트워크를 만들어서 사용해야 해요."
실전 팁
💡 - 기본 bridge 네트워크는 테스트용으로만 사용하고, 프로덕션에서는 사용자 정의 네트워크를 사용하세요
- 컨테이너 IP는 변경될 수 있으므로 하드코딩하지 마세요
3. Host와 None 네트워크
박시니어 씨가 덧붙였습니다. "bridge 말고도 host와 none 네트워크가 있어요.
특수한 상황에서 사용하는 건데, 알아두면 유용해요." 김개발 씨는 메모장을 꺼내들었습니다. 이 세 가지 네트워크의 차이점을 확실히 정리해두고 싶었습니다.
Host 네트워크는 컨테이너가 호스트 머신의 네트워크를 직접 사용하는 모드입니다. 네트워크 격리가 없어지므로 성능은 좋지만 보안에 주의해야 합니다.
None 네트워크는 네트워크 기능을 완전히 비활성화합니다. 외부와 단절된 환경이 필요할 때 사용합니다.
다음 코드를 살펴봅시다.
# Host 네트워크로 nginx 실행 (Linux에서만 완전히 동작)
docker run -d --network host --name web-host nginx
# 포트 매핑 없이 바로 localhost:80으로 접속 가능
# None 네트워크로 컨테이너 실행
docker run -d --network none --name isolated alpine sleep 3600
# 네트워크 인터페이스 확인 - lo(loopback)만 존재
docker exec isolated ip addr
# 출력: lo 인터페이스만 보임, eth0 없음
# Host 모드에서는 호스트의 모든 포트에 직접 바인딩
docker run --rm --network host alpine netstat -tuln
김개발 씨는 bridge 네트워크를 이해했습니다. 그런데 docker network ls를 실행했을 때 host와 none이라는 네트워크도 보였습니다.
이것들은 언제 사용하는 걸까요? 박시니어 씨가 설명을 이어갔습니다.
"host와 none은 특수한 목적을 위한 네트워크야. 자주 쓰이진 않지만, 필요한 순간이 분명히 있어." 먼저 host 네트워크에 대해 알아봅시다.
이것은 마치 원룸에 사는 것과 같습니다. 아파트 단지(bridge)에 살면 단지 내 규칙을 따라야 하고, 외부와 연락하려면 관리사무소(NAT)를 거쳐야 합니다.
하지만 원룸은 다릅니다. 바로 도로에 면해 있어서 별도의 중개 없이 외부와 직접 소통할 수 있습니다.
host 네트워크를 사용하면 컨테이너는 호스트 머신의 네트워크 스택을 그대로 공유합니다. 별도의 IP 주소 할당이나 포트 매핑이 필요 없습니다.
nginx를 host 모드로 실행하면 호스트의 80번 포트에 바로 바인딩됩니다. 이 방식의 장점은 성능입니다.
네트워크 변환 과정(NAT)이 없으므로 네트워크 지연이 최소화됩니다. 초당 수만 건의 요청을 처리해야 하는 고성능 서비스에서 유용합니다.
하지만 단점도 분명합니다. 네트워크 격리가 사라지므로 보안 위험이 커집니다.
또한 같은 포트를 사용하는 여러 컨테이너를 동시에 실행할 수 없습니다. 호스트의 80번 포트는 하나뿐이니까요.
중요한 점은 host 네트워크가 Linux에서만 완전하게 동작한다는 것입니다. macOS나 Windows의 Docker Desktop에서는 Docker가 가상 머신 위에서 돌아가기 때문에 host 모드의 효과가 제한적입니다.
다음은 none 네트워크입니다. 이것은 마치 무인도에 혼자 사는 것과 같습니다.
외부와의 연결이 완전히 차단됩니다. 컨테이너 내부에서 ip addr을 실행해보면 loopback 인터페이스(lo)만 존재하고, 외부와 통신할 수 있는 eth0 같은 인터페이스는 없습니다.
언제 이런 완전한 격리가 필요할까요? 보안이 극도로 중요한 배치 작업을 실행할 때가 대표적입니다.
예를 들어, 외부에서 받은 파일을 처리하는 작업이 있다고 합시다. 만약 그 파일에 악성 코드가 숨어 있다면?
none 네트워크를 사용하면 설령 악성 코드가 실행되더라도 외부로 데이터를 유출할 방법이 없습니다. 김개발 씨가 고개를 끄덕였습니다.
"그러니까 bridge는 일반적인 용도, host는 성능이 중요할 때, none은 보안이 중요할 때 사용하는 거네요?" 박시니어 씨가 미소 지었습니다. "정확해요.
대부분의 경우 bridge로 충분하지만, 특수한 요구사항이 있을 때 host와 none을 고려하면 돼요."
실전 팁
💡 - host 네트워크는 Linux 환경에서 성능이 중요한 서비스에 사용하세요
- none 네트워크는 외부와 완전히 격리해야 하는 보안 민감한 작업에 적합합니다
4. 사용자 정의 네트워크 생성
김개발 씨가 기본 bridge 네트워크의 한계를 알게 되었습니다. "컨테이너 이름으로 통신할 수 없다니, 실무에서는 정말 불편하겠네요." 박시니어 씨가 고개를 끄덕였습니다.
"그래서 우리는 항상 사용자 정의 네트워크를 만들어서 사용해요. 이게 Docker 네트워크의 핵심이에요."
사용자 정의 네트워크는 docker network create 명령으로 생성하는 커스텀 네트워크입니다. 기본 bridge와 달리 자동 DNS 해석을 지원하여 컨테이너 이름으로 서로 통신할 수 있습니다.
또한 네트워크 격리를 통해 보안도 향상됩니다.
다음 코드를 살펴봅시다.
# 사용자 정의 bridge 네트워크 생성
docker network create my-app-network
# 네트워크 목록에서 확인
docker network ls
# 네트워크에 연결된 컨테이너 실행
docker run -d --name db --network my-app-network mysql:8
docker run -d --name api --network my-app-network my-api-image
# 컨테이너 이름으로 통신 가능 (DNS 자동 해석)
docker exec api ping -c 3 db
# 출력: PING db (172.18.0.2): 56 data bytes ...
# 기존 컨테이너를 네트워크에 연결
docker network connect my-app-network existing-container
# 네트워크에서 연결 해제
docker network disconnect my-app-network existing-container
김개발 씨는 이제 문제의 핵심을 이해했습니다. 기본 bridge 네트워크에서는 IP 주소로만 통신할 수 있고, IP는 언제든 바뀔 수 있습니다.
이것은 실무에서 큰 문제입니다. 웹 서버의 설정 파일에 database_host=172.17.0.3이라고 적어뒀다고 생각해봅시다.
데이터베이스 컨테이너를 재시작하면 IP가 바뀔 수 있습니다. 그러면 웹 서버는 더 이상 데이터베이스에 접속하지 못합니다.
매번 IP를 확인하고 설정을 바꿔야 한다면 정말 피곤한 일입니다. 사용자 정의 네트워크는 이 문제를 깔끔하게 해결합니다.
마치 사내 전화번호부와 같습니다. "김개발 씨 좀 바꿔주세요"라고 하면 교환원이 알아서 연결해줍니다.
김개발 씨가 자리를 옮겨도 전화번호부만 업데이트되면 됩니다. 전화를 거는 사람은 항상 "김개발 씨"라고만 말하면 됩니다.
docker network create my-app-network 명령으로 새 네트워크를 만들면, Docker는 내장 DNS 서버를 함께 구성합니다. 이 네트워크에 연결된 컨테이너들은 서로의 이름을 DNS로 조회할 수 있습니다.
위 코드에서 db라는 이름의 MySQL 컨테이너와 api라는 이름의 API 서버 컨테이너를 같은 네트워크에 생성했습니다. api 컨테이너에서 ping db를 실행하면 Docker의 내장 DNS가 db를 172.18.0.2 같은 실제 IP로 해석해줍니다.
이것이 왜 중요할까요? API 서버의 데이터베이스 연결 설정에 database_host=db라고 적으면 됩니다.
컨테이너 이름은 직접 지정하는 것이므로 변하지 않습니다. 데이터베이스 컨테이너를 재시작해도 이름은 그대로이므로 연결이 끊기지 않습니다.
사용자 정의 네트워크의 또 다른 장점은 네트워크 격리입니다. my-app-network에 연결된 컨테이너들은 서로 통신할 수 있지만, 다른 네트워크의 컨테이너와는 기본적으로 통신할 수 없습니다.
마치 서로 다른 부서의 내선 전화가 분리된 것과 같습니다. 실무에서는 보통 프로젝트별로, 또는 서비스 그룹별로 네트워크를 분리합니다.
예를 들어, 프론트엔드 관련 컨테이너들은 frontend-network에, 백엔드 관련 컨테이너들은 backend-network에 연결합니다. 필요한 경우 특정 컨테이너를 여러 네트워크에 동시에 연결할 수도 있습니다.
docker network connect 명령을 사용하면 이미 실행 중인 컨테이너를 네트워크에 추가할 수 있습니다. 반대로 docker network disconnect로 연결을 해제할 수도 있습니다.
이 기능 덕분에 실행 중인 서비스를 중단하지 않고도 네트워크 구성을 변경할 수 있습니다. 김개발 씨가 직접 실습해보았습니다.
사용자 정의 네트워크를 만들고, 웹 서버와 데이터베이스를 연결하니 모든 것이 매끄럽게 동작했습니다. "와, 이렇게 간단한 거였어요?"
실전 팁
💡 - 새 프로젝트를 시작할 때 가장 먼저 사용자 정의 네트워크를 생성하세요
- 하나의 컨테이너를 여러 네트워크에 연결하여 게이트웨이 역할을 하게 할 수 있습니다
5. 포트 매핑 옵션
김개발 씨의 컨테이너들이 서로 잘 통신하게 되었습니다. 그런데 새로운 문제가 생겼습니다.
웹 브라우저에서 localhost:80으로 접속했는데 아무것도 뜨지 않습니다. "컨테이너 안에서는 웹 서버가 잘 돌아가고 있는데, 왜 밖에서 접속이 안 되지?"
포트 매핑은 호스트의 포트를 컨테이너의 포트와 연결하는 기능입니다. -p 옵션을 사용하며, 호스트포트:컨테이너포트 형식으로 지정합니다.
컨테이너 내부의 서비스를 외부에 노출시키기 위한 필수 설정입니다. 마치 회사의 대표번호를 내선과 연결하는 것과 같습니다.
다음 코드를 살펴봅시다.
# 기본 포트 매핑: 호스트 8080 -> 컨테이너 80
docker run -d -p 8080:80 --name web nginx
# 여러 포트 동시 매핑
docker run -d -p 80:80 -p 443:443 --name web-ssl nginx
# 특정 IP에만 바인딩 (보안 강화)
docker run -d -p 127.0.0.1:8080:80 --name web-local nginx
# 호스트 포트 자동 할당 (Docker가 빈 포트 선택)
docker run -d -p 80 --name web-auto nginx
# 할당된 포트 확인
docker port web-auto
# 출력: 80/tcp -> 0.0.0.0:32768
# UDP 포트 매핑
docker run -d -p 53:53/udp --name dns-server dns-image
김개발 씨는 nginx 컨테이너를 실행했습니다. 컨테이너 내부에서 curl localhost를 실행하면 nginx 환영 페이지가 잘 나옵니다.
그런데 호스트 머신의 브라우저에서 localhost로 접속하면 아무것도 뜨지 않습니다. 박시니어 씨가 설명했습니다.
"컨테이너는 격리된 환경이야. 컨테이너 안의 80번 포트와 호스트의 80번 포트는 완전히 별개의 포트야.
둘을 연결해주지 않으면 외부에서 접근할 수 없어." 쉽게 비유하자면, 포트 매핑은 마치 회사의 대표전화 시스템과 같습니다. 회사 대표번호(호스트 포트)로 전화가 오면 교환원이 내선번호(컨테이너 포트)로 연결해줍니다.
대표번호 없이는 외부에서 내선으로 직접 전화할 수 없습니다. -p 옵션의 기본 형식은 -p 호스트포트:컨테이너포트입니다.
-p 8080:80이라고 하면 호스트의 8080번 포트로 들어온 요청을 컨테이너의 80번 포트로 전달합니다. 이제 브라우저에서 localhost:8080으로 접속하면 컨테이너의 웹 서버에 연결됩니다.
여러 포트를 동시에 매핑할 수도 있습니다. 웹 서버가 HTTP(80)와 HTTPS(443)를 모두 제공한다면 -p 80:80 -p 443:443처럼 두 포트를 모두 매핑하면 됩니다.
보안이 중요한 환경에서는 특정 IP에만 바인딩할 수 있습니다. -p 127.0.0.1:8080:80이라고 하면 오직 로컬에서만 접속 가능하고, 외부 네트워크에서는 접근할 수 없습니다.
개발 환경이나 관리자 페이지에 유용한 설정입니다. 호스트 포트를 생략하면 Docker가 자동으로 빈 포트를 할당합니다.
-p 80이라고만 하면 Docker가 32768번 이후의 빈 포트 중 하나를 선택합니다. docker port 컨테이너이름 명령으로 어떤 포트가 할당되었는지 확인할 수 있습니다.
기본적으로 -p 옵션은 TCP 포트를 매핑합니다. UDP를 사용하는 서비스(예: DNS)는 -p 53:53/udp처럼 명시적으로 UDP를 지정해야 합니다.
실무에서 자주 하는 실수 중 하나는 포트 충돌입니다. 호스트의 80번 포트는 하나뿐입니다.
이미 다른 프로세스나 컨테이너가 80번 포트를 사용 중이라면 새 컨테이너를 실행할 수 없습니다. 이런 경우 다른 포트를 사용하거나, 기존 프로세스를 종료해야 합니다.
또 다른 주의점은 0.0.0.0 바인딩입니다. 기본적으로 포트 매핑은 모든 네트워크 인터페이스(0.0.0.0)에 바인딩됩니다.
이는 같은 네트워크의 다른 컴퓨터에서도 접근 가능하다는 뜻입니다. 개발 환경에서는 괜찮지만, 보안이 중요한 환경에서는 주의가 필요합니다.
김개발 씨가 -p 8080:80 옵션을 추가하고 컨테이너를 다시 실행했습니다. 브라우저에서 localhost:8080으로 접속하니 드디어 nginx 환영 페이지가 나타났습니다.
"아, 포트를 연결해줘야 하는 거였군요!"
실전 팁
💡 - 개발 환경에서는 호스트와 컨테이너 포트를 다르게 설정하여 충돌을 방지하세요 (예: -p 8080:80)
- 프로덕션에서는 필요한 포트만 최소한으로 노출하고, 가능하면 특정 IP에 바인딩하세요
6. 컨테이너 간 통신 설정
이제 김개발 씨의 프로젝트가 본격적으로 시작되었습니다. 웹 서버, API 서버, 데이터베이스, Redis 캐시까지 네 개의 컨테이너를 운영해야 합니다.
"이 컨테이너들이 서로 잘 통신하려면 어떻게 설정해야 하지?" 김개발 씨는 지금까지 배운 내용을 종합하여 실제 구성을 해보기로 했습니다.
컨테이너 간 통신을 올바르게 설정하려면 사용자 정의 네트워크, 컨테이너 이름, 포트 매핑을 종합적으로 활용해야 합니다. 내부 통신은 컨테이너 이름과 내부 포트를 사용하고, 외부 노출이 필요한 서비스만 포트 매핑을 합니다.
이것이 Docker 네트워크의 베스트 프랙티스입니다.
다음 코드를 살펴봅시다.
# 1. 프로젝트 전용 네트워크 생성
docker network create myapp-network
# 2. 데이터베이스 (외부 노출 불필요)
docker run -d --name db \
--network myapp-network \
-e MYSQL_ROOT_PASSWORD=secret \
mysql:8
# 3. Redis 캐시 (외부 노출 불필요)
docker run -d --name cache \
--network myapp-network \
redis:alpine
# 4. API 서버 (내부에서 db, cache에 접근)
docker run -d --name api \
--network myapp-network \
-e DATABASE_HOST=db \
-e REDIS_HOST=cache \
my-api-image
# 5. 웹 서버 (외부 노출 필요)
docker run -d --name web \
--network myapp-network \
-p 80:80 \
-e API_URL=http://api:3000 \
my-web-image
김개발 씨는 드디어 실전 프로젝트에 돌입했습니다. 팀장님이 요구한 아키텍처는 다음과 같습니다.
사용자는 웹 서버에 접속하고, 웹 서버는 API 서버와 통신하며, API 서버는 데이터베이스와 Redis 캐시를 사용합니다. 이것을 Docker로 어떻게 구성해야 할까요?
박시니어 씨가 화이트보드에 그림을 그렸습니다. "먼저 전체 구조를 생각해봐.
외부에서 접근해야 하는 건 뭐야?" 김개발 씨가 대답했습니다. "웹 서버요.
사용자가 브라우저로 접속하니까요." "맞아. 그러면 웹 서버만 포트 매핑을 하면 돼.
나머지 db, cache, api는 외부에 노출할 필요가 없어. 오히려 노출하면 보안 위험이야." 이것이 핵심입니다.
외부에 노출해야 하는 서비스만 포트를 열고, 나머지는 내부 네트워크에서만 통신하게 합니다. 마치 회사 건물과 같습니다.
안내 데스크(웹 서버)는 외부인이 접근할 수 있지만, 서버실(데이터베이스)은 내부 직원만 들어갈 수 있어야 합니다. 위 코드에서 먼저 myapp-network라는 전용 네트워크를 만들었습니다.
모든 컨테이너가 이 네트워크에 연결됩니다. db와 cache 컨테이너는 -p 옵션 없이 실행됩니다.
포트 매핑이 없으므로 호스트에서 직접 접근할 수 없습니다. 오직 같은 네트워크의 다른 컨테이너만 접근 가능합니다.
api 컨테이너는 환경 변수로 DATABASE_HOST=db와 REDIS_HOST=cache를 전달받습니다. 사용자 정의 네트워크 덕분에 db와 cache라는 이름으로 DNS 조회가 가능합니다.
API 서버 코드에서는 이 환경 변수를 읽어서 각 서비스에 연결합니다. web 컨테이너만 -p 80:80 옵션으로 외부에 노출됩니다.
환경 변수로 API_URL=http://api:3000을 전달받아 API 서버와 통신합니다. 여기서 api는 컨테이너 이름이고, 3000은 API 서버가 리슨하는 포트입니다.
주목할 점은 내부 통신에서는 컨테이너 내부 포트를 사용한다는 것입니다. 호스트에 매핑된 포트가 아닙니다.
web에서 api에 접속할 때 http://api:3000을 사용합니다. 만약 api가 -p 8080:3000으로 매핑되어 있더라도, 내부 통신에서는 여전히 3000번 포트를 사용합니다.
이 구조의 장점은 명확합니다. 첫째, 보안이 강화됩니다.
데이터베이스에 외부에서 직접 접근할 수 없습니다. 둘째, 유연성이 높아집니다.
각 컨테이너를 독립적으로 재시작하거나 교체할 수 있습니다. 컨테이너 이름만 유지하면 다른 컨테이너들은 영향받지 않습니다.
김개발 씨가 이 구조로 서비스를 구성했습니다. 모든 컨테이너가 정상적으로 통신하는 것을 확인하고 뿌듯해했습니다.
"이제 Docker 네트워크가 어떻게 동작하는지 확실히 이해했어요!" 박시니어 씨가 덧붙였습니다. "이게 기본이야.
나중에 docker-compose를 배우면 이 모든 설정을 하나의 파일로 관리할 수 있어. 하지만 지금처럼 기본 원리를 이해하는 게 먼저야."
실전 팁
💡 - 데이터베이스와 캐시 같은 백엔드 서비스는 절대 외부에 포트를 노출하지 마세요
- 환경 변수를 통해 서비스 주소를 전달하면 설정 변경이 쉬워집니다
- docker-compose를 사용하면 이 모든 설정을 YAML 파일 하나로 관리할 수 있습니다
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
백업 및 복구 전략 완벽 가이드
메일 서버와 중요 데이터를 안전하게 보호하는 백업 전략을 알아봅니다. Maildir 백업부터 증분 백업, 오프사이트 백업, 그리고 재해 복구 계획까지 실무에서 바로 적용할 수 있는 내용을 담았습니다.
Roundcube 웹메일 인터페이스 완벽 가이드
Docker 컨테이너 기반으로 Roundcube 웹메일을 구축하고, Nginx 리버스 프록시부터 플러그인 관리, 테마 커스터마이징까지 전체 과정을 다룹니다. 초급 개발자도 쉽게 따라할 수 있는 실무 중심 가이드입니다.
SSL/TLS 인증서 설정 완벽 가이드 (Let's Encrypt)
메일 서버 운영에 필수적인 SSL/TLS 인증서 설정 방법을 다룹니다. Let's Encrypt를 활용한 무료 인증서 발급부터 자동 갱신까지, 실무에서 바로 적용할 수 있는 내용을 담았습니다.
Dovecot으로 IMAP/POP3 메일 서버 구축하기
Linux 환경에서 Dovecot을 활용하여 IMAP과 POP3 메일 서버를 구성하는 방법을 다룹니다. 메일 저장소 설정부터 사용자 인증, 쿼터 관리까지 실무에서 필요한 핵심 설정을 단계별로 학습합니다.
SMTP 서버 구성 Postfix 완벽 가이드
리눅스 환경에서 Postfix를 활용한 메일 서버 구축의 모든 것을 다룹니다. 아키텍처 이해부터 보안 설정까지, 실무에서 바로 적용할 수 있는 핵심 내용을 담았습니다.