Simple is IT, 누구나 보고 누구나 깨닫는 IT

Docker 컨테이너 자원 할당 제한_Memory, CPU, Block I/O 본문

Simple is IT/Cloud & Container

Docker 컨테이너 자원 할당 제한_Memory, CPU, Block I/O

currenjin 2020. 7. 23. 13:16

Docker 컨테이너 자원 할당 제한

우리가 컨테이너를 생성할 때 따로 옵션을 지정하지 않으면 컨테이너는 호스트의 자원을 제한 없이 쓸 수 있게 설정이 됩니다!

만약 우리가 제품 단계의 컨테이너를 고려한다면 자원에 대해 예민해져야 해요.

 

Memory, CPU, Block I/O 제한

컨테이너를 생성하는 run, create 명령어에서 컨테이너의 자원 할당량을 조정하도록 옵션을 설정할 수 있답니다.

 

기존에 만들어져있는 컨테이너에 대해 자원 제한을 변경하려면 update 명령을 입력해주세요.

docker update [resource limit] [container name]

 

자원이 제한되어 있는 컨테이너를 확인하기 위해선 inspect 명령어를 입력하세요.

docker inspect [container name]

# docker inspect ubuntu
.....
        "HostConfig": {
            .....
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DiskQuota": 0,
            "KernelMemory": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": 0,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            .....
.....

기본값은 0이군요!

 


Container Memory

 

docker run 명령에 --memory 옵션을 지정해 메모리를 제한할 수 있습니다!

docker run -itd --name memory_1g \
--memory=1g \
ubuntu:16.04

입력할 수 있는 단위는 m(megabyte), g(gigabyte)에요. 최소로 제한할 수 있는 메모리는 4MB랍니다.

 

inspect 명령으로 확인해보니 잘 적용 되었네요.

# docker inspect memory_1g | grep \"Memory\"
    "Memory": 1073741824,

 

주의하세요!

컨테이너 내의 프로세스가 컨테이너에 할당된 메모리를 초과하면 컨테이너는 자동으로 종료됩니다.
그렇기 때문에 애플리케이션에 따라 메모리를 적절하게 할당하는 것이 좋죠.

 

아래 명령은 메모리를 매우 적게 할당하는 경우로서 4MB 메모리로 mysql 컨테이너를 실행하면 메모리가 부족해 컨테이너가 실행이 되지 않는 상황입니다.

docker run -d --name memory_4m \
--memory=4m \
mysql

기본적으로 컨테이너의 Swap 메모리는 메모리의 2배로 설정되지만 별도로 지정할 수도 있어요!

docker run -it --name swap_500m \
--memory=200m \
--memory-swap=500m \
ubuntu:16.04

Swap 메모리를 500MB로, 메모리를 200MB로 설정해 컨테이너를 생성했습니다 ㅎㅎ

 


Container CPU

 

--cpu-shares

--cpu-shares 옵션은 컨테이너의 가중치를 설정해 해당 컨테이너가 CPU를 상대적으로 얼마나 사용하는지를 나타냅니다!

즉, CPU의 개수를 할당하는 것이 아닌 CPU를 나누는 비중을 정의하는 것입니다.

docker run -it --name cpu_share \
--cpu-shares 1024 \
ubutnu:16.04

아무 컨테이너도 설정되어있지 않기 때문에 cpu_share 컨테이너에 할당하는 CPU 비중은 1이에요.

stress 옵션을 통해 cpu 부하를 줄게요.

# docker run -d --name cpu_1024 \
--cpu-shares 1024 \
alicek106/stress stress --cpu 1

(stress 패키지가 설치된 alicek106님의 이미지를 사용했어요)

 

CPU 사용률을 확인해볼까요?

# ps aux | grep stress
root      38833  0.1  0.0   7484  1024 ?        Ss   12:26   0:00 stress --cpu 1
root      38880 96.4  0.0   7484    96 ?        R    12:26   0:14 stress --cpu 1

제한된 cpu 값이 1024이지만 대부분의 사용률을 차지하고 있습니다.

이 상태에서 cpu 값이 512만큼 사용하는 컨테이너를 생성하면 어떻게 될까요?

# docker run -d --name cpu_512 \
--cpu-shares 512 \
alicek106/stress stress --cpu 1

 

시간이 지나고 CPU 사용률을 확인해볼게요.

# ps aux | grep stress
root      38833  0.0  0.0   7484  1024 ?        Ss   12:26   0:00 stress --cpu 1
root      38880 70.0  0.0   7484    96 ?        R    12:26  19:27 stress --cpu 1
root      39105  0.0  0.0   7484   948 ?        Ss   12:30   0:00 stress --cpu 1
root      39150 33.2  0.0   7484    92 ?        R    12:30   8:12 stress --cpu 1

두 컨테이너가 각각 [1024 : 512 = 2 : 1] 비율로 CPU를 나누어 쓰는군요!

 

--cpuset-cpus

호스트에 CPU가 여러 개 있을 때 해당 옵션을 지정해 컨테이너가 특정 CPU만 사용하도록 해요.

아래는 컨테이너가 3번째 CPU만 사용하도록 설정하는 명령입니다.

docker run -d --name cpuset_2 \
--cpuset-cpus=2 \
alicek106/stress stress --cpu 1

 

--cpu-period, --cpu-quota

컨테이너의 CFS 주기는 기본적으로 100ms로 설정됩니다. 하지만 위 옵션을 통해 주기를 변경할 수 있지요.

--cpu-period 값은 기본적으로 100000이며, 100ms를 뜻해요. --cpu-quota 옵션은 --cpu-period에 설정된 시간 중 CPU 스케줄링에 얼마나 할당할 것인지를 설정합니다.

docker run -d --name quota \
--cpu-period=100000 \
--cpu-quota=25000 \
alicek106/stress stress --cpu 1

 

이 예시에서는 100000 중 25000 만큼 할당해 CPU 주기가 1/4로 줄었으므로 일반적인 컨테이너보다 CPU 성능이 1/4로 감소해요.

 

1/4으로 줄은 만큼의 사용률을 확인해보면 쉽게 이해할 수 있어요!

# ps aux | grep stress
root      39893  0.1  0.0   7484   936 ?        Ss   13:00   0:00 stress --cpu 1
root      39941 25.7  0.0   7484    92 ?        R    13:00   0:04 stress --cpu 1

 

--cpus

이 옵션은 --cpu-period, --cpu-quota 옵션과 동일하지만 더욱 직관적이에요. CPU의 개수를 직접 지정하거든요.

docker run -d --name cpus \
--cpus=0.25 \
alicek106/stress stress --cpu 1

 

quota를 이용한 설정과 cpus 옵션의 CPU 사용률을 서로 비교해봤어요.

# ps aux | grep stress

[--cpu-period, --cpu-quota]
root      39941 25.0  0.0   7484    92 ?        R    13:00   1:17 stress --cpu 1

[--cpus]
root      40215 25.1  0.0   7484    92 ?        R    13:04   0:23 stress --cpu 1

사용하는 비율이 동일하군요!

 


Container Block I/O

 

우리가 컨테이너를 생성할 때 아무런 옵션도 설정하지 않으면 컨테이너 내부에서 파일을 읽고 쓰는 대역폭에 제한이 설정되지 않아요.

한 컨테이너에서 블록 입출력을 과도하게 사용하지 않도록 설정하려면 아래 옵션이 필요해요.

[절대적인 값으로 제한]
--device-write-bps
--device-read-bps

[상대적인 값으로 제한]
--device-write-iops
--device-read-iops

 

--device-write-bps, --device-read-bps

docker run -it \
--device-write-bps /dev/sda:1mb \
ubuntu:16.04

위 명령어로 생성된 컨테이너에서 쓰기 작업을 테스트 해보면 제한되는 것을 확인할 수 있어요.

root@0ba7400b69af:/# dd if=/dev/zero of=test.out bs=1M count=10 oflag=direct
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 15.001 s, 699 kB/s

 

--device-write-iops, --device-read-iops

--device-write-iops 값이 약 2배 차이나는 컨테이너에 쓰기 작업을 수행하면 시간 또한 2배 가량 차이가 나게돼요.

[컨테이너 생성]
docker run -it \
--device-write-iops /dev/sda:5 \
ubuntu:16.04

[쓰기 작업 수행]
root@459696708c1d:/# dd if=/dev/zero of=test.out bs=1M count=10 oflag=direct
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 4.00854 s, 2.6 MB/s
[컨테이너 생성]
docker run -it \
--device-write-iops /dev/sda:10 \
ubuntu:16.04

[쓰기 작업 수행]
root@38a1ba0be9a6:/# dd if=/dev/zero of=test.out bs=1M count=10 oflag=direct
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 2.00477 s, 5.2 MB/s

 

Comments