본 실습은 아래 자료를 바탕으로 진행되었습니다.
https://tomatohj.tistory.com/82
이제 본격적으로 실제 배포를 위한 웹 서버 2대를 구성해야 한다.
Jenkins를 이용하여 Blue/Green 형태의 무중단 배포를 구현할 것이므로 "docker run -it --name [이름] ubuntu" 명령어로 동일한 환경의 컨테이너를 2개 생성할 수 있다. 이후, 'apt update && apt install -y vim net-tools openjdk-17-jdk ssh psmisc'를 수행한다.
📂 무중단 배포
말 그대로 서비스가 중단되지 않은 상태로 새로운 버전을 배포하는 것이다. 서비스가 계속 운영되는 상태에서 새로운 버전의 어플리케이션을 배포하는 과정에서 시스템 가동시간을 최소화하여 사용자에게 생기는 불편함(다운타임)이 없는 방식이다. 이를 위해서는 서버를 2대 이상 확보해야한다.
[출처] 무중단 배포란? 무중단 배포 전략에 대해 알아보자, 무중단 배포 아키텍처와 배포 전략
2개 서버 모두 설치가 끝나면 "service ssh start" 명령어로 ssh server를 동작시킬 수 있다.
▶ Jenkins가 실제로 배포를 수행할 때, scp를 이용하기 때문에 웹서버의 ssh 가동은 필수
이후 Jenkins 컨테이너로 돌아와서 ssh를 위한 public key를 생성해야 한다.
📌 public key 생성 이유
Jenkins가 scp를 이용하여 웹 서버에게 배포를 수행하기 위해서는 ID와 PW를 물어보는 과정이 있어서는 안된다. 따라서 Jenkins 컨테이너의 public key를 각 웹 서버들에 등록해두어, 별도의 추가 인증과정 없이 접근이 가능하도록 설정해주어야 한다.
"su - jenkins" 명령어를 통해 Jenkins를 구동시키는 전용 계정으로 전환할 수 있다. 전환 후, "ssh-keygen" 명령어를 통해 public key를 생성할 것이다. 생성이 완료되었다면 "cat ~/.ssh/id_rsa.pub" 명령어로 생성된 public key의 내용을 확인할 수 있다.
다음으로 웹 서버 역할을 하는 2개의 컨테이너로 돌아와 다음 명령어를 수행하여 Jenkins 컨테이너의 public key를 등록해줄 수 있다.
먼저 "mkdir ~/.ssh && chmod 700 ~/.ssh" 명령어를 통해 .ssh 디렉토리를 생성하고 권한을 부여한다. 이후, 'echo [public key] > ~/.ssh/authorized_keys && chmod 644 ~/.ssh/authorized_keys' 명령어를 통해 authorized_keys라는 파일에 Jenkins 컨테이너의 public key를 등록하고 적절한 권한을 부여할 수 있다.
설정을 모두 마쳤다면, 웹 서버 역할을 하는 2개의 컨테이너에서 "ifconfig eth0" 명령어를 실행시켜 각각의 IP 주소를 확인한다.
다음으로 우리가 의도한 대로 Jenkins 컨테이너에서 웹 서버용 컨테이너로 추가 인증과정 없이 ssh 접근이 잘 되는지 확인해보자.
"ssh root@[웹 서버 IP]" 형태의 명령어를 실행하면 추가 인증과정 없이 원격 접속에 성공하는 것을 확인할 수 있다.
→ 맨 처음 접속 시에는 fingerprint 관련하여 물어보는 부분이 있는데, 해당 부분은 scp를 통한 배포 과정에서 문제를 야기하기 때문에 배포 스크립트에서 처리할 것이다.
▶ blue 서버에 접속한 후 exit 명령어로 로그아웃하고 다시 green 서버로 접속을 시도해 보면 2개의 서버 모두 문제 없이 추가 인증과정 없이 원격접속에 성공하는 것을 볼 수 있다.
여기까지가 Blue/Green 웹서버 구축 방법이었다면 이제는 Blue/Green 서버 중 어떤 웹 서버로 서비스를 제공할지 통신 경로를 제어하는 리버스 프록시 역할의 Ngnix를 구축해야 한다.
새로운 터미널에서 "docker run -it --name nginx -p 80:80 ubuntu" 명령어로 Nginx 용 컨테이너를 생성한다. 이후 "apt update && apt install -y vim ssh nginx" 명령어를 통해 필요한 패키지를 설치한다.
▶ 설치가 완료되었다면, 앞서 웹 서버 구축 과정 중 ssh public key 등록과정을 Nginx 서버에도 동일하게 진행해준다.
📌 Nginx 서버 ssh public key 등록
1. "mkdir ~/.ssh && chmod 700 ~/.ssh" 명령어를 통해 .ssh 디렉토리를 생성하고 권한을 부여
2. 'echo [public key] > ~/.ssh/authorized_keys && chmod 644 ~/.ssh/authorized_keys' 명령어를 통해 authorized_keys라는 파일에 Jenkins 컨테이너의 public key를 등록하고 적절한 권한을 부여
등록 완료 후, Nginx를 리버스 프록시로서의 역할로 사용하기 위해 설정 파일을 수정해주어야 한다. "vi /etc/nginx/sites-available/default" 명령어를 통해 파일을 열어 아래와 같이 수정한다.
- include 구문 : /etc/nginx/sites-available/deploy_server라는 파일을 포함시킨다는 뜻으로, 이 파일 안에는 아래에서 사용될 $deploy_server의 값이 설정될 것이다.
- proxy_pass : Nginx로 들어오는 웹 통신을 $deploy_server에 해당하는 대상에게 전달하는 역할
- proxy_redirect : 웹 애플리케이션에서 redirect 발생 시 리버스 프록시 기능이 정상동작 하지 않을 수 있어, http://localhost로 리다이렉트 되는 경우 $deploy_server로 강제로 리다이렉트 시키는 역할
다음으로 $deploy_server의 값을 설정하기 위해 "vi /etc/nginx/sites-available/deploy_server" 명령어를 통해 파일을 열어 아래와 같이 작성한다.
▶ $deploy_server의 초기값을 webserver-blue에 해당하는 172.17.0.3으로 설정하겠다는 뜻으로, Jenkins에서 배포를 할 때 마다 이 값은 배포한 서버에 맞게 변경될 것이다.
다음으로 "service nginx start"를 통해 nginx를 실행시킨다.
이제 웹 서버 2대(Blue/Green)와 Nginx 리버스 프록시 세팅이 끝났다.
본격적으로 Jenkins를 통해 웹 애플리케이션 빌드(CI), 배포(CD)를 수행해보자.
Jenkins 메인 화면에서 왼쪽 메뉴 중 Jenkin 관리를 클릭하고 System 메뉴를 클릭한다.
System 메뉴에서 아래로 내리다 보면 Global properties 항목 중 Environment variables가 있다. 이는 환경 변수를 설정하는 곳으로, 매번 IP 주소를 치기 번거로우므로 여기에 2개의 웹서버와 Nginx의 IP 환경변수 형태로 저장하여 이용할 수 있다.
총 3개의 환경변수에 대해 아래와 같이 이름과 IP 주소를 입력해준다.
저장 후, 만들어둔 devops 프로젝트로 돌아와 메뉴 부분에 있는 구성 버튼을 클릭한다.
내리다보면 'Build Steps'를 확인할 수 있는데, 이는 빌드를 진행할 때 어떤 행동을 취할지 지정하는 것이다. 지금까지는 이 부분을 설정하지 않아, Github에서 코드를 다운로드만 받고 아무 행위도 취하지 않았었는데, 이 과정을 통해 진짜 빌드를 수행할 수 있다.
📌 Shell Script를 이용하여 2개의 Step으로 나누어 진행
1. 사용할 WebGoat 애플리케이션 빌드
2. 빌드된 WebGoat를 웹 서버로 배포하고, 실행시킨 뒤, Nginx 리버스 프록시 설정을 변경
우선 아래와 같이 Add build step에서 Execute shell을 클릭하여 2개의 Build Step을 생성한다.
첫번째 Step에는 WebGoat를 빌드하기 위한 명령어를 입력
▶ maven 프로젝트인 WebGoat를 빌드하는 명령어 : ./mvnw spotless:apply && ./mvnw clean install -D skipTests
두번째 Step에서는 빌드된 웹 애플리케이션을 웹 서버로 전달하고, 이를 실행시킨 뒤 Nginx 리버스 프록시 설정을 변경하는 과정을 작성
📌 코드 해석
#!/bin/bash if curl -s "http://${blue_ip}:8080" > /dev/null then deploy_ip=$green_ip else deploy_ip=$blue_ip fi echo "Deploy IP choosed : ${deploy_ip}" ssh-keyscan ${deploy_ip} > ~/.ssh/known_hosts scp ./target/webgoat-*-SNAPSHOT.jar root@${deploy_ip}:/root/webgoat.jar ssh root@${deploy_ip} "nohup java -jar /root/webgoat.jar > /dev/null &" & sleep 60 if curl -s "http://${deploy_ip}:8080" > /dev/null then echo "Deploy Success" else echo "Deploy Error" exit 1 fi ssh-keyscan ${nginx_ip} > ~/.ssh/known_hosts ssh root@${nginx_ip} "echo 'set \$deploy_server http://${deploy_ip}:8080;' > /etc/nginx/sites-available/deploy_server && service nginx reload" echo "Nginx reverse proxy now pass the packet to ${deploy_ip}" if [ "${deploy_ip}" == "${blue_ip}" ] then ssh-keyscan ${green_ip} > ~/.ssh/known_hosts ssh root@${green_ip} "fuser -k 8080/tcp" else ssh-keyscan ${blue_ip} > ~/.ssh/known_hosts ssh root@${blue_ip} "fuser -k 8080/tcp" fi echo "Kill other server process"
- fingerprint관련 이슈가 없도록 ssh-keyscan을 이용
→ blue 웹 서버에서 웹 애플리케이션을 동작중이라면 green 웹 서버에, green 웹 서버에서 웹 애플리케이션이 동작중이라면 blue 웹 서버에 배포를 수행
- scp를 이용해 빌드된 jar파일을 /root/webgoat.jar 경로에 저장
- 저장이 완료되면 ssh를 이용하여 webgoat.jar를 실행시키고 1분간 sleep → WebGoat 애플리케이션 정상작동까지 걸리는 시간
- 1분이 끝나면 웹 애플리케이션이 정상적으로 배포되었는지 curl을 이용하여 확인한 뒤, 문제가 없다면 Nginx 컨테이너 내 /etc/nginx/sites-available/deploy_server에 설정된 IP주소를 배포서버 IP주소로 수정
- 모든 작업이 다 끝나면, 이전에 사용하던 서버의 8080포트에서 동작중인 웹 애플리케이션을 kill
▶ 본 작업을 통해 서비스가 새롭게 배포되면 배포되는 동안에는 기존 서버에 올라가 있는 서비스를 사용하고, 배포가 완료되면 리버스 프록시를 통해 자연스럽게 새롭게 배포된 서비스로 접근할 수 있게 되기 때문에 서비스 사용을 중단할 필요가 없다. 즉 무중단 배포가 가능해진다.
'Cloud > DevSecOps' 카테고리의 다른 글
AWS DevSecOps Service & Tool (0) | 2024.05.04 |
---|---|
[DevOps 구축] Github Webhook 설정, DevOps 구축 완성 (0) | 2024.04.30 |
[DevOps 구축] Jenkins와 Github 연결하기 (0) | 2024.04.29 |
[DevOps 구축] Jenkins 설치 및 초기 설정 (0) | 2024.04.29 |