포트 매핑은 컨테이너화된 애플리케이션을 개발하고 배포할 때 중요한 측면입니다. 일반적으로 컨테이너를 생성할 때 컨테이너의 내부 포트와 호스트 머신의 포트 간 연결을 설정합니다. 하지만 이미 실행 중인 컨테이너에 새로운 포트 매핑을 동적으로 추가해야 하는 상황이 발생할 수 있습니다. 이는 개발, 디버깅 또는 새로운 서비스 엔드포인트를 임시로 노출할 때 특히 유용할 수 있습니다. 이 글에서는 컨테이너를 중지하지 않고도 포트 매핑을 동적으로 추가하는 방법을 자세히 설명합니다.
1.배경 지식
컨테이너 포트 매핑의 기본 원리
Docker에서 컨테이너의 내부 포트와 호스트 머신의 포트 간 연결은 포트 매핑을 통해 이루어집니다. 일반적으로 컨테이너를 시작할 때 -p 또는 --publish 매개변수를 사용하여 포트 매핑을 지정합니다. 예시는 다음과 같습니다.
docker run -d -p 8080:80 nginx
위 명령은 호스트 머신의 포트 8080을 컨테이너 내부의 포트 80에 매핑합니다. 그 결과 외부 사용자는 호스트의 포트 8080을 통해 컨테이너 내에서 실행 중인 웹 서비스에 액세스할 수 있습니다.
포트 매핑 동적 추가의 어려움
컨테이너가 시작된 후 Docker는 일반적으로 새로운 포트 매핑을 동적으로 추가하는 것을 지원하지 않습니다. 즉, 초기 포트 매핑은 컨테이너의 전체 수명 주기 동안 고정됩니다. 추가 포트 매핑이 필요할 경우 전통적인 방법은 컨테이너를 중지하고 다시 시작하는 것인데, 이는 서비스를 중단시킬 수 있으며 프로덕션 환경에서는 허용되지 않습니다.
2.구현 솔루션
실행 중인 컨테이너에 포트 매핑을 동적으로 추가하기 위해 여러 방법을 사용할 수 있습니다.
2.1 docker network를 사용한 프록시 컨테이너 생성
원래 컨테이너와 동일한 네트워크에 새 프록시 컨테이너를 생성하고, 프록시 컨테이너에 새 포트 매핑을 추가할 수 있습니다. 구체적인 단계는 다음과 같습니다. 먼저 원래 컨테이너와 동일한 네트워크에 프록시 컨테이너를 생성합니다.
docker run -d --name proxy-container --net container:your-container nginx
그런 다음 프록시 컨테이너에 원하는 포트 매핑을 추가합니다.
docker run -d -p 8081:81 --net container:your-container nginx
주의해서 사용하세요. 이 방법은 원래 컨테이너를 수정하지 않고 새 포트 매핑을 추가할 수 있지만, 추가 컨테이너 인스턴스가 생성되며 모든 시나리오에 적합하지 않을 수 있습니다.
2.2 iptables를 사용한 수동 포트 포워딩 규칙 추가
iptables를 수정하여 호스트 머신의 특정 포트에서 실행 중인 Docker 컨테이너의 내부 포트로 요청을 전달할 수 있습니다. 예를 들어 호스트의 포트 8081을 컨테이너의 포트 81에 매핑하려면 다음 명령을 사용합니다.
iptables -t nat -A DOCKER -p tcp --dport 8081 -j DNAT --to-destination <container_ip>:81
여기서 <container_ip>는 컨테이너의 내부 IP 주소이며, docker inspect 명령을 사용하여 얻을 수 있습니다. 이 방법은 포트 매핑을 추가하는 데 완전한 유연성을 제공하지만 iptables에 대한 충분한 이해가 필요하며 복잡성 때문에 프로덕션 환경에서 자주 사용하는 것은 권장되지 않습니다.
2.3 socat을 사용한 포트 포워딩 생성
socat 은 호스트 머신과 컨테이너 간에 포트 포워딩을 설정할 수 있는 다목적 네트워크 도구입니다. 다음 명령을 실행하여 호스트 머신의 특정 포트를 컨테이너의 지정된 포트로 전달할 수 있습니다.
socat TCP-LISTEN:8081,fork TCP:<container_ip>:81
주의해서 사용하세요. 이 방법의 장점은 컨테이너를 중지할 필요가 없다는 것입니다. 그러나 socat은 추가 프로세스이므로 성능과 안정성에 주의해야 합니다. 다른 포트 포워딩 도구로도 비슷한 결과를 얻을 수 있습니다.
2.4 Docker Compose를 사용한 서비스 동적 업데이트
애플리케이션에서 Docker Compose를 사용하여 컨테이너를 관리하는 경우 docker-compose.yml 파일을 업데이트한 후 docker-compose up을 실행하여 새 포트 매핑을 추가할 수 있습니다. 이 방법은 편리하고 통합 관리가 가능하지만, 업데이트할 때마다 Compose 파일을 다시 적용해야 하며 일시적인 서비스 중단이 발생할 수 있습니다.
2.5 컨테이너 설정 파일 강제 수정
먼저 /var/lib/docker/containers/<container_id>/config.v2.json 파일을 직접 수정하여 HostPort 8081을 컨테이너의 포트 81에 매핑하는 내용을 추가합니다. 두 섹션을 수정해야 합니다. 한 섹션에서는 HostPort 8081만 추가하면 됩니다.
"ExposedPorts": {
"8080/tcp": {}
"8081/tcp": {}
},
다른 섹션에서는 완전한 매핑 관계를 추가해야 합니다.
"Ports": {
"80/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "8080"
},
],
"81/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "8081"
},
]
},
또한 /var/lib/docker/containers/<container_id>/hostconfig.json도 수정하여 새 매핑을 추가해야 합니다.
"PortBindings": {
"80/tcp": [
{
"HostIp": "",
"HostPort": "8080"
},
"81/tcp": [
{
"HostIp": "",
"HostPort": "8081"
}
]
},
마지막으로 dockerd를 다시 시작해야 합니다.
sudo systemctl restart docker
이 방법은 컨테이너에 포트 매핑을 영구적으로 추가할 수 있지만, dockerd 재시작으로 인해 호스트 머신의 모든 컨테이너가 중지되는 부작용이 있습니다. 컨테이너가 자동 시작으로 설정되지 않은 경우 dockerd가 다시 시작된 후에도 자동으로 시작되지 않습니다. 이 방법은 효과적이지만 실행 중인 컨테이너에 큰 영향을 미칠 수 있으므로 프로덕션 환경에서는 권장되지 않습니다.
3.결론
컨테이너에 포트 매핑을 동적으로 추가하는 것은 Docker의 기본 지원 기능은 아니지만, 위에서 설명한 방법을 통해 어느 정도 구현할 수 있습니다. 각 방법에는 장단점이 있으므로 개발자는 특정 요구 사항에 따라 가장 적합한 방법을 선택할 수 있습니다. 프로덕션 환경에서는 비교적 간단하고 위험이 적은 프록시 컨테이너나 Docker Compose를 사용하는 것이 좋습니다. 포트 매핑을 자주 변경해야 하는 애플리케이션의 경우 설계 단계에서 유연한 네트워크 아키텍처를 고려하여 컨테이너 실행 중 포트 매핑을 자주 수정하지 않도록 하고, 이를 통해 서비스 중단을 최소화하는 것이 좋습니다.
Novita AI에서 더 많은 정보를 확인하실 수 있습니다.
