というリポジトリがあります。
システム管理者としてどれくらいの実力があるかの質問と答えを集めたものです。
これで自分の実力を知ることができます。
このリポジトリをほぼChatGPTに投げて日本語にしてみました。
とレベルが別れているのですが、一般レベルはなんとかなりつつもシニアレベルが大変でした。
ここでは筆者が答えられなかった質問とその答えを載せておきます。
もっと挑戦したい方はぜひ以下へ↓
サーバーをデバッグしようとしている他の管理者が誤って入力してしまった:chmod -x /bin/chmod。パーミッションをデフォルトに戻すには?
答え
# 1:
cp /bin/ls chmod.01
cp /bin/chmod chmod.01
./chmod.01 700 file
# 2:
/bin/busybox chmod 0700 /bin/chmod
# 3:
setfacl --set u::rwx,g::---,o::--- /bin/chmod
# 4:
/usr/lib/ld*.so /bin/chmod 0700 /bin/chmod
useradd または adduser コマンドを使わずに新しいユーザーを追加する方法は?
useraddやadduserコマンドが何をしているかというのを答える質問
手動でやると面倒
答え
-
vipw
コマンドを使って、/etc/passwd
にユーザーの詳細を追加します:
# username:password:UID:GID:Comments:Home_Directory:Login Shell
user:x:501:501:test user:/home/user:/bin/bash
構文には注意してください。直接エディタで編集しないでください。
vipw
はファイルをロックするため、他のコマンドが同時にファイルを更新しようとすることはありません。
- 同じ名前のグループを
/etc/group
にvigr
で作成する必要があります(vipw
と似たツールです)。
user:x:501:
- ユーザーにパスワードを与えます:
passwd user
-
mkdir
コマンドを使ってユーザーのホームディレクトリを作成します:
mkdir -m 0700 /home/user
-
/etc/skel
から新しいホームディレクトリにファイルをコピーします:
rsync -av --delete /etc/skel/ /home/user
-
chown
とchmod
を使って所有権と権限を修正します:
chown -R user:user /home/user
chmod -R go-rwx /home/user
アプリケーションにパフォーマンスの問題が発生しています。最適化すべきコードを見つける必要があります。Linux環境でアプリをプロファイルする方法は?
あまりシステム管理っぽくない質問
ツールにお任せしているところをコマンドでできるかな?
答え
理想的には、プロセスにアタッチして、メモリ使用量、スレッド数、CPU使用率の定期的なスナップショットを記録するアプリが必要です。
-
top
をバッチモードで使用できます。バッチモードでは、終了するまで、または指定した回数の反復が完了するまで実行されます。
top -b -p `pidof a.out`
または
top -b -p `pidof a.out` -n 100
- psも使用できます (例えばシェルスクリプトで):
ps --format pid,pcpu,cputime,etime,size,vsz,cmd -p `pidof a.out`
Linuxマシンでアプリケーションのパフォーマンスを記録する手段が必要です。
- パフォーマンスデータを記録する:
perf record -p `pidof a.out`
または10秒間記録するには:
perf record -p `pidof a.out` sleep 10
または、コールグラフを記録するには:
perf record -g -p `pidof a.out`
- 記録されたデータを解析する
perf report --stdio
perf report --stdio --sort=dso -g none
perf report --stdio -g none
perf report --stdio -g
これはテストプログラムのプロファイリングの例です
- テストプログラム(C++)を実行します:
./my_test 100000000
- 実行中のプロセスのパフォーマンスデータを記録します:
perf record -g -p `pidof my_test` -o ./my_test.perf.data sleep 30
- 次に、モジュールごとの負荷を分析します:
perf report --stdio -g none --sort comm,dso -i ./my_test.perf.data
# Overhead Command Shared Object
# ........ ....... ............................
#
70.06% my_test my_test
28.33% my_test libtcmalloc_minimal.so.0.1.0
1.61% my_test [kernel.kallsyms]
- 次に、機能ごとの負荷を分析します:
perf report --stdio -g none -i ./my_test.perf.data | c++filt
# Overhead Command Shared Object Symbol
# ........ ....... ............................ ...........................
#
29.30% my_test my_test [.] f2(long)
29.14% my_test my_test [.] f1(long)
15.17% my_test libtcmalloc_minimal.so.0.1.0 [.] operator new(unsigned long)
13.16% my_test libtcmalloc_minimal.so.0.1.0 [.] operator delete(void*)
9.44% my_test my_test [.] process_request(long)
1.01% my_test my_test [.] operator delete(void*)@plt
0.97% my_test my_test [.] operator new(unsigned long)@plt
0.20% my_test my_test [.] main
0.19% my_test [kernel.kallsyms] [k] apic_timer_interrupt
0.16% my_test [kernel.kallsyms] [k] _spin_lock
0.13% my_test [kernel.kallsyms] [k] native_write_msr_safe
...
- 次に、コールチェインを分析します:
perf report --stdio -g graph -i ./my_test.perf.data | c++filt
# Overhead Command Shared Object Symbol
# ........ ....... ............................ ...........................
#
29.30% my_test my_test [.] f2(long)
|
--- f2(long)
|
--29.01%-- process_request(long)
main
__libc_start_main
29.14% my_test my_test [.] f1(long)
|
--- f1(long)
|
|--15.05%-- process_request(long)
| main
| __libc_start_main
|
--13.79%-- f2(long)
process_request(long)
main
__libc_start_main
...
この時点で、プログラムがどこに時間を費やしているかがわかります。
また、アプリケーションのプロファイルを作成する簡単な方法は、pstack
ユーティリティまたはlsstack
を使用することです。
もう一つのツールはValgrindです。これをお勧めします。まずプログラムを実行します:
valgrind --tool=callgrind --dump-instr=yes -v --instr-atstart=no ./binary > tmp
プログラムが動作しているときに、プロファイリングを開始するには別のウィンドウで以下を実行します:
callgrind_control -i on
これでプロファイリングがオンになります。オフにして全タスクを停止するには次のコマンドを使用します:
callgrind_control -k
これで、現在のディレクトリにcallgrind.out.*
という名前のファイルが生成されます。プロファイリングの結果を確認するには次のコマンドを使用します:
kcachegrind callgrind.out.*
次のウィンドウでSelf列のヘッダーをクリックすることをお勧めします。そうしないと、main()
が最も時間を消費しているタスクとして表示されてしまいます。
プロダクションサーバーでルートによって実行されたすべてのコマンドをログに記録するには?
auditdを知っているか使えるかの質問
筆者は使ったことないです
答え
auditd
がこの作業には適切なツールです:
-
/etc/audit/audit.rules
に以下の2行を追加します:
-a exit,always -F arch=b64 -F euid=0 -S execve
-a exit,always -F arch=b32 -F euid=0 -S execve
これにより、ルート(euid=0)によって実行されたすべてのコマンドが追跡されます。なぜ2つのルールが必要なのか?execve
システムコールは、32ビットおよび64ビットの両方のコードで追跡する必要があります。
-
ログに
auid=4294967295
メッセージを表示させないようにするには、カーネルのコマンドラインにaudit=1
を追加します(/etc/default/grub
を編集)。 -
以下の
session required pam_loginuid.so
を、ログインに関連するすべてのPAM設定ファイル(/etc/pam.d/{login,kdm,sshd}
)に追加しますが、su
または sudo
に関連するファイルには追加しません。これにより、sudo
または su
を呼び出すときに、auditd
が呼び出し元ユーザーのUIDを正しく取得できるようになります。
システムを再起動してください。
ログインしてコマンドを実行してみましょう:
$ id -u
1000
$ sudo ls /
bin boot data dev etc home initrd.img initrd.img.old lib lib32 lib64 lost+found media mnt opt proc root run sbin scratch seLinux srv sys tmp usr var vmlinuz vmlinuz.old
$ sudo su -
# ls /etc
[...]
/var/log/audit/auditd.log
を読み取って、どのコマンドがログに記録されたかを確認してください。
2>&-、2>/dev/null、|&、&>/dev/null、および >/dev/null 2>&1 の違いを説明してください。
エラー出力やファイルディスクリプタについて
とっさに聞かれてもわからないかも
答え
-
番号 1 = 標準出力(
STDOUT
) -
番号 2 = 標準エラー(
STDERR
) - 明示的に番号が指定されていない場合、シェル(bash)はデフォルトで番号 1を使用します。
これらの機能について説明します。
2>&-
一般的な形式は M>&-
で、ここで "M" はファイルディスクリプタ番号です。これは、指定されたファイルディスクリプタ "M" の出力を閉じます。
2>/dev/null
一般的な形式は M>/dev/null
で、ここで "M" はファイルディスクリプタ番号です。これは、ファイルディスクリプタ "M" の出力を /dev/null
にリダイレクトします。
2>&1
一般的な形式は M>&N
で、ここで "M" と "N" はファイルディスクリプタ番号です。これは、ファイルディスクリプタ "M" と "N" の出力を単一のストリームに結合します。
|&
これは 2>&1 |
の省略形です。Bash 4 で追加されました。
&>/dev/null
これは >/dev/null 2>&1
の省略形です。ファイルディスクリプタ 2(STDERR
)とファイルディスクリプタ 1(STDOUT
)の出力を /dev/null
にリダイレクトします。
>/dev/null
これは 1>/dev/null
の省略形です。ファイルディスクリプタ 1(STDOUT
)の出力を /dev/null
にリダイレクトします。
有用なリソース:
nohup、disown、& の違い。すべてを一緒に使用した場合にどうなりますか?
似たようなものの細かい違いについて
nohup &はよく使われますがどのような違いがあるのでしょう
答え
-
&
はジョブをバックグラウンドで実行し、入力の読み込みをブロックし、シェルがジョブの完了を待たないようにします -
disown
はプロセスをシェルのジョブ制御から削除しますが、ターミナルへの接続は維持されます。これにより、シェルはプロセスにSIGHUPを送信しなくなります。明らかに、これはバックグラウンドジョブにのみ適用されるため、フォアグラウンドジョブが実行中にこの操作を行うことはできません -
nohup
はプロセスをターミナルから切り離し、その出力をnohup.out
にリダイレクトし、SIGHUP から保護します。効果の1つ(名前に関連するもの)は、プロセスが送信されたSIGHUPを受け取らなくなることです。ジョブ制御とは完全に独立しており、原理的にはフォアグラウンドジョブにも使用できます(ただし、あまり便利ではありません)
これらをすべて一緒に使用すると、プロセスはバックグラウンドで実行され、シェルのジョブ制御から削除され、ターミナルから効果的に切り離されます。
inodeに格納されているフィールドはどれですか?
inodeの話
どのような情報が入っているかはよく知らない人も多いハズ
答え
POSIXシステム内では、ファイルには次の属性があり、stat
システムコールによって取得できます:
-
デバイスID(これはファイルを含むデバイスを識別します。つまり、シリアル番号の一意性の範囲です。)
-
ファイルモード(ファイルの種類と、ファイルの所有者、そのグループ、および他のユーザーがファイルにどのようにアクセスできるかを決定します)
-
リンクカウント(inodeを指すハードリンクの数を示します)
-
ファイルのユーザーID
-
ファイルのグループID
-
ファイルがデバイスファイルの場合、そのデバイスID
-
ファイルのサイズ(バイト単位)
-
タイムスタンプ(inode自体が最後に変更された時刻(ctime、inode変更時間)、ファイル内容が最後に変更された時刻(mtime、修正時間)、最後にアクセスされた時刻(atime、アクセス時間))
-
推奨されるI/Oブロックサイズ
-
このファイルに割り当てられたブロックの数
カーネルの種類とその違いを説明してください。
カーネルに種類あったんだ…
答え
モノリシックカーネル
従来のこのタイプのカーネルアーキテクチャでは、プロセス管理やメモリ管理、割り込み処理などの基本的なシステムサービスがカーネル空間内の単一モジュールにまとめられていました。このアーキテクチャには、以下のような深刻な欠点がありました:
- カーネルのサイズが非常に大きい
- メンテナンス性が低く、新しい機能を追加したりバグ修正を行うたびに、カーネル全体を再コンパイルする必要があり、数時間かかることもある
現代のモノリシックアーキテクチャでは、カーネルは動的にロードおよびアンロードできる複数のモジュールで構成されています。このモジュラーアプローチにより、OSの機能を簡単に拡張できるようになり、特定のモジュールに変更やバグ修正があった場合、関連するモジュールだけをロードおよびアンロードするだけで済むため、カーネルのメンテナンスが非常に簡単になりました。
Linuxはモノリシックモジュラーアプローチを採用しています。
マイクロカーネル
このアーキテクチャは、モノリシックアプローチで制御できなかったカーネルコードの増大に対応するために開発されました。このアーキテクチャでは、デバイスドライバの管理、プロトコルスタック、ファイルシステムなどの基本的なサービスがユーザー空間で実行されます。
このアーキテクチャでは、OSの基本サービスがユーザー空間の一部となり、システム内の他のプログラムがこれらのサービスを利用する際に、プロセス間通信(IPC)を介してサーバーとして実行されます。
例: デバイスドライバ、ネットワークプロトコルスタック、ファイルシステム、グラフィックスなどにサーバーがあります。マイクロカーネルのサーバーは、他のプログラムと同様にデーモンプログラムですが、一部のサーバーには物理メモリの一部にアクセスできる特権が与えられています。
ハイブリッドカーネル(モジュラーカーネル)
これは上記の2つの組み合わせであり、OSサービスがカーネル空間に存在し、メッセージパッシングやパフォーマンスオーバーヘッドがなく、ユーザー空間でサービスを実行することによる信頼性の向上もありません。
これは、MicrosoftのNTカーネル(最新のWindowsバージョンまで)で使用されています。