development

라이브 Docker 컨테이너에 포트 노출

big-blog 2020. 2. 25. 22:49
반응형

라이브 Docker 컨테이너에 포트 노출


완전한 가상 머신처럼 작동하는 Docker 컨테이너를 만들려고합니다. Dockerfile 내에서 EXPOSE 명령을 사용하여 포트를 노출 할 수 있으며 -pwith 플래그를 사용하여 docker run포트를 할당 할 수 있지만 컨테이너가 실제로 실행되면 추가 포트를 열거 나 매핑하는 명령이 있습니까?

예를 들어 sshd를 실행하는 Docker 컨테이너가 있다고 가정 해 봅시다. 컨테이너 ssh를 사용하는 다른 사람이 httpd를 설치하고 설치합니다. 컨테이너에서 포트 80을 노출하고 호스트에서 포트 8080으로 매핑하여 컨테이너에서 다시 시작하지 않고도 컨테이너에서 실행되는 웹 서버를 방문 할 수있는 방법이 있습니까?


Docker를 통해이 작업을 수행 할 수는 없지만 호스트 시스템에서 컨테이너의 노출되지 않은 포트에 액세스 할 수 있습니다.

포트 8000에서 실행중인 컨테이너가있는 경우 다음을 실행할 수 있습니다.

wget http://container_ip:8000

컨테이너의 IP 주소를 얻으려면 다음 두 명령을 실행하십시오.

docker ps

docker inspect container_name | grep IPAddress

내부적으로 Docker는 이미지를 실행할 때 iptables를 호출하기 위해 껍질을 벗기므로 약간의 변형이 가능합니다.

로컬 호스트 포트 8001에서 컨테이너의 포트 8000을 노출하려면 :

 iptables -t nat -A  DOCKER -p tcp --dport 8001 -j DNAT --to-destination 172.17.0.19:8000

이것을 해결할 수있는 한 가지 방법은 원하는 포트 매핑으로 다른 컨테이너를 설정하고 iptables-save 명령 의 출력을 비교하는 것입니다 (트래커가 트래픽을 도커를 통과하도록 강제하는 다른 옵션 중 일부를 제거해야했습니다) 대리).

참고 : 이것은 도커를 파괴하는 것이므로 푸른 연기를 생성 할 수 있다는 인식으로 수행해야합니다

또는

또 다른 대안은 무작위 호스트 포트를 사용하는 (새로운? post 0.6.6?) -P 옵션을 확인한 다음 연결하는 것입니다.

또는

0.6.5에서는 LINKs 기능을 사용하여 기존 컨테이너와 대화하는 새 컨테이너를 가져올 수 있으며 컨테이너의 -p 플래그에 대한 추가 릴레이가 있습니까? (아직 LINK를 사용하지 않았습니다)

또는

도커 0.11? docker run --net host ..컨테이너를 호스트의 네트워크 인터페이스에 직접 연결 하는 사용할 수 있습니다 (즉, net은 이름 간격이 아님). 따라서 컨테이너에서 연 모든 포트가 노출됩니다.


내가 할 일은 다음과 같습니다.

  • 라이브 컨테이너를 커밋하십시오.
  • 포트가 열린 상태에서 새 이미지로 컨테이너를 다시 실행하십시오 (공유 볼륨을 마운트하고 ssh 포트도 여는 것이 좋습니다)
sudo docker ps 
sudo docker commit <containerid> <foo/live>
sudo docker run -i -p 22 -p 8000:80 -m /data:/data -t <foo/live> /bin/bash

기존 컨테이너 의 새 포트를 노출 할 수는 없지만 동일한 Docker 네트워크에서 새 컨테이너를 시작하고 트래픽을 원래 컨테이너로 전달할 수 있습니다.

# docker run \
  --rm \
  -p $PORT:1234 \
  verb/socat \
    TCP-LISTEN:1234,fork \
    TCP-CONNECT:$TARGET_CONTAINER_IP:$TARGET_CONTAINER_PORT

작동 예

포트 80에서 수신 대기하지만 내부 포트 80을 노출 하지 않는 웹 서비스를 시작하십시오 (oops!) :

# docker run -ti mkodockx/docker-pastebin   # Forgot to expose PORT 80!

Docker 네트워크 IP를 찾으십시오.

# docker inspect 63256f72142a | grep IPAddress
                    "IPAddress": "172.17.0.2",

verb/socat포트 8080이 노출 된 상태에서 시작 하여 TCP 트래픽을 해당 IP의 포트 80으로 전달하십시오.

# docker run --rm -p 8080:1234 verb/socat TCP-LISTEN:1234,fork TCP-CONNECT:172.17.0.2:80

이제 http : // localhost : 8080 / 에서 pastebin에 액세스 할 수 있으며 요청이로 socat:1234전달 pastebin:80되고 응답이 동일한 경로를 반대로 이동합니다.


적어도 Docker 1.4.1에서는 IPtables 해킹이 작동하지 않습니다.

가장 좋은 방법은 노출 된 포트로 다른 컨테이너를 실행하고 socat으로 릴레이하는 것입니다. 이것이 SQLPlus로 데이터베이스에 (일시적으로) 연결 한 것입니다.

docker run -d --name sqlplus --link db:db -p 1521:1521 sqlplus

도커 파일 :

FROM debian:7

RUN apt-get update && \
    apt-get -y install socat && \
    apt-get clean

USER nobody

CMD socat -dddd TCP-LISTEN:1521,reuseaddr,fork TCP:db:1521

다른 아이디어가 있습니다. SSH를 사용하여 포트 전달을 수행하십시오. Docker 호스트가 VM 인 경우 OS X (및 아마도 Windows)에서도 작업 할 수 있다는 이점이 있습니다.

docker exec -it <containterid> ssh -R5432:localhost:5432 <user>@<hostip>

나는이 같은 문제를 해결해야했고 실행중인 컨테이너를 멈추지 않고 해결할 수있었습니다. 이 솔루션은 2016 년 2 월 현재 Docker 1.9.1을 사용하는 최신 솔루션입니다. 어쨌든,이 답변은 @ ricardo-branco의 답변에 대한 자세한 버전이지만 새로운 사용자에게는 더 깊이 있습니다.

내 시나리오에서는 컨테이너에서 실행되는 MySQL에 임시로 연결하고 싶었고 다른 응용 프로그램 컨테이너가 컨테이너에 연결되어 있기 때문에 데이터베이스 컨테이너를 중지, 재구성 및 다시 시작하는 것은 시작이 아닙니다.

SSH 터널링을 통해 Sequel Pro에서 외부로 MySQL 데이터베이스에 액세스하고 싶기 33306때문에 호스트 컴퓨터에서 포트를 사용하려고 합니다. 3306외부 MySQL 인스턴스가 실행중인 경우에는 아닙니다 .

iptables를 한 시간 정도 조정하면 다음과 같은 결과가 나타나지 않습니다.

단계별로 여기 내가 한 일이 있습니다.

mkdir db-expose-33306
cd db-expose-33306
vim Dockerfile

dockerfile이것을 안에 넣고 편집하십시오 .

# Exposes port 3306 on linked "db" container, to be accessible at host:33306
FROM ubuntu:latest # (Recommended to use the same base as the DB container)

RUN apt-get update && \
    apt-get -y install socat && \
    apt-get clean

USER nobody
EXPOSE 33306

CMD socat -dddd TCP-LISTEN:33306,reuseaddr,fork TCP:db:3306

그런 다음 이미지를 빌드하십시오.

docker build -t your-namespace/db-expose-33306 .

그런 다음 실행중인 컨테이너에 연결하여 실행하십시오. ( 명시 적으로 중지하고 제거 할 때까지 백그라운드에서 유지하는 -d대신 사용하십시오 -rm.이 경우 일시적으로 실행하기를 원합니다.)

docker run -it --rm --name=db-33306 --link the_live_db_container:db -p 33306:33306  your-namespace/db-expose-33306

허용되는 답변 iptables 솔루션에 추가하기 위해 호스트에서 두 개의 명령을 더 실행하여 외부 세계에서 열어야했습니다.

HOST> iptables -t nat -A DOCKER -p tcp --dport 443 -j DNAT --to-destination 172.17.0.2:443
HOST> iptables -t nat -A POSTROUTING -j MASQUERADE -p tcp --source 172.17.0.2 --destination 172.17.0.2 --dport https
HOST> iptables -A DOCKER -j ACCEPT -p tcp --destination 172.17.0.2 --dport https

참고 : 포트 https (443)를 열었습니다. 도커 내부 IP는 172.17.0.2

참고 2 :이 규칙과 임시는 컨테이너가 다시 시작될 때까지만 지속됩니다.


SSH를 사용하여 터널을 만들고 컨테이너를 호스트에 노출시킬 수 있습니다.

컨테이너에서 호스트로, 호스트에서 컨테이너로, 두 가지 방법으로 모두 수행 할 수 있습니다. 그러나 OpenSSH와 같은 SSH 도구가 필요합니다 (하나의 클라이언트와 다른 서버의 서버).

예를 들어 컨테이너에서 다음을 수행 할 수 있습니다.

$ yum install -y openssh openssh-server.x86_64
service sshd restart
Stopping sshd:                                             [FAILED]
Generating SSH2 RSA host key:                              [  OK  ]
Generating SSH1 RSA host key:                              [  OK  ]
Generating SSH2 DSA host key:                              [  OK  ]
Starting sshd:                                             [  OK  ]
$ passwd # You need to set a root password..

컨테이너의이 줄에서 컨테이너 IP 주소를 찾을 수 있습니다.

$ ifconfig eth0 | grep "inet addr" | sed 's/^[^:]*:\([^ ]*\).*/\1/g'
172.17.0.2

그런 다음 호스트에서 다음을 수행 할 수 있습니다.

sudo ssh -NfL 80:0.0.0.0:80 root@172.17.0.2

Weave Net 과 같은 오버레이 네트워크를 사용하면 각 컨테이너에 고유 한 IP 주소를 할당하고 모든 포트를 네트워크의 모든 컨테이너 부분에 암시 적으로 노출합니다.

Weave는 호스트 네트워크 통합 도 제공 합니다 . 기본적으로 비활성화되어 있지만 호스트에서 컨테이너 IP 주소 및 모든 포트에 액세스하려면 간단히 run을 실행할 수 있습니다 weave expose.

전체 공개 : 저는 Weaveworks에서 근무합니다.


편리한 HAProxy 래퍼가 있습니다.

docker run -it -p LOCALPORT:PROXYPORT --rm --link TARGET_CONTAINER:EZNAME -e "BACKEND_HOST=EZNAME" -e "BACKEND_PORT=PROXYPORT" demandbase/docker-tcp-proxy

대상 컨테이너에 HAProxy가 작성됩니다. 쉬워요.


Ricardo 의 답변을 먼저 읽으십시오 . 이것은 나를 위해 일했습니다.

그러나 docker-compose를 사용하여 실행중인 컨테이너가 시작된 경우 작동하지 않는 시나리오가 있습니다. docker-compose (docker 1.17을 실행 중임)가 새 네트워크를 생성하기 때문입니다. 이 시나리오를 해결하는 방법은

docker network ls

그런 다음 다음을 추가하십시오 docker run -d --name sqlplus --link db:db -p 1521:1521 sqlplus --net network_name


누군가에게 응답이없는 경우-대상 컨테이너가 이미 docker 네트워크에서 실행 중인지 확인하십시오.

CONTAINER=my-target-container
docker inspect $CONTAINER | grep NetworkMode
        "NetworkMode": "my-network-name",

나중에 변수에 저장하십시오 $NET_NAME.

NET_NAME=$(docker inspect --format '{{.HostConfig.NetworkMode}}' $CONTAINER)

그렇다면 동일한 네트워크에서 프록시 컨테이너를 실행해야합니다.

다음으로 컨테이너의 별명을 찾으십시오.

docker inspect $CONTAINER | grep -A2 Aliases
                "Aliases": [
                    "my-alias",
                    "23ea4ea42e34a"

나중에 변수에 저장하십시오 $ALIAS.

ALIAS=$(docker inspect --format '{{index .NetworkSettings.Networks "'$NET_NAME'" "Aliases" 0}}' $CONTAINER)

이제 socat네트워크의 컨테이너에서 실행 $NET_NAME하여 $ALIASed 컨테이너의 노출 된 (발행되지 않은) 포트 에 브리지하십시오 .

docker run \
    --detach --name my-new-proxy \
    --net $NET_NAME \
    --publish 8080:1234 \
    alpine/socat TCP-LISTEN:1234,fork TCP-CONNECT:$ALIAS:80

라이브 포트 매핑은 불가능하지만 Docker 컨테이너에 가상 머신과 같은 실제 인터페이스에 필요한 양을 여러 가지 방법으로 제공 할 수 있습니다.

맥 블란 인터페이스

Docker는 이제 Macvlan 네트워크 드라이버를 포함합니다 . Docker 네트워크를 "실제"인터페이스에 연결하고 해당 네트워크 주소를 컨테이너에 직접 할당 할 수 있습니다 (가상 머신 브리지 모드).

docker network create \
    -d macvlan \
    --subnet=172.16.86.0/24 \
    --gateway=172.16.86.1  \
    -o parent=eth0 pub_net

pipework실제 인터페이스 를 컨테이너에 매핑 하거나 이전 버전의 Docker에서 하위 인터페이스설정할 수도 있습니다 .

라우팅 IP

네트워크를 제어 할 수 있는 경우 컨테이너에서 사용하기 위해 추가 네트워크 를 Docker 호스트로 라우팅 할 수 있습니다 .

그런 다음 해당 네트워크를 컨테이너에 할당하고 Docker 네트워크를 통해 패킷을 라우팅하도록 Docker 호스트를 설정하십시오.

공유 호스트 인터페이스

--net host옵션을 사용하면 호스트 인터페이스를 컨테이너로 공유 할 수 있지만 공유 특성으로 인해 하나의 호스트에서 여러 컨테이너를 실행하기에는 적합하지 않습니다.


해결책은 다음과 같습니다.

https://forums.docker.com/t/how-to-expose-port-on-running-container/3252/12

컨테이너를 실행하는 동안 포트를 매핑하는 솔루션입니다.

docker run -d --net = host myvnc

포트를 자동으로 호스트에 노출하고 매핑합니다.

참고 URL : https://stackoverflow.com/questions/19897743/exposing-a-port-on-a-live-docker-container



반응형