[Linux] 리눅스 디스크 용량 확인

 

l  Linux

 

리눅스 시스템을 운영하다 보면 디스크 공간 사용률이 100% 되어 서비스에 장애가 발생하는 경우가 있다. 일반적으로 실수하는 부분이 로그 파일을 방치하여 어느 순간 디스크 공간을 모두 소진하였거나, 데이터베이스 서버의 경우 데이터를 백업할 순간적으로 디스크를 모두 소진하여 발생할 때가 있다. 주기적인 시스템 모니터링으로 디스크 공간에 대한 사용률을 확인하여 사전에 이러한 부분을 방지할 있도록 하는 것이 중요하다. 그렇다면 어느 디렉터리에서 많은 공간을 사용하는지를 확인하는 방법은 무엇일까? 이번 포스트에서는 리눅스에서 디스크 사용량을 확인하는 방법에 대해서 알아본다.

 

리눅스에서 디스크 공간을 확인하는 명령어는 df (Disk Free)이다. 마운트 되어있는 모든 디스크의 사용량을 보여준다. 1K-blocks 항목이 디스크에 할당된 용량이며, Used 실제 사용량, Available 사용 가능한 공간, Use% 디스크 공간에서 사용률을 퍼센트로 나타낸다.

df

 

 

디스크 용량 사용량이 킬로바이트로 표시되기 때문에 용량이 경우 자릿수로 인해 쉽게 사용자가 확인하기 어렵다. 이때 -h 옵션을 사용하면 사용자 친화적으로 확인할 있다.

df -h

 

 

 

디스크가 아닌 디렉터리별 사용량 확인은 du명령을 사용한다. du disk usage 약자로 하위 디렉토리를 포함한 디스크 사용량을 보여준다.

du -h /var/lib/

 

 

 

하위 디렉터리가 많을 경우, 어느 디렉토리에서 사용량이 많은지 한번에 확인하기 힘들다. 따라서 사용량 기준으로 정렬한 결과를 표시할 때에는 sort -n 옵션을 사용한다.

du -h /var/log | sort -n

 

 

 

그런데 나타난 결과를 보면 정렬 상태가 이상하다. 단위가 바뀌면서 88K 4.1G 보다 것처럼 정렬되었다. 따라서 정렬을 때에는 -h 옵션을 사용하지 않도록 한다.

du  /var/log | sort -n

 

 

 

 

 

 

2023-09-26 / Sungwook Kang / https://sungwookkang.com

 

 

리눅스, Linux, 디스크 사용량, 리눅스 디스크, 디스크 usage, disk usage

'Linux' 카테고리의 다른 글

[Linux] 쉘(shell) 스크립트 기초  (0) 2023.09.05
[Linux] Alpine Linux (알파인 리눅스) 는 무엇일까?  (0) 2023.09.04
[Linux] OOM(Out of Memory)란?  (0) 2023.08.30
CnetOS 방화벽 설정  (0) 2015.07.22
CentOS 파일 압축/풀기  (0) 2015.07.22

[Linux] (shell) 스크립트 기초

 

l  Linux

 

스크립트(shell script) 셸이나 명령줄 인터프리터(Interpreter)에서 실행되도록 작성되었거나 운영 체제를 위해 쓰인 스크립트이다. 스크립트가 수행하는 일반 기능으로는 파일 이용, 프로그램 실행, 문자열 출력 등이 있다. 스크립트에서는 .sh라는 파일 확장자를 가진 파일이 특정 종류의 스크립트를 가리키는 것이 보통이지만, 대부분의 스크립트는 파일 확장자를 지니지 않는다. 스크립트는 인터프리터 방식이므로 라인별로 읽어 실행함으로 속도가 다소 느리다는 단점이 있다.

스크립트라는 말은 유닉스 쉘을 위해 쓰인 스크립트를 말하는 반면, command.com(도스) cmd.exe (윈도우) 명령 스크립트는 보통 배치 파일이라고 불린다.  최근엔 마이크로소프트가 개발한 CLI쉘인 파워쉘이 있다.

 

이번 포스트에서는 가장 널리 쓰이는 bash 쉘을 사용하는 스크립트를 설명한다.

 

문장의 시작 (#!/bin/bash)

스크립트의 번째줄에는 항상 #!/bin/bash 기입되어 있어야 한다. 내용은 쉘이 실행될 어떤 쉘로 스크립트를 실행할지 정의하는 곳이다. 쉘에는 다양한 버전이 있다. 아래 예시는 hello.sh 라는 스크립트를 생성하고 실행하는 방법을 설명한다. 아래 스크립트를 hello.sh라는 파일을 생성하고 입력한다.

#!/bin/bash
 
echo "Hello, Shell Script"

 

아래 명령을 사용하여 스크립트를 실행하면 Hello, Shell Script 출력한다. 스크립트 명령어에 대한 부분은 아래에서 자세히 설명하도록 한다. 만약 실행이 되지 않는다면 실행 권한이 없어 발생한것으로 chmod 777 hello.sh 실행하여 권한 변경 실행한다.

$sh hello.sh

 

 

 

주석 처리 (#)

스크립트에서 단일 주석은 (#) 사용한다.

#!/bin/bash
 
#여기는 주석입니다.
#주석은 실행되지 않습니다.
 
echo "Hello, Shell Script"

 

블록 주석은 : <<”END” ~ ~ END 사용한다.

#!/bin/bash
 
: << “END” #주석 시작
여기는 주석입니다.
주석은 실행되지 않습니다.
END #주석
 
echo "Hello, Shell Script"
 

 

 

입력(read), 출력(echo)

echo 출력, read 입력을 있다. 위에서 이미 echo 사용하였으므로 read 사용하여 입력한 값을 출력하도록 스크립트를 작성해 본다. 입력 받은 값을 변수로 사용하려면 $기호를 사용한다.

#!/bin/bash
read input_value
echo "Hello, $input_value!"

 

스크립트를 실행하면 입력값이 발생할 때까지 실행되지 않고 대기한다. hahaha라고 입력하면 입력 받은 값이 변수로 사용되어 결과가 출력된다.

$sh hello.sh
hahaha

 

 

 

변수 특징

l  변수의 타입에는 로컬변수와 전역변수, 환경변수, 예약변수, 매개변수 다양하다.

l  변수는 , 소문자를 구별한다.

l  변수명에는 영문자, 숫자, 언더바( _ ) 사용된다.

l  변수의 이름은 숫자를 포함할 있지만, 숫자로 시작할 없다.

l  변수에는 모든 값을 문자열로 저장된다.

l  변수에는 자료형을 기입하지 않기 때문에 어떠한 값도 입력할 있다. (변수에 타입을 지정할 수도 있다.)

l  값을 사용할 때는 변수명 앞에 특수문자 "$" 사용한다. (Ex. echo ${data})

l  값을 대입(삽입) 때는 특수문자 "$" 사용하지 않는다. (Ex. data=mac)

l  변수를 생성할 때는 "=" 대입문자 앞뒤로 공백이 없어야 한다. (Ex. data="abcd") 문자열인 경우 “ “ 감싼다.

l  하나의 변수에 개의 값만 보존된다.

l  변수 값이 덮어 쓰기되는 것을 방지하기 위해서는 readonly 사용한다.

l  변수를 unset으로 삭제할 있다. (readonly 선언된 것은 삭제가 불가능하다.)

 

스크립트에서 시스템이 사용하는 예약어가 있다. 가지 대표적인 예약어이다.

변수 설명
HOME 사용자 디렉토리 의미
PATH 실행 파일의 경로
LANG 프로그램 실행 지원되는 언어
UID 사용자의 UID
SHELL 사용자가 로그인시 실행되는
USER 사용자 계정 이름
FUNCNAME 현재 실행되고 있는 함수 이름
TERM 로그인 터미널
Set 변수를 출력하는 명령어
Env 환경 변수를 출력하는 명령어
Export 특정 변수의 범위를 환경 변수의 데이터 공간으로 전송하여 자식 프로세스에서도 특정 변수를 사용 가능하게 한다.
unset 선언된 변수를 제거

 

 

전역변수, 지역변수

쉘에서 선언된 변수는 기본적으로 전역변수(global variable)이며, 함수안에서 지역변수(local variable) 사용할 있는데, 이때에는 local 붙여서 사용한다. 함수안에서 local 사용하지 않으면 전역 변수의 값을 덮어쓰게 된다.

#!/bin/bash
 
# 전역 변수 지정
string="hello shell, global variable"
 
function string_test() {
    # local 붙여야 지역변수로 인식. 만약 local 빼면 전역변수에 덮어쓰기로 적용
    local string="hello shell, local variable"
    echo ${string}
}
 
# 함수 호출
string_test # > hello shell, local variable
echo ${string} # > hello shell, global variabl
 
# 변수 초기화
unset string

 

 

 

변수 타입 지정

기본적으로 Bash 문자열만 저장하지만 데이터 타입을 지정할 수도 있다.

변수타입 설명
declare -r 읽기 전용 타입
declare -i 정수형 타입
declare -a 배열 타입
declare -A 연관배열(MAP) 타입
declare -f 함수 타입
declare -x 환경변수(export) 지정으로 외부 환경에서도 변수를 사용할 있다.

 

 

읽기전용 변수 (readonly)

변수에 값을 덮어 쓸수 있지만 readonly 지정한 경우 변수를 덮어쓸수 없다. 아래 예시는 readonly에서 변수 덮어쓰기를 시도할 발생한 오류를 확인할 있다.

#!/bin/bash
 
var="변수1"
VaR_2="변수2"
echo "Var_2=$VaR_2"
 
VaR_2="VaR_2 변경합니다."
echo ${VaR_2}
 
readonly var
var="readonly var 변수를 변경해 봅니다."

 

 

 

변수 값의 치환

변수의 값을 치환할 사용하는 문법을 표로 정리하였다.

문법 설명
${var} 변수 값을 바꿔 넣는다.
${var:-word} 변수가 아직 세팅되지 않거나 공백 문자열의 경우 word 반환한다. var에는 저장되지 않는다.
${var:=word} 변수가 아직 세팅되지 않거나 공백 문자열의 word 반환한다. var 저장된다.
${var:?word} 변수가 아직 세팅되지 않거나 공백 문자열의 경우 치환에 실패하고, 스탠다드 에러에 에러가 표시된다.
${var:+word} 변수가 세팅되지 않은 경우 word 반환된다. var에는 저장되지 않는다.

 

#!/bin/sh
 
echo "1 - ${var:-wordSetInEcho1}"
echo "2 - var = ${var}"
echo "3 - ${var:=wordSetInEcho3}"
echo "4 - var = ${var}"
unset var
echo "5 - ${var:+wordSetInEcho5}"
echo "6 - var = $var"
var="newVarValue"
echo "7 - ${var:+wordSetInEcho7}"
echo "8 - var = $var"
echo "9 - ${var:?StandardErrorMessage}"
echo "10 - var = ${var}"

 

 

문자열 패턴 비교는 아래 조건을 사용할 있다.

문법 설명
${var%pattern} 끝에서 부터 word 패턴이 일치하는 var 최소 부분(첫번째 일치) 제거하고 나머지를 반환
${var%%pattern} 끝에서 부터 word 패턴이 일치하는 var 최대 부분(마지막 일치) 제거하고 나머지를 반환
${var#pattern} 처음 부터 word 패턴이 일치하는 var 최소 부분( 번째 일치) 제거하고 나머지 부분을 반환
${var##pattern} 처음 부터 word 패턴이 일치하는 var 최대 부분(마지막 일치) 제거하고 나머지 부분을 반환

 

 

환경 변수 (export)

스크립트에서 변수명 앞에 export 붙여 환경변수(environment variable) 사용할 있다. 다만 환경변수 사용시 시스템에 미리 정의된 예약변수와 겹치지 않게 주의한다. 실습을 위해 개의 파일을 준비한다.

shell1.sh
#!/bin/bash
 
echo ${export_variable}

 

shell2.sh
#!/bin/bash
 
#환경변수 선언
export export_variable="export test, hello shell"
 
#변수값을 받아서 사용할 스크립트 호출
/파일 경로/shell1.sh

 

shell2.sh 실행한다. Export 변수의 값은 shell1.sh 호출할 사용된다.

 

 

매개변수

프로그램에서 실행할 인자를 사용하듯 스크립트에서도 매개변수를 사용할 있다. 규칙이 있는데, 실행한 스크립트 이름은 ${0}, 이후 인자 값들은 ${1}. ${2}…으로 사용한다.

변수 기능
$0 스크립트명
$1 ~ $9 인수 1 번째부터 인수 9번째까지 사용
$# 스크립트에 전달될 인수의
$* 모든 인수를 모아 하나로 처리
$@ 모든 인수를 각각 처리
$? 직전에 실행한 커멘드의 종료 (0 성공, 1 실패)
$$ 스크립트의 프로세스ID
$! 마지막으로 실행한 백그라운드 프로세스 ID

 

아래 스크립트는 매개변수를 입력 받아 어떻게 사용되는지 알아보는 예시이다.

#!/bin/sh
 
echo "\$0script name: $0"
echo "\$11st param: $1"
echo "\$22nd param: $2"
echo "\$#number of param: $#"
echo "\"\$*\": \"$*\""
echo "\"\$@\": \"$@\""
VAR="exit code is  0 "
echo $?

 

실행 결과는 아래와 같이 나타난다.

 

 

배열 (Array)

스크립트에서 배열은 1차원 배열만 지원하며 중괄호를 사용해야 한다. 배열 원소는 소괄호안에 공백으로 구분하며, 배열 원소는 문자열이든 숫자형이던 상관없이 있다.

#!/bin/bash
 
arr=("hello" "shell" 1 2 3 4 5)
 
echo "배열 전체 : ${arr[@]}"
echo "배열 원소의 갯수 : ${#arr[@]}"
echo "배열 첫번째 : ${arr}, 혹은 ${arr[0]}"
echo "4 index 갖는 배열의 원소 : ${arr[4]}"
 
arr[5]="four"
 
echo "4번째 index 갖는 배열의 원소 : ${arr[4]}"
 
# 4번째 해제
unset arr[4]
echo "4 배열 삭제 완료"
echo "4 index 갖는 배열의 원소 : ${arr[4]}"
echo "5 index 갖는 배열의 원소 : ${arr[5]}"

 

 

 

함수(function)

스크립트에서도 함수를 사용할 있다. 함수의 정의 형식은 아래와 같다. 주의할 점은 함수가 호출되기 전에 함수가 정의되어 있어야 하며 호출할 때는 괄호를 사용하지 않고 호출한다.

#!/bin/bash
 
function func(){
        echo "func()"
}
 
#함수 호출
func

 

 

비교문(if..fi)

쉘에서는 비교문이 약간 특이하다. bash if문의 특이한 점은 fi 대괄호([ ]) 이다. 다른 언어와 달리 중괄호를 사용하지 않기 때문에 fi if문의 끝을 알려주어야 한다. 주의해야 점은 if 뒤에 나오는 대괄호 [ ] 조건식 사이에는 반드시 공백이 존재해야 한다.

 

비교문에는 다양한 연산자를 사용할 있다.

연산자 설명
1 -eq 2 # 값이 같음(equal)
1 -ne 2 # 값이 같지 않음(not equal)
1 -lt 2 # 1 2보다 작음(less than)
1 -le 2 # 1 2보다 작거나 같음(less or equal)
1 -gt 2 # 1 2보다 (greater than)
1 -ge 2 # 1 2보다 크거나 같음(greater or equal)

 

문자열 비교

연산자 설명
문자1 = 문자2 # 문자1 문자2 일치 (sql같이 = 하나만 써도 일치로 인식)
문자1 == 문자2 # 문자1 문자2 일치
문자1 != 문자2 # 문자1 문자2 일치하지 않음
-z 문자 # 문자가 null 이면
-n 문자 # 문자가 null 아니면
문자 == 패턴 # 문자열이 패턴과 일치
문자 != 패턴 # 문자열이 패턴과 일치하지 않음

 

논리 연산자

연산자 설명
조건1 -a 조건2 # AND
조건1 -o 조건2 # OR
조건1 && 조건2 # 양쪽 성립
조건1 || 조건2 # 한쪽 또는 양쪽다 성립
!조건 # 조건이 성립하지 않음
true # 조건이 언제나 성립
false # 조건이 언제나 성립하지 않음

 

산술연산자 (쉘에서는 expr 숫자 연산자 숫자형식으로 사용한다.)

연산자 의미 예시
+ 덧셈 echo `expr 10 + 20` => 30
- 뺄셈 echo `expr 20 - 10` => 10
\* 제곱 echo `expr 11 \* 11` => 121
/ 나눗셈 echo `expr 10 / 2` => 5
% 나머지 echo `expr 10 % 4` => 2
= 저장 a=$b b 값은 a 저장
== 동일 [ "$a" == "$b" ] $a $b 동일하는 경우 TRUE 반환
!= 다름 [ "$a" != "$b" ] $a $b 동일하지 않는 경우 TRUE 반환

 

 

예제로 살펴본다.

#!/bin/bash
 
function func(){
        a=10
        b=5
 
        if [ ${a} -eq ${b} ]; then
                echo "a b 같다."
        fi
 
        if [ ${a} -ne ${b} ]; then
                echo "a b 같지 않다."
        fi
 
        if [ ${a} -gt ${b} ]; then
                echo "a b보다 크다."
        fi
 
        if [ ${a} -ge ${b} ]; then
                echo "a b보다 크거나 같다."
        fi
 
        if [ ${a} -lt ${b} ]; then
                echo "a b보다 작다."
        fi
 
        if [ ${a} -le ${b} ]; then
                echo "a b보다 작거나 같다."
        fi
 
}
 
#함수 호출
func

 

 

 

여러 조건을 사용할때, 다른 언어에서는 else if역할을 하는 것을 스크립트에서는 elif라는 것을 사용하여 else if 동일한 역할을 있다. elif[ 조건 ]; then 형식으로 사용한다. 만약 반복문에서 사용하여 조건이 참일때 반복문을 멈추고 싶을때 break라는 키워드를 사용하여 반복문을 멈출 있다.

#!/bin/bash
 
case ${1} in
        "linux") echo "리눅스" ;;
        "unix") echo "유닉스" ;;
        "windows") echo "윈도우즈" ;;
        "MacOS") echo "OS" ;;
        *) echo "해당없음" ;;
esac

 

 

파일 관련 조건문

스크립트는 명령어를 다루는 스크립트이기 때문에 파일이 존재하는지, 디렉토리가 존재하는지 파일과 관련된 조건 여부도 조건문을 통해 있다. 아래 표는 조건을 정리한 것이다. , 거짓을 판단할 , 느낌표(!) 사용하면 반대로 결과를 출력한다.

조건 설명
if [ -d ${변수} ]; then ${변수} 디렉토리가 존재하면 true.
if [ ! -d ${변수} ]; then ${변수} 디렉토리가 존재하지 않으면 true.
if [ -e ${변수} ]; then ${변수}라는 파일이 존재하면 true.
if [ ! -e ${변수} ]; then ${변수}라는 파일이 존재하지 않으면 true.
if [ -L ${변수} ]; then 파일이 symbolic link이면 true.
if [ -s ${변수} ]; then 파일의 크기가 0보다 크면 true.
if [ -S ${변수} ]; then 파일 타입이 소켓이면 true.
if [ -r ${변수} ]; then 파일을 읽을 있으면 true.
if [ -w ${변수} ]; then 파일을 있으면 true.
if [ -x ${변수} ]; then 파일을 실행할 있으면 true.
if [ -f ${변수} ]; then 파일이 정규 파일이면 true.
if [ -c ${변수} ]; then 파일이 문자 장치이면 true.
if [ ${변수1} -nt ${변수2}]; then 변수1 파일이 변수2 파일보다 최신 파일이면 true.
if [ ${변수1} -ot ${변수2}]; then 변수1 파일이 변수2 파일보다 최신이 아니면 true.
if [ ${변수1} -ef ${변수2}]; then 변수1 파일과 변수2 파일이 동일하면 true.

 

 

CASE

일반적인 CASE 사용법과 비슷하지만 CASE 끝에 세미콜론을 2개씩 사용하는 특징이 있다. 그리고 CASE 끝은 ESAC 닫아준다.

#!/bin/bash
 
DRINK="coffee"
case "$DRINK" in
    "beer") echo "맥주입니다"
    ;;
    "juice") echo "주스입니다"
    ;;
    "coffee") echo "개발자에겐 카페인 필수!"
    ;;
esac

 

 

CASE에서 OR 연산도 가능하다.

COUNTRY=korea
 
case $COUNTRY in
  "korea"|"japan"|"china") # or 연산도 가능하다
    echo "$COUNTRY is Asia"
    ;;
  "USA"|"Canada"|"Mexico")
    echo "$COUNTRY is Ameria"
    ;;
  * )
    echo "I don't know where is $COUNTRY"
    ;;
esac

 

 

반복문(for)

반복문을 빠져나갈때에는 break 사용하고, 현재 반복분이나 조건을 건너뛸때에는 continue 사용한다.

#!/bin/bash
 
# 초기값; 조건값; 증가값을 사용한 정통적인 for
for ((i=1; i<=4; i++)); do
    echo $i
done

 

 

 

반복문(for in)

#!/bin/bash
 
function func(){
        echo "사용예1"
        for i in 1 2 3 4 5
        do
                echo "${i}"
        done
 
        echo "사용예2"
        list="1 2 3 4 5"
        for i in ${list}
        do
                echo "${i}"
        done
 
        echo "사용예3"
        for i in {1..5}
        do
                echo "${i}"
        done
 
        echo "사용예4: 크기를 2만큼 증가시키면서 출력"
        for i in {1..5..2}
        do
                echo "${i}"
        done
 
        echo "사용예5: 배열을 이용"
        arr=(1 2 3 4 5)
        for i in "${arr[@]}"
        do
                echo "${i}"
        done
 
 
        echo "사용예6: C 유사한 형식의 for"
        for ((i=0; i<5; i++)); do
                echo "${i}"
        done
}
 
#함수 호출
func

 

 

 

반복문 (while)

수행 조건이 true일때 실행되는 반복문이다.

count=0
while [ ${count} -le 5 ];
do
    echo ${count}
    count=$(( ${count}+1 ))
done

 

 

이중 괄호를 사용하면 논리 기호로도 사용 가능하다.

count=0
while (( ${count} <= 5 ));  # 이중괄호 사용하면 논리기호 사용 가능
do
    echo ${count}
    count=$(( ${count}+1 ))
done

 

 

반복문(until)

수행 조건이 false 일때 실행되는 반복문이다. 조건이 While 반대라고 생각하면 된다.

count2=10
 
until [ ${count2} -le 5 ]; do
    echo ${count2}
    count2=$(( ${count2}-1 ))
done

 

 

 

종료 상태 코드

명령어가 실패할 경우 리턴되는 결과에 따라 다른 동작을 하려면 명령어의 종료 코드를 반환 받아 사용하면 된다. 명령어의 종료 코드는 $? 사용하여 가장 최근 실행한 명령어의 종료 코드를 받을 있다. 정상적인 종료는 0 반환되며 0 아닌 값은 오류라고 판단할 있다. 아래 표는 종료 코드에 따른 설명을 정리한 것이다.

종료 코드 설명
0 성공 (Success)
1 일반적 오류 (Catchall for general errors)
2 내장 명령의 틀린 사용 (Misuse of shell builtins)
126 파일이 실행 가능하지 않음 (Command invoked cannot execute)
127 명령어를 찾을 없음 (Command not found)
128 종료할 잘못된 인수 적용 (Invalid argument to exit)
128+n 치명적인 시그널 n 에러 (Fatal error signal “n”)
130 [Ctrl + C] 조합에 의한 종료 (Script terminated by Control-C)

 

 

이스케이프 문자

명령어 설명
\f 문자열만큼 열을 밀어서 이동한다.
\n 새로운 줄로 바꾼다.
\r 문자열의 앞부분 부터 뒷문자열 만큼 대체하고 반환한다.
\t 만큼 띄운다.

 

 

외에도 다양한 명령이 있다. 명령을 활용하면 리눅스 환경에서 시스템 관련 다양한 정보들을 스크립트로 얻을 있다.

 

 

 

[참고자료]

l   https://ko.wikipedia.org/wiki/%EC%85%B8_%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8

l   https://reakwon.tistory.com/136

l   https://inpa.tistory.com/entry/LINUX-%EC%89%98-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%ED%95%B5%EC%8B%AC-%EB%AC%B8%EB%B2%95-%EC%B4%9D%EC%A0%95%EB%A6%AC

l   https://engineer-mole.tistory.com/200

 

 

 

2023-09-05 / Sungwook Kang / https://sungwookkang.com

 

 

리눅스, Linux, 쉘스크립트, 쉘사용법, 쉘명령어, shell command, shell script

'Linux' 카테고리의 다른 글

[Linux] 리눅스 디스크 용량 확인  (0) 2023.09.26
[Linux] Alpine Linux (알파인 리눅스) 는 무엇일까?  (0) 2023.09.04
[Linux] OOM(Out of Memory)란?  (0) 2023.08.30
CnetOS 방화벽 설정  (0) 2015.07.22
CentOS 파일 압축/풀기  (0) 2015.07.22

[Linux] Alpine Linux (알파인 리눅스) 무엇일까?

 

l  Linux

 

컨테이너 환경으로 다양한 서비스를 빌드하다보니, DevOps 팀에서 베이스 이미지를 ubuntu centos 대신 alpine(알파인) 리눅스를 사용하는 것이 어떻겠냐는 제안을 받았다. 리눅스는 다양한 커널 기반으로 배포판을 가지고 있다. 이번 포스트에서는 Alpine Linux (이하 알파인 리눅스”) 대해서 알아본다.

 

[개요]

알파인 리눅스는 리눅스 커널 기반으로 리눅스 배포판 하나이며 MIT 라이선스 아래에 배포되었으며 LEAF 리눅스의 포크 버전이다. 알파인 리눅스는 다른 배포판과 다르게 Musl BusyBox 기반으로 한다. 알파인 리눅스의 컨셉은 LEAF 리눅스와 동일하게 작고”, “보안이 뛰어나고”, “간단함 기반으로 한다. 하지만 시간이 지나면서 다양한 사람들에 의해 알파인 리눅스만의 형태로 발전되고 있다.

 

[특징]

장점

l  가볍고, 간단하며 보안성을 목적으로 개발한 배포판

l  용량을 줄이기 위해 시스템의 기본 C runtime glibc 대신 musl libc 사용

l  다양한 명령어는 GNU util대신 busybox 탑재

l  초경량( 80MB) 배포판으로 임베디드나 네트워크 서버 특정 용도에 적합.

l  특히 도커(Docker) 공식 이미지로 채택되어 5MB 크기의 리눅스 이미지로 유명함

l  보안에 염두해두고 설계되어 모든 바이너리는 독립적인 실행 파일(PIE) 컴파일

 

단점

l   리눅스 표준인 GNU 도구가 없어가나 Busybox 대신 들어가 있어, 명령어를 실행할 주의가 필요

l   라이트한 대신 패키지가 설치되어 있지 않아 직접 설치해주어야 하는 것들이 많다.

l   이것저것 설치하다보면 표준 리눅스 배포판과 거의 비슷한 용량이 되기도 한다. (개인적인 생각)

 

 

BusyBox?
BusyBox 일종의 명령어 모음집으로 박스안에 필요한 응용 프로그램들을 담아 놓은 것이다. 리눅스에서 사용되는 명령어들만 모아 놓아도 상당한 크기를 차지할 있는데, BusyBox에서는 각각에 함수들을 최소 사이즈로 다시 구현하였다. 그렇기 때문에 Embbeded(임베디드), 네트웍 서버 특정 용도에 적합하며 도커 컨테이너의 OS 많이 사용한다.

 

 

[자주 사용되는 명령어]

알파인 리눅스에서는 패키지 인스톨러가, 전통적인 yum, apt 대신에 apk 사용한다. 그리고 기본 쉘이 배시가 아니라 애쉬(ash)이다.

 

명령 설명
apk update 패키지 저장소 목록을 업데이트
apk search <package> 패키지 저장소 목록에서 패키지를 검색. v 옵션으로 설명 확인 가능.
apk add <package[=version]> 패키지를 설치. 버전을 명시하여 설치 가능.
apk del <package> 특정 패키지를 제거
apk cache clean 패키지 캐시를 모두 제거
apk cache -v sync 패키지 캐시를 초기화하고 부족한 패키지를 자동으로 다운로드
apk stats 현재 패키지 저장소에서 사용가능한 패키지나 설치된 패키지 등의 정보를 출력
apk fix 복구가 필요한 패키지를 복구하거나 종속성을 제외하고 업그레이드 진행.
apk info 현재 설치된 모든 패키지 정보 나열. -L 옵션을 사용하면 패키지내 파일 정보 출력.

 

 

[ 컨테이너에서 알파인 리눅스를 사용할까?]

지극히 개인적인 생각이다. 컨테이너 이미지 파일을 만들 , 베이스 이미지 위에 필요한 다양한 패키지를 설치하게 된다. 당연히 베이스 이미지 + 기타 필요한 패키지 크기만큼 이미지 사이즈가 되므로 빌드 용량도 커지게 된다. 그리고 이를 보관 배포하기 위해 스토리지 비용 네트워크 비용이 증가할 있다. 사실 스토리지 비용은 컴퓨팅 비용중에 가장 저렴한 부분 하나이다. 그래서 요즘은 용량 고민은 많이 하지 않는 편이다. 특히 온프레미스 환경에서 직접적으로 모든 것을 운용할 때에는 더더욱 그렇다. 하지만 클라우드 환경에선, 모든것이 비용으로 청구되기 때문에 최소한의 사이즈로 운영하면 비용 최적화에 많은 도움이 있을 것이라 생각한다.

 

 

 

[참고자료]

l   Alpine Linux:Overview : https://wiki.alpinelinux.org/wiki/Alpine_Linux:Overview

l   Alpine Linux  : https://namu.wiki/w/Alpine%20Linux

 

 

 

2023-09-04 / Sungwook Kang / https://sungwookkang.com

 

 

리눅스, Linux, 알파인 리눅스, Apline Linux, APK 명령어, 리눅스 배포판

'Linux' 카테고리의 다른 글

[Linux] 리눅스 디스크 용량 확인  (0) 2023.09.26
[Linux] 쉘(shell) 스크립트 기초  (0) 2023.09.05
[Linux] OOM(Out of Memory)란?  (0) 2023.08.30
CnetOS 방화벽 설정  (0) 2015.07.22
CentOS 파일 압축/풀기  (0) 2015.07.22

[Linux] OOM(Out of Memory)?

 

l  Linux

 

몇일전부터 개발 환경에서 겪던 문제로 멀쩡하던 MySQL 서비스가 갑자기 연결이 되지 않는다. 처음엔 단순히 현상인줄 알고, MySQL 서비스를 재시작 하였다. 그런데 동일한 상황이 하루에도 여러 발생하고 있어서 원인을 살펴보기로 했다. 원인을 살펴보니, 아래와 같은 로그가 있었다.

Aug 30 01:35:08 xxxxx kernel: [7189052.423131] [18540]   111 18540  1930392  1535479 12935168        0             0 mysqld
Aug 30 01:35:08 xxxxx kernel: [7189052.423132] Out of memory: Kill process 18540 (mysqld) score 512 or sacrifice child
Aug 30 01:35:08 xxxxx kernel: [7189052.424065] Killed process 18540 (mysqld) total-vm:7721568kB, anon-rss:6141916kB, file-rss:0kB, shmem-rss:0kB
Aug 30 01:35:08 xxxxx kernel: [7189052.749286] oom_reaper: reaped process 18540 (mysqld), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB

 

OOM으로 인한 OOM Killer(강제 서비스 종료)였다. OOM 무엇이고 발생하는 것일까? 그리고 로그는 어떻게 확인할 있을까?

 

OOM (Out of Memory)

Linux swap 메모리와 물리 메모리를 모두 사용 , 프로세스에서는 필요에 의해 추가적인 물리 메모리 할당을 요청하였는데, 이상 할당할 물리 메모리 공간이 없어 할당이 불가능한 상태를 의미한다. 메모리 Over Commit 상태일 발생하는 현상으로 물리적으로 메모리가 부족하다는 뜻이다. 이러한 문제는 물리 메모리만 증설하면 사실 간단히 해결된다. 하지만 이러한 현상이 발생하는지 원인을 찾지 못한 상태에서 무한정 메모리를 증설할 수도 없다.

 

OOM Killer

서버 메모리 부족으로 OOM 발생하였을 , 리눅스에서는 메모리를 확보하기 위해 OOM Score 기준으로 점수가 높은 프로세스를 강제로 Kill 하여 메모리를 확보하는 Kernel 기능이다. 이렇게 OOM Killer 프로세스가 종료되면 내부 시스템 로그에 기록되어 추후 확인할 있다.

 

OOM Killer Log 확인

OOM Killer 프로세스가 종료되었을 때에는 각종 시스템 로그에서 확인할 있다. 시스템 로그에는 OOM Killer외에도 다양한 로그가 있기 때문에 로그 양이 많을 경우 필터를 해서 검색을 해야 수도 있다. 일반적으로 특별히 로그 경로를 수정하지 않았다면 아래 경로에서 다양한 시스템 로그를 확인할 있다.

 /var/log/

 

Kern.log에서는 아래와 같은 OOM 로그를 확인할 있었다.

cat kern.log

 

Aug 30 01:35:08 XXXXX kernel: [7189052.423131] [18540]   111 18540  1930392  1535479 12935168        0             0 mysqld
Aug 30 01:35:08 XXXXX kernel: [7189052.423132] Out of memory: Kill process 18540 (mysqld) score 512 or sacrifice child
Aug 30 01:35:08 XXXXX kernel: [7189052.424065] Killed process 18540 (mysqld) total-vm:7721568kB, anon-rss:6141916kB, file-rss:0kB, shmem-rss:0kB
Aug 30 01:35:08 xxxxx kernel: [7189052.749286] oom_reaper: reaped process 18540 (mysqld), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB

 

syslog에서는 다양한 로그가 많이 기록되어 OOM이라는 필터를 사용하여 확인하였다.

cat syslog | grep oom

 

Aug 29 23:45:33 xxxxx kernel: [7182478.018455]  oom_kill_process+0x21f/0x420
Aug 29 23:45:33 xxxxx kernel: [7182478.018529] [ pid ]   uid  tgid total_vm      rss pgtables_bytes swapents oom_score_adj name
Aug 29 23:45:34 xxxxx kernel: [7182478.495925] oom_reaper: reaped process 22648 (mysqld), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB
Aug 30 01:35:08 xxxxx kernel: [7189052.422998] icinga2 invoked oom-killer: gfp_mask=0x14200ca(GFP_HIGHUSER_MOVABLE), nodemask=(null), order=0, oom_score_adj=0
Aug 30 01:35:08 xxxxx kernel: [7189052.423021]  oom_kill_process+0x21f/0x420
Aug 30 01:35:08 xxxxx kernel: [7189052.423096] [ pid ]   uid  tgid total_vm      rss pgtables_bytes swapents oom_score_adj name
Aug 30 01:35:08 xxxxx kernel: [7189052.749286] oom_reaper: reaped process 18540 (mysqld), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB

 

message 로그 파일에서도 동일한 오류 내역을 확인할 있다. Message 로그 파일은 다양한 로그 파일의 미러 역할을 하기 때문에 정말 다양한 로그가 기록되어 있다.

 

 

OOM killer 우선순위

로그를 살펴보면 OOM 의해 mysqld kill 되었음을 확인할 있다. 그렇다면 프로세스를 종료시키는 우선순위는 어떻게 정해질까? 가지 방법이 있다.

1.          oom_badness() 메소드에서 프로세스별 점수를 계산하여 종료시킬 프로세스를 선택한다.

2.          사용자가 특별히 지정하여 순위를 변동시킬 있다.

 

oom_badness() 사용하는 우선순위 선정 방법은 아래와 같다.

1.          특정 프로세스를 함으로써 최소한의 프로세스만 잃을 있어야 한다.

2.          많은 메모리를 회수할 있는 프로세스 (메모리 사용량이 작으면 되지 않는다.)

3.          프로세스중 Leak 발생하지 않는 프로세스 (릭이 발생하면 프로세스 Kill 의미가 없다)

4.          사용자가 특별히 지정한 프로세스

 

외에도 nice score 기반으로 우선순위를 선정할 있다.

 

 

OOM Killer score 확인

OOM score 확인 방법은 /proc/${pid}/oom_score 파일을 통해 조회할 있다. PID 확인하는 방법은 ps 명령을 사용한다.

l  ps : shell에서 실행중인 프로세스만 출력

l  ps -e : 실행 중인 모든 프로세스 출력

l  ps -f : 실행중인 모든 프로세스의 상태 정보 출력

l  ps -ef | grep mysql : grep 사용하여 특정 프로세스(mysql) PID 확인 한다.

 

ps -e | grep mywql

 

 

cat /proc/15368/oom_score

 

 

 

OOM Killer 순위 설정 방법

1.          특정 프로세스의 PID 조회

2.          /proc/PID/oom_adj 파일에 -17 입력. oom_adj -17 ~ 15 값을 가지며, 낮은 일수록 후순위.

3.          /proc_PID/oom_scroe_adj 파일에 -1000 입력. oom_score_adj -1000 ~ 1000 값을 가지며 낮은 값일수록 후순위.

 

아래 예시는 oom_adj 파일에 -17 변경하는 것으로 PID 변경하여 사용할 있다.

sudo echo -17 > /proc/${pid}/oom_ajd

 

아래 예시는 oom_score_adj파일에 -1000 변경하는 것으로 PID 변경하여 사용할 있다.

sudo echo -1000 > /proc/${pid}/oom_score_adj

 

 

메모리 누수로 인한 System hang 현상을 방지하기 위해 리눅서 커널에서는 OOM killer 자체는 비활성화 없기 때문에 순위 설정을 참고하여 중요한 프로세스는 Kill 되지 않도록 한다.

 

 

 

 

2023-08-30 / Sungwook Kang / https://sungwookkang.com

 

 

리눅스, Linux, OOM, OutOfMemory, 메모리부족현상, 강제킬, 프로세스확인, 메모리압박, 아웃오브메모리, OOMKiller, oom_score

'Linux' 카테고리의 다른 글

[Linux] 쉘(shell) 스크립트 기초  (0) 2023.09.05
[Linux] Alpine Linux (알파인 리눅스) 는 무엇일까?  (0) 2023.09.04
CnetOS 방화벽 설정  (0) 2015.07.22
CentOS 파일 압축/풀기  (0) 2015.07.22
CentOS 심볼 링크 설정  (0) 2015.07.22

SQL Linux 업그레이드

 

·         Version : SQL Linux, Ubuntu

 

SQL Linux 최신버전으로 업그레이드 하는 방법에 대해서 살펴본다. 필자는 Ubuntu SQL Linux 설치된 상태이다. SQL Linux 업그레이드 진행 하기전 전체 사용자 데이터베이스 백업을 진행한다. 만약 업그레이드가 잘못되어 데이터베이스를 복원해야 경우를 대비해서 백업본을 보관하는 것이 좋다.

 

서버 로컬 접속 또는  Putty등을 사용하여 Ubuntu 서버에 연결한다.필자의 경우 Putty 사용하여 Ubuntu 서버에 접속 하였다.

 

Ubuntu에서 기존에 실행되고 있는 SQL Linux 버전을 확인한다. Sqlcmd 유틸리티를 사용하여 SQL Linux 연결하여 정보를 확인 있다. (Sqlcmd외에도 다양한 연결방법이 있으니 sqlcmd 사용할 필요는 없다.)

sqlcmd -S localhost -U sa

 

SELECT @@VERSION

GO

 

 

“apt-get” 명령을 사용하여 설치된 패키지 mssql-server 세부 사항을 확인할 수도 있다. apt-get 유틸리티는 Ubuntu APT(Advanced Packaging Tool)라이브러리를 사용하여 소프트웨어 패키지 설치, 기존 소프트웨어 패지키 제거, 기존 소프트웨어 패키지 업그레이드 등에 사용되는 무료 패키지 관리 명령어 프로그램이다. 아래 명령을 사용하여 mssql-server 버전, 체크섬 크기, 설치된 크기, 카테고리 간단한 설명과 함께 패치지 정보를 확인할 있다.

apt-cache show mssql-server

 

 

SQL Server 업그레이드 있는 사용가능한 업데이트 파일이 있는지 확인한다. 필요한 작업은 아니지만 업그레이드 프로세스를 이해하는데 도움이 된기 때문에 간단히 살펴본다. 명령은 설치된 모든 패키지에 대해 사용가능한 업데이트를 표시한다.

apt-get --just-print upgrade

 

 

현재 mssql-server 보류중인 업데이트가 있으므로 apt-get update 실행하여 /etc/apt/sources.list 파일에 지정된 소스에서 패키지 인덱스 파일을 동기화 한다. Update 명령은 패키지 인덱스 파일을 최신 버전으로 업데이트 한다. 아래 명령을 사용하여 패키지를 업데이트 한다.

sudo apt-get update

 

패키지 인데스 업데이트가 완료 되었으면 아래 명령을다시 실행하여 사용가능한 업데이트를 확인한다. 아래 스크린샷에서는 개의 패키지가 있음을 수있다. 하나는 이전 버전이고 다른 하나는 mssql-server 업그레이드하기 위해 적용해야하는 새로운 업데이트이다.

apt-cache show mssql-server

 

 

사용가능한 최신버전으로 업레이드하기 위해 아래 명령을 실행한다. 아래 명령은 최신 패키지를 다운로드 하고 /opt/mssql 있는 바이너리를 교체한다. 작업은 SQL 엔진을 교체하는 작업으로  사용자 데이터베이스에는 영향을 미치지 않지만 혹시 발생할 오류를 대비해서 처음 언급 한것처럼 백업을 것을 권장한다.

sudo apt-get install mssql-server

 

 

작업이 완료되면 SQL Server 빈드 버전이 14.0.3026.27에서 14.0.3029.16 업그레이드 것을 확인할 있다.

 

 

[참고자료]

https://www.mssqltips.com/sqlservertip/4647/upgrading-sql-server-running-on-ubuntu-to-latest-update/

 

 

2018-06-21 / Sungwook Kang / http://sqlmvp.kr

 

SQL Server, SQL Linux, SQL Upgrade, apt-get, apt-get update, apt-get install, 리눅스, linux,

+ Recent posts