위 환경은 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
managmentactuator 기능중에 /health 기능 관련 설정이다./health는 기본적으로 /actuator/health 경로를 통해 상태를 확인할 수 있다./application/health를 통해 확인 가능하다.profileprofile 이름을 부여함으로써 두개의 포트를 관리한다.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 설정 을 참고
ApplicationStopstop.sh를 만들어야 한다.ApplicationStartstart.sh 스크립트를 작성해야한다.ValidateServicehealth.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 이면 test2test2 이면 test1test1find_port : ${IDLE_PROFILE} 값으로 포트번호를 ${IDLE_PORT}로 지정한다.test1이면 8081test2이면 8082find_switch_port : 실행중인 컨테이너를 통해 바꿔줄 포트 확인-f : filter 이다. ancestor=test2 조건에 맞는 컨테이너를 찾는것이다.ancestor : 공유받은 컨테이너 이미지이다.-q : 컨테이너ID만 출력한다.8081find_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.shdirname : 경로에서 디렉토리 이름까지만 가져온다.$> dirname /User/abc.sh/Usersource : 쉘 스크립터 실행. 이 스크립터를 통해 메서드를 읽어온다.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 buildIDLE_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
에러가 났을때

정상 작동을 할때
