25/09/03 NFS

344th·2025년 12월 11일

AWS AI

목록 보기
12/48
**$ vagrant init
$ ii Vagrantfile**
# -*- mode: ruby -*-
# vi: set ft=ruby :
vm_image = "nobreak-labs/rocky-9"
vm_subnet = "192.168.56."

Vagrant.configure("2") do |config|
  config.vm.synced_folder ".", "/vagrant", disabled: true

  config.vm.define "client" do |node|
    node.vm.box = vm_image
    node.vm.provider "virtualbox" do |vb|
      vb.name = "client"
      vb.cpus = 2
      vb.memory = 1024
    end
    
    node.vm.network "private_network", ip: vm_subnet + "33", nic_type: "virtio"
    node.vm.hostname = "client"
  end

  config.vm.define "server" do |node|
    node.vm.box = vm_image
    node.vm.provider "virtualbox" do |vb|
      vb.name = "server"
      vb.cpus = 2
      vb.memory = 1024
    end
    
    node.vm.network "private_network", ip: vm_subnet + "44", nic_type: "virtio"
    node.vm.hostname = "server"
  end
end
**$ vagrant up
$ vagrant ssh client
$ vagrant ssh server**

NFS 스토리지

: 분산 파일 시스템 프로토콜

: 중앙집중형 모델

: 내부망(로컬 네트워크 환경)에서 사용

  • 클라이언트/서버 서비스 모델 사용
  • 클라이언트의 사용자는 서버에서 제공하는 공유 디렉토리에 접근할 때 로컬 스토리지에 존재하는 디렉토리처럼 접근 및 사용 가능 → 마운트된 디렉토리인지 로컬 디렉토리인지 구분 x
  • 유닉스와 리눅스용으로 개발되었지만, 윈도우, mac os 에서도 사용 가능
  • 파일을 중앙에서 관리하므로 파일의 일관성 유지 가능
    • 매번 버전 관리, 최신화를 신경쓸 필요가 없음
  • 보안을 위해 커버로스를 사용해 데이터의 무결성을 검증하거나 데이터를 암호화해 통신 가능
    • 커버로스: 네트워크 인증 시스템

내부망에서 사용하는 이유?

  • 성능 : 이더넷을 통해 접근하면 속도가 느려짐 → [MTU = 1500] == 이더넷 표준

    MTU: 네트워크에서 한 번에 보낼 수 있는 최대 패킷 크기(바이트 단위)

    → 내부망에서는 MTU 를 임의로 설정 가능
    • 내부망이 이더넷보다 빠른 이유

      MTU 확장 (Jumbo Frame)

      • 내부망에서는 MTU=9000 같은 Jumbo Frame을 허용.

      • 대량 데이터 전송 시 fragmentation 줄고, 헤더 오버헤드 감소 → 처리 효율 ↑.

        네트워크 스택 최적화

      • 내부망 전용 NIC, 스위치, 드라이버 튜닝(RDMA, offloading, interrupt moderation 등).

      • CPU가 패킷 처리로 낭비되는 걸 줄임.

  • 보안

NFS 소개

중앙 서버에 데이터를 저장해서, 각 클라이언트는 그 데이터를 직접 저장해서 리소스를 낭비할 필요가 없음

또한 동일 데이터에 접근하므로 데이터의 일관성 유지 가능

규모가 큰 소프트웨어를 배포할 때 시스템의 부하를 감소시킬 수 있음

NFSv3

  • 비동기식 쓰기 지원
    • 동기 : 파일이 디스크에 완전히 저장될 때까지 기다림
    • 비동기 : 메모리에 일단 저장하고 나중에 디스크에 저장
  • RPC(Remote Procedure Call)에 의존 → rpcbind 서비스 필요
    • rpcbind: RPC 서비스들의 포트 관리
    • RPC : 다른 컴퓨터(원격 서버)에 있는 함수(프로시저)를 마치 내 프로그램 안 함수처럼 호출
      • 동작 방식
        1. 클라이언트가 원격 함수를 호출 (result = remote_add(3,4))

        2. 호출 요청이 RPC 런타임에 의해 메시지로 변환 (직렬화)

        3. 네트워크를 통해 서버로 전송

        4. 서버 측 RPC 런타임이 메시지를 받아 실제 함수 실행 (add(3,4))

        5. 결과를 응답 메시지로 직렬화해 클라이언트로 전송

        6. 클라이언트는 마치 로컬 함수 결과처럼 받음

          👉 내부적으로는 네트워크 요청/응답이지만, 프로그래머 입장에서는 함수 호출처럼 보이는 것이 핵심.

      • nfs 에서의 RPC

        1. 왜 NFS에서 RPC를 쓰는가?

        • NFS의 목적: 원격 서버의 파일을 마치 로컬 파일처럼 접근

        • 구현 방법: 파일 작업(open, read, write, mkdir, unlink 등)을 원격 서버의 함수 호출로 변환해야 함

        • 따라서 “파일 연산 = RPC 호출” 구조로 설계됨


          2. 동작 흐름

          클라이언트에서 read(file, offset, length) 호출한다고 가정해 볼게요.

        1. 클라이언트 애플리케이션: read() 시스템콜 호출

        2. NFS 클라이언트 커널 모듈: 이 호출을 NFS 프로토콜로 변환

        3. RPC 호출 생성:

          • 함수명: READ
          • 인자: 파일 핸들, offset, length
          • 직렬화(XDR, External Data Representation 사용)
        4. 네트워크 전송: TCP 또는 UDP를 통해 NFS 서버로 전송

        5. NFS 서버: RPC 요청 수신 → 해당 파일시스템 함수 실행

        6. 응답 생성: 읽은 데이터 블록을 직렬화하여 RPC 응답으로 전송

        7. 클라이언트 커널: 응답을 받아 로컬 read() 호출에 데이터 반환

          👉 이렇게 해서 애플리케이션은 네트워크 통신 사실을 모른 채 로컬 파일 읽듯이 동작할 수 있음.


          3. NFS에서 쓰이는 RPC 예시

          NFS 프로토콜은 여러 가지 RPC 절차(Procedure)로 정의돼 있어요:

        • LOOKUP: 파일 이름 → 파일 핸들 얻기

        • GETATTR: 파일 속성(stat 정보) 가져오기

        • READ: 파일 데이터 읽기

        • WRITE: 파일 데이터 쓰기

        • CREATE / REMOVE / MKDIR / RMDIR: 파일·디렉토리 생성/삭제

        • READDIR: 디렉토리 엔트리 읽기

          즉, 우리가 POSIX 파일 시스템에서 쓰는 거의 모든 동작이 NFS RPC 요청으로 매핑됨.


          4. 기술적 특징

        • RPC 프로토콜: SunRPC (ONC RPC) 사용

        • 데이터 포맷: XDR (서로 다른 머신 아키텍처 간 호환성 위해)

        • 네트워크 계층: UDP (NFSv2/v3) 또는 TCP (NFSv3/v4)

        • 버전별 차이:
          - NFSv2/3: stateless, RPC 호출마다 모든 정보 포함 → 단순하지만 성능 저하 가능
          - NFSv4: stateful, 세션 유지, 보안(ACL, Kerberos) 강화


          5. 핵심 요약

        • NFS = “파일시스템을 RPC로 노출한 것”

        • 클라이언트의 파일 연산을 RPC 요청으로 변환 → 서버에서 처리 → 결과 응답

        • LOOKUP, READ, WRITE 등 모든 파일 연산이 RPC 프로시저로 정의되어 있음

        • 따라서 NFS의 성능, 안정성, 지연시간은 RPC와 네트워크 품질에 크게 의존


  • 방화벽 설정 복잡함

NFSv3 와 관련된 서비스

  • nfs : 메인 서비스 : NFS 서버에 대한 요청을 처리하기 위해 NFS 서버와 적절한 RPC 프로세스를 실행
  • nfslock : NFS 서버의 파일을 클라이언트가 잠금할 수 있도록 하는 서비스
  • rpcbind : 로컬 RPC 서비스로부터 포트를 예약해줌 : RPC 서비스에 대한 요청에 응답하고 요청된 RPC 서비스로 연결을 설정함
    • NFSv4 에서는 사용되지 않음
  • rpc.mountd : 마운트 요청을 처리하기 위해 NFS 서버에서 사용됨 : 권한이 있는지, 설정 파일이 제대로 돼있는지 확인
    • 마운트 요청이 허용되면 성공(Success) 상태 응답하고 클라이언트에게 NFS 공유에 대한 파일-핸들(File-Handle) 제공
  • lockd : 서버와 클라이언트 모두에서 실행되는 커널 스레드 : 클라이언트가 서버의 파일을 잠글 수 있도록 함 : NFS 서버가 실행되거나 공유 디렉토리가 마운트 될 때마다 자동으로 시작됨
  • rpc.stad
  • rpc.rquotad

NFSv4

  • rpcbind를 사용하지 않고 서버 자체가 2049/TCP 포트에서 대기함
  • 마운팅과 잠금 프로토콜이 NFSv4 프로토콜로 통합되어 별개의 서비스를 요구하지 않음 → 방화벽 구성이 쉬워짐
  • pNFS(Parallel NFS)를 사용 가능
    • 병렬 처리가 가능해짐
  • 이전 버전의 NFS 서버와 호환 가능

NFSv4와 관련된 서비스

  • rpc.mountd : NFS 서버에서 export 를 설정
  • nfs-server
  • rpc.idmapd

NFS 서버 구성

# 대부분 root 권한을 필요로 하므로
**[vagrant@client ~]$ sudo su -
[vagrant@server ~]$ sudo su -**

# ip 확인
**[root@client ~]# ip a**
...
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:5c:69:5a brd ff:ff:ff:ff:ff:ff
    inet **192.168.56.33**/24 brd 192.168.56.255 scope global noprefixroute enp0s8
...
**[root@client ~]# ip a**
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:be:3a:8f brd ff:ff:ff:ff:ff:ff
    inet **192.168.56.44**/24 brd 192.168.56.255 scope global noprefixroute enp0s8
    
# 가상 머신 환경 세팅 잘되었는지 네트워크 테스트
**[root@client ~]# ping 192.168.56.44**
PING 192.168.56.44 (192.168.56.44) 56(84) bytes of data.
64 bytes from 192.168.56.44: icmp_seq=1 ttl=64 time=0.897 ms
64 bytes from 192.168.56.44: icmp_seq=2 ttl=64 time=0.967 ms
64 bytes from 192.168.56.44: icmp_seq=3 ttl=64 time=0.851 ms
64 bytes from 192.168.56.44: icmp_seq=4 ttl=64 time=1.19 ms
64 bytes from 192.168.56.44: icmp_seq=5 ttl=64 time=1.43 ms

**[root@server ~]# ping 192.168.56.33**
PING 192.168.56.33 (192.168.56.33) 56(84) bytes of data.
64 bytes from 192.168.56.33: icmp_seq=1 ttl=64 time=8.37 ms
64 bytes from 192.168.56.33: icmp_seq=2 ttl=64 time=0.965 ms
64 bytes from 192.168.56.33: icmp_seq=3 ttl=64 time=0.533 ms
# nfs 패키지 설치
**[root@server ~]# yum install nfs-utils -y**
# 공유 디렉토리 생성
# /srv : service. 시스템에서 제공하는 서비스의 데이터를 담아서 쓰라는 용도로 만들어짐
**[root@server ~]# mkdir /srv/share
[root@server ~]# ls -ld /srv/share/**
drwxr-xr-x. 2 root root 6 Sep  3 03:35 /srv/share/

# 공유 디렉토리에 파일 생성
**[root@server ~]# echo "NFS Share Test File" > /srv/share/test.txt**
# 설정 파일 작성
**[root@server ~]# vi /etc/exports**
// 어떤 클라이언트에게 어떤 디렉토리에 어떤 옵션으로 공유할 것인지
/srv/share      *(rw,sync,no_root_squash)
  • * : 어떤 호스트가 접근 가능하게 할 것인지. : *은 모두를 가리킴. : 원래는 ip 주소를 적는게 정상
  • (rw,sync,no_root_squash) : NFS의 서버 공유 옵션
    • ro : 읽기 전용으로 공유
    • rw : 읽기-쓰기로 공유
    • no_root_squash : 클라이언트의 root 사용자가 NFS 서버의 root 사용자처럼 사용될 수 있도록 하는 옵션
      • root_squash : 클라이언트의 root 사용자가 NFS 서버의 root 사용자처럼 사용되는 걸 막기 위해(권한을 제한하기 위해) 클라이언트의 root 사용자가 파일 생성시 해당 파일의 소유자 및 소유그룹을 nfsnobody 로 설정하는 기능
    • sync : 이전 요청 사항이 스토리지에 저장되기 전에 다른 요청에 응답하지 않음 : 반대 옵션을 사용하려면 async 를 사용하거나 지정 x
    • sec
profile
새싹 개발자

0개의 댓글