2023年12月30日土曜日

Kickstartを使ってRHEL 8やRHEL 9を自動インストールする

自宅で検証をする際に、Red Hat Enterprise Linux (RHEL) やCentOS、最近ではRocky LinuxやAlmaLinuxなど、RHEL系のディストリビューションを利用することが多く、頻繁にインストール作業を手作業で行っていた。

慣れてしまえばそこまで時間を要するものではないので、GUIを使ってせっせとインストール作業をしていたが、もっと効率よくインストールできるよう、Kickstart (キックスタート) を使ってインストールの自動化をすることにした。

環境

Kickstartの検証はESXi上に構築したRHEL 8及びRHEL9で実施した。検証完了後に同じKickstartファイルを使って、他ディストリビューションでの動作確認もしており、Rocky Linux、AlmaLinuxでもKickstartによる自動インストールが動作することを確認している。

以下に確認したディストリビューションの一覧を記載する。

  • RHEL 8.3
  • Rocky Linux 8.3
  • AlmaLinux 8.3
  • RHEL 9.2

手順

1. Kickstartファイル (ks.cfg) を作成

Kickstartは、インストール情報を定義したKickstartファイルと呼ばれるファイルを読み込ませることで自動インストールを実現する。このファイルは通常ks.cfgというファイル名で作成をするのが一般的となるが、ファイル名は任意で設定して問題ない。

Kickstartファイルは、インストール時に各種設定を定義するためのコマンドやオプションが用意されている。詳細は公式マニュアルを参照いただきたいが、最低限必要となるコマンドについては、以下表にて説明する。

なお、RHEL 8とRHEL 9で細かいところで設定方法が異なる個所があるため注意すること。

設定項目 設定コマンド 説明
インストールモード text インストールをGUIベース (graphical) にするか、CLIベース (text) にするかの設定。
利用規約 (EULA) への同意 eula --agreed 利用規約への同意を自動で行う設定。
リポジトリ repo インストールに使用するリポジトリのパスを指定。インストールイメージに応じて変更が必要。
パッケージ %packages%end 必要なパッケージを指定。最小インストールの場合は、@^minimal-environmentを指定。
インストール後のスクリプト実行 %post%end インストール後の処理として実行するコマンドを記載する。インストール中の文字化けを防止するため、このタイミングで言語設定をja_JP.UTF-8へ変更をしている。
キーボードレイアウト keyboard キーボードレイアウトを指定。
言語設定 lang システムの言語設定。ここでja_JP.UTF-8を選ぶと、インストールは進むものの画面表示が文字化けした状態となるため、あえてen_US.UTF-8を選択している。
ネットワーク network ホスト名やIPアドレスなどの設定。本設定を省略すると、DHCPによる設定が反映される。
インストールタイプ cdrom ISOイメージからのインストールを設定。
初期セットアップ firstboot 初期セットアップの処理を実行するかどうか。初期インストールであれば、有効にしておけば問題ない。
無視するディスク ignoredisk --drivesオプションにてインストールに関係ないディスクを無視するよう設定する。逆に特定のディスクのみを指定する場合は、--only-useを使用する。仮想環境の場合は、sdaのみ指定しておけば問題ない。
自動パーティション autopart 自動的にパーティションを設定する際に指定。
パーティション初期化 clearpart パーティションの初期化動作を指定。--initlabelオプションにて、対象ディスク (ignorediskで指定したディスク) をすべてフォーマットする。--noneはもしパーティションが存在する場合は削除しないためのオプション。
タイムゾーン timezone タイムゾーンを設定する。日本にする場合はAsia/Tokyoを選択する。RHEL 8の場合はここでNTPサーバを指定できる。その場合は、--ntpserversにて指定する。また、ハードウェアクロックをUTCの時刻とみなす際のオプションがRHEL 8は--isUtc、RHEL 9は--utcと異なるため注意する。
タイムソース timesource RHEL 9の場合は本設定項目にてタイムソースとするNTPサーバを指定する。--ntp-serverを用いて指定する。
rootパスワード rootpw 平文 (--plaintext) またはハッシュ化 (--iscrypted) した文字列でパスワードを指定できる。ハッシュ化したパスワードは、インストール済みの環境の/etc/shadowから抽出すると楽。
RHEL 9以降はデフォルトでrootログインが禁止されるため、もしrootログインを許可したい場合は、--allow-sshオプション(RHEL 9.1以降で使用可能)を付与する(RHEL 8の場合は特に指定しなくてもデフォルトでrootにてログイン可能)。
SELinux selinux SELinuxの有効化、無効化を設定。
ファイアウォール firewall firewalldの有効化、無効化を設定。
インストール後の動作 reboot インストール後に自動で再起動かける場合に指定。同時にDVDを取り出したい場合は、--ejectを付与する。
kdump %addon com_redhat_kdump%end kdumpの設定。
パスワードポリシー %anaconda%end パスワードの最小文字列などのパスワードポリシーの設定。RHEL 9からは本設定項目は非推奨となっている。

以下に私が実際に使用しているKickstartファイルを例として記載する。OSインストールイメージがDVD版の場合とMinimal版の場合で変更を加える箇所があり、具体的には以下2点となる。

  • レポジトリのパス
  • open-vm-toolsのインストール方式 (Minimalのイメージにはopen-vm-toolsが含まれないため、dnfを使ってインストールする必要がある)

▼【RHEL 8】OSインストールイメージがDVDの場合

#version=RHEL8
# Use text install
text

# Agree EULA
eula --agreed

# Package
repo --name="AppStream" --baseurl=file:///run/install/sources/mount-0000-cdrom/AppStream

%packages
@^minimal-environment
@guest-agents
kexec-tools

%end

# Run post script
%post --logfile=/root/ks-post.log
echo 'LANG="ja_JP.UTF-8"' > /etc/locale.conf ; cat /etc/locale.conf

%end

# Keyboard layouts
keyboard --xlayouts='jp'

# System language
lang en_US.UTF-8 --addsupport=ja_JP.UTF-8

# Network information
network  --bootproto=static --device=ens192 --gateway=192.168.11.31 --ip=192.168.11.192 --nameserver=192.168.11.61,192.168.11.62 --netmask=255.255.255.0 --noipv6 --activate
network  --hostname=localhost.localdomain

# Use CDROM installation media
cdrom

# Run the Setup Agent on first boot
firstboot --enable

ignoredisk --only-use=sda
autopart
# Partition clearing information
clearpart --none --initlabel

# System timezone
timezone Asia/Tokyo --isUtc --ntpservers=192.168.33.23

# Root password
rootpw --plaintext XXXXXXXX
#rootpw --iscrypted XXXX~(省略)~XXXX

# Disable SELinux
selinux --disabled

# Disable firewalld
firewall --disabled

# Reboot after installation
reboot

%addon com_redhat_kdump --enable --reserve-mb='auto'

%end

%anaconda
pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty
pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok
pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty
%end

▼【RHEL 8】OSインストールイメージがMinimalの場合

#version=RHEL8
# Use text install
text

# Agree EULA
eula --agreed

# Package
repo --name="Minimal" --baseurl=file:///run/install/sources/mount-0000-cdrom/Minimal

%packages
@^minimal-environment
kexec-tools

%end

# Run post script
%post --logfile=/root/ks-post.log
echo 'LANG="ja_JP.UTF-8"' > /etc/locale.conf ; cat /etc/locale.conf

export http_proxy=http://192.168.33.23:8080
export https_proxy=http://192.168.33.23:8080
dnf install open-vm-tools -y

%end

# Keyboard layouts
keyboard --xlayouts='jp'

# System language
lang en_US.UTF-8 --addsupport=ja_JP.UTF-8

# Network information
network  --bootproto=static --device=ens192 --gateway=192.168.11.31 --ip=192.168.11.192 --nameserver=192.168.11.61,192.168.11.62 --netmask=255.255.255.0 --noipv6 --activate
network  --hostname=localhost.localdomain

# Use CDROM installation media
cdrom

# Run the Setup Agent on first boot
firstboot --enable

ignoredisk --only-use=sda
autopart
# Partition clearing information
clearpart --none --initlabel

# System timezone
timezone Asia/Tokyo --isUtc --ntpservers=192.168.33.23

# Root password
rootpw --plaintext XXXXXXXX
#rootpw --iscrypted XXXX~(省略)~XXXX

# Disable SELinux
selinux --disabled

# Disable firewalld
firewall --disabled

# Reboot after installation
reboot

%addon com_redhat_kdump --enable --reserve-mb='auto'

%end

%anaconda
pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty
pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok
pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty
%end

▼【RHEL 9】OSインストールイメージがDVDの場合

#version=RHEL9
# Use text install
text

# Agree EULA
eula --agreed

# Package
repo --name="AppStream" --baseurl=file:///run/install/sources/mount-0000-cdrom/AppStream

%packages
@^minimal-environment
@guest-agents

%end

# Run post script
%post --logfile=/root/ks-post.log
echo 'LANG="ja_JP.UTF-8"' > /etc/locale.conf ; cat /etc/locale.conf

%end

# Keyboard layouts
keyboard --xlayouts='jp'

# System language
#lang ja_JP.UTF-8
lang en_US.UTF-8 --addsupport=ja_JP.UTF-8

# Network information
#network --bootproto=static --device=ens192 --gateway=192.168.11.31 --ip=192.168.11.192 --nameserver=192.168.11.61,192.168.11.62 --netmask=255.255.255.0 --noipv6 --activate
network --hostname=localhost.localdomain

# Use CDROM installation media
cdrom

# Run the Setup Agent on first boot
firstboot --enable

ignoredisk --only-use=sda
autopart
# Partition clearing information
clearpart --none --initlabel

# System timezone
timezone Asia/Tokyo --utc
timesource --ntp-server 192.168.33.23

# Root password
#rootpw --plaintext --allow-ssh XXXXXXXX
rootpw --iscrypted --allow-ssh XXXX~(省略)~XXXX

# Disable SELinux
selinux --disabled

# Disable firewalld
firewall --disabled

# Reboot after installation
reboot

%addon com_redhat_kdump --enable --reserve-mb='auto'

%end

2. NFSサーバにKickstartファイルを配置

作成したKickstartファイルは、OSインストール時に読み込ませる必要がある。いくつか方式はあるが、今回はNFSサーバにKickstartファイルを配置して、ネットワーク経由で読み込みさせることにする。

NFSサーバの構築は本題とは関係がないため割愛するが、今回はQNAP NASをNFSサーバとして使用することにした。配置パスは以下となる。

nfs:192.168.11.13:/Public2/ks/ks.cfg

3. OSインストールメディアで起動

通常通りOSインストールメディアにて起動し、最初の画面にて「Install Red Hat Enterprise Linux 8.3」を選択したのち、「e」を押し、インストールパラメータを指定する画面に遷移する。

4. インストールパラメータでkickstartファイルを指定

インストールパラメータでは、以下の通り、init.ksのパラメータを追記する。追記箇所を間違えないよう注意。

linuxefi /images/pxeboot/vmlinuz inst.stage2=hd:LABEL=RHEL-8-3-0-BaseOS-x86_64 quiet inst.ks=nfs:192.168.11.13:/Public2/ks/ks_rhel8.cfg

パラメータ追記後、「Ctrl + x」を押してインストールを開始する。

5. 自動インストール開始

Kickstartによる自動インストールが成功した場合は、以下画面のように「Starting automated install」といった表示がされ、自動的にインストールが進む。

なお、Kickstartファイルにてlang ja_JP.UTF-8を設定した場合、インストールは実行されるが、文字化けするので注意。文字化けを回避するため、前述したKickstartファイルでは、%postの処理で言語設定を変更するようにしている。

インストール完了後、自動で再起動がされ、ログインプロンプトが表示されればインストール完了となる。

6. インストール後の確認

インストール完了後、SSHでログインし以下であることを確認した。Kickstartにより問題なく初期設定がされていることが確認できた。

  • 言語設定がja_JP.UTF-8であること
  • タイムゾーンがAsia/Tokyoであること
  • Chronyにて指定したNTPサーバと同期していること
  • open-vm-toolsがインストールされ起動していること
  • SELinuxが無効化されていること
  • firewalldのサービスが停止していること
# localectl
   System Locale: LANG=ja_JP.UTF-8
       VC Keymap: jp
      X11 Layout: jp

# timedatectl
               Local time: 土 2021-05-08 17:46:57 JST
           Universal time: 土 2021-05-08 08:46:57 UTC
                 RTC time: 土 2021-05-08 08:46:57
                Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

# chronyc -n sources
210 Number of sources = 1
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^* 192.168.33.23                 2   6   377    54   +208us[ +253us] +/- 2101us

# systemctl status vmtoolsd
● vmtoolsd.service - Service for virtual machines hosted on VMware
   Loaded: loaded (/usr/lib/systemd/system/vmtoolsd.service; enabled; vendor pr>
   Active: active (running) since Sat 2021-05-08 16:17:38 JST; 1h 29min ago
     Docs: http://github.com/vmware/open-vm-tools
 Main PID: 988 (vmtoolsd)
    Tasks: 3 (limit: 10900)
   Memory: 6.5M
   CGroup: /system.slice/vmtoolsd.service
           mq988 /usr/bin/vmtoolsd

 5月 08 16:17:38 localhost.localdomain systemd[1]: Started Service for virtual >

# getenforce
Disabled

# systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor >
   Active: inactive (dead)
     Docs: man:firewalld(1)

参考

更新履歴

  • 2021/5/8 新規作成
  • 2023/12/30 RHEL 9の情報を追記
2023年12月23日土曜日

UbuntuにZabbix Agent 2をインストールする手順

Zabbix Agentは過去のバージョンから利用されているZabbix Agentとは別に、新たにGo言語ベースで作り直されたZabbix Agent 2が存在する。

過去Windows環境にZabbix Agent 2をインストールする手順は記載した。

今回は、Ubuntuに対してZabbix Agent 2をインストールする手順を記載する。

環境

導入対象となるOSとZabbixのバージョンは以下の通り。

  • OS : Ubuntu 22.04.2 LTS
  • Zabbix Agent 2 : 6.0

Ubuntuは初期状態ではcurlコマンドが使えない場合があるので、その場合は以下の通りインストールをしておくこと。

$ sudo apt install curl

手順

1. zabbix-releaseをインストール

以下URLから最新のzabbix-releaseのパッケージファイルのURLを確認する。

バージョン URL
6.0 https://repo.zabbix.com/zabbix/6.0/ubuntu/pool/main/z/zabbix-release/
6.2 https://repo.zabbix.com/zabbix/6.2/ubuntu/pool/main/z/zabbix-release/
6.4 https://repo.zabbix.com/zabbix/6.4/ubuntu/pool/main/z/zabbix-release/

今回の場合は、Ubuntu 22.04.2 LTSに対して、Zabbix 6.0のエージェントをインストールすることから、https://repo.zabbix.com/zabbix/6.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_latest%2Bubuntu22.04_all.debcurlを使ってダウンロードしてインストールする。

$ curl -LO https://repo.zabbix.com/zabbix/6.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_latest%2Bubuntu22.04_all.deb
$ sudo dpkg -i zabbix-release_latest%2Bubuntu22.04_all.deb
以前に未選択のパッケージ zabbix-release を選択しています。
(データベースを読み込んでいます ... 現在 204627 個のファイルとディレクトリがインストールされています。)
zabbix-release_latest%2Bubuntu22.04_all.deb を展開する準備をしています ...
zabbix-release (1:6.0-4+ubuntu22.04) を展開しています...
zabbix-release (1:6.0-4+ubuntu22.04) を設定しています ...

$ sudo apt update

2. Zabbix Agnet 2をインストール

$ apt search zabbix-agent
ソート中... 完了
全文検索... 完了
pcp-export-zabbix-agent/jammy 5.3.6-1build1 amd64
  Module for exporting PCP metrics to Zabbix agent

zabbix-agent/jammy 1:6.0.25-1+ubuntu22.04 amd64
  Zabbix network monitoring solution - agent

zabbix-agent-dbgsym/jammy 1:6.0.25-1+ubuntu22.04 amd64
  debug symbols for zabbix-agent

zabbix-agent2/jammy 1:6.0.25-1+ubuntu22.04 amd64
  Zabbix network monitoring solution - agent

zabbix-agent2-dbgsym/jammy 1:6.0.25-1+ubuntu22.04 amd64
  debug symbols for zabbix-agent2

zabbix-agent2-plugin-mongodb/jammy 1:6.0.25-1+ubuntu22.04 amd64
  Zabbix Agent2 plugin for monitoring MongoDB installations

zabbix-agent2-plugin-postgresql/jammy 1:6.0.25-2+ubuntu22.04 amd64
  Zabbix Agent2 plugin for monitoring PostgreSQL installations
$ sudo apt install zabbix-agent2

$ systemctl status zabbix-agent2
● zabbix-agent2.service - Zabbix Agent 2
     Loaded: loaded (/lib/systemd/system/zabbix-agent2.service; enabled; vendor preset: enabled)
     Active: active (running) since Sat 2023-12-16 20:34:53 JST; 25s ago
   Main PID: 4798 (zabbix_agent2)
      Tasks: 10 (limit: 4599)
     Memory: 4.5M
        CPU: 21ms
     CGroup: /system.slice/zabbix-agent2.service
             mq4798 /usr/sbin/zabbix_agent2 -c /etc/zabbix/zabbix_agent2.conf

12月 16 20:34:53 t1082ubnt systemd[1]: Started Zabbix Agent 2.
12月 16 20:34:53 t1082ubnt zabbix_agent2[4798]: Starting Zabbix Agent 2 (6.0.25)
12月 16 20:34:53 t1082ubnt zabbix_agent2[4798]: Zabbix Agent2 hostname: [Zabbix server]
12月 16 20:34:53 t1082ubnt zabbix_agent2[4798]: Press Ctrl+C to exit.

3. 設定ファイルを修正

/etc/zabbix/zabbix_agent2.confのファイルを修正し、Zabbix Serverと疎通できるようにする。最低限以下の通り設定すれば動作する。

Server=[Zabbix ServerのIPアドレス]
ServerActive=[Zabbix ServerのIPアドレス]
Hostname=[Ubuntuのホスト名]

設定反映のため、Zabbix Agent 2を再起動する。

$ sudo systemctl restart zabbix-agent2

以上で、Ubuntuに対してZabbix Agent 2をインストールする手順は完了となる。

2023年12月16日土曜日

Kubernetesにてノードの削除・追加を行う

Kubernetesでノードの調子が悪くなったりした際に、一度ノードを削除して同じ名前で再度追加をさせたい場合がある。

簡単にノードを削除・追加するだけであればよいが、Kubernetesの場合、少し追加で必要な作業がある。本記事では、Kubernetesにてノードの削除・追加を行うために必要な手順を記載する。

環境

以下に今回構築する各種ソフトウェアのバージョンを記載する。

  • ホストOS : AlmaLinux 8.6
  • Kubernetes : v1.28.2
  • Docker : 24.0.6
  • CRI : cri-dockerd 0.3.4
  • CNI : flannel v0.22.0

今回の構成の概要図を以下に記載する。

作業前のKubernetesのノードの状態は以下の通り。3台目に存在する「t1053kube」のノードを削除したのち、追加する手順を説明する。

# kubectl get node -o=wide
NAME        STATUS   ROLES           AGE    VERSION   INTERNAL-IP     EXTERNAL-IP   OS-IMAGE                    KERNEL-VERSION              CONTAINER-RUNTIME
t1051kube   Ready    control-plane   202d   v1.28.2   192.168.11.51   <none>        AlmaLinux 8.6 (Sky Tiger)   4.18.0-372.9.1.el8.x86_64   docker://24.0.6
t1052kube   Ready    control-plane   202d   v1.28.2   192.168.11.52   <none>        AlmaLinux 8.6 (Sky Tiger)   4.18.0-372.9.1.el8.x86_64   docker://24.0.6
t1053kube   Ready    control-plane   174d   v1.28.2   192.168.11.53   <none>        AlmaLinux 8.6 (Sky Tiger)   4.18.0-372.9.1.el8.x86_64   docker://24.0.6

ノード削除手順

1. Kubernetesクラスタからノードを削除

Kubernetesクラスタからノードを削除する際は、kubectl delete node [ノード名]で行う。処理はすぐに完了する。

# kubectl delete node t1053kube
node "t1053kube" deleted

3台存在したノードが2台になったことが確認できる。

# kubectl get node -o=wide
NAME        STATUS   ROLES           AGE    VERSION   INTERNAL-IP     EXTERNAL-IP   OS-IMAGE                    KERNEL-VERSION              CONTAINER-RUNTIME
t1051kube   Ready    control-plane   202d   v1.28.2   192.168.11.51   <none>        AlmaLinux 8.6 (Sky Tiger)   4.18.0-372.9.1.el8.x86_64   docker://24.0.6
t1052kube   Ready    control-plane   202d   v1.28.2   192.168.11.52   <none>        AlmaLinux 8.6 (Sky Tiger)   4.18.0-372.9.1.el8.x86_64   docker://24.0.6

2. ノードをリセット

削除した対象のOSにログインし、kubeadm resetを用いて、一度ノードをリセットする。なお、複数のCRIがインストールされている環境の場合は、--cri-socketオプションにて使用するCRIを明記する必要がある(オプションを指定しない場合、Found multiple CRI endpoints on the host.というエラーが表示されコマンドが失敗する)。

# kubeadm reset --cri-socket=unix:///var/run/cri-dockerd.sock
[reset] Reading configuration from the cluster...
[reset] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
W1210 07:53:07.866239  247333 reset.go:120] [reset] Unable to fetch the kubeadm-config ConfigMap from cluster: failed to get node registration: failed to get node name from kubelet config: open /etc/kubernetes/kubelet.conf: no such file or directory
W1210 07:53:07.866312  247333 preflight.go:56] [reset] WARNING: Changes made to this host by 'kubeadm init' or 'kubeadm join' will be reverted.
[reset] Are you sure you want to proceed? [y/N]: y ★"y"を入力
[preflight] Running pre-flight checks
W1210 07:53:09.421805  247333 removeetcdmember.go:106] [reset] No kubeadm config, using etcd pod spec to get data directory
[reset] Deleted contents of the etcd data directory: /var/lib/etcd
[reset] Stopping the kubelet service
[reset] Unmounting mounted directories in "/var/lib/kubelet"
[reset] Deleting contents of directories: [/etc/kubernetes/manifests /var/lib/kubelet /etc/kubernetes/pki]
[reset] Deleting files: [/etc/kubernetes/admin.conf /etc/kubernetes/kubelet.conf /etc/kubernetes/bootstrap-kubelet.conf /etc/kubernetes/controller-manager.conf /etc/kubernetes/scheduler.conf]

The reset process does not clean CNI configuration. To do so, you must remove /etc/cni/net.d

The reset process does not reset or clean up iptables rules or IPVS tables.
If you wish to reset iptables, you must do so manually by using the "iptables" command.

If your cluster was setup to utilize IPVS, run ipvsadm --clear (or similar)
to reset your system's IPVS tables.

The reset process does not clean your kubeconfig files and you must remove them manually.
Please, check the contents of the $HOME/.kube/config file.

3. etcdからNode情報を削除

Kubernetesクラスタから削除しても、etcdからは情報が削除されない。そこで、直接etcdのPodにログインし削除作業を行う。etcdにログインすると、プロンプトがsh-5.1#に変わる。

# kubectl exec -it -n kube-system etcd-t1051kube -- sh
sh-5.1#

etcdの操作はetcdctlコマンドで実行する。オプションが多いため超絶コマンドが長いが、以下の通りetcdctl member listを実行すると、現在etcdに登録されている情報を確認することができる。先ほどKubernetesクラスタから削除した「t1053kube」のノードの情報が残っていることがわかる。

sh-5.1# ETCDCTL_API=3 etcdctl --cert=/etc/kubernetes/pki/etcd/peer.crt --key=/etc/kubernetes/pki/etcd//peer.key --cacert=/etc/kubernetes/pki/etcd/ca.crt --endpoints=https://127.0.0.1:2379 member list
391db64cfd0b76da, started, t1052kube, https://192.168.11.52:2380, https://192.168.11.52:2379, false
40f1e9f856640698, started, t1051kube, https://192.168.11.51:2380, https://192.168.11.51:2379, false
a642d0757a50ab59, started, t1053kube, https://192.168.11.53:2380, https://192.168.11.53:2379, false

テーブル形式でもう少し見やすくする場合は、etcdctl -w table member listを実行する。

sh-5.1# ETCDCTL_API=3 etcdctl --cert=/etc/kubernetes/pki/etcd/peer.crt --key=/etc/kubernetes/pki/etcd//peer.key --cacert=/etc/kubernetes/pki/etcd/ca.crt --endpoints=https://127.0.0.1:2379 -w table member list
+------------------+---------+-----------+----------------------------+----------------------------+------------+
|        ID        | STATUS  |   NAME    |         PEER ADDRS         |        CLIENT ADDRS        | IS LEARNER |
+------------------+---------+-----------+----------------------------+----------------------------+------------+
| 391db64cfd0b76da | started | t1052kube | https://192.168.11.52:2380 | https://192.168.11.52:2379 |      false |
| 40f1e9f856640698 | started | t1051kube | https://192.168.11.51:2380 | https://192.168.11.51:2379 |      false |
| a642d0757a50ab59 | started | t1053kube | https://192.168.11.53:2380 | https://192.168.11.53:2379 |      false |
+------------------+---------+-----------+----------------------------+----------------------------+------------+

削除対象の「t1053kube」のIDを引数として、etcdctl member remove [ID]を実行する。

sh-5.1# ETCDCTL_API=3 etcdctl --cert=/etc/kubernetes/pki/etcd/peer.crt --key=/etc/kubernetes/pki/etcd//peer.key --cacert=/etc/kubernetes/pki/etcd/ca.crt --endpoints=https://127.0.0.1:2379 member remove a642d0757a50ab59
Member a642d0757a50ab59 removed from cluster 786da9e9c378caa1

再度登録状況を確認すると、「t1053kube」が削除されていることが確認できる。

sh-5.1# ETCDCTL_API=3 etcdctl --cert=/etc/kubernetes/pki/etcd/peer.crt --key=/etc/kubernetes/pki/etcd//peer.key --cacert=/etc/kubernetes/pki/etcd/ca.crt --endpoints=https://127.0.0.1:2379 -w table member list
+------------------+---------+-----------+----------------------------+----------------------------+------------+
|        ID        | STATUS  |   NAME    |         PEER ADDRS         |        CLIENT ADDRS        | IS LEARNER |
+------------------+---------+-----------+----------------------------+----------------------------+------------+
| 391db64cfd0b76da | started | t1052kube | https://192.168.11.52:2380 | https://192.168.11.52:2379 |      false |
| 40f1e9f856640698 | started | t1051kube | https://192.168.11.51:2380 | https://192.168.11.51:2379 |      false |
+------------------+---------+-----------+----------------------------+----------------------------+------------+

最後にexitでetcdから抜けておく。

sh-5.1# exit

ノード参加手順

1. 参加するためのtoken作成

ノード参加のためには、tokenを作成する必要がある。現在作成されているtokenは以下コマンドで確認できる。何も表示されない場合は、未登録であることを意味する。

# kubeadm token list

tokenを作成しつつノード追加のコマンドを表示させるため、以下コマンドを実行する。

# kubeadm token create --print-join-command
kubeadm join t1041kube.intrat.local:6443 --token hqrq5b.lmlys2u5vsqmza06 --discovery-token-ca-cert-hash sha256:cd21077ae8389da3990d28424f3e8aa1fcbf5394094bcb849803b8664d700b55

また、ノード追加時に必要となる証明書の更新も実施する。

# kubeadm init phase upload-certs --upload-certs
[upload-certs] Storing the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace
[upload-certs] Using certificate key:
36568d37aa84232e623cd8df34c1704c2fb16e7846e7df92b55f13072ce262f0

再度tokenを確認すると、tokenと証明書の2行が表示されていることが確認できる。

# kubeadm token list
TOKEN                     TTL         EXPIRES                USAGES                   DESCRIPTION                                                EXTRA GROUPS
hqrq5b.lmlys2u5vsqmza06   23h         2023-12-10T22:41:01Z   authentication,signing   <none>                                                     system:bootstrappers:kubeadm:default-node-token
x87o7b.ya73txnsszqsx8x5   1h          2023-12-10T00:58:59Z   <none>                   Proxy for managing TTL for the kubeadm-certs secret        <none>

2. kubectl joinコマンド実行

token作成時に生成したkubeadm joinコマンドを実行し、ノードを再参加させる。なお、コントロールプレーンとして追加する場合は、--control-plane--certificate-keyのオプション指定が追加で必要となる。--cri-socketは前述したとおり、複数のCRIがインストールされている環境の場合に必要となる。

今回の場合はコントロールプレーンとしてノードを参加させるため、コマンドは以下のようになった。

kubeadm join t1041kube.intrat.local:6443 --token hqrq5b.lmlys2u5vsqmza06 \
--discovery-token-ca-cert-hash sha256:cd21077ae8389da3990d28424f3e8aa1fcbf5394094bcb849803b8664d700b55 \
--control-plane \
--certificate-key 36568d37aa84232e623cd8df34c1704c2fb16e7846e7df92b55f13072ce262f0 \
--cri-socket=unix:///var/run/cri-dockerd.sock

実際の実行結果は以下となる。

# kubeadm join t1041kube.intrat.local:6443 --token hqrq5b.lmlys2u5vsqmza06 \
> --discovery-token-ca-cert-hash sha256:cd21077ae8389da3990d28424f3e8aa1fcbf5394094bcb849803b8664d700b55 \
> --control-plane \
> --certificate-key 36568d37aa84232e623cd8df34c1704c2fb16e7846e7df92b55f13072ce262f0 \
> --cri-socket=unix:///var/run/cri-dockerd.sock
[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[preflight] Running pre-flight checks before initializing the new control plane instance
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
W1210 08:16:25.328679  250776 checks.go:835] detected that the sandbox image "registry.k8s.io/pause:3.6" of the container runtime is inconsistent with that used by kubeadm. It is recommended that using "registry.k8s.io/pause:3.9" as the CRI sandbox image.
[download-certs] Downloading the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace
[download-certs] Saving the certificates to the folder: "/etc/kubernetes/pki"
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [localhost t1053kube] and IPs [192.168.11.53 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [localhost t1053kube] and IPs [192.168.11.53 127.0.0.1 ::1]
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local t1041kube.intrat.local t1053kube] and IPs [10.96.0.1 192.168.11.53]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Valid certificates and keys now exist in "/etc/kubernetes/pki"
[certs] Using the existing "sa" key
[kubeconfig] Generating kubeconfig files
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[check-etcd] Checking that the etcd cluster is healthy
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...
[etcd] Announced new etcd member joining to the existing etcd cluster
[etcd] Creating static Pod manifest for "etcd"
[etcd] Waiting for the new etcd member to join the cluster. This can take up to 40s
The 'update-status' phase is deprecated and will be removed in a future release. Currently it performs no operation
[mark-control-plane] Marking the node t1053kube as control-plane by adding the labels: [node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers]
[mark-control-plane] Marking the node t1053kube as control-plane by adding the taints [node-role.kubernetes.io/control-plane:NoSchedule]

This node has joined the cluster and a new control plane instance was created:

* Certificate signing request was sent to apiserver and approval was received.
* The Kubelet was informed of the new secure connection details.
* Control plane label and taint were applied to the new node.
* The Kubernetes control plane instances scaled up.
* A new etcd member was added to the local/stacked etcd cluster.

To start administering your cluster from this node, you need to run the following as a regular user:

        mkdir -p $HOME/.kube
        sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
        sudo chown $(id -u):$(id -g) $HOME/.kube/config

Run 'kubectl get nodes' to see this node join the cluster.

最後にノードの状態を確認すると「t1053kube」が正常に登録されステータスがReadyになっていることがわかる。

# kubectl get node -o=wide
NAME        STATUS   ROLES           AGE    VERSION   INTERNAL-IP     EXTERNAL-IP   OS-IMAGE                    KERNEL-VERSION              CONTAINER-RUNTIME
t1051kube   Ready    control-plane   202d   v1.28.2   192.168.11.51   <none>        AlmaLinux 8.6 (Sky Tiger)   4.18.0-372.9.1.el8.x86_64   docker://24.0.6
t1052kube   Ready    control-plane   202d   v1.28.2   192.168.11.52   <none>        AlmaLinux 8.6 (Sky Tiger)   4.18.0-372.9.1.el8.x86_64   docker://24.0.6
t1053kube   Ready    control-plane   17s    v1.28.2   192.168.11.53   <none>        AlmaLinux 8.6 (Sky Tiger)   4.18.0-372.9.1.el8.x86_64   docker://24.0.6

以上で、Kubernetesにてノードの削除・追加を行うために必要な手順は完了となる。

2023年12月9日土曜日

RHEL 9のsshdでPermitRootLoginなどを設定する方法

先日、RHEL 9互換OSのAlmaLinux 9を使った際に、SSHで直接rootログインを禁止しようと、PermitRootLogin noの設定を/etc/ssh/sshd_configに記載した。

しかし、記載したにも関わらずSSHでrootログインできてしまうという事象が発生した。調べてみると、RHEL 9からはsshdの設定方法が少し変更となったようだ。

本記事では、RHEL 9のsshdでPermitRootLoginなどを設定する方法を記載する。

環境

  • OS : Red Hat Enterprise Linux release 9.2

設定手順

RHEL 7や8などでは/etc/ssh/sshd_configにPermitRootLoginの設定を実施すれば問題なかったが、RHEL 9からは追加の設定は/etc/ssh/sshd_config.d/のディレクトリ内の設定ファイルに記載する方式に変わっている。

/etc/ssh/sshd_configを確認すると、以下の通りディレクトリ内の設定ファイルをIncludeする設定が記載されている。

# cat /etc/ssh/sshd_config | grep -B3 'Include'

# To modify the system-wide sshd configuration, create a  *.conf  file under
#  /etc/ssh/sshd_config.d/  which will be automatically included below
Include /etc/ssh/sshd_config.d/*.conf

実際に/etc/ssh/sshd_config.d/のディレクトリを見ると、以下の通り2つのファイルが存在した。

# ls -l /etc/ssh/sshd_config.d/
合計 8
-rw-r--r--. 1 root root 141 10月  6 20:08 01-permitrootlogin.conf
-rw-------. 1 root root 719  1月 16  2023 50-redhat.conf

今回はPermitRootLoginの設定なので、01-permitrootlogin.confのファイルを編集する。

# cat /etc/ssh/sshd_config.d/01-permitrootlogin.conf
PermitRootLogin no # noに変更しSSHによるrootログインを拒否する

設定後、sshdをリロードすれば完了となる。

# systemctl reload sshd

以上で、RHEL 9のsshdでPermitRootLoginなどを設定する方法は完了となる。

2023年12月2日土曜日

ソースからインストールしたOpenLDAPのSSL有効化手順

先日、RHEL 9にOpenLDAPをソースからインストールする手順を記載した。

上記手順ではLDAPのみ有効としており、通信が暗号化されていない。LDAPでは通信を暗号化する方法としてLDAPS (LDAP over SSL/TLS) があり、OpenLDAPにおいても設定を有効化することでLDAPS通信を利用できる。

本記事では、ソースからインストールOpenLDAPに対してSSLを有効化する手順を記載する。

環境

今回は以下のOSに対してインストールを行った。OpenLDAPは本記事作成時のLTSリリースの最新版である2.5.16をダウンロードした。

  • OS : RHEL 9
  • OpenLDAP : 2.5.16

OpenLDAPのドメイン等の情報は以下とする。

設定項目 設定値
ドメイン dc=example,dc=com
RootDN cn=Manager,dc=example,dc=com
OU ou=group,dc=example,dc=com
グループ cn=ldapgrp,ou=group,dc=example,dc=com
ユーザ1 uid=user01,ou=group,dc=example,dc=com
ユーザ2 uid=user01,ou=group,dc=example,dc=com

OpenLDAPをソースからインストール

OpenLDAPをソースからインストールする手順は、以下記事の通り実施する。

  • URL

OpenLDAP SSL有効化手順

1. 証明書作成

OpenLDAPをSSLするための公開鍵と秘密鍵を作成する。作成した鍵は/etc/openldap/certs/に配置するため、あらかじめ移動しておく。

# cd /etc/openldap/certs/

秘密鍵を作成する。

# openssl genrsa 2048 > ldaps.key

秘密鍵をもとにCSRを作成する。

# openssl req -new -key ldaps.key > ldaps.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:JP
State or Province Name (full name) []:Tokyo
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:LDAPS
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

公開鍵に埋め込むSAN (サブジェクト代替名) の情報をテキストファイルで作成しておく。今回はOpenLDAPのドメイン (example.com) とOpenLDAPサーバのIPアドレス (192.168.11.191) で設定した。

# cat << EOF > san.txt
subjectAltName = DNS:*.example.com, IP:192.168.11.191
EOF

最後にCSRとSANの情報を用いて公開鍵を作成する。

# openssl x509 -days 3650 -req -signkey ldaps.key -in ldaps.csr -out ldaps.crt -extfile san.txt
Certificate request self-signature ok
subject=C = JP, ST = Tokyo, L = Default City, O = Default Company Ltd, CN = LDAPS

最終的に以下4つのファイルが作成される。

# ls -l
合計 16
-rw-r--r--. 1 root root 1302 10月 29 08:11 ldaps.crt
-rw-r--r--. 1 root root  997 10月 29 08:10 ldaps.csr
-rw-r--r--. 1 root root 1704 10月 29 08:10 ldaps.key
-rw-r--r--. 1 root root   54 10月 29 08:07 san.txt

2. SSL有効化用LDIFファイルを作成

OpenLDAPの設定は、LDIF (LDAP Interchange Format)と呼ばれる設定ファイルを読み込ませることで行う。

まずは、以下の通りLDIFファイルを作成する。

# cd ~
# cat << EOF > ssl.ldif
dn: cn=config
changetype: modify
replace: olcTLSCertificateFile
olcTLSCertificateFile: /etc/openldap/certs/ldaps.crt
-
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/openldap/certs/ldaps.key
EOF

反映はslapmodifyコマンドで行う。

# /usr/sbin/slapmodify -v -n 0 -F /etc/openldap/slapd.d -l ssl.ldif
modify: "cn=config" (00000001)
Closing DB...

なお、ldapaddコマンドではInsufficient access (50)で失敗するため設定変更できないため注意しよう。

# ldapadd -Y EXTERNAL -H ldapi:// -f ssl.ldif
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "cn=config"
ldap_modify: Insufficient access (50)

3. systemdの設定を修正

systemdでOpenLDAPのサービス起動時のコマンドにおいて、LDAPSを受け付けするよう設定追加を行う。

# vi /etc/systemd/system/slapd.service
[Unit]
Description=OpenLDAP server
After=syslog.target network.target

[Service]
Type=forking
User=root
Group=root
PIDFile=/usr/var/run/slapd.pid
ExecStart=/usr/libexec/slapd -F /etc/openldap/slapd.d -h 'ldapi:/// ldap:/// ldaps:///' ←★「ldaps:///」を追加
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -TERM $MAINPID

[Install]
WantedBy=multi-user.target

設定を反映させる。

# systemctl daemon-reload
# systemctl restart slapd

反映後、LDAPSのポート番号である636が開放されていることを確認する。

# ss -nl | egrep '389|636'
tcp   LISTEN 0      2048        0.0.0.0:389         0.0.0.0:*
tcp   LISTEN 0      2048        0.0.0.0:636         0.0.0.0:*
tcp   LISTEN 0      2048           [::]:389            [::]:*
tcp   LISTEN 0      2048           [::]:636            [::]:*

4. LDP.exeを使った確認

実際に、外部からアクセスできることをWindows ServerのLDP.exeを利用して確認する。なお、LDP.exeは、役割管理ツールの「AD DSおよびAD LDSツール」に含まれる

なお、LDAPSはそのままではLDP.exeにて接続することができず、OpenLDAPサーバにて作成したSSLサーバ証明書の公開鍵であるldaps.crtを「信頼されたルート証明機関」として登録が必要となる。

/etc/openldap/certs/ldaps.crtLDP.exeを実行するサーバにダウンロードし、ファイルをダブルクリックすると証明書の情報を確認することができ、「証明書のインストール」を選択することで「証明書のインポートウィザード」を開始できる。

インポートウィザードでは証明書ストアにて「信頼されたルート証明機関」を選択する。

セキュリティ警告が表示される場合があるが、自己署名証明書による証明書エラーとなることから、そのまま「はい」を選択する。

証明書をインポートしたのち、再度LDP.exeにて接続すると、以下の通りSSLによる接続に成功する。

以上で、ソースからインストールOpenLDAPに対してSSLを有効化する手順は完了となる。

人気の投稿