k8s를 공부하면서 리눅스에 대한 공부가 필수라는 것을 점점 더 느낀다.
딥하게 알고 운영하고 싶은 사람으로써 부족한 점을 채우고자 공부하며 정리한 내용을 적어봅니다.
리눅스 컨테이너는 운영체제 수준의 가상화 기술로 리눅스 커널을 공유하면서 프로세스를 격리된 환경에서 실행하는 기술입니다.
커널은 공유되기 때문에 실행 속도가 빠르고 성능상의 손실이 거의 없습니다.
컨테이너로 실행된 프로세스는 커널을 공유하지만 뒤에서 설명한 네임스페이스, cgroup 등을 격리하여 실행되므로 사용자 관점에서는 마치 독립된 환경을 가진 가상 머신처럼 보입니다.
따라서, 컨테이너는 호스트 서버의 운영체제 (리눅스 커널)을 공유합니다.
운영체제를 공유하기에 컨테이너 하나가 차지하는 용량이 작고, 컨테이너가 실행되는 과정도 앱코드 (+ 컨테이너 런타임) -> host의 커널코드로 매우 단순합니다.
이러한 특징을 살려 컨테이너는 개발환경과 운영 환경의 차이에 상관없는 높은 이식성을 가질 수 있었고,
리눅스 컨테이너 안의 앱은 독립적인 파일시스템과 library bin을 가지고 실행되므로, library/bin 버전을 개발환경과 운영 환경 모두에 완전히 동일하게 설정할 수 있었습니다.
이렇게 설명한 컨테이너는 다양한 기술로 구현되지만 크게 네임스페이스, cgroup이 대표적입니다.
이 둘을 좀 더 자세히 알아봅시다.
Cgroup의 C는 control로 프로세스들이 사용하는 하드웨어 양 (CPU, mem, 네트워크 대역폭 등)을 제한하는 기술입니다.
리눅스 커널
Cgroup이 제한할 수 있는 리소스는 CPU, mem, cpuset(개별 CPU 및 메모리 노드를 cgroup에 반인딩하기 위한 서브 시스템), namespace 등
Cgroup은 2가지 버전으로 나눠지는데 2버전이 집중하는 기준이 다르다.
sudo apt update && apt install -y stress
// cgroup 버전 확인
grep cgroup /proc/filesystems
// 현재 쉘의 pid가 어떤 cgroup인지 확인
cat /proc/$$/cgroup
// /sys/fs/cgroup경로로 가서 시스템에 설치된 cgroup 목록을 확인
// cpu를 subtree이 추가하여 컨트롤 할 수 있도록 설정
// +는 추가, -는 삭제임
echo "+cpu" >> /sys/fs/cgroup/test_cgroup_parent/cgroup.subtree_control
cpu.max를 통해 제한 걸기
cpu.max의 첫 번쨰 값은 허용된 시간(마이크로초) 할당량임.
이번 실습에서는 1000000마이크로초(1초) 중에 100000 마이크로초만 실행되게끔 제한을 걸어보자
(1/10만 실행하도록 설정)
echo 100000 1000000 > /sys/fs/cgroup/test_cgroup_parent/cpu.max
cat으로 잘 설정되었는지 확인할 수 있다.
실험을 하기에 앞서, CPU에 부하를 걸어본다.
stress -c 1
# 다른 쉘에서 사용량을 확인해본다.
top
CPU가 100%이다.
test용 자식 디렉토리를 생성하고, pid를 추가하여 제한을 걸어본다.
mkdir test_cgroup_child && cd test_cgroup_child
# 현재 쉘의 pid를 cgroup.procs에 추가
# 현재 pid는 echo $$ 를 통해 알 수 있음
echo $$ > /sys/fs/cgroup/test_cgroup_parent/test_cgroup_child/cgroup.procs
stress -c 1
# 다른 쉘에서 사용량을 확인해본다.
top
네임스페이스는 각 프로세스가 독립적인 파일 시스템, 프로세스 네트워크 인터페이스 등의 뷰를 가질 수 있도록 하는 기술입니다.
namespace vs cgroup
- cgroup : 해당 프로세스가 쓸 수 있는 사용량을 제한
- namespace : 해당 프로세스가 볼 수 있는 범위를 제한
한 시스템의 프로시스들은 기본적으로 시스템의 리소스를 공유해서 실행됩니다. (단일 네임스페이스)
$ diff <(ls -Al /proc/1/ns | awk '{ print $11 }') \
<(ls -Al /proc/1074/ns | awk '{ print $11 }')
위 코드는 1번, 1074번 프로세스 결과 차이를 보여달라는 건데 출력되는 게 없을겁니다.
즉, 리소스를 동일하게 사용하기 때문입니다.