Linux namespace, cgroup 정리
Linux의 namespace와 cgroup은 커널의 기능이다. 커널의 기능에 대해 깊게 아는것은 당장은 힘들지만, 2개의 기능(namespace, cgroup)이 어떤 개념과 원리로 사용되는지 간략히 정리해본다.
namespace(자원 격리)
VM
(Virtual Machine)에서는 각 Guest 머신
(Guest OS)별로 독립적인 공간
이 제공
된다.
이로 인해 Guest 머신 끼리
서로 충돌하지 않는다.
리눅스
에서 이와 동일한 역할
을 하는 namespace
기능이 커널
에 내장
되어 있다.namespace
는 리눅스 커널의 리소스
를 논리적
으로 분리
하는 역할
을 한다.
- namespace aaa는 process에 포함
- namespace bbb도 process에 포함
- namespace ccc는 network에 포함
- namespace ddd는 filesystem에 포함
- Python + /bin/bash 도 각각 namespace에 맞춰서 포함됨
리눅스
가 부팅
이 되면 여러 namespace
가 생성
이 된다.제일 처음 실행
되는 init process
가 생성 된 namespace
와 연결
이 된다.
또한 우리가 실행
하는 프로세스는
init 프로세스와 연결된 namespace를 같이 사용
한다.
리눅스 커널 namespace 종류
리눅스 커널에서는 아래 6가지 namespace를 지원한다.
네임스페이스 종류 | 설명 |
---|---|
mnt(파일시스템 마운트) | 호스트 파일시스템에 구애받지 않고 독립적으로 파일시스템 마운트 or 언마운트 |
pid(프로세스) | 독립적인 프로세스 공간 할당 |
net(네트워크) | namespace 간 네트워크 충돌 방지 (중복 포트 바인딩 등) |
ipc(SystemV IPC) | 프로세스 간 독립적인 통신 통로 할당 |
uts(hostname) | 독립적인 hostname 할당 |
user(UID) | 독립적인 사용자 할당 |
namespace 테스트
# 현재 bash shell의 PID 확인
$ echo $$
2820
- 현재 프로세스의 PID는
2820
를 갖는다 - 다음으로 해당 PID의 namespace를 찾기 위해 /proc/2820 경로로 이동하자
# 프로세스 정보를 가지고 있는 DIR로 이동
# cd /proc/2820 임
$ cd /proc/$$
# 해당 프로세스에 대한 정보를 아래와 같이 전부 확인 가능
$ ls
arch_status clear_refs cwd gid_map map_files mountstats oom_score projid_map setgroups statm timers
attr cmdline environ io maps net oom_score_adj root smaps status timerslack_ns
autogroup comm exe latency mem ns pagemap sched smaps_rollup syscall uid_map
auxv coredump_filter fd limits mountinfo numa_maps patch_state schedstat stack task wchan
cgroup cpuset fdinfo loginuid mounts oom_adj personality sessionid stat timens_offsets
# namespace dir로 이동
$ cd ns
$ ll
total 0
lrwxrwxrwx. 1 root root 0 Oct 1 09:07 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx. 1 root root 0 Oct 1 09:07 ipc -> 'ipc:[4026531839]'
lrwxrwxrwx. 1 root root 0 Oct 1 09:07 mnt -> 'mnt:[4026531841]'
lrwxrwxrwx. 1 root root 0 Oct 1 09:07 net -> 'net:[4026531840]'
lrwxrwxrwx. 1 root root 0 Oct 1 09:07 pid -> 'pid:[4026531836]'
lrwxrwxrwx. 1 root root 0 Oct 1 09:07 pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx. 1 root root 0 Oct 1 09:07 time -> 'time:[4026531834]'
lrwxrwxrwx. 1 root root 0 Oct 1 09:07 time_for_children -> 'time:[4026531834]'
lrwxrwxrwx. 1 root root 0 Oct 1 09:07 user -> 'user:[4026531837]'
lrwxrwxrwx. 1 root root 0 Oct 1 09:07 uts -> 'uts:[4026531838]'
위 경로
에서 namespace 관련 정보
를 확인이 가능하다.
해당 PID(2820)에 매핑된 namespace의 ID[4026531835, 4026531839..]를 확인할 수 있는데,
그렇다면 init process와 동일한 namespace를 쓰는건 맞는지 확인 해보자.
# 관리자 전환
$ sudo su
# init process의 namespace 경로로 이동
$ cd /proc/1/ns
# init process의 namespace 확인
$ ll
total 0
lrwxrwxrwx. 1 root root 0 Oct 1 08:55 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx. 1 root root 0 Oct 1 09:14 ipc -> 'ipc:[4026531839]'
lrwxrwxrwx. 1 root root 0 Oct 1 09:14 mnt -> 'mnt:[4026531841]'
lrwxrwxrwx. 1 root root 0 Oct 1 09:14 net -> 'net:[4026531840]'
lrwxrwxrwx. 1 root root 0 Oct 1 09:14 pid -> 'pid:[4026531836]'
lrwxrwxrwx. 1 root root 0 Oct 1 09:14 pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx. 1 root root 0 Oct 1 09:14 time -> 'time:[4026531834]'
lrwxrwxrwx. 1 root root 0 Oct 1 09:14 time_for_children -> 'time:[4026531834]'
lrwxrwxrwx. 1 root root 0 Oct 1 09:14 user -> 'user:[4026531837]'
lrwxrwxrwx. 1 root root 0 Oct 1 09:14 uts -> 'uts:[4026531838]'
init process의 ns를 확인한 결과 이전 Bash의 PID와 동일한 namespace ID 사용중이다.
여기서 중요
한건 "같은 namespace를 쓰는건 같은 리소스를 사용"
한다는 점을 알아야 한다.
즉, 서로 같은 파일
, 네트워크
, 프로세스 정보
에 접근 가능
.
$ ls /home/ec2-user
terraform
2개의 터미널 창에서 위 명령어를 치면 동일한 내용을 출력 된다.
이게 가능한 이유는 2개의 프로세스가 동일한 namespace(filesystem + PID)를 공유하기 때문이다.
💡 이번 장에서 가장 중요한 키워드
- 1) (중요)
Docker
는init process
의namespace를 사용하지 않는다
- 2) (중요)
Docker 컨테이너
는리눅스
의프로세스
라는 점이다
- 1) 컨테이너 엔진 관점
- H/W > 리눅스 OS > Docker Engine > Container가 존재
- 2) Linux OS 입장 관점
- H/W > 리눅스 OS > container application(이거를 Linux는 1개의 process로 바라본다) > container process 1 + process 2 + process 3
- Linux OS 입장에서는 Container Application 1개 떠있는거임
- 그 Container Application process를 만들어서 관리하는걸로 본다
EC2 > Docker Ubuntu container 구동 후 sleep 테스트
root@bdad3d9d3376:/# sleep 10000 &
[1] 10
root@bdad3d9d3376:/# ps
PID TTY TIME CMD
1 pts/0 00:00:00 bash
10 pts/0 00:00:00 sleep
11 pts/0 00:00:00 ps
EC2 서버
에서Ubuntu Container 구동
후sleep 함수 실행
- 그렇다면 위 sleep 프로세스는 누가 관리를 하게 될까?
- (중요)
위 프로세스
는해당 컨테이너를 구동한 Linux에서 관리
한다 - (중요) 위에서 말했다시피
Docker Container
는Linux의 프로세스
(process)이기 때문이다
- (중요)
Docker Container의 namespace?
결과적으로 Docker Container
는 init process
의 namespace
를 사용하지 않는다
.Docker Container Engine
이 namespace
생성 후
docker container에 연결
한다.
각 서버에서 /proc/1/ns 경로로 이동한 후의 사진이며, namespace가 다르다는 것을 확인할 수 있다.
결국 이러한 부분
은 호스트 시스템과 Docker의 namespace는 논리적으로 다른 자원을 사용
한다 봐야 한다.
정리
정리하면 컨테이너 자체
는 Linux 프로세스
이고 같은 리눅스 커널
에서 돌아간다.
이걸 분리 시킨 개념은 리눅스 namespace를 개별적으로 같게
해서 마치 자기만의 Linux 리소스를 가진 것처럼 착각을 만들게 할 수 있다
.
아래와 같이 다른 ns를 가진것도 있고 같은 ns를 가진 부분도 존재
한다.
# 1번째 ubuntu container
root@43c4234ae89c:/proc/1/ns# ls -l
total 0
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 cgroup -> 'cgroup:[4026532308]'
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 ipc -> 'ipc:[4026532237]'
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 mnt -> 'mnt:[4026532235]'
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 net -> 'net:[4026532239]'
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 pid -> 'pid:[4026532238]'
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 pid_for_children -> 'pid:[4026532238]'
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 time -> 'time:[4026531834]'
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 time_for_children -> 'time:[4026531834]'
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 user -> 'user:[4026531837]'
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 uts -> 'uts:[4026532236]'
# 2번째 ubuntu container
root@e5a41f1ef391:/proc/1/ns# ls -l
total 0
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 cgroup -> 'cgroup:[4026532383]'
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 ipc -> 'ipc:[4026532312]'
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 mnt -> 'mnt:[4026532310]'
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 net -> 'net:[4026532314]'
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 pid -> 'pid:[4026532313]'
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 pid_for_children -> 'pid:[4026532313]'
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 time -> 'time:[4026531834]'
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 time_for_children -> 'time:[4026531834]'
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 user -> 'user:[4026531837]'
lrwxrwxrwx. 1 root root 0 Oct 1 10:22 uts -> 'uts:[4026532311]'
cgroups(Control Groups)
cgroups
(Control Groups)은 리소스
(resources) 제어를
수행하는 커널
의 기능
이다.컨테이너 기술
은 namespace
를 통해 자원을 격리
하고, 해당 프로세스가 사용하는 자원
은 cgroups
를 통해 제어
한다.
cgroups(Control Groups)은 아래 리소스 제어가 가능하다.
- CPU
- Mem
- I/O
- Network
- device 노드(/dev/)
cgroup 서브 시스템
서브시스템 | 설명 |
---|---|
CPU | - CPU 사용량 제어 - 각 그룹에 CPU 시간 할당 |
cpuacct | - CPU 사용량 모니터링 - 각 그룹의 CPU 사용량 통계 제공 |
Memory | - 메모리 사용량 제어 - 메모리 사용량 통계 제공 - OOM 시 특정 그룹 프로세스 종료 가능 |
blkio | - 블록 장치 I/O 사용량 제어 - 디스크 읽기/쓰기 속도 제한 |
net_cls | - 네트워크 트래픽 분류 및 제어 - 각 그룹에 고유 클래스 ID 할당하여 트래픽 관리 |
devices | - 특정 장치에 대한 접근 권한 제어 - 각 그룹의 장치 접근 허용 및 차단 |
freezer | - 프로세스 일시 중단/재개 - 시스템 관리 작업 중에 프로세스 중단 가능 |
cpuset | - 개별 CPU 메모리 노드를 cgroup에 할당 |
ns | - Namespace 서브시스템, 프로세스의 이름 공간 관리 |
cgroup v1 vs cgroup v2
- cgroupv1: 각 리소스별로 따로 관리한다. 예를 들어 CPU, Mem, I/O같은 자원을 각각 따로 나눠서 제어한다.
즉, CPU 그룹, 메모리 그룹처럼 자원을 기준으로 그룹을 나누는 방식을 의미한다. - cgroupv2: 여러 자원을 하나의 그룹에서 통합적으로 관리한다. CPU, 메모리, I/O 같은 자원을
하나의 그룹에 묶어서 프로세스 단위로 관리한다. 즉, 하나의 그룹이 여러 리소스 동시 제어.
99. 참고 자료
GitHub - choisungwook-vagrant/docker: 리눅스 컨테이너 실습
리눅스 컨테이너 실습. Contribute to choisungwook-vagrant/docker development by creating an account on GitHub.
github.com
Docker(container)의 작동 원리: namespaces and cgroups
리눅스 컨테이너(LXC) 기술이 등장한 이후로 전가상화(full virtualization) 및 반가상화(para virtualization)의 시대가 저물어버렸습니다. Docker는 LXC에서 사용하는 리눅스 커널 컨테이너 기술을 이용해 만
tech.ssut.me
TLDR Understanding the new cgroups v2 API by Rami Rosen
Cgroups v2 is a new API designed to make it more suitable for container resource limitation.
medium.com
'Containerize > Docker - Experience' 카테고리의 다른 글
[Docker] Docker commit, save, load 차이점 정리 (0) | 2025.01.06 |
---|---|
[Docker] Dockerfile 옵션 관련 정리(ADD, COPY, ENV, ARG, ENTRYPOINT, FROM) (1) | 2024.02.07 |
[Docker] Docker, Kubernetes, EKS 까지의 흐름 (0) | 2023.04.23 |
[Docker] Docker 기본 명령어 정리 (0) | 2023.04.23 |