Backend.AI의 코어 엔진은 많은 오픈소스 소프트웨어들을 활용함과 동시에 그 자체도 오픈소스로 개발되고 있습니다. Backend.AI를 사용하다가 뭔가 불편한 점이 있거나 버그를 발견하였을 때, 엔터프라이즈 고객분들의 경우 고객 지원 및 기술 지원 채널을 이용하여 이슈 트래킹 및 지원을 해드리고 있지만, 그렇지 않은 경우에는 오픈소스에 직접 기여하는 것도 가능합니다. 기여 방법은 크게 어떤 문제가 있는지 혹은 개선 아이디어가 있는지 상세하게 설명하는 issue와, 직접 코드를 고쳐서 기여하는 pull request가 있습니다. 이번 글에서는 그러한 기여 과정에서 개발팀과 보다 효과적이고 빠른 의사소통을 하기 위해서 몇가지 미리 알아두면 좋은 것들을 소개하고자 합니다.
GitHub 저장소 소개
먼저 이슈를 올리고 싶다면 가장 먼저 살펴보실 곳은 Backend.AI meta-repository입니다. 그냥 "backend.ai"라는 프로젝트 이름을 가진 저장소를 meta-repository라고 부르는 이유는 실제로 어떤 기능을 하는 코드가 들어있는 곳이 아닌 프로젝트 관리용으로 사용하고 있는 저장소이기 때문입니다. Backend.AI의 서버 및 Client SDK 관련 이슈들은 모두 여기서 관리하고 있으며, README를 통해 다른 프로젝트로의 링크를 제공합니다. 또한 이 저장소의 패키지를 통해 Backend.AI의 주요 릴리즈에 대한 컴포넌트별 버전 매핑을 제공합니다. (예: 21.03 버전의 backend.ai 패키지의 의존성으로 21.03 버전의 backend.ai-manager, backend.ai-agent 패키지들이 등록되어 있음)
이슈를 새로 생성할 때 기본 템플릿으로는 bug report와 feature request 2가지 양식을 제공하고 있으나, 이 양식을 꼭 엄격하게 따라야만 하는 것은 아닙니다. 다만 Backend.AI의 복잡도나 다양한 사용 환경을 고려하였을 때 해당 양식에 맞춰서 내용을 작성해주시면 좀더 문제 파악을 위한 맥락 공유가 쉬워진다는 점을 고려해주시면 되겠습니다.
Backend.AI의 컴포넌트 관계
그림 1은 Backend.AI의 주요 컴포넌트 관계를 나타낸 다이어그램입니다.
모든 컴포넌트들은 backend.ai-xxx-yyy
같은 형식으로 저장소 및 패키지 이름이 붙어있습니다.
간략하게 컴포넌트별로 하는 일을 요약하면 다음과 같습니다:
backend.ai-manager
(Manager): 전체 클러스터의 연산자원 모니터링 및 세션 스케줄링을 담당하고 사용자 인증 및 세션 실행 등의 API 제공하는 핵심 서비스backend.ai-agent
(Agent): 연산노드에 설치되어 컨테이너들을 관리 및 제어하는 서비스backend.ai-common
(Common): 여러 서버측 컴포넌트에서 공통적으로 또는 자주 사용되는 기능 및 데이터 형식을 모아놓은 라이브러리backend.ai-client-py
(Client SDK for Python): 공식 명령줄 인터페이스이자 Python을 위한 API wrapper 함수·클래스들을 제공하는 라이브러리backend.ai-client-js
(Client SDK for Javascript): Javascript 환경을 위한 API wrapper 함수·클래스들을 제공하는 라이브러리backend.ai-storage-proxy
(Storage Proxy): 사용자 웹브라우저 또는 Client SDK가 네트워크 스토리지로부터의 대용량 입출력을 바로 할 수 있도록 해주는 서비스backend.ai-webserver
(Web Server): Web UI와 SPA (single-page app) 구현을 위한 라우팅을 제공하고 웹 세션 기반 사용자 인증을 제공하는 HTTP 서비스backend.ai-webui
(Web UI & Desktop App): 실제 사용자가 접하는 UI의 웹컴포넌트 기반 구현체. Electron 기반 데스크톱 앱 빌드도 지원. 또한 사용자가 컨테이너 내부에서 실행 중인 애플리케이션 포트로 바로 접속할 수 있도록 해주는 app proxy의 로컬 경량화 버전도 포함.
Backend.AI의 버전 관리 방법
Backend.AI는 6개월(매년 3월과 9월)마다 주요 릴리즈가 이뤄지며, 릴리즈 후 사후 지원을 약 1년 간 제공합니다.
따라서 버전 번호는 YY.0M.micro
방식의 CalVer 형식을 따르고 있습니다 (예: 20.09.14, 21.03.8).
다만 Python 패키징 시스템의 버전 번호 정규화로 인해 wheel 패키지의 버전은 월 부분에 zero-padding이 없는 YY.MM.micro
형식입니다 (예: 20.9.14, 21.3.8).
버전 업데이트 주기가 본체 릴리즈 주기와 다른 세부 컴포넌트들은 일반 SemVer 형식을 따르고 있는 경우도 있습니다.
개발 환경 설치 방법
실제 코드 기여를 하기 위해서는 pull request를 작성하는데, 단순 오타 수정이나 문서 관련 기여가 아닌 경우 코드를 고쳐서 직접 돌려봐야 하므로 직접 개발환경을 구축하는 것이 꼭 필요합니다. Backend.AI는 여러 개의 컴포넌트가 함께 맞물려 돌아가는 구조 상 하나의 저장소를 clone하고 Python 가상환경을 만들어 editable install1을 해주는 것만으로는 설치가 끝나지 않습니다. 최소한 manager, agent, storage-proxy, webserver, wsproxy를 모두 설정 및 실행해야만 동작하는 GUI를 확인할 수 있으며 CLI 환경을 위해서는 여기에 client SDK도 별도로 설치해야 합니다. 또한 manager 구동 및 agent와의 통신을 위한 Redis, PostgreSQL, etcd 서버도 함께 실행해야 합니다.
이러한 복잡한 설치과정을 자동화해주기 위해 만든 것이 meta-repository의 scripts/install-dev.sh
스크립트입니다.
이 스크립트가 하는 일은 다음과 같습니다:
- pyenv, docker, python 등의 설치 여부를 검사하여 자동 설치 또는 설치 방법을 안내
- 위와 같은 다양한 컴포넌트들을 모두 각자의 디렉토리와 각자의 Python 가상환경에 editable 상태로 설치
- 이때 common, accelerator-cuda와 같이 다른 컴포넌트의 동작에 필요한 컴포넌트들은 자신들의 가상환경뿐만 아니라 의존 주체 컴포넌트의 가상환경에도 함께 editable 상태로 추가 설치됩니다. 예를 들어, common 소스코드를 변경하면 manager와 agent 실행 시에도 반영되게끔 설치됩니다.
- 각 컴포넌트들이 서로를 바라볼 수 있는 기본 포트 설정 및 예제 인증키 등을 포함한 database/etcd fixture 추가
- postgresql, redis, etcd 서비스를 "halfstack"이라는 이름으로 docker-compose를 이용해 생성 및 실행
install-dev 스크립트가 성공적으로 완료되면 manager, agent 등의 서비스 데몬을 실행하기 위한 명령어 및 기본 설정된 예제 계정 정보를 출력합니다. 설명을 따라 tmux, screen 등의 터미널 멀티플렉서 또는 터미널 앱의 다중 탭 기능 등을 활용하여 각각의 독립된 shell에서 서비스 데몬들을 실행하고, hello world 예제까지 동작하는 것을 확인하면 Backend.AI를 개발 및 테스트할 수 있는 준비가 된 것입니다.
현재 이 방법은 Intel (amd64/x86_64) 기반 macOS 및 Ubuntu/CentOS Linux 환경, Windows 10의 WSL v2 환경만 지원합니다. WSL에서는 약간의 추가적인 설정이 필요합니다.
보통 처음 이 install-dev 스크립트를 이용하면 도중에 다양한 오류나 사전 검사 실패로 인해 중단하고 다시 실행해야 하는 경우가 자주 발생합니다.
이때는 scripts/delete-dev.sh
스크립트를 활용하면 삭제 절차를 간편하게 수행할 수 있습니다.
방금 언급한 이 한 쌍의 설치/삭제 스크립트는 한 컴퓨터에 Backend.AI의 여러 버전 또는 여러 사본을 설치 및 테스트해볼 수 있도록 environment ID라는 것을 생성 및 사용합니다.
install-dev 스크립트를 실행할 때 -e
옵션으로 직접 ID를 지정할 수 있고, 지정하지 않는 경우 랜덤으로 생성해서 사용합니다.
delete-dev 스크립트를 실행할 때는 반드시 -e
옵션을 지정해야 합니다.
install-dev 스크립트 실행 시 지정한 값 또는 설치 로그의 초반부에 출력된 생성값을 다시 지정하면 해당 개발환경을 삭제할 수 있습니다.
한 컴퓨터에 여러 버전의 Backend.AI 설치 및 개발하기
이 install-dev 및 delete-dev 스크립트와 위에서 설명한 environment ID를 활용하면, 한 컴퓨터에서 여러 버전의 Backend.AI를 돌아가면서 실행하는 것도 가능합니다. 예를 들어, dev2103, dev2109 2개의 버전으로 Backend.AI 개발환경을 만들어봅시다.
install-dev 스크립트에서 설치 시 --server-branch
및 --client-branch
옵션을 지정하여 기본값 main 브랜치가 아닌 20.09
, 21.03
과 같은 특정 릴리즈 브랜치를 지정하는 방식으로 다른 버전을 설치할 수도 있습니다.
먼저 meta 저장소를 복제하여 install-dev 스크립트를 확보합니다.:
$ git clone https://github.com/lablup/backend.ai meta
dev2103 환경을 먼저 설치합니다.:
$ meta/scripts/install-dev.sh \
-e dev2103 \
--server-branch=21.03 \
--client-branch=21.03 \
--install-path=./dev2103
이제 dev2109 환경을 설치하는데, 먼저 dev2103 환경용으로 생성된 docker-compose 컨테이너 집합을 종료해야 두번째 환경용 install-dev 스크립트가 새로운 docker-compose 컨테이너 집합을 생성할 수 있습니다. 이 글의 작성 시점 현재 21.09 버전은 main 브랜치로 개발 중이므로 브랜치 이름을 버전 번호가 아닌 "main"으로 지정하였습니다.
$ docker-compose \
-f ./dev2103/backend.ai/docker-compose.halfstack.dev2103.yml \
-p dev2103 \
stop
$ meta/scripts/install-dev.sh \
-e dev2109 \
--server-branch=main \
--client-branch=main \
--install-path=./dev2109
이후 dev2103 환경과 dev2109 환경을 전환하고 싶다면, 먼저 이전 환경에서 실행 중인 모든 Backend.AI 서비스 데몬을 종료하고 다음과 같이 docker-compose 컨테이너 집합을 정지 및 실행해주면 됩니다. (전환 방향에 따라 dev2103, dev2109를 바꿔주면 됩니다)
$ docker-compose \
-f ./dev2109/backend.ai/docker-compose.halfstack.dev2109.yml \
-p dev2109 \
stop
$ docker-compose \
-f ./dev2103/backend.ai/docker-compose.halfstack.dev2103.yml \
-p dev2103 \
start
docker-compose의 -f
옵션에 들어가는 compose 파일명과 -p
옵션의 값이 install-dev 스크립트의 -e
옵션으로 지정한 environment ID에 해당하며, 디렉토리 경로 상의 ./dev2103
과 같은 부분은 install-dev 스크립트의 --install-path
옵션에 해당합니다.
CUDA 플러그인 설치하기
위와 같이 설치한 경우 기본값으로는 CPU만 사용할 수 있는 상태로 Backend.AI가 설치됩니다.
CUDA GPU 가속 환경들을 실행하려면 agent에 CUDA 플러그인을 설치해야 합니다.
현재 오픈소스 버전에서는 CUDA 장치 단위로 컨테이너에 할당 가능한 오픈소스 버전 CUDA 플러그인이 함께 제공되고 있습니다.
install-dev 스크립트를 실행할 때 옵션으로 --enable-cuda
옵션을 주시면 agent에 함께 설치되며, --cuda-branch
옵션으로 플러그인 버전을 지정할 수 있습니다.
특정 Backend.AI 릴리즈 버전과 CUDA 플러그인 버전의 호환성에 대해서는 이 표를 참고하시기 바랍니다.
Pull Request 작성 요령
실제 특정 버그패치나 기능 구현 사항을 PR로 보내려면 먼저 이를 GitHub에 올려야 합니다. 여러 방법이 있지만, 다음과 같은 방법을 권장합니다:
- GitHub의 저장소 페이지에서 fork를 뜹니다. (직접 커밋 권한이 있는 경우라면 fork 없이 바로 브랜치를 만드는 것을 권장합니다.)
- 코드 복사본(local working copy)에서 git remote로 해당 fork 저장소를 가리키게 합니다.
- 이때, 관례를 따라 래블업의 원본 저장소를
upstream
으로, fork해서 새로 만든 저장소를origin
이라고 이름을 붙이면 좋습니다. - fork 후 처음 clone하는 경우가 아니라 install-dev로 설치를 먼저 했던 경우라면 원본 저장소가
origin
일 것이므로 remote 이름 변경 작업을 해줘야 합니다.
- 이때, 관례를 따라 래블업의 원본 저장소를
- 새 브랜치를 만듭니다.
- 브랜치 이름은 버그수정인 경우
fix/
를, 기능 추가나 개선인 경우feature/
를 앞에 붙여 kebab-case 방식으로 주제를 요약하여 짓습니다. (예:feature/additional-cluster-env-vars
,fix/memory-leak-in-stats
) 그 외에docs/
,refactor/
같은 prefix를 사용하기도 합니다. - main 브랜치에 직접 수정하여 PR을 작성하는 것도 가능하지만, PR 리뷰 및 수정 기간 동안 main 브랜치에 추가 변겨사항이 생기는 경우 upstream 저장소와 동기화할 때마다 매번 rebase 또는 merge해줘야 하기 때문에 더 귀찮습니다. 별도의 브랜치를 따두면 내가 원할 때 rebase 및 merge를 할 수 있습니다.
- 브랜치 이름은 버그수정인 경우
- 변경사항을 해당 브랜치로 커밋합니다.
- 커밋 메시지는 가급적 conventional commit 스타일을 따릅니다. 브랜치 이름과 마찬가지로
fix:
,feat:
,refactor:
,docs:
,release:
와 같은 제목 접두어들을 사용하며, Backend.AI 한정으로 의존성 관련 커밋에는setup:
, gitignore 업데이트나 저장소 디렉토리 구조 변경과 같은 경우에는repo:
같은 추가 접두어를 사용하기도 합니다. 괄호를 묶어 영향받는 컴포넌트를 표기하기도 합니다. (예:fix(scripts/install-dev): Update for v21.03 release
) - 커밋 메시지는 영어로 작성해야 합니다.
- 커밋 메시지는 가급적 conventional commit 스타일을 따릅니다. 브랜치 이름과 마찬가지로
- 브랜치를 push하고 PR을 작성합니다.
- 별도 이슈가 있는 PR의 경우 PR 본문에 해당 이슈 번호를 적어주어야 합니다. Meta-repository의 이슈를 참조하려면
lablup/backend.ai#123
과 같은 형식으로 적으면 GitHub이 자동 링크를 걸어줍니다. - PR 본문에 특정한 형식을 요구하지는 않지만, 어떤 문제를 해결하기 위한 것인지, 어떤 원리로 작성하였는지 혹은 어떤 도구나 라이브러리를 활용하였는지, 그러한 선택을 한 이유는 무엇인지 등을 적어주면 좋습니다.
- PR 제목 및 본문은 영어 또는 한국어로 작성 가능합니다.
- PR을 생성하면 다양한 자동화된 검사 도구가 동작하는 것을 볼 수 있습니다. 특히, CLA (contributor license agreement)는 반드시 서명(GitHub 사용자이름 등록)해주셔야만 리뷰가 진행됩니다.
- 각 언어별 기본 코딩스타일·코딩규칙 검사를 모두 통과해야 합니다. (Python 코드의 경우 flake8, mypy 등)
changes
디렉토리가 존재하고towncrier
검사가 있는 저장소에서는, PR을 생성하여 그 번호를 받으면changes/<PR번호>.<수정유형>
이름의 파일을 생성하여 Markdown 문법으로 변경사항 내용 요약을 한 줄의 영어 문장으로 작성합니다. (비교적 간단한 내용이거나 기존 이슈가 따로 있는 경우에는 이 내용이 PR 본문 역할을 대신하기도 합니다) 수정 유형은fix
,feature
,breaking
,misc
,deprecation
,doc
이 있으며 프로젝트 별로 다른 부분은 각 저장소의pyproject.toml
에 정의됩니다. 기존 메시지들을 어떻게 적었는지는CHANGELOG.md
또는CHANGES.md
와 같은 파일을 참고하면 됩니다.
- 별도 이슈가 있는 PR의 경우 PR 본문에 해당 이슈 번호를 적어주어야 합니다. Meta-repository의 이슈를 참조하려면
- 리뷰 과정을 진행합니다.
- 완료되면 보통 squash-merge 형태로 리뷰어가 커밋 로그를 정리하여 하나의 단일 커밋으로 만들어 병합하게 됩니다.
- 따라서 리뷰 과정에서 자잘한 수정 커밋을 자주 만드는 것에 부담을 가지지 않고 자유롭게 생각날 때마다 커밋을 만들어주시면 됩니다.
GitHub CLI, SourceTree, GitKraken과 같은 도구들을 git 명령어와 함께 활용하면 더욱 좋습니다.
정리
지금까지 Backend.AI의 전체적인 컴포넌트 구조와 저장소 구조, 개발환경 설치 방법, 그리고 pull request 작성 요령을 살펴보았습니다. 이 가이드가 Backend.AI 소스코드에 한발짝 더 다가갈 수 있도록 도움이 되었으면 좋겠습니다.
- "editable" 설치란 Python 패키지를 소스 디렉토리를 직접 바라보도록 설치하여 site-packages 디렉토리 내부를 편집하지 않고 소스 디렉토리를 수정하는 것만으로도 해당 패키지를 import 시 변경 내용이 바로 반영되어 있도록 하는 설치 방법을 말합니다.↩