Linuxの/procとは(入門者向け)

/procとは

Linuxには、/procというディレクトリがあります。このディレクトリの中のファイルはLinuxカーネルが内部情報を提供するための仮想的なもです。SSD上のファイルのように、どこかにファイルの実体があるわけではありません。

ディレクトリ内容の例

実際に見てみると以下のようになっています。ls-Fオプションをつけてあるので、 末尾に/があるものはディレクトリ、@があるのは、シンボリックリンクです。
$ ls -F /proc/
1/      73669/     crypto          irq/         modules       sys/
3674/   73681/     devices         kallsyms     mounts@       sysrq-trigger
3675/   73687/     diskstats       kcore        mtrr          sysvipc/
38/     91/        dma             keys         net@          thread-self@
4771/   92/        driver/         key-users    pagetypeinfo  timer_list
4777/   acpi/      dynamic_debug/  kmsg         partitions    tty/
4778/   asound/    execdomains     kpagecgroup  pressure/     uptime
61/     buddyinfo  fb              kpagecount   schedstat     version
72/     bus/       filesystems     kpageflags   self@         vmallocinfo
73/     cgroups    fs/             loadavg      slabinfo      vmstat
73632/  cmdline    interrupts      locks        softirqs      zoneinfo
73638/  consoles   iomem           meminfo      stat
73639/  cpuinfo    ioports         misc         swaps
一見して分かるように、数字だけのディレクトリ(例: 1/, 3674/など)と、それ以外のファイルやディレクトリ(例: acpi/, buddyinfoなど)があります。 数字のディレクトリは、その値のプロセス番号をもつプロセスの情報をそのディレクトリ以下にファイルとして持ちます。 それ以外のファイルやディレクトリ(以下のファイル)には、システム全体の情報が格納されています。

プロセス用のディレクトリ

いま、例としてsleepコマンドを実行させ、プロセスを起動します。 プロセスID 73717で起動しました。
$ sleep 3600 &
[1] 73717
このプロセスに関する/procの情報を見てみましょう。
$ ls -F /proc/73717/
arch_status         fd/                net/           setgroups
attr/               fdinfo/            ns/            smaps
autogroup           gid_map            numa_maps      smaps_rollup
auxv                io                 oom_adj        stack
cgroup              ksm_merging_pages  oom_score      stat
clear_refs          ksm_stat           oom_score_adj  statm
cmdline             limits             pagemap        status
comm                loginuid           patch_state    syscall
coredump_filter     map_files/         personality    task/
cpu_resctrl_groups  maps               projid_map     timens_offsets
cpuset              mem                root@          timers
cwd@                mountinfo          sched          timerslack_ns
environ             mounts             schedstat      uid_map
exe@                mountstats         sessionid      wchan
いろんなファイルやディレクトリがありますが、筆者がよく参照するものを2つここではあげます。

exe

そのプロセスの実行ファイルへのリンクです。プロセスの実行ファイルは/usr/bin/sleep であることが分かります。
 $ ls -l /proc/73717/exe
lrwxrwxrwx 1 foo foo 0 Mar 19 11:06 /proc/73717/exe -> /usr/bin/sleep

fd

そのプロセスがオープンしているファイルへのシンボリックリンクが格納されています。 シンボリックリンクのファイル名はデスクリプタ番号です。 この場合、標準入出力のためのファイル3つがオープンしていることが分かります。
$ ls -l /proc/73717/fd
total 0
lrwx------ 1 foo foo 64 Mar 19 11:15 0 -> /dev/pts/5
lrwx------ 1 foo foo 64 Mar 19 11:15 1 -> /dev/pts/5
lrwx------ 1 foo foo 64 Mar 19 11:15 2 -> /dev/pts/5

システム全体の情報

システム全体のファイルについても、3つ紹介します。

partitions

Linuxカーネルが認識しているパーティションが格納されています。以下ではNVMeのストレージのパーティションが表示されいてます。 USBストレージを挿入するとsda, sda1, sda2など、USBストレージに対応する項目が追加されます。Linuxカーネルが 接続したストレージを認識しているかを確認するときに有用です。
$ cat /proc/partitions 
major minor  #blocks  name

 259        0 1953514584 nvme0n1
 259        1     498688 nvme0n1p1
 259        2   19530752 nvme0n1p2
 259        3   19530752 nvme0n1p3
 259        4   19530752 nvme0n1p4
 259        5   19530752 nvme0n1p5
 259        6 1874891776 nvme0n1p6

uptime

Linuxが起動してからの時間が格納されています。
$ uptime
 11:22:23 up  9:19,  2 users,  load average: 0.00, 0.00, 0.00

self

あるプロセスがこのファイルを参照する時、それは、そのプロセス用ディレクトリへのリンクになっています。つまり、読み出すプロセスによって異なるリンク先を示します。

以下の例では、リンク先になっている73729は、/procを読み出しているlsコマンド自身のプロセスIDを持つディレクトリです。

$ ls -l /proc/self
lrwxrwxrwx 1 root root 0 Mar 19 02:02 /proc/self -> 73729

より詳しい情報

この記事の例で示したように/procにはたくさんのファイルがあります。それらの詳しい説明は以下を参照ください。

Linuxカーネルのビルド方法

この記事では、Linuxカーネルをビルドする方法を紹介します。Linuxコミュニティの最新カーネルでのみサポートされる機能を使う場合や、独自のLinux OSを作成する際に有用です。ここに掲載したコマンドは、Debian 11で実行を確認しましたが、他のLinux OSでも(パッケージのインストール方法を除いて)基本的には同じです。

ビルド準備

以下のパッケージをインストールします。
sudo apt install gcc make flex bison bc libncurses-dev libelf-dev libssl-dev

カーネルソースコードの取得

以下のサイトにカーネルのソースコードが掲載されています。

この記事を書いた日の最新安定版は6.2.7でした。以下は、それをビルド用マシンの作業用ディレクトリにダウンロードする例です。
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.2.7.tar.xz

ビルド

ソースコード展開

tar xf linux-6.2.7.tar.xz

設定

ここではデフォルト設定を行います。
cd linux-6.2.7
make defconfig

さらなる設定を行う場合 (TUI)

make menuconfig
上記のように入力すると、次のTUIベースの設定画面が表示されます。これを使って必要なCONFIGを追加/削除できます。

さらなる設定を行う場合 (コマンドライン)

以下のようにscript/configを使用する
scripts/config -e CONFIG_DEBUG_INFO_DWARF5
その後、設定されていないシンボルをデフォルトにする
make olddefconfig

参考

以下にコマンドラインでCONFIGを設定する方法を説明しています。

コンパイル

make -j32

上記の-j32は、32並列でのコンパイルを行うオプション。実際のCPU数に合わせて適宜変更。

次のメッセージが表示されればビルド成功。下記のbzImageは、多くのLinux OSでvmlinuz-6.1.0-5-amd64のような名前になっているものと同じです。

Kernel: arch/x86/boot/bzImage is ready  (#1)

起動テスト

ここではrootfsにDebian 11のドライブイメージを使い、QEMUで起動してみます。なお、QEMUの使用方法に関しては、以下に関連記事がまとめられています。

rootfsドライブイメージのダウンロード

以下のようにrootfsのイメージをダウンロードします。
wget https://cloud.debian.org/images/cloud/bullseye/20230124-1270/debian-11-nocloud-amd64-20230124-1270.qcow2

起動

次のとおりQEMUを実行します。--nographicオプションを付与しているので、仮想マシンにシリアルデバイスが作成されます。 また、カーネルオプションにconsole=ttyS0を付与して、コンソールをシリアルデバイスに設定しています。 これらによりQEMUを実行している端末が、そのままシリアルデバイスへの入出力端末となります。

なお、defconfigで設定した場合、virtio経由のストレージ機能がカーネルに組み込まれます。 initrdなしで直接rootfsをカーネルがマウントできます。

sudo qemu-system-x86_64 \
-cpu host \
--enable-kvm \
-m 1024 \
-nographic \
-drive id=drive0,format=qcow2,file=debian-11-nocloud-amd64-20230124-1270.qcow2,if=virtio \
-kernel arch/x86_64/boot/bzImage \
-append "root=/dev/vda1 console=ttyS0"
以下のようなログインプロンプトが表示されれば成功です。
(省略)
Debian GNU/Linux 11 debian ttyS0

debian login:
このイメージでは、ユーザ名としてrootと入力すると、パスワードなしで以下のようにログインできます。
Linux debian 6.2.7 #1 SMP PREEMPT_DYNAMIC Sun Mar 19 02:39:21 UTC 2023 x86_64
(省略)
root@debian:~#

起動失敗時のQEMU強制終了方法

QEMU起動中にCtrl-a、続いてcを入力するとQEMUのモニタ画面に移行します。ここでqを入力します。
(Ctrl-a, cを入力)
QEMU 7.2.0 monitor - type 'help' for more information
(qemu) q

Debian 11(サーバ)でのネットワーク設定例(ブリッジあり)

設定例

以下は/etc/network/interfacesの内容。ここでは、ブリッジbr0に物理NICenp6s0を含む。
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
allow-hotplug enp6s0
iface enp6s0 inet manual

auto br0
iface br0 inet static
  bridge_ports enp6s0
  address 192.168.10.10
  netmask 255.255.255.0
  gateway 192.168.10.1
  dns-nameservers 192.168.10.1
  bridge_stp off
  bridge_maxwait 0

注記

上記の設定には'bridge-utils'パッケージが必要です。

ブリッジを使う利点

物理NICをブリッジに含めておくと、下図のようにLXCコンテナやQEMUのインスタンスをホストマシンが所属するネットワークに容易に接続できる。macvlanやmacvtapだと、ホストOSと仮想マシンが通信できない課題があるが、この方法ならそれを解決できる。

topコマンドの見方

topを実行すると、(Debian 12の)デフォルトでは以下の画面が表示される。特に重要な図中の赤枠の3箇所について説明する。

(1) CPUの実行時間

ここには、全てのCPUの合計を100%として、実行種別ごとの割合が表示される。
種別 説明
us ユーザモードでのプログラム実行時間。プログラムの通常処理の時間
sy カーネルモードでのプログラム実行時間。プログラムがシステムコールを呼び出すことにより、カーネル内のコードが実行された時間。ファイルの読み書きや、ネットワーク処理などがこれに相当
ni 正のNICE値が設定され、低優先度となっているプロセスのプログラム実行時間
id アイドル時間。何も実行していない時間
wa ストレージなどのデバイスへの入出力処理で、デバイスから応答を待っている時間
hi ハードウェア割り込み処理の実行時間
si ソフトウェア割り込み処理の実行時間
st ハイパーバイザ型仮想マシン上の仮想CPUが、物理CPUの割り当てを待っている時間

(2) メモリ使用量

OS全体のメモリ使用量が表示される。デフォルトの単位は、MiB。
分類 項目 説明
Mem total 全メモリ容量
free 空きメモリ容量
used 使用中のメモリ容量
buff/cache ディレクトリエントリやファイル内容のキャッシュ容量。Linuxは、空きメモリを積極的にこれらのキャッシュに割り当てるため、使用するに従い空きメモリが減少し、これらの値が増加する傾向にある
Swap total 全スワップ容量
free 空きスワップ容量
used 使用中のスワップ容量
avail Mem 利用可能なメモリ容量。大雑把には空きメモリ容量とキャッシュの合計

(3) プロセスごとの状態

ヘッダの各列の意味は次のとおり。デフォルトではプロセスはCPU使用率の降順で表示される。メモリ関連の容量のデフォルト単位はKiB。  
項目 説明
PID プロセスID
USER そのプロセスの実行ユーザー
PR プロセスの実行優先度。20が標準。数値が小さいほど優先度が高い
NI NICE値。この値が正なら、その値に応じて低優先度で実行される。負ならその値に応じて高優先度で実行される
VIRT 仮想メモリ使用量。プロセスが確保したメモリ量。この値の一部にしか物理メモリが割り当てられていない。この値が大きくてもそれほどメモリを使っていない場合もある。
RES 物理メモリ使用量。プロセスに割り当てられた物理メモリ量。そのプロセスの実際のメモリ使用量。
SHR 共有メモリ使用量。RESのうち、他のプロセスと共有されているメモリ量。
S プロセスの状態: R (実行中)、S (スリープ)、D(割り込み不可のスリープ)、Z(ゾンビ状態)
%CPU CPU使用率。ひとつのCPUをフルに使った場合100%となる。複数のCPUを使っている場合、100%を超えることがある
%MEM メモリ使用率
TIME+ プロセスのCPU使用時間。起動してからの時間ではなく、CPUが割り当てられた(つまりそのプロセスのプログラムが実行された)時間の合計。1/100秒単位。
例: 1:23.45の場合、1分23秒450ミリ秒
COMMAND 実行コマンド

参考

topコマンドの記事一覧

noVNCでWebブラウザをVNCクライアントとして利用

以下の記事は、Ubuntu 20.04上で下図の構成での実行記録。

準備と実行

以下の手順をnoVNC Server上で行う

 noVNCのダウンロード

git clone https://github.com/novnc/noVNC.git

websockifyがインストールされていない場合、インストール

sudo apt install python3-websockify

実行

--web=オプションには、ダウンロードしたnoVNCのレポジトリを指定。次いで公開するポート番号。最後にVNCサーバのIPアドレスとポート番号。
websockify --web=noVNC 8081 192.168.1.20:5901

Webブラウからのアクセス

以下のURLへWebブラウザでアクセス

  • http://192.168.1.10:8081/vnc.html
以下の画面が表示されます。

Debianでfirmware-nvidia-gsp 525.85.12がないと表示された場合の対応

firmware-nvidia-gspのこのバージョンからは、non-free-firmwareレポジトリに含まれる。 そのため、例えば、/etc/apt/sources.listに以下のようにnon-free-firmwareを追加する。
deb http://deb.debian.org/debian/ bookworm contrib non-free non-free-firmware

小規模な利用ならLXDよりLXCが使い勝手がよい

LXDは、大雑把に言えば、LXCに管理機能を強化し大規模な運用にも利用しやすくしたもの。 個人で簡易的な仮想マシンとして使う場合、LXDの機能がやや冗長に感じることがある。 そのため私はLXDでなくLXCを主に使っている。以下にその理由を述べる。

ストレージ(コンテナ内のファイルの格納場所)

LXC

ホストOS上の特定のディレクトリ/var/lib/lxc/[コンテナ名]/rootfsの下に、そのコンテナのファイルシステムがそのまま格納されている。 ホスト側から見ると、デフォルトでファイル共有されているようなもの。

LXD

デフォルトでは、ホストOS上にストレージプール用のループバックマウント用のファイルを作成する。作成時点でそのサイズを決める(例えば100GiB)。

このストレージプール用のファイルは、シンプロビジョニングされるので、最初のサイズは0。使った分だけ増えていく。ただし、コンテナを削除したり、コンテナ内のファイルを削除しても、ストレージプールの容量は減少しない。これがパーソナルユースでは、ストレスになる。ストレージプール用のファイルを拡張できるものの、最初に最大サイズをいくらにするかを決めるのは、なかなか悩みどころである。

ストレージプールのループバックファイル上btrfsなどのパーティションを作れば、スナップショットやコンテナのコピーを高速に取得できるなどのメリットもある。しかし、私の使い方では、動作中にスナップショットをとるような用途もほとんどない。コンテナそのものは、それほど肥大化しないので、コピーすることがあっても、少し待てば終わる。そのため、これらのメリットをほぼ享受できない。

また、LXCでも同様のことは可能である。自前でループバックマウント用ファイルを作ってbtrfsでフォーマットし、rootfsをその上に設定すればよい。

設定

LXC

/var/lib/lxc/[コンテナ名]/configに設定が集約されている。構成を変えたいときは、このテキストファイルを編集すればよい。構成の保存もこのファイルをバックアップすればよい。

LXD

lxc configなどのコマンドで設定する。設定をまとめて保存したり、設定するのがやや面倒。

インストール方法

LXC

DebianでもUbuntuでもaptでインストールできる。

LXD

snapで提供される。snap自体それほどメジャーでもないし、パッケージ管理システムが増えるのは、システムが複雑になりあまり嬉しくない。