반응형

이번에 시작한 프로젝트에서 Jenkins를 사용해서 CI/CD 파이프라인을 구성하고 있습니다.

develop 브랜치에서 작업을 하고, push를 하면 Jenkins Pipeline이 동작하면서 자동화 배포 작업이 진행됩니다.

 

우리 프로젝트에서는 다음과 같은 Pipeline이 동작해서 배포를 진행합니다.

  1. Git Clone
    • Github Repository의 develop 브랜치에 변화가 발생되면 Jenkins 동작이 시작됩니다.
    • develop 브랜치를 Jenkins 서버로 clone 해서 가져옵니다.
  2. DEV-Build
    • 이 과정에서 프로젝트의 Build와 Test를 진행합니다.
  3. Deploy
    • Jenkins 서버에서 Develop 서버로 SSH 통신을 통해 배포 스크립트를 실행합니다.
    • 이 글에서는 이 "Deploy" 과정에서 스크립트 실행 후 발생한 "ERROR: script returned exit code 255"에 대해서 다룰 예정입니다.

 

1. 기존 스크립트


기존 스크립트는 다음과 같습니다.

#!/bin/bash
source ~/.bashrc

REPOSITORY=/home/praise-push
echo "### check running application... ###"
CURRENT_PID=$(pgrep -f praise-push)
echo "### current pid = $CURRENT_PID"

if [[ -z ${CURRENT_PID} ]]; then
    echo "### Not found running application ###"
else
    echo "### Found application!! try to kill process $CURRENT_PID ###"
    kill -15 $CURRENT_PID
    sleep 3
fi
echo "### Ready to deploy ###"

JAR_NAME=$(ls $REPOSITORY | grep 'praise-push' | tail -n 1)

echo "### Source file Name: $JAR_NAME"
chmod +x $REPOSITORY/$JAR_NAME
nohup /usr/bin/java -jar $REPOSITORY/$JAR_NAME >> $REPOSITORY/nohup.out 2>&1 &
echo "success"

 

[ 실행 중인 프로세스가 있는지 확인 ]

간단하게 설명하면 현재 실행 중인 java application의 PID를 찾아서 CURRENT_PID에 저장합니다.

현재 실행중인 프로세스가 있다면 kill 명령어를 통해 중지시키고, 없다면 그냥 넘어가도록 합니다.

 

[ 새로운 프로세스를 실행합니다. ]

Jenkins 서버에서 Build, Test 과정이 끝난 jar 파일을 Develop 서버로 복사해서 가져오게 됩니다.

이 jar 파일을 nohup을 이용해서 서버를 실행합니다.

 

Jenkins에서 Deploy Pipeline은 다음과 같습니다.

stage('Deploy') {
    steps {
        sshagent(credentials: ['dev_server']) {
            sh "ssh -o StrictHostKeyChecking=no -p 9001 root@123.11.11.11 'uptime'"
            sh "scp -P 9001 /var/jenkins_home/workspace/praise-push-dev/build/libs/praise-push-0.0.1-SNAPSHOT.jar root@123.11.11.11:/home/praise-push"
            sh "ssh -t -p 9001 root@123.11.11.11 'cd /home/praise-push && ./deploy.sh'"
        }
    }
}

 

ssh으로 uptime을 요청하여 첫 SSH 연결을 진행합니다.

scp를 이용하여 Jenkins 서버에서 Build, Test 과정을 마치고 생성된 jar 파일을 Develop 서버로 복사합니다.

ssh를 이용하여 원격으로 "/home/praise-push/deploy.sh" 스크립트를 실행하여 배포를 작업을 완료합니다.

 

 

 

2. 문제 분석


먼저 script에서 어떻게 해야 255 exit code가 발생되는지 찾아봤습니다.

 

Remote(원격) 서버에 SSH가 설치되어 있지 않거나, 올바른 Connection이 아닌 경우

 

처음에는 SSH 연결이 잘 안 되고 있구나라고 판단하여 이쪽으로 찾아보기 시작했었습니다.

 

클라이언트(Jenkins)에서 Key Pair를 생성하여 공개키(pub)를 원격서버(Develop)로 보내서 서버의 "authrized_keys"에 클라이언트의 공개키를 저장해야 합니다.

 

SSH 요청 시 클라이언트와 서버 사이의 세션키(대칭키) 생성을 위한 키 교환이 시작되는데, 이때 "authrized_keys"에 있는 이 공개키가 사용됩니다.

 

그래서 저는 SSH 연결이 잘 못 된 것은 아닌지 Jenkins 서버와 Develop 서버를 다시 연결을 해봤습니다.

 

그래도 결과는 달라지지 않았습니다. 다시 한번 확인해 보니 위 스크립트에서 이 부분 이전까지는 스크립트가 실행되는 것을 확인했습니다.

echo "### Ready to deploy ###"

 

이 echo 명령어전까지는 실행이 되었다는 것은 Jenkins -> Develop의 SSH 연결에서 발생한 문제는 아니라는 것을 의미합니다.

 

정상적으로 SSH 연결을 통해 "/home/praise-push/deploy.sh" 명령까지 들어와서 실행을 했지만, 어떤 이유 때문에 중간에 script가 비정상적으로 종료되어 script가 exit 255 code를 리턴했던 것이라는 판단을 하게 되었습니다.

 

즉, 문제는 deploy.sh 스크립트에 있다!

 

deploy.sh를 하나씩 실행하며 디버깅을 해봤습니다.

 

1. 첫 번째 시도

#!/bin/bash
source ~/.bashrc
REPOSITORY=/home/praise-push

 

당연히 문제는 없겠지만, 이틀 넘게 SSH가 원인인 줄 알고 삽질을 해서 아주 꼼꼼하게... 진행해 보기 위해서 스크립트의 시작 부분부터 진행했습니다.

 

결과는 당연히 성공입니다!

 

 

2. 두 번째 시도

#!/bin/bash
source ~/.bashrc
REPOSITORY=/home/praise-push
echo "### check running application... ###"
CURRENT_PID=$(pgrep -f praise-push)
echo "### current pid = $CURRENT_PID"

 

이 부분도 별 다른 특별한 명령어는 없었기 때문에 성공했습니다!

 

 

3. 세 번째 시도

#!/bin/bash
source ~/.bashrc
REPOSITORY=/home/praise-push
echo "### check running application... ###"
CURRENT_PID=$(pgrep -f praise-push)
echo "### current pid = $CURRENT_PID"

if [[ -z ${CURRENT_PID} ]]; then
    echo "### Not found running application ###"
else
    echo "### Found application!! try to kill process $CURRENT_PID ###"
    kill -15 $CURRENT_PID
    sleep 3
fi

 

예상했던대로 세 번째 시도에서 실패했습니다. 그럼 이 if 블록 내부에 문제가 있다는 것을 의미합니다.

문법적인 오류는 아닌 것으로 보였고, 의심이 갔던 부분은 "kill -15 $CURRENT_PID" 부분이었습니다.

 

 

 

4. 네 번째 시도

#!/bin/bash
source ~/.bashrc
REPOSITORY=/home/praise-push
echo "### check running application... ###"
CURRENT_PID=$(pgrep -f praise-push)
echo "### current pid = $CURRENT_PID"

if [[ -z ${CURRENT_PID} ]]; then
    echo "### Not found running application ###"
else
    echo "### Found application!! try to kill process $CURRENT_PID ###"
    sleep 3
fi

 

의심이 들었던 kill 명령어를 제거한 후 다시 시도해봤는데, Deploy Pipeline이 성공했습니다.

역시 원인은 이 부분이었습니다.

 

 

 

3. 원인 분석


kill 명령어로 CURRENT_PID를 종료하고 있었기 때문에 Deploy Pipeline을 실행시켜 두고, Develop 서버에서 계속 "ps -ef | grep praise-push"을 실행하며 콘솔을 확인해 봤습니다.

root@praise-push-dev:/home/praise-push# ps -ef | grep praise-push
root     22623     1  3 19:01 pts/0    00:00:16 /usr/bin/java -jar /home/praise-push/praise-push-0.0.1-SNAPSHOT.jar
root     23741 16549  0 19:09 pts/0    00:00:00 grep --color=auto praise-push
root@praise-push-dev:/home/praise-push# ps -ef | grep praise-push
root     22623     1  3 19:01 pts/0    00:00:16 /usr/bin/java -jar /home/praise-push/praise-push-0.0.1-SNAPSHOT.jar
root     23789 23720  0 19:09 ?        00:00:00 bash -c                              cd /home/praise-push                             ./deploy.sh
root     23794 16549  0 19:09 pts/0    00:00:00 grep --color=auto praise-push

 

이상한 점을 확인했습니다. Deploy Pipeline이 실행되는 중간에 "praise-push"가 포함된 새로운 프로세스가 하나 실행되는 것을 보았습니다.

root     23789 23720  0 19:09 ?        00:00:00 bash -c                              cd /home/praise-push                             ./deploy.sh

 

살펴보니 Deploy Pipeline에서 실행했던 "cd /home/priase-push" 명령어에서 시작되었던 프로세스가 kill의 대상인 "pgrep -f praise-push"에 발견되어 계속 종료되고 있었습니다.

 

찾은 원인은 이렇습니다.

 

  1. Jenkins에서 SSH를 통해 Develop 서버의 cd /home/praise-push/deploy.sh를 실행 (PID 1)
  2. deploy.sh 스크립트에서 현재 실행 중인 praise-push-0.0.1.jar(PID 2)를 찾기 위해서 "pgrep -f praise-push"을 실행
  3. "pgrep -f praise-push"의 결과를 CURRENT_PID 변수에 저장합니다.
    • 여기서 CURRENT_PID에는 의도대로라면 (PID 2)만 있어야 합니다.
    • 하지만, 결과에는 (PID 1)(PID 2)가 들어가게 됩니다.
    • 이유는 "cd /home/praise-push/deploy.sh"에 praise-push가 포함되어 탐색 대상이 되었던 것입니다.
  4. "kill -15 $CURRENT_PID"에서 (PID 1) (PID 2)를 모두 죽이게 됩니다.
  5. 여기서 deploy.sh의 비정상적인 종료가 되고, exit code 255를 리턴하게 됩니다.

 

 

 

4. 해결


"pgrep -f praise-push" 스크립트를 통해 찾으려는 대상은 "praise-push-0.0.1.jar"인 jar 프로세스이기 때문에 아래와 같이 변경했습니다.

CURRENT_PID=$(pgrep -f praise-push-*.jar)

 

이 부분만 이렇게 수정한 후 Jenkins CI/CD Pipeline을 실행시켜 보니 모든 stage가 통과되었고, 정상적으로 배포에 성공했습니다!

 

 

 

생각보다 굉장히 사소한 실수로 시작된 문제인데, 꽤나 오랜 시간 잡고 있었어서 기록해 봤습니다.

 

반응형
반응형

1. 기존 아키텍처와 배포 스크립트 분석


 

프로젝트 진행 과정에서 초반에 간단한 인프라 설계를 위처럼 진행했습니다.

먼저 EC2(Ubuntu) 내부에 Node 16 버전을 포함해서 필요한 것들을 모두 수동으로 설치했습니다.

그 후 deploy.sh라는 스크립트 파일을 만들어 배포 스크립트를 작성했습니다.

이제 Github Actions에서 SSH 연결을 통해 EC2에 접근하여 deploy.sh를 실행하여 자동화 배포가 되도록 설정하여 완료했습니다.

 

기존의 스크립트는 아래와 같이 git 저장소에서 프로젝트 최근 파일을 가져온 후 추가된 npm 라이브러리를 확인하고 설치합니다.

프로젝트를 build 하고, 빌드가 성공하면 현재 실행 중인 프로세스를 확인하고 중지시켜 줍니다.

그 후 백그라운드 실행을 위해서 nohup을 통해서 application을 실행시켜 줬습니다.

# deploy.sh

echo "1. project root로 이동"
cd ~/server/ginger-hotel-server

echo "2. git pull"
git pull origin develop

echo "3. 추가된 라이브러리 설치"
npm install

echo "4. project build"
npm run build

if [ $? -eq 0 ]; then
  # 빌드 성공 시
  echo "5. 실행중인 프로세스 확인"
  CURRENT_PID=$(pgrep -f node)

  echo "6. 실행중인 프로세스 중지"
  sudo kill -15 $CURRENT_PID

  echo "7. 홈 경로 이동 후 프로젝트 재실행"
  nohup npm run start:prod > ~/nohup.out 2> ~/nohup.err < /dev/null &
else
  echo "프로젝트 Build 실패"
  exit 1
fi

 

이 상태로도 자동화 배포환경에는 문제가 없었고, 개발 단계에서 크게 불편한 점은 못 느꼈었습니다.

개발이 거의 마무리될 때쯤 두 가지 의문점이 들었습니다.

서버(EC2)가 증설되었을 때, EC2에 필요한 환경(특정 버전 Node)을 모두 수동으로 설치해줘야 하는 건가? Node 말고, 환경이 추가된다면?

실제 서비스를 운영중일 때, Application이 실행되고 있는 서버(EC2)에서 Git Pull을 하고, Build를 하는 과정이 부하를 주어 서버 성능에 영향을 주지는 않을까?

 

이러한 불편했던 점을 해결하기 위해서 "도커"를 활용하여 필요한 환경까지 함께 이미지로 만들고, Build 환경을 운영 서버와 분리해 보자는 생각을 하게 되었습니다.

 

 

 

2. Ubuntu에 도커 설치하기


1. ubuntu 패키지를 먼저 업데이트합니다.

sudo apt-get update

 

2. Docker 설치에 필요한 패키지를 설치합니다.

sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common -y

 

3. Docker 공식 GPG 키를 추가합니다.

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

 

4. Docker 공식 apt 저장소를 추가합니다.

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

 

5. 시스템 패키지를 다시 업데이트합니다.

sudo apt-get update

 

6. Docker를 설치합니다.

sudo apt-get install docker-ce docker-ce-cli containerd.io -y

 

7. Docker의 실행 상태를 확인합니다.

sudo systemctl status docker

 

8. 도커 허브 로그인을 진행합니다.

sudo docker login
  • Docker Hub에서 가입한 이메일과 비밀번호로 로그인을 진행할 수 있습니다.
  • Docker Hub는 무료로 계정 1개당 1개의 Private 저장소를 사용할 수 있도록 제공해 줍니다.
  • 저는 이전에 Private 저장소를 쓴 적이 없기 때문에 이번 프로젝트에서 Private 저장소를 만들어 사용했습니다.

 

 

 

3. 프로젝트의 Root 경로에 DockerFile 생성


여기서 DockerFile은 도커에 존재하는 이미지를 기반으로 하여 내가 작성한 스크립트 파일을 통해 나만의 이미지를 생성할 수 있는 파일입니다. 즉, 저는 여기에 필요한 Docker 이미지를 골라 담아서 제가 만들고 있는 서버에 필요한 이미지를 생성하는 DockerFile을 생성했습니다.

# Node Base Image
FROM node:16-alpine

# RUN mkdir -p /app
WORKDIR /app

# Current Local . to /app/
ADD . /app/

# install Library
RUN npm install

# Build
RUN npm run build

# PORT
EXPOSE 8080

# Start
ENTRYPOINT npm run start:prod
  • 먼저 저는 Node 16 버전을 Base로 해서 Application을 실행시키고 있기 때문에 Base 이미지를 Node의 16 버전을 사용합니다.
  • RUN, CMD, COPY 등이 실행되는 기본 경로를 WORKDIR로 "/app"으로 설정합니다.
  • ADD 명령어를 통해 현재 프로젝트 경로(.)에 있는 소스파일을 WORKDIR로 설정한 도커의 경로(/app/)로 복사합니다.
  • 이제 순서대로 npm 라이브러리를 설치하고, build를 진행합니다.
  • EXPOSE를 통해서 도커 컨테이너가 실행되었을 때, 요청을 기다리고 있을 Listen 포트를 8080으로 지정합니다.
  • 마지막으로 ENTRYPOINT 명령어를 통해서 컨테이너가 생성되고, 최초로 실행될 때 수행하는 명령어를 설정하고 마무리합니다.

 

 

 

4. EC2 서버에서 실행할 스크립트 파일 생성


기존에 작성했던 배포 스크립트에서는 Git을 통해 EC2로 직접 Pull 하여 코드를 통합하고, Build 하는 과정도 모두 EC2에서 진행했었습니다. 하지만 이제 코드 통합과 Build는 DockerFile에 설정된 대로 Github Actions에서 진행하여 Docker Hub의 Private 저장소로 저장하게 됩니다.

 

즉, 이제 EC2에서는 이 Private Docker Hub 저장소에 있는 이미지를 가져와서 실행만 시켜 Deploy 과정을 마무리하는 스크립트를 실행하면 완료됩니다.

# start-docker.sh

echo "1. Pull Docker Image"
sudo docker pull khsrla9806/ginger-hotel:lastest

echo "2. Stop and Remove Container / Remove <none> Image"
sudo docker stop ginger-hotel
sudo docker rm -f $(sudo docker ps -qa -f status=exited)
sudo docker rmi -f $(sudo docker images -qa --filter "dangling=true")

echo "3. 새로운 이미지 실행"
sudo docker run -d --name ginger-hotel -p 80:8080 -v ./logs:/app/logs khsrla9806/ginger-hotel:lastest
  • Github Actions에서 코드 통합, Build를 거친 새로운 Docker Image를 가져옵니다.
  • 현재 실행되고 있는 컨테이너는 종료하고, 기존의 컨테이너와 이미지는 모두 삭제합니다. (계속 누적되는 것을 방지)
  • 새롭게 가져왔던 이미지를 실행시키고 배포를 완료합니다.

 

 

 

5. Github Actions WorkFlow 설정


이제 DockerFile까지 설정을 완료했기 때문에 Github Actions를 통해서 제가 설정한 DockerFile대로 이미지를 만들어 제 Private Docker Hub 저장소에 이미지를 올리고, SSH로 EC2에 접속하여 새롭게 작성한 start-docker.sh 스크립트 파일을 실행할 수 있도록 Github Actions WorkFlow를 설정해야 합니다.

name: GINGER PRODUCTION SERVER DEPLOY

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout Source Code
        uses: actions/checkout@v3

      - name: Nodejs 16
        uses: actions/setup-node@v3
        with:
          node-version: 16.20.2
          cache: 'npm'

      - name: Setting Production Env
        run: echo "${{ secrets.PRODUCTION_ENV }}" >> .env.prod

      - name: Login Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_PASSWORD }}

      - name: Build and Push Docker Image
        uses: docker/build-push-action@v4.0.0
        with:
          context: .
          file: ./Dockerfile
          push: true
          tags: ${{ secrets.DOCKERHUB_REPO }}/ginger-hotel:lastest

      - name: SSH Remote Command
        uses: appleboy/ssh-action@v0.1.4
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.KEY }}
          port: ${{ secrets.PORT }}
          timeout: 40s

          script: ./start-docker.sh

 

위에서 ${{ secrets.USERNAME }} 이런 부분들은 Github Actions에서 사용할 수 있는 Secret 변수들을 설정해 둘 수 있습니다.

 

 

 

6. 동작 확인


이제 main 브랜치에 Merge가 되는 순간 작성해 둔 WorkFlow대로 Github Actions가 실행됩니다.

 

모든 Flow가 완료되면 자동화 배포 작업이 완료됩니다.

 

이렇게 변경한 후의 아키텍처는 다음과 같습니다.

 

 

지금까지 프로젝트의 CI/CD를 할 때, 처음에 소개했던 것 처럼 EC2 서버에게 너무 많은 책임을 부여했던 것 같아서 늘 도커로 해보자라고 생각을 했었는데 드디어 해볼 수 있게 되어 값진 경험을 가져간 것 같습니다.

 

 

 

반응형
반응형

Client에서 EC2까지 가는 아키텍처 (RDS, S3 등 제외)

 

최근 아키텍처를 설계해야 하는 일이 있어서 위와 같이 Cloud Front를 앞단에 두고, ELB에 요청을 전달해서 EC2로 가는 방향으로 설계를 했습니다.

 

예상했던 결과대로 서버 도메인을 입력하면 API 서버에 접근할 수 있었습니다. 하지만, 원하는 결과와는 조금 다르게 ELB의 DNS 서버로도 아무나 접근이 가능했습니다.

 

누구나 ELB의 DNS를 알면 접근이 가능

 

서버에 접근하는 경로는 단 하나만 있는 게 보안상으로도 좋을 거 같아서 ELB(Origin)에서는 내가 배포한 Cloud Front에서 오는 요청만 받고, 나머지 요청은 모두 403 Forbbiden으로 처리하도록 하고자 했습니다.

 

 

 

1. Cloud Front에 등록된 Origin(ELB)로 보내는 요청에 헤더 추가하기


Cloud Front 콘솔 -> 배포 -> 원본 -> 내 ELB 체크 -> 편집
헤더 추가 -> 헤더 이름, 값 입력 -> 변경 사항 저장

위에서는 헤더 이름을 "X-Custom-Access-Token"이라고 했지만, 본인이 원하는 이름으로 하면 됩니다.

기존에 사용되는 통상적인 헤더 이름은 피해 주시는 것이 좋습니다.

값도 본인이 원하는 값으로 입력합니다. 값을 정하기 어렵다면 여기를 눌러서 한번 Random한 Key 값을 만들어보세요.

모두 입력했으면 이제 변경 사항 저장을 눌러서 저장해 줍니다.

 

 

 

2. ELB(Elastic Load Balancer) 리스너 및 규칙 추가하기


EC2 -> 로드밸런서 -> 내 로드 밸런서 선택 -> HTTP:80 또는 본인이 설정한 규칙 선택 -> 규칙 편집

 

이제 Cloud Front에서 보내는 커스텀 헤더를 받아서 내 Cloud Front에서 온 요청이구나를 알 수 있도록 로드 밸런서(ELB)의 리스너 규칙을 편집해줘야 합니다. 위에 파란 부분은 최종 결과물입니다. 저는 이미 설정을 해뒀었기 때문에 저렇게 뜨니 참고만 해주시면 될 거 같습니다.

 

들어와서 아래로 내린 후 "규칙 추가"를 눌러줍니다.
규칙의 이름을 입력해줍니다. 아무 거나 입력하셔도 됩니다. Ex) "Listener Rule"
"조건 추가"를 클릭해서 조건을 추가해줍니다.
저희는 HTTP 헤더를 이용할 것이기 때문에 HTTP 헤더를 선택해줍니다.
헤더의 이름과 헤더의 값을 입력해줍니다.

 

여기서 입력할 때는 1번에서 Cloud Front 원본(Origin)에 설정했던 헤더의 이름과 값을 입력해줘야 합니다.

이제 확인을 누르고 쭉쭉쭉 넘겨서 대상 그룹(EC2 인스턴스 그룹)을 선택하고, 규칙을 저장합니다.

 

규칙을 저장을 한 후의 화면

 

규칙을 저장하면 이제 내가 만든 규칙이 뜨는 것을 확인할 수 있습니다. 이제 거의 다 왔습니다.

처음 ELB를 만들면 "기본값"으로 규칙이 하나 추가됩니다. 

보면 "다른 규칙이 적용되지 않는 경우"에는 대상 그룹으로 전달된다고 되어 있습니다.

이렇게 되면 내가 정해둔 조건 이외의 어떤 요청이 오더라도 대상 그룹으로 전달되어 처음과 달라지는 것이 없습니다.

그렇기 때문에 기본값의 작업 내용을 바꿔줘야 합니다.

기본값 규칙 체크 -> 규칙 편집 클릭
고정 응답 반환 선택 -> 응답 코드 입력 -> 응답 본문 입력

 

기존에 "대상 그룹으로 전달"로 되어 있는 선택지를 "고정 응답 반환"으로 변경합니다.

응답 코드는 어떤 걸로 입력해도 상관없습니다. 저는 Forbidden으로 사용하기 위해서 403을 입력해 줬습니다.

응답 본문은 선택 내용입니다. 저는 "Access denied"라고 뜰 수 있도록 설정해 뒀습니다.

이제 변경 내용 저장을 눌러줍니다.

 

이제 서버 도메인으로 한번 접근을 해보겠습니다. (Cloud Front을 통해서 접근하는 방법)

200 OK를 응답하면서 접근에 성공했습니다.

 

이 부분도 사실 추후에 Client가 완성되면 Cors에 등록해서 외부 접근은 막아 주는 것이 좋습니다.

 

이제 ELB의 DNS로 접근을 한번 해보겠습니다. (Elastic Load Balancer에 직접 접근하는 방법)

의도했던 대로 403 에러를 발생하며, "Access denied"라는 문구가 출력됩니다.

 

모두 의도한 대로 설정에 성공했습니다!

 

 

 

반응형

+ Recent posts