프로젝트

[프로젝트] 네이버 클라우드로 인프라 구축하기 (VPC, 서브넷, 로드밸런서)

투웨이코더 2026. 2. 5. 02:27

Spring Boot 애플리케이션을 개발하고 나면 이제 실제 사용자가 접속할 수 있는 프로덕션 환경을 구축해야 합니다.

저는 Naver Cloud Platform을 선택했고 Docker와 GitHub Actions를 활용해 자동 배포 파이프라인까지 구성했습니다.

이 글에서는 제가 겪은 시행착오와 해결 과정을 공유하려고 합니다.

 

1. 왜 Naver Cloud Platform을 선택했나?

AWS나 GCP도 좋지만 한국 서비스를 위해서는 Naver Cloud Platform이 몇 가지 장점이 있었습니다.

우선 국내 리전이라 레이턴시가 낮고 한글 문서가 잘 되어 있어서 트러블슈팅이 수월했습니다.

무엇보다 학생 크레딧이나 스타트업 지원 프로그램을 활용하면 비용 부담도 적습니다.

 

2. 인프라 아키텍처 설계

프로덕션 환경을 구축하면서 가장 먼저 고민한 것은 네트워크 구조였습니다.

MVP 단계에서는 빠른 구축과 비용 효율성을 위해 Public Subnet 기반으로 시작했지만

향후 보안 강화를 위한 확장 계획과 함께 개선해 나갔습니다.

 

2.1. VPC 구성 

이전까지는 Public Subnet 단일 구성으로 운영하고 있습니다.

애플리케이션 서버와 데이터베이스를 모두 Public Subnet에 배치하고 ACL과 방화벽 규칙으로 보안을 관리하는 방식입니다.

MVP 단계에서는 관리 포인트를 줄이고 빠르게 서비스를 런칭하는 게 우선이었기 때문에 이 구조를 선택했습니다.

 

 

하지만  SSL 인증서와 같이 요구사항이 높아지면 Private Subnet 분리를 시도했습니다.

 

Load Balancer를 Public Subnet에 두고 SSL 인증서를 여기서 처리합니다.

사용자의 HTTPS 요청은 Load Balancer에서 복호화되고 내부 네트워크에서는 HTTP로 애플리케이션 서버와 통신합니다.

애플리케이션 서버와 데이터베이스는 Private Subnet으로 옮겨서 외부에서 직접 접근할 수 없게 만들었습니다.

이렇게 하니 보안은 확실히 강화됐지만 NAT Gateway 비용이 추가로 발생하고 네트워크 구성이 복잡해졌습니다.

하지만 사용자 데이터를 다루는 서비스인 만큼 이 정도 투자는 필요하다고 판단했습니다.

 

2.2. Docker Compose로 컨테이너화

애플리케이션을 배포하는 방법은 여러 가지가 있지만

저는 Docker를 선택했습니다. "내 컴퓨터에서는 되는데..."라는 문제를 피하고 싶었고

나중에 Kubernetes로 전환하기도 쉬울 것 같았습니다.

 

2.3. 서버 폴더 구조

서버 구조

 

현재 서버의 폴더 구조는 /app/moyeorak를 서비스 단위의 루트로 두고

그 하위에 backend, database, docker-compose.yml을 배치한 형태로 구성되어 있습니다.

 

이 구조는 단일 서버, 단일 서비스 환경에서 빠른 배포와 명확한 역할 분리를 목표로 설계했습니다. 

 

애플리케이션 소스는 backend에 집중시키고 데이터베이스와 관련된 초기 스크립트나 볼륨 관리는 database 디렉토리로 분리함으로써 코드와 데이터의 책임을 명확히 나누었습니다.

또한 docker-compose.yml을 서비스 루트에 배치해 서버에 접속했을 때 한 번의 docker-compose up으로 전체 구성을 파악하고 기동할 수 있도록 했습니다. 다만 이 구조는 서비스 규모가 커지고 개발, 운영 환경 분리나 추가 인프라가 필요해질 경우 한계가 명확해질 수 있기 때문에 향후에는 apps, infra, compose와 같은 디렉토리로 역할을 세분화하고 환경별 docker-compose 파일을 분리하는 방향으로 개선할 계획입니다. 

 

초기에는 단순함과 가독성을 우선한 구조로 빠르게 서비스를 운영하고 이후 확장 단계에서 자연스럽게 구조를 진화시키는 것을 목표로 하고 있습니다.

 

3. GitHub Actions로 CI/CD 파이프라인 구축

코드를 수정할 때마다 서버에 SSH 접속해서 수동으로 배포하는 건 비효율적입니다.

GitHub에 코드를 푸시하면 자동으로 빌드하고 배포되도록 CI/CD 파이프라인을 만들었습니다.

 

관련 코드는 아래 링크에서 확인 가능합니다.

https://github.com/dnd-side-project/dnd-14th-8-backend/tree/dev/.github/workflows

 

dnd-14th-8-backend/.github/workflows at dev · dnd-side-project/dnd-14th-8-backend

[모여락] 모임 일정 및 장소 조율 통합 서비스. Contribute to dnd-side-project/dnd-14th-8-backend development by creating an account on GitHub.

github.com

 

3.1. Naver Cloud Container Registry 설정

우선 Docker 이미지를 저장할 곳이 필요합니다.

Naver Cloud의 Container Registry를 생성하고 GitHub Actions에서 접근할 수 있도록 Access Key를 발급받았습니다.

 

3.2. 워크플로우

name: Deploy to Naver Cloud

on:
  push:
    branches:
      - main  # main 브랜치에 push될 때 실행

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
    # 1. 코드 체크아웃
    - name: Checkout code
      uses: actions/checkout@v4

    # 2. JDK 25 설치
    - name: Set up JDK 25
      uses: actions/setup-java@v4
      with:
        java-version: '25'
        distribution: 'temurin'

    # 3. Gradle 빌드 (실행 권한 부여)
    - name: Grant execute permission for gradlew
      run: chmod +x gradlew

    # 4. Spring Boot 애플리케이션 빌드
    - name: Build with Gradle
      run: ./gradlew clean build -x test

    # 5. Docker 이미지 빌드
    - name: Build Docker image
      run: |
        docker build -t ${{ secrets.NCP_REGISTRY_URL }}/moyeorak-backend:latest \
          -t ${{ secrets.NCP_REGISTRY_URL }}/moyeorak-backend:${{ github.sha }} .

    # 6. Naver Cloud Container Registry 로그인
    - name: Login to NCP Container Registry
      run: |
        echo ${{ secrets.NCP_REGISTRY_PASSWORD }} | docker login ${{ secrets.NCP_REGISTRY_URL }} \
          -u ${{ secrets.NCP_REGISTRY_USERNAME }} --password-stdin

    # 7. Docker 이미지 Push
    - name: Push Docker image
      run: |
        docker push ${{ secrets.NCP_REGISTRY_URL }}/moyeorak-backend:latest
        docker push ${{ secrets.NCP_REGISTRY_URL }}/moyeorak-backend:${{ github.sha }}

    # 8. 서버에 SSH 접속하여 배포
    - name: Deploy to server
      uses: appleboy/ssh-action@v1.0.0
      with:
        host: ${{ secrets.NCP_SERVER_HOST }}
        username: ${{ secrets.NCP_SERVER_USERNAME }}
        password: ${{ secrets.NCP_SERVER_PASSWORD }}
        script: |
          # moyeorak 디렉토리로 이동
          cd /app/moyeorak

          # Container Registry 로그인
          echo ${{ secrets.NCP_REGISTRY_PASSWORD }} | docker login ${{ secrets.NCP_REGISTRY_URL }} \
            -u ${{ secrets.NCP_REGISTRY_USERNAME }} --password-stdin

          # 최신 이미지 Pull
          docker pull ${{ secrets.NCP_REGISTRY_URL }}/moyeorak-backend:latest

          # 기존 backend 컨테이너 중지 및 제거
          docker-compose down backend

          # 새 backend 컨테이너 시작
          docker-compose up -d backend

          # 사용하지 않는 이미지 정리
          docker image prune -f

          # 배포 완료 확인
          echo "Deployment completed!"
          docker ps | grep moyeorak-backend

 

3.3. GitHub Secrets 관리

워크플로우에서 사용하는 민감한 정보들은 모두 GitHub Secrets에 저장했습니다.

이렇게 하면 코드에는 실제 값이 노출되지 않고 팀원들과 안전하게 협업할 수 있습니다.

 

4. 마치며

처음 인프라를 구축할 때는 막막했지만 하나씩 배우고 적용하면서 안정적인 프로덕션 환경을 만들 수 있었습니다.

Public Subnet으로 시작해서 점진적으로 보안을 강화하고 Docker와 GitHub Actions로 자동화를 구축했습니다.

 

중요한 건 처음부터 완벽할 필요는 없다는 것입니다.

MVP는 빠르게 만들고 실제 사용자 피드백을 받으면서 개선하는 게 맞습니다.

다만 보안이나 자동화처럼 나중에 바꾸기 어려운 부분은 처음부터 신경 쓰는 게 좋습니다.

 

인프라는 한 번 만들고 끝이 아니라 서비스 규모에 맞춰 계속 개선해 나가는 과정입니다. 지금은 Docker Compose로 충분하지만

언젠가는 Kubernetes로 전환하고 Private Subnet으로 분리하고 모니터링을 강화할 날이 올 것입니다.
그때를 대비해서 확장 가능한 구조로 설계한 게 의미가 있을 것 같습니다.

 

4.1. 쿠버네티스로 고도화한다면?