Computer >> 컴퓨터 >  >> 소프트웨어 >> 가상 기기

Docker 컨테이너 네트워킹 - 자습서

Docker의 경이로움을 좀 더 탐색할 시간입니다. 지금까지 두 개의 튜토리얼을 진행했습니다. 하나는 매우 철저한 소개에 중점을 두었습니다. 여기에서 기술, 서비스 실행 방법 및 포트 노출 방법, Dockerfile로 이미지를 커밋 및 빌드하는 방법 및 기타 몇 가지 요령에 대해 모두 배웠습니다. 그런 다음 Supervisord를 초기화 스크립트 및 systemd 대신 사용했습니다.

오늘은 네트워킹에 대해 알아보겠습니다. 컨테이너에 연결하는 방법, 생성된 인스턴스 내에서 호스트에 액세스하는 방법, 그리고 가장 중요한 것은 토폴로지에 대한 사전 지식 없이 한 컨테이너에서 다른 컨테이너로 연결하는 방법입니다. 이것은 흥미로울 것입니다. 이전 두 가이드와 마찬가지로 단계별로 모든 것을 자세히 설명합니다. 나 후에.


목차

<올 아이디="mozToc">
  • 설정
  • 호스트-컨테이너 네트워킹
    1. 요약
  • 네트워킹을 호스팅할 컨테이너
  • 컨테이너 간 네트워킹
  • 컨테이너 링크!
    1. 호스트 파일
    2. 이름을 사용하여 서버에 연결
  • 더 읽어보기
  • 결론

  • 설정

    먼저 여러 컨테이너를 생성해 보겠습니다. 마지막 테스트의 이미지가 이미 있으므로 처음부터 시작할 필요가 없습니다. 각각 고유한 SSH 및 Apache 서비스가 포함된 3개의 컨테이너를 실행합니다. 네트워킹 부분에 초점을 맞추려고 하기 때문에 보안 측면은 무시하십시오.

    마지막으로 수행하지 않은 한 가지 작업은 더 쉽게 식별할 수 있도록 컨테이너 이름을 지정하는 것입니다. 이것은 --name 옵션을 사용하여 수행됩니다. 예:

    도커 실행 -d -ti -p 22 -p 80 --이름 net3 이미지-4:최신

    또한 세 인스턴스에 어떤 IP 주소가 있는지 살펴보겠습니다.

    [root@localhost ~]# docker inspect net1 | grep -i ipaddr
    "IP 주소":"172.17.0.5",

    [root@localhost ~]# docker inspect net2 | grep -i ipaddr
    "IP주소":"172.17.0.6",

    [root@localhost ~]# docker inspect net3 | grep -i ipaddr
    "IP 주소":"172.17.0.7",

    테스트를 위한 초기 구성입니다. 서비스 및 노출된 서비스 포트와 함께 모두 동일한 호스트에서 실행되는 3개의 컨테이너가 있습니다. 이제 다소 흥미로운 작업을 시작할 수 있습니다.

    호스트-컨테이너 네트워킹

    이것은 쉬운 부분이며 솔직히 말해 이전 연습에서 이미 수행했습니다. SSH를 사용하여 컨테이너에 연결했으며 telnet을 사용하여 포트 테스트를 시도했습니다. 예, netcat(nc)도 잘 작동합니다. 보안 클랙슨을 끄십시오. 연결하는 방법은 두 가지가 있습니다. 첫째, 이전에 했던 것처럼 IP 주소를 사용하여 컨테이너에 직접 액세스할 수 있습니다.

    SSH 172.17.0.5
    호스트 '172.17.0.5(172.17.0.5)'의 신뢰성을 설정할 수 없습니다. ECDSA 키 지문은 00:4b:de:91:60:e5:22:cc:f7:89:01:19:3e:61:cb:ea입니다.
    계속 연결하시겠습니까(예/아니오)? 예
    경고:알려진 호스트 목록에 '172.17.0.5'(ECDSA)가 영구적으로 추가되었습니다.
    root@172.17.0.5의 암호:

    둘째, 컨테이너 내부의 서비스 포트에 해당하는 호스트 매핑된 포트에 액세스할 수도 있습니다. docker ps 출력에서 ​​PORTS 정보만 보면 다음과 같습니다.

    0.0.0.0:49162->22/tcp, 0.0.0.0:49161->80/tcp net1
    0.0.0.0:49163->22/tcp, 0.0.0.0:49164->80/tcp net2
    0.0.0.0:49165->22/tcp, 0.0.0.0:49166->80/tcp net3

    위의 예에서 net1이라는 컨테이너의 경우 포트 22는 호스트의 포트 49162에 매핑되며, 이는 기본적으로 172.17.42.1/16 네트워크에 할당된 docker0 인터페이스를 의미합니다. 실제로 우리는 다음을 봅니다.

    텔넷 172.17.42.1 49163
    172.17.42.1 시도 중...
    172.17.42.1에 연결되었습니다.
    이스케이프 문자는 '^]'입니다.
    SSH-2.0-OpenSSH_6.6.1

    이제 더 혼란스럽고 기억하기 어려운 두 번째 방법을 사용하려는 이유는 무엇입니까? 대답은 동적 매핑을 사용하지 않고 대신 알려진 주어진 호스트 포트를 지정하는 경우 컨테이너 네트워크에 대한 매우 명확한 지형을 가질 수 있다는 것입니다. 또한 호스트 외부에서 컨테이너에 액세스할 수 있도록 하려면 IP 전달 및 NAT가 필요합니다. 통신에 docker0 인터페이스를 사용하는 경우 더 적고 간단한 iptables 규칙이 필요합니다.

    iptables -L 명령을 실행하고 DOCKER 체인을 확인하여 이를 확인할 수 있습니다. -p 옵션으로 컨테이너를 실행할 때마다 새 규칙이 자동으로 추가됩니다.

    체인 DOCKER (1 참조)
    타겟 prot 선택 소스 목적지
    ACCEPT tcp -- 어디서나 172.17.0.5 tcp dpt:http
    ACCEPT tcp -- 어디서나 172.17.0.5 tcp dpt:ssh
    ACCEPT tcp -- 어디서나 172.17.0.6 tcp dpt:ssh
    ACCEPT tcp -- 어디서나 172.17.0.6 tcp dpt:http
    ACCEPT tcp -- 어디서나 172.17.0.7 tcp dpt:ssh
    ACCEPT tcp -- 어디서나 172.17.0.7 tcp dpt:http
    ACCEPT tcp -- 어디서나 172.17.0.8 tcp dpt:ssh
    ACCEPT tcp -- 어디서나 172.17.0.8 tcp dpt:http

    그러나 보안 제한이 없는 경우 컨테이너를 시작할 때 포트 매핑을 알 필요가 없기 때문에 동적 방법이 매우 유용할 수 있습니다. docker ps 출력을 구문 분석하여 실시간으로 정보를 도출할 수 있습니다. 그러나 서비스의 경우 고정 IP 주소와 알려진 포트를 설정하는 것이 유용한 경우가 많습니다.

    요약

    다소 혼란스럽기 때문에 간단히 요약해 보겠습니다. 모든 도커 호스트에는 일반적으로 /16 서브넷과 함께 docker0 또는 비슷한 이름의 브리지가 실행되지만 서브넷 또는 네트워크의 이름을 변경할 수 있습니다. 그 뒤에는 각각 고유한 사설 IP 주소와 하나 이상의 노출된 포트가 있는 전체 범위의 컨테이너가 있을 수 있습니다.

    이러한 컨테이너 및 관련 포트에 연결하려는 경우 몇 가지 옵션이 있습니다. 직접 연결할 수 있지만 각각에 대한 IP 포워딩, NAT 및 방화벽 규칙이 필요하고 IP 주소를 알아야 합니다.

    호스트 인터페이스(docker0) 및 호스트 포트 방법을 사용하여 연결하려는 경우 컨테이너가 어떻게 실행되는지 알 필요가 없습니다. 호스트 포트와 컨테이너 포트의 매핑만 알면 됩니다. 즉, 여러 호스트 노드 간에 컨테이너에 액세스할 수 있도록 하려면 호스트 인터페이스(docker0)를 다른 호스트에 표시하기만 하면 됩니다. 이렇게 하면 IP 전달, NAT 및 방화벽 규칙이 간단해집니다. 예:

    0.0.0.0:30001->22/tcp net1
    0.0.0.0:30007->22/tcp net4
    0.0.0.0:30008->22/tcp net5

    위의 예에서는 세 가지 다른 컨테이너의 SSH에 연결할 수 있습니다. 일대일 매핑, 즉 동일한 호스트 포트와 컨테이너 포트(예:22:22)를 사용하는 경우 단일 서비스가 수신 대기하는 단일 컨테이너만 있는 것으로 효과적으로 제한됩니다. 이것은 가정용 라우터와 같습니다. 컨테이너가 일대일 매핑을 사용하려면 다른 포트를 사용해야 합니다. 그러나 이것은 서비스가 예측 가능한 포트에서 실행될 것으로 예상하기 때문에 혼란스럽습니다.

    위의 예에서 3개의 컨테이너가 SSH를 사용하도록 할 수 있음을 알 수 있습니다. 내부적으로 컨테이너 관점에서 보면 항상 포트 22입니다. 외부에서 포트 번호는 컨테이너와 서비스를 모두 식별합니다. 그리고 이것은 배후에서 일어나는 일에 신경 쓰지 않고 알아야 할 유일한 부분이 됩니다.

    즉, 일종의 스크립트 논리 등을 사용하여 컨테이너를 생성할 때 호스트 포트를 동적으로 할당한 다음 해당 정보를 사용하여 서비스 포트를 식별할 수 있습니다. 따라서 호스트-컨테이너 네트워킹은 간단하고 우아한 작업이 됩니다. 또한 컨테이너 지형을 미리 알지 않고도 호스트에서 다른 호스트로 다시 연결할 수 있습니다.

    호스트 네트워킹을 위한 컨테이너

    이것은 좀 더 흥미로운 부분입니다. 컨테이너는 수명이 긴 용도로 사용할 수 있으므로 잠시 동안 가동 상태를 유지해야 할 수 있습니다. 이는 업그레이드, 패치, 호스트 파일 업데이트 등을 의미하는 컨테이너를 유지 관리해야 할 수도 있음을 의미합니다. Chef, Puppet 또는 Cfengine과 같은 구성 관리 도구를 사용 중일 수도 있으므로 그 부분도 있습니다.

    가장 먼저 해야 할 큰 질문은 컨테이너가 외부 세계와 접촉할 수 있는가입니다. 네. 소개 가이드에서 우리는 공식 리포지토리에서 CentOS 업데이트를 직접 다운로드했기 때문에 이 부분이 잘 작동한다는 것을 알고 있습니다. docker0을 핑하는 것은 어떻습니까:

    두 번째 질문은 docker0 인터페이스에 액세스한 다음 호스트 포트에 연결할 수 있는지입니다. 컨테이너 내부에 필요한 정보가 어떻게든 주어졌다고 잠시 가정해 봅시다.

    텔넷 172.17.42.1 49162
    172.17.42.1 시도 중...
    텔넷:주소 172.17.42.1에 연결:호스트로 가는 경로 없음

    호스트에서 IP 전달을 구성하지 않았기 때문에 작동하지 않습니다. 또한 필요한 트래픽을 허용하려면 방화벽 규칙이 필요합니다. 여기에서는 조금 복잡해집니다. iptables에 익숙하지 않은 경우 다소 어려움을 겪을 수 있기 때문입니다.

    에코 1> /proc/sys/net/ipv4/ip_forward

    그리고 iptables 규칙 - 다소 느슨한 설정, 마음(호스트에서):

    iptables -t 필터 -A FORWARD -d 172.17.0.0/16 \
    -o docker0 -j 수락
    iptables -t 필터 -A FORWARD -s 172.17.0.0/16 \
    -i docker0 -j 수락
    iptables -t 필터 -A 앞으로 -i docker0 -o docker0 -j ACCEPT
    iptables -t nat -A POSTROUTING -s 172.17.0.0/16 \
    ! -d 172.17.0.0/16 -p tcp -j 마스커레이드 --to-ports 1016-65535 \
    iptables -t nat -A POSTROUTING -s 172.17.0.0/16
    ! -d 172.17.0.0/16 -p udp -j 마스커레이드 --to-ports 1016-65535 \
    iptables -t nat -A POSTROUTING -s 172.17.0.0/16
    ! -d 172.17.0.0/16 -j 가장

    가장 간단한 대안은 방화벽을 끄거나 모두 허용하는 것입니다. 이는 systemctl stop firewalld, iptables -F 또는 이에 상응하는 명령을 실행할 수 있음을 의미합니다. 일부 시나리오에서는 추가 보안이 필요하므로 불가능할 수 있습니다. 그러나 이것은 또한 우리가 논의한 첫 번째 사용 사례와 관련이 있습니다. 이제 모든 단일 컨테이너 및 관련 서비스에 대한 수동 규칙을 만들어야 한다고 상상해 보십시오.

    올바른 네트워킹 규칙이 있으면 호스트 포트에 연결할 수 있습니다. 즉, 대상이 다른 컨테이너여야 하는 특정 IP 주소나 포트에는 아무 것도 없지만 다른 컨테이너와 효과적으로 통신할 수 있습니다. 또한 호스트 또는 원격 호스트의 다른 네트워킹 장치에 연결할 수도 있습니다.

    컨테이너 간 네트워킹

    David Bowie의 노래 Ashes to Ashes처럼 멋지지는 않습니다. 가장 유용한 시나리오인 것 같습니다. 다시 말하지만 두 가지 옵션이 있습니다. 다른 컨테이너에 직접 연결을 시도하거나 동적으로 매핑된 docker0 포트를 사용해 볼 수 있습니다. 우리는 속일 것입니다. 호스트 및 호스트 포트를 컨테이너에 대한 게이트웨이로 사용합니다. 이제 첫 번째 방법은 매우 간단합니다. net1에서 net2와 net3에 대해 ping을 시도해 봅시다.

    문제없이 작동합니다. 하지만 문제는 외부 세계의 IP 주소에 대해 알고 있다는 것입니다. 우리는 컨테이너 내부에서 이 정보를 얻지 못했습니다. 실제로 보안상의 이유와 기본 컨테이너가 비교적 작은 이미지라는 사실 때문에 기본적으로 사용할 수 있는 훌륭한 네트워킹 도구가 없습니다. ifconfig 유틸리티를 사용할 수도 없습니다. 또한 다음 중 하나라도 컨테이너 내부의 iptables를 조작할 수 없습니다.

    iptables -L
    iptables v1.4.21:iptables 테이블 `필터'를 초기화할 수 없습니다:권한이 거부되었습니다(루트여야 함).
    아마도 iptables나 커널을 업그레이드해야 할 것입니다.

    따라서 docker0에 액세스하고 호스트 포트에 연결하는 두 번째 방법은 컨테이너 내에서가 아니라 호스트 방화벽 규칙을 조작할 수 없기 때문에 실제로 실현 가능하지 않을 수 있습니다. 이것이 우리가 세 번째 방법에 대해 논의하는 이유입니다.

    컨테이너 링크!

    이를 수행하는 적절한 방법은 --link 기능을 사용하는 것입니다. 이것이 의미하는 바는 새로운 인스턴스를 생성하면서 다른 기존 컨테이너에 연결한다는 것입니다. 링크 기능은 연결된 컨테이너의 호스트 이름과 IP 주소를 새 인스턴스의 환경 및 /etc/hosts 파일에 삽입합니다. 다소 혼란스럽게 들릴 수 있으므로 예를 들어 보겠습니다.

    docker run -d -ti -p 80 --웹 이미지 이름-4:최신
    8e689d8ae3ef43eeab3bfa9cf523e1cc6658dae5fc665f8cbf889db17db46c26

    도커 검사 웹 | grep -i ipaddr
    "IP주소":"172.17.0.9",

    nc -w1 -v 172.17.0.9 80
    Ncat:버전 6.40( https://nmap.org/ncat )
    Ncat:172.17.0.9:80에 연결되었습니다.

    실행 중인 컨테이너가 있고 웹 서버가 되어야 합니다. 이제 클라이언트가 액세스할 수 있기를 바랍니다. 지형에 대한 사전 지식이 없을 수 있으므로 IP 주소가 아닌 서버 이름을 사용하려고 합니다. 또한 이름은 네트워크 레이아웃을 변경할 수 있으므로 유용합니다. 이제 클라이언트 컨테이너를 만들어 웹 서버에 연결해 보겠습니다.

    docker run -ti --name client --link web:web image-4:latest /bin/bash

    여기에 있는 내용은 다음과 같습니다. 우리는 source:target의 링크를 만들고 있습니다. 즉, web이라는 서버(컨테이너)는 client라는 새 컨테이너 내에서 web으로 표시됩니다. 컨테이너를 생성한 다음 연결하면 BASH 셸에서 env 명령을 실행하여 환경을 확인할 수 있습니다.

    WEB_PORT_80_TCP_PORT=80
    WEB_PORT_80_TCP=tcp://172.17.0.9:80
    경로=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    패스워드=/
    WEB_PORT_22_TCP_ADDR=172.17.0.9
    container_uuid=558a9db0-6d1e-d9d2-b62d-a8dbfbad0b2d
    WEB_PORT_22_TCP=tcp://172.17.0.9:22
    SHLVL=1
    홈=/루트
    WEB_NAME=/클라이언트/웹
    WEB_PORT_80_TCP_PROTO=tcp
    WEB_PORT_80_TCP_ADDR=172.17.0.9
    LESSOPEN=||/usr/bin/lesspipe.sh %s
    WEB_PORT=tcp://172.17.0.9:22
    _=/usr/bin/env

    같은 이름 매핑은 혼란스러울 수 있으므로 다른 매핑을 시도해 보겠습니다.

    docker run -ti --name client --link web:dedoimedo image-4:latest /bin/bash

    그런 다음 다음을 얻습니다.

    선택적으로 빠른 작업이 필요한 컨테이너를 생성하는 경우 run --rm 옵션을 사용하여 생성하는 것을 고려할 수 있습니다. 수명이 짧은 작업의 경우 컨테이너 파일을 디스크에 보관할 이유가 없으며 Docker가 자동으로 정리하도록 할 수 있습니다. 공식 문서 읽기:

    기본적으로 컨테이너의 파일 시스템은 컨테이너가 종료된 후에도 지속됩니다. 이렇게 하면 디버깅이 훨씬 쉬워지고(최종 상태를 검사할 수 있으므로) 기본적으로 모든 데이터를 유지할 수 있습니다. 그러나 단기 포그라운드 프로세스를 실행하는 경우 이러한 컨테이너 파일 시스템이 실제로 쌓일 수 있습니다. 대신 컨테이너가 종료될 때 Docker가 자동으로 컨테이너를 정리하고 파일 시스템을 제거하도록 하려면 --rm 플래그를 추가할 수 있습니다.

    도커 실행 --rm -ti --이름 클라이언트 --link web:dedoimedo image-4:latest /bin/bash

    호스트 파일

    링크 기능에 대한 두 번째 좋은 점은 새 컨테이너가 필요한 이름으로 채워진 /etc/hosts 파일을 자동으로 가지므로 치료를 받을 수 있다는 것입니다. IPv6 항목이 제거된 다음과 같이 표시됩니다.

    [root@e1e92f6918dd /]# 고양이 /etc/hosts
    172.17.0.11 e1e92f6918dd
    127.0.0.1 로컬 호스트
    172.17.0.9 데도이메도 8e689d8ae3ef 웹

    이름을 사용하여 서버에 연결

    그리고 호스트 이름 확인 및 환경 설정이 있기 때문에 어디에서나 네트워킹처럼 됩니다. 정말 간단하고 기억하기 쉬우며 가장 중요한 것은 스크립트를 작성할 수 있다는 것입니다.

    더 읽어보기

    충분한 재미를 느끼지 못했다고 생각되면:

    Docker 고급 네트워킹 가이드

    결론

    자. 또 다른 두려운 주제가 밝혀졌습니다. 문제는 Docker 컨테이너로 작업할 때 직면하게 될 가장 큰 문제는 이 기술의 네트워킹 부분에 필수적인 것이 아니라 방화벽 규칙의 구성이라고 생각합니다. 하지만 일단 요령을 터득하면 그렇게 어렵거나 복잡하지 않습니다.

    우리는 컨테이너를 시작하고 포트를 노출하고, 호스트에서 컨테이너로, 컨테이너에서 호스트로, 컨테이너에서 컨테이너로 네트워킹을 실행하고, 포워딩을 설정하고, 링크를 사용하여 우리의 삶을 훨씬 쉽고 예측 가능하게 만드는 방법을 보았습니다. 대체로 바쁘지만 희망적으로 실용적인 가이드였습니다. 다시 말하지만, 다른 주제가 있으면 자유롭게 제안하십시오. 그리고 끝났습니다.

    추신 이 기사가 마음에 든다면 Dedoimedo에 약간의 사랑을 돌려주는 것이 좋습니다!

    건배.