middlemoon

AWS Bastion Host의 연결과 Jenkins 파이프라인 설계 - 프로젝트 (2) 본문

DevOps/AWS

AWS Bastion Host의 연결과 Jenkins 파이프라인 설계 - 프로젝트 (2)

중대경 2025. 10. 21. 10:00

 

회사에서의 첫번째 과제를 성공적으로 마치고, 두번째 과제를 할당받아 프로젝트 회고를 하고자 한다.

진행했던 프로젝트의 구조의 도식화는 아래와 같다.

 

 

Point 1
[외부 Jenkins 서버(Domain: 회사도메인.ne.kr)]
          │  SSH (22/tcp)
          ▼
[JenkinsEC2 = Bastion 역할 (Public Subnet, IP: 13.125.211.15)]
          │  SSH (22/tcp, 사설 IP)
          ▼
[WebEC2 (Private Subnet, IP: 192.168.100.170)]


1. WEB EC2 app.jar, app.log 삭제 -> rm -rf app.jar / rm -rf app.log
2. ps -ef | grep app.jar , netstat -lntp 입력 후 포트 종료 확인

2. JenKins 들어가 빌드 실행 
3. 
. Java -jar로 실행 후 localhost:8080/api/health




Point 2
🌍 브라우저
    ↓ HTTP (80)
[Bastion EC2:13.125.211.15]
    Nginx proxy_pass
    ↓
[Web EC2:192.168.100.170:8080]
    Spring Boot → "Health Check 성공"

 

 

 

 

 

 

 

회사에서 사용하고 있는 Jenkins 서버는 AWS VPC를 아예 벗어난 곳이다.

Jenkins 서버에서 파이프라인으로 GitLab에 있는 소스를 가져와 Bastion EC2 부터 Web EC2 까지 불러들여온 소스를 가져와

Ping 체크에 성공하면 되는 프로젝트이다. 

 

물론 온프렘으로 진행하였을 때 3-Tier Stacture로 진행하게 되면 Jenkins의 서버에 접속하여 Nginx Proxy 경유를 진행하여도 진행은 되지만 거의 모든 서버에 Migration 을 진행하여 AWS를 반드시 경유해야한다.

 

 

 

pipeline {
  agent any

  parameters {
    string(name: 'KEY_FILE_NAME', defaultValue: 'mun-test-ec2.pem')
    string(name: 'BASTION_HOST', defaultValue: '13.125.211.15')
    string(name: 'WEB_HOST', defaultValue: '192.168.100.170')
    string(name: 'JAR_PATH', defaultValue: './target/kong-0.0.1-SNAPSHOT.jar')
    text(name: 'PEM_KEY_VALUE', defaultValue: '', description: 'Paste PEM content here (multi-line OK)')
  }

  environment {
    APP_NAME = "kong"
    WORK_DIR = "${WORKSPACE}/tmp_pem"
  }

  stages {

    stage('Create PEM') {
      steps {
        sh '''
          set -e
          mkdir -p "$WORK_DIR"
          PEM_PATH="$WORK_DIR/${KEY_FILE_NAME:-pem_key.pem}"

          echo "=== Restoring PEM from parameter ==="
          printf "%b" "$PEM_KEY_VALUE" > "$PEM_PATH"
          chmod 600 "$PEM_PATH"

          echo "[INFO] PEM created at $PEM_PATH"
          ls -l "$WORK_DIR"
        '''
      }
    }

    stage('Checkout & Build') {
      steps {
        git branch: 'master',
            credentialsId: 'gitlab-token',
            url: 'https://gitlab.bizbee.ne.kr/sb/mwsun0303/test-api.git'

        sh '''
          chmod +x ./mvnw || true
          ./mvnw clean package -DskipTests
        '''
      }
    }

    stage('SCP: Office → Bastion') {
      steps {
        sh '''
          echo "=== SFTP Office → Bastion ==="
          scp -i "$WORK_DIR/$KEY_FILE_NAME" -o StrictHostKeyChecking=no \
            "$JAR_PATH" ec2-user@"$BASTION_HOST":/home/ec2-user/app.jar
        '''
      }
    }

    stage('SCP: Bastion → Web EC2') {
      steps {
        sh '''
          echo "=== SFTP Bastion → Web EC2 ==="

          # Jenkins → Bastion 연결
          ssh -i "$WORK_DIR/$KEY_FILE_NAME" -o StrictHostKeyChecking=no ec2-user@"$BASTION_HOST" '
            echo "=== Copying app.jar to Web EC2 ==="

            # Bastion 내부에서 PEM 내용을 직접 복원 (Jenkins의 PEM을 그대로 전달)
            cat > /home/ec2-user/mun-temp.pem <<EOF
'"$PEM_KEY_VALUE"'
EOF
            chmod 600 /home/ec2-user/mun-temp.pem
            
            # Web EC2에 폴더 먼저 생성
            ssh -i /home/ec2-user/mun-temp.pem -o StrictHostKeyChecking=no ec2-user@'"$WEB_HOST"' "mkdir -p /home/ec2-user/app"


            # Bastion → Web EC2 파일 복사
            scp -i /home/ec2-user/mun-temp.pem -o StrictHostKeyChecking=no \
              /home/ec2-user/app.jar ec2-user@'"$WEB_HOST"':/home/ec2-user/app/app.jar

            # Bastion 내 임시 PEM 삭제
            rm -f /home/ec2-user/mun-temp.pem
          '
        '''
      }
    }

    stage('Deploy on Web EC2') {
      steps {
        sh '''
          echo "=== Deploy on Web EC2 ==="
          
          ssh -i "$WORK_DIR/$KEY_FILE_NAME" -o StrictHostKeyChecking=no ec2-user@"$BASTION_HOST" '
        cat > /home/ec2-user/mun-temp.pem <<EOF
'"$PEM_KEY_VALUE"'
EOF
          chmod 600 /home/ec2-user/mun-temp.pem
          
          ssh -i /home/ec2-user/mun-temp.pem -o StrictHostKeyChecking=no ec2-user@'"$WEB_HOST"' "
              pkill -f 'java -jar' || true;
              mkdir -p /home/ec2-user/app;
              cd /home/ec2-user/app;
              java -jar app.jar > app.log 2>&1 & 
              pgrep -f app.jar > /dev/null && echo '\''✅ App started'\'' || echo '\''❌ App start failed'\'';
            "
            
            rm -f /home/ec2-user/mun-temp.pem
          '
        '''
      }
    }
  }

  post {
    always {
      sh 'rm -rf "$WORK_DIR" || true'
      echo "🧹 Cleaned up PEM"
    }
    success {
      echo "✅ Build & Deploy complete!"
    }
    failure {
      echo "❌ Build or Deploy failed — check logs."
    }
  }
}

 

 

 

📌 핵심 단계 요약

단계Stage 이름기능 요약
1️⃣ Create PEM Jenkins에서 전달받은 PEM 복원
2️⃣ Checkout & Build GitLab 소스 체크아웃 및 빌드
3️⃣ SCP: Office → Bastion 빌드된 JAR → Bastion 전송
4️⃣ SCP: Bastion → Web EC2 Bastion → Private Web EC2 전송
5️⃣ Deploy on Web EC2 Web EC2에서 JAR 실행 및 Health Check

 

 

다음과 같이 파이프라인을 구성하였다. 

 

Jenkins 빌드를 하게되면 아래와 같이 String_parameter로 받을 수 있도록 구성하였다.

Pem_key는 등록된 Jenkins_Credentals 에 등록된 Key로 가져온다.

 

 

 

 

Jenkins-Credentilas

 

 

 

등록 후 빌드된 파이프라인이 성공하게 된다.

 

 

 

192-168-100-10 (Bastion Private IP -> 192.168.100.170 WEB EC2 Private IP) 로 진입한다.

 

 

빌드를 성공하게 되면 app.jar로 서버가 정상실행되며 프로세스도 정상작동되는것을 확인할 수 있다.

 

 

 

 

 

 

 

curl로 현재 Web EC2 서비스가 제대로 돌고있는지 확인할 수 있으며,

13.125.211.15은 Bastion EC2 공인IP인데 Nginx의 url을 paramter 로 설정하여 특정 도메인으로 호출 시, 성공메세지가 나올 수 있도록 구성하였다. 

 

 

 

 

 

Bastion EC2 의 공인IP에서 Web EC2 애플리케이션 서버가 구성될 수 있었던 이유는 

Bastion 쪽에 Proxy를 경유하여 외부 서버에서도 확인할 수 있도록 구성하였다.

 

보통 실무에서는 보안이나, 기본 특성상 Web EC2에 있는 사설IP를 직접가져와 보는 경우는 희박하므로

공인IP로 한번 더 거쳐 서비스를 실행한다.

 

Proxy서버가 껴있다보니 성능, 보안, 비용 적으로 효율을 볼 수 있다는 점이 가장크다.

 

 

 

마무리하며..

 

무엇보다도 프로젝트를 진행하면서 가장 공부해보고 싶었던 AWS와 Jenkins를 위주로 학습을 하였다. 

 

VPC생성부터, EC2 구성까지 그리고 Jenkins 서버와 연동하여 애플리케이션을 실행해보는 시간까져 가져보았다. 

 

AWS를 배워 이번년도 까지 관련 자격증을 취득하고, CI/CD 툴을 직접적으로 다룰 수 있어 뜻깊은 프로젝트가 아니였나 싶다.

 

가장 많이 할애했던 부분은 파이프라인을 구성하는 부분에서 시간이 많이 걸리긴하였다. 

 

Jenkins에서 서버를 두번이상 Traffic을 타야하니 쉽지많은 않았다. 

 

하지만, Cloud Engineer 라면 꼭 거쳐야 하는 관문이라 생각이 되었다. 

 

앞으로는 AWS의 더욱 다양한 기능을 다루게 될텐데 그 부분이 가장 기대가 된다. 

 

꾸준히 발전하며 더 나은 엔지니가 될 수 있도록 노력해볼것이다 !

 

 

 

Comments