NASを持っていないので、GlusterFSで分散ファイルシステムを構築してNFSとして運用する

Jul 27, 2024, 5:10 PM
NASを買おうかな・・・と思っていたのですが、高性能なNASは高い・・・ので、手元にあるPC郡で、分散ファイルシステムを構築して使用します。

GlusterFS とは

オープンソースの分散ファイルシステムで、大規模なデータストレージソリューションを提供します。複数のサーバーを統合して1つの大規模なストレージプールを形成し、高い可用性、拡張性、パフォーマンスを実現します。

簡単な言葉にすると・・・
複数PCのディレクトリを1つにまとめて、大きなサイズのディレクトリにすることができたり、あるいは、RAID1のようにファイルのコピーを複数のPCに持たせることでPCが壊れてもデータを守ることができる、そんな素晴らしいシステムです。

GlusterFSの特徴

  • 分散性
    複数のサーバーを一つの論理的なストレージプールとして利用できます。これにより、ストレージ容量やパフォーマンスを容易に拡張可能です。
  • 高可用性
    データのレプリケーション機能により、サーバーやディスクの故障時でもデータが失われることなくアクセスを継続できます。
  • スケーラビリティ
    サーバーやディスクを追加するだけで、ストレージ容量や性能を簡単に拡張できます。数ペタバイト規模のストレージにも対応可能です。
  • パフォーマンス
    ストライピングやキャッシングなどの技術を用いて、データの読み書き速度を向上させます。
  • フレキシビリティ
    標準的なハードウェアを使用して構築でき、専用のストレージハードウェアが不要です。また、さまざまなオペレーティングシステム上で動作します。

GlusterFSの仕組み

  • ボリューム
    GlusterFSでは、ストレージを論理的な単位である「ボリューム」に分けて管理します。ボリュームは複数のサーバー(ノード)上のディスクから構成されます。
  • トランスポートレイヤー
    GlusterFSは、通信プロトコルとしてTCP/IPやRDMA(Remote Direct Memory Access)を使用し、データ転送の効率を高めています。
  • ストレージアグリゲーション
    GlusterFSは、複数のディスクを統合して一つの大容量ストレージとして扱います。これにより、管理の簡便さと性能向上を図ります。
  • ネイティブクライアントとNFS
    GlusterFSにはネイティブクライアントが用意されており、効率的なファイルアクセスが可能です。また、NFSやSMBなどのプロトコルを使用してアクセスすることもできます。

GlusterFSのボリュームタイプ

GlusterFSは、RAID0, RAID1 のように、ファイルを保存する方法が沢山あります。ここでは3つのボリュームタイプのみ説明します。
以下、画像はわかりやすさ優先で作っています。実際とは多少違うかもしれません。

Distributed Volume (分散ボリューム)


  • 特徴: データを複数のノードに均等に分散して保存します。
  • メリット: ストレージ容量を最大限に活用できます。
  • デメリット: 冗長性がなく、一つのノードが故障すると、そのノード上のデータが失われます。

Striped Volume (ストライプボリューム)


  • 特徴: ファイルを複数のノードに分割して保存し、並列にアクセスします。
  • メリット: 大きなファイルの読み書き速度が向上します。
  • デメリット: 冗長性がなく、ストライプのいずれかのノードが故障すると、そのファイル全体が失われます。


Replicated Volume (レプリケートボリューム)


  • 特徴: データを複数のノードに複製(レプリケーション)して保存します。
  • メリット: 各データが複数のノードに保存されるため、1つのノードが故障してもデータは失われません。ノードの故障時でもデータアクセスが可能です。
  • デメリット: 同じデータを複数のノードに保存するため、総ストレージ容量は減少します。書き込み操作が複数のノードに対して行われるため、書き込み速度が低下する可能性があります。

レプリケーションボリュームで構築

私のニーズ的に、1台のPCが壊れても(再起動しても)データにアクセスできる状態を作りたいので、レプリケーションボリュームで構築していきます。
なお、2つのノード(PC)でも構築可能ですが、例えば、1台を再起動したとして、再起動後、どちらの状態が正しいのか?がわからなくなるため、最低でも3つのノード(PC)での構築が好ましいです。

ノードの選定

microAIのおうちDCの構成は
  • Raspberry Pi 4 x 1台
  • Raspberry Pi 5 x 3 台
  • Jetson Orin Nano NX 16G x 2台
  • GEEKOM Mini Air 12 x 2台
の合計、8台で構築されています。GEEKOM Mini Air 12 は、今回のファイルシステム構築用に購入しているので、この2台は確定です。
Raspberry Pi 4 (SDカード)は、ディスクの読み書きが遅く、Raspberry Pi 5 もSSDを乗せていますが、やはり遅いため除外。
GEEKOM (amd64) と Jetson Orin Nano NX 16G (arm64) と、アーキテクチャが違うのが、若干気になりますが、4台で構築していきます。
4台のIPは以下の通りです
  • GEEKOM Mini Air 12 1: 10.0.0.31
  • GEEKOM Mini Air 12 2: 10.0.0.32
  • Jetson Orin Nano NX 16G 1: 10.0.0.21
  • Jetson Orin Nano NX 16G 2: 10.0.0.22

ファイルシステムの確認

GEEKOM Mini Air 12

lsblk -f
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
nvme0n1
├─nvme0n1p1 vfat FAT32 9527-FE9E 1G 1% /boot/efi
├─nvme0n1p2 ext4 1.0 908bf71c-6f46-461b-83cf-c9f75efc2e62 1.6G 9% /boot
└─nvme0n1p3 LVM2_member LVM2 001 EKmeoX-ReZs-YBda-mMOh-SUCG-aYRE-wYdaEi
└─ubuntu--vg-ubuntu--lv
436.8G 2% /
ext4 です

Jetson Orin Nano NX 16G

lsblk -f
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
loop0
vfat FAT16 L4T-README
1234-ABCD
nvme0n1

├─nvme0n1p1
│ ext4 1.0 0aaf6132-7822-48ee-975e-692640881866 577G 32% /var/lib/kubelet/pods/541dc032-6a61-4136-bd7f-e0f54c8f5ade/volume-subpaths/milvus-config/standalone/2
こちらも ext4 でした。問題なさそうです。

GlusterFS のインストール

4台ともにインストールします
sudo apt update
sudo apt install -y glusterfs-server
sudo systemctl start glusterd
sudo systemctl enable glusterd

インストールされたバージョンの確認

GEEKOM Mini Air 12

$ gluster --version
glusterfs 11.1
Repository revision: git://git.gluster.org/glusterfs.git
Copyright (c) 2006-2016 Red Hat, Inc. <https://www.gluster.org/>
GlusterFS comes with ABSOLUTELY NO WARRANTY.
It is licensed to you under your choice of the GNU Lesser
General Public License, version 3 or any later version (LGPLv3
or later), or the GNU General Public License, version 2 (GPLv2),
in all cases as published by the Free Software Foundation.

Jetson Orin Nano NX 16G

$ gluster --version
glusterfs 10.1
Repository revision: git://git.gluster.org/glusterfs.git
Copyright (c) 2006-2016 Red Hat, Inc. <https://www.gluster.org/>
GlusterFS comes with ABSOLUTELY NO WARRANTY.
It is licensed to you under your choice of the GNU Lesser
General Public License, version 3 or any later version (LGPLv3
or later), or the GNU General Public License, version 2 (GPLv2),
in all cases as published by the Free Software Foundation.

Jetson の方は古いですね。バージョンを合わせていきます。
一度、アンインストール
sudo apt remove --purge glusterfs-server glusterfs-cli glusterfs-common
sudo apt autoremove
sudo apt clean

リポジトリ追加
sudo add-apt-repository ppa:gluster/glusterfs-11

再度インストール
sudo apt update
sudo apt install -y glusterfs-server
sudo systemctl start glusterd
sudo systemctl enable glusterd

バージョン確認
$ gluster --version
glusterfs 11.1
Repository revision: git://git.gluster.org/glusterfs.git
Copyright (c) 2006-2016 Red Hat, Inc. <https://www.gluster.org/>
GlusterFS comes with ABSOLUTELY NO WARRANTY.
It is licensed to you under your choice of the GNU Lesser
General Public License, version 3 or any later version (LGPLv3
or later), or the GNU General Public License, version 2 (GPLv2),
in all cases as published by the Free Software Foundation.
11.1 になってくれました。

バージョンを固定

バージョンがあったので、今後ずれないように、バージョンを固定します。
4台ともに実行
sudo apt-mark hold glusterfs-server glusterfs-cli glusterfs-common

クラスター構築

4台中どれからでも良いのですが今回は、GEEKOM Mini Air 12 1: 10.0.0.31 を起点にクラスターを構築します。
sudo gluster peer probe 10.0.0.32
sudo gluster peer probe 10.0.0.21
sudo gluster peer probe 10.0.0.22
※自分自身は追加する必要がありません。自動的に追加されます。

クラスターの状況確認

sudo gluster peer status
Number of Peers: 3

Hostname: 10.0.0.32
Uuid: ca708d7f-b87b-492f-8586-65c8be2a3cdb
State: Peer in Cluster (Connected)

Hostname: 10.0.0.22
Uuid: a45cb44b-4d2b-4a25-b9be-6d7fd1c33303
State: Peer in Cluster (Connected)

Hostname: 10.0.0.21
Uuid: 68d3ae1c-53df-4115-a398-5f0c40fd52ca
State: Peer in Cluster (Connected)
自分が、他の3台(合計4台)とつながっていることがわかります。

GlusterFS 用のディレクトリ(Brick)を作成

4台ともに以下のコマンドでGlusterFS用のディレクトリを作ります。
sudo mkdir /glusterfs
sudo chmod 775 /glusterfs
sudo chown gluster:gluster /glusterfs

ボリュームを作る

作った Brick をまとめたボリュームを作ります。本来はパーティションを分けた方が良いのですが、面倒なので、force オプションを付けてルートパーティションで行います。
$ sudo gluster volume create gv0 replica 4 10.0.0.31:/glusterfs 10.0.0.32:/glusterfs 10.0.0.21:/glusterfs 10.0.0.22:/glusterfs force
volume create: gv0: success: please start the volume to access data
上記は4つのノードのBrickに4つのレプリカが作られます。(最大3台止まってもデータへアクセエスできます)

ボリュームを起動

$ sudo gluster volume start gv0
volume start: gv0: success

ボリューム確認

$ sudo gluster volume info
Volume Name: gv0
Type: Replicate
Volume ID: 32608863-f7c0-451d-9c3f-f6d963a49172
Status: Started
Snapshot Count: 0
Number of Bricks: 1 x 4 = 4
Transport-type: tcp
Bricks:
Brick1: 10.0.0.31:/glusterfs
Brick2: 10.0.0.32:/glusterfs
Brick3: 10.0.0.21:/glusterfs
Brick4: 10.0.0.22:/glusterfs
Options Reconfigured:
cluster.granular-entry-heal: on
storage.fips-mode-rchecksum: on
transport.address-family: inet
nfs.disable: on
performance.client-io-threads: off

作ったボリュームをマウントする

4台全部で行っても、NFSとして運用するノードだけでも良いのですが、作ったボリュームをマウントします。
sudo mkdir -p /mnt/gv0
sudo mount -t glusterfs 10.0.0.31,10.0.0.32,10.0.0.21,10.0.0.22:/gv0 /mnt/gv0
このようにIPを複数書いておくことで、どれかが止まってもフェイルオーバーしてくれます。
今後、ノードを足したとしても追記する必要は必ずしもありません。4台のうち、どれかが動いていればよいので。

再起動時もマウントされるように

sudo nano /etc/fstab

10.0.0.31,10.0.0.32,10.0.0.21,10.0.0.22:/gv0 /mnt/gv0 glusterfs defaults,_netdev 0 0


動作確認

cd /mnt/gv0
sudo touch test.txt
どのノードでも良いので、上記でファイルを作ります。
別のノードで
cd /mnt/gv0
ls -la
total 8
drwxrwxr-x 4 gluster gluster 4096 Jul 27 16:47 .
drwxr-xr-x 3 root root 4096 Jul 27 16:45 ..
-rw-r--r-- 1 root root 0 Jul 27 16:47 test.txt
今作ったファイルがあれば正しく動いています。

NFSでファイルサーバー化する

GlusterFS用のNFSサーバーを使って、このボリュームをファイルサーバー化します。

NFSのインストール

今回は、
  • GEEKOM Mini Air 12 1: 10.0.0.31
  • GEEKOM Mini Air 12 2: 10.0.0.32
の2台をNFSにします。

GEEKOM Mini Air 12 1: 10.0.0.31, GEEKOM Mini Air 12 2: 10.0.0.32 両方で

sudo apt install -y nfs-ganesha nfs-ganesha-gluster

NFSの設定

GEEKOM Mini Air 12 1: 10.0.0.31

sudo nano /etc/ganesha/ganesha.conf

EXPORT {
FSAL {
name = GLUSTER;
hostname = "10.0.0.31";
volume = "gv0";
}

Export_Id = 1;
Path = "/mnt/gv0";
Pseudo = "/gv0";
Access_type = RW;
Squash = No_root_squash;
Disable_ACL = TRUE;
Protocols = "3,4";
Transports = "UDP,TCP";
SecType = "sys";
}
上記を追記します。

sudo systemctl restart nfs-ganesha
リスタート

$ showmount -e localhost
Export list for localhost:
/mnt/gv0 (everyone)
/mnt/gv0 が公開されていることが確認できます。

GEEKOM Mini Air 12 2: 10.0.0.32

sudo nano /etc/ganesha/ganesha.conf

EXPORT {
FSAL {
name = GLUSTER;
hostname = "10.0.0.32";
volume = "gv0";
}

Export_Id = 1;
Path = "/mnt/gv0";
Pseudo = "/gv0";
Access_type = RW;
Squash = No_root_squash;
Disable_ACL = TRUE;
Protocols = "3,4";
Transports = "UDP,TCP";
SecType = "sys";
}
上記を追記します。

sudo systemctl restart nfs-ganesha
リスタート

$ showmount -e localhost
Export list for localhost:
/mnt/gv0 (everyone)
/mnt/gv0 が公開されていることが確認できます。

NFSをマウントする

GlusterFS をインストールしていない作業用の M1 Mac から、作ったNFSをマウントしてみます
$ showmount -e 10.0.0.31
Exports list on 10.0.0.31:
/mnt/gv0 Everyone

$ sudo mkdir -p /Users/home/gluster
$ sudo mount -t nfs -o vers=4 10.0.0.31:/gv0 /Users/home/gluster
$ cd gluster/
$ ls -la
total 8
drwxrwxr-x 4 nobody nobody 4096 Jul 27 16:47 .
drwxr-xr-x+ 106 akimoto staff 3392 Jul 27 17:04 ..
-rw-r--r-- 1 root wheel 0 Jul 27 16:47 test.txt

$ sudo touch mac.txt
上述で作った、test.txt が確認できました。

クラスター側で
ls -la
total 12
drwxrwxr-x 4 gluster gluster 4096 Jul 27 08:05 .
drwxr-xr-x 3 root root 4096 Jul 27 07:45 ..
-rw-r--r-- 1 root root 4096 Jul 27 08:05 ._mac.txt
-rw-r--r-- 1 root root 0 Jul 27 08:05 mac.txt
-rw-r--r-- 1 root root 0 Jul 27 07:47 test.txt
Mac側で作ったファイルも確認できました。

まとめ

まだ運用に乗せていないので、読み書きのスピードが実用に耐えうるかはわかりませんが、それほど速度を求められないケースにおいては有効なのではないでしょうか?
NASを買うコストが節約できたので、とりあえず満足です🍻
とはいえ、NASほしいな・・・

Jul 28, 2024, 8:04 AM 追記 速度テスト

書き込み

$ sudo dd if=/dev/zero of=/mnt/gv0/testfile bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 27.4427 s, 39.1 MB/s
1Gのファイル書き込みに、27.4427秒、39.1MB/s=312.8 Mbps でした。
スイッチングハブは、1Gbps なので、もう少しスピードでて欲しいところではあります。

ちなみに、クラスター外の通常のディレクトリの速度での実行結果は
$ sudo dd if=/dev/zero of=/home/geekom-02/testfile bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 0.884114 s, 1.2 GB/s
GlusterFSのNFS経由だと 1/31 までスピードが落ちますね。

読み込み (GEEKOM)

$ dd if=/mnt/gv0/testfile of=/dev/null bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 1.22425 s, 877 MB/s
読み込みは、自身からとっているのでしょうか、877 MB/s = 7,016 Mbps と、スイッチングハブ 1Gbps を超えています。

読み込み(Jetson)

dd if=/mnt/gv0/testfile of=/dev/null bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 2.82261 s, 380 MB/s
こちらも 3,040 Mbps とスイッチングハブ 1Gbps を超えています。


GlusterFS, NFS のステータス確認

ピアステータスの確認

$ sudo gluster peer status
Number of Peers: 3

Hostname: 10.0.0.32
Uuid: ca708d7f-b87b-492f-8586-65c8be2a3cdb
State: Peer in Cluster (Connected)

Hostname: 10.0.0.22
Uuid: a45cb44b-4d2b-4a25-b9be-6d7fd1c33303
State: Peer in Cluster (Connected)

Hostname: 10.0.0.21
Uuid: 68d3ae1c-53df-4115-a398-5f0c40fd52ca
State: Peer in Cluster (Connected)

ボリュームステータスの確認

$ sudo gluster volume status
Status of volume: gv0
Gluster process TCP Port RDMA Port Online Pid
------------------------------------------------------------------------------
Brick 10.0.0.31:/glusterfs 57519 0 Y 862348
Brick 10.0.0.32:/glusterfs 52023 0 Y 861227
Brick 10.0.0.21:/glusterfs 58455 0 Y 3727323
Brick 10.0.0.22:/glusterfs 57976 0 Y 3067620
Self-heal Daemon on localhost N/A N/A Y 862365
Self-heal Daemon on 10.0.0.32 N/A N/A Y 861244
Self-heal Daemon on 10.0.0.21 N/A N/A Y 3727339
Self-heal Daemon on 10.0.0.22 N/A N/A Y 3067652

Task Status of Volume gv0
------------------------------------------------------------------------------
There are no active volume tasks

$ sudo gluster volume info gv0
Volume Name: gv0
Type: Replicate
Volume ID: 32608863-f7c0-451d-9c3f-f6d963a49172
Status: Started
Snapshot Count: 0
Number of Bricks: 1 x 4 = 4
Transport-type: tcp
Bricks:
Brick1: 10.0.0.31:/glusterfs
Brick2: 10.0.0.32:/glusterfs
Brick3: 10.0.0.21:/glusterfs
Brick4: 10.0.0.22:/glusterfs
Options Reconfigured:
cluster.granular-entry-heal: on
storage.fips-mode-rchecksum: on
transport.address-family: inet
nfs.disable: on
performance.client-io-threads: off

NFS-Ganeshaサービスのステータス確認

$ sudo systemctl status nfs-ganesha
● nfs-ganesha.service - NFS-Ganesha file server
Loaded: loaded (/usr/lib/systemd/system/nfs-ganesha.service; enabled; preset: enabled)
Active: active (running) since Sat 2024-07-27 07:56:05 UTC; 21h ago
Docs: http://github.com/nfs-ganesha/nfs-ganesha/wiki
Main PID: 871110 (ganesha.nfsd)
Tasks: 26 (limit: 18836)
Memory: 68.8M (peak: 84.4M)
CPU: 1min 26.987s
CGroup: /system.slice/nfs-ganesha.service
└─871110 /usr/bin/ganesha.nfsd -C -L /var/log/ganesha/ganesha.log -f /etc/ganesha/ganesha.conf -N NIV_EVENT

Jul 27 07:56:05 geekom-01 systemd[1]: Starting nfs-ganesha.service - NFS-Ganesha file server...
Jul 27 07:56:05 geekom-01 (bash)[871108]: nfs-ganesha.service: Referenced but unset environment variable evaluates to an empty string: EPOCH, GNODEID, NUMACTL, NUMAOPTS
Jul 27 07:56:05 geekom-01 systemd[1]: Started nfs-ganesha.service - NFS-Ganesha file server.
Jul 27 07:56:05 geekom-01 ganesha.nfsd[871110]: libnfsidmap: Unable to determine the NFSv4 domain; Using 'localdomain' as the NFSv4 domain which means UIDs will be mapped to the 'Nobo>

NFS-Ganeshaログファイルの確認

$ sudo tail -f /var/log/ganesha/ganesha.log
27/07/2024 07:57:35 : epoch 66a4a815 : geekom-01 : ganesha.nfsd-871110[reaper] nfs_try_lift_grace :STATE :EVENT :check grace:reclaim complete(0) clid count(0)
27/07/2024 07:57:35 : epoch 66a4a815 : geekom-01 : ganesha.nfsd-871110[reaper] nfs_lift_grace_locked :STATE :EVENT :NFS Server Now NOT IN GRACE

RPCサービスの確認

$ sudo systemctl status rpcbind
● rpcbind.service - RPC bind portmap service
Loaded: loaded (/usr/lib/systemd/system/rpcbind.service; enabled; preset: enabled)
Active: active (running) since Sat 2024-07-27 06:01:01 UTC; 23h ago
TriggeredBy: ● rpcbind.socket
Docs: man:rpcbind(8)
Main PID: 837327 (rpcbind)
Tasks: 1 (limit: 18836)
Memory: 800.0K (peak: 1.5M)
CPU: 264ms
CGroup: /system.slice/rpcbind.service
└─837327 /sbin/rpcbind -f -w

Jul 27 06:01:01 geekom-01 systemd[1]: Starting rpcbind.service - RPC bind portmap service...
Jul 27 06:01:01 geekom-01 systemd[1]: Started rpcbind.service - RPC bind portmap service.

GlusterFS, NFS の再起動

RPCサービスの再起動

sudo systemctl status rpcbind

GlusterFSサービスの再起動

sudo systemctl restart glusterd

NFS-Ganeshaサービスの再起動

sudo systemctl restart nfs-ganesha
sudo systemctl enable nfs-ganesha


NFS-Ganesha のトラブルシューティング

少し使っていたら、マウントが勝手に外れてNFSにアクセスできなくなってしまいました。
その後 sudo systemctl restart nfs-ganesha で一時的に復旧したもののまたすぐにアクセスできなくなりました。

ステータス確認

$ sudo systemctl status nfs-ganesha
× nfs-ganesha.service - NFS-Ganesha file server
Loaded: loaded (/usr/lib/systemd/system/nfs-ganesha.service; enabled; preset: enabled)
Active: failed (Result: core-dump) since Sun 2024-07-28 05:30:38 UTC; 12s ago
Duration: 1min 34.476s
Docs: http://github.com/nfs-ganesha/nfs-ganesha/wiki
Process: 1209086 ExecStart=/bin/bash -c ${NUMACTL} ${NUMAOPTS} /usr/bin/ganesha.nfsd -C ${OPTIONS} ${EPOCH} ${GNOD>
Main PID: 1209087 (code=dumped, signal=ABRT)
CPU: 907ms

Jul 28 05:29:03 geekom-01 systemd[1]: Starting nfs-ganesha.service - NFS-Ganesha file server...
Jul 28 05:29:03 geekom-01 (bash)[1209086]: nfs-ganesha.service: Referenced but unset environment variable evaluates to>
Jul 28 05:29:03 geekom-01 systemd[1]: Started nfs-ganesha.service - NFS-Ganesha file server.
Jul 28 05:29:03 geekom-01 ganesha.nfsd[1209087]: libnfsidmap: Unable to determine the NFSv4 domain; Using 'localdomain>
Jul 28 05:30:38 geekom-01 systemd[1]: nfs-ganesha.service: Main process exited, code=dumped, status=6/ABRT
Jul 28 05:30:38 geekom-01 systemd[1]: nfs-ganesha.service: Failed with result 'core-dump'.
lines 1-15/15 (END)


ボリュームの削除

停止

$ sudo gluster volume stop gv0

削除

sudo gluster volume delete gv0


ベクトルデータベース Weaviate (GPU使用) を Jetson Orin Nano NX 16G で動かす
GlusterFSで構築したファイルシステムを2つのNFSサーバーで公開し、Keepalivedを使用してフェイルオーバー機能を実装する方法