1. 서버의 기본 개념
1.1 서버란?
서버 = 요청을 받아서 처리하고 응답하는 컴퓨터
[클라이언트] ──요청──> [서버] ──응답──> [클라이언트]
예시:
브라우저(클라이언트) ──"상품 목록 보여줘"──>
API 서버
──"여기 데이터야"──>
브라우저
1.2 서버의 종류
물리적 분류:
1. 온프레미스 (On-Premise)
└─ 회사 건물에 직접 서버 컴퓨터 설치
└─ 예: 삼성, 네이버 같은 대기업
2. 클라우드 (Cloud)
└─ 다른 회사(AWS, GCP 등)의 서버를 빌려 쓰기
└─ 예: 대부분의 스타트업
역할별 분류:
1. 웹 서버 (Web Server)
└─ Nginx, Apache
└─ 정적 파일(HTML, CSS, JS) 제공
└─ 리버스 프록시 역할
2. 애플리케이션 서버 (WAS)
└─ Spring Boot, Node.js, Django
└─ 비즈니스 로직 처리
3. 데이터베이스 서버
└─ MySQL, PostgreSQL, MongoDB
└─ 데이터 저장/조회
4. 캐시 서버
└─ Redis, Memcached
└─ 빠른 데이터 임시 저장
5. 파일 서버
└─ AWS S3, NAS
└─ 이미지, 동영상 등 저장
1.3 서버 스펙 이해하기
서버 스펙 예시:
├─ CPU: 4 Core (vCPU)
│ └─ 동시 처리 능력
│
├─ Memory: 8GB RAM
│ └─ 프로그램 실행 공간
│
├─ Storage: 100GB SSD
│ └─ 데이터 저장 공간
│
└─ Network: 1Gbps
└─ 네트워크 속도
선택 기준:
개발/테스트 서버:
└─ t3.small (2 vCPU, 2GB RAM) - 월 $15
소규모 운영:
└─ t3.medium (2 vCPU, 4GB RAM) - 월 $30
중규모 운영:
└─ t3.large (2 vCPU, 8GB RAM) - 월 $60
대규모:
└─ c5.xlarge (4 vCPU, 8GB RAM) - 월 $120+
2. 네트워크 기초
2.1 IP 주소
IP = 인터넷 상의 주소
IPv4: 192.168.1.10
└─ 4개 숫자 (0~255)
└─ 총 43억개 (부족해서 IPv6로 전환 중)
Public IP (공인 IP):
└─ 52.79.123.45
└─ 인터넷에서 접근 가능
└─ 돈 내고 할당받음
Private IP (사설 IP):
└─ 10.0.1.10
└─ 내부 네트워크에서만 사용
└─ 공짜
2.2 포트 (Port)
포트 = 서비스 구분 번호
IP 주소 = 아파트 주소
포트 = 동/호수
예시:
192.168.1.10:8080
└─ IP: 192.168.1.10
└─ 포트: 8080
주요 포트:
22 - SSH (서버 접속)
80 - HTTP (웹)
443 - HTTPS (보안 웹)
3306 - MySQL
5432 - PostgreSQL
6379 - Redis
8080 - Spring Boot (개발)
8081 - API 서버
3000 - React, Node.js
2.3 도메인과 DNS
도메인 → DNS → IP 주소
example.com
↓ (DNS 조회)
52.79.123.45
↓
EC2 서버
설정 예시:
도메인 구매: example.com (가비아, Route53)
DNS 설정:
├─ example.com → 52.79.123.45
├─ api.example.com → 52.79.123.45
└─ admin.example.com → 52.79.123.45
2.4 CIDR 표기법
CIDR = IP 주소 범위 표현 방법
10.0.0.0/16
└─ 10.0.0.0 ~ 10.0.255.255 (65,536개)
10.0.1.0/24
└─ 10.0.1.0 ~ 10.0.1.255 (256개)
10.0.1.0/28
└─ 10.0.1.0 ~ 10.0.1.15 (16개)
계산법:
/16 = 32-16 = 16비트 → 2^16 = 65,536개
/24 = 32-24 = 8비트 → 2^8 = 256개
/28 = 32-28 = 4비트 → 2^4 = 16개
2.5 프로토콜
HTTP (Hypertext Transfer Protocol)
├─ 포트: 80
├─ 암호화: ❌
└─ 사용: 개발 환경
HTTPS (HTTP + SSL/TLS)
├─ 포트: 443
├─ 암호화: ✅
└─ 사용: 운영 환경 (필수!)
TCP (Transmission Control Protocol)
├─ 신뢰성: ✅ (데이터 순서 보장)
└─ 사용: HTTP, SSH, 데이터베이스
UDP (User Datagram Protocol)
├─ 신뢰성: ❌ (빠르지만 손실 가능)
└─ 사용: 동영상 스트리밍, 게임
3. Linux 서버 기본
3.1 왜 Linux인가?
서버 OS 점유율:
├─ Linux: 96%
│ ├─ Ubuntu (가장 인기)
│ ├─ CentOS
│ └─ Amazon Linux
│
├─ Windows Server: 3%
└─ 기타: 1%
Linux 장점:
✅ 무료
✅ 안정적
✅ 보안 강함
✅ 가벼움 (GUI 없음)
✅ 자동화 쉬움
3.2 필수 Linux 명령어
파일 & 디렉토리:
# 현재 위치 확인
pwd
# 파일 목록
ls -la
# 디렉토리 이동
cd /home/ubuntu
# 디렉토리 생성
mkdir myapp
# 파일 생성
touch file.txt
# 파일 내용 보기
cat file.txt
less file.txt # 긴 파일 (스크롤 가능)
# 파일 복사
cp source.txt dest.txt
# 파일 이동/이름 변경
mv old.txt new.txt
# 파일 삭제
rm file.txt
rm -rf directory/ # 디렉토리 삭제 (조심!)
# 파일 편집
vi file.txt
nano file.txt # 초보자 추천
프로세스 관리:
# 실행 중인 프로세스 확인
ps aux
ps aux | grep java
# 실시간 프로세스 모니터링
top
htop # 더 보기 좋음 (설치 필요)
# 프로세스 종료
kill 1234 # PID로 종료
kill -9 1234 # 강제 종료
killall java # 이름으로 종료
네트워크:
# 포트 확인
netstat -tulpn
ss -tulpn # 최신 방식
# 특정 포트 사용 확인
lsof -i :8080
# 네트워크 연결 테스트
ping google.com
curl http://localhost:8080
wget http://example.com/file.zip
시스템 정보:
# 디스크 사용량
df -h
# 디렉토리 크기
du -sh /var/log
# 메모리 사용량
free -h
# CPU 정보
lscpu
# 시스템 정보
uname -a
로그 확인:
# 로그 실시간 확인
tail -f /var/log/application.log
# 최근 100줄
tail -n 100 app.log
# 로그 검색
grep "ERROR" app.log
grep -i "error" app.log # 대소문자 무시
권한 관리:
# 권한 변경
chmod 755 script.sh # rwxr-xr-x
chmod +x script.sh # 실행 권한 추가
# 소유자 변경
chown ubuntu:ubuntu file.txt
# sudo (관리자 권한으로 실행)
sudo apt update
3.3 패키지 관리
Ubuntu (apt):
# 패키지 목록 업데이트
sudo apt update
# 패키지 설치
sudo apt install docker.io
# 패키지 삭제
sudo apt remove docker.io
# 시스템 업그레이드
sudo apt upgrade
CentOS (yum):
sudo yum update
sudo yum install docker
3.4 서비스 관리 (systemd)
# 서비스 시작
sudo systemctl start nginx
# 서비스 중지
sudo systemctl stop nginx
# 서비스 재시작
sudo systemctl restart nginx
# 서비스 상태 확인
sudo systemctl status nginx
# 부팅 시 자동 시작 설정
sudo systemctl enable nginx
# 자동 시작 해제
sudo systemctl disable nginx
# 로그 확인
sudo journalctl -u nginx -f
3.5 환경변수
# 환경변수 확인
echo $PATH
env
# 임시 설정 (현재 세션만)
export MY_VAR="hello"
# 영구 설정 (~/.bashrc 또는 ~/.profile)
echo 'export MY_VAR="hello"' >> ~/.bashrc
source ~/.bashrc
# Spring Boot 환경변수
export SPRING_PROFILES_ACTIVE=prd
export DB_PASSWORD=mypassword
4. 클라우드 (AWS) 기초
4.1 AWS 주요 서비스
컴퓨팅:
├─ EC2: 가상 서버
├─ Lambda: 서버리스 함수
└─ ECS/EKS: 컨테이너 오케스트레이션
스토리지:
├─ S3: 파일 저장소
├─ EBS: EC2용 디스크
└─ EFS: 공유 파일 시스템
데이터베이스:
├─ RDS: 관계형 DB (MySQL, PostgreSQL)
├─ DynamoDB: NoSQL
└─ ElastiCache: Redis, Memcached
네트워크:
├─ VPC: 가상 네트워크
├─ Route53: DNS
├─ CloudFront: CDN
└─ ELB: 로드 밸런서
보안:
├─ IAM: 권한 관리
├─ Security Group: 방화벽
└─ ACM: SSL 인증서
4.2 VPC (Virtual Private Cloud)
VPC = 내 전용 네트워크 공간
VPC: 10.0.0.0/16
│
├─ Public Subnet (10.0.1.0/24)
│ ├─ 인터넷 연결 ✅
│ └─ 웹서버, API 서버
│
├─ Private Subnet (10.0.2.0/24)
│ ├─ 인터넷 연결 ❌
│ └─ 데이터베이스, 캐시
│
├─ Internet Gateway
│ └─ VPC와 인터넷 연결
│
└─ NAT Gateway
└─ Private 서브넷에서 외부 접속
실제 설정:
VPC 생성:
├─ 이름: my-vpc
├─ CIDR: 10.0.0.0/16
│
├─ Public Subnet:
│ ├─ CIDR: 10.0.1.0/24
│ ├─ AZ: ap-northeast-2a
│ └─ 용도: 웹/API 서버
│
└─ Private Subnet:
├─ CIDR: 10.0.2.0/24
├─ AZ: ap-northeast-2a
└─ 용도: DB, Redis
4.3 EC2 (Elastic Compute Cloud)
EC2 = 가상 서버
인스턴스 타입:
t 시리즈 (범용, 가성비):
├─ t3.micro: 2 vCPU, 1GB - 무료 티어
├─ t3.small: 2 vCPU, 2GB - 개발/테스트
├─ t3.medium: 2 vCPU, 4GB - 소규모 운영
└─ t3.large: 2 vCPU, 8GB - 중규모 운영
c 시리즈 (CPU 최적화):
└─ c5.xlarge: 4 vCPU, 8GB - CPU 집약적
r 시리즈 (메모리 최적화):
└─ r5.large: 2 vCPU, 16GB - 캐시, 인메모리 DB
m 시리즈 (균형):
└─ m5.large: 2 vCPU, 8GB - 균형 잡힌 워크로드
EC2 생성 과정:
1. AMI 선택:
└─ Ubuntu 24.04 LTS
2. 인스턴스 타입:
└─ t3.small
3. 네트워크:
├─ VPC: my-vpc
├─ Subnet: Public Subnet
└─ Public IP: 자동 할당
4. 스토리지:
└─ 20GB gp3 (SSD)
5. Security Group (방화벽):
├─ SSH (22): 내 IP만
├─ HTTP (80): 0.0.0.0/0
└─ HTTPS (443): 0.0.0.0/0
6. Key Pair (SSH 키):
└─ my-key.pem 다운로드
SSH 접속:
# 키 권한 설정 (한 번만)
chmod 400 my-key.pem
# EC2 접속
ssh -i my-key.pem ubuntu@52.79.123.45
# 또는 퍼블릭 DNS 사용
ssh -i my-key.pem ubuntu@ec2-52-79-123-45.ap-northeast-2.compute.amazonaws.com
4.4 Security Group (보안 그룹)
Security Group = 방화벽 규칙
Inbound Rules (들어오는 트래픽):
┌──────────┬──────┬─────────────┬─────────────┐
│ Type │ Port │ Source │ 설명 │
├──────────┼──────┼─────────────┼─────────────┤
│ SSH │ 22 │ 내IP/32 │ 내 PC만 │
│ HTTP │ 80 │ 0.0.0.0/0 │ 모두 허용 │
│ HTTPS │ 443 │ 0.0.0.0/0 │ 모두 허용 │
│ Custom │ 8080 │ 10.0.0.0/16 │ VPC 내부만 │
└──────────┴──────┴─────────────┴─────────────┘
Outbound Rules (나가는 트래픽):
└─ All traffic: 0.0.0.0/0 (기본 전체 허용)
베스트 프랙티스:
✅ SSH는 내 IP만 허용
✅ 불필요한 포트는 닫기
✅ 애플리케이션 포트는 내부망만
✅ 주기적으로 규칙 검토
4.5 S3 (Simple Storage Service)
S3 = 파일 저장소 (무제한)
사용 사례:
├─ 이미지, 동영상 저장
├─ 정적 웹사이트 호스팅
├─ 백업 파일 저장
└─ 로그 아카이빙
특징:
✅ 용량 무제한
✅ 99.999999999% 내구성
✅ 저렴 (GB당 $0.023/월)
✅ CDN(CloudFront) 연동
Spring Boot에서 S3 사용:
@Service
public class S3Service {
private final AmazonS3 s3Client;
public String uploadFile(MultipartFile file) {
String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
s3Client.putObject(
"my-bucket",
fileName,
file.getInputStream(),
new ObjectMetadata()
);
return s3Client.getUrl("my-bucket", fileName).toString();
}
}
4.6 RDS (Relational Database Service)
RDS = 관리형 데이터베이스
지원 엔진:
├─ PostgreSQL
├─ MySQL
├─ MariaDB
├─ Oracle
└─ SQL Server
vs 직접 설치:
┌────────────────┬─────────────┬──────────────┐
│ │ EC2에 직접 │ RDS │
├────────────────┼─────────────┼──────────────┤
│ 설치/설정 │ 직접 │ 자동 │
│ 백업 │ 직접 │ 자동 │
│ 업데이트 │ 직접 │ 자동 │
│ 모니터링 │ 직접 구축 │ 기본 제공 │
│ 장애 복구 │ 직접 │ 자동 │
│ 비용 │ 저렴 │ 약간 비쌈 │
└────────────────┴─────────────┴──────────────┘
추천:
- 소규모/학습: EC2에 직접 설치
- 운영 환경: RDS 사용
4.7 ElastiCache (Redis/Memcached)
ElastiCache = 관리형 캐시 서버
Redis vs Memcached:
┌──────────────┬─────────────┬──────────────┐
│ │ Redis │ Memcached │
├──────────────┼─────────────┼──────────────┤
│ 데이터 구조 │ 다양 │ Key-Value만 │
│ 영속성 │ 지원 │ 미지원 │
│ 복제 │ 지원 │ 미지원 │
│ 트랜잭션 │ 지원 │ 미지원 │
│ 속도 │ 빠름 │ 아주 빠름 │
└──────────────┴─────────────┴──────────────┘
추천: Redis (기능이 많음)
사용 사례:
✅ 세션 저장
✅ API 응답 캐싱
✅ 실시간 랭킹
✅ 분산 락
✅ 메시지 큐 (Redis Pub/Sub)
5. Docker & 컨테이너
5.1 Docker란?
Docker = 애플리케이션을 컨테이너로 패키징하는 도구
전통적 방식:
서버에 직접 설치
├─ Java 설치
├─ Node.js 설치
├─ PostgreSQL 설치
└─ 환경 설정...
문제점:
❌ 환경마다 설정 다름
❌ 버전 충돌
❌ 배포 어려움
Docker 방식:
컨테이너로 격리
├─ API 컨테이너 (Java + 앱)
├─ Admin 컨테이너 (Java + 앱)
├─ PostgreSQL 컨테이너
└─ Redis 컨테이너
장점:
✅ 어디서든 동일하게 동작
✅ 격리되어 충돌 없음
✅ 배포 간단
✅ 롤백 쉬움
5.2 Docker 핵심 개념
이미지 (Image):
└─ 애플리케이션 + 의존성을 묶은 "설계도"
└─ 예: ubuntu:24.04, nginx:1.25, postgres:15
컨테이너 (Container):
└─ 이미지를 실행한 "실제 프로세스"
└─ 예: 실행 중인 API 서버
Dockerfile:
└─ 이미지를 만드는 "레시피"
Docker Hub:
└─ 이미지 저장소 (GitHub 같은 것)
5.3 Docker 설치
# Ubuntu에서 Docker 설치
sudo apt update
sudo apt install docker.io docker-compose -y
# Docker 서비스 시작
sudo systemctl start docker
sudo systemctl enable docker
# 현재 사용자를 docker 그룹에 추가 (sudo 없이 사용)
sudo usermod -aG docker $USER
# 로그아웃 후 재로그인 필요
# 또는
newgrp docker
# 설치 확인
docker --version
docker-compose --version
5.4 Docker 명령어
이미지 관련:
# 이미지 다운로드
docker pull nginx:1.25
# 이미지 목록
docker images
# 이미지 빌드
docker build -t myapp:1.0 .
# 이미지 삭제
docker rmi myapp:1.0
# 사용하지 않는 이미지 삭제
docker image prune
컨테이너 관련:
# 컨테이너 실행
docker run -d -p 8080:8080 --name myapp myapp:1.0
# -d: 백그라운드 실행
# -p: 포트 매핑 (호스트:컨테이너)
# --name: 컨테이너 이름
# 실행 중인 컨테이너 목록
docker ps
# 모든 컨테이너 목록 (중지된 것 포함)
docker ps -a
# 컨테이너 중지
docker stop myapp
# 컨테이너 시작
docker start myapp
# 컨테이너 재시작
docker restart myapp
# 컨테이너 삭제
docker rm myapp
# 컨테이너 로그 확인
docker logs myapp
docker logs -f myapp # 실시간
# 컨테이너 내부 접속
docker exec -it myapp /bin/bash
# 컨테이너 리소스 사용량
docker stats
5.5 Dockerfile 작성
Spring Boot 애플리케이션 예시:
# 1단계: 베이스 이미지
FROM openjdk:21-jdk-slim
# 2단계: 작업 디렉토리 설정
WORKDIR /app
# 3단계: JAR 파일 복사
COPY build/libs/app.jar app.jar
# 4단계: 포트 노출
EXPOSE 8080
# 5단계: 실행 명령
ENTRYPOINT ["java", "-jar", "app.jar"]
멀티 스테이지 빌드 (권장):
# 1단계: 빌드 스테이지
FROM gradle:8.5-jdk21 AS builder
WORKDIR /app
COPY . .
RUN ./gradlew bootJar -x test
# 2단계: 실행 스테이지
FROM openjdk:21-jdk-slim
WORKDIR /app
COPY --from=builder /app/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
이미지 빌드:
docker build -t myapp:1.0 .
5.6 Docker Compose
Docker Compose = 여러 컨테이너를 한 번에 관리
# docker-compose.yml
version: '3.8'
services:
# PostgreSQL
db:
image: postgres:15
container_name: myapp-db
environment:
POSTGRES_DB: mydb
POSTGRES_USER: user
POSTGRES_PASSWORD: password
ports:
- "5432:5432"
volumes:
- db-data:/var/lib/postgresql/data
networks:
- myapp-network
# Redis
redis:
image: redis:7-alpine
container_name: myapp-redis
ports:
- "6379:6379"
networks:
- myapp-network
# API 서버
api:
build: ./api
container_name: myapp-api
ports:
- "8080:8080"
depends_on:
- db
- redis
environment:
SPRING_PROFILES_ACTIVE: prd
DB_HOST: db
REDIS_HOST: redis
networks:
- myapp-network
# Nginx
nginx:
image: nginx:1.25
container_name: myapp-nginx
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- api
networks:
- myapp-network
networks:
myapp-network:
driver: bridge
volumes:
db-data:
Docker Compose 명령어:
# 모든 서비스 시작
docker-compose up -d
# 특정 서비스만 시작
docker-compose up -d api
# 서비스 중지
docker-compose stop
# 서비스 중지 및 삭제
docker-compose down
# 볼륨까지 삭제
docker-compose down -v
# 로그 확인
docker-compose logs -f
# 특정 서비스 로그
docker-compose logs -f api
# 서비스 재시작
docker-compose restart api
5.7 Docker 네트워크
Bridge 네트워크 (기본):
├─ 같은 네트워크의 컨테이너끼리 통신
└─ 컨테이너 이름으로 접근 가능
Host 네트워크:
└─ 호스트의 네트워크를 직접 사용
None 네트워크:
└─ 네트워크 없음 (격리)
컨테이너 간 통신:
# API 서버에서 PostgreSQL 접속
spring:
datasource:
url: jdbc:postgresql://db:5432/mydb
# ↑ 컨테이너 이름으로 접근!
5.8 Docker 볼륨
볼륨 = 데이터 영구 저장
문제:
컨테이너 삭제 → 데이터도 삭제됨
해결:
볼륨 사용 → 호스트에 데이터 저장
볼륨 타입:
services:
db:
volumes:
# Named Volume (추천)
- db-data:/var/lib/postgresql/data
# Bind Mount (호스트 경로 직접 지정)
- /host/path:/container/path
# Anonymous Volume
- /var/lib/postgresql/data
volumes:
db-data: # Named Volume 선언
6. 배포 자동화 (CI/CD)
6.1 CI/CD란?
CI (Continuous Integration):
└─ 코드 변경 → 자동 빌드 → 자동 테스트
CD (Continuous Deployment):
└─ 빌드 성공 → 자동 배포
전체 흐름:
코드 푸시 → 빌드 → 테스트 → 배포 → 모니터링
6.2 GitLab CI/CD
.gitlab-ci.yml 기본 구조:
# 단계 정의
stages:
- build
- test
- deploy
# 공통 설정
variables:
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
# 빌드 작업
build-job:
stage: build
image: gradle:8.5-jdk21
script:
- ./gradlew bootJar -x test
artifacts:
paths:
- build/libs/*.jar
expire_in: 1 hour
# 테스트 작업
test-job:
stage: test
image: gradle:8.5-jdk21
script:
- ./gradlew test
coverage: '/Total.*?(\d+\.?\d*)%/'
# 배포 작업
deploy-job:
stage: deploy
tags:
- my-runner # 특정 Runner 지정
script:
- docker build -t myapp:latest .
- docker-compose up -d
only:
- main # main 브랜치만
when: manual # 수동 실행
고급 기능:
# 환경별 배포
deploy-dev:
stage: deploy
environment:
name: development
url: https://dev.example.com
only:
- develop
deploy-prd:
stage: deploy
environment:
name: production
url: https://example.com
only:
- main
when: manual
# 조건부 실행
deploy-api:
stage: deploy
script:
- echo "Deploy API"
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
changes:
- api/**/*
# 캐시 사용 (빌드 속도 향상)
build-job:
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- .gradle/wrapper
- .gradle/caches
6.3 GitLab Runner 설치 & 등록
# 1. Runner 설치
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
sudo apt-get install gitlab-runner
# 2. Runner 등록
sudo gitlab-runner register
# 입력 정보:
# GitLab URL: https://gitlab.com
# Token: (프로젝트 Settings → CI/CD → Runners에서 복사)
# Description: my-runner
# Tags: my-runner,docker
# Executor: shell 또는 docker
# 3. Runner 상태 확인
sudo gitlab-runner status
# 4. Runner 시작
sudo gitlab-runner start
6.4 GitHub Actions
.github/workflows/deploy.yml:
name: Deploy to EC2
on:
push:
branches: [ main ]
workflow_dispatch: # 수동 실행
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
java-version: '21'
distribution: 'temurin'
- name: Build with Gradle
run: ./gradlew bootJar -x test
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: app-jar
path: build/libs/*.jar
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Download artifact
uses: actions/download-artifact@v3
with:
name: app-jar
- name: Deploy to EC2
env:
PRIVATE_KEY: ${{ secrets.EC2_SSH_KEY }}
HOST: ${{ secrets.EC2_HOST }}
USER: ubuntu
run: |
echo "$PRIVATE_KEY" > private_key
chmod 600 private_key
scp -i private_key -o StrictHostKeyChecking=no \
*.jar $USER@$HOST:/home/ubuntu/app/
ssh -i private_key -o StrictHostKeyChecking=no $USER@$HOST << 'EOF'
cd /home/ubuntu/app
docker build -t myapp:latest .
docker-compose up -d
EOF
6.5 Blue-Green 배포
무중단 배포 전략:
현재 상태:
├─ Blue (v1.0) ← 사용자 트래픽
└─ Green (idle)
배포 시:
1. Green에 v1.1 배포
2. Green 헬스체크
3. 트래픽을 Green으로 전환
4. Blue 중지
장점:
✅ 무중단 배포
✅ 빠른 롤백 (Blue로 다시 전환)
Docker Compose 예시:
# docker-compose.blue.yml
services:
api-blue:
image: myapp:blue
ports:
- "8080:8080"
# docker-compose.green.yml
services:
api-green:
image: myapp:green
ports:
- "8081:8080"
배포 스크립트:
#!/bin/bash
# 1. 현재 활성화된 컨테이너 확인
if docker ps | grep -q "api-blue"; then
CURRENT="blue"
NEW="green"
NEW_PORT="8081"
else
CURRENT="green"
NEW="blue"
NEW_PORT="8080"
fi
# 2. 새 버전 배포
docker-compose -f docker-compose.$NEW.yml up -d
# 3. 헬스체크 (30초 대기)
echo "Waiting for health check..."
for i in {1..30}; do
if curl -f http://localhost:$NEW_PORT/actuator/health; then
echo "Health check passed!"
break
fi
sleep 1
done
# 4. Nginx 설정 변경 (트래픽 전환)
sed -i "s/$CURRENT/$NEW/g" /etc/nginx/conf.d/default.conf
nginx -s reload
# 5. 이전 버전 중지
docker-compose -f docker-compose.$CURRENT.yml down
7. 웹서버 & 리버스 프록시
7.1 Nginx란?
Nginx = 웹서버 + 리버스 프록시
역할:
1. 정적 파일 제공 (HTML, CSS, JS, 이미지)
2. 리버스 프록시 (API 서버로 요청 전달)
3. 로드 밸런싱 (여러 서버로 분산)
4. SSL/TLS 처리
5. 캐싱
7.2 Nginx 설치
# Ubuntu
sudo apt update
sudo apt install nginx
# 시작
sudo systemctl start nginx
sudo systemctl enable nginx
# 상태 확인
sudo systemctl status nginx
# 설정 파일 위치
/etc/nginx/nginx.conf # 메인 설정
/etc/nginx/conf.d/ # 추가 설정
7.3 Nginx 기본 설정
리버스 프록시 설정:
# /etc/nginx/conf.d/default.conf
server {
listen 80;
server_name example.com;
# 로그
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# API 서버로 프록시
location /api/ {
proxy_pass http://localhost:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Admin 서버
location /admin/ {
proxy_pass http://localhost:8081/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 정적 파일
location / {
root /var/www/html;
index index.html;
try_files $uri $uri/ /index.html;
}
}
로드 밸런싱:
# Upstream 정의
upstream api_servers {
least_conn; # 연결이 가장 적은 서버로
server 10.0.1.10:8080 weight=3;
server 10.0.1.11:8080 weight=1;
server 10.0.1.12:8080 backup; # 백업 서버
}
server {
listen 80;
location /api/ {
proxy_pass http://api_servers/;
}
}
SSL/HTTPS 설정:
server {
listen 443 ssl http2;
server_name example.com;
# SSL 인증서
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
# SSL 설정
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://localhost:8080;
}
}
# HTTP → HTTPS 리다이렉트
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
캐싱:
# 캐시 존 정의
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:10m max_size=1g inactive=60m;
server {
location /api/products {
proxy_cache api_cache;
proxy_cache_valid 200 10m; # 200 응답은 10분간 캐시
proxy_cache_key "$request_uri";
add_header X-Cache-Status $upstream_cache_status;
proxy_pass http://localhost:8080;
}
}
7.4 Nginx 명령어
# 설정 테스트
sudo nginx -t
# 재시작 (다운타임 발생)
sudo systemctl restart nginx
# Reload (다운타임 없음)
sudo nginx -s reload
# 중지
sudo nginx -s stop
# 로그 확인
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log
8. 데이터베이스 & 캐시
8.1 PostgreSQL
설치:
# Ubuntu
sudo apt install postgresql postgresql-contrib
# 시작
sudo systemctl start postgresql
sudo systemctl enable postgresql
# PostgreSQL 사용자로 전환
sudo -u postgres psql
기본 명령:
-- 데이터베이스 생성
CREATE DATABASE mydb;
-- 사용자 생성
CREATE USER myuser WITH PASSWORD 'mypassword';
-- 권한 부여
GRANT ALL PRIVILEGES ON DATABASE mydb TO myuser;
-- 데이터베이스 목록
\l
-- 테이블 목록
\dt
-- 종료
\q
외부 접속 허용:
# postgresql.conf 수정
sudo vi /etc/postgresql/15/main/postgresql.conf
# listen_addresses = '*'
# pg_hba.conf 수정
sudo vi /etc/postgresql/15/main/pg_hba.conf
# host all all 0.0.0.0/0 md5
# 재시작
sudo systemctl restart postgresql
8.2 Redis
설치:
sudo apt install redis-server
# 시작
sudo systemctl start redis-server
sudo systemctl enable redis-server
# 접속
redis-cli
기본 명령:
# 값 저장
SET mykey "hello"
# 값 조회
GET mykey
# TTL 설정 (초 단위)
SETEX mykey 60 "expires in 60 seconds"
# 모든 키 조회
KEYS *
# 키 삭제
DEL mykey
# 데이터베이스 전환 (0~15)
SELECT 1
# 모든 데이터 삭제
FLUSHALL
# 종료
exit
Redis 설정:
# redis.conf 수정
sudo vi /etc/redis/redis.conf
# 주요 설정:
bind 0.0.0.0 # 외부 접속 허용
requirepass mypassword # 비밀번호 설정
maxmemory 256mb # 최대 메모리
maxmemory-policy allkeys-lru # 메모리 부족 시 정책
8.3 백업 & 복구
PostgreSQL 백업:
# 전체 백업
pg_dump -U myuser mydb > backup.sql
# 복구
psql -U myuser mydb < backup.sql
# 자동 백업 스크립트
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
pg_dump -U myuser mydb > /backup/mydb_$DATE.sql
find /backup -name "*.sql" -mtime +7 -delete # 7일 이상된 백업 삭제
Redis 백업:
# RDB (스냅샷)
redis-cli SAVE
# AOF (Append Only File) - 모든 쓰기 명령 기록
# redis.conf에서 설정:
appendonly yes
appendfsync everysec
9. 모니터링 & 로깅
9.1 애플리케이션 로깅
Logback 설정 (Spring Boot):
<!-- logback-spring.xml -->
<configuration>
<springProfile name="prd">
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/var/log/myapp/application.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/var/log/myapp/application.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="FILE"/>
</root>
</springProfile>
</configuration>
9.2 시스템 모니터링
기본 모니터링 명령:
# CPU, 메모리 실시간 확인
top
htop
# 디스크 사용량
df -h
# 메모리 사용량
free -h
# 네트워크 연결
netstat -tulpn
# 프로세스 확인
ps aux | grep java
CloudWatch (AWS):
기본 메트릭:
├─ CPU 사용률
├─ 네트워크 In/Out
├─ 디스크 I/O
└─ 상태 체크
커스텀 메트릭:
└─ 애플리케이션 로그
└─ JVM 메모리
└─ API 응답 시간
9.3 로그 수집 (ELK 스택)
Elasticsearch: 로그 저장 & 검색
Logstash: 로그 수집 & 변환
Kibana: 시각화
간단한 로그 관리:
# 로그 로테이션 설정
sudo vi /etc/logrotate.d/myapp
/var/log/myapp/*.log {
daily # 매일 로테이션
rotate 30 # 30일 보관
compress # 압축
delaycompress # 1일 후 압축
missingok # 파일 없어도 에러 없음
notifempty # 빈 파일은 로테이션 안 함
}
10. 보안
10.1 SSH 보안
# 1. 비밀번호 로그인 비활성화
sudo vi /etc/ssh/sshd_config
# PasswordAuthentication no
# PermitRootLogin no
# 2. SSH 포트 변경
# Port 2222
# 3. 재시작
sudo systemctl restart sshd
# 4. 키 기반 인증만 허용
ssh-keygen -t ed25519
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
10.2 방화벽 (UFW)
# UFW 설치 (Ubuntu에 기본 포함)
sudo apt install ufw
# 기본 정책: 들어오는 거 차단, 나가는 거 허용
sudo ufw default deny incoming
sudo ufw default allow outgoing
# 포트 허용
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
# 특정 IP만 허용
sudo ufw allow from 1.2.3.4 to any port 22
# UFW 활성화
sudo ufw enable
# 상태 확인
sudo ufw status
10.3 SSL/TLS 인증서
Let's Encrypt (무료):
# Certbot 설치
sudo apt install certbot python3-certbot-nginx
# 인증서 발급 (Nginx 자동 설정)
sudo certbot --nginx -d example.com -d www.example.com
# 인증서 자동 갱신
sudo certbot renew --dry-run
# Cron으로 자동 갱신 설정 (이미 자동으로 됨)
# /etc/cron.d/certbot
10.4 환경변수 보안
민감 정보는 환경변수로:
# .env 파일 (Git에 커밋 금지!)
DB_PASSWORD=secret123
REDIS_PASSWORD=redis_secret
JASYPT_PASSWORD=jasypt_key
# Docker Compose에서 사용
services:
api:
env_file:
- .env
Jasypt로 암호화:
// application.yml
spring:
datasource:
password: ENC(암호화된_비밀번호)
// 실행 시 복호화 키 전달
java -jar app.jar -Djasypt.encryptor.password=secret
11. 실전 배포 프로세스
11.1 전체 배포 플로우
1. 개발
└─ 로컬에서 개발 & 테스트
2. 코드 푸시
└─ git push origin main
3. CI/CD 자동 실행
├─ 빌드
├─ 테스트
└─ Docker 이미지 생성
4. 배포
├─ 새 컨테이너 시작
├─ 헬스체크
└─ 트래픽 전환
5. 모니터링
└─ 로그 & 메트릭 확인
11.2 체크리스트
배포 전:
✅ 테스트 통과 확인
✅ 환경변수 설정 확인
✅ 데이터베이스 마이그레이션 계획
✅ 롤백 계획 수립
✅ 백업 완료
배포 중:
✅ 헬스체크 통과 확인
✅ 로그 모니터링
✅ 에러율 확인
배포 후:
✅ 주요 기능 동작 확인
✅ 응답 시간 확인
✅ 에러 로그 확인
✅ 사용자 피드백 모니터링
11.3 트러블슈팅
자주 발생하는 문제:
문제 1: 컨테이너가 시작하자마자 종료됨
해결:
└─ docker logs [container] 로그 확인
└─ 환경변수, 설정 파일 확인
문제 2: 502 Bad Gateway
해결:
└─ 백엔드 서버 실행 여부 확인
└─ 포트 확인
└─ 방화벽/Security Group 확인
문제 3: 메모리 부족 (OOM)
해결:
└─ JVM 메모리 설정 확인
└─ 서버 스펙 업그레이드
└─ 메모리 누수 확인
문제 4: 디스크 공간 부족
해결:
└─ docker system prune # 미사용 이미지/컨테이너 삭제
└─ 로그 로테이션 확인
└─ 불필요한 파일 삭제
마무리: 학습 로드맵
1단계: 기초 (1~2주)
✅ Linux 기본 명령어
✅ SSH 접속
✅ Docker 기본 (이미지, 컨테이너)
✅ EC2 생성 및 접속
2단계: 중급 (2~4주)
✅ Docker Compose
✅ Nginx 리버스 프록시
✅ GitLab CI/CD 설정
✅ 간단한 배포 자동화
3단계: 고급 (1~2개월)
✅ Blue-Green 배포
✅ 모니터링 & 로깅
✅ 보안 강화
✅ 성능 최적화
4단계: 전문가 (지속적 학습)
✅ Kubernetes
✅ 마이크로서비스 아키텍처
✅ 인프라 자동화 (Terraform)
✅ 대규모 트래픽 처리