사전 네트워크 네임스페이스
개념

네트워크 네임스페이스

gabury1고친 사람 github-actions[bot]

네트워크 네임스페이스는 한 컴퓨터 안의 네트워크를 여러 벌로 갈라 줍니다. 갈라진 한 벌마다 네트워크 장치와 주소와 경로를 제각각 가집니다. 그래서 두 프로그램이 같은 포트 번호를 열어도 네임스페이스가 다르면 부딪히지 않습니다. 컨테이너가 저마다 제 주소를 가지는 것도 이 기능으로 됩니다.

쉽고 빠른 이해

한 기계의 네트워크를 칸막이로 나누는 기능입니다. 컨테이너 둘이 저마다 80번 포트를 열어도 부딪히지 않습니다.

칸막이가 없으면 기계 위의 모든 프로그램이 네트워크 한 벌을 나눠 씁니다. 같은 포트 번호를 원하는 프로그램 둘은 같이 못 뜹니다. 누가 방화벽이나 경로를 바꾸면 모두가 그 영향을 받습니다.

어떻게 도나:

  1. 커널에 새 네임스페이스를 요청합니다. 새 네임스페이스에는 자기 자신과만 통하는 장치 하나만 있습니다
  2. 양 끝이 이어진 가상 케이블을 놓습니다. 한 끝은 새 네임스페이스에, 다른 끝은 기계가 처음부터 쓰던 네임스페이스에 둡니다
  3. 양 끝에 주소를 주고 경로를 정하면 새 네임스페이스 안의 프로그램이 바깥과 통합니다

대가는 배선입니다. 네임스페이스 사이는 저절로 이어지지 않아서 누군가 케이블과 주소와 경로를 깔아야 합니다. 통신이 안 될 때도 어느 네임스페이스를 들여다볼지부터 골라야 합니다.

떼어 놓을 까닭이 없으면 칸막이를 치지 않습니다. 기계 하나에 서비스 하나만 돌 때가 그렇습니다.

상세

한 건물에 사무실이 여럿 있습니다. 사무실마다 전화기와 내선 번호표가 따로 있어서, 두 사무실 모두 내선 1번을 써도 헷갈리지 않습니다. 옆 사무실과 통화하려면 두 사무실 사이에 선을 새로 깔아야 합니다.

네트워크 네임스페이스(network namespace)는 리눅스 커널이 네트워크를 여러 벌로 나눠 두게 하는 기능입니다. 커널은 기계의 자원을 관리하며 프로그램에게 나눠 주는 운영체제의 중심부입니다. 앞의 사무실 하나가 네트워크 네임스페이스 하나, 내선 번호가 포트입니다.

네임스페이스는 커널이 가진 자원을 구역마다 갈라 보여 주는 장치입니다. 프로세스 번호를 가르는 것, 파일 시스템의 보이는 범위를 가르는 것 등 여러 갈래가 있습니다. 네트워크 네임스페이스는 그중 네트워크를 가르는 갈래입니다. 이 문서에서 그냥 「네임스페이스」라고 쓰면 네트워크 네임스페이스를 가리킵니다.

네임스페이스마다 따로 가지는 것

네트워크로 오가는 데이터는 패킷이라는 조각에 담겨 다닙니다. 커널은 패킷을 어디로 내보낼지, 들어온 패킷을 어느 프로그램에 넘길지 정하는 설정을 여럿 들고 있습니다. 네트워크 네임스페이스는 이 설정 전부를 네임스페이스마다 한 벌씩 둡니다.

네임스페이스마다 가지는 것 무엇인가
네트워크 인터페이스 패킷이 드나드는 장치입니다. 랜 카드 같은 물리 장치도 있고 커널이 만든 가상 장치도 있습니다
IP 주소 인터페이스에 붙는 주소입니다. IP 는 Internet Protocol(인터넷 프로토콜)의 줄임말입니다
라우팅 테이블 목적지 주소마다 어느 인터페이스로 내보낼지 적은 표입니다
방화벽 규칙 어떤 패킷을 통과시키고 어떤 패킷을 버릴지 정한 규칙입니다
포트 한 기계 안에서 패킷을 받을 프로그램을 가르는 번호입니다

그래서 한 네임스페이스에서 표의 무엇을 바꿔도 옆 네임스페이스는 모릅니다. 네임스페이스 A 에서 경로를 지워도 네임스페이스 B 의 라우팅 테이블은 바뀌지 않습니다. A 에서 80번 포트를 열어도 B 의 80번 포트는 비어 있습니다.

네임스페이스가 없을 때 생기는 일

네트워크가 한 벌뿐이면 기계 위의 모든 프로그램이 그 한 벌을 나눠 씁니다. 웹 서버 둘이 모두 80번 포트를 원하면 하나는 번호를 바꿔야 합니다. 프로그램마다 설정 파일을 고쳐야 하니 번거롭습니다.

설정도 함께 흔들립니다. 한 서비스를 위해 방화벽 규칙이나 경로를 바꾸면 같은 기계의 다른 서비스도 그 규칙을 받습니다. 서비스끼리 서로의 네트워크를 건드리지 못하게 막을 방법이 없습니다.

떼어 놓는 다른 길은 가상 머신입니다. 기계 안에 가상의 컴퓨터를 한 대 더 만들고 운영체제를 하나 더 띄웁니다. 떼어 놓는 힘은 크지만 운영체제를 하나 더 돌리는 만큼 무겁습니다. 네트워크 네임스페이스는 커널 하나를 함께 쓰면서 네트워크만 떼어 냅니다.

프로세스가 속하는 네임스페이스

실행 중인 프로그램을 프로세스라고 부릅니다. 프로세스는 언제나 네트워크 네임스페이스 하나에 속합니다.

기계가 켜질 때 네트워크 네임스페이스가 하나 생깁니다. 이것을 호스트 네임스페이스라고 부릅니다. 달리 정하지 않은 프로세스는 모두 여기에 속합니다.

프로세스가 네트워크를 쓸 때 여는 통로를 소켓이라고 합니다. 소켓은 그 프로세스가 속한 네임스페이스의 인터페이스와 주소와 포트만 봅니다. 그래서 네임스페이스가 다른 두 프로세스는 같은 포트 번호로 각자 소켓을 열 수 있습니다.

프로세스는 다른 프로세스를 띄울 수 있습니다. 띄운 쪽을 부모 프로세스라고 부릅니다. 새 프로세스는 달리 정하지 않으면 부모 프로세스의 네임스페이스를 물려받습니다.

새 네임스페이스로 옮기려면 커널에 요청해야 합니다. 프로그램이 커널에 일을 요청하는 통로를 시스템 호출이라고 합니다. 새 네임스페이스를 만들어 옮겨 가는 시스템 호출이 unshare입니다.

프로세스 여럿이 네임스페이스 하나를 같이 쓸 수도 있습니다. 그러면 그 프로세스들은 한 기계 안의 프로그램처럼 같은 주소와 포트를 나눠 씁니다. 서로를 localhost로 부를 수도 있습니다.

새로 만든 네임스페이스의 모습

새 네임스페이스는 거의 비어서 시작합니다. 인터페이스가 루프백 하나뿐입니다. 루프백은 자기 자신에게 보낸 패킷을 되돌려 주는 가상 인터페이스입니다. localhost 로 보낸 패킷이 이 루프백을 지납니다.

새 네임스페이스에서는 이 루프백마저 꺼져 있습니다. 켜기 전에는 네임스페이스 안에서 자기 자신에게도 패킷을 못 보냅니다.

손으로 만들 때는 리눅스의 ip 명령을 씁니다. ip netns add 가 이름 붙은 네임스페이스를 만듭니다. ip netns exec <이름> <명령> 은 그 네임스페이스 안에서 명령을 돌립니다. 아래는 ns1 을 만들고, 그 안의 인터페이스 목록을 보는 두 줄입니다.

터미널
ip netns add ns1           # ns1 생성
ip netns exec ns1 ip link  # lo 하나, 꺼짐

둘째 줄의 lo 가 루프백입니다. 목록에 다른 장치가 없으니, 이 네임스페이스 안의 프로세스는 아직 바깥 어디와도 통하지 못합니다. 라우팅 테이블도 비어 있습니다.

네임스페이스를 잇는 가상 케이블

네임스페이스 사이는 저절로 이어지지 않습니다. 물리 인터페이스 하나는 한 번에 네임스페이스 하나에만 속합니다. 둘을 통하게 하려면 선을 새로 깔아야 합니다.

이 선으로 많이 쓰는 것이 veth 쌍입니다. veth 는 virtual Ethernet(가상 이더넷)의 줄임말입니다. 언제나 두 끝이 한 쌍으로 만들어집니다. 한 끝으로 들어간 패킷은 다른 끝으로 나옵니다.

한 끝(안쪽 끝)은 새 네임스페이스에 두고 다른 끝(바깥 끝)은 호스트 네임스페이스에 둡니다. 그러면 두 네임스페이스를 잇는 케이블이 됩니다.

스위치는 여러 장치를 꽂아 서로 패킷을 주고받게 하는 네트워크 장비입니다. 브리지는 스위치 노릇을 커널 안에서 하는 가상 장치입니다. 네임스페이스가 여럿이면 호스트 네임스페이스에 브리지를 하나 둡니다. 네임스페이스마다 놓은 veth 의 바깥 끝을 모두 이 브리지에 꽂으면 서로 통합니다.

네임스페이스 안에서 인터넷으로 나가려면 호스트 네임스페이스가 패킷을 받아 물리 인터페이스로 대신 내보내야 합니다. 이때 NAT(Network Address Translation, 네트워크 주소 변환)를 씁니다. NAT 는 패킷에 적힌 보낸 쪽 주소를 기계 자신의 주소로 바꿔 내보내는 일입니다. 네임스페이스 안의 주소는 기계 밖에서 모르는 주소라서, 바꾸지 않고 내보내면 답장이 돌아올 곳이 없습니다.

flowchart TD
    subgraph A["네임스페이스 A"]
        A1["veth 안쪽 끝"]
    end
    subgraph B["네임스페이스 B"]
        B1["veth 안쪽 끝"]
    end
    subgraph H["호스트 네임스페이스"]
        A2["veth 바깥 끝"]
        B2["veth 바깥 끝"]
        BR["브리지"]
        E["물리 인터페이스"]
    end
    A1 --- A2
    B1 --- B2
    A2 --- BR
    B2 --- BR
    BR -- "NAT 로 주소를 바꿔 내보낸다" --> E

네트워크 네임스페이스를 쓰는 곳

컨테이너가 대표입니다. Docker는 기본 설정에서 컨테이너마다 네트워크 네임스페이스를 하나씩 만듭니다. 그 네임스페이스들을 veth 와 브리지로 잇습니다. 그래서 컨테이너 둘이 모두 80번 포트를 열 수 있습니다.

컨테이너를 여러 기계에 띄워 관리하는 Kubernetes에는 파드라는 단위가 있습니다. 파드는 Kubernetes 가 한 단위로 띄우는 컨테이너 묶음입니다. 파드 하나에 네트워크 네임스페이스가 하나라서, 그 안의 컨테이너들은 네임스페이스 하나를 같이 씁니다. 서로를 localhost 로 부르고 주소 하나를 나눠 씁니다.

컨테이너 밖에서도 씁니다. 기계 한 대에 네트워크 네임스페이스 셋을 만들고 veth 로 줄지어 잇습니다. 그러면 가운데 네임스페이스를 라우터로 삼아 양 끝끼리 통하게 하는 라우팅 설정을 장비 없이 시험할 수 있습니다.

네트워크 네임스페이스를 안 쓰는 때

떼어 놓을 까닭이 없으면 네임스페이스를 만들 일도 없습니다. 기계 하나에 서비스 하나만 돌면 호스트 네임스페이스로 충분합니다.

새 네임스페이스를 거치는 패킷은 veth 와 브리지를 한 번 더 지납니다. 이 일마저 아끼고 싶은 서비스는 컨테이너 안에서도 호스트 네임스페이스를 그대로 씁니다. Docker 에서 컨테이너를 띄울 때 주는 --network host 옵션이 이 방식입니다. 대신 포트 번호가 다시 기계 전체에서 부딪힙니다.

네트워크 네임스페이스는 네트워크만 가릅니다. 프로세스 목록이나 파일은 다른 종류의 네임스페이스가 가릅니다. 네트워크 네임스페이스 하나만으로는 프로그램을 통째로 떼어 놓지 못합니다.

관련 항목

네트워크 네임스페이스가 속하는 상위 분류

네임스페이스 · 리눅스 · 커널 · 운영체제 · 격리 · 가상화

네트워크 네임스페이스와 함께 쓰이는 다른 네임스페이스

PID 네임스페이스 · 마운트 네임스페이스 · 사용자 네임스페이스 · UTS 네임스페이스 · IPC 네임스페이스 · cgroup 네임스페이스 · cgroup

네임스페이스마다 따로 가지는 네트워크 구성 요소

네트워크 인터페이스 · IP 주소 · 라우팅 테이블 · 방화벽 · netfilter · iptables · nftables · 포트 · 소켓 · 루프백 · ARP

네임스페이스 사이를 잇는 가상 장치

veth · 브리지 · 가상 스위치 · 이더넷 · NAT · macvlan · VXLAN · 터널링

네트워크 네임스페이스를 만들고 다루는 명령

unshare · setns · clone · 시스템 호출 · iproute2 · nsenter

네트워크 네임스페이스를 채택한 기술

컨테이너 · Docker · Kubernetes · 파드 · 컨테이너 런타임 · CNI · 서비스 메시 · 라우터

네트워크를 떼어 놓는 다른 수단

가상 머신 · VLAN · VPN · chroot · 호스트 네트워크

다른 이름: network namespace · netns · net namespace · 넷 네임스페이스