GitLab에서 NFS 사용
GitLab v19.5Offering: GitLab Self-Managed
요약
NFS는 오브젝트 스토리지의 대안으로 사용할 수 있지만, 성능상의 이유로 일반적으로 권장하지는 않습니다. LFS, Uploads, Artifacts 같은 데이터 개체에는 성능이 더 좋은 오브젝트 스토리지 서비스를 NFS보다 우선해 사용합니다.
NFS는 오브젝트 스토리지의 대안으로 사용할 수 있지만, 성능상의 이유로 일반적으로 권장하지는 않습니다.
LFS, Uploads, Artifacts 같은 데이터 개체에는 성능이 더 좋은 오브젝트 스토리지 서비스를 NFS보다 우선해 사용합니다. NFS 사용을 없앨 때는 오브젝트 스토리지로 옮기는 것 외에 추가로 수행해야 하는 단계가 있습니다.
NFS는 리포지터리 저장소로 사용할 수 없습니다.
파일 시스템 성능을 테스트하는 방법은 파일 시스템 성능 벤치마킹을 참고합니다.
인가된 SSH 키의 빠른 조회#
빠른 SSH 키 조회 기능은 블록 저장소를 사용하는 GitLab 인스턴스에서도 성능을 개선할 수 있습니다.
빠른 SSH 키 조회는 GitLab 데이터베이스를 사용해
authorized_keys(/var/opt/gitlab/.ssh에 있음)를 대체합니다.
NFS는 지연을 늘리므로 /var/opt/gitlab을 NFS로 옮긴다면 빠른 조회를
권장합니다.
GitLab은 빠른 조회를 기본값으로 삼는 방안을 검토하고 있습니다.
NFS 서버#
nfs-kernel-server 패키지를 설치하면 GitLab 애플리케이션을 실행하는
클라이언트와 디렉터리를 공유할 수 있습니다.
sudo apt-get update
sudo apt-get install nfs-kernel-server
필수 기능#
파일 잠금: GitLab은 권고적 파일 잠금을 요구하며, 이는 NFS 버전 4 에서만 기본으로 지원됩니다. NFSv3도 Linux 커널 2.6.5 이상을 사용하면 잠금을 지원합니다. GitLab은 버전 4 사용을 권장하며 NFSv3는 별도로 테스트하지 않습니다.
권장 옵션#
NFS 내보내기를 정의할 때는 다음 옵션도 함께 추가하는 것을 권장합니다.
no_root_squash- NFS는 보통root사용자를nobody로 바꿉니다. 여러 사용자가 NFS 공유에 접근할 때는 좋은 보안 조치입니다. 다만 여기서는 GitLab만 NFS 공유를 사용하므로 안전합니다. GitLab은 파일 권한을 자동으로 관리해야 하므로no_root_squash설정을 권장합니다. 이 설정이 없으면 Linux 패키지가 권한을 변경할 때 오류가 발생할 수 있습니다. GitLab과 함께 번들된 다른 구성 요소는root가 아니라 권한이 없는 사용자로 실행됩니다.no_root_squash를 권장하는 이유는 Linux 패키지가 필요에 따라 파일의 소유권과 권한을 설정할 수 있도록 하기 위해서입니다.no_root_squash옵션을 사용할 수 없는 일부 환경에서는root플래그로 같은 결과를 얻을 수 있습니다.sync- 동기 동작을 강제합니다. 기본값은 비동기이며, 특정 상황에서는 데이터가 동기화되기 전에 장애가 발생하면 데이터가 유실될 수 있습니다.
LDAP와 함께 Linux 패키지를 운영하는 일이 복잡하고 LDAP 없이 ID 매핑을 유지하는 일도 복잡하므로, 대부분의 경우 시스템 간 권한 관리를 단순화하기 위해 숫자 UID와 GID를 활성화해야 합니다(일부 환경에서는 기본적으로 꺼져 있습니다).
- NetApp 안내
- NetApp 이 아닌 장비에서는 NFSv4 idmapper 활성화의 반대로 수행해 NFSv4
idmapping을 비활성화합니다.
NFS 서버 위임 비활성화#
모든 NFS 사용자는 NFS 서버 위임 기능을 비활성화하는 것을 권장합니다. 이는
수많은 TEST_STATEID NFS 메시지로 인한 과도한 네트워크 트래픽 때문에
NFS 클라이언트가 급격히 느려지게 만드는
Linux 커널 버그를 피하기 위해서입니다.
NFS 서버 위임을 비활성화하는 방법은 다음과 같습니다.
-
NFS 서버에서 다음을 실행합니다.
echo 0 > /proc/sys/fs/leases-enable sysctl -w fs.leases-enable=0 -
NFS 서버 프로세스를 재시작합니다. 예를 들어 CentOS에서는
service nfs restart를 실행합니다.
이 커널 버그는 이 커밋이 반영된 최신 커널에서 해결되었을 수 있습니다. Red Hat Enterprise 7은 2019 년 8 월 6 일에 커널 업데이트를 배포했으며 이 업데이트로도 문제가 해결되었을 수 있습니다. 수정이 반영된 Linux 커널 버전을 사용하고 있다면 NFS 서버 위임을 비활성화하지 않아도 됩니다. 그렇더라도 GitLab은 인스턴스 관리자가 NFS 서버 위임을 계속 비활성화해 두기를 권장합니다.
NFS 클라이언트#
nfs-common은 애플리케이션 노드에서 실행할 필요가 없는 서버 구성 요소를
설치하지 않고 NFS 기능을 제공합니다.
apt-get update
apt-get install nfs-common
마운트 옵션#
다음은 /etc/fstab에 추가할 예시입니다.
10.1.0.1:/var/opt/gitlab/.ssh /var/opt/gitlab/.ssh nfs4 defaults,vers=4.1,hard,rsize=1048576,wsize=1048576,noatime,nofail,_netdev,lookupcache=positive 0 2
10.1.0.1:/var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/uploads nfs4 defaults,vers=4.1,hard,rsize=1048576,wsize=1048576,noatime,nofail,_netdev,lookupcache=positive 0 2
10.1.0.1:/var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-rails/shared nfs4 defaults,vers=4.1,hard,rsize=1048576,wsize=1048576,noatime,nofail,_netdev,lookupcache=positive 0 2
10.1.0.1:/var/opt/gitlab/gitlab-ci/builds /var/opt/gitlab/gitlab-ci/builds nfs4 defaults,vers=4.1,hard,rsize=1048576,wsize=1048576,noatime,nofail,_netdev,lookupcache=positive 0 2
마운트된 각 NFS 파일 시스템의 정보와 설정된 옵션은 nfsstat -m과
cat /etc/fstab을 실행해 확인할 수 있습니다.
다음 옵션들은 사용을 검토할 만합니다.
| 설정 | 설명 |
|---|---|
vers=4.1 |
오래된 데이터로 인해 심각한 문제를 일으킬 수 있는 Linux NFS 클라이언트 v4.0 버그 때문에 v4.0 대신 NFS v4.1을 사용해야 합니다. |
nofail |
이 마운트를 사용할 수 있을 때까지 기다리며 부팅 과정을 멈추지 않습니다. |
lookupcache=positive |
NFS 클라이언트가 positive 캐시 결과는 유지하되 negative 캐시 결과는 무효화하도록 지시합니다. 네거티브 캐시 결과는 Git에서 문제를 일으킵니다. 특히 git push가 모든 NFS 클라이언트에 일관되게 등록되지 않을 수 있습니다. 네거티브 캐시 때문에 클라이언트가 이전에 파일이 없었다고 기억하기 때문입니다. |
hard |
soft 대신 사용합니다. 추가 세부 정보. |
cto |
cto가 기본 옵션이며 이 옵션을 사용해야 합니다. nocto는 사용하지 않습니다. 추가 세부 정보. |
_netdev |
네트워크가 온라인 상태가 될 때까지 파일 시스템 마운트를 기다립니다. high_availability['mountpoint'] 옵션도 함께 참고합니다. |
soft 마운트 옵션#
soft를 써야 할 특별한 이유가 없다면 마운트 옵션에 hard를 사용하는 것을
권장합니다.
GitLab.com 이 NFS를 사용하던 시절에는 NFS 서버를 재부팅하는 경우가 있어
가용성을 높이려고 soft를 사용했지만, 인프라는 환경마다 다릅니다.
예를 들어 이중화된 컨트롤러를 갖춘 온프레미스 스토리지 어레이가 NFS를
제공한다면 NFS 서버 가용성을 걱정하지 않아도 됩니다.
NFS man 페이지에는 다음과 같이 적혀 있습니다.
"soft" 타임아웃은 특정 상황에서 조용한 데이터 손상을 일으킬 수 있습니다
차이를 이해하려면 Linux man 페이지를 읽고,
soft를 사용한다면 위험을 완화하는 조치를 취했는지 확인합니다.
커밋이 사라지는 등 NFS 서버의 디스크 쓰기가 이루어지지 않아
발생했을 법한 동작을 겪는다면 hard 옵션을 사용합니다.
man 페이지에 다음과 같이 적혀 있기 때문입니다.
데이터 무결성보다 클라이언트 응답성이 더 중요한 경우에만 soft 옵션을 사용합니다
다른 벤더도 비슷한 권장 사항을 제시합니다.
읽기·쓰기 디렉터리에 권장되는 마운트 옵션과 NetApp의
기술 자료가 그 예입니다.
이들은 NFS 클라이언트 드라이버가 데이터를 캐시하면 soft에서는 GitLab의
쓰기가 실제로 디스크에 반영되었는지 확신할 수 없다는 점을 강조합니다.
hard 옵션으로 설정한 마운트 지점은 성능이 떨어질 수 있고, NFS 서버가
중단되면 hard 때문에 마운트 지점과 상호작용하는 프로세스가 멈춥니다.
멈춘 프로세스는 SIGKILL(kill -9)로 처리합니다.
intr 옵션은
2.6 커널부터 동작하지 않습니다.
nocto 마운트 옵션#
nocto는 사용하지 않습니다. 대신 기본값인 cto를 사용합니다.
nocto를 사용하면 dentry 캐시가 생성된 시점부터 acdirmax 초(속성 캐시 시간) 동안 항상 사용됩니다.
이 때문에 클라이언트가 여러 개일 때 dentry 캐시가 오래되는 문제가 생기며, 클라이언트마다 서로 다른(캐시된) 버전의 디렉터리를 보게 됩니다.
Linux man 페이지에서 중요한 부분은 다음과 같습니다.
nocto옵션을 지정하면 클라이언트는 서버의 파일이 변경된 시점을 판단할 때 표준이 아닌 휴리스틱을 사용합니다.
nocto옵션은 읽기 전용 마운트의 성능을 개선할 수 있지만, 서버의 데이터가 가끔씩만 변경되는 경우에만 사용해야 합니다.
GitLab은 푸시 후 ref를 찾지 못하는 문제에서 이 동작을 확인했습니다. 이 이슈에 설명된 대로 새로 추가된 loose ref가 로컬 dentry 캐시를 가진 다른 클라이언트에서 없는 것으로 보일 수 있습니다.
단일 NFS 마운트#
모든 GitLab 데이터 디렉터리를 하나의 마운트 안에 중첩하는 것을 권장하며, 이렇게 하면 기존 데이터를 수동으로 옮기지 않고도 백업을 자동으로 복원할 수 있습니다.
mountpoint
└── gitlab-data
├── builds
├── shared
└── uploads
이를 위해 마운트 지점 안에 중첩된 각 디렉터리 경로로 Linux 패키지를 다음과 같이 구성합니다.
/gitlab-nfs를 마운트한 다음, 아래 Linux 패키지 구성으로 각 데이터
위치를 하위 디렉터리로 옮깁니다.
gitlab_rails['uploads_directory'] = '/gitlab-nfs/gitlab-data/uploads'
gitlab_rails['shared_path'] = '/gitlab-nfs/gitlab-data/shared'
gitlab_ci['builds_directory'] = '/gitlab-nfs/gitlab-data/builds'
sudo gitlab-ctl reconfigure를 실행해 중앙 위치를 사용하기 시작합니다. 기존
데이터가 있었다면 새 위치로 직접 복사하거나 rsync로 옮긴 다음
GitLab을 재시작해야 합니다.
바인드 마운트#
Linux 패키지의 구성을 변경하는 대신 바인드 마운트를 사용해 NFS 마운트에 데이터를 저장할 수도 있습니다.
바인드 마운트를 사용하면 NFS 마운트를 하나만 지정하고 GitLab의 기본 데이터
위치를 그 NFS 마운트에 바인드할 수 있습니다. 먼저 평소처럼 /etc/fstab에
단일 NFS 마운트 지점을 정의합니다. NFS 마운트 지점이 /gitlab-nfs 라고
가정하겠습니다. 그런 다음 /etc/fstab에 다음 바인드 마운트를
추가합니다.
/gitlab-nfs/gitlab-data/.ssh /var/opt/gitlab/.ssh none bind 0 0
/gitlab-nfs/gitlab-data/uploads /var/opt/gitlab/gitlab-rails/uploads none bind 0 0
/gitlab-nfs/gitlab-data/shared /var/opt/gitlab/gitlab-rails/shared none bind 0 0
/gitlab-nfs/gitlab-data/builds /var/opt/gitlab/gitlab-ci/builds none bind 0 0
바인드 마운트를 사용하면 복원을 시도하기 전에 데이터 디렉터리가 비어 있는지 직접 확인해야 합니다. 자세한 내용은 복원 사전 요구 사항을 참고합니다.
여러 NFS 마운트#
기본 Linux 패키지 구성을 사용할 때는 모든 GitLab 클러스터 노드 사이에서 데이터 위치 3 곳을 공유해야 합니다. 다른 위치는 공유하지 않습니다. 공유해야 하는 위치 3 곳은 다음과 같습니다.
| 위치 | 설명 | 기본 구성 |
|---|---|---|
/var/opt/gitlab/gitlab-rails/uploads |
사용자가 업로드한 첨부 파일 | gitlab_rails['uploads_directory'] = '/var/opt/gitlab/gitlab-rails/uploads' |
/var/opt/gitlab/gitlab-rails/shared |
빌드 아티팩트, GitLab Pages, LFS 개체, 임시 파일 같은 개체. LFS를 사용한다면 데이터의 많은 부분을 차지할 수도 있습니다 | gitlab_rails['shared_path'] = '/var/opt/gitlab/gitlab-rails/shared' |
/var/opt/gitlab/gitlab-ci/builds |
GitLab CI/CD 빌드 추적 | gitlab_ci['builds_directory'] = '/var/opt/gitlab/gitlab-ci/builds' |
다른 GitLab 디렉터리는 노드 사이에 공유하지 않습니다. 이들 디렉터리에는 노드별 파일과 공유할 필요가 없는 GitLab 코드가 들어 있습니다. 로그를 중앙 위치로 보내려면 원격 syslog 사용을 검토합니다. Linux 패키지는 UDP 로그 전송 구성을 제공합니다.
NFS 마운트를 여러 개 사용하면 복원을 시도하기 전에 데이터 디렉터리가 비어 있는지 직접 확인해야 합니다. 자세한 내용은 복원 사전 요구 사항을 참고합니다.
NFS 테스트#
NFS 서버와 클라이언트를 설정한 다음에는 아래 명령을 테스트해 NFS가 올바르게 구성되었는지 검증할 수 있습니다.
sudo mkdir /gitlab-nfs/test-dir
sudo chown git /gitlab-nfs/test-dir
sudo chgrp root /gitlab-nfs/test-dir
sudo chmod 0700 /gitlab-nfs/test-dir
sudo chgrp gitlab-www /gitlab-nfs/test-dir
sudo chmod 0751 /gitlab-nfs/test-dir
sudo chgrp git /gitlab-nfs/test-dir
sudo chmod 2770 /gitlab-nfs/test-dir
sudo chmod 2755 /gitlab-nfs/test-dir
sudo -u git mkdir /gitlab-nfs/test-dir/test2
sudo -u git chmod 2755 /gitlab-nfs/test-dir/test2
sudo ls -lah /gitlab-nfs/test-dir/test2
sudo -u git rm -r /gitlab-nfs/test-dir
Operation not permitted 오류가 발생하면 NFS 서버의 내보내기 옵션을 확인해야 합니다.
방화벽 환경에서의 NFS#
NFS 서버와 NFS 클라이언트 사이의 트래픽이 방화벽의 포트 필터링 대상이라면, NFS 통신을 허용하도록 방화벽을 다시 구성해야 합니다.
The Linux Documentation Project(TDLP)의 이 가이드는 방화벽 환경에서 NFS를 사용하는 기본 사항을 다룹니다. 아울러 사용하는 운영 체제나 배포판, 방화벽 소프트웨어의 문서를 찾아 함께 확인할 것을 권장합니다.
Ubuntu 예시는 다음과 같습니다.
sudo ufw status 명령을 실행해 클라이언트에서 오는 NFS 트래픽이 호스트의
방화벽에서 허용되는지 확인합니다. 차단되고 있다면 아래 명령으로 특정
클라이언트의 트래픽을 허용할 수 있습니다.
sudo ufw allow from <client_ip_address> to any port nfs
알려진 문제#
클라우드 기반 파일 시스템 사용 금지#
GitLab은 다음과 같은 클라우드 기반 파일 시스템을 사용하지 않을 것을 강력히 권장합니다.
- AWS Elastic File System(EFS).
- Google Cloud Filestore.
- Azure Files.
GitLab 지원팀은 클라우드 기반 파일 시스템 접근과 관련된 성능 문제를 지원하지 못합니다.
고객과 사용자는 이러한 파일 시스템이 GitLab 이 요구하는 파일 시스템 접근에
적합하지 않다고 보고했습니다. git처럼 작은 파일을 많이, 그리고 직렬화된 방식으로
기록하는 워크로드는 클라우드 기반 파일 시스템에 잘 맞지 않습니다.
이러한 파일 시스템을 사용하기로 했다면 GitLab 로그 파일(예: /var/log/gitlab의 파일)은
그곳에 저장하지 않습니다. 성능에 영향을 주기 때문입니다. 로그 파일은 로컬
볼륨에 저장할 것을 권장합니다.
GitLab에서 클라우드 기반 파일 시스템을 사용한 경험에 대한 자세한 내용은 이 Commit Brooklyn 2019 영상을 참고합니다.
CephFS 및 GlusterFS 사용 금지#
GitLab은 CephFS와 GlusterFS를 사용하지 않을 것을 강력히 권장합니다. 이러한 분산 파일 시스템은 GitLab의 입출력 접근 패턴에 잘 맞지 않습니다. Git은 작은 파일을 많이 사용하고, 접근 시간과 파일 잠금 시간이 전파되면서 Git 작업이 매우 느려지기 때문입니다.
NFS와 함께 PostgreSQL 사용 금지#
GitLab은 PostgreSQL 데이터베이스를 NFS 위에서 운영하지 않을 것을 강력히 권장합니다. GitLab 지원팀은 이 구성과 관련된 성능 문제를 지원하지 못합니다.
또한 PostgreSQL 문서는 이 구성을 명시적으로 경고합니다.
PostgreSQL은 NFS 파일 시스템을 특별히 다루지 않으며, NFS가 로컬에 연결된 드라이브와 똑같이 동작한다고 가정합니다. 클라이언트나 서버의 NFS 구현이 표준 파일 시스템 의미론을 제공하지 않으면 안정성 문제가 생길 수 있습니다. 특히 NFS 서버로의 지연된(비동기) 쓰기는 데이터 손상 문제를 일으킬 수 있습니다.
지원되는 데이터베이스 아키텍처는 복제 및 장애 조치를 위한 데이터베이스 구성 문서를 참고합니다.
문제 해결#
NFS로 전달되는 요청 확인#
NFS 관련 문제가 발생하면 perf로 파일 시스템 요청을 추적하는 것이
도움이 될 수 있습니다.
sudo perf trace -e 'nfs4:*' -p $(pgrep -fd ',' puma)