본문 바로가기
서버 인프라 실무

Docker 설치부터 Compose v2로 서비스 올리기(Nginx+PostgreSQL, Ubuntu 24.04)

by yamoojin83 2025. 10. 21.

Docker 설치부터 Compose v2로 서비스 올리기(Nginx+PostgreSQL, Ubuntu 24.04)

컨테이너는 배포를 단순화하고 환경 차이를 줄여줍니다. 이 글에서는 Ubuntu 24.04 서버에서 Docker EngineDocker Compose v2를 설치한 뒤, Nginx(리버스 프록시)PostgreSQL(데이터베이스)compose.yaml 하나로 올려보겠습니다. 설치→권한→네트워크/볼륨→헬스체크→백업→점검까지 운영 관점으로 정리합니다.


1) Docker Engine + Compose v2 설치

# 1) 패키지 준비
sudo apt update
sudo apt install -y ca-certificates curl gnupg

# 2) Docker 공식 GPG 키/리포지토리
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu noble stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 3) Docker 엔진/CLI/Compose 플러그인 설치
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 4) 서비스 활성화 & 버전 확인
sudo systemctl enable --now docker
docker --version
docker compose version

옵션: 현재 사용자로 sudo 없이 쓰려면:

sudo usermod -aG docker $USER
# 로그아웃/로그인 또는
newgrp docker

2) 프로젝트 디렉터리 & 기본 구조

sudo mkdir -p /opt/stack/nginx/conf
sudo mkdir -p /opt/stack/nginx/html
sudo mkdir -p /opt/stack/pg/data
sudo chown -R $USER:$USER /opt/stack
cd /opt/stack

테스트용 index 페이지:

echo "<h1>It works (Docker + Nginx)!</h1>" > /opt/stack/nginx/html/index.html

3) Nginx 기본 설정(리버스 프록시 예시 포함)

정적 파일 서빙 + 백엔드 프록시(있다면) 템플릿:

# /opt/stack/nginx/conf/default.conf
server {
  listen 80;
  server_name _;

  # 정적 테스트 페이지
  root /usr/share/nginx/html;
  index index.html;

  # (선택) 백엔드 프록시
  # location /api/ {
  #   proxy_pass http://backend: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;
  # }
}

4) compose.yaml 작성: Nginx + PostgreSQL

# /opt/stack/compose.yaml
name: app-stack
services:
  nginx:
    image: nginx:1.27-alpine
    container_name: nginx
    ports:
      - "80:80"
      # HTTPS를 붙일 계획이면 "443:443" 매핑(추가 설정 필요)
    volumes:
      - ./nginx/html:/usr/share/nginx/html:ro
      - ./nginx/conf/default.conf:/etc/nginx/conf.d/default.conf:ro
    healthcheck:
      test: ["CMD-SHELL", "wget -qO- http://localhost:80 || exit 1"]
      interval: 10s
      timeout: 3s
      retries: 5
    depends_on:
      - db
    restart: unless-stopped
    networks:
      - appnet

  db:
    image: postgres:16-alpine
    container_name: postgres
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: strongpassword
      POSTGRES_DB: appdb
    volumes:
      - ./pg/data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
      interval: 10s
      timeout: 5s
      retries: 10
    restart: unless-stopped
    networks:
      - appnet

# (선택) 백엔드 앱 컨테이너 예시
#  backend:
#    build: ./app
#    container_name: backend
#    environment:
#      SPRING_PROFILES_ACTIVE: prod
#      DB_URL: jdbc:postgresql://db:5432/appdb
#      DB_USER: app
#      DB_PASS: strongpassword
#    depends_on:
#      db:
#        condition: service_healthy
#    restart: unless-stopped
#    networks:
#      - appnet

networks:
  appnet:
    driver: bridge

포인트:

  • volumes데이터 영속성 보장(PostgreSQL), Nginx 설정/정적파일은 :ro로 읽기전용 마운트
  • healthcheck로 서비스 준비 상태 확인 → depends_on.condition로 의존성 제어(예시 주석)
  • restart: unless-stopped로 장애 시 자동 재기동

5) 기동 & 동작 확인

cd /opt/stack
docker compose up -d
docker compose ps

웹 확인(서버에서):

curl -I http://127.0.0.1
# HTTP/1.1 200 OK

DB 접속 확인(PostgreSQL 클라이언트):

docker exec -it postgres psql -U app -d appdb -c "\l"

6) 운영 옵션(로그·리소스·보안)

  • 로그: docker logs -f nginx, docker logs -f postgres
  • 리소스 제한 (고급):
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
    
    주의: Swarm/Compose v2 환경에 따라 적용 범위가 다릅니다(테스트 후 사용).
  • 환경변수/비밀: 민감값은 .env 또는 secrets 매커니즘 사용(레포에 커밋 금지)
  • 네트워크: 외부에 직접 노출할 서비스만 ports 사용. 내부 통신은 networks로 격리

7) 백업/복구(필수 루틴)

DB 볼륨을 주기적으로 덤프합니다(로컬/원격 저장소에 보관).

# 백업
docker exec postgres pg_dump -U app -d appdb | gzip > /opt/stack/pg/backup/appdb_$(date +%F).sql.gz

# 복원(예시: 새 DB에)
gunzip -c /opt/stack/pg/backup/appdb_2025-10-14.sql.gz | \
  docker exec -i postgres psql -U app -d appdb

정기 자동화는 crontab -e로 예약(예: 매일 새벽 3시):

0 3 * * * docker exec postgres pg_dump -U app -d appdb | gzip > /opt/stack/pg/backup/appdb_$(date +\%F).sql.gz

8) HTTPS 적용(요약)

컨테이너 앞단에 호스트 Nginx(또는 프록시 전용 컨테이너)를 두고 Certbot으로 인증서를 받아 443을 개방하세요. 호스트 Nginx에서 proxy_pass http://127.0.0.1:80 → 컨테이너 Nginx로 라우팅하면 관리가 수월합니다.


9) 트러블슈팅

  • 80 포트 충돌: 호스트에서 다른 데몬이 점유(ss -lntup | grep :80). 기존 서비스 포트 변경 또는 compose의 포트를 8080:80으로 매핑
  • 파일 권한 문제: Nginx/PG 볼륨의 소유권/권한 확인(chown, chmod)
  • 헬스체크 실패: docker inspect --format='{{json .State.Health}}' <컨테이너> | jq로 상세 원인 확인
  • 이미지 업데이트: docker compose pull && docker compose up -d

10) 배포 전/후 체크리스트

  • Docker/Compose 버전 확인 & 서비스 자동 시작
  • compose.yaml볼륨 영속성·헬스체크·재시작 정책 반영
  • 외부 노출 포트 최소화(80/443만), 내부 통신은 네트워크 격리
  • 백업 크론 동작 확인, 복원 리허설 1회
  • 로그/리소스 모니터링 확보(예: Promtail+Loki, node-exporter 등)

여기까지면 Nginx+PostgreSQL 구성의 컨테이너 기반 운영이 가능합니다. 다음 단계로는 백엔드 앱 컨테이너를 추가하고, HTTPS관찰성 스택(Prometheus/Grafana)을 붙여 운영 품질을 높이세요.