Step 16-17. 접근 제어 & 백업/복구 — 인프라 파이프라인 최종 단계

이전 단계: 08-deploy-and-alerting.md 돌아가기: 09-hands-on.md

용어 안내

이 문서에서 “슬롯”은 학습용 비유다. 실무 용어가 아니다. 각 슬롯 옆에 실무에서 실제로 쓰는 용어를 병기한다.

Step 16. Nginx Basic Auth로 접근 제어 체험하기 — ⑬ Identity/Access (누가 무엇을 할 수 있는가)

왜 접근 제어가 필요한가? (WHY)

관리자 페이지에 누구나 접근할 수 있으면? DB를 아무나 삭제할 수 있으면? 접근 제어가 없으면 보안 사고가 난다.

회사 건물을 생각해보자. 1층 로비는 누구나 들어가지만, 서버실은 특정 카드키를 가진 사람만 들어간다. 웹 서비스도 마찬가지다. /health는 공개, /admin은 인증된 사용자만.

핵심 용어

Identity (아이덴티티)

  • 영어 뜻: “신원, 정체” — “너 누구야?”에 대한 답
  • IT 뜻: 시스템에 접근하는 사용자/서비스가 누구인지 식별하는 것
  • 비유: 회사 출입증. 이름과 사진으로 본인을 증명하는 것
  • 실무 용어: “IAM(Identity and Access Management)”

Access (액세스)

  • 영어 뜻: “접근, 이용 권한” — “너는 이것만 할 수 있어”
  • IT 뜻: 식별된 사용자에게 어떤 행동을 허용할지 정하는 것
  • 비유: 출입증의 등급. 일반 직원은 사무실만, 임원은 서버실까지
  • 실무 용어: “RBAC(Role-Based Access Control)”

Authentication(인증) vs Authorization(인가)

  • Authentication(인증): 출입증으로 본인 확인. “너 누구야?” → “김철수입니다”
  • Authorization(인가): 출입증 등급에 따라 들어갈 수 있는 층이 다름. “김철수는 3층까지만”
  • 인증이 먼저, 인가가 그 다음. 순서가 바뀔 수 없다

16-1. 비밀번호 파일 생성

# htpasswd 도구 설치 (비밀번호 파일을 만드는 도구)
brew install httpd          # Mac (Linux: apt install apache2-utils)

# nginx 디렉토리에 비밀번호 파일 생성
# -c: 새 파일 생성, -b: 커맨드라인에서 비밀번호 입력
htpasswd -cb nginx/.htpasswd admin secret123

16-2. Nginx 설정 업데이트

# nginx/default.conf
server {
    listen 80;

    # --- 일반 API — 누구나 접근 가능 ---
    location /health {
        proxy_pass http://app:3000;    # 인증 없이 앱으로 전달
    }

    location /info {
        proxy_pass http://app:3000;    # 인증 없이 앱으로 전달
    }

    # --- 관리 영역 — 인증 필요 ---
    location /admin {
        auth_basic "Admin Area";              # 브라우저에 표시될 로그인 메시지
        auth_basic_user_file /etc/nginx/.htpasswd;  # 비밀번호 파일 경로
        proxy_pass http://app:3000;           # 인증 통과 시 앱으로 전달
    }
}

16-3. Express 앱에 /admin 엔드포인트 추가

// app.js — /admin 엔드포인트 추가
app.get('/admin', (req, res) => {
  res.json({
    status: 'admin area',
    uptime: process.uptime(),         // 서버 가동 시간 (초)
    memory: process.memoryUsage(),    // 메모리 사용량
    timestamp: new Date().toISOString()
  });
});

16-4. docker-compose.yml 볼륨 추가

# docker-compose.yml의 nginx 서비스에 .htpasswd 볼륨 추가
services:
  nginx:
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf  # 기존 설정
      - ./nginx/.htpasswd:/etc/nginx/.htpasswd               # 비밀번호 파일 추가

16-5. 테스트

# 1. 인증 없이 일반 API — 성공
curl localhost/health
# → {"status":"ok"} (200 OK)

# 2. 인증 없이 관리 영역 — 거부!
curl localhost/admin
# → 401 Unauthorized (비밀번호 필요!)

# 3. 올바른 인증 정보 — 성공
curl -u admin:secret123 localhost/admin
# → {"status":"admin area","uptime":...} (200 OK)

# 4. 틀린 비밀번호 — 거부!
curl -u admin:wrong localhost/admin
# → 401 Unauthorized

핵심 인사이트: 이것이 접근 제어의 가장 기본적인 형태다. 실무에서 AWS IAM이나 K8s RBAC가 하는 일도 본질은 같다: **“누가 무엇을 할 수 있는가”**를 정하는 것.


Step 17. Docker 볼륨 백업과 복원 — ⑭ Backup/Disaster Recovery (데이터 보호)

왜 백업이 필요한가? (WHY)

Redis에 저장된 /count 데이터가 날아가면? DB가 실수로 삭제되면? 백업이 없으면 복구가 불가능하다.

핵심 용어

Backup (백업)

  • 영어 뜻: “예비 복사본” — 원본 손상에 대비해 미리 복사해두는 것
  • IT 뜻: 데이터를 별도 장소에 복사해두는 것
  • 비유: 스마트폰 사진을 클라우드에 올려두는 것. 폰이 고장나도 사진은 살아있다
  • 실무 용어: “백업/복원(Backup & Restore)”

Disaster Recovery (DR) (재해 복구)

  • 영어 뜻: “disaster(재해) + recovery(복구)” — 재앙에서 되살리는 것
  • IT 뜻: 서버 폭발, DB 삭제 등 최악의 상황에서 서비스를 되살리는 계획
  • 비유: 건물에 비상구와 대피 계획을 마련해두는 것
  • 실무 용어: “DR 플랜(Disaster Recovery Plan)”

RPO (Recovery Point Objective) = “복구 시점 목표”

  • 얼마만큼의 데이터 손실을 감수할 수 있는가? RPO = 1시간이면 최대 1시간 전까지 복구 가능
  • 비유: “저장 버튼을 얼마나 자주 누르는가”

RTO (Recovery Time Objective) = “복구 시간 목표”

  • 얼마 안에 서비스를 복구해야 하는가? RTO = 30분이면 30분 안에 복구
  • 비유: “정전 후 비상 발전기가 켜지는 데 걸리는 시간”

17-0. 준비: Redis에 볼륨 붙이기 (⚠️ 먼저 해야 함)

백업/복원을 하려면 Redis 데이터가 호스트 볼륨에 저장돼 있어야 한다. 지금까지 작성한 docker-compose.yml의 redis 서비스에는 볼륨이 없다 → 컨테이너를 내리면 데이터가 같이 사라진다. 백업/복원 실습이 성립하려면 볼륨부터 붙인다.

왜 필요한가?

  • 컨테이너의 파일시스템은 일회용이다. 컨테이너가 지워지면 내부 데이터도 증발한다
  • volumes는 호스트 디스크(또는 Docker 관리 볼륨)에 데이터를 영속 저장하는 메커니즘
  • 볼륨이 없으면 docker run --rm -v my-infra-lab_redis-data:/data ... 로 백업해도 Redis가 그 볼륨을 안 쓰므로 내용이 비어 있다 — 복원해도 반영 안 됨

docker-compose.yml 수정

# docker-compose.yml
services:
  redis:
    image: redis:alpine
    volumes:
      - redis-data:/data          # ← 추가: Redis 데이터 디렉토리(/data)를 볼륨에 연결

# 파일 맨 아래에 top-level volumes 선언 추가 (named volume 사용 시 필수)
volumes:
  redis-data:                     # services에서 참조한 볼륨 이름을 여기에 등록

/data 인가? Redis 공식 이미지가 RDB 스냅샷(dump.rdb)과 AOF 파일을 /data 에 저장하도록 기본 설정돼 있다. 이 경로를 볼륨에 연결해야 데이터가 살아남는다.

왜 top-level volumes: 를 따로 써야 하나? redis-data 같은 이름 있는 볼륨(named volume) 은 compose 규약상 서비스에서 참조하기 전에 top-level에 등록돼 있어야 한다. 빠뜨리면 service "redis" refers to undefined volume redis-data: invalid compose project 에러가 난다.

재기동

docker compose down              # -v 는 붙이지 말 것 (기존 데이터 있으면 유지)
docker compose up -d             # 이제 Redis가 볼륨을 마운트하고 뜬다

# 확인: 볼륨이 붙었는지
docker compose exec redis ls /data
# → dump.rdb 가 생길 예정이거나, 비어있으면 곧 채워짐

17-1. 데이터 만들기

docker compose up -d

# /count를 여러 번 호출해서 데이터를 쌓는다
curl localhost/count    # → 1
curl localhost/count    # → 2
# ... 여러 번 반복해서 카운트를 10까지 올린다

17-2. 백업하기

⚠️ 먼저: BGSAVE로 디스크에 저장 강제하기

Redis는 메모리 DB라서 카운트 값이 RAM에만 있을 수 있다. Redis 기본 저장 규칙(save 3600 1, save 300 100, save 60 10000)은 “카운트 10번” 정도로는 트리거되지 않는다/data/dump.rdb 가 비어 있거나 옛날 값.

백업 전에 강제로 스냅샷을 디스크에 쓰라고 명령한다:

docker compose exec redis redis-cli BGSAVE
# → Background saving started

sleep 2    # BGSAVE는 비동기이므로 잠깐 대기

docker compose exec redis redis-cli LASTSAVE
# → (integer) 1745200000   ← 방금 시각이면 저장 성공

BGSAVE vs SAVE: SAVE는 동기(Redis가 저장 동안 멈춤), BGSAVE는 비동기(백그라운드 자식 프로세스). 운영 중에는 반드시 BGSAVE를 쓴다.

백업 파일 생성

mkdir -p backup    # 백업 저장 디렉토리 생성

# Redis 볼륨을 tar.gz 파일로 백업
docker run --rm \
  -v my-infra-lab_redis-data:/data \
  -v $(pwd)/backup:/backup \
  alpine \
  tar czf /backup/redis-backup.tar.gz -C /data .
# --rm: 작업 끝나면 컨테이너 자동 삭제
# -v ..._redis-data:/data: 백업할 볼륨을 /data에 마운트
# -v $(pwd)/backup:/backup: 백업 파일 저장 위치 (호스트)
# alpine: 경량 리눅스 이미지 (tar 실행용)
# tar czf: c=create, z=gzip, f=file — 압축 아카이브 생성
# -C /data .: /data 안의 모든 파일을 아카이브에 포함

# 확인: 백업 안에 dump.rdb 가 들어있는지
tar tzvf backup/redis-backup.tar.gz
# → ./dump.rdb  (파일이 있고 크기가 0이 아니어야 정상)

17-3. 재해 시뮬레이션 (데이터 삭제)

docker compose down -v    # -v: 볼륨까지 삭제!
# 볼륨 : 컨테이너 전용 외장하드 -> 컨테이너는 일회용이라, 컨테이너를 지우면 데이터가 함께 사라짐. 해당 문제 해결을 위해 데이터를 컨테이너 외부(호스트pc)에 저장하는 메커니즘
docker compose up -d      # 다시 시작

curl localhost/count
# → 1 (이전 데이터가 모두 사라졌다!)

17-4. 백업에서 복원하기

docker compose stop redis    # Redis 중지 (파일 덮어쓰기 위해)

# 백업 파일에서 볼륨으로 데이터 복원
docker run --rm \
  -v my-infra-lab_redis-data:/data \
  -v $(pwd)/backup:/backup \
  alpine \
  tar xzf /backup/redis-backup.tar.gz -C /data
# tar xzf: x=extract — 압축 아카이브 풀기

docker compose start redis   # Redis 재시작

curl localhost/count
# → 11 (이전 데이터 10 + 새 요청 1 = 복원 성공!)

17-5. 자동 백업 스크립트

#!/bin/bash
# backup.sh — Redis 볼륨 자동 백업 스크립트
BACKUP_FILE="backup/redis-backup-$(date +%Y%m%d-%H%M%S).tar.gz"

docker run --rm \
  -v my-infra-lab_redis-data:/data \
  -v $(pwd)/backup:/backup \
  alpine \
  tar czf /$BACKUP_FILE -C /data .

echo "백업 완료: $BACKUP_FILE"
chmod +x backup.sh    # 실행 권한 부여
./backup.sh           # → 백업 완료: backup/redis-backup-20260416-143000.tar.gz

실무에서는 이 스크립트를 cron(리눅스 예약 작업)이나 Kubernetes CronJob으로 자동 실행한다. 예: “매일 새벽 3시에 백업”.

핵심 인사이트: 백업이 있어도 복원을 테스트하지 않으면 소용없다. “백업은 있는데 복원이 안 돼요”는 실제로 자주 일어나는 사고다. 반드시 복원까지 테스트하라.


전체 실습 완료!

14개 인프라 역할을 모두 로컬에서 체험했다. 클라우드로 가면 도구 이름만 바뀔 뿐, 역할은 같다.

슬롯 (학습용)이 실습에서 사용한 도구실무 도구
① Version ControlGitHubGitHub / GitLab
② Build/TestGitHub ActionsJenkins / CircleCI
③ Artifact Storageghcr.ioECR / Docker Hub
④ Deploy/Release수동 pull & upArgoCD / Flux
⑤ OrchestrationDocker ComposeKubernetes
⑥ ProvisioningTerraform (Docker)Terraform (AWS)
⑦ ConfigurationAnsible (컨테이너)Ansible (EC2)
⑧ NetworkingNginx 리버스 프록시ALB / Ingress
⑨ Secrets/Config.env 파일Vault / AWS SSM
⑩ Observability로그 미들웨어Datadog / Grafana
⑪ Alerting콘솔 경고PagerDuty / Slack
⑫ Security ScanningTrivySnyk / Prisma
⑬ Identity/AccessNginx Basic AuthAWS IAM / K8s RBAC
⑭ Backup/DRDocker 볼륨 백업RDS 스냅샷 / Velero

최종 체크리스트

□ Nginx Basic Auth로 접근 제어를 체험했다
□ Docker 볼륨을 백업하고 복원할 수 있다
□ RPO와 RTO가 무엇인지 체감했다
□ 14개 인프라 역할을 모두 로컬에서 체험했다

09-hands-on.md로 돌아가기

Comments

  • // 댓글을 불러오는 중...
main ⚠ 0 ✕ 0 Ln 1, Col 1 Spaces: 2 UTF-8 LF Markdown