위 환경은 AWS CodeDeploy + Jenkins를 이용한 Spring boot 자동화 + Jenkins CodeDeploy plugin 오류 해결 에서 설정가능하고 이 작업 이후로 이어진다.
# aws ec2 linux nginx 설치(nginx1)
sudo amazon-linux-extras install nginx1 -y
# nginx 설치 확인
nginx -v
nginx version: nginx/1.20.0
# nginx 시작
sudo service nginx start
Redirecting to /bin/systemctl start nginx.service
# 리버스 프록시 설정
# 기본 설정은 유지
sudo vim /etc/nginx/nginx.conf
server {
include /etc/nginx/conf.d/service-url.inc;
location / {
proxy_pass $service_url;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forworded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
}
}
# 리버스 프록시 설정
# 배포할 때 마다 포트 변경
# real1 -> 8081, real2 -> 8082
# 첫 번째 배포 시에 정상적으로 포트가 설정되는지 확인하기 위해 8082로 설정
# /etc/nginx/conf.d/service-url.inc 파일을 아래 내용으로 생성
set $service_url http://127.0.0.1:8082;
# nginx 재시작
# service-url.inc 파일을 미리 만들어두지 않을 경우 에러가 발생함
sudo service nginx restart
Redirecting to /bin/systemctl restart nginx.service
혹시 sudo service nginx restart
를 했을때, 포트번호가 이미 사용중이라는 오류가 발생한다면
sudo fuser -k 80/tcp
sudo fuser -k 443/tcp
를 실행한 후에 재시작 하면 된다.
actuator
는 어플리케이션 상태를 모니터링할 수 있게 해준다.
앤드 포인트로 접근하여 해당 어플리케이션이 어떤 상태인지 알려준다.
이중에서 /health
앤드 포인트를 이용할 계획이다.
management:
endpoint:
endpoints:
web:
base-path: /application
---
spring:
config:
activate:
on-profile: test1
server:
port: 8081
---
spring:
config:
activate:
on-profile: test2
server:
port: 8082
managment
actuator
기능중에 /health
기능 관련 설정이다./health
는 기본적으로 /actuator/health
경로를 통해 상태를 확인할 수 있다./application/health
를 통해 확인 가능하다.profile
profile
이름을 부여함으로써 두개의 포트를 관리한다.test1
, test2
이름으로 만들어졌습니다.이 요청은 test1
또는 test2
profile
이 적용됐을 경우, 적용된 profile
을 알려주는 요청이다.
FROM openjdk:11-jdk
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} testboard.jar
ARG IDLE_PROFILE
ENV ENV_IDLE_PROFILE=$IDLE_PROFILE
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=${ENV_IDLE_PROFILE}", "/testboard.jar"]
FROM
: 도커 이미지는 base
이미지부터 시작하여 층층이 올려가는 layer
구조이다. 이중에 FROM
은 base
의 최상단이라고 생각하면된다.ARG
: docker build
를 하게 될때 옵션으로 --build-arg
등으로 옵션을 넘겨 해당 옵션을 정의하기 위한 용도이다.ENV
: 환경변수 설정이다. ARG
는 빌드되는 동안에만 사용한다면, - - ENV
는 도커 컨테이너 내부에서 계속 사용한다고 생각하면 된다.COPY
: 복사.ENTRYPOINT
: 실행 명령어를 직접 입력하는 것이다.java -jar
: 자바 실행 기본 옵션이다. jar
파일로 자바를 실행-D
: 어플리케이션 내부 properties
를 설정하는 옵션이다.version: 0.0
os: linux
files:
- source: /
destination: /home/ec2-user/testboard
overwrite: yes
permissions:
- object: /
pattern: "**"
owner: ec2-user
group: ec2-user
hooks:
ApplicationStop:
- location: scripts/stop.sh
timeout: 360
runas: ec2-user
ApplicationStart:
- location: scripts/start.sh
timeout: 360
runas: ec2-user
ValidateService:
- location: scripts/health.sh
timeout: 360
runas: ec2-user
appspec.yml
의 자세한 설정은 이전글의 Build 설정 을 참고
ApplicationStop
stop.sh
를 만들어야 한다.ApplicationStart
start.sh
스크립트를 작성해야한다.ValidateService
health.sh
에서 actuator
모니터링을 진행하면 된다.#!/bin/bash
function find_profile()
{
CURRENT_PROFILE=$(curl -s http://localhost/profile)
if [ $CURRENT_PROFILE == test1 ]
then
IDLE_PROFILE=test2
elif [ $CURRENT_PROFILE == test2 ]
then
IDLE_PROFILE=test1
else
IDLE_PROFILE=test1
fi
echo "${IDLE_PROFILE}"
}
function find_port()
{
IDLE_PROFILE=$(find_profile)
if [ $IDLE_PROFILE == test1 ]
then
IDLE_PORT=8081
elif [ $IDLE_PROFILE == test2 ]
then
IDLE_PORT=8082
fi
echo "${IDLE_PORT}"
}
function find_switch_port()
{
CONTAINER_ID=$(sudo docker ps -f "ancestor=test2" -q)
if [ -z $CONTAINER_ID ]
then
echo "8081"
else
find_port
fi
}
find_profile
: /profile
접근을 통해 어떤 profile
이 실행중인지 확인한 후에 값에 따라 ${IDLE_PROFILE}
를 정한다.test1
이면 test2
test2
이면 test1
test1
find_port
: ${IDLE_PROFILE}
값으로 포트번호를 ${IDLE_PORT}
로 지정한다.test1
이면 8081
test2
이면 8082
find_switch_port
: 실행중인 컨테이너를 통해 바꿔줄 포트 확인-f
: filter
이다. ancestor=test2
조건에 맞는 컨테이너를 찾는것이다.ancestor
: 공유받은 컨테이너 이미지이다.-q
: 컨테이너ID만 출력한다.8081
find_port
값#!/bin/bash
ABSPATH=$(readlink -f $0)
ABSDIR=$(dirname $ABSPATH)
source ${ABSDIR}/profile.sh
function switch_nginx_proxy()
{
IDLE_PORT=$(find_switch_port)
echo "> 실행 포트 : $IDLE_PORT" >> /home/ec2-user/deploy.log
echo "> /etc/nginx/conf.d/service-url.inc 변경" >> /home/ec2-user/deploy.log
echo "set \$service_url http://127.0.0.1:${IDLE_PORT};" | sudo tee /etc/nginx/conf.d/service-url.inc
echo "> nginx 재시작" >> /home/ec2-user/deploy.log
sudo service nginx restart
}
포트 번호 설정을 바꾸는 메서드가 들어있다.
service-url.inc
에 $service_url
값이 들어있고, 이 정의는 nginx
에서 활용한다.
80
-> $service_url
로 넘겨주는 작업을 nginx
가 해준다.
그러므로, $service_url
만 바꾸면,
80
포트로 접근했을때, nginx
가 바뀐 url
로 넘겨준다.
#!/bin/bash
echo "> stop 시작" >> /home/ec2-user/deploy.log
ABSPATH=$(readlink -f $0)
ABSDIR=$(dirname $ABSPATH)
source ${ABSDIR}/profile.sh
IDLE_PROFILE=$(find_profile)
echo "> 실행할 profile : $IDLE_PROFILE " >> /home/ec2-user/deploy.log
CONTAINER_ID=$(sudo docker ps -f "ancestor=${IDLE_PROFILE}" -q)
if [ -z $CONTAINER_ID ]
then
echo "> 기존에 실행되고 있던 컨테이너가 없습니다. " >> /home/ec2-user/deploy.log
else
echo "> 기존에 실행되고 있던 컨테이너 : $CONTAINER_ID" >> /home/ec2-user/deploy.log
sudo docker stop $CONTAINER_ID
sudo docker rm $CONTAINER_ID
echo "> 컨네이너 종료 완료, $CONTAINER_ID" >> /home/ec2-user/deploy.log
sudo docker image rm $IDLE_PROFILE
echo "> 기존 이미지 삭제 완료, $IDLE_PROFILE" >> /home/ec2-user/deploy.log
sleep 10
fi
readlink -f
: symbolic link
원본의 절대 경로를 출력한다.$> readlink -f ./abc.sh
/Users/abc.sh
dirname
: 경로에서 디렉토리 이름까지만 가져온다.$> dirname /User/abc.sh
/User
source
: 쉘 스크립터 실행. 이 스크립터를 통해 메서드를 읽어온다.IDLE_PROFILE
: profile.sh
내부 메서드를 통해 profile
값을 얻어온다. 이때 얻어온 profile
값은 새롭게 실행할 profile
이다.CONTAINER_ID
위 작업은 새로 만들 포트번호가 있는 컨테이너를 확인하고 삭제하는 단계이다.
쉽게말해 test1
이 이전 profile
이고, test2
를 새로 빌드할 예정이라면, 현재 test2
컨테이너를 삭제하는 것이다.
deploy.log - stop.sh
첫 시작
두번째 시작
echo "> start 시작" >> /home/ec2-user/deploy.log
ABSPATH=$(readlink -f $0)
ABSDIR=$(dirname $ABSPATH)
source ${ABSDIR}/profile.sh
IDLE_PROFILE=$(find_profile)
IDLE_PORT=$(find_port)
echo "> 도커 이미지 파일을 생성합니다." >> /home/ec2-user/deploy.log
sudo docker build --build-arg IDLE_PROFILE=${IDLE_PROFILE} -f /home/ec2-user/testboard/Dockerfile -t ${IDLE_PROFILE} /home/ec2-user/testboard >> /home/ec2-user/deploy.log 2>/home/ec2-user/deploy_err.log
sleep 30
echo "> 도커 컨테이너를 실행합니다." >> /home/ec2-user/deploy.log
sudo docker run -p ${IDLE_PORT}:${IDLE_PORT} ${IDLE_PROFILE} >> /home/ec2-user/spring.log 2>/home/ec2-user/deploy_err.log &
sleep 10
ABSPATH
, ABSDIR
, source
, IDLE_PROFILE
, IDLE_PROT
: 이전과 동일하다.docker build
IDLE_PROFILE
: DockerFile
에서 환경변수로 지정된 변수이다.-f
: 도커 파일을 직접 사용하므로 이 옵션을 통해 도커파일 경로를 사용-t
: tag
이다. 말 그대로 태그 이름 설정이다.CodeDeploy
설정으로 /home/ec-user/testboard
에 파일을 복사하므로 이곳에서 build
를 진행한다.deploy.log
에 담는다.deploy_err.log
에 담는다.deploy.log - start.sh
첫 시작
두번째 시작
#!/bin/bash
ABSPATH=$(readlink -f $0)
ABSDIR=$(dirname $ABSPATH)
source ${ABSDIR}/profile.sh
source ${ABSDIR}/switch.sh
IDLE_PORT=$(find_switch_port)
echo "> 새롭게 실행한 애플리케이션 health 확인 " >> /home/ec2-user/deploy.log
echo "> 실행 포트 : $IDLE_PORT" >> /home/ec2-user/deploy.log
for CNT in {1..10}
do
echo "> health 확인용 반복문 시작... $CNT 회" >> /home/ec2-user/deploy.log
UP=$(curl -s http://127.0.0.1:${IDLE_PORT}/application/health | grep 'UP')
if [ -z "${UP}" ]
then
echo "> 아직 애플리케이션이 시작되지 않았습니다." >> /home/ec2-user/deploy.log
else
echo "> 애플리케이션이 정상적으로 실행되었습니다." >> /home/ec2-user/deploy.log
switch_nginx_proxy
break ;
fi
sleep 10
done
if [ $(CNT) -eq 10 ]
then
echo "> 애플리케이션 실행에 실패했습니다." >> /home/ec2-user/deploy.log
exit 1
fi
/health
를 요청했을때 해당 서버가 동작하고 있다면 {"status" : "UP"}
로 날라온다. 이를 이용해 값 유무에 따라 어플리케이션 동작 유무를 결정하는 것이다.
정상 작동이 확인되면, nginx
환경변수 값을 바꾸고 재시작해준다.
deploy.log - health.sh
에러가 났을때
정상 작동을 할때