GitLab Shell 개발 지침

파이프라인 상태 커버리지 보고서 Code Climate

GitLab Shell은 GitLab을 위한 Git SSH 세션을 처리하고, 인증된 키 목록을 수정합니다.

GitLab Shell은 Unix 셸이 아니며, Bash나 Zsh의 대체물이 아닙니다.

GitLab은 SSH를 통해 Git LFS 인증을 지원합니다.

요구 사항

GitLab Shell은 Go로 작성되었으며, 빌드를 위해 Go 컴파일러가 필요합니다.

여전히 빌드 및 테스트를 위해 Ruby가 필요하지만, 실행하는 데는 필요하지 않습니다.

GitLab Shell은 Omnibus 설치에서 22번 포트에서 실행됩니다. 일반 SSH 서비스를 사용하려면 대체 포트에서 구성합니다.

현재 버전의 Go를 다운로드 및 설치하세요.

우리는 Go 릴리즈 정책을 따르며 다음을 지원합니다:

  • 현재 안정 버전.
  • 이전 두 개의 주요 버전.

버전

GitLab Shell과 관련된 두 개의 버전 파일:

GitLab 팀원들은 #announcements 내부 Slack 채널에서 모니터링할 수도 있습니다.

GitLab Shell 작동 방식

SSH를 통해 GitLab 서버에 접근하면, GitLab Shell은 다음과 같이 진행합니다:

  1. 미리 정의된 Git 명령어(git push, git pull, git fetch)로 제한합니다.

  2. GitLab Rails API를 호출하여 당신이 권한이 있는지, 그리고 당신의 리포지토리가 어떤 Gitaly 서버에 있는지 확인합니다.

  3. SSH 클라이언트와 Gitaly 서버 간에 데이터를 주고받습니다.

HTTP(S)를 통해 GitLab 서버에 접근하면 gitlab-workhorse로 연결됩니다.

SSH를 통해 git pull

%%{init: { "fontFamily": "GitLab Sans" }}%% graph LR A[Git pull] --> |via SSH| B[gitlab-shell] B -->|API 호출| C[gitlab-rails<br>인증] C -->|수락 또는 거부| D[Gitaly 세션]

SSH를 통해 git push

git push 명령은 gitlab-rails가 푸시를 수락한 후에 수행됩니다:

%%{init: { "fontFamily": "GitLab Sans" }}%% graph LR subgraph 사용자가 시작 A[Git push] -->|via SSH| B[gitlab-shell] end subgraph Gitaly B -->|Gitaly 세션 설정| C[gitlab-shell pre-receive hook] C -->|API 인증 호출| D[Gitlab-rails] D --> E[푸시 수락 또는 거부] end

전체 기능 목록

authorized_keys 수정

GitLab Shell은 클라이언트 머신의 authorized_keys 파일을 수정합니다.

GitLab Shell에 기여하기

GitLab Shell에 기여하려면:

  1. GitLab API 접근과 내부 API와의 Redis 연결이 가능한지 확인하세요: make check

  2. gitlab-shell 바이너리를 컴파일하고 bin/에 배치하세요: make compile

  3. make install을 실행하여 gitlab-shell 바이너리를 빌드하고 파일 시스템에 설치하세요.
    기본 위치는 /usr/local입니다. 이를 변경하려면 PREFIXDESTDIR 환경 변수를 설정하세요.

  4. 단일 머신에서 소스에서 GitLab을 설치하려면 make setup을 실행하세요.
    이것은 GitLab Shell 바이너리를 컴파일하고 파일 시스템상의 다양한 경로가 올바른 권한으로 존재하는지 확인합니다.
    설치 방법 문서에서 지시하지 않는 한 이 명령을 실행하지 마세요.

자세한 내용은
CONTRIBUTING.md를 참조하세요.

테스트 실행하기

기여할 때, 테스트를 실행하세요:

  1. bundle installmake test로 테스트를 실행하세요.

  2. Gofmt를 실행하세요: make verify

  3. 테스트와 검증을 함께 실행하세요 (기본 Makefile 대상):

    bundle install
    make validate
    
  4. 필요하다면 Gitaly를 구성하세요.

로컬 테스트를 위한 Gitaly 구성

일부 테스트는 Gitaly 서버가 필요합니다.
docker-compose.yml 파일은 포트 8075에서 Gitaly를 실행합니다.
테스트에 Gitaly의 위치를 알려주려면 GITALY_CONNECTION_INFO를 설정하세요:

export GITALY_CONNECTION_INFO='{"address": "tcp://localhost:8075", "storage": "default"}'
make test

GITALY_CONNECTION_INFO가 설정되지 않은 경우, 테스트 모듈은 여전히 실행되지만 Gitaly가 필요한 테스트는 건너뜁니다.
테스트는 항상 CI 환경에서 실행됩니다.

속도 제한

GitLab Shell은 Git 작업을 위해 사용자 계정과 프로젝트별로 속도 제한을 수행합니다.
GitLab Shell은 Git 작업 요청을 수락한 후 Redis에 의해 지원되는 Rails 속도 제한기에 호출을 합니다.
user + project가 속도 제한을 초과하면, GitLab Shell은 해당 user + project에 대한 추가 연결 요청을 거부합니다.

속도 제한기는 Git 명령 (plumbing) 수준에서 적용됩니다. 각 명령은 분당 600의 속도 제한이 있습니다.
예를 들어, git push는 분당 600, git pull은 또 다른 600입니다.

같은 plumbing 명령인 git-upload-pack을 사용하기 때문에, git pullgit clone은 속도 제한을 위한 명령으로 사실상 동일합니다.

Gitaly에도 속도 제한기가 설정되어 있지만, GitLab Shell에서 속도 제한이 초과되면 Gital리에 호출이 이루어지지 않습니다.

GitLab Shell의 로그

일반적으로, 로그를 검사하여 GitLab Shell 또는 gitlab-sshd 세션의 구조는 파악할 수 있지만, 내용은 파악할 수 없습니다. 몇 가지 지침:

  • 우리는 로깅을 위해 gitlab.com/gitlab-org/labkit/log 을 사용합니다.

  • 항상 상관 ID를 포함하세요.

  • 로그 메시지는 불변하고 고유해야 합니다. 부가 정보는 log.WithField, log.WithFields, 또는 log.WithError를 사용하여 필드에 포함하세요.

  • 성공적인 사례와 오류 사례 모두를 기록하세요.

  • 너무 많은 로그는 부족한 로그보다 나은 경우가 많습니다. 메시지가 너무 장황하게 보인다면, 메시지를 제거하기 전에 로그 수준을 줄이는 것을 고려하세요.

GitLab SaaS

GitLab.com의 gitlab-shell 흐름 다이어그램:

%%{init: { "fontFamily": "GitLab Sans" }}%% graph LR a2 --> b2 a2 --> b3 a2 --> b4 b2 --> c1 b3 --> c1 b4 --> c1 c2 --> d1 c2 --> d2 c2 --> d3 d1 --> e1 d2 --> e1 d3 --> e1 a1[Cloudflare] --> a2[TCP<br/> load balancer] e1[Git] subgraph HAProxy Fleet b2[HAProxy] b3[HAProxy] b4[HAProxy] end subgraph GKE c1[Internal TCP<br/> load balancer<br/>port 2222] --> c2[GitLab-shell<br/> pods] end subgraph Gitaly d1[Gitaly] d2[Gitaly] d3[Gitaly] end

GitLab Shell 아키텍처

%%{init: { "fontFamily": "GitLab Sans" }}%% sequenceDiagram participant Git on client participant SSH server participant AuthorizedKeysCommand participant GitLab Shell participant Rails participant Gitaly participant Git on server Note left of Git on client: git fetch Git on client->>+SSH server: ssh git fetch-pack request SSH server->>+AuthorizedKeysCommand: gitlab-shell-authorized-keys-check git AAAA... AuthorizedKeysCommand->>+Rails: GET /internal/api/authorized_keys?key=AAAA... Note right of Rails: 키 ID 조회 Rails-->>-AuthorizedKeysCommand: 200 OK, command="gitlab-shell upload-pack key_id=1" AuthorizedKeysCommand-->>-SSH server: command="gitlab-shell upload-pack key_id=1" SSH server->>+GitLab Shell: gitlab-shell upload-pack key_id=1 GitLab Shell->>+Rails: GET /internal/api/allowed?action=upload_pack&key_id=1 Note right of Rails: 인증 확인 Rails-->>-GitLab Shell: 200 OK, { gitaly: ... } GitLab Shell->>+Gitaly: SSHService.SSHUploadPack 요청 Gitaly->>+Git on server: git upload-pack 요청 Note over Git on client,Git on server: Git 클라이언트와 서버 간의 양방향 통신 Git on server-->>-Gitaly: git upload-pack 응답 Gitaly -->>-GitLab Shell: SSHService.SSHUploadPack 응답 GitLab Shell-->>-SSH server: gitlab-shell upload-pack 응답 SSH server-->>-Git on client: ssh git fetch-pack 응답

관련 주제