UTM 실행하여 리눅스 환경 준비

ssh 로그인

cgroup
namespace
chroot
유닉스 도메인 소켓
overlayFS
cgroups (control groups)는 리눅스 커널 기능으로, 프로세스 그룹을 조직하고 관리할 수 있게 한다. 이를 통해 CPU, 메모리, 디스크 I/O 등의 자원을 제한하고 할당할 수 있다. cgroups를 사용하면 프로세스 그룹에 자원 제한을 설정하거나 모니터링 가능함.
cgroup cpu 제한 실습
# cgroup-tools 및 stress 패키지 설치
sudo apt-get install cgroup-tools stress
# cgroup을 이용한 CPU 제한 실습
# 새로운 cgroup을 생성하여 'cpulimit'이라는 이름을 지정
sudo cgcreate -g cpu:/cpulimit
# 'cpu.max' 파일에 50000을 작성하여 CPU 사용량을 제한
# 50000 마이크로초 (50 밀리초) 동안의 CPU 사용 시간을 허용하고, 100000 마이크로초 (100 밀리초) 주기 내에서 제한
echo "50000 100000" | sudo tee /sys/fs/cgroup/cpu/cpulimit/cpu.max
# 'cpulimit' cgroup 안에서 stress 명령어를 실행하여 CPU 2개와 VM 1개를 30초 동안 사용
sudo cgexec -g cpu:/cpulimit stress --cpu 2 --vm 1 --timeout 30s &
# top 명령어를 실행하여 현재 시스템 상태를 모니터링
top
# 'cpulimit' cgroup 삭제
sudo cgdelete -g cpu:/cpulimit
top 명령어 이용해서 시스템 상태 모니터링, 실행중인 프로세스와 시스템 자원 사용률 등이 보인다. q를 눌러서 나간다.
하단 사진을 보면 cpu 부하가 stress 프로세스에 의해 증가한 것을 확인할 수 있다.


이외에도 메모리, 네트워크 ,I/O 제한 실습등을 해볼 수 있다.
리눅스 커널의 기능 중 하나로, 프로세스 간의 자원 격리를 제공하여 시스템의 특정 리소스가 서로 독립적으로 동작하도록 한다. 컨테이너 기술(예: Docker)에서 중요한 역할이기도 하다.
패키치 설치
# 패키지 목록 업데이트
sudo apt-get update
# util-linux 패키지 설치
sudo apt-get install -y util-linux
User Namespace 실습
# 새로운 사용자 네임스페이스 생성 및 bash 쉘 실행
sudo unshare --user /bin/bash
# 현재 사용자 및 그룹 ID 확인
id
# 루트 권한으로 파일 생성 시도 (실제로는 권한이 없음)
touch /root_test_file
ls -l /root_test_file
# 쉘 종료하여 네임스페이스 종료
exit
# 원래 네임스페이스에서 파일 삭제
sudo rm /root_test_file
User Namespace를 사용하여 새로운 네임스페이스를 생성하면, 네임스페이스 내에서 루트 권한을 가질 수 있다.

UTS Namespace 실습
# 현재 호스트 이름 확인
hostname
# 새로운 UTS 네임스페이스 생성 및 bash 쉘 실행
sudo unshare --uts /bin/bash
# 새로운 호스트 이름 설정
hostname <영어이름>
# 설정된 호스트 이름 확인
hostname
# 쉘 종료하여 네임스페이스 종료
exit
# 원래 네임스페이스에서 호스트 이름 확인
hostname
새로운 UTS 네임스페이스 내에서 호스트 이름을 변경하면, 해당 네임스페이스에서만 변경이 적용됨.
컨테이너 환경에서 각 컨테이너가 독립된 호스트 이름을 가질 수 있도록 함.

프로세스의 루트 디렉토리를 변경하여 격리된 파일 시스템 환경을 제공
동일한 호스트 내에서 프로세스 간 통신(Inter Process Communication, IPC)을 위한 메커니즘
서버와 클라이언트 통신 확인하기 위해 터미널을 분할한다.

vim server.py
vim client.py
vim 에디터로 접속이 되는데 영어 i를 누르고 편집 모드로 변경, 코드를 작성한다.

server.py
import socket
import os
# 유닉스 도메인 소켓 파일 경로
SOCKET_FILE = "/tmp/mysocket"
# 기존 소켓 파일이 존재하면 삭제
if os.path.exists(SOCKET_FILE):
os.remove(SOCKET_FILE)
# 서버 소켓 생성
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
server.bind(SOCKET_FILE)
server.listen(1)
print("서버가 클라이언트를 기다리고 있습니다...")
# 클라이언트 연결 수락
conn, addr = server.accept()
print("클라이언트 연결 수락")
# 데이터 수신 및 송신 루프
while True:
data = conn.recv(1024)
if not data:
break
print("클라이언트로부터 받은 데이터:", data.decode())
conn.sendall(data)
# 연결 종료
conn.close()
server.close()
client.py
import socket
# 유닉스 도메인 소켓 파일 경로
SOCKET_FILE = "/tmp/mysocket"
# 클라이언트 소켓 생성
client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
client.connect(SOCKET_FILE)
# 서버로 메시지 전송
message = "안녕하세요, 서버!"
client.sendall(message.encode())
# 서버로부터 데이터 수신
data = client.recv(1024)
print("서버로부터 받은 데이터:", data.decode())
# 연결 종료
client.close()
작성을 완료하면 esc를 누르고 :wq!를 누르면 저장이 된다.
실행하려면
python3 server.py
python3 client.py


리눅스와 관련된 여러 실습을 해보면서 docker의 기능들을 미리 학습하고 체험해 볼 수 있었다.
추후에 docker를 사용할 때 빠르게 적응을 할 수 있을 것이다.