Help us learn about your current experience with the documentation. Take the survey.

GitLab Shell 开发指南

GitLab Shell 处理 GitLab 的 Git SSH 会话,并修改授权密钥列表。 GitLab Shell 不是 Unix shell,也不是 Bash 或 Zsh 的替代品。

GitLab 通过 SSH 支持 Git LFS 认证。

要求

GitLab Shell 使用 Go 语言编写,需要 Go 编译器来构建。它仍然需要 Ruby 来构建和测试,但运行时不需要。

在 Linux 包安装中,GitLab Shell 运行在 端口 22。要使用常规 SSH 服务,请在其他端口上配置它。

下载并安装 Go 的当前版本。 我们遵循 Go 发布策略 并支持:

  • 当前稳定版本。
  • 前两个主要版本。

版本

与 GitLab Shell 相关的两个版本文件:

GitLab 团队成员也可以监控 #announcements 内部 Slack 频道。

GitLab Shell 工作原理

当您通过 SSH 访问 GitLab 服务器时,GitLab Shell 会:

  1. 将您限制在预定义的 Git 命令(git pushgit pullgit 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 call| C[gitlab-rails<br>authorization]
    C -->|accept or decline| D[Gitaly session]

通过 SSH 执行 git push

gitlab-rails 接受推送之前,不会执行 git push 命令:

%%{init: { "fontFamily": "GitLab Sans" }}%%
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. 运行测试和验证(默认 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 操作请求,然后调用 Rails 速率限制器,该限制器由 Redis 支持。如果 用户 + 项目 超过速率限制, 那么 GitLab Shell 将丢弃该 用户 + 项目 的后续连接请求。

速率限制器应用于 Git 命令(plumbing)级别。每个命令每分钟 有 600 次的速率限制。例如,git push 每分钟 600 次, git pull 每分钟另外 600 次。

因为它们使用相同的 plumbing 命令,git-upload-packgit pullgit clone 在速率限制方面实际上是同一个命令。

Gitaly 也有速率限制器,但如果 GitLab Shell(Rails)中的速率限制被超过,则永远不会调用 Gitaly。

GitLab Shell 中的日志

通常,通过检查日志,您可以确定 GitLab Shell 或 gitlab-sshd 会话的结构,但不能确定其内容。一些指导原则:

  • 我们使用 gitlab.com/gitlab-org/labkit/log 进行日志记录。
  • 始终包含关联 ID。
  • 日志消息应该是不可变且唯一的。使用 log.WithFieldlog.WithFieldslog.WithError 将辅助信息包含在字段中。
  • 同时记录成功和错误情况。
  • 记录过多比记录不足更好。如果消息看起来过于 冗长,请考虑在删除消息之前降低日志级别。

GitLab SaaS

gitlab-shell 在 GitLab.com 上的流程图:

%%{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: 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

相关主题