MLops 에서의 CI/CD
회사에서 AI Engine의 개발을 담당하고 관리하는 ML Engineer로써 항상 걱정되는 부분은 이번에 수정한 코드가 기존에 동작하던 application 단의 결과들을 변화시키는지 혹은 작동되어야 할 기능들이 잘 작동이 여전히 되는지입니다. 물론 매번 수동으로 project들을 하나하나 학습시켜보고 기능들을 테스트해볼 수 있지만 생각보다 쉽지 않은 일입니다.
그래서 이번 포스팅에서는 MLOps 의 핵심인 CI/CD 를 구축하기 위한 기본적인 방법인 Jenkins를 통한 테스트 과정 자동화를 하는 방법에 대해서 적어보려고 합니다. 이러한 방법의 장점은 사람이 하나하나 하다보면 생길 수 있는 테스트라는 요소를 자동화 시켜서 시스템에게 책임을 전가한다는 점입니다. ML engineer는 모델 혹은 필요한 AI engine의 기능들에 대한 구현만 신경쓰면 되기 때문에 훨씬 걱정해야 할 거리가 줄어들게 됩니다.
Jenkins
이 포스트에서는 Jenkins를 활용하여 github 저장소에 있는 테스트 코드가 push 됐을 때 자동으로 테스트를 실행하는 과정을 정리해 보겠습니다. 기본적으로 Ubutu 서버의 docker 환경을 가정하고 진행한다는 것을 주의해주세요.
Jenkins 설치
docker container를 사용해서 Jenkins가 동작할 수 있도록 할 예정이기 때문에 docker의 image를 다운받는 것이 제일 먼저 할 일입니다. docker 의 pull 명령어를 통해서 아래와 같이 설치를 진행해주세요. 설치가 완료되면 docker images 명령어로 다운로드가 잘 되었는지 확인하는 것 까지가 설치의 전부입니다.
docker pull jenkins/jenkins:lts
docker images
# REPOSITORY TAG IMAGE ID CREATED SIZE
# jenkins/jenkins lts e4ebf98bd6ca 7 days ago 441MB
설치가 완료되었다면, images를 cotainer로 실행시켜주는 것이 필수적입니다. 아래와 같은 명령어를 통해서 위에서 설치한 jenkins 이미지를 container로 run 해주시면 됩니다.
여기서 주의해야 할 것들은 아래와 같습니다.
docker run -d -p 60008:8080 -v ~/jenkins_home:/var/jenkins_home --name=jenkins e4ebf98bd6ca
docker ps
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# 2ac3bc1b4aed e4ebf98bd6ca "/sbin/tini -- /usr/…" 4 minutes ago Up 4 minutes 50000/tcp, 0.0.0.0:60008->8080/tcp jenkins
- -d : 실행한 container가 background 모드로 종료되지 않고 계속 동작합니다. 즉, 위의 명령어로 한번 실행시켜 놓으면 알아서 동작하기 때문에 신경쓸 것이 없어지게 됩니다.
- -p : 포트포워딩을 설정합니다. <host-port> : <container-port> 로 정의하게 됩니다. host-port는 서버로 접근할 때 사용되는 port를 의미합니다. 제가 사용하는 회사의 경우 jenkins 를 설정한 서버의 포트가 60000번대로 열려 있기 때문에 임의로 60008번을 사용하였습니다. 그리고 jenkins container는 8080을 사용하기 때문에 60008:8080을 하였습니다.
- -v : 서버가 가진 폴더와 container 내부의 폴더를 연결시켜줍니다. 이렇게 연결을 하게 되면 container 내부에서 /var/jenkins_home 의 폴더에 어떤 변화를 준 것이 서버에서의 ~/jenkins_home 의 폴더에 변화를 주게 됩니다.
- --name : 실행된 컨테이너의 이름을 의미합니다. docker ps로 확인할때 알 수 있습니다.
- e4ebf98bd6ca : docker pull로 생성한 image의 IMAGE ID입니다.
Jenkins 설정
위의 설정이 잘 되었다면, 이제 크롬으로 Jenkins 설정을 해야합니다. 위에서 설정한 <server-port>를 기억해서 사용할 차례입니다. 네모로 가린 부분은 회사 서버 ip 주소라서 가렸지만, 따라하시는 분들은 자신이 사용하는 서버의 ip 주소를 입력해주세요.
<서버-ip> : <서버-port>
위의 설명을 살펴보면, /var/jenkins_home/secretes/initialAdminPassword에서 Administrator password를 복사해오라는 말입니다. 그런데 사용하는 서버에는 해당 경로가 없다는 것을 찾아보시면 아실 수 있습니다. 저 경로는 사실 container 내부의 경로에 존재하고 있습니다.
그런데, 저희가 docker run 시에 -v 옵션으로 container 내부의 /var/jenkins_home을 서버의 ~/jenkins_home과 연결했기 때문에 서버의 ~/jenkins_home 에는 conatiner 내부의 /var/jenkins_home과 동일한 상태라는 것을 기억해내셨다면 쉽게 해결할 수 있습니다.
그러므로, 서버의 ~/jenkins_home에 가서 아래의 명령어로 나오는 값을 복사해주면 됩니다.
$ cat ~/jenkins_home/secrets/initialAdminPassword
#hewrsrdadfgaddd9da8a1219d21691f
위의 password를 잘 복사해서 입력해주면 다음 화면으로 이어집니다. 플러그인을 설정하라는 페이지 인데 저는 잘 모르니 추천해주는 플러그인들을 자동으로 설정해주는 왼쪽꺼를 선택했습니다.
설치를 눌러주면 자동으로 Getting Started 메세지와 함께 progress bar가 진행되면서 설치가 진행됩니다. 설치가 완료되면 아래와 같은 Create First Admin User라는 메시지가 뜨고 가입을 해주면 됩니다.
계정을 설정해주면 jenkins url 을 설정하라는 화면이 등장합니다. 기본적으로 저희가 크롬으로 접속한 주소가 설정되어 있는데 저는 그대로 사용하였습니다.
Jenkins 설정
위의 과정들이 모두 지났다면 아래와 같은 페이지가 등장하게 됩니다. 이제 본격적으로 Jenkins 설정을 진행할 차례입니다.
SSH-Key
우선 이 화면에서 잠시 멈추고, 저희는 ssh-key를 통해서 Github 프로젝트에 접근할 생각이기 때문에 ssh key 를 생성하는 과정을 먼저 살펴보도록 하겠습니다. 위에서 저희가 생성해서 run 했던 docker container에 잠깐 접근을 해봅시다.
docker exec -it 2ac3bc1b4aed /bin/bash
2ac3bc1b4aed는 docker ps를 통해서 실행중인 jenkins container의 container id입니다. 위의 명령어로 container에 접근 후에는 ssh-key gen명령어를 입력해서 ssh key를 생성해줍니다. 여기서 중요한 건 /var/jenkins_home에 키가 생성되었는지만 확인하시면 나머지는 알아서 진행됩니다.
ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/var/jenkins_home/.ssh/id_rsa):
Created directory '/var/jenkins_home/.ssh'.
....
이제 /var/jenkins_home/.ssh에 접근해서 private key를 확인해 봅시다.
cat /var/jenkins_home/.ssh/id_rsa
보통 public key를 사용할텐데 왜 private key를 사용하냐고 생각하실 수도 있겟지만, 아래에서 Jenkins create job을 수행할 때 사용하게 되므로 꼭 기억해주세요.
그리고, 최근일자로 git 관련 사용을 위해서는 ssh나 personal access token을 생성해서 사용해야 합니다. 이때 PAT이 jenkins의 create job 과정에서 필요하니 github -> setting -> Developer setting -> Personal access tokens 에서 키를 하나 생성해주세요. 그리고 가장 중요한건 PAT키를 생성하면 나오는 ghp_xxxxxxxxxxxxxxxx 의 코드를 복사해두셔야 합니다. 아래쪽에서 사용할 정보에요!
Create Job
이제 다시 Jenkins의 create job 으로 돌아가보도록 하겠습니다. name은 사용하고자 하시는 아무거나 상관없이 설정하셔도 됩니다. 그리고, 저는 freestyle project를 지정해서 진행하였습니다.
Freestyle project를 누르고 OK키를 누르면 다음과 같은 화면이 나타납니다.
저희는 먼저 소스코드관리 탭을 눌러서 사용하고자 하는 git 주소를 연동시키는 것부터 하도록 하겠습니다. 처음에는 소스코드관리 탭 아래에 None에 체크가 되어 있는데 이 부분을 Git 으로 바꿔주시면 아래에 Repositories와 여러 정보가 등장합니다.
가장 중요한 Repository URL에 git clone시에 사용하는 주소를 복사 해줍니다. 이때, 위에서 말씀드린 PAT 키의 ghp_xxxxxx 하던 키를 추가로 해주어야 정상적인 등록이 가능합니다. 아래와 같은 형태로 등록해주세요. <xxxxx> 부분은 각자의 repository에 따라 다르게 생겼으니 적절하게 ....
https://ghp_xxxxxxxxxxxxxxxxxx@github.com/<xxxxxxxx>/<xxxxxxxx>.git
그 후에 Credentials 의 Add를 클릭해서 Jenkins를 눌러주세요. 저는 등록을 해둬서 mf-myungjae-shin이라고 나타나지만 처음이시면 None 이라고 되어있으니 걱정마세요.
그러면 다음과 같은 Jenkins Credentials Provider 라는 창이 나타납니다. 이때, 기본 설정은 password 접근이기 때문에 Kind 부분에서 SSH username with private key로 설정을 바꿔주세요. 그 후에 입력해야 할 내용은 다음과 같습니다.
- ID : 하고싶은 이름으로 (저는 mf-myungjae-shin)
- Username : GitHub ID 입력
- private key 에 Enter directly 선택후 Add 버튼 클릭
- key 입력 영역에 jenkins container의 private key를 복사하여 입력 (포스팅 중간 부분에서 생성해서 확인)
위의 내용들을 모두 채우셨다면 add 버튼을 눌러서 등록을 해주시면 credential 부분도 완료가 됩니다. 그 다음 master branch에 누군가의 commit이 push된 경우에 Jenkins가 관리 되도록 master를 입력하였습니다. (만약 develop브랜치에 push시에 빌드되도록 하신다면 */develop를 입력하시면 됩니다.)
그 후, 조금 더 내려가서 빌드 유발 이라는 섹션의 Github hook trigger for GITScm polling 을 선택합니다. 이 설정을 해주는 것으로 위에서 설정한 master branch에 PR 이 올라와서 push될 때 테스트가 진행되도록 할 수 있습니다. (github 저장소에서 설정이 조금 더 필요하며 아래에서 정리하도록 하겠습니다.)
그리고 의도한 바와 같이 Jenkins가 테스트를 실행되로록 Build > Add Build Step > Execute shell을 선택하고 실행시키고자 하는 test에 대한 코드를 입력해줍니다.
여기까지 진행하셨다면 create job까지 모두 완성된 것입니다. 이제 Add 버튼을 눌러서 저장하시면 Jenkins의 Dashboard 에서 새롭게 생긴 job을 확인하실 수 있습니다.
Github 설정
저희의 목적은 소설정한 소스 코드 저장소의 master branch에 push가 발생했을 때, 자동으로 테스트가 실행될 수 있게 하는 것입니다. 그래서 몇가지 Github에서의 설정이 필요합니다. Github에 접속한 뒤 위에서 저희가 연동하고자 했던 project로 가주세요.
여기서는 개인 계정의 Settings가 아니라 project의 Settings입니다. Settings -> Webhooks -> Add webhook 을 선택한 뒤 새로운 Webhook을 추가 합니다.
Payload URL에는 {jenkins 가 설치된 url주소}/github-webhook/ 을 입력합니다. Content type은 application/json 을 선택합니다. Payload URL로 저희는 docker container가 작동중인 주소를 입력해 줍니다.
이때, 하단에 Which events would you like to trigger this webhook 의 탭에서 Let me select inidividual events 를 선택한 뒤 여러가지 목록 (ex. push, PR ...) 을 보시고 원하는 것을 선택하시면 됩니다. 만약 Pull Requests 를 선택하셨다면 PR이 발생할 때 test가 진행되도록 설정할 수 있습니다.
만약 PR이 발생했다면 Jenkins 의 Dash 보드 좌하단에서 현재 진행중인 test에 대한 진행 상황이 나타나며 끝난 이후에는 아래 사진처럼 fail 또는 success가 기록됩니다.
정리
여기까지가 Jenkins를 docker container로 설치하고 Github에 연동하는 기본 과정입니다. 하지만 저는 MLOps 를 위해 Jenkins를 설치하였는데 이 설정으로는 해당 부분을 완성할 수 없습니다. 다음 포스팅에서 이어서 작성하도록 하겠습니다.
Reference
https://phoby.github.io/docker-jenkins-github/
https://jojoldu.tistory.com/139
https://dnight.tistory.com/entry/Github-Jenkins-%EC%97%B0%EB%8F%99-%EC%84%A4%EC%A0%95
https://www.comtec.kr/2021/07/22/jenkins-webhook-%EC%84%A4%EC%A0%95/
'MLOps' 카테고리의 다른 글
[Tensorboard] Multi Process 에서 하나의 Tensorboard 에 접근할 때 문제점 (0) | 2021.10.29 |
---|---|
[유용한 블로그 포스팅 모음] (0) | 2021.10.29 |
[Kubernetes, Container] MLOps를 위한 기본 - Container란? [1] (0) | 2021.10.23 |
[Github, MLOps] ML 모델 CI/CD 를 위한 Jenkins 테스트 자동화 [3] (0) | 2021.10.22 |
[Github, MLOps] ML 모델 CI/CD 를 위한 Jenkins 테스트 자동화 [2] (0) | 2021.10.15 |