2021 오픈소스 컨트리뷰션 아카데미를 통해 래블업 인턴십에 지원할 수 있는 기회를 얻게 되었다.
Backend.AI 는 규모가 크고 어려워서 두 달이라는 시간이 짧게 느껴졌고 더 알아보고 싶다는 생각이 들었다. 부족한 점이 많아서 "내가 할 수 있는 일이 있을까?"라는 걱정이 들었지만, 실무를 경험해볼 좋은 기회라 생각하여 지원하게 되었다. 프로젝트에 참여하는 동안 멘토님들에게 많이 배웠고, 다 좋은 분들이었기 때문에 같이 일해보고 싶기도 했다.
서류 합격 후 처음으로 기술면접을 보게 됐다. 질문이 예상가지 않아 이것저것 봤는데, 오히려 역효과였던 것 같다.. 웹 프론트엔드 개발을 주로 해와서 웹과 프론트엔드 관련 지식을 물어보셨는데, 많이 대답하지는 못했다. 그냥 최선을 다해 답변했다. 다행히 합격했다는 연락이 왔다! 그리고 4일 후에 바로 인턴을 시작하게 되었다. 합격 통보나 면접같은 과정이 빠르게 진행됐다.
래블업에서는 Backend.AI라는 솔루션을 개발&관리하고 있기 때문에, orientation에서는 Backend.AI를 설치하고 이용하는 과제들을 수행했다. 대부분 Backend.AI를 이용해서 머신러닝 모델을 개발하는 과제였다. 머신러닝을 공부해본 적이 없어서 막막했지만, 어떻게든 해냈다. 인턴십을 하면서 "계속 찾아서 하다보면 되는구나"라는 걸 가장 많이 느꼈다. 모르면 질문하고, 에러나면 고치고 하다 보면 어느샌가 완료한 나를 발견할 수 있었다.
Orientation에서 진행했던 task들은 아래와 같이 간단하게 정리해본다.
Task 1. Change MNIST code to be Fashion MNIST
Task 2. Increase the accuracy without changing the model
Task 3. Install Backend.AI
Task 4. Run code on Backend.AI CLI
Task 5. Run code on Backend.AI Web UI
Task 6. Increase the accuracy without changing the data
Task 7. Increase the accuracy within time limit
개인적으로 2번 task가 가장 어려웠다. 데이터 증강 기법을 이용하여 정확도를 높이려 했지만, 생각대로 되지 않았다. 뒤집은 이미지들을 추가하여 모델을 학습시켰는데, 이상하게 세로로 뒤집은 이미지를 추가하면 정확도가 내려갔다. 가로로 뒤집은 이미지만 추가했을 때 가장 정확도가 높아서 그 방법으로 과제를 제출했다.
Backend.AI 는 여러가지 컴포넌트가 상호작용하면서 돌아가도록 구현되어 있다.
manager, agent, webui, common, client-py, kernels, storage-proxy, webserver 총 8개의 컴포넌트가 있다. 인턴십 기간에는 manager, agent, webui, common과 관련된 이슈들을 해결했다. 컴포넌트별로 진행했던 내용을 정리해보려 한다.
API를 제공하고, 연산자원 모니터링 및 세션 스케줄링을 담당하는 컴포넌트이다. 핵심 서비스라 하는 일도 많고 코드도 많다. manager가 모든 컴포넌트들과 연결이 되어있어서 코드를 이해하는 게 어려웠지만, 전체적인 그림을 보는데 도움이 많이 되었다.
PR(Merged): https://github.com/lablup/backend.ai-manager/pull/498
mgr clear-history
명령어 추가하기VACUUM cannot run inside a transaction block
CREATE DATABASE
나 VACUUM
과 같은 명령어들을 트랜잭션 안에서 실행이 불가하기 때문에, AUTOCOMMIT 모드로 바꿔주어야한다. 그래서 아래의 방법을 사용하여 해결했다.conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
PR: https://github.com/lablup/backend.ai-manager/pull/504
PR: https://github.com/lablup/backend.ai-manager/pull/511
가장 마지막에 진행했던 이슈인데, 이 기능을 추가하기 위해서는 webui, manager, agent 컴포넌트를 모두 업데이트해야했다. webui에서는 변경 요청을 보낼 수 있도록 UI요소를 추가해야했고, manager와 agent에서 그 요청을 적절하게 수행할 수 있도록 구현해야했다. webui는 작업하지 못했지만, manager와 agent컴포넌트는 완료하고 PR을 올려놓은 상태이다.(PR이 merge되면 webui도 작업을 해보려한다.)
agent 컨테이너들을 관리하는 컴포넌트인데, 작업할 일이 거의 없었다. 거의 끝나갈 무렵 위에서 언급한 대로 기능 추가를 위해 작업을 하게 되었다.
PR: https://github.com/lablup/backend.ai-agent/pull/327
async def update_scaling_group(self, scaling_group):
cfg_src_path = config.find_config_file('agent')
with open(cfg_src_path, 'r') as f:
data = tomlkit.load(f)
data['agent']['scaling-group'] = scaling_group
with open(cfg_src_path, 'w') as f:
tomlkit.dump(data, f)
self.local_config['agent']['scaling-group'] = scaling_group
log.info('rpc::update_scaling_group()')
파일을 읽기 권한으로 열고, load하여 data라는 TOMLDocument 객체를 만들었다. 파일을 쓰기 모드로 열어 수정한 data를 저장했다.
읽기('r')와 쓰기('w') 권한을 나누고 싶지는 않았다. 하지만 'r+' 권한으로 시도하면 수정된 데이터로 덮어씌워지는 게 아니라, 원본 아래에 추가가 돼서 내용이 반복됐기 때문에 이 방법밖에 없었다.
이 이슈를 진행하면서 tomlkit에 대해 많이 알게 되었다. 정보가 많이 없어서 이 부분에 대해서는 따로 포스팅을 올리면 좋을 것 같다.
PR(Merged): https://github.com/lablup/backend.ai-common/pull/99
mgr clear-history
를 위한 함수인 clear_history()
에서는 TimeDuration을 이용하여 expiratation_date
를 계산하고 그 날짜 이전의 데이터들을 삭제한다. unit = retention[-2:]
today = datetime.now()
if unit == 'yr':
yr = int(retention[:-2])
expiration_date = today - relativedelta(years=yr)
elif unit == 'mo':
mo = int(retention[:-2])
expiration_date = today - relativedelta(months=mo)
else:
duration = TimeDuration()
expiration_date = today - duration.check_and_return(retention)
TimeDuration을 months와 years를 지원한다면 아래와 같이 간결하게 코드를 찔 수 있다.
today = datetime.now()
duration = TimeDuration()
expiration = today - duration.check_and_return(retention)
expiration_date = expiration.strftime('%Y-%m-%d %H:%M:%S')
→ months와 years를 지원할 수 있도록 TimeDuration 업데이트하기
dateutil.relativedelta.relativedelta
를 사용해야했다. datautil은 datetime 모듈의 확장 패키지이다. date = datetime(2020, 2, 29)
...
assert iv.check('1yr') == relativedelta(years=1)
assert iv.check('1mo') == relativedelta(months=1)
assert date + iv.check('4yr') == date + relativedelta(years=4)
iv는 TimeDuration object이다. '1yr'과 '1mo'를 넣었을 때 원하는 값이 나오는지 확인하는 테스트 코드이다. 윤년일 때도 잘 계산이 되는지 테스트한다.
PR(Merged): https://github.com/lablup/backend.ai-webui/pull/1160
x
버튼과 dismiss
버튼 두 개가 있는데, dismiss를 눌러서 닫은 경우에는 다시 창이 열렸다. 하지만 x버튼의 경우 그렇지 않았다.lablup-terms-of-service
안에 backend-ai-dialog
컴포넌트가 있는 구조였다. dismiss 버튼은 lablup-terms-of-service
컴포넌트 안에 존재하고, x 버튼은 backend-ai-dialog
안에 존재한다.backend-ai-dialog
를 닫을 때 "dialog-closed" customEvent를 발생시켰다. 그리고 그에 대한 EventListener를 lablup-terms-of-service
컴포넌트에 추가했다. 그리고 콜백함수에 위의 두 가지 조건들을 만족시킬 수 있도록 코드를 추가했다.PR(Merged): https://github.com/lablup/backend.ai-webui/pull/1170
한 마디로 정리하면, 매우 자유롭고 수평적이었다. 모두 oo님으로 부른다.(대표님도!)
인턴십 기간이 두 달이라 기업 문화를 모두 이해하기에 짧은 시간이지만, 그 기간 동안 느꼈던 회사의 문화를 정리해보았다. 스타트업에 취업하고 싶다는 생각은 한 번도 못했는데, 래블업에서 인턴으로 일하면서 생각이 많이 바뀌었다. 다들 좋은 회사 문화를 만들기 위해 항상 노력하셨다.
인턴을 시작할 때에는 머릿속에 걱정이 대부분이었다. 하지만 이슈를 해결하면서 조금씩 이해되기 시작하니 점점 즐거워졌다. 지원할 때 동기를 물어보는 질문에 좋은 분들과 함께 열정적으로 일해보고 싶다고 적었던 것 같은데, 기대했던 대로 좋았다. 그동안은 프론트엔드 개발만 했는데, 백엔드를 경험할 수 있었다. 생각보다 훨씬 흥미로웠기 때문에, 앞으로 백엔드를 더 공부해볼 계획이다.
확실히 실무는 달랐다. Github에서 code와 pull request tab만 썼었는데, Action을 처음 사용해봤다. 프로젝트가 어떻게 관리되는지 배울 수 있었다. git 명령어도 조금 더 다양하게 쓰게 되었다. 이곳에서 일하면서 시야가 많이 넓어졌다. 배운 것들이 앞으로 도움이 많이 될 것이라고 생각한다.
두 달이라는 시간이 짧게 느껴질 정도로 즐겁고 유익한 시간이었다. 마무리해야하는 게 아쉽지만, 나중에 좋은 모습으로 다시 뵐 수 있도록 열심히 공부하려 한다.