Jenkins를 이용한 CI/CD 서버를 구축하던 중에 겪은 어려움이었다. 결론은 Linux기반 운영체제에 대한 이해가 부족해서 생긴 문제였다. 운이 좋았다면 금방 끝났었을 수도 있는 문제였지만 돌고돌아 결국 서버 구축에 성공하는데에는 3명이서 5시간이 걸리고 말았다 ..

 

사건의 계기

 

CI과정에서 생긴 오류

 블로그들을 참고하며 진행해서 큰 어려움이 없었는데,, 바로 난관에 부딪혀 버렸다. 깃허브에 웹훅을 걸어 잘 오는 것이 확인된 후 Build를 하는데 0.7초만에 입구컷을 당해버린 것이었다! 앞으로 일어날 일도 모르고 천천히 원인을 좁혀가보기로 했다. 

 

 

왜 안될까?

 

1. 파일 자체문제 또는 gradle문제?

 

 일단 취합을 수동으로 한 후 였으므로 로컬로 돌려봤다. 결과는 잘됐고 사실은 여기까진 예상했다. 그렇다면 다른 점은 환경(로컬은 Windows, Jenkins는 ubuntu)이기에 여기서 생긴 문제리라 추측했었다.

 

 

2. 혹시나 Jenkins에서만 안되나?

 

 ubuntu에서 잘되면 Jenkins 설정 문제가 맞기에 find / -name '프로젝트명'으로 경로를 찾은 후 직접 들어가서 명령어를 실행시켜보았다. 여기서 우린 매우매우매우 큰 실수를 저질렀는데 "똑같이" 실험해보지 않은 것이었다. 처음에는 ./gradlew로 실행해서 permission denied가 나왔었다. 그래서 chmod -x ./gradlew를 실행 후 build해봤는데 되는 것이었다! 하지만 위 사진에서도 봤듯이 Jenkins에서는 sudo ./gradlew로 되어있다.

 '그냥 ./gradlew로도 되는데 sudo는 당연히 되는 거지'라는 내재된 생각 속에 우린 "아 그렇다면 이건 Jenkins문제다" 라는 결론을 내려버리고 만 것이었다.................

 

 

3. 에러 메세지 구글링

 

 언제나 그랬듯 무지성으로 에러 메세지를 복붙해서 구글링을 갈겨보았다. Jenkins에서 JAVA_HOME 변수가 세팅되지 않았다는 것으로 이해하고 세팅하는 법을 찾아보았다.

 

  1. cmd에서 직접 추가하기(export JAVA_HOME=...)
  2. Jenkins 설정에서 설정하기 

Jenkins 관리 화면

여러 방법으로 JAVA_HOME을 덕지덕지 붙여보았는데 여전히 되지 않았다. 이쯤에서 시간이 많이 소요되어 각자도생으로 각자 블로그들 찾아보고 각자 한번씩 실험해보기 시작했다. 여기서 살짝 우릴 멘붕으로 이끌었던 것은

??? 이건 왜 잘나옴??????

그렇다면 $JAVA_HOME은 잘 지정되었단 뜻이니 쉘 스크립트(gradlew)에서 문제점을 찾아봐야할 것 같다.

 

 

4. 에러 메세지의 출처를 따져보자

gradlew 파일

에러메세지는 찾았는데 단순한 if문이라 뭔가를 도출해낼 수 없었다. 그러던 중

맨 위에 #!/bin/sh를 보았다. 이건 쉘 스크립트를 실행할 때 지정한 쉘을 사용한다는 뜻이었는데 우리는 ubuntu를 사용해서 기본 쉘이 dash로 된다. 이때 번뜩 떠오른 생각이 있었다.

 

 Jenkins를 만들때 ubuntu->docker(ubuntu)->Jenkins로 만들었다. 2번을 시도할 때 docker 내부로 접근하기 위해

docker exec -it jenkins /bin/bash

 이 명령어를 사용했는데 /bin/bash를 실행하는 것을 볼 수 있다. bash와 dash는 기능의 차이가 있어서 bash에선 되는데 dash에선 안되는 것들이 있다는 글을 보아서 설마 bash에서만 돌아가는 것이 아닐까...?? 라는 생각을 하게 되었다.

 

 

5. Shell executable에서 쉘 설정

 

Jenkins 설정 화면

다 왔다고 생각했고 실행해보았는데 드디어 처음으로 초록색 화면들만 보았다.

첫 빌드 성공

이렇게 끝난줄 알았다. 확실한 원인규명을 위해 bash와 dash의 어떤 차이때문에 이런 일이 벌어졌는지 찾기 시작했다. 도중에 에러 메세지를 다시 한번 보려고 Shell executable에서 /bin/bash를 빼고 실행해보았는데...

빌드 성공 log

??? 왜 잘나옴???2

 

다행히 이번엔 왜인지 빨리 찾을 수 있었다. sudo를 지운 분이 자진납세해서 그러고보니 sudo도 지웠다고 하셨기 때문이다. 그래서 sudo를 다시 붙여서 실행해보니

sudo 실패 log

정겨운 에러메세지가 나왔다. 이때는 제발 에러메세지가 나와달라고 기도했던 것 같다. 여기서 적잖은 충격을 받았는데 sudo는 만능이라 무조건 sudo를 붙이면 다 되는줄 알았었고, 실제로 이제까진 다 됐기 때문이다. 그렇다면 sudo를 붙이면 왜 저런 에러가 뜨는 것일까?

 

 

sudo 파헤쳐보기

 

1. sudo의 실행원리

 

sudo는 실행될 때 /etc/sudoers 파일을 보고 기본 설정을 한다.

cat /etc/sudoers

이 때 env_reset이 Defaults로 설정되는데 env_reset은 sudo가 실행되면 몇 가지 환경변수를 제외하고 나머지 환경변수를 env_keep에 정의된 것 빼고는 모두 reset 시킨다고 한다. 그렇기 때문에 사용자가 설치한 경로인 $JAVA_HOME은 사라지게 되는 것이다. 

 

 

2. sudo 사용시 JAVA_HOME 설정 방법

 

2-1. env_keep에 $JAVA_HOME 추가

 

Defaults	env_keep += "JAVA_HOME"

/etc/sudoers파일에 들어가서 한 줄 추가하면 된다. 그러면 env_reset이 되어도 $JAVA_HOME이 유지되게 된다. 이 와중에 sudoers는 vi sudoers 이런식으로 수정하면 안되고 visudo 명령어로 수정해야된다. 그 이유는 동시 접근 제어를 해주고 기본 문법 오류를 잡아주기 때문이라고 한다.

 

2-2. sudo -E

 

-E 옵션은 존재하는 환경변수를 보존하겠다는 의사를 security policy에 명시하는 것이다. 이것도 user에 따라 권한이 없으면 실행되지 않을 수도 있다는데 우린 어차피 root라 그런지 됐다.

sudo -E 사용시 빌드성공

 

 

마무리

  이유도 알고 원인도 알았으나 그냥 sudo를 빼면 되는 일이라 결국 최종 코드는 ./gradlew clean build였다.

돌아돌아돌아돌아돌아 왔지만 결국엔 해결이 되었다...!

 오후 5시에 모여서 시작한 Jenkins서버 구축하기는 이를 포함한 여러문제와 함께 오후 10시경에 끝났다. 이런게 이론으로는 못배우는 실전인 것 같다. 얼떨결에 여러가지 Linux 운영체제 관한 이해도 갖게 되었고 docker 명령어도 조금 알게되었다. 돌이켜보면 바보같이 디버깅을 했고 다음에도 이런 원인모를 디버깅을 해야할 때는 더 잘할 수 있을거란 자신감도 얻게되었다. 블로그들에서는 Linux에 관련된 것들이 간략하게 나와서 단번에 이해가 안갔는데 linux man page를 참고하라는 글을 보고 가보니 설명이 잘 나와있었다. 이래서 결국 공식문서를 보나보다.. 앞으로 이런 일들을 자주 부딪혀 지식도 늘고 해결능력도 늘었으면 좋겠다 ! !

'공..부 > 프로젝트' 카테고리의 다른 글

Gradle 빌드시 encoding 문제  (0) 2023.11.07

+ Recent posts