GitLab Shell開発ガイドライン

pipeline status coverage report Code Climate

GitLab ShellはGitLabのSSHセッションを処理し、作成者の鍵リストを変更します。GitLab ShellはUnixシェルではなく、BashやZshの代わりでもありません。

GitLabはSSHを通してGit LFS認証をサポートします。

要件

GitLab ShellはGoで書かれており、ビルドにはGoコンパイラが必要です。ビルドとテストにはRubyが必要ですが、実行には必要ありません。

GitLab ShellはOmnibusインストール上のport 22 。通常のSSHサービスを使うには、別のポートに設定してください。

Goの最新バージョンをダウンロードしてインストールしてください。Goのリリースポリシーとサポートに従ってください:

  • 現在の安定バージョン。
  • 過去の2つのメジャーバージョン。

バージョン

GitLab Shellには2つのバージョンファイルがあります:

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.

git pull になります。

graph LR A[Git pull] --> |via SSH| B[gitlab-shell] B -->|API call| C[gitlab-rails<br>authorization] C -->|accept or decline| D[Gitaly session]

git push になります。

git push コマンドは、gitlab-rails がプッシュを受け入れた後でないと実行されません:

graph LR subgraph User initiates A[Git push] -->|via SSH| B[gitlab-shell] end subgraph Gitaly B -->|establish Gitaly session| C[gitlab-shell pre-receive hook] C -->|API auth call| D[Gitlab-rails] D --> E[accept or decline push] 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. testとverifyの両方を実行します(デフォルトの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はその.Git操作に対するそれ以降の接続リクエストをドロップ user + projectします。

レートリミッターはGitコマンド(配管)レベルで適用されます。各コマンドは毎分600のレートリミットがあります。例えば、git push は毎分600、git pull は毎分600です。

これらは同じ配管コマンドを使っているので、git-upload-packgit 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 のフロー図:

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シェルのアーキテクチャ

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: Lookup key 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: Auth check Rails-->>-GitLab Shell: 200 OK, { gitaly: ... } GitLab Shell->>+Gitaly: SSHService.SSHUploadPack request Gitaly->>+Git on server: git upload-pack request Note over Git on client,Git on server: Bidirectional communication between Git client and server Git on server-->>-Gitaly: git upload-pack response Gitaly -->>-GitLab Shell: SSHService.SSHUploadPack response GitLab Shell-->>-SSH server: gitlab-shell upload-pack response SSH server-->>-Git on client: ssh git fetch-pack response