MMeshOps
Docker와 Docker Compose: 개발 환경을 하나로 통일하는 도구
6예상 8입문

외부와 통신하기: 포트 매핑의 원리

컨테이너 내부의 격리된 네트워크 포트를 내 컴퓨터(호스트)의 포트와 연결하여 외부에서 접근할 수 있게 하는 포트 매핑을 배웁니다.

도커 컨테이너를 무사히 실행했는데, 브라우저에서 `localhost:3000`으로 접속하니 "사이트에 연결할 수 없음"이라는 에러가 나온 적 있으신가요? 이는 컨테이너가 기본적으로 외부와 단절된 격리된 네트워크 공간에 살고 있기 때문입니다.

컨테이너 안에서 서버가 열심히 돌아가고 있더라도, 밖에서 그 서버에 접속할 수 있는 길을 뚫어주지 않으면 아무 소용이 없습니다. 이번 에피소드에서는 내 컴퓨터(호스트)와 도커 컨테이너 내부를 연결해주는 포트 매핑(Port Mapping)의 개념과 설정 방법을 알아봅니다.

왜 포트 매핑이 필요한가요?

도커 컨테이너는 일종의 작은 가상 머신처럼 동작합니다. 내 컴퓨터(호스트) 안에 있지만, 네트워크는 완전히 독립된 공간으로 나뉘어져 있습니다.

철저히 격리된 컨테이너의 세계

예를 들어, 컨테이너 안에서 Node.js 서버가 3000번 포트로 실행되었다고 가정해 보겠습니다. 이 3000번 포트는 컨테이너 내부의 포트일 뿐, 내 컴퓨터의 3000번 포트와는 아무런 관련이 없습니다. 따라서 브라우저를 열고 내 컴퓨터의 `localhost:3000`에 접속하더라도 아무것도 응답하지 않게 됩니다.

이 두 세계를 연결하기 위해서는 내 컴퓨터의 특정 포트로 들어오는 요청을 컨테이너 내부의 특정 포트로 전달(Forwarding)해 주어야 합니다. 이 과정을 포트 매핑(Port Mapping)이라고 부릅니다.

포트 매핑의 흐름

내 컴퓨터 브라우저

요청 전송

내 컴퓨터 포트 (Host Port)

내 컴퓨터 포트

포트 매핑으로 전달

컨테이너 포트 (Container Port)

컨테이너 포트

요청 처리

컨테이너 내부 애플리케이션

포트 매핑 설정 방법

도커 컨테이너를 실행할 때, 명령어에 `-p` (publish) 옵션을 추가하여 포트 매핑을 설정할 수 있습니다.

`-p 호스트_포트:컨테이너_포트` 공식

포트 매핑의 규칙은 아주 단순하지만, 순서를 헷갈리기 쉽습니다. 항상 콜론(:)을 기준으로 왼쪽이 내 컴퓨터(호스트)의 포트, 오른쪽이 컨테이너 내부의 포트입니다.

포트 매핑 명령어 실행

bash
docker run -p 8080:3000 my-node-app
  1. 1docker run -p 8080:3000 my-node-app
  2. 2이 명령어는 컨테이너를 실행하면서 네트워크 포트를 연결합니다.
  3. 3내 컴퓨터의 8080 포트로 들어오는 모든 요청을,
  4. 4컨테이너 내부의 3000 포트로 전달합니다.

위와 같이 실행한 후에는 브라우저에서 `localhost:8080`으로 접속해야 합니다. 사용자가 8080으로 접속하면 도커가 이를 가로채서 컨테이너 안의 3000번에서 기다리고 있는 앱에게 전달해 줍니다.

포트 매핑 시 자주 하는 실수

오해 또는 실수

순서를 반대로 적기 (예: -p 3000:8080)

바로잡기

항상 내 컴퓨터(호스트) 포트가 먼저, 컨테이너 포트가 나중입니다. (-p 호스트:컨테이너)

오해 또는 실수

호스트 포트 충돌

바로잡기

내 컴퓨터에서 이미 8080 포트를 다른 프로그램이 사용 중이라면 에러가 발생합니다. 이럴 때는 호스트 포트를 8081 등으로 변경해야 합니다. (-p 8081:3000)

실전 예제로 이해하는 포트 매핑

바이브코딩을 하다 보면 여러 개의 컨테이너를 동시에 띄워야 할 때가 있습니다. 이때 포트 매핑의 진가가 발휘됩니다.

하나의 이미지로 여러 개의 포트 열기

동일한 애플리케이션 이미지를 두 개 실행하되, 각각 다른 포트로 접근하고 싶다면 어떻게 해야 할까요? 컨테이너 내부 포트는 고정해두고, 호스트 포트만 다르게 매핑하면 됩니다.

두 개의 웹 서버를 동시에 띄우기

Nginx 웹 서버의 기본 컨테이너 포트는 80입니다. 이를 내 컴퓨터의 8081번과 8082번 포트에 각각 연결해 보겠습니다.

# 첫 번째 서버 실행
docker run -d -p 8081:80 nginx

# 두 번째 서버 실행
docker run -d -p 8082:80 nginx

이렇게 하면 내 컴퓨터의 8081, 8082 포트는 다르지만, 목적지인 각 컨테이너 내부에서는 모두 80번 포트로 안전하게 트래픽이 전달됩니다. 포트 충돌 없이 완벽하게 격리된 두 개의 서버가 완성되었습니다.

포트를 열어두지 않았을 때의 보안 효과

역으로 생각해보면, 포트 매핑을 명시적으로 해주지 않으면 외부에서 해당 컨테이너로 절대 접근할 수 없다는 뜻이기도 합니다. 이는 보안상 큰 장점이 됩니다. 예를 들어 데이터베이스 컨테이너를 띄울 때 호스트와 포트 매핑을 하지 않으면, 오직 도커 네트워크 내부에 있는 다른 컨테이너(예: API 서버)만이 데이터베이스에 접근할 수 있게 됩니다. 외부의 악의적인 접근을 원천 차단하는 것이죠.

개념 퀴즈

퀴즈 답을 맞춰야 학습 완료가 됩니다.

다음 중 도커 컨테이너 내부의 80 포트를 내 컴퓨터의 8080 포트로 연결하기 위한 올바른 옵션은 무엇인가요?

3줄 요약

  1. 1컨테이너는 기본적으로 호스트 컴퓨터와 격리된 독립적인 네트워크를 사용합니다.
  2. 2외부에서 컨테이너에 접속하려면 -p 호스트포트:컨테이너포트 형식으로 포트 매핑을 해야 합니다.
  3. 3호스트 포트는 내 마음대로 바꿀 수 있지만, 컨테이너 포트는 애플리케이션 설정에 맞게 지정해야 합니다.