TIFY 프로젝트에서 처럼
github action을 이용하여 CI/CD를 할 수 있었지만
오토 스케일링(결국 못했다는..)을 위해서도 그렇고
젠킨스를 써보고 싶은 마음에 사용하게 되었다,,
CI/CD가 아닌
파이프라인같은 다른 기능을 사용해보지 못하여 조금 아쉽지만
젠킨스를 다룰 때 얽혔던 여러 문제들을 경험하면서 얻은 것이 많았고
추후에 또 젠킨스를 사용할 때 참고하기 위해
기록을 남겨보려고 한다.
0) 프로젝트 아키텍쳐의 특징
특징 읽기 ⬇️
0-1) 다수의 서버 운용
일반적으로 진행하는 프로젝트와는 달리
서버를 참 많이 구동했다.
SSH 접속 시
공인 IP를 가지는 프록시 서버를 두고
어플리케이션 서버는 사설 IP만 가지도록 설정하여
프록시 서버를 통하지 않고서는 어플리케이션 서버에 직접 접속하지 못하게 막았다.
뭐 이렇게까지.. 라고 생각할 수 있겠지만
실제 크레딧이 걸려있고 개인 정보들도 프로젝트에 많이 이용되었기 때문에
이런 식으로 보안을 강화했다.
또 TIFY 프로젝트처럼 로컬 테스트 환경에서도
실제 DB 서버의 데이터베이스를 이용하며
서비스가 실제로 사용하는 DB를 계속 건들기보다는
개개인의 크레딧을 이용하여
로컬 테스트 환경에서 자신만의 DB 서버를 사용할 수 있도록
각자의 DB 서버를 구축했고, 그에 따라 프로젝트를 설정했다.
(위 사진에서 JS, JW... 이런게 팀원의 이니셜이다,,)
이러한 특징 때문에
필자의 프로젝트는 dev 환경과 local 환경의 분리가 확실하게 되어 있다.
0-2) 도커와 젠킨스를 이용한 환경 구축
어플리케이션 서버 내에서 프로젝트를 실행시킬 때
FE던지 BE던지 도커 이미지를 이용해 컨테이너에서 실행시켰고
따라서 무중단 배포를 위해서는
젠킨스가 실행되는 곳에서 도커 명령어를 사용할 수 있어야 했다.
그런데 도커로 실행시킨 젠킨스 안에서는
도커 명령어가 실행되지 않는 문제가 있었고...
경험이 없다보니 여기에서 조금 헤매었어서
이에 대한 이슈 해결은 밑에서 다루겠다.
0-3) NAT Gateway를 이용한 private area - public area 간의 소통
위에서도 언급했듯이
보안을 강화하고자 어플리케이션 서버를 private하게 설정해놓았는데
프로젝트의 필수적인 요소인 네이버 AI 서비스 API를 이용하기 위해서는
public area와의 연결이 필요했고
우리가 도입하고자 했던 Effective Log Search 서비스와도
private area - public area 간의 소통이 되어야 했다.
처음에 이를 고려하지 않고 프로젝트를 진행했는데
중간에 이를 발견하고 NAT Gateway를 도입하고자 했다.
이에 대해서는 따로 포스팅을 남겨놓았으니 참고하시길...!
1) 프록시 서버에 젠킨스 설치하며 서버 설정 추가
위에서 언급했던 도커 컨테이너에서 실행되는 젠킨스 내부에서는
도커 명령어가 실행되지 않는 것을 몰랐기에..
초기에는 젠킨스를 도커로 설치했다.
프록시 서버에 ssh로 접속한 후
docker pull jenkins/jenkins:jdk17
젠킨스 jdk17버전 (이는 우리 서버에 맞춘 것이므로 버전은 다르게 설정 가능) 이미지를 받아왔다.
docker run -d -p 18080:8080 -v /var/jenkins_home --name jenkins -u root jenkins/jenkins:jdk17
젠킨스의 포트를 18080으로 설정하려 했기 때문에 -p 18080:8080
을 사용했다.
여기까지 하고 docker ps -a
명령어로 실행되고있는 컨테이너를 살펴보면
jenkins라는 이름으로 젠킨스가 실행되고 있다.
인프라 구축에 대해 경험이 없었다 보니
여기에서 바로 젠킨스 화면에 접속하려 했으나
당연히 실패...
로드밸런서도 설정되어있지 않았고
심지어는 타겟그룹도 설정하지 않아서
{우리가 설정한 도메인}:18080
에 아무리 접속하려 해도 할 수 없었다.
1-1) 타겟 그룹 & 로드밸런서 설정
프록시 서버에 열린 젠킨스를 타겟 그룹에 추가하여
로드밸런서가 리다이렉트 해줄 수 있도록 설정해야했다.
그리고 로드밸런서의 리스너를 추가해주었다.
여기까지 하면
{설정한 도메인}:18080
으로 접속했을 때
alb가 젠킨스 페이지로 리다이렉트 해줄 수 있게 된다.
1-2) ACG 설정
위 단계까지 했는데도 젠킨스 접속이 되지 않는다면,
당연히 선행이 되어야 했겠지만
ACG 설정을 해주어야 한다... (필자는 처음에 이걸 생각하지도 못했다)
1-3) 타겟 그룹 Health Check 설정
1-2까지 했다면
{프록시 서버의 IP}:18080
으로 접속해서
젠킨스 로그인 화면을 볼 수 있다.
그런데 {설정한 도메인}:18080
으로 접속하면
503 서버에러가 나더라..
그래서 젠킨스 타겟 그룹의 상태를 확인해보니
403 에러가 발생하는 것을 보았고
Health Check Url이 / 으로 설정되어있는 것을 확인했다.
바로 타겟 그룹의 Health Check URL을 /login으로 바꿔주니
타겟 그룹 상태가 200으로 바뀌었고
{도메인 이름}:18080
으로 젠킨스 접속에 성공하는 모습을 볼 수 있었다.
젠킨스 자체에서
로그인이 되지 않았을 때 모든 url(/)을 허용하지 않고
로그인 url(/login)으로 리다이렉트 (어찌보면 당연하다. 다른 서비스들도 다 이러니깐..) 하는데
IP로 접속할 때에는 로드밸런서를 타지 않으니까 Health Check도 안해도 되고 /login으로 리다이렉트 되어도 상관없는데
도메인으로 접속할 때에는 로드밸런서를 타기 때문에
hook-killer.sh-bong.site:18080/ 과 같이 접속하면 젠킨스에서는 로그인이 안된 상태이므로 403 Forbidden 을 반환할 것이다.
그러면 로드밸런서가 행하는 타겟 그룹 Health Check는 당연히 실패할 것이고
이렇게 되면 로드밸런싱 대상에서 제외되어 접속이 되지 않는 것이다. (이게 아마 503 이겠지)
따라서 로그인이 되지 않은 상태에서 젠킨스가 리다이렉트 해주는 url,
즉 /login url을 Health Check 하여 200을 받아오면
Health Check가 성공하고 hook-killer.sh-bong.site:18080/login이 로드밸런싱 대상이 될 수 있는 것이다.
2) Github Repository - Jenkins 연동 & Publish over SSH
이는 구글링하여 과정을 알 수 있다.
간단하게 요약하면,
젠킨스 내의 설정에서 Github Repository를 찾아
우리 Github Repository의 url을 입력하고
Github - Developer Settings의 Generate Token에서 발급받은 키 값을 이용해
Credential을 등록해주면 (Github Repository가 public이라면 등록할 필요 없다)
젠킨스가 우리가 설정한 Github Repository에 대해 감시(?)할 수 있게 된다.
자세한 과정은 아래 블로그에서 확인할 수 있다.
Reference
https://velog.io/@kws60000/react-Jenkins-%EC%9E%90%EB%8F%99-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0-github-%EC%97%B0%EB%8F%99
위 과정까지 마쳤다면
젠킨스에서 Github Repository에 있는 코드를 가지고
프로젝트를 빌드할 수 있다.
빌드 완료 후
다른 서버에서 배포를 하려면
over SSH라는 젠킨스 플러그인이 필요한데,
이 과정도 구글링하여 알 수 있다.
자세한 내용은 아래 블로그와 젠킨스 공식 문서에서 확인할 수 있다.
필자의 경우, 프록시 서버와 어플리케이션 서버 둘 다 설정하였다.
Reference
https://osg.kr/archives/429
https://plugins.jenkins.io/publish-over-ssh/
over SSH까지 뚫어내었다면,
Build Steps 이후 빌드 후 조치 과정에서 아래와 같이
Send build artifacts over SSH 메뉴를 이용할 수 있게 된다.
3) Jenkins 내에서 빌드 과정 / 빌드 후 조치 설정
필자의 프로젝트 같은 경우
프록시 서버의 젠킨스에서 빌드 후
Docker Hub가 아닌
Naver Cloud에서 제공하는 Container Registry에 이미지 파일을 push한 뒤
어플리케이션 서버에서 이미지 파일을 pull 받아
그 이미지 파일을 이용하여 도커로 배포하는 방식을 사용했다.
## 프록시 서버에서 이미지 파일 빌드 (Build Steps - Exec Shell 단계)
echo "Hello, proxy!"
git pull https://github.com/hook-killer/front-end.git dev
cd front-end && docker build -t hook-killer-fe .
docker login ey1cp5gn.kr.private-ncr.ntruss.com -u {NCloud API Access Key} -p {NCloud API Secret Key}
docker push ey1cp5gn.kr.private-ncr.ntruss.com/hook-killer-fe
## 어플리케이션 서버에서 이미지 파일로 배포 (빌드 후 조치 - Send build artifacts over SSH - Exec Command 단계)
echo "Hello, app!"
docker login ey1cp5gn.kr.private-ncr.ntruss.com -u {NCloud API Access Key} -p {NCloud API Secret Key}
docker pull -t fe-image ey1cp5gn.kr.private-ncr.ntruss.com/hook-killer-fe
docker tag ey1cp5gn.kr.private-ncr.ntruss.com/hook-killer-fe fe-image
docker stop hook-killer-fe-server
docker container rm hook-killer-fe-server
docker run -d —name hook-killer-fe-server -p 80:80 fe-image
Reference
https://guide.ncloud-docs.com/docs/container-ncr-1-3
하지만 이때 이슈가 발생했다.
3-1) 도커로 실행한 젠킨스에서의 이슈 발생
포스팅의 거의 맨 처음부터 얘기했던 문제가 발생했다.
도커로 실행된 젠킨스 내에서 또 도커를 사용하려니 문제가 발생한 것이다.
GPT에게도 물어보았는데 답변이 이러하다.
Docker 컨테이너 내에서 Docker 명령어를 실행하는 것은 기본적으로 권장되지 않습니다. 이는 보안 및 격리 이슈로 인해 일반적으로 금지되어 있습니다. Docker 컨테이너에서 Docker를 실행하려는 시도는 다양한 이슈를 일으킬 수 있습니다.
여러 리서치를 거친 결과, 우리 팀이 할 수 있었던 현실적인 선택지는 두 가지였다.
젠킨스가 실행되고 있는 도커 컨테이너(호스트 머신)의 도커 소켓과
빌드된 이미지 파일이 실행될 도커 컨테이너(게스트 머신)의 도커 소켓을 공유시키는 것
혹은
젠킨스를 도커로 구동하지 않고
패키지 매니저를 통해 젠킨스를 직접 설치하여 systemctl로 젠킨스를 돌리는 것
3-2) 이슈 해결
도커 소켓을 공유시키는 방법을 사용하는 것이
조금 어렵더라도 해보지 않았던 것을 하는 것이라 욕심이 났지만
촉박한 시간 안에 프로젝트를 진행하기 위해서는
많은 리서치를 필요로 하지 않는 패키지 매니저를 이용하는 것이 낫다고 판단했다.
결국 프록시 서버에서 돌아가고 있던
젠킨스 패키지를 삭제하였고,
apt 패키지 매니저로 젠킨스를 서버에 설치하여
systemctl 명령어로 젠킨스를 구동하였다.
이 과정에서도 정말 많은 에러가 있었는데,
이 사진들은 아래 명령어로 젠킨스 실행 로그를 뜯어 본 것이다.
cd /var/log && tail -f syslog
권한이 없어서 AccessDenied가 뜨는 것 같아
리서치 이후 다시 실행했더니...
Reference
https://stackoverflow.com/questions/35011699/java-nio-file-accessdeniedexception-at-jenkins-build
문제 없이 돌아갔다..!
4) 결과 확인
위에 써놓은 CLI와는 조금 다르지만 (간절한 마음을 담아.. 다른 명령어들을 좀 넣었었다)
의도한대로 완벽히 돌아가고 있다.
이렇게 포스팅을 써놓고 보니
그렇게 어려운 작업은 아니었지 싶다.
이 당시에는 인프라에 대한 완벽한 이해도 부족했고
내가 다루는 기술들이 정확히 어떤 작업을 하는지도 잘 모르는 상태였었다.
기술을 직접 써보다보니 뭐가 뭔지 알겠더라...
역시 써본놈이 더 잘 쓴다고,,,
새로운 기술을 익히는 것에 대해
두려워하지 말아야한다는걸 다시 한번 깨달았다.
'🎉 프로젝트 > 🍀 Naver Cloud' 카테고리의 다른 글
[NCP] 어플리케이션 성능 모니터링하기 with Pinpoint (0) | 2024.01.31 |
---|---|
[NCP] public area - private area 간의 통신 가능하게 하기 with NAT Gateway (1) | 2024.01.30 |
[NCP] Oriental Unity 프로젝트 (0) | 2024.01.15 |
[NCP] Multipart 파일 업로드 with Object Storage (2) | 2023.10.02 |
[NCP] CI/CD 환경 구축 with Github Action, DBDocs (0) | 2023.10.02 |