tanke25616429のアウトプット

IT技術の基本を勉強したことをアウトプットします。Linux、Kubernetes、クラウド中心です。百番煎じくらいだけど誰かの役に立てばそれはそれでうれしい。

Linuxユーザ管理時に考慮する設定(その2 パスワード)

chageコマンド

chageはパスワードの有効期限等を管理するコマンドである。アカウントが無効化する期限を設定したり、パスワード変更の警告を出す日を設定したり、といったこともできる。管理はrootアカウントで行うが、自身の設定を見るだけであれば一般ユーザのアカウントでも可能である。代表的なオプションを記載する。

-M

パスワードの有効日数(パスワードが有効でいられる最長日数)を設定できる。 有効日数と最終更新日 を足した値が現在の日付より小さい場合(つまり、最後にパスワードを更新してからパスワードが有効でいられる日数が過ぎている状態)、 ユーザはアカウントを使用する前にパスワードを変更しなければならない。

設定例は以下である。まず、事前準備として最近作ったユーザにパスワードを設定する。パスワードはtest1234とした。

[root@nuc-centos8 ~]# passwd testuser3
ユーザー testuser3 のパスワードを変更。
新しいパスワード:
よくないパスワード: このパスワードは辞書チェックに失敗しました。 - 単純/系統的すぎます
新しいパスワードを再入力してください:
passwd: すべての認証トークンが正しく更新できました。

有効日数を10日に変更する。

[root@nuc-centos8 ~]# chage -l testuser3
最終パスワード変更日                            : 3月 23, 2021
パスワード期限:                                 : なし
パスワード無効化中                                      : なし
アカウント期限切れ                                              : なし
パスワードが変更できるまでの最短日数            : 0
パスワードを変更しなくてよい最長日数            : 99999
パスワード期限が切れる前に警告される日数                : 1
[root@nuc-centos8 ~]# chage testuser3 -M 10
[root@nuc-centos8 ~]# chage -l testuser3
最終パスワード変更日                            : 3月 23, 2021
パスワード期限:                                 :  4月 02, 2021
パスワード無効化中                                      : なし
アカウント期限切れ                                              : なし
パスワードが変更できるまでの最短日数            : 0
パスワードを変更しなくてよい最長日数            : 10
パスワード期限が切れる前に警告される日数                : 1

-d

パスワードの最終更新日を設定できる。これを意図的に設定する1つのユースケースとしては、特定のアカウントのパスワードを有効期間切れにしてパスワード変更を促すというものである。

なお、変更後のパスワードとしてtest9876を入力したが、エラーチェックでパスワード変更を拒絶されている。passwdコマンドで初期設定するときとは脆弱なパスワードに対する扱いが異なっている。

[root@nuc-centos8 ~]# ssh testuser3@localhost
testuser3@localhost's password:
You are required to change your password immediately (password expired)
Activate the web console with: systemctl enable --now cockpit.socket

Last login: Tue Mar 23 00:52:00 2021
WARNING: Your password has expired.
You must change your password now and login again!
ユーザー testuser3 のパスワードを変更。
Current password:
新しいパスワード:
よくないパスワード: このパスワードは辞書チェックに失敗しました。 - 単純/系統的すぎます
passwd: 認証トークン操作エラー
Connection to localhost closed.

-m

パスワード変更の間隔の最短日数を設定できる。 このフィールドをゼロとした時は、ユーザはいつでもパスワードを変更できる。

いったん事前準備でパスワードの最終更新日を有効期限内になるように設定する。

[root@nuc-centos8 ~]# chage testuser3 -d 2021-03-22
[root@nuc-centos8 ~]# chage testuser3 -l
最終パスワード変更日                            : 3月 22, 2021
パスワード期限:                                 :  4月 01, 2021
パスワード無効化中                                      : なし
アカウント期限切れ                                              : なし
パスワードが変更できるまでの最短日数            : 0
パスワードを変更しなくてよい最長日数            : 10
パスワード期限が切れる前に警告される日数                : 1

最短パスワード変更間隔を1日に設定する。testuser3にログインしてパスワード変更をする。一度目は問題なく実施でき、すぐ二度目を実施しようとすると失敗する。これはパスワード変更に最低1日待たなくてはならないからである。

[root@nuc-centos8 ~]# chage testuser3 -m 1
[root@nuc-centos8 ~]# ssh testuser3@localhost
testuser3@localhost's password:
Activate the web console with: systemctl enable --now cockpit.socket

Last login: Wed Mar 24 00:05:19 2021 from ::1
Welcome
[testuser3@nuc-centos8 ~]$ passwd
ユーザー testuser3 のパスワードを変更。
Current password:
新しいパスワード:
新しいパスワードを再入力してください:
passwd: すべての認証トークンが正しく更新できました。
[testuser3@nuc-centos8 ~]$ passwd
ユーザー testuser3 のパスワードを変更。
Current password:
パスワードを変更するには長く待つ必要があります

/etc/login.defs

デフォルトのパスワード有効日数は/etc/login.defsに記載されている。パスワードの長さなども設定できることがわかる。

[root@nuc-centos8 ~]# cat /etc/login.defs
(略)
PASS_MAX_DAYS   99999
PASS_MIN_DAYS   0
PASS_MIN_LEN    8
PASS_WARN_AGE   1
(略)

例えばパスワードの最小の長さと、パスワードが有効となる日数を変更してみる。

[root@nuc-centos8 ~]# cat /etc/login.defs
(略)
#PASS_MAX_DAYS  99999
PASS_MAX_DAYS   99
PASS_MIN_DAYS   0
#PASS_MIN_LEN   8
PASS_MIN_LEN    15
PASS_WARN_AGE   1
(略)

新たにユーザを作成し、デフォルト設定を確認する。初期パスワードはtest1234とする。

[root@nuc-centos8 ~]# useradd testuser4
[root@nuc-centos8 ~]# chage testuser4 -l
最終パスワード変更日                            : 3月 23, 2021
パスワード期限:                                 :  6月 30, 2021
パスワード無効化中                                      : なし
アカウント期限切れ                                              : なし
パスワードが変更できるまでの最短日数            : 0
パスワードを変更しなくてよい最長日数            : 99
パスワード期限が切れる前に警告される日数                : 1
[root@nuc-centos8 ~]# passwd testuser4
ユーザー testuser4 のパスワードを変更。
新しいパスワード:
よくないパスワード: このパスワードは辞書チェックに失敗しました。 - 単純/系統的すぎます
新しいパスワードを再入力してください:
passwd: すべての認証トークンが正しく更新できました。

パスワードを変更してみる。一度目はqazxswedc(9文字)で失敗し、二度目はqazxswedcvfrtgb(15文字)で成功している。

[testuser4@nuc-centos8 ~]$ passwd
ユーザー testuser4 のパスワードを変更。
Current password:
新しいパスワード:
よくないパスワード: このパスワードは辞書チェックに失敗しました。 - 辞書の単語に 基づいています
passwd: 認証トークン操作エラー
[testuser4@nuc-centos8 ~]$ passwd
ユーザー testuser4 のパスワードを変更。
Current password:
新しいパスワード:
新しいパスワードを再入力してください:
passwd: すべての認証トークンが正しく更新できました。

参考にしたもの

Linuxユーザ管理時に考慮する設定(その1 /etc/skel)

/etc/skel

bash関連の設定ファイル(.bashrcと.bash_profile) - tanke25616429のアウトプットで書いたとおり~/.bashrcや~/.bash_profile等は個人ごとに設定できるが、一方で共通の設定を入れておきたいケースがある。また、作成したユーザのホームディレクトリにデフォルトでREADMEを置いておきたいといったケースがあり得る。そういった場合は/etc/skelを利用する。/etc/skel配下に用意したファイルは新規ユーザ作成時にユーザのホームディレクトリに作成される。つまり、/etc/skelはホームディレクトリのデフォルト状態、またはテンプレートのようなものと言える。

/etc/skel配下にREADMEを配置し、.bashrcの内容もカスタマイズする。

[root@nuc-centos8 ~]# echo "Read this!" > /etc/skel/README
[root@nuc-centos8 ~]# ls -la /etc/skel/
合計 28
drwxr-xr-x.   2 root root   76  3月 23 00:47 .
drwxr-xr-x. 115 root root 8192  3月 22 00:20 ..
-rw-r--r--.   1 root root   18 11月  9  2019 .bash_logout
-rw-r--r--.   1 root root  141 11月  9  2019 .bash_profile
-rw-r--r--.   1 root root  312 11月  9  2019 .bashrc
-rw-r--r--.   1 root root   11  3月 23 00:48 README
[root@nuc-centos8 ~]# vi /etc/skel/.bashrc
[root@nuc-centos8 ~]# cat /etc/skel/.bashrc
# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

# User specific environment
PATH="$HOME/.local/bin:$HOME/bin:$PATH"
export PATH

# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=

# User specific aliases and functions
echo Welcome
alias sl='ls -la'

新たにtestuser3というユーザを作成する。/etc/skelで追加した設定が反映されていることがわかる。

[root@nuc-centos8 ~]# useradd testuser3
[root@nuc-centos8 ~]# su - testuser3
Welcome
[testuser3@nuc-centos8 ~]$ ls -la
合計 16
drwx------.  2 testuser3 testuser3  76  3月 23 00:51 .
drwxr-xr-x. 10 root      root      122  3月 23 00:51 ..
-rw-r--r--.  1 testuser3 testuser3  18 11月  9  2019 .bash_logout
-rw-r--r--.  1 testuser3 testuser3 141 11月  9  2019 .bash_profile
-rw-r--r--.  1 testuser3 testuser3 343  3月 23 00:50 .bashrc
-rw-r--r--.  1 testuser3 testuser3  11  3月 23 00:48 README
[testuser3@nuc-centos8 ~]$ cat README
Read this!
[testuser3@nuc-centos8 ~]$ sl /
合計 24
dr-xr-xr-x.  20 root    root        271  2月  4 00:45 .
dr-xr-xr-x.  20 root    root        271  2月  4 00:45 ..
drwxrwsr-T.   2 laura   accounting   70  1月 13 01:07 accounting
lrwxrwxrwx.   1 root    root          7  5月 11  2019 bin -> usr/bin
dr-xr-xr-x.   7 root    root       4096 12月  6 21:58 boot
drwxr-xr-x.  21 root    root       3520  3月 21 23:28 dev
drwxr-xr-x. 115 root    root       8192  3月 23 00:51 etc
drwxr-xr-x.   3 root    root         24  2月  4 00:45 find
(略)

参考にしたもの

.bashrcや.bash_profileなどの変更設定をすぐに反映させたい - ITmedia エンタープライズ

bash関連の設定ファイル(.bashrcと.bash_profile)

bash関連の設定ファイルについて簡単に触れる。ログオン時や、新たなシェルを起動した際に読み込まれるbash関連の設定ファイルがいくつか存在する。代表的なものは~/.bashrcと~/.bash_profileである。~/は各ユーザのホームディレクトリなので、これらの設定ファイルは個人ごとに設定できる。設定ファイル、と言っているが実態はシェルスクリプトとなっており編集したい場合はbashの記法で行う。

~/.bashrcはシェルの起動時、~/.bash_profileはログオン時に読み込まれる(スクリプトなので、=実行される)。~/.bash_profileはデフォルトは以下のようになっているので、内部で~/.bashrcを呼び出していることがわかる。したがって、個別の設定を追加したいときは~/.bashrcに追加しておけばシェルの起動時とログオン時のいずれの場合も実行される。なお、. ~/.bashrcの先頭のピリオドはカレントシェルで実行することを示す。

[testuser2@nuc-centos8 ~]$ cat .bash_profile
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs

設定を追加し、動作を確認してみる。~/.bashrcに追加すると、bashを新たに立ち上げたときに追加したコマンドが動作していることが確認できる。

[testuser2@nuc-centos8 ~]$ vi .bashrc
[testuser2@nuc-centos8 ~]$ cat .bashrc
# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

# User specific environment
PATH="$HOME/.local/bin:$HOME/bin:$PATH"
export PATH

# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=

# User specific aliases and functions

echo add to bashrc
[testuser2@nuc-centos8 ~]$ bash
add to bashrc

一方で~/.bash_profileに設定を追加した場合は新たにbashを立ち上げても、追加したコマンドが実行されていないが改めてログインすると実行されることがわかる。

[testuser2@nuc-centos8 ~]$ vi .bash_profile
[testuser2@nuc-centos8 ~]$ cat .bash_profile
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs

echo add to bash_profile
[testuser2@nuc-centos8 ~]$ bash
add to bashrc
[testuser@nuc-centos8 ~]$ exit
ログアウト
[root@nuc-centos8 ~]# su - testuser2
add to bashrc
add to bash_profile

参考1:ピリオドをつけてシェルを実行する意味

~/.bash_profileの中に. ~/.bashrcと先頭にピリオドをつけて実行する構文があった。ピリオドの有無での動作の違いを参考までに確認する。

事前準備で変数fooを設定するシェルスクリプトを作成する。

[testuser2@nuc-centos8 ~]$ cat > foo.sh
#!/bin/bash
foo=123
echo $foo
[testuser2@nuc-centos8 ~]$ chmod +x foo.sh

ピリオドなしで実行する。シェルスクリプト内で設定したはずの変数fooが実行元のシェルには引き継がれていない。

[testuser2@nuc-centos8 ~]$ ./foo.sh
123
[testuser2@nuc-centos8 ~]$ echo $foo

ピリオドをつけて実行する。シェルスクリプト内で設定した変数fooが実行元のシェルでも設定されている。ピリオドをつけることによってfoo=123が、実行元のシェル=カレントシェルの上で実行されていることを示している。

[testuser2@nuc-centos8 ~]$ . ./foo.sh
123
[testuser2@nuc-centos8 ~]$ echo $foo
123

参考2:追加した設定をすぐに反映するには

追加した設定をすぐに反映させたい場合は、sourceコマンドを用いる。

[testuser2@nuc-centos8 ~]$ vi .bashrc
[testuser2@nuc-centos8 ~]$ cat .bashrc
# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

# User specific environment
PATH="$HOME/.local/bin:$HOME/bin:$PATH"
export PATH

# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=

# User specific aliases and functions
echo add to bashrc
alias youbi='date +%a' #新たに追加
[testuser2@nuc-centos8 ~]$ youbi
-bash: youbi: コマンドが見つかりません
[testuser2@nuc-centos8 ~]$ source .bashrc
add to bashrc
[testuser2@nuc-centos8 ~]$ youbi
火

参考にしたもの

3. 環境のカスタマイズ

www.koikikukan.com

.bashrcや.bash_profileなどの変更設定をすぐに反映させたい - ITmedia エンタープライズ

Linuxの時刻関連

NTP

NTP(Network Time Protocol)は、コンピュータに内蔵されているシステムクロックをネットワークを介して正しく同期させるためのプロトコルである。NTPは階層的なクライアントサーバモデルとなっており、NTPクライアントはNTPサーバから時刻を同期する。NTPサーバにも上位のNTPサーバが存在しており、階層的に時刻同期を行う。

NTPの階層構造はstratumと呼ばれ、最上位のNTPサーバが原子時計GPSの正確な時刻源から正しい時刻情報を得て、下位のNTPサーバはそれを参照して時刻同期を行っていく。最上位のNTPサーバはstratum 1であり、階層を降りるごとにstratumの値が増えていく。

NTPの通信は123番ポートが利用されるが、後述するChronyではデフォルトの123から変更することも可能。

Chrony

NTPクライアントとNTPサーバーの実装のひとつである。NTPのリファレンス実装*1のntpdより効率良く正確な時刻同期を提供できる。chronyの設定ファイルは/etc/chrony.confに記載されている。

# cat /etc/chrony.conf
# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
pool 2.centos.pool.ntp.org iburst
(略)

poolというのは、仮想的なNTPサーバでNTPサーバのクラスタから構成されている。NTPクライアントから見ると個々の実NTPサーバを意識する必要がない。CentOSでデフォルトで設定されている2.centos.pool.ntp.orgはpool.ntp.orgという何百万ものクライアントへ 使いやすく安定した NTP サービスを提供するプロジェクトによって提供されている。

chronyc trackingコマンドで同期先のNTPサーバ等の時刻同期状況を調べることができる。

# chronyc tracking
Reference ID    : D4120312 (ntp1.m-online.net)
Stratum         : 3
Ref time (UTC)  : Sun Mar 21 13:59:57 2021
System time     : 0.000853356 seconds fast of NTP time
Last offset     : +0.000408658 seconds
RMS offset      : 0.000285201 seconds
Frequency       : 11.395 ppm slow
Residual freq   : +0.001 ppm
Skew            : 0.040 ppm
Root delay      : 0.257479399 seconds
Root dispersion : 0.004164010 seconds
Update interval : 1041.4 seconds
Leap status     : Normal

chronyc sourcesコマンドで同期先候補のNTPサーバ一覧をリストできる。

# chronyc sources
210 Number of sources = 4
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^+ nsa.lds.net.ua                3  10   357   353   -132us[+6293ns] +/-  186ms
^+ 198.51-174-198.customer.>     2  10   377  1070  -2307us[-2166us] +/-  133ms
^+ ns2.vedur.is                  3  10   377    87    +17ms[  +17ms] +/-  279ms
^* ntp1.m-online.net             2  10   377   132    +12ms[  +13ms] +/-  155ms

タイムゾーンの設定

タイムゾーンに関する設定にtimedatectlを使う。オプションをつけないと現在の設定を確認することができる。

# timedatectl
               Local time: Sun 2021-03-21 23:21:12 JST
           Universal time: Sun 2021-03-21 14:21:12 UTC
                 RTC time: Sun 2021-03-21 14:21:12
                Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

設定可能なタイムゾーンの一覧はtimedatectl list-timezonesコマンドで確認できる。

# timedatectl list-timezones
Africa/Abidjan
Africa/Accra
Africa/Addis_Ababa
Africa/Algiers
Africa/Asmara
Africa/Bamako
Africa/Bangui
Africa/Banjul
Africa/Bissau
Africa/Blantyre
Africa/Brazzaville
(略)

タイムゾーンの変更はtimedatectl set-timezoneコマンドで可能。試しにパリ時間に変更してみる。dateコマンドの出力も変わっていることがわかる。

# timedatectl
               Local time: Sun 2021-03-21 23:25:15 JST
           Universal time: Sun 2021-03-21 14:25:15 UTC
                 RTC time: Sun 2021-03-21 14:25:15
                Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no
# date
Sun Mar 21 23:25:18 JST 2021
# timedatectl set-timezone Europe/Paris
# timedatectl
               Local time: Sun 2021-03-21 15:25:58 CET
           Universal time: Sun 2021-03-21 14:25:58 UTC
                 RTC time: Sun 2021-03-21 14:25:58
                Time zone: Europe/Paris (CET, +0100)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no
# date
Sun Mar 21 15:26:15 CET 2021

ちなみに、この方法での変更は再起動しても永続している。

# reboot
(再起動後)
# timedatectl
               Local time: 日 2021-03-21 15:29:39 CET
           Universal time: 日 2021-03-21 14:29:39 UTC
                 RTC time: 日 2021-03-21 14:29:39
                Time zone: Europe/Paris (CET, +0100)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

内部的な時計について

カーネル内の多くのサブシステム*2が、時間に関する処理をする際にWall clockと呼ばれる時刻を参照する。Wall clockを呼び出すAPIが用意されており、それによって現在の時刻を得る。カーネル内の時刻はNTPの補正を受ける。

参考にしたもの

TCP/IP - NTPとは

リファレンス実装 - Wikipedia

qiita.com

qiita.com

ttlx.hateblo.jp

eng-entrance.com

www.valinux.co.jp

hackers-high.com

www.server-world.info

pool.ntp.org: the internet cluster of ntp servers

*1:他者がそれを参考にして独自に実装することを助ける目的で作られた実装のこと。

*2:カーネルの各機能、もしくはカーネルを構成するプログラム群という理解でよいと思う。

Linuxにおけるブート設定入門

本記事の範囲

システム起動までの流れは以下である。

  1. 電源投入
  2. BIOS / UEFI によるデバイス初期化
  3. ブートデバイスの決定
  4. ブートストラップローダのロード
  5. ブートローダGRUB等)の実行
  6. OSの起動

本記事では5.のブートローダの設定に関して、新旧のGRUBがあったりシステムがBIOSなのかUEFIなのかでやり方が異なり、紛らわしい部分があるので整理する。

GRUB LegacyとGRUB2

GRUBにもGRUB Legacyと呼ばれる古いものと、新しいGRUB2がある。GRUB Legacyはサポートが打ち切られているため、基本的には現在はGRUB2を使う。GRUB LegacyとGRUB2の主な違いは以下である。

今後覚える場合は、GRUB2の書式を覚えればよい*1。本記事でも以降はGRUB2前提で記載する。

基本的な設定方法

/etc配下にGRUB関連の設定ファイルがあるため、これを編集する。編集しただけでは反映されていないため、grub2-mkconfigコマンドでビルドし/boot配下の設定ファイルに反映する。システムは起動時に/boot配下の設定ファイルを参照して動作する。人間が直接/boot配下の設定ファイルを編集はしない。

全体的な設定の変更

全体的な設定は/etc/default/grubで行う。例えば、起動メニューのタイムアウト時間や、起動メッセージを流すかどうかといった点を設定する。

# cat /etc/default/grub
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto spectre_v2=retpoline rhgb quiet"
GRUB_DISABLE_RECOVERY="true"

ここでは起動メニューのタイムアウト時間とスタイルを変更してみる。

# vi /etc/default/grub
# cat /etc/default/grub
#GRUB_TIMEOUT=5
GRUB_TIMEOUT=10 # changed
GRUB_TIMEOUT_STYLE=countdown # changed
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto spectre_v2=retpoline rhgb quiet"
GRUB_DISABLE_RECOVERY="true"

変更後、grub2-mkconfigでビルドし、変更を反映する。 -oで反映先を指定しているが、/boot/grub2/grub.cfgを指定するのはBIOSのシステムの場合である*2UEFIのシステムの場合は、/boot/efi/EFI/ディストリビューション名(redhat, centos等)/grub.cfgに反映する。

# grub2-mkconfig -o /boot/grub2/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-3.10.0-1160.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-1160.el7.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-7c3a299321421f40be4427dfd36d6708
Found initrd image: /boot/initramfs-0-rescue-7c3a299321421f40be4427dfd36d6708.img
done
[root@localhost ~]# reboot

f:id:tanke25616429:20210321160227p:plain
GRUB_TIMEOUT_STYLE=countdownを指定した場合のメニュー画面

GRUB_TIMEOUT_STYLE=countdownをコメントアウトして再度試す。

# vi /etc/default/grub
# cat /etc/default/grub
#GRUB_TIMEOUT=5
GRUB_TIMEOUT=10 # changed
#GRUB_TIMEOUT_STYLE=countdown
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto spectre_v2=retpoline rhgb quiet"
GRUB_DISABLE_RECOVERY="true"

grub2-mkconfigでビルド後、再起動する。もともと5秒からカウントダウンだったが、下記画面キャプチャ時点では残り9秒になっていることがわかる。

f:id:tanke25616429:20210321160626p:plain
GRUB_TIMEOUT=10の場合のメニュー画面

参考:BIOSUEFIかの区別の仕方

/sys/firmware配下に/efiというディレクトリがある場合はUEFI、ない場合はBIOSである。

UEFIの場合

# ls /sys/firmware/
acpi/        dmi/         efi/         memmap/      qemu_fw_cfg/

BIOSの場合

# ls /sys/firmware/
acpi  dmi  memmap  qemu_fw_cfg

メニューエントリーの変更

カーネルアップデートをかけた場合など、起動メニューに複数の選択肢が発生する場合がある。デフォルトの選択肢をどれにするかを設定することができる。以下の例では、バージョンが3.10.0-1062.18.1.el7.x86_64と3.10.0-957.el7.x86_64のカーネルがインストールされている。

# cat /etc/redhat-release
CentOS Linux release 7.7.1908 (Core)
# uname -r
3.10.0-1062.18.1.el7.x86_64
# grep ^menuentry /boot/grub2/grub.cfg
menuentry 'CentOS Linux (3.10.0-1062.18.1.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-957.el7.x86_64-advanced-668d17f8-c677-448b-ace3-cb888f1f9633' {
menuentry 'CentOS Linux (3.10.0-957.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-957.el7.x86_64-advanced-668d17f8-c677-448b-ace3-cb888f1f9633' {
menuentry 'CentOS Linux (0-rescue-88e66ec094834d12b89d26902abe40ce) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-88e66ec094834d12b89d26902abe40ce-advanced-668d17f8-c677-448b-ace3-cb888f1f9633' {

デフォルトメニューは/etc/default/grubGRUB_DEFAULTで設定するが、ここがsavedの場合は別ファイルに保存されている。この場合は、grub2-editenv listコマンドでも確認できる。saved_entry=0なので一番上のもの(=3.10.0-1062.18.1.el7.x86_64)がデフォルトで選択されている。

# cat /etc/default/grub
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet"
GRUB_DISABLE_RECOVERY="true"
# grub2-editenv list
saved_entry=0

3.10.0-957.el7.x86_64のカーネルがデフォルトになるように書き換える。

# grub2-set-default 1
# grub2-editenv list
saved_entry=1
# reboot

起動後、↓キーで移動していないが、2番目のエントリーが選択されている。

f:id:tanke25616429:20210321162655p:plain
saved_entry=1としたときのメニュー画面

当然、そのまま起動すれば、バージョン3.10.0-957.el7.x86_64のカーネルで起動する。なお、GRUBの設定は違うメニューから起動しても共通である。

# cat /etc/redhat-release
CentOS Linux release 7.7.1908 (Core)
# uname -r
3.10.0-957.el7.x86_64
# grub2-editenv list
saved_entry=1
# grep ^menuentry /boot/grub2/grub.cfg
menuentry 'CentOS Linux (3.10.0-1062.18.1.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-957.el7.x86_64-advanced-668d17f8-c677-448b-ace3-cb888f1f9633' {
menuentry 'CentOS Linux (3.10.0-957.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-957.el7.x86_64-advanced-668d17f8-c677-448b-ace3-cb888f1f9633' {
menuentry 'CentOS Linux (0-rescue-88e66ec094834d12b89d26902abe40ce) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-88e66ec094834d12b89d26902abe40ce-advanced-668d17f8-c677-448b-ace3-cb888f1f9633' {

まとめ

  • GRUB Legacy:古いので基本的には覚えなくてよい(ので本記事では割愛)
    • GRUB Legacy×UEFIの組み合わせはそもそも対応もしていない
  • GRUB2:設定は/etc配下の設定ファイルで行い、/boot配下の設定ファイルは直接編集しない。grub2-mkconfigコマンドで/etc配下の設定ファイルの変更点をビルドして反映するが、反映先がUEFIの場合とBIOSの場合で異なる。

参考にしたもの

www.pc-koubou.jp

第5回 ブートローダ|Linux技術者認定機関 LPI-Japan [エルピーアイジャパン]

enakai00.hatenablog.com

www.youtube.com

websetnet.net

【 grub2-mkconfig/grub-mkconfig 】コマンド――GRUB 2の起動メニューを生成する:Linux基本コマンドTips(278) - @IT

第26章 GRUB 2 での作業 Red Hat Enterprise Linux 7 | Red Hat Customer Portal

*1:古いシステムを扱わなくてはいけない場合は別。

*2:今回はVirtualBox上で試しており、VirtualBoxではデフォルトはBIOSとなっている。

Autofs

Autofsの動機

動機は一言で言うとマウントすることにかかるリソースの効率化である。

ファイルシステムをマウントする方法はいくつかある。1つはmountコマンドを用いてシェル上で対話的に行う方法である。以下はxfsでフォーマットされたデバイス/dev/sda1を、/mntというマウントポイント(アクセスするディレクトリのパス)にマウントする例である。

# mount -t xfs /dev/sda1 /mnt

これだと再起動した場合はマウントが解除されるので、マウントが永続するようにするように/etc/fstabというファイルに記載する*1

# cat /etc/fstab
(略)
/dev/sda1                                 /mnt           xfs     defaults        0 0

上記いずれのやり方でも、マウントされたファイルシステムはアクセス有無によらずマウントされた状態である。これだとマウントを維持するにかかるリソースを常に消費する。アクセスがあったときだけ自動的に(オンデマンドで)マウントすることができればマウント維持にかかるリソースを効率化できる。これがAutofsの動機で、実現することである。

使い方

Autofsは、autofsをインストール・有効化し、マウントに関する設定ファイルを記載することで利用できる。

# yum install autofs
(略)
# systemctl enable autofs --now
(略)

マウントに関する設定ファイルではマウントポイントに関する指定をする。/etc/auto.masterというファイルに基本の設定を記載しつつ、他の設定ファイルを組み合わせる。設定ファイルでは一行に1エントリを記載する。書き方は直接マップと間接マップという2通りがある。これについては各々節を分けて後述する。

Autofsの利用例を示す。mountコマンドで表示されないし、umountしても「マウントされていないよ」とメッセージが出るがアクセスはできる*2

# mkdir /test
# mkfs.xfs /dev/sdc
meta-data=/dev/sdc               isize=512    agcount=4, agsize=66993 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=0, sparse=0
data     =                       bsize=4096   blocks=267969, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
# vi /etc/auto.master

/  /etc/auto.test

# vi /etc/auto.test

/test -fstype=xfs /dev/sdc

# systemctl restart autofs
# cd /test/
# touch hogehoge
# ls
hogehoge
# umount /test
umount: /test: not mounted
# mount |grep test
# mount |grep sdc
# cd /test/
# ls
hogehoge

直接マップ

直接マップは/-で始まる行で記載する。/-の後にある/etc/auto.directも設定ファイルであり、ここで指定したファイルにマウントポイントとデバイスの設定を記載する。

# cat /etc/auto.master
(略)
/-      /etc/auto.direct
(略)

マウントポイント/mnt/synologyにnas1:/volume1/dir1をNFSマウントする設定が記載されている。

# cat /etc/auto.direct
/mnt/synology -rw,sync nas1:/volume1/dir1

間接マップ

間接マップでは、/etc/auto.masterにマウントポイントと追加の設定ファイルの情報を記載する。以下はマウントポイント/mntに関する設定を/etc/auto.mntに記載する例である(直接マップで示した例と同じことを間接マップで実現した例である)。

# cat /etc/auto.master
(略)
/mnt     /etc/auto.mnt
(略)

以下のsynologyは/mntからの相対パスを示す。すなわち、この/etc/auto.masterと/etc/auto.mntを組み合わせることで、/mnt/synologyにnas1:/volume1/dir1をマウントすることができる。

# cat /etc/auto.mnt
synology -rw,sync nas1:/volume1/dir1

間接マップでのワイルドカードの利用

マウント設定のエントリ数が多い場合、一行一行書くのは大変なのでワイルドカードを用いて簡略化することができる。

# cat /etc/auto.master
(略)
/mnt     /etc/auto.mnt
(略)

*はマウントポイントに関するワイルドカード、&はマウント元に関するワイルドカードである。これによって/mnt/dir1にアクセスしたらnas1:/volume1/dir1が、/mnt/dir2にアクセスしたらnas1:/volume1/dir2が自動マウントされる(もちろんnas1:/volume1/dir1やnas1:/volume1/dir2が存在する前提である)。

# cat /etc/auto.mnt
* -rw,sync nas1:/volume1/&

参考にしたもの

access.redhat.com

www.8wave.net

access.redhat.com

kazmax.zpp.jp

kazmax.zpp.jp

documentation.suse.com

https://docs.oracle.com/cd/E19504-01/805-0673/6j0msjnjf/index.html

kirifue.hatenadiary.org

*1:この例ではデバイスファイル名/dev/sda1で指定しているが、同じデバイスでもデバイスファイル名は変わり得るので、本来は/dev/sda1ではなくUUID="/dev/sda1のUUID"と書いたほうがよい。

*2:この辺りの挙動は一概に言えないようである。後述のNFSで試した場合、自動マウントされている間はmountコマンドで表示された。したがって「autofsだからmountコマンで表示されない」と断言はできない。

bashの制御構文(for文、if文)

この記事の目的

シェルスクリプトで自分がいろいろ混乱しがちな制御構文の備忘録として記す。種類はbashシェルとする。

事前準備

いろいろ試す用のシェルスクリプトのファイルを作成する*1

[testuser@nuc-centos8 shelltest]$ touch test.sh
[testuser@nuc-centos8 shelltest]$ chmod +x test.sh
[testuser@nuc-centos8 shelltest]$ cat > test.sh
#!/bin/sh
echo hogehoge
[testuser@nuc-centos8 shelltest]$ ./test.sh
hogehoge

サンプルのファイルも置いておく。

[testuser@nuc-centos8 shelltest]$ ls
fileA  fileB  fileC  test.sh

制御構文

for文

for 変数 in 変数の取りうる値の列挙; do
 処理
done

の形式になる。処理をdo~doneではさむこと、doの前にセミコロン;が入ることがポイント。以下が実例。

#!/bin/sh

for file in fileA fileB; do
        ls -i $file
done
[testuser@nuc-centos8 shelltest]$ ./test.sh
144 fileA
145 fileB

列挙の部分は何らかのコマンドの実行結果にしてもよい。コマンドの実行結果を展開するので` `で実行したいコマンドを囲う。

#!/bin/sh

for file in `ls`; do
        ls -i $file
done
[testuser@nuc-centos8 shelltest]$ ./test.sh
144 fileA
145 fileB
146 fileC
147 test.sh

シェルスクリプト内のセミコロンはシェル上のワンライナーで書く場合は、処理の後にもつける。

[testuser@nuc-centos8 shelltest]$ for file in `ls`; do ls -i $file; done
144 fileA
145 fileB
146 fileC
147 test.sh

if文

if [ 条件 ]
then
 処理
elif [ 条件 ]
then
 処理
else
 処理
fi

の形式となる。if~fiで囲むこと、ifとelifの後はthenが入るが最後のelseの後は入らないこと、[ ](ブレース)の条件と左右の括弧の間は半角スペースが必要なことなどがポイントである。

#!/bin/sh

if [ $1 -lt 3 ]
then
        echo AAA
elif [ $1 -eq 3 ]
then
        echo BBB
else
        echo CCC
fi
[testuser@nuc-centos8 shelltest]$ ./test.sh 5
CCC
[testuser@nuc-centos8 shelltest]$ ./test.sh 3
BBB
[testuser@nuc-centos8 shelltest]$ ./test.sh 2
AAA

[ ]thenを同一行に書くこともできるが、その場合は;で区切る必要がある。ワンライナーで書いてみる。ワンライナーで書く場合は処理部分の最後にも;が必要。

[testuser@nuc-centos8 shelltest]$ if [ `ls | wc -w` -eq 4 ]; then echo Yes; fi
Yes

ファイルのタイプを確認できるtestコマンドがあるが、if文の[ ]の中身はtestコマンドと同じである。

[testuser@nuc-centos8 shelltest]$ mkdir dir
[testuser@nuc-centos8 shelltest]$ ln -s /etc/
[testuser@nuc-centos8 shelltest]$ ls -l
total 4
drwxrwxr-x. 2 testuser testuser  6 Mar 19 01:23 dir
lrwxrwxrwx. 1 testuser testuser  5 Mar 19 01:23 etc -> /etc/
-rw-rw-r--. 1 testuser testuser  0 Mar 19 00:31 fileA
-rw-rw-r--. 1 testuser testuser  0 Mar 19 00:31 fileB
-rw-rw-r--. 1 testuser testuser  0 Mar 19 00:31 fileC
-rwxrwxr-x. 1 testuser testuser 93 Mar 19 01:07 test.sh

-fで通常ファイルかどうかを確認する。$?は直前のコマンドの終了ステータスで0は成功、1は失敗である。fileAは通常ファイルだが、dirはディレクトリなので以下のような結果になる。

[testuser@nuc-centos8 shelltest]$ test -f fileA; echo $?
0
[testuser@nuc-centos8 shelltest]$ test -f dir; echo $?
1
[testuser@nuc-centos8 shelltest]$ if [ -f fileA ]; then echo Yes; fi
Yes
[testuser@nuc-centos8 shelltest]$ if [ -f dir ]; then echo Yes; fi
[testuser@nuc-centos8 shelltest]$

-dで通常ファイルかどうかを確認する。dirはディレクトリだが、filrBは通常ファイルでディレクトリではないので以下のような結果になる。

[testuser@nuc-centos8 shelltest]$ test -d dir; echo $?
0
[testuser@nuc-centos8 shelltest]$ test -d fileB; echo $?
1
[testuser@nuc-centos8 shelltest]$ if [ -d dir ]; then echo Yes; fi
Yes
[testuser@nuc-centos8 shelltest]$ if [ -d fileB ]; then echo Yes; fi
[testuser@nuc-centos8 shelltest]$

-Lシンボリックリンクかどうかを確認する。etcはシンボリックリンクだがdirはそうではないので以下のようになる。

[testuser@nuc-centos8 shelltest]$ test -L etc; echo $?
0
[testuser@nuc-centos8 shelltest]$ test -L dir; echo $?
1
[testuser@nuc-centos8 shelltest]$ if [ -L etc ]; then echo Yes; fi
Yes
[testuser@nuc-centos8 shelltest]$ if [ -L dir ]; then echo Yes; fi
[testuser@nuc-centos8 shelltest]$

参考にしたもの

qiita.com

qiita.com

www.koikikukan.com

【 expr 】コマンド――計算式や論理式を評価する:Linux基本コマンドTips(171) - @IT

stackoverflow.com

www.atmarkit.co.jp testコマンド、条件分岐

*1:ちなみにスクリプトの冒頭にある#!から始まる1行目をシェバン (shebang)と呼ぶ。起動して読み込むインタプリタ(シェルの種類など)を指定する。shを指定しているが、この環境ではbashエイリアスになっている。