GitLab Shell 개발 가이드라인

pipeline status coverage report Code Climate

GitLab Shell은 GitLab의 Git SSH 세션을 처리하고 인증된 키 디렉터리을 수정합니다. GitLab Shell은 Unix 셸이나 Bash 또는 Zsh 대체가 아닙니다.

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

요구 사항

GitLab Shell은 Go로 작성되었으며 Go 컴파일러가 필요합니다. 여전히 빌드하고 테스트하기 위해 Ruby가 필요하지만 실행에는 필요하지 않습니다.

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

현재 버전의 Go을 다운로드하고 설치하세요. 우리는 Go 릴리스 정책을 따르며 다음을 지원합니다:

  • 현재 안정 버전
  • 이전 두 대 버전

버전

GitLab Shell과 관련된 두 가지 버전 파일이 있습니다:

GitLab 팀 멤버들은 내부 Slack 채널 #announcements를 모니터링할 수 있습니다.

GitLab Shell 작동 방식

SSH를 통해 GitLab 서버에 액세스하면 GitLab Shell이 다음을 수행합니다:

  1. 미리 정의된 Git 명령(git push, git pull, git fetch)으로 제한합니다.
  2. 권한이 있는지 및 리포지터리가 있는 Gitaly 서버를 GitLab Rails API를 호출하여 확인합니다.
  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 사전 수신 후크] 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. bin/gitlab-shell 이진 파일을 컴파일: 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 파일은 Gitaly를 8075 포트에서 실행합니다. 테스트에 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 작업 요청을 받은 후 Rails의 요율 제한기를 호출하여 사용자 + 프로젝트가 요율을 초과하면 해당 사용자 + 프로젝트의 추가 연결 요청을 삭제합니다.

요율 제한은 Git 명령(plumbing) 수준에서 적용됩니다. 각 명령에는 분당 600개의 요율 제한이 있습니다. 예를 들어 git push는 분당 600개이고 git pull은 다른 600개가 있습니다.

이들은 동일한 plumbing 명령을 사용하므로 git-upload-pack, git pullgit clone은 요율 제한을 위해 실제로 동일한 명령입니다.

Gitaly에도 요율 제한기가 있지만 GitLab Shell(Rails)에서 요율 제한을 초과하면 Gitaly로 호출을 수행하지 않습니다.

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/> 로드 밸런서] e1[Git] subgraph HAProxy Fleet b2[HAProxy] b3[HAProxy] b4[HAProxy] end subgraph GKE c1[내부 TCP<br/> 로드 밸런서<br/>포트 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 participant SSH 서버 participant AuthorizedKeysCommand participant GitLab Shell participant Rails participant Gitaly participant 서버의 Git Note left of 클라이언트의 Git: git fetch 클라이언트의 Git->>+SSH 서버: ssh git fetch-pack 요청 SSH 서버->>+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 서버: command="gitlab-shell upload-pack key_id=1" SSH 서버->>+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: git upload-pack 요청 Note over 클라이언트의 Git,서버의 Git: Git 클라이언트와 서버 간 양방향 통신 서버의 Git-->>-Gitaly: git upload-pack 응답 Gitaly -->>-GitLab Shell: SSHService.SSHUploadPack 응답 GitLab Shell-->>-SSH 서버: gitlab-shell upload-pack 응답 SSH 서버-->>-클라이언트의 Git: ssh git fetch-pack 응답

관련 주제