로컬에서 멀티 서비스 환경을 구축하고, 이를 통해 반복 가능한(repeatable) IaaC 환경을 만드는 것이 목표다.
사용자 → Nginx(로드밸런서) → Tomcat(Java 앱) → MySQL(DB)
↕ ↕
RabbitMQ Memcache(캐시)
| 서비스 | 역할 | VM |
|---|---|---|
| Nginx | 로드밸런서 | web01 (Ubuntu) |
| Tomcat | Java 애플리케이션 서버 | app01 (CentOS) |
| RabbitMQ | 메시지 브로커 (더미) | rmq01 (CentOS) |
| Memcache | DB 캐싱 서버 | mc01 (CentOS) |
| MySQL(MariaDB) | 데이터베이스 | db01 (CentOS) |
서비스 시작 순서는 의존받는 쪽부터: MySQL → Memcache → RabbitMQ → Tomcat → Nginx
vagrant plugin install vagrant-hostmanager
이 플러그인은 모든 VM의 /etc/hosts에 hostname과 IP 매핑을 자동으로 등록한다. 덕분에 VM 간에 IP 대신 hostname으로 통신할 수 있다.
Vagrant.configure("2") do |config|
config.hostmanager.enabled = true
config.hostmanager.manage_host = true
config.vm.define "db01" do |db01|
db01.vm.box = "bandit145/centos_stream9_arm"
db01.vm.hostname = "db01"
db01.vm.network "private_network", ip: "192.168.56.25"
end
config.vm.define "mc01" do |mc01|
mc01.vm.box = "bandit145/centos_stream9_arm"
mc01.vm.hostname = "mc01"
mc01.vm.network "private_network", ip: "192.168.56.24"
end
config.vm.define "rmq01" do |rmq01|
rmq01.vm.box = "bandit145/centos_stream9_arm"
rmq01.vm.hostname = "rmq01"
rmq01.vm.network "private_network", ip: "192.168.56.23"
end
config.vm.define "app01" do |app01|
app01.vm.box = "bandit145/centos_stream9_arm"
app01.vm.hostname = "app01"
app01.vm.network "private_network", ip: "192.168.56.22"
app01.vm.provider "vmware_desktop" do |vb|
vb.memory = "1024"
end
end
config.vm.define "web01" do |web01|
web01.vm.box = "spox/ubuntu-arm"
web01.vm.hostname = "web01"
web01.vm.network "private_network", ip: "192.168.56.21"
end
end
vagrant ssh db01
sudo -i
dnf update -y
dnf install git mariadb-server -y
dnf install epel-release -y
systemctl start mariadb
systemctl enable mariadb
패키지 이름은
mariadb-server이지만 systemd 서비스 이름은mariadb다.
mysql_secure_installation
# root 비밀번호 설정 (자신의 비밀번호를 설정해야 한다)
mysql -u root -pyourpassword
create database accounts;
grant all privileges on accounts.* TO 'admin'@'localhost' identified by 'yourpassword';
grant all privileges on accounts.* TO 'admin'@'%' identified by 'yourpassword';
FLUSH PRIVILEGES;
exit
yourpassword부분을 자신의 비밀번호로 변경해야 한다. 이후 애플리케이션 설정(application.properties)에서도 동일한 비밀번호를 사용해야 한다.
cd /tmp/
git clone -b local https://github.com/hkhcoder/vprofile-project.git
cd vprofile-project
mysql -u root -pyourpassword accounts < src/main/resources/db_backup.sql
systemctl start firewalld
systemctl enable firewalld
firewall-cmd --get-active-zones
firewall-cmd --zone=public --add-port=3306/tcp --permanent
firewall-cmd --reload
systemctl restart mariadb
vagrant ssh mc01
sudo -i
dnf update -y
dnf install memcached -y
systemctl start memcached
systemctl enable memcached
sed -i 's/127.0.0.1/0.0.0.0/g' /etc/sysconfig/memcached
systemctl restart memcached
Memcache는 기본적으로 127.0.0.1(자기 자신)에서만 접속을 허용한다. 0.0.0.0으로 변경하면 다른 VM에서도 접속할 수 있다. app01(Tomcat)에서 mc01으로 접속해야 하기 때문에 필요한 설정이다.
sudo memcached -p 11211 -U 11111 -u memcached -d
| 옵션 | 의미 |
|---|---|
-p 11211 | TCP 포트 11211에서 대기 |
-U 11111 | UDP 포트 11111에서 대기 |
-u memcached | memcached 사용자 권한으로 실행 |
-d | 백그라운드(데몬)로 실행 |
vagrant ssh rmq01
sudo -i
dnf update -y
dnf install epel-release -y
dnf install wget -y
dnf install centos-release-rabbitmq-38 -y
dnf --enablerepo=centos-rabbitmq-38 -y install rabbitmq-server
systemctl start rabbitmq-server
systemctl enable rabbitmq-server
centos-release-rabbitmq-38은 RabbitMQ 패키지가 있는 저장소(repository) 정보를 추가하는 것이고, 그 다음 --enablerepo로 해당 저장소를 활성화해서 실제 패키지를 설치한다. CentOS 기본 저장소에는 RabbitMQ가 없기 때문에 두 단계가 필요하다.
sudo sh -c 'echo "[{rabbit, [{loopback_users, []}]}]." > /etc/rabbitmq/rabbitmq.config'
systemctl restart rabbitmq-server
sudo rabbitmqctl add_user test test
sudo rabbitmqctl set_permissions -p / test ".*" ".*" ".*"
sudo systemctl restart rabbitmq-server
test 사용자를 비밀번호 test로 생성한다.".*"는 각각 configure(설정), write(쓰기), read(읽기) 권한이고, ".*"는 모든 리소스를 의미한다.vagrant ssh app01
sudo -i
dnf install epel-release -y
dnf install java-17-openjdk java-17-openjdk-devel -y
dnf install git wget -y
cd /tmp/
wget https://archive.apache.org/dist/tomcat/tomcat-10/v10.1.28/bin/apache-tomcat-10.1.28.tar.gz
tar xzvf apache-tomcat-10.1.28.tar.gz
useradd --home-dir /usr/local/tomcat --shell /sbin/nologin tomcat
cp -r /tmp/apache-tomcat-10.1.28/* /usr/local/tomcat/
chown -R tomcat.tomcat /usr/local/tomcat
vi /etc/systemd/system/tomcat.service
[Unit]
Description=Tomcat
After=network.target
[Service]
Type=forking
User=tomcat
Group=tomcat
WorkingDirectory=/usr/local/tomcat
Environment=JAVA_HOME=/usr/lib/jvm/jre
Environment=CATALINA_PID=/var/tomcat/%i/run/tomcat.pid
Environment=CATALINA_HOME=/usr/local/tomcat
Environment=CATALINA_BASE=/usr/local/tomcat
ExecStart=/usr/local/tomcat/bin/catalina.sh run
ExecStop=/usr/local/tomcat/bin/shutdown.sh
RestartSec=10
Restart=always
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl start tomcat
systemctl enable tomcat
cd /tmp/
wget https://archive.apache.org/dist/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.zip
unzip apache-maven-3.9.9-bin.zip
cp -r apache-maven-3.9.9 /usr/local/maven3.9
export MAVEN_OPTS="-Xmx512m"
Maven은 Java 프로젝트의 빌드 도구다. 소스코드 컴파일, 의존성 다운로드, 배포 파일(WAR) 생성을 자동화한다.
git clone -b local https://github.com/hkhcoder/vprofile-project.git
cd vprofile-project
# application.properties에 백엔드 서버 정보 업데이트
vim src/main/resources/application.properties
# 빌드
/usr/local/maven3.9/bin/mvn install
rm -rf /usr/local/tomcat/webapps/ROOT
cp target/vprofile-v2.war /usr/local/tomcat/webapps/ROOT.war
chown -R tomcat.tomcat /usr/local/tomcat/webapps/ROOT.war
systemctl restart tomcat
webapps/ROOT는 Tomcat의 기본 웹 애플리케이션 경로다. http://서버IP:8080/으로 접속하면 ROOT에 있는 앱이 응답한다.systemctl start firewalld
systemctl enable firewalld
firewall-cmd --zone=public --add-port=8080/tcp --permanent
firewall-cmd --reload
vagrant ssh web01
sudo -i
apt update
apt upgrade -y
apt install nginx -y
vi /etc/nginx/sites-available/vproapp
upstream vproapp {
server app01:8080;
}
server {
listen 80;
location / {
proxy_pass http://vproapp;
}
}
Nginx가 80번 포트로 들어오는 요청을 Tomcat(app01:8080)으로 전달하는 리버스 프록시 설정이다. upstream은 요청을 전달할 백엔드 서버를 정의하는 블록이다.
rm -rf /etc/nginx/sites-enabled/default
ln -s /etc/nginx/sites-available/vproapp /etc/nginx/sites-enabled/vproapp
systemctl restart nginx
sites-available/: 설정 파일을 보관하는 곳sites-enabled/: 여기에 있는 설정만 실제로 활성화됨ln -s: 심볼릭 링크(바로가기)를 생성. 비활성화하려면 링크만 삭제하면 되고 원본 파일은 그대로 남는다.default)를 지우는 이유는 프로젝트 설정과 충돌 방지.위 수동 과정을 각 서비스별 shell script 파일로 생성하고, Vagrantfile에서 provisioning으로 연결하면 vagrant up 한 번으로 전체 환경을 자동 구축할 수 있다.
config.vm.define "web01" do |web01|
web01.vm.provision "shell", path: "nginx.sh"
end
config.vm.define "app01" do |app01|
app01.vm.provision "shell", path: "tomcat.sh"
end
# db01, mc01, rmq01도 동일하게 각각의 sh 파일 연결
shell script 안에서 설정 파일을 생성할 때는 vi 대신 Heredoc(cat > 파일 <<EOT ... EOT)을 사용한다. 자동화 스크립트에서는 대화형 편집기를 쓸 수 없기 때문이다.
이 자동화를 통해 기존에 수동으로 처리했던 내용을 개선했다:
자동화된(Automated) Local setup 환경을 코드 기반의(IaaC) 반복적으로(Repeatable) 구축할 수 있는 환경을 마련
Q. Nginx가 로드밸런서에 적합한 이유는?
이벤트 기반(event-driven) 아키텍처로, 적은 리소스로 수만 개의 동시 연결을 처리할 수 있다. Apache는 요청당 프로세스/스레드를 생성하는 방식이라 동시 연결이 많아지면 메모리 사용량이 급증한다. 그래서 Nginx는 앞단에서 트래픽을 분산하는 역할에 적합하고, Apache는 뒤에서 애플리케이션을 실행하는 역할에 적합하다.
Q. NFS 서버란?
Network File System. 네트워크를 통해 여러 서버가 하나의 스토리지를 공유할 수 있게 해주는 파일 시스템이다. 예를 들어 웹 서버가 3대인데 업로드된 이미지를 모든 서버에서 접근해야 할 때, 각 서버에 파일을 복사하는 대신 NFS로 중앙 스토리지를 공유한다.
Q. 서버 클러스터란?
같은 역할을 하는 서버들의 그룹이다. 웹 서버 3대를 묶어서 운영하면 "웹 서버 클러스터"라고 부른다.
Q. 서비스 시작 순서가 중요한 이유는?
의존성 때문이다. Tomcat(앱)이 시작할 때 MySQL(DB)과 Memcache(캐시)에 연결을 시도한다. DB가 아직 안 떠있으면 연결 실패로 앱이 에러가 난다. 그래서 의존받는 쪽(DB)부터 의존하는 쪽(Web)으로 순서대로 올린다.
Q. dnf update는 매번 실행해야 하는가?
새 VM을 처음 세팅할 때는 실행하는 것이 좋다. box 이미지가 만들어진 시점의 패키지 상태이므로 보안 패치가 누락되어 있을 수 있다. CentOS/RHEL 계열은 메이저 버전을 올리지 않고 보안 패치와 버그 수정만 적용하므로 호환성 문제가 거의 없다.
Q. epel-release 패키지는 무엇인가?
Extra Packages for Enterprise Linux. CentOS/RHEL 기본 저장소에 없는 추가 패키지를 설치할 수 있게 해주는 확장 저장소다.
Q. centos-release-rabbitmq-38을 설치한 뒤 다시 rabbitmq-server를 설치하는 이유는?
centos-release-rabbitmq-38은 RabbitMQ 패키지가 있는 저장소(repository) 정보를 추가하는 것이다. 앱스토어에 새로운 마켓을 등록한 것과 같다. 이후 --enablerepo로 해당 저장소를 활성화해서 실제 패키지를 다운로드한다.
Q. Memcache IP를 0.0.0.0으로 설정하면 모든 곳에서 접속 허용인가?
이 서버의 모든 네트워크 인터페이스에서 접속을 허용한다는 의미다. 실습 환경에서는 편의상 열지만, 실무에서는 특정 IP만 허용하거나 방화벽으로 접근을 제한한다.
Q. Maven은 어떤 역할인가?
Java 프로젝트의 빌드 도구다. 소스코드 컴파일, 의존성(라이브러리) 다운로드, 최종 배포 파일(WAR/JAR) 생성을 자동화한다.
Q. webapps/ROOT를 왜 지우는가?
webapps/ROOT는 Tomcat의 기본 웹 애플리케이션 경로다. 기존 Tomcat 기본페이지를 지우고 프로젝트 WAR를 ROOT.war로 배포하면, Tomcat이 자동으로 압축을 풀어 ROOT 폴더를 생성한다.
Q. WAR 파일은 수정할 일이 거의 없는가?
맞다. WAR 파일은 빌드의 결과물이다. 수정이 필요하면 소스코드를 수정하고 다시 mvn install로 빌드해서 새 WAR를 만든다.
Q. web01은 왜 Ubuntu인가?
강의에서 의도적으로 CentOS와 Ubuntu를 섞어서 실습하는 것이다. 실무에서도 팀마다 다른 OS를 쓸 수 있으므로 양쪽 다 다뤄보는 것이 목적이다.
Q. apt update와 upgrade의 차이는?
update는 패키지 목록을 최신으로 갱신하는 것(어떤 패키지가 있는지 정보만), upgrade는 설치된 패키지를 실제로 최신 버전으로 업그레이드하는 것이다. CentOS의 dnf update는 이 두 과정을 한 번에 처리한다.
Q. sites-available은 Nginx 공식 폴더인가?
Nginx 공식 구조가 아니라 Ubuntu/Debian 계열의 패키지가 사용하는 관례적 구조다. vproapp이라는 이름도 자유롭게 지은 것이다.
Q. upstream이란?
"위쪽 흐름", 즉 요청을 전달할 백엔드 서버를 정의하는 블록이다. 서버를 여러 개 나열하면 로드밸런싱이 된다.
Q. ln -s로 만드는 링크는 무엇인가?
심볼릭 링크(바로가기)다. Nginx는 sites-enabled/ 폴더에 있는 설정만 활성화한다. sites-available/에 원본을 두고, 활성화할 것만 링크를 걸어서 관리한다. 비활성화하려면 링크만 삭제하면 된다.
Q. shell script에서 EOT란?
End Of Text의 약자로, Heredoc 문법의 종료 표시다. 자동화 스크립트에서 vi 대신 cat > 파일 <<EOT ... EOT로 파일 내용을 직접 작성할 때 사용한다.