본문 바로가기
Network/Linux - Practice

[Network] Linux namespace, cgroup

by ymkim 2025. 8. 28.

01. namespace?

01-1. namespace

리눅스에서 프로세스(process)는 네임스페이스(namespace)라는 단위를 기본적으로 가진다. 네임스페이스는 커널 자원을 논리적으로 분리하여 각 프로세스가 독립된 리소스 환경을 가지도록 하는 기술이다. 쉽게 말해, 대형 쇼핑몰 안에 여러 개의 상점이 있고 각 상점이 독립적으로 운영되는 것과 같다. 하나의 상점(namespace)은 다른 상점에 허락 없이 접근할 수 없듯, 프로세스 역시 다른 네임스페이스의 자원에 직접 접근할 수 없다.

01-2. namespace 종류

pid, net, mnt, uts, user, ipc

Linux에서 생성되는 프로세스(process)들은 별다른 설정이 없는 경우, 최초로 실행되는 init 프로세스가 속한 '초기(initial) 네임스페이스'를 공유하는 형태로 구동된다. 즉, 시스템에서 구동되는 모든 프로세스가 동일한 네임스페이스를 사용한다는 말이다.

도커(Docker)는 그렇지 않다. 컨테이너가 생성될 때, init 프로세스의 네임스페이스를 그대로 사용하는 것이 아니라 대부분의 네임스페이스를 새로 생성하여 컨테이너 내의 프로세스들을 격리한다. 이 덕분에 컨테이너는 고유한 네트워크, 파일 시스템, PID 등을 가지게 된다. 하지만 모든 네임스페이스를 새로 생성하는 것은 아니고, 사용자(User) 네임스페이스는 호스트와 공유한다.

✅ PID 네임스페이스(pid)

ls -l /proc/$$/ns/pid

pid:[4026531836]

PID 네임스페이스는 네임스페이스별로 프로세스를 격리하는 기술이다. 각 네임스페이스는 독립적인 PID 번호 공간을 가지므로, 한 네임스페이스(A:4026531835)의 프로세스는 다른 네임스페이스(B:3344554455)의 PID를 확인하거나 접근할 수 없다. 이를 통해 프로세스 간 격리가 이루어지며, 컨테이너 환경에서 독립된 프로세스 트리를 가질 수 있는 이유가 PID 네임스페이스 덕분이다.

✅ 네트워크 네임스페이스(net)

ls -l /proc/$$/ns/net

net:[4026531993]

네트워크 네임스페이스는 네트워크 인터페이스(Network Interface), IP 주소, 라우팅 테이블과 같은 네트워크 자원을 격리하는 기술이다. 동일한 네임스페이스에 속한 프로세스들은 같은 네트워크 자원을 공유하며, 이를 통해 하나의 물리적 서버에서 여러개의 가상 네트워크 환경을 구성할 수 있다.

✅ 마운트 네임스페이스(mnt)

$ mount
/dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro)
/dev/sda2 on /home type ext4 (rw,relatime)
tmpfs on /run type tmpfs (rw,nosuid,nodev,mode=755)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)

마운트 네임스페이스는 파일 시스템의 마운트 포인트를 격리하는 기술로, 각 네임스페이스는 고유한 마운트 테이블을 가진다. 새로운 네임스페이스가 생성될 때는 부모 네임스페이스의 마운트 테이블을 상속받지만, 이후에 mount나 umount 작업을 수행해도 부모나 다른 자식 네임스페이스에는 영향을 주지 않는다. 이러한 동작은 도커 컨테이너가 구동될 때의 구조와 유사하다.

✅ UTS 네임스페이스(uts)

# ls -l
lrwxrwxrwx 1 root root 0  8월 14 12:31 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0  8월 14 12:31 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0  8월 14 12:31 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0  8월 14 12:31 net -> net:[4026532089]
lrwxrwxrwx 1 root root 0  8월 14 12:31 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0  8월 14 12:31 pid_for_children -> pid:[4026531836]
lrwxrwxrwx 1 root root 0  8월 14 12:31 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0  8월 14 12:31 uts -> uts:[4026531838]

UTS 네임스페이스는 컴퓨터의 hostname과 domain을 격리하는데 사용되는 기술이다. 일반적으로 1대의 컴퓨터에는 1개의 hostname(호스트 이름)만 존재할 수 있다. 특정 A 프로세스가 서버의 hostname을 변경하려고 하여도 이는 불가능하다. 하지만 UTS 네임스페이스를 사용하면, 각 프로세스(process)들은 고유한 hostname(호스트 이름)을 가질 수 있다. 즉, 하나의 물리적인 컴퓨터 위에서 여러개의 가상 컴퓨터가 존재하는 것처럼, 각각 다른 호스트 이름을 사용할 수 있다.

또한, 일반적으로 시스템의 hostname(호스트 이름)을 바꾸는 작업은 루트(root) 사용자만 할 수 있는 작업이다.

만약 host_A라는 이름을 가진 물리적인 서버가 있다고 가정해보자. UTS 네임스페이스를 사용하지 않으면 해당 서버에 구동되는 모든 프로세스들은 host_A라는 호스트 이름을 공유하며, 특정 프로세스(process)가 호스트 이름을 변경하면 서버 호스트명이 변경된다. 이에 반해 UTS 네임스페이스를 사용하면, 특정 프로세스만의 호스트 이름을 지정할 수 있다.

✅ 사용자 네임스페이스(user)

# ls -l
lrwxrwxrwx 1 root root 0  8월 14 12:31 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0  8월 14 12:31 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0  8월 14 12:31 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0  8월 14 12:31 net -> net:[4026532089]
lrwxrwxrwx 1 root root 0  8월 14 12:31 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0  8월 14 12:31 pid_for_children -> pid:[4026531836]
lrwxrwxrwx 1 root root 0  8월 14 12:31 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0  8월 14 12:31 uts -> uts:[4026531838]
$ id
uid=1000(ec2-user) gid=1000(ec2-user) groups=1000(ec2-user),4(adm),10(wheel),190(systemd-journal),991(docker)
# /proc/<PID>/uid_map
# /proc/<PID>/pid_map
# 첫 번째 컬럼: namespace 내부 UID
# 두 번째 컬럼: 호스트(커널) UID
# 세 번째 컬럼: 범위(size)
0          1000       1

사용자 네임스페이스는 리눅스에서 UID(사용자 ID)와 GID(그룹 ID)를 네임스페이스별로 격리하는 기술이다. 이 기술은 uid_map과 gid_map이라는 매핑 파일을 통해 네임스페이스 내부의 ID를 외부(부모) ID로 변환하여, 내외부의 사용자 및 그룹 ID를 분리한다. 그 결과, 네임스페이스 내부에서는 프로스세가 루트(root) 사용자(UID 0)처럼 행동할 수 있다. 하지만 네임스페이스 밖에서 보면 일반 사용자로 보이며, 프로세스가 가진 권한(capability) 또한 네임스페이스 내로 한정된다. 이러한 특성 덕분에 사용자 네임스페이스는 컨테이너 같은 환경에서 안전하게 관리자 권한을 부여하는 기술로 활용이 된다. 즉, 프로세스가 필요한 관리자 권한을 내부에서만 사용하고, 외부 시스템에는 영향을 주지 않도록 격리하는 것이다.

✅ IPC 네임스페이스(ipc)

IPC 네임스페이스는 운영체제 커널이 제공하는 프로세스 간 통신 자원(공유 메모리, 세마포어[동기화], 메시지 큐 등)을 환경별로 분리해, 마치 각 환경이 자신만의 전용 IPC 리소스를 갖는 것처럼 독립적인 실행 공간을 제공하는 기능이다.

02. Cgroups?

02-1. Cgroups

cgroups(Control Groups)는 리눅스 커널이 프로세스들을 ‘그룹’으로 묶어 CPU, Mem, Disk I/O, 네트워크 대역폭 등의 사용량을 제한하고 관리하는 기능이다. 실제로 자원을 제한하는 방법은 컨트롤러(Controller, 서브시스템)을 통해 자원을 제한한다.

✅ 1. cpu

# 1. CPU cgroup 생성
sudo mkdir /sys/fs/cgroup/cpu/mygroup

# 2. 제한할 프로세스 PID를 이전에 만든 cgroup 그룹에 추가
echo 12345 | sudo tee /sys/fs/cgroup/cpu/mygroup/cgroup.procs

# 3. CPU 비율 제한(shares 방식) - 기본값 1024
# 값이 작을수록 CPU를 적게 할당받음
echo 512 | sudo tee /sys/fs/cgroup/cpu/mygroup/cpu.shares

# 4. CPU 쿼터 제한 (절대 시간 방식)
# period = 100ms, quota = 50ms -> CPU 50% 제한
# 마이크로 단위임 -> 100000 / 1000 => 100ms
echo 100000 | sudo tee /sys/fs/cgroup/cpu/mygroup/cpu.cfs_period_us
echo 50000  | sudo tee /sys/fs/cgroup/cpu/mygroup/cpu.cfs_quota_us

CPU 컨트롤러는 특정 프로세스 그룹이 사용할 수 있는 CPU 시간을 제한한다. 제한 방식은 아래 2가지가 존재한다.

  • 비율 기반 방식(cpu.shares): CPU가 여러 cgroup에서 경쟁이 일어났을때, 미리 정해둔 점수(share 값)에 따라 CPU 시간을 나눠주는 방식이다. 점수가 높을수록 CPU를 더 많은 CPU 시간을 배정받고, 점수가 낮으면 적게 받는다.
  • 절대 시간 방식(cpu.cfs_quota_us / cpu.cfs_period_us): 절대 시간 방식은 CPU 사용을 일정 주기로 제한하는 방식이다. period_us는 주기의 길이(예: 100ms)이고, quota_us는 그 주기 안에서 쓸 수 있는 최대 시간이다.

✅ 2. cpuacct

# 1. cpuacct 전용 cgroup 생성
sudo mkdir /sys/fs/cgroup/cpuacct/mygroup

# 2. 특정 PID(예: 12345)를 그룹에 추가
echo 12345 | sudo tee /sys/fs/cgroup/cpuacct/mygroup/cgroup.procs

# 3. CPU 사용량 확인 (나노초 단위)
cat /sys/fs/cgroup/cpuacct/mygroup/cpuacct.usage

# 4. CPU 사용 통계 확인 (user / system 모드별)
cat /sys/fs/cgroup/cpuacct/mygroup/cpuacct.stat

cpuacct 컨트롤러는 cgroup의 CPU 사용을 제한하는 것이 아니라, 실제 cgroup별로 CPU를 사용한 시간을 기록하는 기능이다. 즉, 특정 그룹이 CPU를 얼마나 썼는지 숫자로 확인할 수 있고, 모니터링이나 과금 확인 시 사용한다.

✅ 3. cpuset

 

[컴퓨터 구조] SMP와 NUMA

개요 Mutilprocessor System의 종류 중 하나인 SMP와 NUMA에 대해 서술한다. 먼저, 컴퓨터 시스템 구성요소의 용어 정의를 할 필요가 있다. CPU : 명령을 실행하는 하드웨어 프로세서(processor) : 하나 이상의

gamedoridori.tistory.com

cpuset은 특정 cgroup을 지정된 CPU 코어 집합과 메모리 노드 집합에만 배치해 실행하도록 강제하는 기능이다. 특히 NUMA 구조에서 프로세스가 가까운 메모리 노드를 사용하게 해 성능 저하를 막고 자원 간섭을 줄이는 역할을 한다.

✅ 4. memory

memory 컨트롤러는 특정 cgroup이 사용할 수 있는 메모리와 스왑 공간을 제한하고, 실제 사용량을 추적한다. 예를 들어 “최대 500MB까지만 사용”처럼 한도를 설정할 수 있고, 초과 시 그룹 내부에서만 OOM Killer가 동작한다. 또한, 애플리케이션이 직접 사용하는 메모리뿐만이 아니라 커널이 내부적으로 관리하는 버퍼나 캐시 같은 메모리까지 제한이 가능하고, 스왑 메모리 공간을 사용할지 말지까지의 여부도 지정 가능하다.

✅ 5. freezer

freezer 컨트롤러는 특정 cgroup에 속한 프로세스를 일시적으로 “멈춤” 상태로 두거나 다시 “재시작” 할 수 있게 해주는 기능이다. 이는 마치 영상을 일시정지(paush) 했다가 다시 재생(play)하는 것과 비슷하다. 프로세스를 완전히 종료하지 않고도 실행을 멈출 수 있기 때문에, 디버깅이나 스냅샷 생성, 체크포인트처럼 프로그램의 상태를 그대로 보존해야 하는 경우 유용하다. freeze 상태에서는 CPU를 전혀 사용하고 있지 않고 멈춰있다가, thaw 상태로 바뀌면 멈췄던 지점에서 그대로 실행을 이어간다.

✅ 6. blkio

블록 I/O 컨트롤러는 특정 cgroup에 속한 프로세스들이 사용할 수 있는 블록 I/O(디스크 입출력)를 제한하고 관리하는 기능이다. 디스크 I/O 처리량(Throughput, MB/s)이나, I/O 요청 횟수(IOPS, 초당 작업 수)를 제어해, 한 그룹이 디스크를 독점하지 못하도록 하고 다른 그룹과의 간섭을 줄인다. 이를 통해 대규모 시스템이나 컨테이너 환경에서 안정적인 I/O 성능을 보장할 수 있다.

✅ 7. net_cls

net_cls 컨트롤러는 특정 cgroup에 속한 프로세스가 발생시키는 네트워크 패킷에 classid 값을 부여한다. 이 classid 값은 tc나 iptables 같은 네트워크 관리 도구가 인식할 수 있는 식별자 역할을 하며, 이를 통해 트래픽을 구분하고 대역폭 제한, 우선순위 지정, 모니터링 같은 정책을 적용할 수 있다.

✅ 8. devices

리눅스의 디바이스란 무엇인지? 리눅스 상의 디바이스(device)라는 것은 우리가 서버에 HDD, SDD, USB, 키보드, NIC 같은 하드웨어(H/W) 장치를 꽃으면, Linux 커널은 이러한 장치들을 인식하게 되는데, 이러한 H/W 장비들은 Application 수준에서 접근이 되면 안된다.

그래서 리눅스 커널은 이런 하드웨어 장치와 프로그램(program)이 직접 소통하지 못하게 하고 중간에 있는 인터페이스를 제공하게 되는데, 해당 인터페이스를 /dev/파일명 형태로 제공한다. 즉, 이 인터페이스가 바로 /dev 디렉토리에 있는 디바이스 파일(device file)이다. 즉, /dev 안에 있는 파일들은 그냥 텍스트 파일이 아니라, “이 파일을 열면, 실제 장치랑 연결된다”는 의미다.

디바이스 종류 
HDD / SSD: /dev/sda, /dev/sdb
USB 메모리: /dev/sdc, /dev/sdd
키보드: /dev/input/event
마우스: /dev/input/mouse


블록 디바이스(저장 장치) 확인 명령어
 
dmesg | grep -i device

device 컨트롤러는 특정 cgroup에 속한 프로세스가 접근할 수 있는 디바이스를 제한하거나 허용하는 역할을 한다. 이를 통해 프로세스가 특정 블록 디바이스나 문자 디바이스(예: 디스크, USB, TTY 등)에 대해 읽기, 쓰기, 실행 권한을 가질 수 있는지 제어할 수 있으며, 불필요한 디바이스 접근은 차단해 보안을 강화할 수 있다.

99. 참고 자료

 

리눅스 네임스페이스(Linux Namespace)란?

리눅스 네임스페이스는 프로세스를 실행할 때 시스템의 리소스를 분리해서 실행할 수 있도록 도와주는 기능입니다. 한 시스템의 프로세스들은 기본적으로 시스템의 리소스들을 공유해서 실행

www.44bits.io

 

Docker(container)의 작동 원리: namespaces and cgroups

리눅스 컨테이너(LXC) 기술이 등장한 이후로 전가상화(full virtualization) 및 반가상화(para virtualization)의 시대가 저물어버렸습니다. Docker는 LXC에서 사용하는 리눅스 커널 컨테이너 기술을 이용해 만

tech.ssut.me

 

GitHub - choisungwook-vagrant/docker: 리눅스 컨테이너 실습

리눅스 컨테이너 실습. Contribute to choisungwook-vagrant/docker development by creating an account on GitHub.

github.com

'Network > Linux - Practice' 카테고리의 다른 글

[Linux] sudo / su / su - 차이  (0) 2025.02.18