Linux Basics
분류: Layer 4 - CS 기초: 운영체제 & Linux
1. 한 줄 정의
섹션 제목: “1. 한 줄 정의”Linux는 대부분의 서버에서 사용되는 운영체제이며, 서버 관리의 기본 언어가 되는 CLI(명령줄 인터페이스) 환경이다.
2. 왜 중요한가
섹션 제목: “2. 왜 중요한가”AWS든 GCP든, 서버에 들어가면 Linux다. 로그를 보고, 프로세스를 확인하고, 파일을 찾고, 네트워크를 진단하는 모든 작업이 Linux 명령어로 이뤄진다. Docker 컨테이너 안도 Linux다. CLI를 못 다루면 서버 문제가 생겼을 때 할 수 있는 게 거의 없다.
3. 핵심 개념
섹션 제목: “3. 핵심 개념”파일 시스템과 inode — 파일 이름 뒤에 숨어있는 구조
비유: 도서관을 생각해보자. 책(파일 데이터)은 선반 어딘가에 꽂혀 있고, 카탈로그 카드(inode)에는 그 책의 위치와 저자·발행일·장르 등 메타데이터가 적혀 있다. 사람들은 카탈로그(디렉토리)에서 책 이름으로 카드를 찾고, 카드에서 책 위치를 확인한다. 책의 실제 내용과 카탈로그 카드는 분리되어 있다.
원리: Linux에서 모든 파일과 디렉토리는 inode(index node) 라는 자료구조로 관리된다. inode에는 파일 이름 빼고 모든 메타데이터가 저장된다.
| inode에 저장되는 것 | 저장되지 않는 것 |
|---|---|
| 파일 크기, 권한(rwx), 소유자 | 파일 이름 |
| 생성/수정/접근 시간 | 파일 내용(별도 블록) |
| 데이터 블록 포인터 | |
| 링크 카운트(하드 링크 수) |
왜 파일 이름이 inode에 없는가? 파일 이름은 디렉토리에 저장된다. 디렉토리는 (파일이름 → inode번호) 매핑 테이블이다. 이 분리 덕분에 같은 inode를 여러 이름(하드 링크)으로 가리킬 수 있고, 파일을 이동할 때 inode를 건드리지 않고 디렉토리 항목만 바꾸면 된다.
# inode 번호 확인ls -li /var/log/nginx/access.log# 예상 출력:# 1234567 -rw-r--r-- 1 root root 102400 Apr 9 10:00 /var/log/nginx/access.log# └──────┘ ← inode 번호
# inode 상세 정보 확인stat /var/log/nginx/access.log# 예상 출력:# File: /var/log/nginx/access.log# Size: 102400# Inode: 1234567 Links: 1# Access: (0644/-rw-r--r--) Uid: (0/root) Gid: (0/root)# Access: 2024-04-09 09:00:00# Modify: 2024-04-09 10:00:00# Change: 2024-04-09 10:00:00
# 파일시스템의 inode 사용량 확인 (inode 고갈 진단)df -i# 예상 출력:# Filesystem Inodes IUsed IFree IUse% Mounted on# /dev/xvda1 1310720 102400 1208320 8% /📖 더 보기: Inodes and the Linux filesystem — Red Hat Blog — inode 구조, 하드 링크 vs 심볼릭 링크, inode 고갈 문제 실무 가이드 (입문)
inode 원리의 크로스 도메인 매핑 — “번호로 실체를 특정한다”는 구조는 DB와 컨테이너에서도 동일하게 나타난다:
| 개념 | Linux inode | DB 인덱스 (B-Tree) | 컨테이너 레이어 해시 |
|---|---|---|---|
| 식별자 | inode 번호 (정수) | Primary Key / Row ID | 레이어 SHA256 해시 |
| 실체 위치 | 데이터 블록 포인터 | Heap Page 오프셋 | overlay2 lowerdir 경로 |
| 이름·경로 | 디렉토리(별도 저장) | 인덱스 엔트리(별도 구조) | 이미지 태그(별도 메타데이터) |
| 고갈 패턴 | inode 소진 → 파일 생성 불가 | 인덱스 bloat → 쿼리 저하 | 레이어 누적 → 이미지 용량 폭증 |
| 재사용 원리 | 하드 링크(같은 inode, 여러 이름) | FK 참조(같은 Row ID, 여러 테이블) | 공유 레이어(같은 해시, 여러 이미지) |
근거: Docker overlay2는 Linux overlayfs(커널 3.18, 2014) 위에서 동작하며, 컨테이너 수정 시 copy-on-write로 upper 레이어에 새 inode를 생성한다. 레이어를 삭제하지 않으면 inode·디스크 모두 고갈될 수 있어
docker system prune정기 실행이 필요하다. (Linux File System Architecture — DEV Community)
실무 연결 — inode 고갈 장애: 디스크 용량(블록)이 남아있어도 inode가 모두 소진되면 새 파일을 만들 수 없다. 이 경우 df -h는 여유 공간이 있어 보이지만 df -i를 보면 IUse%가 100%다. 소용량 파일이 수백만 개 생성되는 환경(로그 파일, 임시 파일, PHP 세션 파일)에서 발생한다. Docker 컨테이너가 /tmp에 임시 파일을 무한 생성하는 패턴도 원인이 된다.
모든 것이 파일이다. 디렉토리 구조: / (루트), /home (사용자), /var/log (로그), /etc (설정), /tmp (임시).
Linux 파일 시스템은 계층 구조(트리 형태)이다. /(루트)가 최상위이고, 모든 파일과 디렉토리는 여기서 시작한다. 디바이스, 프로세스 정보(/proc), 시스템 설정도 모두 파일로 표현된다. 예를 들어 cat /proc/1/status를 실행하면 PID 1 프로세스의 상태를 파일처럼 읽을 수 있다.
꼭 알아야 할 명령어
| 명령어 | 용도 | 예시 |
|---|---|---|
ls | 파일 목록 | ls -la /var/log |
cd | 디렉토리 이동 | cd /home/deploy |
cat | 파일 내용 출력 | cat config.yml |
tail | 파일 끝부분 보기 | tail -f /var/log/app.log (실시간) |
grep | 문자열 검색 | grep "ERROR" app.log |
find | 파일 찾기 | find / -name "*.log" |
ps | 프로세스 목록 | ps aux |
top/htop | 리소스 사용량 | htop |
df | 디스크 사용량 | df -h |
curl | HTTP 요청 | curl -v http://localhost:3000 |
chmod | 파일 권한 | chmod 755 script.sh |
ssh | 원격 접속 | ssh user@server-ip |
프로세스가 내부적으로 어떻게 동작하는가
비유: 프로세스는 “실행 중인 프로그램의 인스턴스”이다. 같은 프로그램을 두 번 실행하면 두 개의 프로세스가 생긴다.
각 프로세스는 Linux 커널로부터 고유한 PID(Process ID)를 부여받고, 독립된 메모리 공간을 가진다. ps 명령어는 /proc 가상 파일시스템에서 정보를 읽어온다.
# 모든 프로세스 확인ps aux
# 예상 출력:# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND# root 1 0.0 0.1 168936 13040 ? Ss 09:00 0:05 /sbin/init# deploy 1234 0.3 2.1 812340 87432 ? Sl 09:01 1:23 node dist/main.js# root 5678 0.0 0.0 14428 1012 pts/0 R+ 10:30 0:00 ps aux📖 더 보기: Linux Process Management - DigitalOcean — 프로세스 생성부터 종료까지 생명주기와 관리 명령어 설명 (입문)
파이프(|)와 리다이렉션(>)
명령어의 출력을 다른 명령어의 입력으로 연결. 강력한 조합 도구.
# 에러 로그 줄 수 세기cat app.log | grep "ERROR" | wc -l# 예상 출력: 42
# 파일에 쓰기echo "hello" > file.txt
# 실시간 로그에서 에러만 필터링tail -f /var/log/app.log | grep "ERROR"# 예상 출력 (실시간 스트리밍):# 2024-01-15T10:30:01 ERROR [AppController] Database connection failed# 2024-01-15T10:30:05 ERROR [AuthService] Token expired for user 123로그 분석 실전 조합 (grep + awk + tail)
# 특정 시간대의 에러만 추출grep "ERROR" app.log | grep "2024-01-15 10:"
# IP별 요청 횟수 집계 (awk 활용)cat access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10# 예상 출력:# 1523 203.0.113.42# 892 198.51.100.7# 234 192.168.1.100
# NestJS 앱 로그에서 에러만 뽑아 최신 50줄 확인tail -n 1000 app.log | grep "ERROR" | tail -50📖 더 보기: Log Like a Pro: Mastering grep, awk, and sed — 실제 서버 로그 분석에 사용하는 grep/awk/sed 조합 예시 (중급)
프로세스와 포트
# node 프로세스 찾기ps aux | grep node# 예상 출력:# deploy 1234 0.3 2.1 812340 87432 ? Sl 09:01 1:23 node dist/main.js
# 3000번 포트를 점유 중인 프로세스 확인 (포트 충돌 디버깅)lsof -i :3000# 예상 출력:# COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME# node 1234 deploy 23u IPv4 12345 0t0 TCP *:3000 (LISTEN)
# ss (Socket Statistics) — 현대 Linux의 표준 포트/소켓 확인 도구 (netstat 대체)ss -tlnp# 예상 출력:# State Recv-Q Send-Q Local Address:Port Peer Address:Port Process# LISTEN 0 511 0.0.0.0:3000 0.0.0.0:* users:(("node",pid=1234,fd=23))# LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=678,fd=3))# 옵션: -t(TCP), -l(LISTEN 중), -n(숫자 주소), -p(프로세스 이름)
# 모든 TCP 연결 상태 확인 (ESTABLISHED, TIME_WAIT 등)ss -tn | grep ESTABLISHED | wc -l# 예상 출력: 42 ← 현재 활성 연결 42개
# 프로세스 강제 종료kill -9 1234SIGTERM vs SIGKILL — 언제 어떤 시그널을 쓰는가
kill -9(SIGKILL)는 커널이 프로세스를 즉시 제거하며 프로세스가 핸들러를 등록할 수 없다. 반면 kill(SIGTERM, 기본값)은 프로세스에게 “정리하고 종료하라”고 요청하는 신호다.
| 상황 | 권장 시그널 | 이유 |
|---|---|---|
| 서비스 재시작 / 정상 배포 | SIGTERM | 진행 중 요청 완료, DB 커넥션 반납, 파일 플러시 후 종료 |
| graceful shutdown 대기 중 (10~30초 타임아웃) | SIGTERM → 대기 → SIGKILL | 업계 표준 에스컬레이션 패턴 |
| 프로세스가 응답 없음 (deadlock, 무한루프) | SIGKILL | SIGTERM 무시되는 경우에만 최후 수단 |
| 포트 충돌로 새 서버 기동 불가 | SIGKILL | 빠른 해제 필요. 단, 데이터 손상 위험 인지 후 사용 |
# 권장 절차: SIGTERM 먼저, 안 죽으면 SIGKILLkill 1234 # SIGTERM (기본값, 핸들러 실행 기회 부여)sleep 15 # graceful shutdown 대기kill -0 1234 2>/dev/null && kill -9 1234 # 살아있으면 강제 종료
# 프로세스가 시그널을 무시하는지 진단strace -e trace=signal -p 1234 # 수신 시그널 추적cat /proc/1234/status | grep State # D(Uninterruptible Sleep) 이면 SIGKILL도 효과 없음SIGKILL 오남용 시 진행 중인 파일 쓰기 손상, 고아 자식 프로세스 발생, DB 트랜잭션 롤백 미완료 등의 부작용이 생긴다. systemd는
TimeoutStopSec(기본 90초) 초과 후 자동으로 SIGKILL을 보내는 에스컬레이션을 내장하고 있다. (SIGKILL vs SIGTERM — SUSE Communities)
환경변수
서버/컨테이너에서 설정값(DB 주소, API Key 등)은 환경변수로 주입된다. 코드에 하드코딩하지 않고 환경변수로 분리하는 것이 기본 원칙이다.
# 모든 환경변수 출력printenv
# 특정 변수 확인 (NestJS의 DATABASE_URL 확인)echo $DATABASE_URL# 예상 출력: postgresql://user:pass@mydb.xxxx.ap-northeast-2.rds.amazonaws.com:5432/mydb
# 현재 셸에서 변수 설정export PORT=3000권한 (rwx)
-rwxr-xr-- = 소유자(rwx) / 그룹(r-x) / 기타(r—). 숫자로는 754.
# 파일 권한 확인ls -la script.sh# 예상 출력:# -rw-r--r-- 1 deploy deploy 1234 Jan 15 10:00 script.sh# (소유자: 읽기/쓰기, 그룹: 읽기, 기타: 읽기)
# 실행 권한 부여chmod +x script.shls -la script.sh# 예상 출력:# -rwxr-xr-x 1 deploy deploy 1234 Jan 15 10:00 script.shchmod 777 오남용 리스크 — 최소 권한 원칙 적용 기준
chmod 777은 “모든 사용자에게 읽기·쓰기·실행 권한 부여”로, 빠른 해결처럼 보이지만 보안 사고의 주요 원인이다.
| 시나리오 | 위험 | 올바른 대안 |
|---|---|---|
| 웹서버 업로드 디렉토리를 777로 설정 | 공격자가 PHP 웹셸 업로드 후 서버 탈취 | chmod 755 + 소유자만 쓰기 허용 |
설정 파일(.env, credentials)을 777로 설정 | DB 비밀번호·API Key 노출 | chmod 600 (소유자 읽기·쓰기만) |
| 배포 스크립트를 777로 설정 | 임의 사용자가 스크립트 수정·실행 가능 | chmod 750 (그룹 읽기·실행만) |
| 실제 사고 (2020, 금융기관) | 777 디렉토리로 cryptojacking 스크립트 주입, 시스템 자원 탈취 | 권한 감사 자동화 필요 |
# 현재 777 파일 탐색 (보안 감사)find /var/www -perm 777 -type f
# 안전한 권한 설정 기준chmod 644 config.yml # 파일: 소유자 읽기/쓰기, 나머지 읽기만chmod 600 .env # 민감 파일: 소유자만 읽기/쓰기chmod 755 deploy.sh # 실행 스크립트: 소유자 전체, 나머지 읽기/실행chmod 750 /app/scripts # 디렉토리: 그룹 접근, 외부 차단최소 권한 원칙(Principle of Least Privilege): 필요한 최소한의 권한만 부여한다.
chmod 777은 문제의 근본 원인(잘못된 소유자, 그룹 설정)을 감추고 Linux 권한 체계 전체를 무력화한다. (Chmod 777 Is Not a Fix — xygeni.io)
systemd와 journalctl — 서비스 관리의 표준
비유: systemd는 “서버의 관리자”이다. 시스템이 부팅될 때 어떤 서비스를 어떤 순서로 시작할지를 결정하고, 서비스가 죽으면 자동으로 재시작한다.
AWS EC2에 직접 NestJS를 배포하거나 시스템 데몬(nginx, 크론 등)을 다룰 때 systemd 명령어가 필요하다. ECS/Docker 환경에서는 systemd 대신 컨테이너 수명 관리가 이를 대체하지만, EC2에 직접 배포된 서비스나 서버 수준 디버깅 시 반드시 마주친다.
# 서비스 상태 확인systemctl status nginx# 예상 출력:# ● nginx.service - A high performance web server# Loaded: loaded (/lib/systemd/system/nginx.service; enabled)# Active: active (running) since Mon 2024-01-15 09:00:00 UTC; 2h 30min ago# Main PID: 1234 (nginx)
# 서비스 시작/중지/재시작systemctl start nginxsystemctl stop nginxsystemctl restart nginx
# 부팅 시 자동 시작 등록systemctl enable my-nestapp
# 최근 로그 50줄 보기journalctl -u nginx -n 50# 예상 출력:# Jan 15 09:00:01 server nginx[1234]: nginx: the configuration file /etc/nginx/nginx.conf test is successful
# 실시간 로그 스트리밍 (tail -f 와 동일)journalctl -u my-nestapp -f
# 특정 시간 이후 에러만 필터링journalctl -u my-nestapp --since "2024-01-15 10:00" -p err# 예상 출력:# Jan 15 10:30:01 server node[1234]: Error: connect ECONNREFUSED 127.0.0.1:5432📖 더 보기: How To Use journalctl - DigitalOcean — journalctl 필터링, 시간 범위 지정, 우선순위별 로그 조회 완전 가이드 (입문)
보안 하드닝 — 서버를 안전하게 운영하는 기본 원칙 (2025)
프로덕션 EC2 서버를 처음 만들었다면 반드시 아래 설정을 점검한다. 이 체크리스트는 CIS Benchmark 기반이다.
-
SSH Root 로그인 비활성화
Terminal window # /etc/ssh/sshd_config 수정sudo sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_configsudo systemctl restart sshd# → 해커가 root 계정을 직접 노릴 수 없게 됨 -
SSH 키 기반 인증만 허용 (비밀번호 로그인 차단)
Terminal window # /etc/ssh/sshd_configPasswordAuthentication noPubkeyAuthentication yes -
불필요한 서비스 비활성화
Terminal window # 실행 중인 서비스 목록 확인systemctl list-units --type=service --state=running# 필요 없는 서비스 비활성화 (예: telnet, ftp)sudo systemctl disable telnetsudo systemctl stop telnet -
Fail2Ban — 브루트포스 공격 차단
Fail2Ban은 로그 파일을 모니터링하여, 일정 횟수 이상 로그인 실패 시 해당 IP를 자동으로 차단한다.
Terminal window sudo apt install fail2bansudo systemctl enable fail2ban# 기본 설정: 5회 실패 시 10분 차단 -
최소 권한 사용자로 서비스 실행
NestJS를 root로 실행하지 않는다. 전용
deploy유저를 만들고 해당 유저로 서비스를 실행한다. root로 실행된 서비스가 해킹당하면 서버 전체가 위험해진다.Terminal window # 서비스 전용 유저 생성 (로그인 쉘 없음, 홈 없음)sudo useradd --no-create-home --shell /usr/sbin/nologin deploy# systemd Unit 파일에서 User=deploy 설정
4. 실무에서 어디에 쓰이나
섹션 제목: “4. 실무에서 어디에 쓰이나”- 서버 로그 확인 (
tail -f,grep) - 서버 상태 점검 (CPU, 메모리, 디스크)
- 배포 스크립트 실행
- SSH로 원격 서버 접속
- Docker 컨테이너 안에서 디버깅
5. 현재 내 업무와 연결점
섹션 제목: “5. 현재 내 업무와 연결점”- 서비스 장애 시 서버에 접속해서 로그 확인
- 배포 관련 스크립트 읽기/수정
- Docker 컨테이너 안에 들어가서 상태 확인
- CI/CD 파이프라인의 셸 스크립트 이해
6. 자주 헷갈리는 개념 비교
섹션 제목: “6. 자주 헷갈리는 개념 비교”| 개념 A | 개념 B | 차이점 |
|---|---|---|
> | >> | >는 덮어쓰기, >>는 이어쓰기 |
kill | kill -9 | kill은 정상 종료 요청, kill -9는 강제 종료 |
| 절대경로 | 상대경로 | /var/log는 절대, ./log는 현재 위치 기준 상대 |
sudo | su | sudo는 한 명령만 관리자 권한 실행, su는 사용자 전환 |
tail -f | journalctl -f | tail -f는 파일 직접 스트리밍, journalctl -f는 systemd 서비스 로그 스트리밍 |
6.5 트러블슈팅
섹션 제목: “6.5 트러블슈팅”🔧 “Permission denied” — 파일/스크립트 실행 불가
섹션 제목: “🔧 “Permission denied” — 파일/스크립트 실행 불가”증상: bash: ./deploy.sh: Permission denied 또는 cat: /etc/nginx/nginx.conf: Permission denied
원인: 파일에 실행 권한(x)이 없거나, 현재 사용자가 해당 파일의 읽기/실행 권한이 없음
해결:
# 현재 파일 권한 확인ls -la deploy.sh# 출력: -rw-r--r-- 1 deploy deploy 512 Jan 15 10:00 deploy.sh (실행 권한 없음)
# 실행 권한 추가chmod +x deploy.sh
# 소유자 문제일 경우sudo chown deploy:deploy deploy.sh🔧 “No space left on device” — 디스크 꽉 참
섹션 제목: “🔧 “No space left on device” — 디스크 꽉 참”증상: 파일 쓰기/로그 기록 실패, No space left on device 에러. Docker 빌드/컨테이너 기동 실패
원인: 디스크 용량 소진. 서버에서 오래된 로그가 쌓이거나, Docker 이미지/레이어가 누적되는 경우 자주 발생
해결:
# 디스크 사용량 확인df -h# 예상 출력:# Filesystem Size Used Avail Use% Mounted on# /dev/xvda1 20G 19G 100M 100% / ← 100%!
# 어느 디렉토리가 많이 차지하는지 확인 (상위 5개)du -sh /* 2>/dev/null | sort -rh | head -5
# Docker 미사용 이미지/컨테이너 정리docker system prune -f
# 오래된 로그 파일 삭제find /var/log -name "*.log" -mtime +30 -delete🔧 포트가 이미 사용 중 — 서버 기동 실패
섹션 제목: “🔧 포트가 이미 사용 중 — 서버 기동 실패”증상: Error: listen EADDRINUSE: address already in use :::3000 — NestJS 또는 Node.js 서버 시작 시 발생
원인: 이전 프로세스가 종료되지 않고 해당 포트를 계속 점유하고 있음
해결:
# 3000번 포트 사용 프로세스 확인lsof -i :3000# 출력: node 1234 deploy 23u IPv4 12345 0t0 TCP *:3000 (LISTEN)
# 해당 PID 종료kill -9 1234
# 또는 한 줄로kill -9 $(lsof -ti :3000)🔧 systemd 서비스가 시작되지 않는 경우
섹션 제목: “🔧 systemd 서비스가 시작되지 않는 경우”증상: systemctl start my-nestapp 실행 후 Active: failed (Result: exit-code) 상태
원인: 환경변수 누락, 실행 파일 경로 오류, 포트 충돌, 코드 에러 등 다양한 이유로 프로세스가 시작 직후 종료됨
해결:
# 서비스 상태와 최근 에러 확인systemctl status my-nestapp# 출력에서 에러 메시지 확인:# Jan 15 10:30:01 server node[5678]: Error: Cannot find module 'dist/main.js'
# 더 자세한 로그 확인journalctl -u my-nestapp -n 100 --no-pager
# 서비스 유닛 파일 확인 (환경변수, 실행 경로 등)cat /etc/systemd/system/my-nestapp.service# [Service]# ExecStart=/usr/bin/node /home/deploy/dist/main.js# EnvironmentFile=/home/deploy/.env ← 이 파일이 실제로 존재하는지 확인
# 유닛 파일 수정 후 반드시 데몬 리로드systemctl daemon-reloadsystemctl restart my-nestapp🔧 EC2 SSH 접속 불가 — “Connection timed out” 또는 “Permission denied (publickey)”
섹션 제목: “🔧 EC2 SSH 접속 불가 — “Connection timed out” 또는 “Permission denied (publickey)””증상: ssh: connect to host 1.2.3.4 port 22: Connection timed out 또는 Permission denied (publickey,gssapi-keyex,gssapi-with-mic)
원인별 구분:
| 에러 메시지 | 원인 | 해결 |
|---|---|---|
Connection timed out | Security Group에 22번 포트 허용 규칙 없음 | EC2 → Security Groups → 인바운드 규칙에 내 IP/22 추가 |
Connection timed out (SG 확인 후에도) | EC2가 Private Subnet에 있어 직접 접근 불가 | Bastion Host 또는 AWS Session Manager(SSM) 사용 |
Permission denied (publickey) | 잘못된 키 파일 또는 키 파일 권한 문제 | chmod 400 my-key.pem 후 재시도 |
Host key verification failed | known_hosts에 이전 IP 정보가 남아 있음 | ssh-keygen -R <서버IP> 실행 후 재접속 |
# SSH 키 권한 수정 후 접속chmod 400 my-key.pemssh -i my-key.pem ec2-user@1.2.3.4
# AWS Session Manager로 SSH 없이 접속 (보안 강화 권고 방식)aws ssm start-session --target i-xxxxxxxxxxxxxxxxx# → 22번 포트/Security Group 불필요, IAM 권한만으로 접속AWS 보안 권고: 22번 포트 개방 대신 **Session Manager(SSM)**을 사용하면 Security Group에 22번 포트를 열 필요가 없어 공격 면을 줄일 수 있다.
7. 체크리스트
섹션 제목: “7. 체크리스트”- SSH로 서버에 접속할 수 있다
-
tail -f로 실시간 로그를 볼 수 있다 -
grep으로 로그에서 특정 에러를 검색할 수 있다 -
ps,top으로 프로세스/리소스 상태를 확인할 수 있다 - 파이프(|)를 써서 명령어를 조합할 수 있다
-
printenv로 환경변수를 확인하고, 서비스 설정값이 어떻게 주입되는지 설명할 수 있다 -
journalctl -u <서비스명> -f로 systemd 서비스 로그를 실시간으로 볼 수 있다
8. 추가 학습 키워드
섹션 제목: “8. 추가 학습 키워드”bash scripting, cron job, systemd, journalctl, scp/rsync, tmux/screen, awk/sed, 환경변수
📚 추천 리소스
섹션 제목: “📚 추천 리소스”- 📖 Linux Process Management - DigitalOcean — ps, kill, top 명령어와 프로세스 생명주기 입문 가이드 (입문)
- 📖 How To Use journalctl - DigitalOcean — systemd 서비스 로그 조회, 시간/우선순위 필터링 완전 가이드 (입문)
- 📖 Inodes and the Linux filesystem — Red Hat Blog — inode 구조, 하드 링크 vs 심볼릭 링크, inode 고갈 문제까지 실무 관점으로 정리 (입문)
- 📖 Log Like a Pro: grep, awk, sed — 실제 서버 로그 분석에 사용하는 파이프 조합 예시 (중급)
- 📖 2025 Linux Hardening Checklist — CIS Benchmark 기반 서버 보안 하드닝 체크리스트 (중급)
9. 내가 직접 확인해볼 것
섹션 제목: “9. 내가 직접 확인해볼 것”-
로컬 터미널에서
tail -f+grep조합으로 로그 필터링 연습Terminal window # Docker 컨테이너 로그 실시간 필터링docker logs -f <컨테이너명> | grep "ERROR" -
ps aux | grep으로 실행 중인 프로세스 찾아보기Terminal window ps aux | grep node# 예상 출력: deploy 1234 0.3 2.1 812340 87432 ? Sl 09:01 1:23 node dist/main.js -
Docker 컨테이너 안에
docker exec -it <id> sh로 들어가서 명령어 연습 -
df -h,free -m으로 서버 리소스 확인해보기Terminal window df -h# 예상 출력:# Filesystem Size Used Avail Use% Mounted on# /dev/xvda1 20G 8.5G 11G 44% /free -m# 예상 출력:# total used free shared buff/cache available# Mem: 3938 2341 234 123 1362 1234 -
EC2에 배포된 서비스가 있다면
journalctl -u <서비스명> -n 50으로 최근 로그 확인 -
ls -li와stat으로 파일의 inode 번호와 메타데이터 확인Terminal window ls -li /etc/hostname# 예상 출력:# 131074 -rw-r--r-- 1 root root 12 Jan 15 09:00 /etc/hostname# └────┘ ← inode 번호stat /etc/hostname# 예상 출력:# File: /etc/hostname# Size: 12# Inode: 131074 Links: 1# Access: (0644/-rw-r--r--) Uid: (0/root)# inode 사용량 확인 (고갈 여부 진단)df -i# 예상 출력:# Filesystem Inodes IUsed IFree IUse% Mounted on# /dev/xvda1 1310720 45231 1265489 4% /
10. 5줄 요약
섹션 제목: “10. 5줄 요약”- 서버는 Linux이고, CLI가 그 언어이다 —
tail,grep,ps,curl4가지만 알아도 장애 대응의 80%가 해결된다 - 파이프(
|)로 명령어를 연결하면 로그 필터링·집계·분석을 단 한 줄로 처리할 수 있다 - 파일 권한(rwx)과 프로세스 관리는 서버 운영의 기본이며, 대부분의 “왜 안 되지?” 문제는 여기서 시작된다
- systemd + journalctl이 프로덕션 서비스 관리의 표준이며, Docker/ECS 환경에서는 컨테이너 런타임이 이를 대체한다
- 컨테이너 안도 Linux다 — Linux를 알면 Docker·ECS Exec·K8s exec 모든 환경에서 디버깅이 가능하다
실무 아키텍처 원칙 (2025): EC2에 직접 SSH 접속하는 방식보다 **AWS Systems Manager Session Manager(SSM)**을 사용하는 것이 현재 AWS 권고 표준이다. 22번 포트를 열 필요 없이 IAM 권한만으로 브라우저/CLI에서 서버에 접속할 수 있어 공격 표면을 줄일 수 있다. 불변 인프라(Immutable Infrastructure) 패턴이 확산되면서 “서버에 SSH로 들어가서 수동 수정”하는 방식은 점점 지양되고 있으며, 설정 변경은 코드로 관리(IaC)하고 서버는 교체하는 방식이 표준이 되고 있다.