일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 도커 엔진
- 멀티 쓰레드
- filewriter filereader
- java
- 스레드
- 실전 자바 고급 1편
- 스레드 제어와 생명 주기
- 자료구조
- 리스트
- 인프런
- 시작하세요 도커 & 쿠버네티스
- 동시성
- 자바
- Thread
- Collection
- container
- Docker
- java socket
- java network
- 쿠버네티스
- 자바 입출력 스트림
- 알고리즘
- 자바 io 보조스트림
- 컨테이너
- 김영한
- 도커
- Java IO
- Kubernetes
- 쓰레드
- LIST
- Today
- Total
쌩로그
[Docker] 시작하세요! 도커 & 쿠버네티스 - 02_도커 엔진 - 컨테이너 자원 할당 제한 본문
목차
- 포스팅 개요
- 본론
2-1. 컨테이너 메모리 제한
2-2. 컨테이너 CPU 제한
2-3. Block I/O 제한
2-4. 스토리지 드라이버와 컨테이너 저장 공간 제한 - 요약
1. 포스팅 개요
이 포스팅은 위키북스 출판사의 '시작하세요! 도커/쿠버네티스'의 제 2장 도커 엔진에서 컨테이너 자원 할당 제한
에 대한 부분을 학습하며 기록한 포스팅이다.
참고
윈도우를 사용한다면 커맨드(CMD)보단 WSL 을 사용하자.
또한 학습하다보면 디렉터리를 확인할 수 있다고 하는 부분이 있는데,
윈도우에서는 아무리 찾아도 확인하려는 디렉터리를 찾아볼 수 없는 경우가 있었다.
2. 본론
컨테이너를 생성하는 run
, create
명령어에서 컨테이너의 자원 할당량을 조정하도록 옵션을 입력 할 수 있다.
아무런 옵션을 입력하지 않으면 컨테이너는 호스트의 자원을 제한 없이 쓸 수 있게 설정되므로 제품 단계의 컨테이너를 고려한다면 컨테이너의 자원 할당을 제한해 호스트와 다른 컨테이너의 동작을 방해하지 않게 설정하는 것이 좋다.
컨테이너에 자원 할당 옵션을 설정하지 않으면 호스트의 자원을 전부 점유해 다른 컨테이너들뿐 아니라 호스트 자체의 동작이 멈출 수 도 있다.
현재 컨테이너에 설정된 자원 제한을 확인하는 가장 쉬운 방법은 docker inspect
명령어를 입력하는 것이다.
지금까지 테스트한 컨테이너 중 하나를 선택해 inspect
명령을 입력하면 상세한 정보를 확인할 수 있을 것이다.
# ex)
$ docker inspect [컨테이너 이름]
자원 할당을 제한하기 위해 컨테이너에 적용할 수 있는 옵션은 많지만, 지금은 대표적인 몇 가지만 살펴보자.
참고
run
명령어에서 설정된 컨테이너의 자원 제한을 변경하려면 update
명령어를 사용한다.
$ docker update (변경할 자원 제한)(컨테이너 이름)
$ docker update --cpuset-cpus=1 centos ubuntu
2-1. 컨테이너 메모리 제한
docker run
명령어에 --memory
를 지정해 컨테이너의 메모리를 제한할 수 있다.
입력할 수 있는 단위는 m(megabyte)
, g(gigabyte)
이며 제한할 수 있는 최소 메모리는 6MB이다.
다음 명령어는 컨테이너의 메모리 사용량을 1GB로 제한한다.
$ docker run -d --memory="1g" --name memory_1g nginx
위 명령어로 컨테이너를 생성한 뒤 inspect 명령어로 메모리의 값을 확인하면 1GB에 해당하는 바 이트 값이 설정됐음을 확인할 수 있습니다.
$ docker inspect memory_1g | grep "Memory"
"Memory": 1073741824,
컨테이너 내에서 동작하는 프로세스가 컨테이너에 할당된 메모리를 초과하면 컨테이너는 자동으로 종료되므로 애플리케이션에 따라 메모리를 적절하게 할당하는 것이 좋다.
다음 명령어는 메모리를 매우 적게 할당하는 경우로서 6MB의 메모리로 mysql 컨테이너를 실행하면 메모리가 부족해 컨테이너가 실행되지 않는다.
(필자는 6MB로 줬는데도 실행되서 당황해서 1MB로 바꿔서 입력했다. 아래 로그를 보는 것처럼 최소 6MB는 줘야 한다고 나온다.
버전이 올라갔는지 표시되는 에러와 지금은 다른 거 같다... 어쨌든 6MB를 에러는 안 나오지만, 실행은 되지 않는다.)
$ docker run -d --name memory_4m --memory="6m" mysql:5.7
docker: Error response from daemon: Minimum memory limit allowed is 6MB
기본적으로 컨테이너의 Swap 메모리는 메모리의 2배로 설정되지만 별도로 지정할 수 있다.
다음 명령어는 Swap 메모리를 500MB로, 메모리를 200MB로 설정해 컨테이너를 생성한다,
$ docker run -it --name swap_500m --memory=200m --memory-swap=500m ubuntu:14.04
2-2. 컨테이너 CPU 제한
-- cpu-shares
--cpu-shares
옵션은 컨테이너에 가중치를 설정해 해당 컨테이너가 CPU를 상대적으로 얼마나 사용할 수 있는지를 나타낸다.
즉 컨테이너에 CPU를 한 개씩 할당하는 방식이 아닌, 시스템에 존재하는 CPU를 어느 비중만큼 나눠(share) 쓸 것인지를 명시하는 옵션이다.
아래의 명령어는 --cpu-shares
옵션을 사용하는 예시다.
$ docker run -i -t --name cpu_share --cpu-shares 1024 ubuntu:14.04
--cpu-shares
옵션은 상대적인 값을 가진다.
아무런 설정을 하지 않았을 때 컨테이너가 가지는 값은 1024로 이는 CPU 할당에서 1의 비중을 뜻한다.
실제로 --cpu—shares
옵션이 어떻게 동작하는지 확인하기 위해 1개의 CPU를 가지는 호스트에서 간단한 테스트를 해보자.
먼저 다음 명령어를 입력해 컨테이너를 생성한다.
cpu_1024 컨테이너는 --cpu-shares
옵션을 이용해 1024의 값을 할당했다.
컨테이너의 명령어는 1개의 프로세스로 CPU에 부하를 주는 명령어( stress --cpu 1
)로 설정됐다.
$ docker run -d --name cpu_1024 --cpu-shares 1024 alicek106/stress stress --cpu 1
cpu_1024 컨테이너의 CPU 사용률을 확인해 보자.
$ ps aux | grep stress
root 1587 0.0 0.2 7488 1664 ? Ss 15:19 0:00 stress --cpu 1
root 1604 85.4 0.0 7488 128 ? R 15:19 1:05 stress --cpu 1
--cpu-shares
의 값이 1024로 설정됐지만, 호스트에 다른 컨테이너가 존재하지 않기 때문에 CPU를 100% 사용하고 있음을 알 수 있다.
그렇다면 --cpu-shares
의 값이 512로 설정된 컨테이너가 같이 실행된다면 어떻게 될까??
아래의 명령어를 실행해 새로운 컨테이너를 생성해보자.
$ docker run -d --name cpu_512 --cpu-shares 512 alicek106/stress stress --cpu 1
어느 정도 시간이 충분히 흐른 뒤, CPU 사용률을 확인해보자.
$ ps aux | grep stress
root 1934 0.1 0.1 7488 1408 ? Ss 15:23 0:00 stress --cpu 1
root 1953 65.5 0.0 7488 128 ? R 15:23 0:08 stress --cpu 1
root 1987 0.2 0.1 7488 1408 ? Ss 15:23 0:00 stress --cpu 1
root 2006 30.3 0.0 7488 128 ? R 15:23 0:02 stress --cpu 1
두 컨테이너가 각각 65%, 30%의 CPU를 사용하고 있으며 약 2:1의 비율로 CPU를 나눠쓰고 있는 것을 확인할 수 있다.
즉, [1024 : 512 = 2 : 1]
의 비율대로 시스템의 CPU를 사용하는 것을 알 수 있다.
이처럼 --cpu-shares
에 설정된 값의 비율에 따라 컨테이너가 CPU를 사용할 수 있는 비율이 정해진다.
참고
위에서 사용한 stress
라는 명령어는 CPU와 메모리에 과부하를 줘서 성능을 테스트한다.
우분투 컨테이너에서는 다음 명령어로 설치할 수 있다.
alicek106/stress 도커 이미지는 미리 준비한 stress
가 설치 된 우분투 이미지다.
$ apt-get install stress
위에서 생성한 컨테이너는 -d
옵션으로 생성되어 백그라운드에서 계속 CPU에 부하를 주므로 테스트가 끝나면 반드시 컨테이너를 삭제해야 한다.
--cpuset-cpus
(CPU를 3개 혹은 4개로 설정하고 진행하자.)
호스트에 CPU가 여러 개 있을 때 --cpuset-cpus
옵션을 지정해 컨테이너가 특정 CPU만 사용하도록 설정할 수 있다.
CPU 집중적인 작업이 필요하다면 여러 개의 CPU를 사용하도록 설정해 작업을 적절하게 분배하는 것이 좋다.
다음 명령어 예시는 컨테이너가 3번째 CPU만 사용하도록 설정한다.
$ docker run -d --name cpuset_2 --cpuset-cpus=2 alicek106/stress stress --cpu 1
CPU별로 사용량을 확인할 수 있는 대표적인 도구로 htop
이 있으며,
우분투와 Rocky 리눅스에서 각각 아래의 명령어를 입력해 설치할 수 있다.
우분투 : apt-get install htop
Rocky : sudo dnf install epel-release / dnf install htop
htop 명령어로 CPU 사용량을 확인하면 3번째 CPU만 사용되는 것을 알 수 있다.

(참고로 알록달록한 건 putty 설정이다
n번 째 CPU는 보통 운영체제가 인식한 CPU 코어(또는 논리 프로세서)를 번호로 구분한 것을 의미한다고 한다.(GPT가)
참고
--cpuset-cpus="0,3"
은 1, 4번째 CPU를, --cpuset-cpus="0-2"
는 1, 2, 3번째 CPU를 사용하도록 설정한다.
--cpu-period, --cpu-quota
컨테이너의 CFS(Completely Fair Scheduler) 주기는 기본적으로 100ms로 설정되지만 run
명령어의 옵션 중 --cpu-period
와 --cpu-quota
로 이 주기를 변경할 수 있다.
다음 명령어를 입력해 컨테이너를 생성하자.
$ docker run -d --name quota_1_4 --cpu-period=100000 --cpu-quota=25000 alicek106/stress stress --cpu 1
--cpti-period
의 값은 기본적으로 100000이며, 이는 100ms를 뜻한다.--cpu-quota
는 --cpu-period
에 설정된 시간 중 CPU 스케줄링에 얼마나 할당할 것인지를 설정한다.
위 예시에서 100000(--cpu-period) 중 25000(--cpu-quota)만큼을 할당해 CPU 주기가 1/4로 줄었으므로 일반적인 컨테이너보다 CPU 성능이 1/4 정도로 감소한다.
즉, 컨테이너는 [--cpu-quota 값] / [—-cpu-period 값]
만큼 CPU 시간을 할당받는다.
성능 비교를 위해 다음 명령어로 컨테이너를 추가로 생성한다.
$ docker run -d --name quota_1_1 --cpu-period=100000 --cpu-quota=100000 alicek106/stress stress --cpu 1
htop
명령어나 ps aux | grep stress
로 CPU 할당량을 확인하면 첫 번째 컨테이너가 1/4만큼 CPU 를 적게 사용하고 있음을 알 수 있다.
$ ps aux | grep stress
root 2381 0.1 0.2 7488 1536 ? Ss 15:55 0:00 stress --cpu 1
root 2403 25.6 0.0 7488 128 ? R 15:55 0:03 stress --cpu 1
root 2445 0.3 0.2 7488 1536 ? Ss 15:55 0:00 stress --cpu 1
root 2467 96.1 0.0 7488 128 ? R 15:55 0:07 stress --cpu 1
--cpus
--cpus
옵션은 --cpu-period
, --cpu-quota
와 동일한 기능을 하지만 좀 더 직관적으로 CPU의 개수를 직접 지정한다는 점에서는 다르다.
예를 들어, --cpus
옵션에 0.5를 설정하면 --cpu-period=100000
또는 --cpu-quota=50000
과 동일하게 컨테이너의 CPU를 제한할 수 있다.
$ docker run -d --name cpus_container --cpus=0.5 alicek106/stress stress --cpu 1
마찬가지로 컨테이너의 사용량을 확인해보면 CPU의 약 50%를 점유하고 있음을 알 수 있다.
$ ps aux | grep stress
root 2733 0.3 0.1 7488 1408 ? Ss 15:58 0:00 stress --cpu 1
root 2757 50.7 0.0 7488 128 ? R 15:58 0:04 stress --cpu 1
참고
병렬 처리를 위해 CPU> 많이 소모하는 워크로드를 수행해야 한다면 --cpu-share
, --cpus --cpu-period
, --cpu-quota
옵션보다는 --cpuset-cpu
옵션을 사용하는 것이 좋다.--cpuset-cpu
옵션을 사용하면 특정 컨테이너가 특정 CPU에서만 동작는 CPU 친화성(Affinity)을 보장할 수 있고 CPU 캐시 미스 또는 컨텍스트 스위칭과 같이 성능을 하락시카는 요안을 최소화할 가능성이 높아지기 때문이다.
2-3. Block I/O 제한
컨테이너를 생성할 때 아무런 옵션도 설정하지 않으면 컨테이너 내부에서 파일을 읽고 쓰는 대역폭 에 제한이 설정되지 않는다.
하나의 컨테이너가 블록 입출력을 과도하게 사용하지 않게 설정하려면 run
명령어에서 --device-write-bps
, --device-read-bps
, --device-write-iops
, --device-read-iops
옵션을 지정해 블록 입출력을 제한할 수 있다.
단, Direct I/O
의 경우에만 블록 입출력이 제한되며, Buffered I/O
는 제한되지 않는다.
--device-write-bps
, --device-read-bps
는 각기 쓰고 읽는 작업의 초당 제한을 설정하며, kb, mb, gb 단위로 제한할 수 있다.
예를 들어, 다음 명령어로 컨테이너를 생성하면 초당 쓰기 작업의 최대치가 1MB로 제한된다.
# AWS EC2
$ docker run -it --device-write-bps /dev/xvda:1mb ubuntu:14.04
# Oracle VirtualBox Rocky-Linux
$ docker run -it --device-write-bps /dev/sda:1mb ubuntu:14.04
참고
여기서 사용되는 Block I/O를 제한하는 옵션은 [디바이스 이름]:[값]
형태로 설정해야 한다.
저자는 AWS의 EC2 인스턴스에서 테스트했기 때문에 /dev/xvda
라는 디바이스를 사용하고 있으며, 이 디바이스에서 컨테이너의 저장 공간을 할당받고 있어 /dev/xvda:1mb
로 설정했다고 한다.
나는 Oracle VirtualBox의 Rocky Linux를 사용 중이라 sda로 지정했다.
단, devicemapper
를 스토리지 드라이버를 사용하는 도커 엔진에서 루프 디바이스를 스토리지로 사용하고 있다면 /dev/loop0:1mb
와 같은 형식으로 써야 한다.
위 명령어로 생성된 컨테이너에서 쓰기 작업을 테스트해보면 속도가 초당 1MB로 제한되는 것을 확인할 수 있다.
다음 명령어는 10MB의 파일을 Direct I/O
를 통해 쓰기 작업을 수행한다.
root@767e43667c45:/# 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) copied, 10.0096 s, 1.0 MB/s
CPU의 자원 할당에서 --cpu-share
에 상대적인 값을 입력했던 것처럼 --device-write-iops
, --device-read-iops
에도 상대적인 값을 입력한다.
예를 들어, --device-write-iops
의 값이 2배 차이 나는 컨테이너로 쓰기 작업을 수행하면 수행 시간 또한 2배 가량 차이가 나는 것을 알 수 있다.
$ docker run -it --device-write-iops /dev/sda:5 ubuntu:14.04
root@1e58d560485a:/# 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) copied, 5.80695 s, 1.8 MB/s
$ docker run -it --device-write-iops /dev/sda:10 ubuntu:14.04
root@98d2814d71c9:/# 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) copied, 1.91865 s, 5.5 MB/s
2-4. 스토리지 드라이버와 컨테이너 저장 공간 제한
- 도커 엔진은 컨테이너 내부의 저장 공간을 제한하는 기능을 보편적으로 제공하지는 않지만, 도커의 스토리지 드라이버나 파일 시스템 등이 특정 조건을 만족하는 경우에만 이 기능을 제한적으로 사용 할 수 있다.
- 아직 도커의 스토리지 드라이버 개념을 설명하지 않았기 때문에 이번 절에서는 이에 대해 자세히 설명하지는 않으며, 이후 컨테이너의 저장 공간을 제한하는 방법을 다시 다룬다.
- 단, 모든 스토리지 드라이버에서 컨테이너의 저장 공간을 제한할 수 있는 것은 아니다.
- 따라서 컨테이너 애플리케이션이 해당 스토리지 드라이버에 적합하지 않다면 이 기능을 사용하지 않는 것이 좋을 수도 있다.
- 또한 컨테이너 내부에서 개발하고 있거나, 그 외의 다른 특별한 상황이 아니라면 컨테이너 자체가 상태를 가지는(stateful) 것은 그다지 바람직하지 않다.
- 따라서 컨테이너의 저장 공간을 제한하지 않는다는 선택지도 고려해 볼 수 있다.
3. 요약
컨테이너에 자원 할당에 대해서 알아봤다.
'Deploy > Docker' 카테고리의 다른 글
[Docker] 시작하세요! 도커 & 쿠버네티스 - 02_도커 엔진 - 도커 컨네이너 로깅 (0) | 2025.03.03 |
---|---|
[Docker] 시작하세요! 도커 & 쿠버네티스 - 02_도커 엔진 - 도커 네트워크 (1) | 2025.02.28 |
[Docker] 시작하세요! 도커 & 쿠버네티스 - 02_도커 엔진 - 도커 볼륨 (1) | 2025.02.27 |
[Docker] 시작하세요! 도커 & 쿠버네티스 - 02_도커 엔진_컨테이너 다루기(명령어 및 애플리케이션 구축) (0) | 2025.02.27 |
[Docker] 시작하세요! 도커 & 쿠버네티스 - 01_도커란 (0) | 2025.02.27 |