Zoekt 문제 해결
GitLab v19.5Offering: GitLab.com, GitLab Self-Managed
요약
Zoekt를 사용할 때 다음과 같은 문제가 발생할 수 있습니다. 오류를 진단할 때 Zoekt 구성 요소가 어떻게 상호 작용하는지 이해하려면 코드 검색에 Zoekt 사용을 참고합니다. 예비 디버깅을 위해 다음을 확인합니다:
Zoekt를 사용할 때 다음과 같은 문제가 발생할 수 있습니다.
오류를 진단할 때 Zoekt 구성 요소가 어떻게 상호 작용하는지 이해하려면 코드 검색에 Zoekt 사용을 참고합니다. 이 설계 문서는 어떤 구성 요소가 어떤 구성 요소를 호출하는지, 각 구성 요소가 어떤 콘텐츠를 보유하는지를 포함해 전체 아키텍처를 설명합니다.
예비 디버깅을 위해 다음을 확인합니다:
네임스페이스가 인덱싱되지 않음#
설정을 활성화하면 새 네임스페이스가 자동으로 인덱싱됩니다.
네임스페이스가 자동으로 인덱싱되지 않는 경우 Sidekiq 로그를 확인해 작업이 처리되고 있는지 점검합니다.
Search::Zoekt::SchedulingWorker가 네임스페이스 인덱싱을 담당합니다.
Rails 콘솔 세션에서 다음을 확인할 수 있습니다:
-
Zoekt가 활성화되지 않은 네임스페이스:
Namespace.group_namespaces.root_namespaces_without_zoekt_enabled_namespace -
Zoekt 인덱스 상태:
Search::Zoekt::Index.all.pluck(:state, :namespace_id)
네임스페이스를 수동으로 인덱싱하려면 인덱싱 설정을 참고합니다.
오류: SilentModeBlockedError#
정확한 코드 검색을 실행하려고 할 때 SilentModeBlockedError가 발생할 수 있습니다.
이 문제는 GitLab 인스턴스에서 침묵 모드가 활성화된 경우 발생합니다.
이 문제를 해결하려면 침묵 모드가 비활성화되어 있는지 확인합니다.
오류: connections to all backends failing#
application_json.log에서 다음과 같은 오류가 발생할 수 있습니다:
connections to all backends failing; last error: UNKNOWN: ipv4:1.2.3.4:5678: Trying to connect an http1.x server
이 문제를 해결하려면 프록시를 사용하고 있는지 확인합니다.
사용하고 있다면 GitLab 서버의 IP 주소를 no_proxy에 설정합니다:
gitlab_rails['env'] = {
"http_proxy" => "http://proxy.domain.com:1234",
"https_proxy" => "http://proxy.domain.com:1234",
"no_proxy" => ".domain.com,IP_OF_GITLAB_INSTANCE,127.0.0.1,localhost"
}
proxy.domain.com:1234는 프록시 인스턴스의 도메인과 포트입니다.
IP_OF_GITLAB_INSTANCE는 GitLab 인스턴스의 공개 IP 주소를 가리킵니다.
ip a를 실행하고 다음 중 하나를 확인해 이 정보를 얻을 수 있습니다:
- 해당 네트워크 인터페이스의 IP 주소
- 사용 중인 로드 밸런서의 공개 IP 주소
메모리 부족 오류#
Zoekt 노드는 검색이나 인덱싱 중 메모리가 부족해질 수 있습니다. 메모리 부족(OOM) 오류는 웹 서버에서 발생할 가능성이 더 높습니다. 웹 서버는 검색을 처리하면서 인덱스 샤드를 물리 메모리에 메모리 매핑하므로, 상주 메모리는 인덱스 크기와 쿼리 볼륨에 따라 증가합니다. OOM 오류의 증상과 필요한 복구 단계는 두 구성 요소 사이에 차이가 있습니다. 자세한 내용은 메모리 아키텍처를 참고합니다.
메모리 부족 이벤트 감지#
Kubernetes 배포에서는 컨테이너가 OOM 오류로 종료되었는지 확인합니다:
kubectl describe pod <your_pod_name> -n <your_namespace>
Last State 섹션에서 OOMKilled와 0이 아닌 Exit Code(일반적으로 137)를 찾습니다:
Last State: Terminated
Reason: OOMKilled
Exit Code: 137
모든 Zoekt 포드의 재시작 횟수도 확인할 수 있습니다:
kubectl get pods -n <your_namespace> -l app=gitlab-zoekt
포드의 RESTARTS 횟수가 높으면 OOM 종료가 반복되고 있음을 나타냅니다. 레이블 셀렉터
app=gitlab-zoekt는 차트 버전이나 오퍼레이터 구성에 따라 다를 수 있습니다.
kube-state-metrics가 설치되어 있다면 Prometheus나 Grafana에서 다음 메트릭도 모니터링할 수 있습니다:
kube_pod_container_status_last_terminated_reason{reason="OOMKilled"}: OOM으로 종료된 포드입니다.kube_pod_container_status_waiting_reason{reason="CrashLoopBackOff"}: 크래시 루프에 있는 포드입니다.kube_pod_container_status_restarts_total: 컨테이너별 누적 재시작 횟수입니다. 급격히 증가하면 크래시가 반복되고 있음을 나타냅니다.
웹 서버는 포트 6070의 /metrics에서 process_resident_memory_bytes를 노출합니다.
웹 서버 포드를 직접 스크래핑하도록 Prometheus를 구성했다면 이 메트릭으로
시간에 따른 웹 서버 상주 메모리 사용량을 모니터링할 수 있습니다.
VM과 베어 메탈 배포에서는 시스템 저널에서 OOM 이벤트를 확인합니다:
sudo journalctl -k | grep -i "oom\|killed process"
메모리 부족 이벤트에서 복구#
복구 단계는 OOM 오류를 겪는 구성 요소가 무엇인지에 따라 다릅니다.
인덱서 메모리 부족 오류#
인덱서가 OOM 오류로 반복해서 종료되는 경우, 조사하는 동안 모든 노드에서 새 인덱싱 작업을 중지하도록 전역 인덱싱을 일시 중지합니다:
gitlab-rake gitlab:zoekt:pause_indexing
또는 UI에서 인덱싱을 일시 중지합니다:
기본 요구사항:
- 관리자 액세스 권한.
- 오른쪽 상단에서 Admin을 선택합니다.
- 왼쪽 사이드바에서 Settings > Search를 선택합니다.
- Exact code search를 확장합니다.
- Pause indexing 확인란을 선택합니다.
- Save changes를 선택합니다.
노드를 안정화한 후 인덱싱을 재개합니다:
gitlab-rake gitlab:zoekt:resume_indexing
웹 서버 메모리 부족 오류#
웹 서버가 OOM 오류로 반복해서 종료되는 경우, 조사하는 동안 Zoekt 검색을 비활성화합니다. 이렇게 하면 인덱싱에는 영향을 주지 않고 충돌하는 노드로 향하는 검색 트래픽만 중지됩니다.
Zoekt 검색을 비활성화하면 코드 검색은 기본 검색 모드로 전환됩니다. Elasticsearch를 사용할 수 없는 경우 기본 검색 모드에서는 프로젝트 범위 코드 검색만 가능하며, 이로 인해 Gitaly의 부하가 증가합니다.
기본 요구사항:
- 관리자 액세스 권한.
- 오른쪽 상단에서 Admin을 선택합니다.
- 왼쪽 사이드바에서 Settings > Search를 선택합니다.
- Exact code search를 확장합니다.
- Enable searching 확인란을 해제합니다.
- Save changes를 선택합니다.
노드를 안정화한 후 검색을 다시 활성화합니다:
- 오른쪽 상단에서 Admin을 선택합니다.
- 왼쪽 사이드바에서 Settings > Search를 선택합니다.
- Exact code search를 확장합니다.
- Enable searching 확인란을 선택합니다.
- Save changes를 선택합니다.
메모리 압력 줄이기#
노드 크기가 올바르게 설정되어 있는데도 메모리 압력이 계속 발생하는 경우 다음 설정을 조정해 메모리 사용량을 줄입니다.
병렬 인덱싱 프로세스 줄이기#
기본 요구사항:
- 관리자 액세스 권한.
인덱서의 피크 메모리를 줄이려면 인덱싱 태스크당 병렬 프로세스 수를 낮춥니다:
- 오른쪽 상단에서 Admin을 선택합니다.
- 왼쪽 사이드바에서 Settings > Search를 선택합니다.
- Exact code search를 확장합니다.
- Number of parallel processes per indexing task를
1로 설정합니다. - Save changes를 선택합니다.
동시 인덱싱 태스크 줄이기#
기본 요구사항:
- 관리자 액세스 권한.
동시에 실행되는 인덱싱 태스크 수를 줄이려면 Indexing CPU to tasks multiplier 값을 낮춥니다:
- 오른쪽 상단에서 Admin을 선택합니다.
- 왼쪽 사이드바에서 Settings > Search를 선택합니다.
- Exact code search를 확장합니다.
- Indexing CPU to tasks multiplier 값을 낮춥니다(예:
0.5). - Save changes를 선택합니다.
강제 재인덱싱 확률 높이기#
Zoekt 웹 서버는 인덱스 샤드를 메모리 매핑합니다. 시간이 지나면서 증분 인덱싱은 작은 샤드를 다수 누적시켜 열려 있는 mmap 핸들 수를 늘립니다. 강제 재인덱싱은 인덱스를 완전히 재구성해 샤드를 더 적고 더 큰 파일로 통합하며, 그 결과 메모리 오버헤드가 줄어듭니다.
기본 요구사항:
- 관리자 액세스 권한.
샤드 누적을 줄이려면 강제 재인덱싱 확률을 높입니다:
- 오른쪽 상단에서 Admin을 선택합니다.
- 왼쪽 사이드바에서 Settings > Search를 선택합니다.
- Exact code search를 확장합니다.
- Probability of random force reindexing (percentage) 값을 높입니다.
기본값은
0.25(0.25%)입니다. 예를 들어 증분 인덱싱 태스크 100개 중 약 1개를 강제 재인덱싱하려면1로 설정합니다. - Save changes를 선택합니다.
노드 크기 적정화#
설정을 조정해도 반복적인 OOM 이벤트가 해결되지 않는다면 노드에 더 많은 메모리가 필요합니다. 인덱스 크기에 따른 메모리 할당 지침은 크기 조정 권장 사항을 참고합니다.
Kubernetes 배포에서는 Helm 차트 values.yaml에서 메모리 요청과 제한을 늘립니다.
메모리 제한이 디스크 계층별 크기 조정 표의 값 이상인지 확인합니다.
VM과 베어 메탈 배포에서는 크기 조정 표에서 더 큰 인스턴스 유형으로 옮기거나, 더 많은 머신에 인덱스를 분산하도록 노드를 추가합니다.
크기를 조정한 후 상태 확인을 실행해 노드가 복구되었는지 확인합니다:
gitlab-rake gitlab:zoekt:health
Zoekt 노드 연결 확인#
Zoekt 노드가 올바르게 구성되고 연결되었는지 확인하려면 Rails 콘솔 세션에서 다음을 확인합니다:
-
구성된 Zoekt 노드의 총 수 확인:
Search::Zoekt::Node.count -
온라인 상태인 노드 수 확인:
Search::Zoekt::Node.online.count
또는 gitlab:zoekt:info Rake 태스크를 사용할 수 있습니다.
온라인 노드 수가 구성된 노드 수보다 적거나, 노드가 구성되어 있는데도 0이라면 GitLab과 Zoekt 노드 사이에 연결 문제가 있을 수 있습니다.
Zoekt 연결 오류 디버그#
Zoekt에서 연결 문제가 발생하면 요청 흐름을 이해하고 아키텍처의 각 구성 요소를 체계적으로 확인하는 것이 중요합니다.
Zoekt 아키텍처#
Zoekt는 두 가지 모드로 동작할 수 있는 통합 바이너리(gitlab-zoekt)를 사용합니다:
- Gitaly의 저장소를 인덱싱하는 인덱서 모드
- 검색 요청을 처리하는 웹 서버 모드
기본 검색 흐름은 다음과 같습니다:
GitLab Rails → Zoekt webserver
Helm 차트(Kubernetes) 배포에서는 아키텍처에 로드 밸런싱을 위한 게이트웨이 구성 요소가 추가로 포함됩니다:
GitLab Rails → external gateway (NGINX) → internal gateway (NGINX) → Zoekt webserver
이러한 게이트웨이 구성 요소는 Zoekt 내부 구성 요소가 아니라 Helm 차트 배포의 일부입니다. 여러 Zoekt 웹 서버 인스턴스에 요청을 분산하고 라우팅, 로드 밸런싱, 선택적 TLS 종료를 처리하는 NGINX 프록시입니다.
Zoekt 아키텍처 설계에 대한 자세한 내용은 코드 검색에 Zoekt 사용을 참고합니다.
네트워크 도달 가능성 확인#
GitLab Rails 포드에서 Zoekt 게이트웨이에 도달할 수 있는지 확인하려면 상태 확인을 실행합니다:
gitlab-rake gitlab:zoekt:health
이 태스크는 Rails에서 Zoekt까지의 연결을 확인하고
전체 상태를 HEALTHY, DEGRADED, UNHEALTHY 중 하나로 보고합니다.
상태 확인이 실패하면 GitLab과 Zoekt 인프라 사이에
네트워크 연결 문제가 있을 수 있습니다.
노드 상태와 구성을 확인하려면 다음 Rake 태스크를 실행합니다:
gitlab-rake gitlab:zoekt:info
URL을 포함한 상세 노드 정보를 보려면 Rails 콘솔에서 다음 명령을 실행합니다:
# View all node attributes including URLs
Search::Zoekt::Node.all.map(&:attributes)
search_base_url은 Zoekt 웹 서버 또는 Kubernetes의 외부 게이트웨이를 가리켜야 합니다 (예:http://gitlab-zoekt:8080/).index_base_url은 Zoekt 인덱서를 가리켜야 합니다.
검색 시 404 응답을 받는다면 요청이 올바르게 라우팅되지 않았을 수 있습니다.
이 오류는 네트워크 연결보다는 게이트웨이 구성에 문제가 있음을 나타냅니다.
Zoekt 로그 모니터링#
Helm 차트(Kubernetes) 배포에서는 Zoekt 구성 요소 로그를 모니터링해 연결 문제를 파악합니다.
StatefulSet에는 컨테이너가 세 개 있습니다:
# Monitor webserver logs (search requests from Rails)
kubectl logs -f statefulset/gitlab-zoekt -c zoekt-webserver -n <your_namespace>
# Monitor indexer logs (repository indexing)
kubectl logs -f statefulset/gitlab-zoekt -c zoekt-indexer -n <your_namespace>
# Monitor internal gateway logs (NGINX proxy between the external gateway and webserver)
kubectl logs -f statefulset/gitlab-zoekt -c zoekt-internal-gateway -n <your_namespace>
외부 게이트웨이 배포를 사용하는 경우 외부 게이트웨이 로그도 모니터링할 수 있습니다:
# Monitor external gateway logs (NGINX proxy for incoming requests from Rails)
kubectl logs -f deployment/gitlab-zoekt-gateway -c zoekt-external-gateway -n <your_namespace>
이러한 로그를 모니터링하는 동안 GitLab UI에서 테스트 검색을 실행합니다. 로그에 요청이 처리되는 모습이 표시되어야 합니다. 로그에 요청이 나타나지 않는다면 Rails와 Zoekt 사이에 네트워크 라우팅 문제가 있을 수 있습니다.
UI에서 테스트 검색 실행#
zoekt.log 파일을 모니터링하는 동안 GitLab UI에서 테스트 검색을 실행할 수 있습니다:
- 프로젝트에서 검색해 특정 노드를 조회합니다.
- 그룹에서 검색해 여러 노드를 조회합니다.
- 전역에서 검색해 모든 노드를 조회합니다.
검색이 실패하면 zoekt.log 파일에서 상세 오류 메시지를 확인합니다:
# For installations that use the Linux package
tail -f /var/log/gitlab/gitlab-rails/zoekt.log
# For self-compiled installations
tail -f /home/git/gitlab/log/zoekt.log
검색이 실패한 경우 application_json.log 파일에는
Global Search Error Rate SLI 항목만 기록됩니다.
이 항목은 상세 오류 메시지가 아니라 서비스 수준 지표(Service Level Indicator, SLI) 메트릭입니다.
GitLab과 Zoekt 인프라 사이의 네트워크 문제를 나타낼 수 있는 연결 오류, 타임아웃, 인증 실패를 확인합니다.
포드 및 서비스 상태 확인#
Helm 차트(Kubernetes) 배포에서는 Zoekt 포드와 서비스 상태를 확인합니다:
# Check pod status
kubectl get pods -n <your_namespace> -l app=gitlab-zoekt
# Check `StatefulSet` status
kubectl get statefulset gitlab-zoekt -n <your_namespace>
# Check service endpoints
kubectl get endpoints gitlab-zoekt -n <your_namespace>
# Describe the service to see the configuration
kubectl describe service gitlab-zoekt -n <your_namespace>
모든 포드가 실행 상태이고 서비스에 유효한 엔드포인트가 있는지 확인합니다. 포드가 실행 중이 아니거나 엔드포인트가 없다면 Zoekt 배포에 구성 문제가 있을 수 있습니다.
배포 아키텍처에 대한 자세한 내용은 다음을 참고합니다:
오류: TaskRequest responded with [401]#
Zoekt 인덱서 로그에서 TaskRequest responded with [401]이 표시될 수 있습니다.
이 오류는 Zoekt 인덱서가 GitLab에 인증하는 데 실패했음을 나타냅니다.
이 문제를 해결하려면 gitlab-shell-secret이 올바르게 구성되어 GitLab 인스턴스와
Zoekt 인덱서 사이에서 일치하는지 확인합니다.
예를 들어 다음 명령의 출력은 gitlab.rb의 gitlab-shell-secret과 일치해야 합니다:
kubectl get secret gitlab-shell-secret -o jsonpath='{.data.secret}' -n your_zoekt_namespace | base64 -d
오류: missing selected ALPN property#
Zoekt 게이트웨이 앞에 외부 로드 밸런서를 사용하는 경우 GitLab 로그에서 다음과 같은 오류가 표시될 수 있습니다:
rpc error: code = Unavailable desc = connection error: desc = "transport: authentication handshake failed: credentials: cannot check peer: missing selected ALPN property"
이 오류는 로드 밸런서가 HTTP/2와 함께 ALPN(Application-Layer Protocol Negotiation)을 지원하지 않거나 알리지 않을 때 발생합니다. Zoekt는 노드 간 통신에 gRPC를 사용하며, 이는 HTTP/2 지원을 필요로 합니다.
이 문제를 해결하려면 다음 중 하나를 수행합니다:
-
로드 밸런서에서 HTTP/2 지원을 활성화합니다(권장):
-
ALPN을 통해 HTTP/2를 지원하고 알리도록 로드 밸런서를 구성합니다:
- HAProxy의 경우 백엔드에서
alpn h2,http/1.1이 구성되어 있는지 확인합니다. - NGINX의 경우 서버 블록에서 다음을 사용합니다:
- NGINX 1.25.1 이상에서는
http2 on;. - NGINX 1.25.0 이하에서는
listen 443 ssl http2;.
- NGINX 1.25.1 이상에서는
- HAProxy의 경우 백엔드에서
-
HTTP/2 지원을 확인합니다:
curl --verbose --http2 "https://your-zoekt-gateway-url/health" 2>&1 | grep ALPN다음과 비슷한 출력이 표시되어야 합니다:
* ALPN, server accepted to use h2
-
-
TLS 패스스루를 사용합니다:
로드 밸런서가 HTTP/2를 지원할 수 없다면 밸런서를 TLS 패스스루로 구성합니다. 그러면 Zoekt 게이트웨이가 TLS 종료를 직접 처리해 ALPN 협상이 제대로 이루어지도록 보장할 수 있습니다. TLS 패스스루를 사용하려면 Zoekt 게이트웨이에 유효한 TLS 인증서를 구성합니다:
-
Helm 차트 배포에서는
values.yaml에서 인증서를 구성합니다:gateway: tls: certificate: enabled: true secretName: zoekt-gateway-cert -
TLS를 종료하지 않고 암호화된 트래픽을 통과시키도록 로드 밸런서를 구성합니다.
-