ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Docker cgroup v2 및 namespace 실습 가이드 (Ubuntu 24.04)
    Cloud/Container 2024. 8. 6. 23:48

    이 실습을 통해 Ubuntu 24.04 환경의 Docker 컨테이너에서 cgroup v2와 namespace의 실제 구현을 살펴볼 수 있습니다.

    준비 사항

    1. Ubuntu 24.04 LTS
    2. Docker 설치
    3. root 권한 또는 sudo 권한

    1. cgroup v2 살펴보기

    Cgroup(Control Group)은 리눅스 커널에서 프로세스와 자원을 관리하기 위한 메커니즘입니다. cgroup v2는 기존의 cgroup v1의 단점을 개선하고 더 일관된 인터페이스를 제공하기 위해 설계된 최신 버전입니다. cgroup v2의 주요 특징과 개선점은 다음과 같습니다.

    Cgroup v1

    커널 버전별 Cgroup 기능

    Cgroup v2

    주요 특징

    1. 단일한 계층 구조
      • cgroup v2는 단일한 계층 구조를 사용하여 모든 컨트롤러를 통합합니다. 이는 cgroup v1에서 발생할 수 있는 여러 계층 구조로 인한 복잡성을 줄여줍니다.
    2. 일관된 인터페이스
      • cgroup v2는 더 일관된 인터페이스를 제공하여 관리가 용이해졌습니다. 모든 컨트롤러는 유사한 방식으로 동작하며, 일관된 파일과 디렉토리 구조를 가집니다.
    3. 통합된 리소스 관리
      • 메모리, CPU, IO 등 다양한 자원을 통합적으로 관리할 수 있습니다. 이를 통해 리소스 관리가 더 직관적이고 효율적입니다.
    4. cgroup 컨트롤러
      • cgroup v2는 여러 컨트롤러를 지원합니다. 예를 들어, cpu, memory, io 등의 컨트롤러가 있습니다. 각 컨트롤러는 특정 자원을 제어하는 데 사용됩니다.

    cgroup v2는 기존 cgroup v1의 개선된 버전으로, 리눅스 커널에서 프로세스 그룹의 리소스 사용을 제어하고 모니터링하는 메커니즘입니다. 주요 특징과 차이점은 다음과 같습니다:

    1. 단일 계층 구조:

      • v1: 각 리소스 컨트롤러(CPU, 메모리 등)가 독립적인 계층 구조를 가짐
      • v2: 모든 컨트롤러가 단일 통합 계층 구조를 공유
    2. 내부 프로세스 규칙:

      • v1: 계층 구조의 모든 레벨에 프로세스 존재 가능
      • v2: 리프 노드에만 프로세스 존재 가능, 이는 리소스 관리를 더 예측 가능하게 만듦
    3. 리소스 컨트롤러 구성:

      • v1: 각 컨트롤러를 개별적으로 마운트하고 구성
      • v2: 단일 마운트 포인트로 모든 컨트롤러 관리
    4. 향상된 성능과 확장성:

      • v2: 더 효율적인 리소스 관리와 모니터링 제공
    5. 일관된 API:

      • v2: 모든 컨트롤러에 대해 더 일관된 인터페이스 제공
    6. 개선된 프레스 컨트롤:

      • v2: 메모리 프레스와 같은 새로운 기능 도입
    7. 향상된 자원 분배:

      • v2: 더 공정하고 효율적인 리소스 분배 메커니즘 제공
    8. 보안 강화:

      • v2: 일부 취약점 해결 및 보안 기능 강화

    실제 사용에서의 주요 차이점:

    1. 파일 시스템 구조가 변경되어 /sys/fs/cgroup/ 아래에 모든 컨트롤러가 통합됨
    2. 리소스 제한 설정 방식이 변경됨 (예: memory.limit_in_bytes 대신 memory.max 사용)
    3. 일부 설정 파일의 이름과 포맷이 변경됨

    cgroup v2는 더 일관되고 예측 가능한 리소스 관리를 제공하며, 컨테이너와 같은 격리 환경에서 특히 유용합니다. 하지만 기존 v1과의 호환성 문제로 인해 전환 과정에서 일부 어려움이 있을 수 있습니다.

    예시

    # 새로운 cgroup을 생성
    mkdir /sys/fs/cgroup/my_cgroup
    
    # CPU 사용 제한 설정
    echo 50000 > /sys/fs/cgroup/my_cgroup/cpu.max
    
    # 메모리 사용 제한 설정
    echo 100M > /sys/fs/cgroup/my_cgroup/memory.max
    
    # 프로세스를 cgroup에 추가
    echo $$ > /sys/fs/cgroup/my_cgroup/cgroup.procs
    • $$는 셸 스크립트에서 현재 실행 중인 셸 프로세스의 PID(Process ID)를 나타내는 특수 변수입니다. 이를 통해 스크립트 내에서 현재 프로세스의 ID를 쉽게 참조할 수 있습니다.

    이 예시는 새로운 cgroup을 생성하고, 해당 cgroup에 CPU와 메모리 사용 제한을 설정한 후, 현재 쉘 프로세스를 해당 cgroup에 추가하는 과정을 보여줍니다.

    cgroup v2는 리소스 관리와 프로세스 격리를 보다 효율적이고 일관되게 만들기 위해 설계된 최신 메커니즘입니다. 이는 컨테이너화된 환경에서 특히 유용하며, Docker와 Kubernetes와 같은 도구에서 널리 사용됩니다.

    cgroup 이 더 자세히 궁금하신 분을 위해 : (동영상)[https://youtu.be/u8h0e84HxcE?si=uHtIyOdNozN_kLkm]

    1.1 Docker 컨테이너 실행

    docker run -d --name cgroup-test ubuntu sleep infinity

    1.2 컨테이너의 프로세스 ID 찾기

    CONTAINER_PID=$(docker inspect -f '{{.State.Pid}}' cgroup-test)
    echo $CONTAINER_PID

    1.3 cgroup v2 파일 시스템 확인

    ls /sys/fs/cgroup/

    1.4 컨테이너의 cgroup 경로 찾기

    CGROUP_PATH=$(cat /proc/$CONTAINER_PID/cgroup | cut -d: -f3)
    echo $CGROUP_PATH

    1.5 메모리 제한 설정 확인

    cat /sys/fs/cgroup$CGROUP_PATH/memory.max

    1.6 CPU 제한 설정 확인

    cat /sys/fs/cgroup$CGROUP_PATH/cpu.max
    1. memory.max의 결과: max
    2. 이 결과는 해당 cgroup (즉, 이 Docker 컨테이너)에 대해 메모리 사용량 제한이 설정되어 있지 않다는 것을 의미합니다. max는 cgroup v2에서 '제한 없음'을 나타내는 특별한 값입니다. 즉, 이 컨테이너는 호스트 시스템의 가용 메모리를 모두 사용할 수 있습니다.
    3. cpu.max의 결과: max 100000
      • 첫 번째 max: CPU 사용량에 대한 상한선이 없다는 것을 의미합니다.
      • 두 번째 100000: 이는 기준 주기를 마이크로초 단위로 나타낸 것입니다. 100000 마이크로초는 100밀리초, 즉 0.1초입니다.이 설정은 컨테이너가 CPU를 무제한으로 사용할 수 있지만, CPU 시간을 0.1초 단위로 할당받는다는 것을 의미합니다.
    4. 이 결과는 두 부분으로 나뉩니다:

    이러한 결과가 나온 이유는 컨테이너를 실행할 때 특별한 리소스 제한을 설정하지 않았기 때문입니다. 기본적으로 Docker는 컨테이너에 리소스 제한을 두지 않습니다.

    만약 리소스 제한을 설정하고 싶다면, 다음과 같이 컨테이너를 실행할 수 있습니다:

    docker run -d --name resource-limited --memory 512m --cpus 1 ubuntu sleep infinity

    컨테이너의 프로세스 ID 찾기

    CONTAINER_PID=$(docker inspect -f '{{.State.Pid}}' resource-limited)
    echo $CONTAINER_PID

    cgroup v2 파일 시스템 확인

    ls /sys/fs/cgroup/

    컨테이너의 cgroup 경로 찾기

    CGROUP_PATH=$(cat /proc/$CONTAINER_PID/cgroup | cut -d: -f3)
    echo $CGROUP_PATH

    이렇게 실행한 후 같은 명령어로 확인하면 다음과 같은 결과를 볼 수 있을 것입니다:

    cat /sys/fs/cgroup$CGROUP_PATH/memory.max
    536870912  # 512MB를 바이트로 표현
    
    cat /sys/fs/cgroup$CGROUP_PATH/cpu.max
    100000 100000  # 1 CPU core를 의미

    이렇게 설정하면 컨테이너는 최대 512MB의 메모리와 1개의 CPU 코어만 사용할 수 있게 됩니다. 이를 통해 컨테이너의 리소스 사용을 제한하고 관리할 수 있습니다.

    2. 실습: cgroup v2 제한 설정하기

    2.1 메모리 제한 설정

    docker run -d --name memory-test --memory 100m ubuntu stress --vm 1 --vm-bytes 90m --timeout 60s

    메모리 사용량 모니터링:

    docker stats memory-test

    2.2 CPU 제한 설정

    docker run -d --name cpu-test --cpus 0.5 ubuntu stress --cpu 1 --timeout 60s

    CPU 사용량 모니터링:

    docker stats cpu-test

    3. namespace 살펴보기

    리눅스의 네임스페이스(namespace)는 서로 다른 프로세스가 다른 자원들을 독립적으로 사용할 수 있게 해주는 기능입니다. 리눅스 네임스페이스에서 관리할 수 있는 주요 자원의 종류는 다음과 같습니다:

    1. Mount Namespace (mnt)
      • 파일 시스템 마운트를 독립적으로 관리할 수 있게 합니다. 이를 통해 각 컨테이너나 프로세스가 서로 다른 파일 시스템 뷰를 가질 수 있습니다.
    2. Process ID Namespace (pid)
      • 프로세스 ID 번호를 독립적으로 관리할 수 있습니다. 이를 통해 하나의 네임스페이스에서 PID 1인 프로세스가 다른 네임스페이스에서는 다른 PID로 보일 수 있습니다.
    3. Network Namespace (net)
      • 네트워크 장치, IP 주소, 포트 등을 독립적으로 관리할 수 있습니다. 이를 통해 각 네임스페이스가 자신만의 네트워크 스택을 가질 수 있습니다.
    4. Inter-process Communication Namespace (ipc)
      • 메시지 큐, 세마포어, 공유 메모리 등의 IPC 자원을 독립적으로 관리할 수 있습니다. 이를 통해 서로 다른 네임스페이스 간의 IPC 충돌을 방지할 수 있습니다.
    5. UTS Namespace (uts)
      • 호스트 이름과 도메인 이름을 독립적으로 관리할 수 있습니다. 이를 통해 각 네임스페이스가 자신만의 호스트 이름과 도메인 이름을 가질 수 있습니다.
    6. User Namespace (user)
      • 사용자와 그룹 ID를 독립적으로 관리할 수 있습니다. 이를 통해 각 네임스페이스가 다른 사용자와 그룹 ID 맵핑을 가질 수 있으며, 보안성을 높일 수 있습니다.
    7. Control Group Namespace (cgroup)
      • 컨트롤 그룹을 독립적으로 관리할 수 있습니다. 이를 통해 네임스페이스마다 서로 다른 리소스 제한을 설정할 수 있습니다.

    이 네임스페이스들을 조합하여 리눅스 시스템에서 컨테이너를 만들거나, 서로 격리된 환경을 만들 수 있습니다. 이 기능들은 Docker와 같은 컨테이너 기술의 핵심적인 부분을 구성합니다.

    3.1 프로세스의 namespace 정보 확인

    ls -l /proc/$CONTAINER_PID/ns/

    3.2 네트워크 namespace 확인

    sudo nsenter -t $CONTAINER_PID -n ip addr

    3.3 마운트 namespace 확인

    sudo nsenter -t $CONTAINER_PID -m mount

    3.4 PID namespace 확인

    sudo nsenter -t $CONTAINER_PID -p ps aux

    4. 실습: namespace 격리 확인하기

    4.1 네트워크 namespace 격리 확인

    호스트에서 실행:

    ip addr

    컨테이너에서 실행:

    docker run --rm ubuntu ip addr

    4.2 호스트 이름 namespace 격리 확인

    호스트에서 실행:

    hostname

    컨테이너에서 실행:

    docker run --rm ubuntu hostname

    5. cgroup v2 상세 정보 확인

    5.1 메모리 사용량 확인

    cat /sys/fs/cgroup$CGROUP_PATH/memory.current

    5.2 CPU 사용량 확인

    cat /sys/fs/cgroup$CGROUP_PATH/cpu.stat

    6. 정리

    실습이 끝나면 생성한 컨테이너들을 삭제합니다:

    docker rm -f cgroup-test memory-test cpu-test

    이 실습을 통해 Ubuntu 24.04 환경에서 Docker 컨테이너의 cgroup v2 설정과 namespace 격리를 직접 확인하고 경험할 수 있습니다.

Designed by Tistory.