가상호스트 환경에서 사용자의 사용량을 쉽게 관리하자

기존방식

저는 학원에서 교육용 서버를 직접 관리 하고 있습니다.
많은 학생들이 이용하다 보니 서버의 용량이 금방 초과 하는 경우가 많은데요. 이는 특정 사용자가 과하게 초과 사용인 경우가 많습니다.
용량 제한을 거는 방법도 있지만 영상을 다루는 과정이다 보니 용량제한을 걸지 않고 과도하게 많이 사용하는 사용자만 모니터링하고 있습니다. 지금까지 용량이 차게 되면 터미널로 용량을 체크하였습니다.

// 남은 용량 체크
# df -h
// 계정별 사용량을 용량순으로 체크
# du -ch /home --max-depth=1 |sort -h

요구사항

주말에 쉬거나 야간에 FTP 안된다고 연락이 오면 가장 먼저 서버용량 부터 확인하곤 하는데 간단한 작업도 컴퓨터 앞이 아니라면 곤란할 때가 많습니다.
이에 웹페이지로 서버사용량을 공개함으로써 교육생 스스로가 사용량 체크를 쉽게 하기 위함이 목적입니다.
요구사항은 다음과 같겠습니다.

  • 웹페이지로 구성하여 교육생이 쉽게 사용량을 체크 해 볼 수 있도록 유도
  • 서버의 전체 사용량과 개인 사용자 계정의 사용량 체크
  • 한 과정의 교육생 계정들만 분리하여 표현

웹페이지에서 사용량 체크

SSH에서 사용자 계정의 폴더 용량 체크는 du -sh '폴더명'을 사용합니다.
이걸 웹에서 보려면 터미널 명령어를 그대로 실행해 주는 shell_exec() 함수를 사용합니다.

<?php
   $folderPath = '/home/a1'; // 폴더 경로 설정

   // du 명령어 실행
   $command = "du -sh $folderPath";
   $output = shell_exec($command);

   // 결과 출력
   echo "$output";
?>

웹 계정 사용자별 사용량을 체크 하기 위해서는 용량 단위가 같아야 하기 때문에 모두 byte로 처리하면 다음처럼 할 수 있겠습니다.

// 홈 디렉토리 내의 모든 디렉토리 목록을 가져옴
$dirs = scandir(/home)

// 사용자 계정 폴더 수 만큼 반복
foreach ($dirs as $dir) {
    // 현재 디렉토리 (.) 또는 상위 디렉토리 (..)인 경우 건너뜀
    if ($dir === '.' || $dir === '..') {
        continue;
    }

    // 디렉토리인지 확인하고 사용자 접두사로 시작하는지 확인
    if (is_dir($homeDir . '/' . $dir) && strpos($dir, $usernamePrefix) === 0) {
        // du 명령어를 사용하여 디렉토리 크기를 가져옴
        $command = "du -s -b $homeDir/$dir";
        $output = shell_exec($command);
        $sizeParts = explode("\t", trim($output));
        $folderSizeBytes = (int)$sizeParts[0];
        $totalUsage += $folderSizeBytes; // 전체 사용 용량에 추가
        $userCount++; // 사용자 수 증가
        echo "$dir: " . formatBytes($folderSizeBytes) . "<br>"; // 사용자와 해당 사용자의 사용 용량 출력
    }
}

사용자 목록으로 사용량 체크

이제 클래스별 목록으로 변경하려고 합니다.
교육생들의 아이디는 앞두자가 공통으로 작명되어 있기 때문에 이를 활용해서 목록을 만들어냅니다.
앞서 설명한 반복문 안에서 다음과 같이 사용량을 얻어옵니다.

// 아이디 접두사 지정
$usernamePrefix = 'a4';

// 디렉토리인지 확인하고 사용자 접두사로 시작하는지 확인
    if (is_dir(/home . '/' . $dir) && strpos($dir, $usernamePrefix) === 0) {
        // du 명령어를 사용하여 디렉토리 크기를 가져옴
        $command = "du -s -b /home/$dir";
        $output = shell_exec($command);
        $sizeParts = explode("\t", trim($output));
        $folderSizeBytes = (int)$sizeParts[0];
        $totalUsage += $folderSizeBytes; // 전체 사용 용량에 추가
        $userCount++; // 사용자 수 증가
        echo "$dir: " . formatBytes($folderSizeBytes) . "<br>"; // 사용자와 해당 사용자의 사용 용량 출력
    }

최종안

여기에 전체 사용량과 단위를 보기 좋게 고치는 적용하면 다음과 같은 최종 파일이 되겠습니다.

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>서버 사용 현황</title>
</head>
<body>
<h1>서버 사용 현황</h1>
<?php
$homeDir = '/home';
$usernamePrefix = 'a4';

// 사용자 현황 제목 출력
echo "<h2>" . $usernamePrefix . "반 사용현황</h2>";

// 디스크 총 용량과 사용 중인 용량 계산
$diskTotal = disk_total_space($homeDir);
$diskUsed = $diskTotal - disk_free_space($homeDir);
$diskUsagePercentage = round(($diskUsed / $diskTotal) * 100, 2);

// 홈 디렉토리 내의 모든 디렉토리 목록을 가져옴
$dirs = scandir($homeDir);

$totalUsage = 0; // 전체 사용 용량 초기화
$userCount = 0; // 사용자 수 초기화

// 각 디렉토리에 대한 반복 처리
foreach ($dirs as $dir) {
    // 현재 디렉토리 (.) 또는 상위 디렉토리 (..)인 경우 건너뜀
    if ($dir === '.' || $dir === '..') {
        continue;
    }

    // 디렉토리인지 확인하고 사용자 접두사로 시작하는지 확인
    if (is_dir($homeDir . '/' . $dir) && strpos($dir, $usernamePrefix) === 0) {
        // du 명령어를 사용하여 디렉토리 크기를 가져옴
        $command = "du -s -b $homeDir/$dir";
        $output = shell_exec($command);
        $sizeParts = explode("\t", trim($output));
        $folderSizeBytes = (int)$sizeParts[0];
        $totalUsage += $folderSizeBytes; // 전체 사용 용량에 추가
        $userCount++; // 사용자 수 증가
        echo "$dir: " . formatBytes($folderSizeBytes) . "<br>"; // 사용자와 해당 사용자의 사용 용량 출력
    }
}

$averageUsage = $totalUsage / $userCount; // 사용자 평균 사용 용량 계산

// 전체 사용 용량과 사용자 평균 사용 용량 출력
echo "<br>Total Usage: " . formatBytes($totalUsage) . "<br>";
echo "Average Usage per User: " . formatBytes($averageUsage) . "<br>";

// /home 디스크 사용량 출력
echo "/home Disk Usage: $diskUsagePercentage%<br>";

// 바이트를 보기 좋은 형식으로 변환하는 함수
function formatBytes($bytes, $precision = 2) {
    $units = array('B', 'KB', 'MB', 'GB', 'TB');
    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) - 1);
    $bytes /= (1 << (10 * $pow));
    return round($bytes, $precision) . ' ' . $units[$pow];
}
?>

</body>
</html>

이상 없이 사용량이 나오면 디자인을 적절히 입혀 사용하면 될것 같습니다.

작업후기

처음에는 용량의 단위가 보기 좋게 가공된 것이라 합산이나 평균값을 구할수가 없어서 사용량을 byte단위로 얻어와 다시 결과 값에 단위를 달아주는 과정이 조금 골치 아팠습니다. 위 소스가 정상적으로 작동되지 않는 경우가 있다면 다음을 체크해 보는 게 좋을 것 같습니다.

  • 디렉터리 권한 설정: /home 디렉터리와 해당 사용자 디렉터리의 권한을 확인해야 합니다. 웹 서버 사용자가 해당 디렉터리에 대한 읽기 권한이 있는지 확인합니다. 사용자 디렉터리의 권한이 문제인 경우, 해당 디렉터리의 소유자나 관리자 권한을 가진 사용자로부터 적절한 읽기 권한을 설정합니다. 예를 들어, chmod 명령어를 사용하여 권한을 변경할 수 있습니다. 예를 들어, chmod -R 755 /home/사용자명은 해당 사용자의 디렉터리에 대한 읽기 권한을 부여합니다.
  • 그룹 설정: 해당 디렉터리에 웹 서버 사용자를 포함하는 그룹이 존재하는지 확인합니다. 그룹에 해당 사용자를 추가하여 디렉터리에 대한 읽기 권한을 부여할 수 있습니다. 예를 들어, chgrp 명령어를 사용하여 그룹을 변경할 수 있습니다. 예를 들어, chgrp -R 웹서버그룹 /home/사용자명은 해당 사용자의 디렉터리에 웹 서버 그룹을 설정합니다.
  • SELinux 또는 AppArmor 설정: SELinux 또는 AppArmor와 같은 보안 모듈이 설치되어 있는 경우, 해당 모듈이 웹 서버 사용자가 디렉터리에 접근할 수 있는지 확인해야 합니다. SELinux의 경우, chcon 명령어를 사용하여 웹 서버 사용자에게 해당 디렉터리에 대한 접근 권한을 부여할 수 있습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다