Geo프록시

Geo프록시를 사용하면 이제 보조 시스템에서 웹 요청을 주 프라이머리(primary)를 통해 Workhorse를 경유하여 프록시하므로, 보조 시스템으로 이동하는 사용자는 읽기-쓰기 UI를 보고, 주 프라이머리에서 할 수 있는 모든 작업을 수행할 수 있습니다.

요청 수명주기

최상위 수준 뷰

프록시 상호작용은 다음 다이어그램을 통해 고수준에서 설명할 수 있습니다.

sequenceDiagram actor client participant secondary participant primary client->>secondary: GET /explore secondary-->>primary: GET /explore (proxied) primary-->>secondary: HTTP/1.1 200 OK [..] secondary->>client: HTTP/1.1 200 OK [..]

프록시 검색 메커니즘

Geo프록시가 활성화되면 프라이머리로 요청을 프록시해야 하는지 여부 및 프라이머리의 URL(데이터베이스에 저장된대로)를 알기 위해 Workhorse는 내부 API를 주기적으로 확인합니다. 프록시를 활성화해야 하는 경우 내부 API는 프라이머리 URL 및 JWT로 서명된 데이터를 응답하여 모든 요청에 대해 프라이머리로 전달합니다.

sequenceDiagram participant W as Workhorse (secondary) participant API as Internal Rails API W->API: GET /api/v4/geo/proxy (internal) loop 10초마다 폴링 API-->W: {geo_proxy_primary_url, geo_proxy_extra_data}, 구성 업데이트 end

깊이 있는 요청 흐름 및 프록시와 로컬 데이터 가속

구현을 상세하게 설명하면, 요청된 보조 시스템의 Workhorse는 데이터를 프록시할지 여부를 결정합니다. 데이터 유형을 로컬로 제공할 수 있는 경우(라운드트립 요청을 저장할 수 있는 경우), 데이터를 즉시 반환합니다. 그렇지 않으면, 트래픽이 주 프라이머리의 내부 URL로 전송되며, 주 프라이머리의 Workhorse에서 정확히 직접 요청과 동일하게 제공됩니다. 그런 다음 응답은 동일한 연결에서 보조 시스템의 Workhorse를 통해 사용자에게 다시 프록시됩니다.

flowchart LR A[Client]--->W1["Workhorse (secondary)"] W1 --> W1C[로컬로 데이터 제공?] W1C -- "예" ----> W1 W1C -- "아니요 (프록시)" ----> W2["Workhorse (primary)"] W2 --> W1 ----> A

로그인

프라이머리에 프록시된 인증 필요한 요청

sequenceDiagram autoNumber participant Client participant Secondary participant Primary Client->>Secondary: `/group/project` 요청 Secondary->>Primary: 프록시 /group/project opt 프라이머리가 로그인되어 있지 않음 Primary-->>Secondary: 302 리디렉트 Secondary-->>Client: 프록시 302 리디렉트 Client->>Secondary: /users/sign_in Secondary->>Primary: 프록시 /users/sign_in Note right of Primary: 인증이 발생, 동일한 URL로 POST 등 Primary-->>Secondary: 302 리디렉트 Secondary-->>Client: 프록시 302 리디렉트 Client->>Secondary: /group/project Secondary->>Primary: 프록시 /group/project end Primary-->>Secondary: /group/project 로그인 응답 (프라이머리에서 세션 생성됨) Secondary-->>Client: 전체 응답을 프록시

Git pull

역사적인 이유로 push_from_secondary 경로를 통해 Git pull을 전달하는 데 사용됩니다. 혼란을 피하기 위해 이 경로의 이름을 바꾸는 문제가 있습니다.

HTTP(s)를 통한 Git pull

가속된 리포지터리

보조 시스템에서 리포지터리가 존재하고 주 프라이머리와 동기화되었다고 감지되면, 프록시하는 대신 해당 리포지터리를 직접 제공합니다.

sequenceDiagram participant C as Git client participant Wsec as "Workhorse (secondary)" participant Rsec as "Rails (secondary)" participant Gsec as "Gitaly (secondary)" C->>Wsec: GET /foo/bar.git/info/refs/?service=git-upload-pack Wsec->>Rsec: <내부 API 확인> note over Rsec: 리포지터리가 동기화되어 있고 최신 상태임을 결정 Rsec-->>Wsec: 401 Unauthorized Wsec-->>C: <응답> C->>Wsec: GET /foo/bar.git/info/refs/?service=git-upload-pack Wsec->>Rsec: <내부 API 확인> Rsec-->>Wsec: Workhorse OK 렌더링 Wsec-->>C: 200 OK C->>Wsec: POST /foo/bar.git/git-upload-pack Wsec->>Rsec: GitHttpController#git_receive_pack Rsec-->>Wsec: Workhorse OK 렌더링 Wsec->>Gsec: Workhorse가 Rails로부터 연결 세부 정보를 받아 Gitaly에 연결: SmartHTTP Service, UploadPack RPC (세부 내용은 프로토를 확인하세요) Gsec-->>Wsec: 프로토 메시지의 스트림 반환 Wsec-->>C: Git 클라이언트로 메시지 전달

프록시된 리포지터리

요청된 리포지터리가 동기화되지 않은 경우 또는 최신 상태가 아닌 것으로 감지되면, 최신 변경 내용을 가져오기 위해 요청이 주 프라이머리로 프록시됩니다.

sequenceDiagram participant C as Git client participant Wsec as "Workhorse (secondary)" participant Rsec as "Rails (secondary)" participant W as "Workhorse (primary)" participant R as "Rails (primary)" participant G as "Gitaly (primary)" C->>Wsec: GET /foo/bar.git/info/refs/?service=git-upload-pack Wsec->>Rsec: <응답> note over Rsec: 리포지터리가 최신 상태가 아님을 결정 Rsec-->>Wsec: /-/push_from_secondary/2/foo/bar.git/info/refs?service=git-upload-pack로 302 리디렉트 Wsec-->>C: <응답> C->>Wsec: GET /-/push_from_secondary/2/foo/bar.git/info/refs/?service=git-upload-pack Wsec->>W: <프록시된 요청> W->>R: <데이터> R-->>W: 401 Unauthorized W-->>Wsec: <프록시된 응답> Wsec-->>C: <응답> C->>Wsec: GET /-/push_from_secondary/2/foo/bar.git/info/refs/?service=git-upload-pack note over W: 프록시됨 Wsec->>W: <프록시된 요청> W->>R: <데이터> R-->>W: Workhorse OK 렌더링 W-->>Wsec: <프록시된 응답> Wsec-->>C: <응답> C->>Wsec: POST /-/push_from_secondary/2/foo/bar.git/git-upload-pack Wsec->>W: <프록시된 요청> W->>R: GitHttpController#git_receive_pack R-->>W: Workhorse OK 렌더링 W->>G: Workhorse가 Rails로부터 연결 세부 정보를 받아 Gitaly에 연결: SmartHTTP Service, UploadPack RPC (세부 내용은 프로토를 확인하세요) G-->>W: 프로토 메시지의 스트림 반환 W-->>Wsec: Git 클라이언트로부터 메시지를 전달 Wsec-->>C: Git로부터의 파이프 메시지 반환

SSH를 통한 Git pull

SSH 작업은 Workhorse 요청을 위한 메커니즘을 통해 프록시되지 않고, GitLab Shell을 통해 SSH 작업이 Git HTTP 요청으로 보조 시스템에서 주 프라이머리로 프록시됩니다.

가속된 리포지터리

보조 시스템에 리포지터리가 존재하고 주 프라이머리와 동기화되었다고 감지되면, 해당 리포지터리를 직접 제공합니다.

sequenceDiagram participant C as Git client participant S as GitLab Shell (secondary) participant I as Internal API (secondary Rails) participant G as Gitaly (secondary) C->>S: git pull S->>I: SSH 키 유효성 검사 (api/v4/internal/authorized_keys?key=..) I-->>S: HTTP/1.1 200 OK S->>G: InfoRefs:UploadPack RPC G-->>S: Git 응답 스트림 반환 S-->>C: Git 응답 스트림 반환 C-->>S: Push할 Git 데이터의 스트림 S->>G: UploadPack RPC G-->>S: Git 응답 스트림 반환 S-->>C: Git 응답 스트림 반환

프록시된 리포지터리

요청된 리포지터리가 동기화되지 않았거나 최신 상태가 아닌 것으로 감지되면, 최신 변경 사항을 가져오기 위해 요청이 기본 리포지터리로 프록시됩니다.

sequenceDiagram participant C as Git client participant S as GitLab Shell (secondary) participant I as Internal API (secondary Rails) participant P as Primary API C->>S: git pull S->>I: SSH 키 유효성 검사 (api/v4/internal/authorized_keys?key=..) I-->>S: HTTP/1.1 300 (custom action status) with {endpoint, msg, primary_repo} S->>I: POST /api/v4/geo/proxy_git_ssh/info_refs_upload_pack I->>P: POST $PRIMARY/foo/bar.git/info/refs/?service=git-upload-pack P-->>I: HTTP/1.1 200 OK I-->>S: <response> S-->>C: 프라이머리로부터의 Git 응답 반환 C-->>S: 푸시하기 위해 Git 데이터 스트림 S->>I: POST /api/v4/geo/proxy_git_ssh/upload_pack I->>P: POST $PRIMARY/foo/bar.git/git-upload-pack P-->>I: HTTP/1.1 200 OK I-->>S: <response> S-->>C: 프라이머리로부터의 Git 응답 반환

Git 푸시

SSH를 통한 Git 푸시

SSH 작업은 Workhorse 대신 GitLab Shell을 통해 수행되므로 Workhorse 요청에 사용되는 메커니즘을 통해 프록시되지 않습니다. SSH 작업의 경우, 2차 Rails 내부 API에서 프라이머리 사이트로 Git HTTP 요청으로 프록시됩니다.

sequenceDiagram participant C as Git client participant S as GitLab Shell (secondary) participant I as Internal API (secondary Rails) participant P as Primary API C->>S: git push S->>I: SSH 키 유효성 검사 (api/v4/internal/authorized_keys?key=..) I-->>S: HTTP/1.1 300 (custom action status) with {endpoint, msg, primary_repo} S->>I: POST /api/v4/geo/proxy_git_ssh/info_refs_receive_pack I->>P: POST $PRIMARY/foo/bar.git/info/refs/?service=git-receive-pack P-->>I: HTTP/1.1 200 OK I-->>S: <response> S-->>C: 프라이머리로부터의 Git 응답 반환 C-->>S: 푸시하기 위해 Git 데이터 스트림 S->>I: POST /api/v4/geo/proxy_git_ssh/receive_pack I->>P: POST $PRIMARY/foo/bar.git/git-receive-pack P-->>I: HTTP/1.1 200 OK I-->>S: <response> S-->>C: 프라이머리로부터의 Git 응답 반환

HTTP(S)를 통한 Git 푸시

요청된 리포지터리가 동기화되지 않았거나 최신 상태가 아닌 것으로 감지되면, 요청은 프라이머리로 프록시되며, 푸시는 /-/push_from_secondary/$SECONDARY_ID/*로 형식화된 로컬 경로로 리디렉션이 됩니다. 이 경로를 통한 요청은 프라이머리로 프록시되어 푸시를 처리합니다.

sequenceDiagram participant C as Git client participant Wsec as Workhorse (secondary) participant W as Workhorse (primary) participant R as Rails (primary) participant G as Gitaly (primary) C->>Wsec: GET /foo/bar.git/info/refs/?service=git-receive-pack Wsec->>C: 302 Redirect to /-/push_from_secondary/2/foo/bar.git/info/refs?service=git-receive-pack C->>Wsec: GET /-/push_from_secondary/2/foo/bar.git/info/refs/?service=git-receive-pack Wsec->>W: <프록시된 요청> W->>R: <데이터> R-->>W: 401 Unauthorized W-->>Wsec: <프록시된 응답> Wsec-->>C: <response> C->>Wsec: GET /-/push_from_secondary/2/foo/bar.git/info/refs/?service=git-receive-pack Wsec->>W: <프록시된 요청> W->>R: <데이터> R-->>W: Render Workhorse OK W-->>Wsec: <프록시된 응답> Wsec-->>C: <response> C->>Wsec: POST /-/push_from_secondary/2/foo/bar.git/git-receive-pack Wsec->>W: <프록시된 요청> W->>R: GitHttpController:git_receive_pack R-->>W: Render Workhorse OK W->>G: Rails에서 연결 세부 정보 가져와 SmartHTTP 서비스에 연결, ReceivePack RPC G-->>W: 프로토 메시지의 스트림 반환 W-->>Wsec: Git 클라이언트로부터의 메시지 전달 Wsec-->>C: Git으로부터의 메시지 반환