Cloud/GCP

GCP 전체 Cloud storage 사용량 조회

달빛궁전- 2025. 4. 22. 07:00
목표
Cloud Storage는 GCP에서 오브젝트 스토리지 용도로 다양하게 활용되고 있습니다.
특성상 Dev, Stg, Prd 등 여러 환경에 걸쳐 여러 프로젝트에 분산되어 생성되며, Cloud Run과 같은 PaaS 서비스를 사용할 경우 자동으로 버킷이 생성되기도 합니다.
이처럼 다양한 위치에 버킷이 존재하다 보니, 전체 현황을 한눈에 파악할 수 있는 방법이 필요합니다.

이 문서에서는 webconsole의 GUI를 통해 스토리지 리스트를 조회하는 방법과, 쉘 스크립트를 이용해 각 버킷의 용량 및 메타 정보를 수집하는 방법을 소개합니다.

 

🧰 방법 1: GUI로 전체 버킷 리스트 확인
GCP 콘솔 접속 → Cloud Asset Inventory 메뉴로 이동
 조직 선택 후→ storage.Bucket 으로 리소스 필터


필요 시 CSV로 내보내기

🧰 방법 2: 쉘 스크립트로 전체 버킷 및 사용량/라벨 정보 조회
GUI방법과 큰 차이점은 리스트 후 gsutil du 명령을 통해 사용량을 조회 하는 부분입니다.
⚠️ 유의
gsutil du 명령이 많은 시간과 권한을 요구할 수 있어
장시간 실행이 필요할 수 있습니다.
만약 사용량이 아닌 Stoage 리스트만 필요하다면 방법1을 추천합니다.
#!/bin/bash

# --- 설정 ---
read -p "대상 조직 ID를 입력하세요 (예: 1234567890): " ORGANIZATION_ID
if [[ -z "$ORGANIZATION_ID" ]]; then
  echo "오류: 조직 ID가 입력되지 않았습니다."
  exit 1
fi
echo "사용할 조직 ID: $ORGANIZATION_ID"

OUTPUT_CSV_FILE="gcs_bucket_list_with_size_${ORGANIZATION_ID}.csv"
SLEEP_DURATION=1
# --- 설정 끝 ---

# --- 1단계: 프로젝트 ID <-> 프로젝트 이름 매핑 생성 ---
echo "조직 '$ORGANIZATION_ID' 내 모든 활성 프로젝트 목록 및 이름 가져오는 중 (폴더 포함)..."
project_list_json=$(gcloud projects list --filter='lifecycleState=ACTIVE' --format='json' --quiet)

if [[ $? -ne 0 ]] || [[ -z "$project_list_json" ]]; then
    echo "오류: 조직 '$ORGANIZATION_ID'에서 활성 프로젝트 목록을 가져오는 데 실패했습니다. (종료 코드: $?)"
    exit 1
fi

declare -A project_names
while IFS= read -r project_json || [[ -n "$project_json" ]]; do
    if [[ -z "$project_json" ]]; then continue; fi
    p_id=$(echo "$project_json" | jq -r '.projectId // empty')
    p_name=$(echo "$project_json" | jq -r '.name // empty')
    if [[ -n "$p_id" ]] && [[ -n "$p_name" ]]; then
        project_names["$p_id"]="$p_name"
    fi
done < <(echo "$project_list_json" | jq -c '.[]')

project_count=${#project_names[@]}
echo "프로젝트 이름 매핑 준비 완료 (${project_count}개 프로젝트)."
# --- 1단계 끝 ---

# --- 2단계: 버킷 목록 조회 및 크기 조회 (gsutil 사용), 결과 조합 ---
echo "조직 '$ORGANIZATION_ID' 내 스토리지 버킷 정보 및 사용량 조회 시작..."
echo "*** 경고: 각 버킷의 사용량 조회(gsutil du)로 인해 매우 오랜 시간이 소요될 수 있습니다. ***"

echo '"BucketName","ProjectName","Location","BucketSize"' > "$OUTPUT_CSV_FILE"
echo "BucketName, ProjectName, Location, BucketSize"
echo "--------------------------------------------------"

gcloud asset search-all-resources \
    --scope="organizations/$ORGANIZATION_ID" \
    --asset-types='storage.googleapis.com/Bucket' \
    --page-size=500 \
    --format='json' | \
jq -c '.[]' | \
while IFS= read -r bucket_json || [[ -n "$bucket_json" ]]; do
    if [[ -z "$bucket_json" ]]; then continue; fi

    bucket_name=$(echo "$bucket_json" | jq -r '(.name | split("/") | last) // empty')
    project_id=$(echo "$bucket_json" | jq -r '(.parentFullResourceName | split("/") | last) // empty')
    location=$(echo "$bucket_json" | jq -r '.location // "N/A"')

    if [[ -z "$bucket_name" ]] || [[ -z "$project_id" ]]; then
        echo "경고: 잘못된 버킷 정보 (JSON: $bucket_json)" >&2
        continue
    fi

    project_name="${project_names[$project_id]}"
    if [[ -z "$project_name" ]]; then
        project_name="($project_id - 이름 조회 불가)"
    fi

    # !!!!! 버킷 크기 조회 (gsutil du 사용) !!!!!
    echo "  -> 버킷 '$bucket_name' 크기 조회 중 (gsutil du 사용)..."
    # '-s' : 합계, '-h' : 사람이 읽기 쉬운 단위
    # 오류 발생 시 stderr 로 메시지 출력될 수 있음 -> 2>/dev/null 로 숨김
    # gsutil 명령어 자체의 종료 코드 확인
    bucket_size_output=$(gsutil du -s -h "gs://$bucket_name" 2>/dev/null)
    gsutil_exit_code=$?

    bucket_size="N/A" # 기본값
    if [[ $gsutil_exit_code -eq 0 ]] && [[ -n "$bucket_size_output" ]]; then
        # 성공 시 출력에서 크기 부분만 추출 (첫 번째 필드)
        # 출력 예시: "1.23 GiB    gs://bucket-name" 또는 "0 B         gs://empty-bucket"
        # 공백(space/tab) 기준으로 첫번째 필드 추출2
        bucket_size=$(echo "$bucket_size_output" | awk '{print $1}')
        # 크기가 0일 때 awk가 빈 문자열을 반환할 수도 있으므로, 0 B 로 처리
        if [[ -z "$bucket_size" ]] && [[ "$bucket_size_output" == 0* ]]; then
             bucket_size="0 B"
        elif [[ -z "$bucket_size" ]]; then
             # 예상치 못한 출력 형식일 경우 대비
             echo "    경고: gsutil du 출력 형식 예상과 다름: $bucket_size_output" >&2
             bucket_size="Parse Error"
        fi
    else
        # gsutil du 실패 시
        echo "    경고: 버킷 '$bucket_name' 크기 조회 실패 (gsutil 종료 코드: $gsutil_exit_code). 권한 또는 버킷 상태 확인 필요." >&2
        # 종료 코드 1은 보통 버킷 없음 또는 권한 문제
        if [[ $gsutil_exit_code -eq 1 ]]; then
             bucket_size="Access Denied/Not Found"
        else
             bucket_size="Error ($gsutil_exit_code)"
        fi
    fi
    echo "    크기: $bucket_size"
    # !!!!! 버킷 크기 조회 끝 !!!!!

    # --- 결과 출력 ---
    echo "$bucket_name / $project_name / $location / $bucket_size"

    printf '"%s","%s","%s","%s"\n' \
        "$(echo "$bucket_name" | sed 's/"/""/g')" \
        "$(echo "$project_name" | sed 's/"/""/g')" \
        "$(echo "$location" | sed 's/"/""/g')" \
        "$(echo "$bucket_size" | sed 's/"/""/g')" >> "$OUTPUT_CSV_FILE"

    echo "  (${SLEEP_DURATION}초 대기...)"
    sleep "$SLEEP_DURATION"

done

pipe_status=("${PIPESTATUS[@]}")
gcloud_asset_exit_code=${pipe_status[0]}
jq_exit_code=${pipe_status[1]}

if [[ $gcloud_asset_exit_code -ne 0 ]]; then
    echo "경고: gcloud asset search-all-resources 명령 실행 중 오류 발생 (종료 코드: $gcloud_asset_exit_code)" >&2
fi
if [[ $jq_exit_code -ne 0 ]]; then
     echo "경고: jq 명령 실행 중 오류 발생 (종료 코드: $jq_exit_code)" >&2
fi


echo "--------------------------------------------------"
echo "버킷 정보 및 사용량 조회가 완료되었습니다."
echo "결과가 화면에 출력되었고, '$OUTPUT_CSV_FILE' 파일에 저장되었습니다."
# --- 2단계 끝 ---

exit 0
 
라벨 정보 추가 출력시 
#!/bin/bash

# --- 설정 ---
read -p "대상 조직 ID를 입력하세요 (예: 1234567890): " ORGANIZATION_ID
if [[ -z "$ORGANIZATION_ID" ]]; then
  echo "오류: 조직 ID가 입력되지 않았습니다."
  exit 1
fi
echo "사용할 조직 ID: $ORGANIZATION_ID"

OUTPUT_CSV_FILE="gcs_bucket_list_with_details_${ORGANIZATION_ID}.csv"
SLEEP_DURATION=1
# --- 설정 끝 ---

# --- 1단계: 프로젝트 ID <-> 프로젝트 이름 매핑 생성 ---
echo "조직 '$ORGANIZATION_ID' 내 모든 활성 프로젝트 목록 및 이름 가져오는 중 (폴더 포함)..."
project_list_json=$(gcloud projects list --filter='lifecycleState=ACTIVE' --format='json' --quiet)

if [[ $? -ne 0 ]] || [[ -z "$project_list_json" ]]; then
    echo "오류: 조직 '$ORGANIZATION_ID'에서 활성 프로젝트 목록을 가져오는 데 실패했습니다. (종료 코드: $?)"
    exit 1
fi

declare -A project_names
while IFS= read -r project_json || [[ -n "$project_json" ]]; do
    if [[ -z "$project_json" ]]; then continue; fi
    p_id=$(echo "$project_json" | jq -r '.projectId // empty')
    p_name=$(echo "$project_json" | jq -r '.name // empty')
    if [[ -n "$p_id" ]] && [[ -n "$p_name" ]]; then
        project_names["$p_id"]="$p_name"
    fi
done < <(echo "$project_list_json" | jq -c '.[]')

project_count=${#project_names[@]}
echo "프로젝트 이름 매핑 준비 완료 (${project_count}개 프로젝트)."
# --- 1단계 끝 ---

# --- 2단계: 버킷 목록 조회, 크기 조회, 라벨 추출, 결과 조합 ---
echo "조직 '$ORGANIZATION_ID' 내 스토리지 버킷 정보, 사용량, 라벨 조회 시작..."
echo "*** 경고: 각 버킷의 사용량 조회(gsutil du)로 인해 매우 오랜 시간이 소요될 수 있습니다. ***"

echo '"BucketName","ProjectName","Location","BucketSize","Labels"' > "$OUTPUT_CSV_FILE"
echo "BucketName, ProjectName, Location, BucketSize, Labels"
echo "---------------------------------------------------------"

gcloud asset search-all-resources \
    --scope="organizations/$ORGANIZATION_ID" \
    --asset-types='storage.googleapis.com/Bucket' \
    --page-size=500 \
    --format='json' | \
jq -c '.[]' | \
while IFS= read -r bucket_json || [[ -n "$bucket_json" ]]; do
    if [[ -z "$bucket_json" ]]; then continue; fi

    bucket_name=$(echo "$bucket_json" | jq -r '(.name | split("/") | last) // empty')
    project_id=$(echo "$bucket_json" | jq -r '(.parentFullResourceName | split("/") | last) // empty')
    location=$(echo "$bucket_json" | jq -r '.location // "N/A"')

    # !!!!! 라벨 정보 추출 (jq 명령어 수정) !!!!!
    labels=$(echo "$bucket_json" | jq -r '.labels | if type=="object" then to_entries | map("\(.key)=\(.value|tostring)") | join(";") else "" end')
    # !!!!! 라벨 정보 추출 끝 !!!!!

    if [[ -z "$bucket_name" ]] || [[ -z "$project_id" ]]; then
        echo "경고: 잘못된 버킷 정보 (JSON: $bucket_json)" >&2
        continue
    fi

    project_name="${project_names[$project_id]}"
    if [[ -z "$project_name" ]]; then
        project_name="($project_id - 이름 조회 불가)"
    fi

    # 버킷 크기 조회 (gsutil du 사용)
    echo "  -> 버킷 '$bucket_name' 크기 조회 중 (gsutil du 사용)..."
    bucket_size_output=$(gsutil du -s -h "gs://$bucket_name" 2>/dev/null)
    gsutil_exit_code=$?
    bucket_size="N/A"
    if [[ $gsutil_exit_code -eq 0 ]] && [[ -n "$bucket_size_output" ]]; then
        bucket_size=$(echo "$bucket_size_output" | awk '{print $1}')
        if [[ -z "$bucket_size" ]] && [[ "$bucket_size_output" == 0* ]]; then
             bucket_size="0 B"
        elif [[ -z "$bucket_size" ]]; then
             bucket_size="Parse Error"
        fi
    else
        echo "    경고: 버킷 '$bucket_name' 크기 조회 실패 (gsutil 종료 코드: $gsutil_exit_code)." >&2
        if [[ $gsutil_exit_code -eq 1 ]]; then bucket_size="Access Denied/Not Found"; else bucket_size="Error ($gsutil_exit_code)"; fi
    fi
    echo "    크기: $bucket_size"

    # --- 결과 출력 (라벨 포함) ---
    echo "$bucket_name / $project_name / $location / $bucket_size / $labels"

    printf '"%s","%s","%s","%s","%s"\n' \
        "$(echo "$bucket_name" | sed 's/"/""/g')" \
        "$(echo "$project_name" | sed 's/"/""/g')" \
        "$(echo "$location" | sed 's/"/""/g')" \
        "$(echo "$bucket_size" | sed 's/"/""/g')" \
        "$(echo "$labels" | sed 's/"/""/g')" >> "$OUTPUT_CSV_FILE"

    echo "  (${SLEEP_DURATION}초 대기...)"
    sleep "$SLEEP_DURATION"

done

pipe_status=("${PIPESTATUS[@]}")
gcloud_asset_exit_code=${pipe_status[0]}
jq_exit_code=${pipe_status[1]}

if [[ $gcloud_asset_exit_code -ne 0 ]]; then
    echo "경고: gcloud asset search-all-resources 명령 실행 중 오류 발생 (종료 코드: $gcloud_asset_exit_code)" >&2
fi
# jq 종료 코드는 파이프라인 마지막 요소이므로 pipe_status[1] 대신 $? 로도 확인 가능
if [[ $jq_exit_code -ne 0 ]] && [[ $jq_exit_code -ne 4 ]]; then # jq exit code 4 means no input, which is ok if no buckets found
     echo "경고: jq 명령 실행 중 오류 발생 (종료 코드: $jq_exit_code)" >&2
fi

echo "---------------------------------------------------------"
echo "버킷 정보, 사용량, 라벨 조회가 완료되었습니다."
echo "결과가 화면에 출력되었고, '$OUTPUT_CSV_FILE' 파일에 저장되었습니다."
# --- 2단계 끝 ---

exit 0
 
스크립트 실행 후 CSV 출력형식
나름 깔끔하게 나오는 결과물
📝 마무리
GCP 조직 내 전체 Cloud Storage 버킷을 한눈에 관리하고자 하는 담당자에게 도움이 되길 바랍니다.