초보자도 쉽게 따라하는 Linux Tomcat WAR 배포 튜토리얼
초보자도 쉽게 따라하는 Linux Tomcat WAR 배포 튜토리얼 리눅스 서버에 Apache Tomcat을 설치하고 WAR 파일을 배포하는 전체 과정을 단계별로 설명합니다. 이 튜토리얼은 Ubuntu 22.04와 CentOS 8 환경에서 Java 17과 Tomcat 10.1을 기준으로 작성되었으며, 실제 동작하는 코드 예제와 트러블슈팅 팁을 포함합니다. 초보 개발자도 쉽게 따라할 수 있도록 구성되었습니다. 1. 튜토리얼 개요 Apache Tomcat은 자바 기반의 웹 애플리케이션을 호스팅하기 위한 오픈소스 서블릿 컨테이너입니다. 이 가이드에서는 Tomcat 10.1 버전을 사용하여 WAR 파일을 배포하는 방법을 다룹니다. 지원 OS는 Ubuntu 22.04와 CentOS 8이며, 두 배포판 모두에서 테스트를 완료했습니다. 전체 프로세스는 다음과 같은 단계로 구성됩니다: ...
Docker Compose로 멀티 컨테이너 환경 구축하기: 단계별 튜토리얼
Docker Compose로 멀티 컨테이너 환경 구축하기: 단계별 튜토리얼 주제 키워드: Docker Compose, 멀티 컨테이너, YAML 구성, 의존성 관리, CI/CD 통합 현대 애플리케이션 개발에서 멀티 컨테이너 아키텍처는 마이크로서비스, 데이터 처리 파이프라인, 개발/운영 환경 통합에 필수적인 요소입니다. Docker Compose는 단일 YAML 파일로 여러 컨테이너의 생명주기, 네트워크, 볼륨, 환경 변수를 관리하는 도구로, 개발부터 프로덕션까지 효율성을 극대화합니다. 이 가이드에서는 DB-웹 애플리케이션 예제부터 고급 설정, 트러블슈팅까지 실제 동작 가능한 예제로 설명합니다. 1. Docker Compose의 핵심 개념과 장점 1.1 멀티 컨테이너 아키텍처의 필요성 단일 컨테이너로 모든 기능을 구현하면 관심사 분리가 어렵고, 확장성이 제한됩니다. 예를 들어, 웹 서버와 데이터베이스를 하나의 컨테이너에 묶으면: ...
Linux 성능 튜닝 트러블슈팅: top, iostat, vmstat로 문제 해결
Linux 성능 튜닝 트러블슈팅: top, iostat, vmstat로 문제 해결 Linux 서버 성능 병목 현상을 해결하는 것은 시스템 관리자와 DevOps 엔지니어의 핵심 역량입니다. top, iostat, vmstat과 같은 기본 제공 도구를 활용하면 CPU, 메모리, 디스크 I/O, 페이징 등 다양한 지표에서 발생하는 문제를 정확히 진단할 수 있습니다. 이 가이드에서는 각 도구의 기본 사용법부터 실제 트러블슈팅 사례까지 단계별로 설명합니다. 1. Linux 성능 모니터링 도구 기본 사용법 1.1 top: 실시간 CPU/메모리 모니터링 top은 Linux 시스템의 실시간 상태를 확인하는 가장 기본적인 도구입니다. CPU 사용률, 메모리 사용량, 실행 중인 프로세스 목록 등을 1초 단위로 업데이트하여 보여줍니다. ...
SpringBoot + GitHub Actions CI/CD 완벽 구성 & 문제 해결
SpringBoot + GitHub Actions CI/CD 완벽 구성 & 문제 해결 SpringBoot 애플리케이션에 GitHub Actions를 활용한 CI/CD 파이프라인을 구축하고, 실제 운영 환경에서 발생하는 문제를 해결하는 방법을 단계별로 설명합니다. 이 가이드는 JDK 설치부터 클라우드 배포까지 전체 워크플로우를 다루며, 실패 사례별 트러블슈팅 기법을 포함합니다. 튜토리얼: SpringBoot CI/CD 기본 구성 1. GitHub 리포지토리 연결 및 기본 Workflow 생성 SpringBoot 프로젝트를 GitHub에 업로드합니다. git init git add . git commit -m "Initial commit" git branch -M main git remote add origin https://github.com/<your-id>/<repo-name>.git git push -u origin main .github/workflows/springboot-ci-cd.yml 파일을 생성합니다. 2. 기본 Workflow YAML 구성 name: SpringBoot CI/CD on: push: branches: [ "main" ] pull_request: branches: [ "main" ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up JDK 17 uses: actions/setup-java@v4 with: java-version: '17' distribution: 'temurin' - name: Build with Gradle run: ./gradlew build - name: Build Docker image run: | docker build -t my-springboot-app:latest . docker tag my-springboot-app:latest \ $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/my-springboot-app:latest - name: Push to ECR run: | aws ecr get-login-password --region $AWS_REGION | \ docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/my-springboot-app:latest env: AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }} AWS_REGION: ${{ secrets.AWS_REGION }} 팁: Maven 사용 시 ./mvnw clean package로 변경합니다. Dockerfile이 프로젝트 루트에 위치해야 합니다. ...
CodePipeline 실패 해결법: CI/CD 파이프라인 문제 분석부터 복구까지
AWS CodePipeline 실패 해결법: CI/CD 파이프라인 문제 분석부터 복구까지 AWS CodePipeline은 서버리스 CI/CD 서비스로, 코드 변경부터 배포까지 자동화된 워크플로우를 제공합니다. 하지만 복잡한 인프라 환경에서 권한 오류, 아티팩트 누락, 빌드 스크립트 실패 등 다양한 문제가 발생할 수 있습니다. 이 가이드에서는 CodePipeline의 기본 구성부터 모니터링, 트러블슈팅, 예방 조치까지 단계별로 설명합니다. 실제 동작하는 코드 예제와 AWS 공식 문서를 참고해 문제를 체계적으로 해결하는 방법을 제시합니다. 1. 튜토리얼: CodePipeline 기본 구성 및 모니터링 1.1 CodePipeline 구조 이해 CodePipeline은 Source → Build → Deploy 3단계로 구성됩니다. 각 단계는 독립적인 액션으로 관리되며, 실패 시 롤백이 가능합니다. 예를 들어, GitHub에서 코드를 가져온 후 CodeBuild로 빌드하고, CodeDeploy로 EC2에 배포하는 파이프라인을 구성할 수 있습니다. ...
SSH PortProxy로 안전하게 원격 서비스 접근하기
튜토리얼 개요 SSH PortProxy는 방화벽 제약이 있는 환경에서도 안전하게 원격 서비스에 접근할 수 있는 강력한 기술입니다. 기존 SSH 터널링과 유사하지만, 로컬 포트 포워딩을 더욱 직관적으로 구성할 수 있으며, 별도의 터널링 소프트웨어 없이도 작동합니다. 예를 들어 개발 서버가 외부 접속을 차단하고 있더라도, SSH 게이트웨이 서버를 경유하여 로컬 머신에서 localhost:8080으로 접근하면 원격 서버의 웹 서비스에 연결할 수 있습니다. 이는 데이터베이스 접근이나 내부 관리 콘솔 접속 시 특히 유용합니다. ...
Chrome DevTools로 잡는 JavaScript 메모리 누수
개요 JavaScript 메모리 누수는 웹 애플리케이션의 성능을 저하시키는 주요 원인 중 하나입니다. 특히 SPA(Single Page Application)에서 페이지 전환 시 메모리 사용량이 지속적으로 증가하거나, DOM 요소를 제거했음에도 불구하고 참조가 유지되는 문제가 빈번히 발생합니다. 이 가이드에서는 Chrome DevTools를 활용해 메모리 누수를 진단하고 해결하는 체계적인 방법을 단계별로 설명합니다. 실제 사례를 바탕으로 한 코드 예제와 검증 방법을 포함해, 개발자들이 즉시 적용할 수 있는 실용적인 솔루션을 제공합니다. 문제 상황: 메모리 누수의 대표적 증상 1. 페이지 전환 시 메모리 사용량 지속 증가 SPA에서 라우터가 페이지 전환을 처리할 때, 이전 페이지의 리소스가 제대로 해제되지 않으면 메모리 사용량이 선형적으로 증가합니다. 예를 들어 React 애플리케이션에서 useEffect 정리 함수를 누락하거나, Vue에서 beforeUnmount 생명주기에서 이벤트 리스너를 제거하지 않는 경우 발생합니다. ...
사내 VM IP 관리 시스템 만들기 - React 대시보드 + Docker Compose 배포 (4편)
React 대시보드 대시보드는 탭 2개로 구성된다. VM 목록 — 전체 VM 현황, 상태별 필터, ONLINE/OFFLINE/UNKNOWN 배지 이벤트 로그 — IP 충돌, IP 변경, 오프라인 이벤트 타임라인 WebSocket이 아닌 30초 폴링으로 구현했다. VM 상태가 초 단위로 바뀌지 않고, 운영 대시보드 특성상 약간의 지연은 허용된다. 심플하게 가는 게 낫다고 판단했다. 30초 폴링 훅 // usePolling.js import { useEffect, useRef } from 'react'; export function usePolling(callback, intervalMs = 30_000) { const callbackRef = useRef(callback); useEffect(() => { callbackRef.current = callback; }); useEffect(() => { callbackRef.current(); // 마운트 시 즉시 1회 실행 const id = setInterval(() => callbackRef.current(), intervalMs); return () => clearInterval(id); }, [intervalMs]); } // App.jsx const [vms, setVms] = useState([]); const [loading, setLoading] = useState(true); usePolling(async () => { const data = await fetch('/api/vms').then(r => r.json()); setVms(data); setLoading(false); }, 30_000); callbackRef를 쓰는 이유는 setInterval 클로저가 최초 등록 시점의 callback을 계속 참조하는 문제를 피하기 위해서다. useRef로 항상 최신 콜백을 가리키도록 한다. ...
사내 VM IP 관리 시스템 만들기 - Spring Boot Heartbeat 처리 + 이상 감지 + Slack 알림 (3편)
heartbeat 처리 흐름 에이전트가 30초마다 POST /api/heartbeat를 호출한다. 서버는 MAC 주소를 기준으로 VM을 식별하고 상태를 갱신한다. heartbeat 수신 │ ▼ MAC 주소로 VM 조회 │ ├─ DB에 없음 → 신규 등록 └─ DB에 있음 → 상태 갱신 (hostname, last_seen_at) │ ▼ 이상 감지 실행 │ ├─ IP 변경 감지 ├─ IP 충돌 감지 └─ IP 대역 이탈 감지 HeartbeatService @Service @RequiredArgsConstructor @Transactional public class HeartbeatService { private final VmRepository vmRepo; private final AnomalyDetectorService anomalyDetector; public void process(HeartbeatRequest req) { Vm vm = vmRepo.findByMacAddress(req.getMacAddress()) .orElseGet(() -> vmRepo.save(Vm.create( req.getMacAddress(), req.getHostname(), req.getAgentVersion() ))); vm.heartbeat(req.getHostname(), req.getAgentVersion()); anomalyDetector.detectAndUpdate(vm, req.getNetworkInterfaces()); } } Vm.create()는 신규 VM을 UNKNOWN 상태로 생성한다. vm.heartbeat()는 lastSeenAt을 현재 시각으로 갱신하고 상태를 ONLINE으로 바꾼다. ...
사내 VM IP 관리 시스템 만들기 - Node.js 에이전트 → Go 에이전트 전환 (2편)
처음엔 Node.js로 만들었다 에이전트를 처음 만들 때 익숙한 Node.js를 썼다. 로직 자체는 단순하다. 30초마다 POST /api/heartbeat 호출 호스트명, MAC 주소, IP 주소를 payload에 담아 전송 const axios = require('axios'); const os = require('os'); const SERVER_URL = process.env.IPAM_SERVER_URL; const INTERVAL_MS = 30_000; function getNics() { const interfaces = os.networkInterfaces(); const result = []; for (const [name, addrs] of Object.entries(interfaces)) { for (const addr of addrs) { if (addr.family === 'IPv4' && !addr.internal) { result.push({ interfaceName: name, macAddress: addr.mac, ipAddress: addr.address, }); } } } return result; } async function sendHeartbeat() { try { await axios.post(`${SERVER_URL}/api/heartbeat`, { hostname: os.hostname(), networkInterfaces: getNics(), }); } catch (e) { console.error('[heartbeat] 실패:', e.message); } } sendHeartbeat(); setInterval(sendHeartbeat, INTERVAL_MS); 동작은 잘 했다. 문제는 배포였다. ...