[IaC] Vagrant로 3-Tier 아키텍처 자동 구성하기

Vagrant를 사용하여 3-Tier 아키텍처(Web-WAS-DB)를 코드로 정의하고 자동으로 프로비저닝하는 Vagrantfile 전체 코드와 상세 설명


🎯 개요

이 문서는 Vagrant를 사용하여 다음 구성을 자동으로 생성하는 코드를 제공합니다:

  • Web Server: Nginx (리버스 프록시)
  • WAS Server: Tomcat 9 (Java 애플리케이션 서버)
  • DB Server: MariaDB (데이터베이스)

관련 실습 포스트: vagrant-3tier-practice


📂 프로젝트 구조

vagrant-3tier/
├── Vagrantfile       # VM 정의 및 프로비저닝 스크립트
└── README.md         # 사용 방법

📋 전체 Vagrantfile

# -*- mode: ruby -*-
# vi: set ft=ruby :
# Version: 1.1
# Description: 3-Tier Architecture (Web-WAS-DB) with Vagrant
# IP Range: 10.0.0.x
 
# 순차 실행 보장 (병렬 실행 방지)
ENV['VAGRANT_NO_PARALLEL'] = 'yes'
 
Vagrant.configure("2") do |config|
  # 공통 설정: OS 이미지 (Ubuntu 22.04 LTS)
  config.vm.box = "ubuntu/jammy64"
  config.vm.box_check_update = false
  
  # ==========================================
  # 1. DB Server (Tier 3) - 가장 먼저 생성
  # ==========================================
  config.vm.define "db" do |db|
    db.vm.hostname = "db-server"
    db.vm.network "private_network", ip: "10.0.0.30"
    
    db.vm.provider "virtualbox" do |vb|
      vb.memory = "1024"
      vb.cpus = 1
      vb.name = "3tier-db"
    end
    
    # DB 설치 및 설정 스크립트
    db.vm.provision "shell", inline: <<-SHELL
      echo "=========================================="
      echo ">>> Starting DB Server Provisioning"
      echo "=========================================="
      
      # 패키지 업데이트
      apt-get update
      
      # MariaDB 설치
      DEBIAN_FRONTEND=noninteractive apt-get install -y mariadb-server
      
      # 방화벽 비활성화 (개발 환경)
      ufw disable
      
      # 외부 접속 허용 (Bind Address 수정)
      sed -i 's/127.0.0.1/0.0.0.0/' /etc/mysql/mariadb.conf.d/50-server.cnf
      
      # MariaDB 재시작
      systemctl restart mariadb
      systemctl enable mariadb
      
      # DB 및 사용자 생성 (WAS에서 접속 가능하도록)
      mysql -e "CREATE DATABASE IF NOT EXISTS mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
      mysql -e "CREATE USER IF NOT EXISTS 'appuser'@'%' IDENTIFIED BY 'password';"
      mysql -e "GRANT ALL PRIVILEGES ON mydb.* TO 'appuser'@'%';"
      mysql -e "FLUSH PRIVILEGES;"
      
      # 샘플 테이블 생성 (테스트용)
      mysql mydb -e "CREATE TABLE IF NOT EXISTS test_table (id INT AUTO_INCREMENT PRIMARY KEY, message VARCHAR(255));"
      mysql mydb -e "INSERT INTO test_table (message) VALUES ('Hello from DB Server!');"
      
      # 연결 테스트 정보 출력
      echo "=========================================="
      echo ">>> DB Server Setup Complete"
      echo "  - IP: 10.0.0.30"
      echo "  - Port: 3306"
      echo "  - Database: mydb"
      echo "  - User: appuser / password"
      echo "=========================================="
      
      # MariaDB 상태 확인
      systemctl status mariadb --no-pager
    SHELL
  end
 
  # ==========================================
  # 2. WAS Server (Tier 2)
  # ==========================================
  config.vm.define "was" do |was|
    was.vm.hostname = "was-server"
    was.vm.network "private_network", ip: "10.0.0.20"
    
    was.vm.provider "virtualbox" do |vb|
      vb.memory = "1024"
      vb.cpus = 1
      vb.name = "3tier-was"
    end
    
    # Tomcat 설치 스크립트
    was.vm.provision "shell", inline: <<-SHELL
      echo "=========================================="
      echo ">>> Starting WAS Server Provisioning"
      echo "=========================================="
      
      apt-get update
      
      # Java 11 & Tomcat 9 설치
      apt-get install -y openjdk-11-jdk tomcat9
      
      # MySQL 클라이언트 설치 (DB 연결 테스트용)
      apt-get install -y mysql-client
      
      # 방화벽 비활성화
      ufw disable
      
      # Tomcat 시작
      systemctl enable tomcat9
      systemctl start tomcat9
      
      # DB 연결 대기 (최대 30초)
      echo ">>> Waiting for DB Server..."
      for i in {1..30}; do
        if mysql -h 10.0.0.30 -u appuser -ppassword -e "SELECT 1" &>/dev/null; then
          echo ">>> DB Connection Successful!"
          break
        fi
        echo "  Retry $i/30..."
        sleep 1
      done
      
      # DB 테스트
      mysql -h 10.0.0.30 -u appuser -ppassword mydb -e "SELECT * FROM test_table;"
      
      echo "=========================================="
      echo ">>> WAS Server Setup Complete"
      echo "  - IP: 10.0.0.20"
      echo "  - Port: 8080"
      echo "  - Tomcat: http://10.0.0.20:8080"
      echo "=========================================="
      
      systemctl status tomcat9 --no-pager
    SHELL
  end
 
  # ==========================================
  # 3. Web Server (Tier 1)
  # ==========================================
  config.vm.define "web" do |web|
    web.vm.hostname = "web-server"
    web.vm.network "private_network", ip: "10.0.0.10"
    
    # 호스트에서 접근 가능하도록 포트 포워딩
    web.vm.network "forwarded_port", guest: 80, host: 8080
    
    web.vm.provider "virtualbox" do |vb|
      vb.memory = "1024"
      vb.cpus = 1
      vb.name = "3tier-web"
    end
    
    # Nginx 설치 및 리버스 프록시 설정
    web.vm.provision "shell", inline: <<-SHELL
      echo "=========================================="
      echo ">>> Starting Web Server Provisioning"
      echo "=========================================="
      
      apt-get update
      apt-get install -y nginx curl
      
      # 방화벽 비활성화
      ufw disable
      
      # Nginx 설정: 80번 요청을 WAS(10.0.0.20:8080)로 프록시
      cat <<EOF > /etc/nginx/sites-available/default
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    
    server_name _;
    
    location / {
        proxy_pass http://10.0.0.20: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;
    }
    
    # Health check endpoint
    location /health {
        access_log off;
        return 200 "OK\\n";
        add_header Content-Type text/plain;
    }
}
EOF
      
      # Nginx 재시작
      systemctl restart nginx
      systemctl enable nginx
      
      # WAS 연결 대기 (최대 30초)
      echo ">>> Waiting for WAS Server..."
      for i in {1..30}; do
        if curl -s http://10.0.0.20:8080 &>/dev/null; then
          echo ">>> WAS Connection Successful!"
          break
        fi
        echo "  Retry $i/30..."
        sleep 1
      done
      
      # 최종 연결 테스트
      curl -s http://10.0.0.20:8080 > /dev/null && echo ">>> Nginx → WAS: OK"
      
      echo "=========================================="
      echo ">>> Web Server Setup Complete"
      echo "  - IP: 10.0.0.10"
      echo "  - Port: 80 (forwarded to host:8080)"
      echo "  - Access: http://localhost:8080"
      echo "=========================================="
      echo ""
      echo "🎉 3-Tier Architecture Setup Complete!"
      echo ""
      echo "Access Path: Browser → Nginx (Web) → Tomcat (WAS) → MariaDB (DB)"
      echo "Test URL: http://localhost:8080"
      echo ""
      
      systemctl status nginx --no-pager
    SHELL
  end
end

📖 코드 상세 설명

1. 헤더 및 환경 설정

# -*- mode: ruby -*-
# vi: set ft=ruby :
  • Vagrantfile은 Ruby 문법 사용
  • 에디터에게 Ruby 파일임을 알려주는 힌트
ENV['VAGRANT_NO_PARALLEL'] = 'yes'
  • 순차 실행 보장: DB → WAS → Web 순서대로 생성
  • 병렬 실행 시 WAS가 DB보다 먼저 뜨면 연결 실패 가능

2. 공통 설정

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/jammy64"
  config.vm.box_check_update = false
설정설명
Vagrant.configure("2")Vagrant API 버전 2 사용
config.vm.box베이스 이미지 (Ubuntu 22.04 LTS)
config.vm.box_check_updateBox 업데이트 자동 확인 비활성화

3. VM 정의 구조

config.vm.define "vm_name" do |vm|
  # 호스트명
  vm.vm.hostname = "server-name"
  
  # 네트워크 (Private Network, 고정 IP)
  vm.vm.network "private_network", ip: "10.0.0.xx"
  
  # 포트 포워딩 (선택사항)
  vm.vm.network "forwarded_port", guest: 80, host: 8080
  
  # VirtualBox 설정
  vm.vm.provider "virtualbox" do |vb|
    vb.memory = "1024"  # RAM (MB)
    vb.cpus = 1         # CPU 코어 수
    vb.name = "vm-name" # VirtualBox GUI 이름
  end
  
  # 프로비저닝 스크립트
  vm.vm.provision "shell", inline: <<-SHELL
    # Shell 명령어들...
  SHELL
end

4. 네트워크 구성

Private Network

vm.vm.network "private_network", ip: "10.0.0.30"
  • VirtualBox의 Host-Only 네트워크
  • VM 간 통신 가능
  • 호스트 PC에서도 접근 가능

Port Forwarding

web.vm.network "forwarded_port", guest: 80, host: 8080
  • 게스트(VM)의 80번 포트를 호스트의 8080번으로 포워딩
  • 호스트에서 http://localhost:8080으로 접근 가능

5. 프로비저닝 스크립트

Shell Script Inline 방식

vm.vm.provision "shell", inline: <<-SHELL
  apt-get update
  apt-get install -y nginx
SHELL

주요 프로비저닝 작업

DB Server:

  • MariaDB 설치
  • 외부 접속 허용 (bind-address = 0.0.0.0)
  • DB 및 사용자 생성
  • 샘플 데이터 삽입

WAS Server:

  • Java 11, Tomcat 9 설치
  • MySQL 클라이언트 설치 (테스트용)
  • DB 연결 대기 로직 (최대 30초)

Web Server:

  • Nginx 설치
  • 리버스 프록시 설정 (80 → 8080)
  • WAS 연결 대기 로직

🚀 사용 방법

1. 프로젝트 생성

mkdir vagrant-3tier
cd vagrant-3tier
 
# Vagrantfile 생성 (위 코드 복사)

2. VM 생성

# 모든 VM 생성 및 프로비저닝 (5-10분 소요)
vagrant up
 
# 특정 VM만 생성
vagrant up db
vagrant up was
vagrant up web

3. 상태 확인

# VM 상태 확인
vagrant status
 
# 출력:
# db        running (virtualbox)
# was       running (virtualbox)
# web       running (virtualbox)

4. VM 접속

# SSH 접속
vagrant ssh db
vagrant ssh was
vagrant ssh web
 
# 종료
exit

5. VM 제어

# 일시 중지
vagrant halt
 
# 재시작
vagrant up
 
# 완전 삭제
vagrant destroy -f
 
# 특정 VM만 삭제
vagrant destroy db -f

6. 재프로비저닝

# VM은 유지하고 프로비저닝 스크립트만 재실행
vagrant provision
 
# 특정 VM만
vagrant provision was

🧪 테스트 방법

1. 웹 브라우저 접근

http://localhost:8080

→ Tomcat 기본 페이지 표시

2. curl 테스트

# 호스트에서
curl http://localhost:8080
 
# Web VM에서
vagrant ssh web
curl http://10.0.0.20:8080
 
# Health check
curl http://localhost:8080/health

3. DB 연결 확인

vagrant ssh was
 
# DB 연결 테스트
mysql -h 10.0.0.30 -u appuser -ppassword mydb
 
# 테이블 확인
SELECT * FROM test_table;
 
# 출력:
# +----+-----------------------+
# | id | message               |
# +----+-----------------------+
# |  1 | Hello from DB Server! |
# +----+-----------------------+

🔧 커스터마이징

IP 변경

# 10.0.0.x 대신 192.168.56.x 사용
db.vm.network "private_network", ip: "192.168.56.30"
was.vm.network "private_network", ip: "192.168.56.20"
web.vm.network "private_network", ip: "192.168.56.10"

리소스 조정

vb.memory = "2048"  # 2GB RAM
vb.cpus = 2         # 2 CPU

다른 DB 사용 (PostgreSQL 예시)

db.vm.provision "shell", inline: <<-SHELL
  apt-get update
  apt-get install -y postgresql postgresql-contrib
  
  # PostgreSQL 외부 접속 허용
  echo "listen_addresses = '*'" >> /etc/postgresql/14/main/postgresql.conf
  echo "host all all 0.0.0.0/0 md5" >> /etc/postgresql/14/main/pg_hba.conf
  
  systemctl restart postgresql
SHELL

📊 리소스 사양

항목DBWASWebTotal
메모리1GB1GB1GB3GB
CPU1113
디스크~2GB~3GB~2GB~7GB

권장 호스트 사양:

  • RAM: 8GB 이상
  • CPU: 4코어 이상
  • 디스크: 20GB 여유 공간

📚 참고 자료


🔗 관련 포스트


마지막 업데이트: 2025-01-19