태그 : 가이드

  • Backend.AI 오픈소스 기여 가이드 (2024년 7월)

    By 성대현

    Backend.AI의 코어 엔진은 많은 오픈소스 소프트웨어를 활용함과 동시에 그 자체도 오픈소스로 개발되고 있습니다. 오픈소스로 개발되는 만큼, 버그를 찾았거나 불편함을 느낀 사용자가 있다면 개인이 직접 Backend.AI 프로젝트에 기여하는 것 또한 가능하죠. (물론, Backend.AI를 이용하시는 엔터프라이즈 고객분들께는 저희의 고객 및 기술 지원 채널을 통해 이슈가 생길 경우 지원을 해드리고 있답니다.)

    기여를 하기 위한 방법에는 두 가지가 있는데요, 첫번째 방법은 어떤 문제가 있는지, 어떤 개선 아이디어가 있는지 상세하게 개발팀에게 설명을 남기는 'issue'이고, 두번째 방법은 직접 코드를 수정하여 기여할 수 있는 'pull request' 입니다.

    Backend.AI 오픈소스 기여 가이드 글을 통해 래블업의 개발팀과 더욱 효과적이고, 빠른 의사소통을 위해 알아두면 좋은 내용을 소개합니다.

    GitHub 저장소 소개

    이전의 글 Backend.AI 오픈소스 기여 가이드에서 보듯 Backend.AI은 원래 Backend.AI meta-repository와 여러 하위 컴포넌트들로 저장소를 구분하여 개발되었습니다.

    그러나, Backend.AI의 "22.06"버전부터는 Pants를 이용한 mono-repository 방식으로 변경되었습니다.

    이와 같은 개발 워크플로의 전환으로 다수의 개별 컴포넌트에서 종종 발생하는 패키지 호환성 문제를 해결해 더욱 편리한 개발 환경을 구성하는 데에 많은 도움이 되었습니다.

    Pants는 빠르고, 확장성이 있으며, 사용자 친화적인 빌드 시스템입니다.

    우선, 이슈를 올리고 싶다면 가장 먼저 살펴보실 곳은 Backend.AI repository입니다. Backend.AI라는 프로젝트 이름을 가진 저장소는 Pants를 이용하여 통해 여러 패키지를 통합 설치하고 있습니다. 이 저장소는 프로젝트 관리뿐만 아니라 실제로 어떤 기능을 하는 코드가 들어가는 저장소입니다. Backend.AI의 서버 및 Client SDK 관련 이슈들은 모두 여기서 관리되고 있으며, README를 통해 다른 프로젝트로의 링크를 제공합니다.

    이슈를 새로 생성할 때 기본 템플릿으로는 bug report와 feature request 2가지 양식을 제공하고 있으나, 이 양식을 꼭 엄격하게 따라야만 하는 것은 아닙니다. 다만 Backend.AI의 복잡도나 다양한 사용 환경을 고려하였을 때 해당 양식에 맞춰서 내용을 작성해주시면 문제 파악을 위한 맥락 공유가 조금 더 쉬워진다는 점을 고려해주십시오.

    Mono-repository에 대한 소개

    Backend.AI는 버전 "22.06"부터 Backend.AI는 Pants를 이용한 mono-repository로 변경하였습니다. Mono-repository는 여러 프로젝트의 기본 종속성, 데이터 모델, 기능, 툴링 및 프로세스를 공유하는 소스코드를 가지고 통합한 코드 베이스의 프로젝트입니다. 이전에 사용하던 여러 프로젝트를 하나의 프로젝트로 통합하여 저장소를 운영하고 있습니다.

    Pants 소개

    Backend.AI는 Pants를 이용한 빌드시스템으로 설치합니다. Pants에 대한 자세한 내용은 다음의 링크 Pants - Getting started를 확인하시기 바랍니다.

    Backend.AI의 컴포넌트 관계

    그림 1. Backend.AI 주요 컴포넌트 사이의 관계 구조

    그림 1은 Backend.AI의 주요 컴포넌트 관계를 나타낸 다이어그램입니다.

    그림 2. Backend.AI의 주요 컴포넌트 구조도 및 실행 방법의 예

    그림 2는 Backend.AI의 주요 컴포넌트 구조를 나타낸 다이어그램이며, 컴포넌트의 소스코드 위치 및 실행 명령등을 보여주고 있습니다.

    Backend.AI의 대다수 컴포넌트는 Backend.AI repository에서 관리되며, 소스코드는 src/ai/backend/ 하위 디렉토리에 위치하여 있습니다. 간략하게, 컴포넌트별로 하는 일에 대해 디렉토리별로 요약하면 다음과 같습니다:

    • src/ai/backend/manager (Manager): 전체 클러스터의 연산자원 모니터링 및 세션 스케줄링을 담당하고 사용자 인증 및 세션 실행 등의 API를 제공하는 핵심 서비스
    • src/ai/backend/agent (Agent): 연산노드에 설치되어 컨테이너들을 관리 및 제어하는 서비스
    • src/ai/backend/common (Common): 여러 서버 측 컴포넌트에서 공통으로 또는 자주 사용되는 기능 및 데이터 형식을 모아놓은 라이브러리
    • src/ai/backend/client (Client SDK for Python): 공식 명령 줄 인터페이스(CLI)이자 Python을 위한 API wrapper 함수·클래스들을 제공하는 라이브러리
    • src/ai/backend/storage (Storage Proxy): 사용자 웹 브라우저 또는 Client SDK가 네트워크 스토리지로부터의 대용량 입출력을 바로 할 수 있도록 해주는 서비스
    • src/ai/backend/web (Web Server): Web UI와 SPA (single-page app) 구현을 위한 라우팅을 제공하고 웹 세션 기반 사용자 인증을 제공하는 HTTP 서비스
    • src/ai/backend/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 형식을 따르고 있는 예도 있습니다.

    개발 전 우선 설치해야 하는 필수 패키지

    Backend.AI를 설치하기 전에 먼저 Docker, Docker Compose v2 등을 설치해야 합니다. Backend.AI는 repository의 scripts/install-dev.sh 스크립트로 설치 시 Docker, Docker Compose v2 등의 설치 여부를 검사하여 설치 방법을 안내합니다. 만약, Python, pyenv, Docker, npm이 설치되지 않았으면 아래와 같이 필수 패키지 설치를 해야합니다. Python의 경우는 시스템 패키지의 Python3로 설치하시기 바랍니다. 이후, pyenvpyenv-virtualenv를 설치해야 합니다.

    $ curl https://pyenv.run | bash
    

    이후 Docker와 Docker Compose v2를 다음과 같이 설치하면 됩니다.

    MacOS

    MacOS의 경우는 Docker Desktop on Mac으로 설치하면 Docker와 Docker Compose v2가 자동으로 설치됩니다.

    Ubuntu, Debian, CentOS, Fedora Core등 Linux 환경

    Ubuntu, Debian, CentOS, Fedora Core의 경우 다음의 스크립트를 이용하면 Docker와 Docker Compose v2가 자동으로 설치됩니다.

    $ sudo curl -fsSL https://get.docker.io | bash
    

    Docker 설치한 후, 만약 sudo 없이 실행하였을때 다음과 같이 unix:///var/run/docker.sock 접근 권한 오류가 생기는 이슈가 있습니다.

    $ docker ps
    Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/json": dial unix /var/run/docker.sock: connect: permission denied
    

    위와 같은 권한 문제가 존재하는 경우 아래와 같이 명령어를 이용하여 권한을 설정합니다.

    $ sudo usermod -aG docker $(whoami)
    $ sudo chown root:docker /var/run/docker.sock
    

    이후, 재부팅을 한 후, docker run hello-world 를 실행하여, 정상 실행되는걸 확인하면 됩니다.

    $ docker run hello-world
    Unable to find image 'hello-world:latest' locally
    latest: Pulling from library/hello-world
    c1ec31eb5944: Pull complete
    Digest: sha256:94323f3e5e09a8b9515d74337010375a456c909543e1ff1538f5116d38ab3989
    Status: Downloaded newer image for hello-world:latest
    
    Hello from Docker!
    This message shows that your installation appears to be working correctly.
    
    To generate this message, Docker took the following steps:
    1. The Docker client contacted the Docker daemon.
    2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
        (amd64)
    3. The Docker daemon created a new container from that image which runs the
        executable that produces the output you are currently reading.
    4. The Docker daemon streamed that output to the Docker client, which sent it
        to your terminal.
    
    To try something more ambitious, you can run an Ubuntu container with:
    $ docker run -it ubuntu bash
    
    Share images, automate workflows, and more with a free Docker ID:
    https://hub.docker.com/
    
    For more examples and ideas, visit:
    https://docs.docker.com/get-started/
    

    chown 으로 /var/run/docker.sock의 group ownership 변경이 아닌 /var/run/docker.sock 파일의 권한을 666으로 변경하여 그룹내 다른 사용자도 접근 가능하게 변경하면 재부팅을 하지 않아도 됩니다.

    sudo chmod 666 /var/run/docker.sock
    

    그러나, /var/run/docker.sock 파일의 권한을 666으로 설정하면, 보안 취약점이 생깁니다.

    Docker Compose v2 설치 여부는 다음과 같이 확인해봅니다.

    $ sudo docker compose version
    Docker Compose version v2.28.1
    

    만약, nvm이 설치되어있지 않다면 nvm을 다음의 링크 nvm - install & Update Script에 나온 것처럼 설치해야 합니다.

    $ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
    

    nvm 설치 이후에는 최신 LTS 버전의 Node.js을 설치 하고 사용 설정을 하면 됩니다.

    $ nvm install --lts
    $ nvm use --lts
    

    개발 환경 설치 방법

    실제로 코드를 통해 기여하기 위해서는 pull request를 작성해야 하는데, 단순한 오타 수정 혹은 문서 기여가 아니라면 코드를 수정하며 직접 결과물을 돌려서 확인해봐야 하기 때문에 개발 환경을 구축하는 절차가 꼭 필요합니다. Backend.AI는 여러 개의 컴포넌트가 함께 맞물려 돌아가는 구조로, 하나의 저장소를 clone하고 Python 가상환경을 만들어 editable install[1]을 해주는 것만으로는 설치가 끝나지 않습니다. 최소한 manager, agent, storage-proxy, webserver, wsproxy를 모두 설정 및 실행해야만 동작하는 GUI를 확인할 수 있으며 CLI 환경을 위해서는 여기에 client SDK도 별도로 설치해야 합니다. 또한 manager 구동 및 agent와의 통신을 위한 Redis, PostgreSQL, etcd 서버도 함께 실행해야 합니다.

    앞서 소개한 필수 패키지를 설치했고, Backend.AI의 여러 컴포넌트를 설치하려면 repository의 scripts/install-dev.sh 스크립트로 설치하면 됩니다. 이 스크립트가 하는 일은 다음과 같습니다:

    • pyenv, Python, Docker, npm 등의 설치 여부를 검사하여 설치 방법을 안내
    • 위와 같은 다양한 컴포넌트들을 모두 각자의 디렉토리에 설치
      • 이때 accelerator-cuda와 같이 다른 컴포넌트의 동작에 필요한 컴포넌트들은 editable 상태로 추가 설치됩니다.
    • 각 컴포넌트가 서로 바라볼 수 있는 기본 포트 설정 및 예제 인증키 등을 포함한 database/etcd fixture 추가
    • PostgreSQL, Redis, etcd 서비스를 "halfstack"이라는 이름으로 Docker Compose를 이용해 생성 및 실행

    install-dev 스크립트 실행이 성공적으로 완료되면, manager, agent 등의 서비스 데몬을 실행하기 위한 명령어 및 기본 설정된 예제 계정 정보를 출력합니다. 설명을 따라 tmux, screen 등의 터미널 멀티플렉서 또는 터미널 앱의 다중 탭 기능 등을 활용하여 각각 독립된 shell에서 서비스 데몬들을 실행하고, hello world 예제까지 동작하는 것을 확인하면 Backend.AI를 개발 및 테스트할 수 있는 준비가 된 것입니다.

    현재 이 방법은 Intel (amd64/x86_64) 및 ARM 기반 macOS 및 Ubuntu/Debian/CentOS/Fedora 및 Docker Compose가 설치되는 배포판의 Linux 환경만 지원합니다.

    보통 처음 이 install-dev 스크립트를 이용하면 도중에 다양한 오류나 사전 검사 실패로 인해 중단하고 다시 실행해야 하는 경우가 자주 발생합니다. 이때는 scripts/delete-dev.sh 스크립트를 활용하면 삭제 절차를 간편하게 수행할 수 있습니다.

    Backend.AI 설치 및 삭제하기

    이 install-dev 및 delete-dev 스크립트를 활용하면, Backend.AI를 자유롭게 설치하고, 삭제할 수 있습니다. 먼저 Backend.AI 저장소를 복제합니다.

    $ git clone https://github.com/lablup/backend.ai 
    

    위의 Backend.AI를 설치합니다.

    $ cd backend.ai
    $ ./scripts/install-dev.sh 
    

    설치가 완료되면, 화면에 나오는 결과 내용을 숙지하시기 바랍니다.

    만약, Backend.AI를 삭제하려면 Backend.AI 저장소를 복제한 위치에서 scripts/delete-dev.sh 스크립트를 실행하면 됩니다.

    $ cd backend.ai
    $ ./scripts/delete-dev.sh 
    

    컨트리뷰션 전에 알아야 할 사항

    대부분의 분산 버전 관리 시스템에서 관리되는 프로젝트와 마찬가지로, Backend.AI 에 기여하기 위해서는 원본 원격 저장소의 main 브랜치의 가장 최신 커밋 기준으로 코드 작업이 이뤄져야 하며, 충돌이 발생하는 경우에는 리뷰를 요청하기 전에 해결되어야 합니다. 원본 저장소를 fork 한 경우, 현재 본인이 fork 한 원본 저장소와 실제 원본 저장소가 동기화되어야 합니다.

    방법 안내 전 이해를 돕기 위해 아래 정리한 명칭을 참고해주세요.

    • 원본 원격 저장소(upstream): Backend.AI 원본 저장소. 모든 주요 커밋 내용이 반영됨.
    • fork 한 원본 저장소(origin): GitHub을 통해 "내" 계정으로 복사해온 Backend.AI 저장소. (주의: 원본 원격 저장소 != fork 한 원본 저장소)
    • 코드 복사본(local working copy): 현재 본인의 로컬 머신에 내려 받은 fork 된 저장소

    Git 명령의 브랜치 표기

    • main: 현재 local working copy의 main 브랜치
    • origin/main: 내가 local working copy를 만들기 위해 clone을 수행해온 저장소(origin)의 main 브랜치
    • upstream/main: 별도로 추가한 upstream 원격 저장소에 속한 main 브랜치

    작업 흐름 개념

    • fork 하는 시점에 origin/main 이 만들어짐
    • fork 한 저장소를 clone하면 내 작업 컴퓨터에 main 이 만들어짐
    • main 으로부터 새로운 topic branch를 만들어 작업 진행
    • 이 작업 branch를 origin에 올리고 PR을 생성하면 GitHub이 알아서 fork 의 원본 저장소를 가리키도록 해줌
    • 이때, 원본 저장소의 main 이 변경된 것을 작업 도중 동기화해오려면 아래의 절차를 따름

    동기화 하는 방법은 다음과 같습니다.

    • step1: upstream 이라는 이름으로 원본 원격 저장소 추가하기
    $ git remote add upstream https://github.com/lablup/backend.ai
    
    • step2: 원본 원격저장소의 main 브랜치의 최신 커밋을 코드 복사본(local working copy)으로 가져오기
    $ git fetch upstream
    
    • step3: 원본 원격저장소의 main 브랜치 최신 커밋 반영 내역을 origin(본인이 fork 한 원본 저장소의 코드 복사본(local working copy))로 가져오기
    $ git switch main && git merge --ff upstream/main
    
    • step4: step 1 ~ 3에서 진행된 코드 복사본(local working copy)의 변경 내역을 origin(본인이 fork 한 원본 저장소의 원격 저장소)에 반영하기
    $ git push origin main
    

    이제 upstream/mainorigin/mainmain을 거쳐 동기화된 것입니다.

    • step5: 작업 중인 내 브랜치에 최신 업데이트 반영하기
    $ git switch topic
    $ git merge main
    

    이 과정을 수행할 때 origin/mainupstream/main 간에 history 분기가 생긴 상태에서 5번 절차를 잘못 수행하면 굉장히 복구하기 까다로워질 수 있습니다. 또한, Backend.AI에서 사용하는 CI 도구들이 PR을 테스트할 때 upstream/mainorigin/topic 사이의 차이점을 보기 위해 공통 조상 커밋을 찾게 되어 있는데 topic 브랜치를 main 이름을 재활용하는 경우 그러한 도구들이 제대로 동작하지 않게 됩니다. 가능하면 새로운 분기를 만들 때는 항상 새로운 이름을 붙여준다고 생각하면 됩니다.

    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)
      • 커밋 메시지는 영어로 작성해야 합니다.
    • 브랜치를 push하고 PR을 작성합니다.
      • 별도 이슈가 있는 PR의 경우 PR 본문에 해당 이슈 번호를 적어주어야 합니다. 만약, 저장소의 이슈를 참조하려면, 다음의 이슈 링크의 https://github.com/lablup/backend.ai/issues/401 숫자를 보고, #401과 같은 형식으로 적으면 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와 같은 파일을 참고하면 됩니다.
    • 리뷰 과정을 진행합니다.
      • 완료되면 보통 squash-merge 형태로 리뷰어가 커밋 로그를 정리하여 하나의 단일 커밋으로 만들어 병합하게 됩니다.
      • 따라서 리뷰 과정에서 자잘한 수정 커밋을 자주 만드는 것에 부담을 가지지 않고 자유롭게 생각날 때마다 커밋을 만들어주시면 됩니다.

    GitHub CLI, SourceTree, GitKraken과 같은 도구들을 git 명령어와 함께 활용하면 더욱 좋습니다.

    정리

    지금까지 Backend.AI의 전체적인 컴포넌트 구조와 저장소 구조, 개발환경 설치 방법, 그리고 pull request 작성 요령을 살펴보았습니다. 이 가이드가 Backend.AI 소스코드에 한 발짝 더 다가갈 수 있도록 도움이 되었으면 좋겠습니다.


    [1]: "editable" 설치란 Python 패키지를 소스 디렉토리를 직접 바라보도록 설치하여 site-packages 디렉토리 내부를 편집하지 않고 소스 디렉토리를 수정하는 것만으로도 해당 패키지를 import 시 변경 내용이 바로 반영되어 있도록 하는 설치 방법을 말합니다.

    10 July 2024

도움이 필요하신가요?

내용을 작성해 주시면 곧 연락 드리겠습니다.

문의하기

본사 및 HPC 연구소

서울특별시 강남구 선릉로 577 CR타워 8층

© Lablup Inc. All rights reserved.