젠투에서 디스크 없는 노드 사용하기 Michael Andrews Kristian Jerpetjoen Sven Vermeulen Xavier Neys shavete Hwang Joonhyung 이 하우투는 여러분이 젠투 리눅스로 디스크 없는 노드를 만들 수 있도록 설치를 돕는다. 1.5 2004년 10월 9일 소개
이 하우투에 대해

이 HOWTO문서는 여러분이 Gentoo Linux 배포판을 기반으로 하는 diskless workstation을 설치하는 데 도움이 될 것이다. 우리는 기존의 사용자는 물론이고 새로운 사용자에게도 최대한 친근하게 다가가려고 할 것이다. 왜냐하면 우리 모두는 어떠한 면에서 하나이기 때문이다. :) 능숙한 사용자가 다수의 HOWTO를 diskless node와 네트워크에 쉽게 적용할 때, 우리는 이 가이드가 흥미를 가진 모든 사용자들 (geek이든 아니든)이 설치를 쉽게 할 수 있게 하기를 희망한다.

diskless 기계란 무엇인가?

diskless machine이란 하드 디스크, 플로피 드라이브나 CD-ROM과 같은 일반적으로 사용되는 부트 디바이스를 가지고 있지 않은 PC를 뜻한다. diskless node는 네트워크를 통해 부팅되며, 로컬 하드 디스크처럼 사용할 수 있는 저장 공간을 제공하는 서버를 필요로 한다. 지금부터 우리는 서버를 master라 부를 것이며, diskless node를 slave라 부를 것이다. (이름이 뭘 의미하지 :) slave node는 PXE 부팅이나 Etherboot를 지원하는 네트워크 어댑터가 필요하다. 지원하는 장치의 목록은 Etherboot.org에서 확인하라. 최근 출시된 대부분의 네트워크 카드가 PXE를 지원하고, 메인보드에 내장된 형태의 어댑터 또한 작동한다.

시작하기 전에

여러분은 master node에 Gentoo가 설치되어 있어야 되고, 여러분이 host하고 싶은 slave node의 파일시스템을 저장할만한 충분한 공간이 master상에 있어야 한다. 여러분이 근거리 연결(local area connection)과 분리된 인터넷 인터페이스를 가지고 있는지도 확인하라.

마스터와 슬레이브 설정하기
커널에 대하여 여러분이 openMosix cluster에 클러스터하려고 한다면, openMosix에 맞는 커널 패치를 사용했는지 확인해야 한다. 그 커널 패치는 portage아래 sys-kernel/openmosix-sources에 있다. 여러분이 openMosix에 맞는 커널을 컴파일하는 법을 배우기 위해서는, openMosix HOWTO을 읽어봐야 한다.

커널이란 하드웨어와 시스템에 설치한 그 밖의 모든 소프트웨어 사이에 존재하는 소프트웨어이며, 커널의 중심부는 필수적으로 운영체제의 기반을 구성한다. 여러분이 컴퓨터를 켰을 때, BIOS는 하드 디스크의 지정된 부트 공간에 있는 instruction을 실행한다. 커널이 로드된 후에, 모든 프로세스는 커널에 의해 제어된다.

커널과 커널 설정에 관한 자세한 정보가 필요하면 kernel HOWTO를 참조하라.

마스터 커널 설정하기

master 커널은 여러분이 원하는만큼 커질 수도 있고, 알맞게 만들 수도 있지만, 여러분이 꼭 선택해야만 하는 몇가지의 커널 옵션이 있다. 아래와 같이 명령을 입력하여 커널 설정 메뉴를 실행한다.

# cd /usr/src/linux
# make menuconfig

여러분은 /usr/src/linux/.config를 직접 수정하는 방법에 대한 안전한 대안을 제공하는 회색과 파란색으로 이루어진 GUI를 볼 것이다. 만약 여러분의 커널이 현재 제대로 작동하고 있어서 현재의 설정을 저장하고자 하면, GUI 환경에서 나와서 아래와 같이 명령을 입력한다.

# cp .config .config_working

아래와 같이 부메뉴로 들어가서 나열된 항목들이 built-in으로 체크되어 있는지 확인하라. (modular가 아니다.) 아래에 있는 옵션들은 커널 2.4.22버전에서 볼 수 있는 것이다. 만약 여러분이 다른 버전의 커널을 사용한다면, 표시되는 문장들이나 순서가 다를 수도 있다. 적어도 아래에 보이는 항목을 선택하였는지 확인해라.

Code maturity level options  --->
  [*] Prompt for development and/or incomplete code/drivers


Networking options --->
  <*> Packet socket
  [ ]   Packet socket: mmapped IO
  < > Netlink device emulation
  [ ] Network packet filtering (replaces ipchains)
  [ ] Socket Filtering
  <*> Unix domain sockets
  [*] TCP/IP networking
  [*]   IP: multicasting

  
File systems --->
  [*] /proc file system support
  [*] /dev file system support (EXPERIMENTAL)
  [*]   Automatically mount at boot    
  Network File Systems  --->
    <*> NFS server support
    [*]   Provide NFSv3 server support


여러분이 마스터 노드를 통해 인터넷에 접속하고 싶거나
보안 방화벽을 만들고 싶다면 iptables 지원을 추가하라.

  [*] Network packet filtering (replaces ipchains)
  IP: Netfilter Configuration  --->
    <*> Connection tracking (required for masq/NAT)
    <*> IP tables support (required for filtering/masq/NAT)

패킷 필터링을 쓰고 싶다면, 여러분은 나머지를 나중에 모듈로 추가할 수 있다. 이를 어떻게 적절히 설치할 수 있는지에 대한 젠투 보안 가이드 12장 방화벽을 읽어 보라.

위의 커널 설정 옵션들은 단지 여러분의 설정 옵션에 추가로 해 줘야 하는 것일 뿐, 여러분의 커널 설정을 완전히 교체하라는 것이 아니다.

master의 커널을 재설정한 다음, 아래와 같이 rebuild하라.

# make dep
# make clean bzImage modules modules_install
(복사하기 전에 /boot가 마운트 되었는지 확인한다)
# cp arch/i386/boot/bzImage /boot/bzImage-master
# cp System.map /boot/System.map-master

그런 다음, 여러분이 사용하는 부트로더에 따라 lilo.confgrub.conf에 새로운 커널 항목을 추가하고, 기본 부팅 항목으로 설정한다. bzImage가 부트 디렉토리에 새로 생성될 것이다. 새로운 옵션들을 로드하기 위해서 시스템을 재부팅하는 것이 마지막 남은 해야할 모든 것이다.

슬레이브 커널에 대하여

slave 커널은 모듈없이 컴파일하는 것을 추천한다. 왜냐하면 원격 부팅을 통해 모듈을 로드하고 설정하는 것은 어렵고, 불필요한 작업이다. 게다가, slave 커널은 네트워크를 통해 효과적으로 부팅하기 위해서 최대한 작고 간단해야 한다. 우리는 master 커널이 설정되었던 공간에서 slave 커널을 컴파일할 것이다.

시간을 낭비하지 않고 혼란을 막기 위해 아래와 같이 명령을 실행하여 master 커널의 설정을 백업해 놓는 것은 좋은 생각이다.

# cp /usr/src/linux/.config /usr/src/linux/.config_master

이제 우리는 master 커널을 설정한 것과 같은 방법으로 slave 커널을 설정할 것이다. 여러분이 새로운 설정 파일을 이용하여 시작하고 싶다면, 아래와 같이 명령을 실행하여 기본 설정 파일인 /usr/src/linux/.config을 다시 불러 올 수 있다.

# cd /usr/src/linux
# cp .config_master .config

아래와 같이 명령을 실행하여 GUI 환경의 설정 화면으로 들어간다.

# cd /usr/src/linux
# make menuconfig

아래의 옵션들을 module이 아니라 built-in으로 선택하였는 지 확인해라.

Code maturity level options  --->
  [*] Prompt for development and/or incomplete code/drivers

Networking options --->
  <*> Packet socket
  [ ]   Packet socket: mmapped IO
  < > Netlink device emulation
  [ ] Network packet filtering (replaces ipchains)
  [ ] Socket Filtering
  <*> Unix domain sockets
  [*] TCP/IP networking
  [*]   IP: multicasting
  [*]   IP: kernel level autoconfiguration
  [*]     IP: DHCP support (NEW)


File systems --->
  [*] /proc file system support
  [*] /dev file system support (EXPERIMENTAL)
  [*]   Automatically mount at boot
  Network File Systems  --->
    <*> file system support 
    [*]   Provide NFSv3 client support
    [*]   Root file system on NFS
dhcp 서버 대신에 BOOTP 서버를 설치할 수도 있다. 네트워크 어댑터를 노드의 커널에 추가하는 것은 중요하다. (모듈로 해서는 안 된다.) 디스크 없는 노드에서 일반적으로 모듈을 사용하는 것은 문제가 되지 않는다.

지금부터 slave 커널을 컴파일해야 한다. master 커널을 컴파일할 때 만든 모듈을 망가뜨리고 싶지 않다면 지금부터 조심해야 한다.

# cd /usr/src/linux
# make clean dep bzImage

slave의 파일과 필요한 파일을 저장해 놓을 디렉토리를 master상에 만들어 놓는다. 우리는 /diskless라고 만들것이지만, 여러분은 여러분 마음대로 만들 수 있다. slave의 bzImage를 /diskless디렉토리에 복사해 놓는다.

만약 여러분이 다른 아키텍처들을 사용한다면 각 설정을 .config_arch에 저장하고 싶을 것이다. 이미지에 대해서도 같은 일을 하라. 그들을 /disklessbzImage_arch로 저장하라.
# mkdir /diskless
# cp /usr/src/linux/arch/i386/boot/bzImage /diskless
준비용 슬레이브 파일 시스템 설정하기

master와 slave의 파일시스템은 얼마든지 조정되고 바뀔 수 있다. 지금부터 우리는 오로지 적당한 설정 파일과 마운트 포인트가 담길 준비적인 파일시스템을 만드는 데 집중할 것이다. 우선 첫번째 slave를 위한 디렉토리를 /diskless안에 만든다. 각각의 slave는 자기만의 root파일시스템이 필요하다. 왜냐하면 시스템 파일을 공유하는 것은 접근권한 문제와 강한 충돌을 일으킬 수 있기 때문이다. 이러한 디렉토리의 이름은 여러분이 마음대로 지을 수 있지만, slave의 IP 주소를 사용할 것을 제안한다. 왜냐하면 slave의 IP 주소는 유일하며, 혼동을 주지 않기 때문이다. 예를 들어 첫번째 slave의 고정 IP 주소는 192.168.1.21이다:

# mkdir /diskless/192.168.1.21

/etc안에 있는 여러 설정 파일들은 slave상에서 작동하기 위해 변경되어야 한다. 아래와 같이 명령을 실행하여 master의 /etc디렉토리를 새로운 slave 루트 디렉토리에 복사한다.

# cp -r /etc /diskless/192.168.1.21/etc

아직 파일시스템은 준비되지 않은 상태이다. 왜냐하면 파일시스템은 여러 마운트 포인트와 디렉토리를 필요로 하기 때문이다. 그것들을 만들기 위해 아래와 같이 명령을 실행한다.

# mkdir /diskless/192.168.1.21/home
# mkdir /diskless/192.168.1.21/dev
# mkdir /diskless/192.168.1.21/proc
# mkdir /diskless/192.168.1.21/tmp
# mkdir /diskless/192.168.1.21/mnt
# chmod a+w /diskless/192.168.1.21/tmp
# mkdir /diskless/192.168.1.21/mnt/.initd
# mkdir /diskless/192.168.1.21/root
# mkdir /diskless/192.168.1.21/var
# mkdir /diskless/192.168.1.21/var/empty
# mkdir /diskless/192.168.1.21/var/lock
# mkdir /diskless/192.168.1.21/var/log
# mkdir /diskless/192.168.1.21/var/run
# mkdir /diskless/192.168.1.21/var/spool
# mkdir /diskless/192.168.1.21/usr
# mkdir /diskless/192.168.1.21/opt
(openMosix 만)
# mkdir /diskless/192.168.1.21/mfs

대부분의 "stubs"는 여러분이 알아볼 수 있어야 한다. /dev/proc같은 stubs는 slave를 시작할 때, populate되고, 나머지는 나중에 마운트 된다. 또한 여러분은 /diskless/192.168.1.21/etc/hostname를 slave의 호스트이름에 맞게 고쳐야 한다. 여러분이 slave를 부팅시키기 바로 전에 바이너리 파일과 라이브러리, 그리고 다른 파일들을 populate할 것이다.

DHCP 서버 설정하기
DHCP 서버에 대하여

DHCP는 Dynamic Host Configuration Protocol의 약자이다. DHCP서버는 slave 컴퓨터가 PXE 부팅했을 때, 처음으로 연결하는 컴퓨터이다. DHCP 서버의 주 목적은 IP 주소를 할당하는 것이다. DHCP 서버는 ethernet의 MAC 주소를 바탕으로 IP주소를 할당한다. slave가 주소를 할당받으면, DHCP 서버는 slave에게 초기화 파일시스템과 커널이 어디 있는지 알려준다.

여러분이 시작하기 전에

시작하기 전에 확인해야할 몇가지가 있다. 첫째로 네트워크의 연결을 확인해야 한다.

# ifconfig eth0 enable multicast
# ifconfig -a

eth0디바이스가 작동하는 지 확인한다. 아래와 같이 보일 것이다.

eth0      Link encap:Ethernet  HWaddr 00:E0:83:16:2F:D6
          inet addr:192.168.1.1  Bcast:192.168.1.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:26460491 errors:0 dropped:0 overruns:2 frame:0
          TX packets:32903198 errors:0 dropped:0 overruns:0 carrier:1
          collisions:0 txqueuelen:100
          RX bytes:2483502568 (2368.4 Mb)  TX bytes:1411984950 (1346.5 Mb)
          Interrupt:18 Base address:0x1800

가장 중요한 부분은 MULTICAST이다. 만약 MULTICAST라고 나오지 않는다면, multicast를 지원할 수 있도록 커널을 다시 컴파일해야 한다.

DHCP 서버 설치하기

네트워크에 DHCP 서버가 아직 설치되어 있지 않다면, DHCP 서버를 설치해야 한다.

# emerge dhcp

네트워크에 DHCP가 설치되어 있다면, PXE 부팅이 제대로 작동하기 위해서 설정을 해야 한다.

DHCP 서버 설정하기

DHCP 서버를 시작하기 전에 고쳐야 할 설정파일은 /etc/dhcp/dhcpd.conf이다. 아래의 예제를 복사한 후 고친다.

# cp /etc/dhcp/dhcpd.conf.sample /etc/dhcp/dhcpd.conf
# nano -w /etc/dhcp/dhcpd.conf

설정 파일의 일반적인 윤곽은 아래와 같이 의도적으로 정해진 방법을 따른다.

# 전체 옵션은 여기에
ddns-update-style none;
shared-network LOCAL-NET {
# 공유 네트워크 옵션은 여기에
subnet 192.168.1.0 netmask 255.255.255.0 {
    # 서브넷 네트워크 옵션은 여기에
    host slave{
        # 호스트에 해당되는 옵션은 여기에
    }
    group {
        # 그룹에 해당되는 옵션은 여기에
    }
}
}

The shared-network block is optional and should be used for IPs you want to assign that belong to the same network topology. At least one subnet must be declared and the optional group block allows you to group options between items. A good example of dhcpd.conf looks like this:

shared-network 부분은 선택사항이며, 같은 네트워크 topology에 속한 IP 주소를 할당할 때 사용되어야 한다. 적어도 하나의 subnet이 반드시 선언되어야 하고, 선택 사항인 group 부분을 써서 항목에 대한 옵션들을 그룹으로 모을 수 있다. dhcpd.conf의 좋은 예는 다음과 같다.

# DHCP configuration file for DHCP ISC 3.0
 
ddns-update-style none;
 
# Definition of PXE-specific options
# Code 1: Multicast IP address of boot file server
# Code 2: UDP port that client should monitor for MTFTP responses
# Code 3: UDP port that MTFTP servers are using to listen for MTFTP requests
# Code 4: Number of seconds a client must listen for activity before trying
#         to start a new MTFTP transfer
# Code 5: Number of seconds a client must listen before trying to restart
#         a MTFTP transfer
 
option space PXE;
option PXE.mtftp-ip               code 1 = ip-address;
option PXE.mtftp-cport            code 2 = unsigned integer 16;
option PXE.mtftp-sport            code 3 = unsigned integer 16;
option PXE.mtftp-tmout            code 4 = unsigned integer 8;
option PXE.mtftp-delay            code 5 = unsigned integer 8;
option PXE.discovery-control      code 6 = unsigned integer 8;
option PXE.discovery-mcast-addr   code 7 = ip-address;
 
subnet 192.168.1.0 netmask 255.255.255.0 {
 
  
  class "pxeclients" {
    match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";
    option vendor-class-identifier "PXEClient";
    vendor-option-space PXE;
 
    # At least one of the vendor-specific PXE options must be set in
    # order for the client boot ROMs to realize that we are a PXE-compliant
    # server.  We set the MCAST IP address to 0.0.0.0 to tell the boot ROM
    # that we can't provide multicast TFTP (address 0.0.0.0 means no
    # address).
 
    option PXE.mtftp-ip 0.0.0.0;
 
    # This is the name of the file the boot ROMs should download.
    filename "pxelinux.0";
    # This is the name of the server they should get it from.
    # 마스터의 IP를 쓰라
    next-server 192.168.1.1;
  }

  # 여러분이 특정한 이미지를 사용하지 않고 etherboot를 사용한다면 다음을 쓴다
  class "etherboot" {
        if substring (option vendor-class-identifier, 0, 9) = "Etherboot" {
        filename "/diskless/vmlinuz";
        }
  }
  
  pool {
    max-lease-time 86400;
    default-lease-time 86400;
    # 다음 줄은 원하지 않는 기계가 IP를 얻는 것을 막는다
    deny unknown clients;
  }
 
  host slave21 {
       # 슬레이브의 MAC 주소
       hardware ethernet                00:40:63:C2:CA:C9;
       # 슬레이브의 정적 IP
       fixed-address                    192.168.1.21;
       server-name                      "master";
       # 필요하다면 게이트웨이 IP
       option routers                   192.168.1.1;
       # 필요하다면 DNS IP
       option domain-name-servers       192.168.1.1;
       option domain-name               "mydomain.com";
       # 슬레이브 호스트 이름
       option host-name                 "slave21";
       
       
       # MAC에 해당하는 이미지로 etherboot나 pxe boot를 할 경우 쓴다
       option root-path                 "/diskless/192.168.1.21";
       
       if substring (option vendor-class-identifier, 0, 9) = "Etherboot" {
                        filename "/vmlinuz_arch";
        } else if substring (option vendor-class-identifier, 0,9) ="PXEClient" {
                        filename "/pxelinux.0";
        }
                                                               
  }
}
PXE 부트와 Ehterboot를 함께 사용할 수도 있다.

next-server다음에 나오는 IP 주소는 구체적인 filename을 필요로 한다. 이 IP 주소는 tftp 서버의 IP 주소이며, 보통 master의 IP 주소이다. filename/diskless디렉토리와 관련되어 있다. (이는 다음에 다룰 tftp 서버의 자세한 옵션에 따른 결과이다.) host부분 안에서 hardware ethernet 옵션은 MAC 주소와 그 MAC 주소에 해당하는 고정 IP 주소를 다루고 있다. host-name옵션은 단지 slave의 hostname이고, 포함시키면 좋을 것이다. 이 HOWTO에서 다루지 않는 dhcpd.conf 옵션에 관한 매우 훌륭한 man 페이지가 있다. 아래와 같이 명령을 실행하여 읽을 수 있다.

# man dhcpd.conf
DHCP 서버 설치하기

dhcp의 초기화 스크립트를 실행하기 전에 /etc/conf.d/dhcp를 수정하여 아래와 같이 보이도록 고친다.

IFACE="eth0"
# 필요한 다른 옵션들을 집어넣는다

IFACE변수는 DHCP 서버를 운영할 디바이스를 뜻한다. 우리의 경우에는 eth0이다. IFACE 변수에 더 많은 인자를 추가하는 것은 여러개의 Ethernet카드를 가진 복잡한 네트워크 topology에 유용하다.

# /etc/init.d/dhcp start

아래와 같이 명령을 실행하여 start-up 스크립트에 dhcp 서버를 추가한다.

# rc-update add dhcp default
DHCP 서버 문제 해결

제대로 부팅되었는 지 확인하기 위해 /var/log/daemon.log를 살펴본다. slave가 제대로 부팅되었다면 syslog.log 파일의 맨 아래에는 다음과 같은 몇 줄이 있을 것이다.

DHCPDISCOVER from 00:00:00:00:00:00 via eth0
DHCPOFFER on 192.168.1.21 to 00:00:00:00:00:00 via eth0
DHCPREQUEST for 192.168.1.21 from 00:00:00:00:00:00 via eth0
DHCPACK on 192.168.1.21 to 00:00:00:00:00:00 via eth0
이 log 파일를 통해 여러분은 slave의 MAC 주소를 알 수 있다.

아래 메세지는 설정 파일에 무엇인가 잘못이 있지만 DHCP 서버는 제대로 broadcasting하고 있다는 것을 뜻한다.

no free leases on subnet LOCAL-NET

설정 파일을 변경하고 그 변경된 내용을 적용할 때마다 DHCP 서버를 재시작해야 한다.

# /etc/init.d/dhcpd restart
TFTP 서버와 PXE 리눅스 부트로더나 Etherboot 설정하기
TFTP 서버에 대하여

TFTP는 Trivial File Transfer Protocol의 약자이다. TFTP 서버는 slave에게 커널과 초기화 파일시스템을 제공할 것이다. slave 커널과 파일시스템 모두는 TFTP 서버에 저장될 것이다. 그래서 master를 TFTP 서버로 만드는 것은 좋은 생각이다.

TFTP 서버 설치하기

가장 추천하는 tftp 서버는 tftp-hpa 패키지에서 구할 수 있다. 이 tftp 서버는 SYSLINUX 제작자가 만든 것이고, pxelinux와 잘 작동할 것이다. 아래와 같이 명령을 실행하여 설치할 수 있다.

# emerge tftp-hpa
TFTP 서버 설정하기

/etc/conf.d/in.tftpd 파일을 고쳐야 한다. INTFTPD_PATH 항목에 tftproot 디렉토리를 적어주고, INTFTPD_OPTS 항목에 명령행 옵션을 적어준다. /etc/conf.d/in.tftpd파일은 아래와 같은 모양이어야 한다.

INTFTPD_PATH="/diskless"
INTFTPD_OPTS="-l -v -s ${INTFTPD_PATH}"

-l 옵션은 서버가 stand alone 모드로 listen하므로, inetd를 실행하지 않아도 된다는 것을 의미한다. -v 옵션은 log/error메세지는 충분해야(verbose) 함을 의미한다. -s /diskless 옵션은 tftp 서버의 루트를 지정한다.

TFTP 서버 시작하기

다음과 같이 명령을 실행하여 tftp서버를 시작한다.

# /etc/init.d/in.tftpd start

위 명령은 여러분이 /etc/conf.d/in.tfpd 파일에 지정해 놓은 옵션을 포함하여 tftp서버를 시작할 것이다. 시스템을 부팅할 때 자동으로 서버가 실행되기를 원한다면 아래와 같이 명령을 실행한다.

# rc-update add in.tftpd default
PXELINUX에 대하여

여러분이 이더부트만 사용한다면 이 절은 건너뛰어도 된다. PXELINUX는 TFTP를 통해 제공될 LILO나 GRUB과 같은 기능을 하는 네트워크 부트로더이다. PXELINUX는 client에게 커널과 초기화 파일시스템이 어디에 위치하는 지를 알려주며 여러가지 커널 옵션을 지정할 수 있게 해주는 instruction으로 이루어진 필수적인 작은 묶음이다.

시작하기 전에

여러분은 H. Peter Anvin이 만든 SYSLINUX 패키지에 포함된 pxelinux.0 파일을 준비해야 한다. 아래와 같이 명령을 실행하여 패키지를 설치할 수 있다.

# emerge syslinux
PXELINUX 설치하기 Etherboot에는 필요하지 않다.

tftp 서버를 시작하기 전에 pxelinux를 설치해야 한다. 우선 /diskless디렉토리에 pxelinux 바이너리를 복사한다.

# cp /usr/lib/syslinux/pxelinux.0 /diskless
# mkdir /diskless/pxelinux.cfg
# touch /diskless/pxelinux.cfg/default

위 작업은 기본 부트로더 설정 파일을 생성할 것이다. pxelinux.0 바이너리는 pxelinux.cfg 디렉토리에서 16진수로 된 client의 IP 주소가 이름인 파일을 찾을 것이다. pxelinux.0 바이너리가 그런 파일을 찾지 못할 경우 파일 이름의 가장 오른쪽 자리의 숫자를 제거한 뒤 다시 찾기 시작할 것이며 이러한 작업은 숫자가 모두 제거될 때까지 계속 될 것이다. 2.05버전 이후의 syslinux는 MAX 주소 뒤에 붙는 이름을 가진 파일을 찾을 것이다. 만약 그러한 파일을 찾지 못했을 경우, default 파일을 사용할 것이다.

(16진수로 지정된 IP)
C0A80115
C0A8011
C0A801
C0A80
C0A8
C0A
C0
C
(처음의 01은 이더넷을 의미하고, 다음 바이트들은 슬레이브의 MAC 주소와 일치한다.)
01-00-40-63-c2-ca-c9
default
이들은 모두 소문자이다.

default 파일을 가지고 시작해보자.

DEFAULT /diskless/bzImage
APPEND ip=dhcp root=/dev/nfs nfsroot=192.168.1.1:/diskless/192.168.1.21

DEFAULT tag는 pxelinux가 미리 컴파일해 놓은 bzImage를 가리키도록 한다. APPEND tag는 초기화 옵션을 덧붙이는 기능을 한다. slave 커널을 NFS_ROOT_SUPPORT으로 컴파일하였기 때문에, nfsroot라고 덧붙일 것이다. 먼저 나오는 IP 주소는 master의 IP 주소이고 두번째 나오는 IP 주소는 slave의 초기화 파일시스템을 저장하기 위해 /diskless 안에 만들어 놓았던 디렉토리이다.

Etherboot에 대하여 여러분이 PXE 부트를 사용한다면 필요하지 않다.

Etherboot는 TFTP 서버의 네트워크 부트 이미지를 이용해 부트한다. PXE와 같이 이것도 LILO나 GRUB과 동등하다. mknbi 유틸리티는 여러분이 다른 옵션을 써서 다른 이미지를 만드는 것을 가능하게 해 준다.

시작하기 전에

여러분은 Etherboot 이미지를 만들기 위해 mknbi (네트워크 부팅에 유용한 태그가 붙은 커널 이미지를 만드는 유틸리티) 패키지를 얻을 필요가 있다. 이 도구는 여러분의 원래 커널로부터 미리 설정된 커널 이미지를 만든다. 이는 아래에서 보여질 부트 옵션들을 포함한다.

# emerge mknbi
Etherboot 설정하기

이 절에서 우리는 단순한 Etherboot 이미지를 만들 것이다. dhcp 서버가 클라이언트에게 dhcp.conf의 "option root-path"에 있는 root-path를 제공하기 때문에, 우리는 이를 여기에서 설명하지 않을 것이다. 더 자세한 내용은 mknbi 매뉴얼에서 찾을 수 있다.

# man mknbi

부트 이미지를 만들어야 한다. dhcp와 rootpath를 커널에 넘길 수 있는 부트 가능한 ELF 이미지를 만들 것이다. 또한 커널에게 네트워크에서 dhcp 서버를 찾도록 강제해야 한다.

# mkelf-linux -ip=dhcp /diskless/bzImage > /diskless/vmlinuz 
아키텍처에 특정한 이미지를 만드려면 bzImage_archvmlinuz_arch를 입력해야 한다.
네트워크 부팅 과정에서의 문제 해결

여러분이 네트워크 부트 프로세스를 디버그할 수 있는 몇가지가 있다. 첫째로 여러분은 tcpdump라 불리우는 툴을 사용할 수 있다. 아래와 같이 명령을 실행하여 tcpdump를 설치한다.

# emerge tcpdump

이제부터 여러분은 여러가지 네트워크 트래픽을 탐지할 수 있고, 여러분의 client/server간의 통신이 제대로 이루어지는 지 확인할 수 있다. 제대로 작동하지 않는 것들이 있을 때, 여러분이 체크할만한 몇가지가 있다. 우선 확인해야 할 것은 client/server가 물리적으로 적절히 연결되어 있는 지와 네트워크 케이블이 손상되지 않았는 지이다. client/server가 특정 포트에서 요청을 받아들이지 못한다면, 방화벽에 의한 간섭이 없는 지 확인해라. 두 컴퓨터 사이의 통신을 확인하기 위해서 아래와 같이 명령을 실행해라.

# tcpdump host client_ip and server_ip

아래와 같이 명령을 실행하여 tcpdump를 이용한 특정 포트상의 통신 탐지도 가능하다.

# tcpdump port 69

보통 "PXE-E32: TFTP open time-out"와 같은 에러가 생길 것이다. 이 에러는 방화벽에 관련된 에러이다. TCPwrappers를 사용한다면 /etc/hosts.allowetc/hosts.deny가 제대로 설정되어 있는 지 확인하라. client는 server로의 연결이 허락되어야 한다.

NFS 서버 설정하기
NFS 서버에 대하여

NFS는 Network File System의 약자다. NFS 서버는 slave에게 디렉토리를 제공하기 위해 사용될 것이다. 이부분은 나중에 조금씩 개인적으로 변경될 수 있다. 지금 다루려는 공통된 부분은 미리 준비된 slave node가 diskless 부팅을 하는 것이다.

Portmapper에 대하여

여러가지 client/server 서비스는 특정 포트를 탐지하지 못하고 대신 RPCs(Remote Procedure Calls)에 의존한다. 서비스가 초기화될 때, 서비스는 임의의 포트를 탐지하고 Portmapper 유틸리티를 이용하여 그 포트를 등록한다. NFS는 RPCs에 의존적이어서 NFS가 시작되기 전에 Portmapper가 실행되어 있어야 한다.

시작하기 전에

NFS 서버는 커널레벨 지원이 필요하며, 여러분의 커널이 지원하지 못하면 master 커널을 다시 컴파일하여야 한다. 아래와 같이 명령을 실행하여 master 커널을 다시 한번 확인하라.

# grep NFS /usr/src/linux/.config_master

커널이 제대로 설정되었다면, 아래와 같은 결과를 보게 될 것이다.

# CONFIG_ROOT_NFS is not set
CONFIG_NFSD=y
CONFIG_NFSD_V3=y
# CONFIG_NFSD_TCP is not set
# CONFIG_NCPFS_NFS_NS is not set
NFS 서버 설치하기

portage를 통해 NFC 패키지를 설치하려면 아래와 같은 명령을 실행한다.

# emerge nfs-utils

이 패키지는 portmapping utility, nft sserver, nfs client utilities를 설치하고, 자동으로 의존성을 구성해준다.

NFS 서버 설정하기

여러분은 세가지 주요 설정 파일을 고쳐야 한다.

/etc/exports
/diskless/192.168.1.21/etc/fstab
/etc/conf.d/nfs

/etc/exports 파일은 NFS를 통해 어떻게, 누구에게, 무엇을 export할지를 정한다. slave의 fstab 파일은 master가 export할 NFS 파일시스템을 마운트 할 수 있도록 고쳐져야 한다.

전형적인 master의 /etc/exports 파일은 아래와 같은 모양이다.

# 각 슬레이브에 대해 다음과 같은 줄을 하나씩
/diskless/192.168.1.21   192.168.1.21(sync,rw,no_root_squash,no_all_squash)
# 모든 슬레이브에 공통
/opt   192.168.1.0/24(sync,ro,no_root_squash,no_all_squash)
/usr   192.168.1.0/24(sync,ro,no_root_squash,no_all_squash)
/home  192.168.1.0/24(sync,rw,no_root_squash,no_all_squash)
# 공유 로그를 쓰고 싶은 경우
/var/log   192.168.1.21(sync,rw,no_root_squash,no_all_squash)

첫번째 필드는 export될 디렉토리를 가리키며, 다음 필드는 대상과 방법을 가리킨다. 이 필드는 두 부분으로 나누어 볼 수 있다. 누가 특정한 디렉토리에 마운트할 수 있도록 허락되었는지와 마운트하는 client가 파일시스템에 무엇을 (ro는 읽기 전용, rw는 읽기/쓰기를 의미한다. no_root_squashno_all_squash는 diskless clients가 I/O를 요청하려 할 때, 서로 충돌하지 않도록 해주기 때문에 매우 중요하다.) 할 수 있는지로 나누어 진다. slave의 fstab, /diskless/192.168.1.21/etc/fstab은 아래와 같은 모양이다.

# 이 항목들은 필수다
master:/diskless/192.168.1.21   /         nfs     sync,hard,intr,rw,nolock,rsize=8192,wsize=8192    0 0
master:/opt                     /opt      nfs     sync,hard,intr,ro,nolock,rsize=8192,wsize=8192    0 0
master:/usr                     /usr      nfs     sync,hard,intr,ro,nolock,rsize=8192,wsize=8192    0 0
master:/home                    /home     nfs     sync,hard,intr,rw,nolock,rsize=8192,wsize=8192    0 0
none                            /proc     proc    defaults                                     0 0
# 유용하지만 필요하지는 않다
master:/var/log                 /var/log  nfs     hard,intr,rw                                 0 0

(openMosix 클러스터를 설치할 때만)
none                            /mfs      mfs     dfsa=1                                       0 0

이 예에서, master는 단지 master의 호스트네임이지만, IP 주소를 대신 사용할 수도 있다. 처음 필드는 마운트 될 디렉토리를 가르키며, 두번째 필드는 그 디렉토리가 마운트 되는 곳을 의미한다. 세번째 필드는 파일시스템을 보여주며, NFS로 마운트 될 디렉토리는 반드시 NFS로 되어 있어야 한다. 네번째 필드는 마운트 과정에서 사용되는 여러가지 옵션을 가리킨다. (마운트 옵션에 대하여 알고 싶으면 mount(1)을 보라.) 몇몇 사람들이 soft 마운트 포인트 때문에 어려움을 겪기 때문에 우리는 모든 디렉토리를 hard로 마운트하였다. 그러나 여러분의 클러스터를 더욱 효율적으로 만들기 위해서 /etc/fstab 안의 여러 옵션들을 살펴보아야 한다.

여러분이 수정해야할 마지막 파일은 /etc/conf.d/nfs이다. 이 파일은 nfs가 초기화될 때 사용되는 여러 옵션들에 대한 파일이며 아래와 같은 모습이다.

# Config file for /etc/init.d/nfs

# Number of servers to be started up by default
RPCNFSDCOUNT=8

# Options to pass to rpc.mountd
RPCMOUNTDOPTS=""

여러분은 RPCNFSDCOUNT를 네트워크에 존재하는 diskless node의 수로 바꿔줘야 한다.

NFS 서버 시작하기

여러분은 아래와 같이 명령을 실행하여 /etc/init.d 안에 있는 스크립트를 이용하여 nfs 서버를 시작해야 한다.

# /etc/init.d/nfs start

만약 시스템이 부팅될 때 nfs 서버를 시작하기 위해 이 스크립트를 실행하려면 아래와 같이 명령을 실행해라.

# rc-update add nfs default
슬레이브 파일시스템 마무리하기
빠진 파일 복사

지금부터 master의 파일시스템에 맞춰서 slave의 파일시스템을 만들고, 구체적인 몇몇 파일을 보존하면서 필요한 바이너리를 넣을 것이다.

# rsync -avz /bin /diskless/192.168.1.21
# rsync -avz /sbin /diskless/192.168.1.21
# rsync -avz /lib /diskless/192.168.1.21
cp 대신에 rsync -avz를 사용하는 이유는 심볼릭 링크들과 권한들을 유지하기 위해서이다.
초기화 스크립트들

기본 스크립트는 여러분의 slave node에는 맞지 않는 checkroot를 실행하려 할 것이다. /diskless/192.168.1.21/sbin/rc를 직접 고치는 어려운 방법이 있지만, 어렵고 위험하다. 여러분이 node의 파일시스템을 다시 동기화하려고 결정했다면, 망가질 수도 있고, 스크립트 파일을 그대로 남겨두는 것을 잊을 수도 있다. 쉽게 하는 방법으로 시스템이 부팅될 때 /fastboot 파일을 가지고 있는 방법이 있다. 이 파일은 checkroot가 어떠한 파일시스템 체크도 실행하지 않도록 해준다. 하지만 그것이 초기화 과정을 마쳤을 때, /fastboot 파일을 지울 것이다. 그렇기 때문에 우리는 아래와 같이 초기화 과정의 마지막에 이 파일을 다시 생성하도록 해야한다.

(다음 부팅을 위해 /fastboot 파일 만들기)
# touch /diskless/192.168.1.21/fastboot
(부팅할 때마다 /fastboot 파일 만들기)
# echo "touch /fastboot" >> /diskless/192.168.1.21/etc/conf.d/local.start

여러분의 diskless node에서 필요한 서비스에 해당하는 초기화 스크립트를 디렉토리 안에 넣어 놓아야 한다. 이 작업은 여러분의 slave가 무엇을 할지에 따라 결정된다.

master로 로그인했을 때, rc-update 프로그램을 이용하여 slave 런레벨로부터 스크립트를 추가하거나 제거하지 말아라. 이 작업은 여러분의 master 런레벨을 변경할 것이다. 직접 링크를 만들거나, slave node로 로그인하여 ssh를 이용하거나, 모니터나 키보드를 slave에 연결하고 작업해라.
/diskless/192.168.1.21/etc/runlevels/:
total 16
drwxr-xr-x    2 root     root         4096 2003-11-09 15:27 boot
drwxr-xr-x    2 root     root         4096 2003-10-01 21:10 default
drwxr-xr-x    2 root     root         4096 2003-03-13 19:05 nonetwork
drwxr-xr-x    2 root     root         4096 2003-02-23 12:26 single
 
/diskless/192.168.1.21/etc/runlevels/boot:
total 0
lrwxrwxrwx    1 root     root           20 2003-10-18 17:28 bootmisc -> /etc/init.d/bootmisc
lrwxrwxrwx    1 root     root           19 2003-10-18 17:28 checkfs -> /etc/init.d/checkfs
lrwxrwxrwx    1 root     root           17 2003-10-18 17:28 clock -> /etc/init.d/clock
lrwxrwxrwx    1 root     root           23 2003-10-18 17:28 consolefont -> /etc/init.d/consolefont
lrwxrwxrwx    1 root     root           20 2003-10-18 17:28 hostname -> /etc/init.d/hostname
lrwxrwxrwx    1 root     root           19 2003-10-18 17:28 keymaps -> /etc/init.d/keymaps
lrwxrwxrwx    1 root     root           22 2003-10-18 17:28 localmount -> /etc/init.d/localmount
lrwxrwxrwx    1 root     root           18 2003-10-18 17:28 net.lo -> /etc/init.d/net.lo
lrwxrwxrwx    1 root     root           20 2003-10-18 17:28 netmount -> /etc/init.d/netmount
lrwxrwxrwx    1 root     root           19 2003-10-18 17:28 portmap -> /etc/init.d/portmap
lrwxrwxrwx    1 root     root           21 2003-10-18 17:28 rmnologin -> /etc/init.d/rmnologin
lrwxrwxrwx    1 root     root           18 2003-10-18 17:28 serial -> /etc/init.d/serial
lrwxrwxrwx    1 root     root           19 2003-10-18 17:28 urandom -> /etc/init.d/urandom
 
/diskless/192.168.1.21/etc/runlevels/default:
total 0
lrwxrwxrwx    1 root     root           17 2003-10-18 17:28 clock -> /etc/init.d/clock
lrwxrwxrwx    1 root     root           19 2003-10-18 17:28 distccd -> /etc/init.d/distccd
lrwxrwxrwx    1 root     root           17 2003-10-18 17:28 local -> /etc/init.d/local
lrwxrwxrwx    1 root     root           19 2003-10-18 17:28 metalog -> /etc/init.d/metalog
lrwxrwxrwx    1 root     root           22 2003-10-18 17:28 ntp-client -> /etc/init.d/ntp-client
lrwxrwxrwx    1 root     root           16 2003-10-18 17:28 ntpd -> /etc/init.d/ntpd
lrwxrwxrwx    1 root     root           16 2003-10-18 17:28 sshd -> /etc/init.d/sshd
lrwxrwxrwx    1 root     root           17 2003-10-18 17:28 vcron -> /etc/init.d/vcron
 
/diskless/192.168.1.21/etc/runlevels/nonetwork:
total 0
lrwxrwxrwx    1 root     root           17 2003-10-18 17:28 local -> /etc/init.d/local
 
/diskless/192.168.1.21/etc/runlevels/single:
total 0

지금이야 말로 여러분의 slave를 부팅하고 행운을 빌기에 좋은 시간이다. 작동하는가? 축하한다. 여러분은 diskless node의 소유자로서 스스로 자랑스럽게 여겨도 좋다. :)