Huge Page與Transparent Huge Page

簡單的說,都跟記憶體分頁管理有關係。要用 Huge Page ,程式需要做調整,為了簡化使用方式,Red Hat 在 RHEL6 引入 Transparent Huge Page ,預設啟用,主要是要讓程式可以不需要更動,就可以使用 Huge Page。

詳情可以參考:

一般來說,若主機主要是執行資料庫,例如 Oracle, Redis, MongoDB, PostgreSQL,就不要使用 Transparent Huge Page。

在 RHEL 6 以後 Transparent Huge Page 預設是啟用,可以用以下指令檢查

cat /sys/kernel/mm/transparent_hugepage/enabled

輸出是 always ,就表示有啟用。若為 never ,就沒有啟用。madvise 是什麼意思呢?

當有啟用 Transparent Huge Page 時,Huge Page 就被禁用,可以用以下指令檢查,若為 0,表示禁用。

cat /proc/sys/vm/nr_hugepages

要禁用 Transparent Huge Page,用以下指令就可以

echo never > /sys/kernel/mm/redhat_transparent_hugepage/enabled

在 RHEL8 裡,有 tuned,當使用上面設定無法生效時,有可能就是這個 tuned 在搞鬼。這時可以建立一個新的 tuned profile: /etc/tuned/nothp_profile/tuned.conf

內容是

[main]
include= throughput-performance

[vm]
transparent_hugepages=never

執行以下指令就可以生效。

chmod +x /etc/tuned/nothp_profile/tuned.conf
tuned-adm profile nothp_profile

若要永久禁用,可以在 /etc/default/grub 的 GRUB_CMDLINE_LINUX 加入 transparent_hugepage=never

執行 grub2-mkconfig -o 之後,重開機即可。

在 Ubuntu 開發 .Net 應用程式

這幾年微軟大力推廣 .Net core ,把 .Net runtime 鋪到每個 Linux 發行版去,所以現在 Ubuntu、Red Hat Enterprise、Debian、Fedora、CentOS、Alpine 等 Linux 發行版都可以安裝 .Net runtime 跟 .Net SDK 。

以 Ubuntu 來說,安裝方法很簡單,就是照這篇 在Ubuntu 上安裝 .NET SDK 或 .NET 執行時間 來做就可以。

我桌機安裝的是 Ubuntu 21.10 ,所以下面就只節錄 Ubuntu 21.10 的部份

wget https://packages.microsoft.com/config/ubuntu/21.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb
sudo apt-get update; \
  sudo apt-get install -y apt-transport-https && \
  sudo apt-get update && \
  sudo apt-get install -y dotnet-sdk-6.0 aspnetcore-runtime-6.0

安裝完成以後,就可以使用 dotnet 這個指令來開發應用程式了。

首先建立目錄,然後切換到此目錄下

mkdir -p ~/dotnetcore-hello
cd ~/dotnetcore-hello

然後用 dotnet 指令建立範本

dotnet new webapp -n dotnetcore-hello -o .
  • webapp 表示建立網頁應用程式。
  • -n 是表示專案名稱。
  • -o . 是表示輸出到目前的目錄。

產生完畢,就可以啟動。

dotnet run

啟動以後會有以下訊息

正在建置...
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: https://localhost:7219
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5063
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /home/user/dotnetcore-hello/

從訊息可以知道,用瀏覽器開啟 http://localhost:5063 或是 https://localhost:7219 就可以開啟網站。

一般在開發時,會把 port 固定起來,以方便開發;或者是禁用 https 。那這樣該怎麼做呢?這時候可以參考 How do I disable HTTPS in ASP.NET Core 2.1 + Kestrel? ,dotnet 應用程式的 port 跟 https 設定是在 Properties/launchSettings.json 裏面去指定的,只要修改裡面的 applicationUrl 即可。

例如 applicationUrl 本來是 https://localhost:7219;http://localhost:5063,改為只有 http,port 8000 並讓網路上其他電腦都可以連進來的話,就改為 http://0.0.0.0:8000

最後,開發完畢以後,要輸出檔案去佈署,可以用 dotnet publish 來建置。

dotnet publish -c release -o out

以上面的指令來說,

  • -c 是指定要使用的 configuration
  • -o 是指定把建置好的檔案輸出到 out 目錄下。

今天就把 QuickStart 的開發流程紀錄起來,免得以後遇到又在那邊查。

RPM解析

察看 RPM 內容,可以用下面指令,無需解開,就可以知道裏面有什麼檔案。

rpm -ql <rpm_file>

需要取出裡面的檔案時,可以用 rpm2cpio + cpio 來解開。

rpm2cpio <rpm_file> | cpio -idmv

cpio 的參數解說如下

  • -i: 從 archive 解開檔案。
  • -d: 建立必要的目錄
  • -m: 保留檔案的變更時間
  • -v: verbose

在安裝 rpm 時,會在安裝前、後去執行腳本,但你會發現在解壓縮後的檔案裡找不到這些腳本。那如果想看這些腳本,該怎麼做?

這時候可以用下面指令來察看

rpm -qp --scripts <rpm_file>

裡面的 %preun、%postun …等等的區段是什麼意思呢?

這部份可以參考 Packaging Guidelines > Scriptlets 裡的說明。

參考資料:

ArchLinux 的 Reflector

Reflector 是一個用來更新 mirrorlist 的程式,前幾年看到的時候就用了,挺不錯的。最近想起來,但怎麼樣也找不到筆記,我想應該是沒有紀錄到吧,特別寫這篇來記著。

ArchLinux 維基的 Reflector 頁面寫的蠻清楚的,就不再贅述,下面主要紀錄我做的設定。

安裝

yay -S reflector

新增檔案:$HOME/bin/renew_mirrorlist ,這主要是方便手動更新用的。

#!/bin/bash
sudo /bin/sh -c "reflector @/etc/xdg/reflector/reflector.conf && rm -f /etc/pacman.d/mirrorlist.pacnew"

編輯檔案:/etc/xdg/reflector/reflector.conf ,這個檔案會被 reflector.service 跟 reflector.timer 使用到。

# 存到 /etc/pacman.d/mirrorlist
--save /etc/pacman.d/mirrorlist
# 只用 http 跟 https 的來源
--protocol http,https
# 從台灣、日本的伺服器來挑
--country Taiwan,Japan
# 挑最近更新的 10 個伺服器
--latest 10
# 用分數來排序
--sort score
# 最近 24 小時內同步完的伺服器
--age 24

新增檔案:/etc/pacman.d/hooks/mirrorupgrade.hook,這會在 pacman 更新 mirrorlist 時去執行。這同時也要修改 /etc/pacman.conf,把裏面 HookDir 那行的註解拿掉。

[Trigger]
Operation = Upgrade
Type = Package
Target = pacman-mirrorlist

[Action]
Description = Updating pacman-mirrorlist with reflector and removing pacnew...
When = PostTransaction
Depends = reflector
Exec = /bin/sh -c "/usr/bin/reflector @/etc/xdg/reflector/reflector.conf && rm -f /etc/pacman.d/mirrorlist.pacnew"

最後再啟用定時更新

systemctl enable reflector.timer
systemctl start reflector.timer

jc – 將指令輸出結果轉為JSON格式

分享 jc 這指令,裝了以後,可以把一些指令的輸出轉為 json,之後就可以搭配 jq 來查詢 json 裡的資料。

安裝

RHEL8 的安裝,需要直接從 jc 的 github 頁面下載 linux binary 。

Debian/Ubuntu 可以使用 apt-get install jc

ArchLinux 可以用 pacman -S jc

MacOS 可以用 brew install jc

使用

例如

 非 jq 作法用 jq
掛載點mount | awk '{print $1;}'mount | jc --mount | jq -r ".[].filesystem"
digdig example.com | awk '/ANSWER\ SECTION/ { getline; print $5; }'dig example.com | jc --dig | jq -r '.[].answer[].data'

除了 mountdig 之外,也可以解析蠻多指令的,這部份可以參照 github 網頁

參考資料:

sudoers 檔案改壞了

昨天不小心在 /etc/sudoers.d 目錄下加了個檔案,格式有問題,導致之後下 sudo 指令都會出現這樣的錯誤:

sudo: unable to initialize policy plugin

本想說要來重開機,進 single 模式來修改了,還好,找到這篇:https://unix.stackexchange.com/questions/677591/how-to-restore-a-broken-sudoers-file-without-being-able-to-use-sudo

照這篇的方法來處理,就免於重開機的命運。

方法是這樣的,先開兩個終端機視窗,都登入需要處理 sudoers 的主機,在第一個終端機視窗輸入下面指令取得當前 bash 的 pid

echo $$

在第二個終端機視窗輸入

pkttyagent --process <pid>

這個 <pid> 就是前面取得的 bash 的 pid。

再回到第一個終端機視窗,因為我是在 /etc/sudoers.d 目錄下加了一個格式錯誤的檔案,所以就刪掉就可以。

pkexec rm -f /etc/sudoers.d/user1

文章裡,是提問者把檔案擁有者改錯了,導致有問題,所以他用的是 chown 來改擁有者。

文章裡有說明為什麼可以用 pkexec 來處理,這指令其實跟 sudo 差不多,主要是用 polkit 在處理,解答的人說的很仔細。

可喜可賀,學到一個有趣的指令,也解決了一個手殘改錯的問題。

RHEL8 iSCSI

target 主要提供 iSCSI 裝置,客戶端要使用這個裝置,就需要設置 iSCSI initiator。

我設置 iSCSI target 的方式主要是參考:How to Share Storage via iSCSI Target in RHEL 7/CentOS 7 還有 RHEL8 的管理存儲設備手冊裡的第七章

客戶端的設置,則是參考:How to Configure iSCSI initiator in RHEL 7/CentOS 7

iSCSI target

首先安裝 targetcli

yum install targetcli
systemctl start target
systemctl enable target
firewall-cmd --permanent --add-port=3260/tcp
firewall-cmd --reload

然後執行 targetcli ,targetcli 指令跟 bash 操作很接近,有 ls ,每個資源則用 cd 進入,操作可以用 create, delete 等,很直覺。

第一步是進入 iscsi 去建立 target

iscsi/
create

若需要使用指定的名稱,則是用

create iqn.2006-04.com.example:444

第二步是建立 backstore,這邊只建立 block storage,是告知 backstore 名稱是 block1,使用的實體裝置是 /dev/sdb

cd /backstores
block/ create name=block1 dev=/dev/sdb

第三步是建立 portal,這邊會先把預設的刪除,再重新建立。這主要是設定要 listen 的 位址跟 port。把預設的刪除掉的原因是,0.0.0.0 範圍太大。

cd /iscsi/iqn.2006-04.example:444/tpg1
delete ip_address=0.0.0.0 ip_port=3260
create 192.168.11.147

第四步是建立 lun

/iscsi/iqn.2006-04.example:444/tpg1/luns/ create /backstores/block/block1

第五步是建立 ACL

/iscsi/iqn.2006-04.example:444/tpg1/acls/ create iqn.2006-04.com.example.foo:888

最後,要重新啟動 target.service

systemctl restart target

iSCSI 客戶端

首先是安裝套件

yum install iscsi-initiator-utils -y

再來是修改設定,主要的設定檔是在 /etc/iscsi/initiatorname.iscsi

內容要填入前面所建立的 acl

InitiatorName=iqn.2006-04.com.example.foo:888

填寫完成後,重新啟動 iscsi.service

systemctl enable iscsi.service
systemctl start iscsi.service

然後去做 discovery,這個步驟會去試探指定的 IP 是否有 iscsi target,然後取得資訊存起來。

iscsiadm -m discovery -t st -p 192.168.11.147 –discover
192.168.11.147:3260,1 iqn.2006-04.com.example:444

這步驟若沒問題,可以在 /var/lib/iscsi/nodes 下找到檔案,這檔案裏面就是連線的資訊。

接下來就是登入

iscsiadm -m node -T iqn.2006-04.com.example:444 -l

這行若成功,就可以用 dmesg 查到 “Attached” 的字樣,表示已經掛載上來了。

這邊有個關鍵,就是有更動 /etc/iscsi/initiatorname.iscsi 內容的話,一定要重新啟動 iscsi.service ,否則會使用到之前的設定,導致失敗。

ls 的 quoting-style

有人來問才知道 ls 是有在改版的。

在 coreutils 8.30 (RHEL8) 預設的 quoting-style 是 shell,在 coreutils 8.22 (RHEL7) 預設的 quoting-style 是 literal,主要差異是在於檔名有空白時是否要加上單引號。

在 coreutils 8.30 (RHEL8) 是這樣

# ls -l
total 8
-rw-r--r--. 1 root root   0 Dec  1 14:38  bar.txt
-rw-r--r--. 1 root root 514 Dec  1 15:38  cluster-logging.yml
-rw-r--r--. 1 root root   0 Dec  1 14:38 'foo bar.txt'
-rw-r--r--. 1 root root   0 Dec  1 14:38  foo.txt
-rw-r--r--. 1 root root 528 Dec  1 15:38  openshift-user-critical.yml

在 coreutils 8.22 (RHEL7) 是這樣

# ls -l
總計 0
-rw-r--r--. 1 root root 0 12月  1 14:41 bar.txt
-rw-r--r--. 1 root root 0 12月  1 14:41 foo bar.txt
-rw-r--r--. 1 root root 0 12月  1 14:41 foo.txt

在 RHEL8 想讓輸出的結果跟 RHEL7 一樣的話,可以加上 –quoting-style 參數

ls -l --quoting-style=literal

RHEL8強制解除註冊

前兩天遇到的狀況是這樣,公司裡的 RHEL8 主機是註冊到 Satellite 上,但 Satellite 主機因為機房設備升級,開不了機,可是這台 RHEL8 主機又急著要安裝套件,那就得先解除註冊。

第一步,是先處理 /etc/rhsm/rhsm.conf ,註冊到 Satellite 時,rhsm.conf 裡的設定會被修改,表明註冊到 Satellite。在這裡可以找到備份的 rhsm.conf ,把這檔案復原回去。

第二步,是移除套件,在註冊到 Satellite 時,會安裝一個套件,這個套件包含了註冊到 Satellite 的資訊以及憑證。套件的名稱裡有 katello-ca ,找到之後,用 rpm -e 或 yum remove 移除。

第三步,是移除 /etc/pki/consumer 跟 /etc/pki/entitlement ,這裡有 subscription-manager 註冊後取得的資訊。

rm -rf /etc/pki/consumer
rm -rf /etc/pki/entitlement
subscription-manager clean

處理完之後,就可以用 subscription-manager register 來註冊到 Red Hat 了。

參考資料

RHEL8 重置 root 密碼

因為查了第二次還第三次,所以紀錄下來。

步驟如下:

  1. 開機時,在 grub 開機選單畫面按上或下,避免自動進入預設項目開機,然後在第一個項目按下 e 來編輯。
  2. 在 linux 那一行的最後加入 rd.break 之後,按下 ctrl + x 繼續開機
  3. 接著會進入 console ,這時輸入下面指令
mount -o remount,rw /sysroot
chroot /sysroot
passwd
touch /.autorelabel
exit
exit

做到這邊,印象中會重開機或繼續開機程序,總之最後就完成了。

參考資料

如果你有 Red Hat developer account 的話,應該可以看到這篇:RESETING THE ROOT PASSWORD