###### tags: `Gentoo` # Gentoo Maintenance [TOC] ## 更新 kernel ### 從原先自訂的 kernel 升級到新版本 * 參閱 [Gentoo 官方的 Kernel/Upgrade 文件](https://wiki.gentoo.org/wiki/Kernel/Upgrade),大致上是多了一步 `make olddefconfig`。 * 其實降級也能使用相同步驟完成,但並不建議。 ### 從 distribution kernel 換成自訂 kernel 1. 確定不要繼續使用 distribution kernel 的話,用 `emerge --unmerge gentoo-kernel` 或 `emerge --unmerge gentoo-kernel-bin` 移除原本的 kernel。一般建議移除,以免在更新系統時意外將 kernel 更新為 distribution kernel。 :::info * 要清理得更乾淨的話,可以手動移除 /boot 裡主檔名以 `gentoo-dist` 結尾的檔案,還有 `/lib/modules` 裡名稱以 `gentoo-dist` 結尾的目錄。 ::: 2. 執行 `emerge sys-kernel/gentoo-sources` 將 linux 原始碼安裝到 `/usr/src` 裡。 3. 確認 `/usr/src/linux` 符號連結指向上一步安裝的 linux 原始碼目錄後,執行 `zcat /proc/config.gz > /usr/src/linux/.config` 複製當前運行中系統的 kernel 設定檔,並按照[自訂 kernel 的流程進行](https://hackmd.io/@tinlans/gentoo-installation#Option-2-%E6%89%8B%E5%8B%95%E8%A8%AD%E5%AE%9A%E5%8F%8A%E5%AE%89%E8%A3%9D-kernel)操作,大致上是多了一步 `make olddefconfig`。如果跟 `uname -a` 顯示的當前 kernel 版本不同,則要按照[升級流程](https://wiki.gentoo.org/wiki/Kernel/Upgrade)操作。 :::info * 從 distribution kernel 複製過來的設定檔在這裡也會加上後綴,可以把它刪除: ``` General setup ---> (-gentoo-dist) Local version - append to kernel release ``` ::: 4. 執行 `grub-mkconfig -o /boot/grub/grub.cfg` 重新產生 `grub.cfg` 後即可重新開機。 ## 系統更新後無法開機的解決方式 ### 共通處理步驟 1. 嘗試在 boot manager 的選單裡選擇舊版 kernel 開機。 2. 如果前一步驟無效,則需要仿照安裝系統的流程,先[使用光碟或 USB 隨身碟開機](https://hackmd.io/@tinlans/gentoo-installation#%E9%96%8B%E6%A9%9F%E5%8F%8A%E5%95%9F%E7%94%A8-sshd),[掛上必要的磁碟分割區](https://hackmd.io/@tinlans/gentoo-installation#%E7%A3%81%E7%A2%9F%E5%88%86%E5%89%B2%E5%8F%8A%E6%A0%BC%E5%BC%8F%E5%8C%96) (不需重新分割硬碟及格式化分割區),再[進入 chroot 的環境](https://hackmd.io/@tinlans/gentoo-installation#%E5%AE%89%E8%A3%9D-stage3-%E4%B8%A6%E9%80%B2%E5%85%A5-chroot-%E7%92%B0%E5%A2%83)以執行修復工作。 ### 解決 boot manager 沒有出現的問題 如果原本有安裝如 `grub` 之類的 boot manager,但是 POST 畫面結束後卻看不見它,可能的原因有: * 相關的 partition flags 沒有被正確設定,參閱[磁碟分割及格式化的說明](https://hackmd.io/@tinlans/gentoo-installation#%E7%A3%81%E7%A2%9F%E5%88%86%E5%89%B2%E5%8F%8A%E6%A0%BC%E5%BC%8F%E5%8C%96)使用 `parted` 加以檢查和修正。 * bootloader 沒有被正確安裝或因不明原因遭到覆蓋,此時只要[重新設定及安裝 bootloader]( https://hackmd.io/@tinlans/gentoo-installation#%E8%A8%AD%E5%AE%9A-bootloader) 就能解決。 ### 解決無法掛載 rootfs 的問題 遇到這個問題時,通常會看到 linux 開機流程已經進行了一小段後突然停止。如果有使用 initramfs,通常會在提示無法掛載 rootfs 後停留在 initramfs 內的 shell 下,否則會在提示後發生 kernel panic。這個問題的可能原因有: * `grub.cfg` 的內容不正確或忘記使用 `grub-mkconfig` 產生與當前系統相符的設定內容,執行 `grub-mkconfig -o /boot/grub/grub.cfg` 重新產生一遍。 * 沒有將相關驅動程式編譯到 kernel 裡或編譯成 kernel modules,利用 `lshw | grep 'driver='` 確認 driver 名稱後,按照[手動設定及安裝 kernel](https://hackmd.io/@tinlans/gentoo-installation#Option-2-%E6%89%8B%E5%8B%95%E8%A8%AD%E5%AE%9A%E5%8F%8A%E5%AE%89%E8%A3%9D-kernel) 的說明重新編譯 kernel 及安裝 kernel modules。如果沒有使用 `initramfs`,必須將驅動程式直接編譯到 kernel 裡。 * 相關裝置的驅動程式沒有被包進 `initramfs` 裡,按照[手動設定及安裝 kernel](https://hackmd.io/@tinlans/gentoo-installation#Option-2-%E6%89%8B%E5%8B%95%E8%A8%AD%E5%AE%9A%E5%8F%8A%E5%AE%89%E8%A3%9D-kernel) 中關於 `dracut` 的說明產生對應的 `initramfs`。在特定情況下,需要修改 `/etc/dracut.conf` [自行指定要加入的驅動程式]((https://wiki.gentoo.org/wiki/Dracut#Kernel_modules))再使用 `dracut` 產生 `initramfs`。 ### 還原到上一版 kernel 通常會選擇這種解決方式是因為能從 boot manager 裡選擇舊版 kernel 並成功開機,因此可能的做法有: * 手動編輯 `/boot/grub/grub.cfg`,刪除不想要的部分。 * 刪除 `/boot` 裡不需要的 kernel 版本及相關檔案,再執行 `grub-mkconfig -o /boot/grub/grub.cfg` 重新產生設定檔,也建議順手刪除 `/lib/modules` 裡對應的目錄;這些清除特定版本 kernel 的操作也可以使用 [`eclean-kernel`](https://wiki.gentoo.org/wiki/Kernel/Removal#Using_eclean-kernel) 這個套件自動完成。 ## 開機流程相關問題 ### log 中出現 kernel: Error: Driver 'pcspkr' is already registered, aborting... 編輯或建立 `/etc/modprobe.d/blacklist.conf` 這個檔案,然後加入一行 `blacklist pcspkr` 即可解決。 ## 編譯 kernel 常見問題 ### 在 /usr/src/linux 打 make 出現錯誤訊息 gold linker 'ld' not supported 在安裝 binutils 時使用了 default-gold 這個 use flag 會遇到這個問題,因為 build kernel 時無法使用 gold linker。將環境變數 `LD=ld.bfd` pass 給 `make` 指令即可暫時將 linker 指定為傳統的 BFD linker,譬如 `make LD=ld.bfd -j8`。 ## GRUB 常見問題 ### 執行 grub-install 時遇到 error: efibootmgr failed to register the boot entry: Input/output error. 使用了不是安裝系統用的 ISO 開機來安裝時會遇到,執行 `mount -o remount,rw /sys/firmware/efi/efivars` 重新掛載成 read-write 模式即可解決。 ## Docker 常見問題 ### OpenVPN 啟動的環境下無法執行 docker create network,且在 /etc/docker/daemon.json 指定 default-address-pools 時會無法啟動 docker engine OpenVPN server 端以 def1 模式推送 gateway redirection 資訊時,OpenVPN client 會在 routing table 裡加入 `0.0.0.0/1` 和 `128.0.0.0/1` 兩條路由,這兩條路由會讓 docker engine 找不到任何可用網段做為 address pool。必須刪除兩條路由,再將 OpenVPN server 指定為 default gateway 來解決。 #### 解決步驟 1. 新增一個 `/etc/openvpn/fix-routes.sh` 檔,內容為 ``` ip route add default via 10.0.27.1 ip route del 0.0.0.0/1 via 10.0.27.1 ip route del 128.0.0.0/1 via 10.0.27.1 ``` 其中 10.0.27.1 是 OpenVPN server 給的 gateway IP。 2. 執行 `chmod +x /etc/openvpn/fix-routes.sh` 新增執行權限。 3. 打開 OpenVPN client config 檔,加入下面兩行後重新啟動 OpenVPN client: ``` script-security 2 route-up /etc/openvpn/fix-routes.sh ``` ### iptables-save 會儲存大量 docker 自動產生的 rules #### 解決步驟 1. 新增一個 `/lib/systemd/system/restore-iptables.service` 檔案如下: ``` [Unit] Description=Iptables rules import After=docker.service [Service] Type=oneshot ExecStart=/root/bin/iptables-custom.sh Restart=no [Install] WantedBy=multi-user.target ``` 2. 在 `/root/bin/iptables-custom.sh` 內編寫完整 iptables 指令。 3. ``` chmod +x /root/bin/iptables-custom.sh systemctl enable restore-iptables ``` ### 讓特定 container 走指定的 IP 出去 #### 解決步驟 1. 在 docker-compose.yml 裡把這個 container 放在特定的 subnet 下。 2. `/sbin/iptables -t nat -I POSTROUTING -p all -s <subnet> -j SNAT --to-source <WAN IP>` ## Systemd 常見問題 ### 在 my.cnf 指定 datadir 為 /home/mysql 時,使用 systemd 來啟動 mysqld 時會出現 permission denied 錯誤 mysqld 預設的 unit file 會防止 /home 被寫入,需要修改 unit file 的內容才能把 datadir 放在 /home 下。 #### 解決步驟 1. 用編輯器打開 `/lib/systemd/system/mysqld.service`,將 `ProtectHome` 改成 `false`。 2. 執行 `systemctl daemon-reload` 後再執行 `systemctl start mysqld`。 ### 執行 systemctl start mysqld 時會卡住,過一陣子 mysqld 會被自動關閉 在 systemd 環境下,MySQL 的 unit file 會指定以 `/usr/libexec/mysqld-wait-ready` 這個 script 監視 MySQL server 是否 ready,原理是檢查 socket file 是否存在,因此 my.cnf 中需要寫一行 `socket = <path>` 指定 socket file 路徑。如果指定在 `/var` 以外的路徑,應檢視 `/lib/systemd/system/mysqld.service` 內的路徑保護參數,譬如 `ProtectSystem` 和 `PrivateTmp`,以確保 socket file 可以被正常寫入且 `mysqld-wait-ready` 可以看見它。 ### 執行 systemctl start slapd 時會卡住,過一陣子 slapd 會被自動關閉 此時 log 應會顯示類似這樣的訊息:`slapd.service: Got notification message from PID 1155492, but reception only permitted for main PID 1155491` #### 解決步驟 1. 用編輯器打開 `/lib/systemd/system/slapd.service`,在 [Service] 裡加上一行 `NotifyAccess=all`。 2. 執行 `systemctl daemon-reload` 後再執行 `systemctl start slapd`。 ### dmesg 中頻繁出現 dhcp4 (enp42s0f3u5u3c2): request timed out,但 enp42s0f3u5u3c2 是沒使用到的網路裝置 使用 NetworkManager 時會遇到這類問題,因為 NetworkManager 會在背景反覆進行一些嘗試。 #### 解決步驟 1. 編輯 `/etc/NetworkManager/NetworkManager.conf` 這個檔案,如果不存在的話新增一個。內容如下: ``` [main] plugins=keyfile [keyfile] unmanaged-devices=interface-name:enp42s0f3u5u3c2 ``` 2. 執行 `systemctl restart NetworkManager` 重新起動 NetworkManager。 ### 每次重開機後 nginx 會啟動失敗,看見錯誤訊息 bind() to xxx.xxx.xxx.xxx:80 failed (99: Cannot assign requested address) 在從 DHCP server 取得 IP 之前,各 daemon 如果嘗試根據其設定檔 bind 某個固定 IP,都會遭遇類似問題,不只有 nginx 會遇到。網路上查到的解法有很多,如 systemctl enable systemd-networkd-wait-online (使用 systemd-networkd 的情況),還有 sysemctl enable NetworkManager-wait-online.service (使用 NetworkManager 的情況),或者在 unit file 裡寫上 `After=network-online.target` 和 `Wants=network-online.target`,經實測都沒有作用。 #### 解決步驟 1. 編輯 `/etc/sysctl.conf`,加入一行 `net.ipv4.ip_nonlocal_bind = 1`。 ## 套件系統常見問題 ### 使用 emerge 安裝套件途中遇到編譯錯誤 可能的解決方法如下: * 選擇安裝其它版本,用 `equery keywords <name>` 或 `ls /usr/portage/<category>/<name>` 找到可安裝版本後,使用 `emerge =<name>-<version>` 或 `emerge =<category>/<name>-<version>` 來安裝,譬如 `emerge =polkit-0.116-r1` 或 `emerge =sys-auth/polkit-0.116-r1`。 :::info * 根據 `/etc/portage/make.conf` 中 `PORTDIR` 的設定不同,portage tree 不一定被存放在 `/usr/portage` 裡面。 * 也可以利用 [`package.mask`](https://wiki.gentoo.org/wiki//etc/portage/package.mask) 手動封鎖某個版本或某個版本以上的套件,再重新執行 `emerge` 就會自動安裝符合條件的舊版本。 ::: * 去官方的 [bugzilla](https://bugs.gentoo.org/) 查詢是否有人回報過同樣的問題,以及是否有人提出過解決問題的有效方法卻還沒被採用。如果都沒有,可以考慮註冊帳號自己發一個上去,但問題被解決的速度通常不樂觀。 * 如果打算自行解決編譯錯誤,需要手動操作 [ebuild](https://dev.gentoo.org/~zmedico/portage/doc/man/ebuild.1.html) 逐步完成原本 emerge 會自動跑完的[流程](https://devmanual.gentoo.org/ebuild-writing/functions/),即 `fetch`、`unpack`、`prepare`、`configure`、`compile`、`install`、`qmerge` 這幾步,編譯錯誤一般會發生在 `compile` 這一步,因此可以直接指定 `compile` 讓流程先一路跑到這裡,確認自己做的修改可以通過編譯後,可以直接跳到 `qmerge` 完成安裝。 :::info 如果不幸需要修改到 ebuild 檔或 patch 檔才能解決問題,則需要使用 `ebuild digest` 更新 Manifest 檔裡的 checksums,否則會因為校驗失敗而拒絕操作。 ::: ### 更新 portage tree 後安裝任何套件都會看到 !!! The following installed packages are masked: 使用 `emerge --sync` 更新 portage tree 後安裝任何套件時看到類似這樣的訊息:  #### 解決步驟 1. 使用 `emerge -vp opentmpfiles` 確認該套件是否還能安裝,如果不行,可以使用 `emerge --unmerge opentmpfiles` 解除安裝,要保留該套件的話也可以忽略這個訊息。 2. 如果上一步確認還能安裝,通常只是需要升級或降級該套件版本,使用 `emerge opentmpfiles` 再裝一遍就行了。 ### 安裝完套件後看見 CONFIG_XXX: is not set when is should be. 的警告  這是因為 kernel 的設定裡缺少了特定選項,可能使該套件無法正常運作或使用其完整功能,需要[自行編譯 kernel](https://hackmd.io/@tinlans/gentoo-installation#Option-2-%E6%89%8B%E5%8B%95%E8%A8%AD%E5%AE%9A%E5%8F%8A%E5%AE%89%E8%A3%9D-kernel)。 #### 解決步驟 1. 在 kernel 設定選單裡使用 `/` 搜尋訊息中的大寫字串,不含 `CONFIG_` 前綴,以上圖為例是 `NF_CT_NETLINK_HELPER`。 2. 按照搜尋結果裡的 `Location:` 路徑找到選項,將該項目切換成 `*` 或 `M` 符號。 3. 如果按照 `Location:` 的路徑找不到該選項,查看 `Depends on:` 列出的各選項後方是否有 `[=n]` 的標記,如果有的話,回到第一步搜尋該項目,並將它切換成 `*` 或 `M` 符號。 4. 儲存 kernel 設定離開選單,按照[自行編譯 kernel 的說明](https://hackmd.io/@tinlans/gentoo-installation#Option-2-%E6%89%8B%E5%8B%95%E8%A8%AD%E5%AE%9A%E5%8F%8A%E5%AE%89%E8%A3%9D-kernel)將 kernel 編譯並安裝。 5. 執行 `grub-mkconfig -o /boot/grub/grub.cfg` 重新產生 `grub.cfg` 後重新開機。 ### 很久沒執行更新 portage tree,執行 emerge --sync 後不管用 emerge 裝什麼都會出現錯誤  太久沒更新 world 的系統,一般不建議魯莽地執行 emerge --sync 更新 portage tree,因為可能同時跨越 python 預設版本變動以及 EAPI 版本變動的時間點。這時需要設法將 portage tree 退回特定日期,以使用系統目前已安裝的 portage 套件來安裝新版本的 python 並更新 portage 套件。 #### 解決步驟 1. 執行 `eselect news list`,查看 python 預設版本的變動日期,如果目前系統預設的版本是 python 3.6,可能會看到 2020-04-22 有預設版本變成 3.7 以及 2021-05-05 預設版本變成 3.9 的 news,如果中間有 EAPI 版本變動的 news 也可以記一下日期。 2. 執行 `cd /usr; mv portage portage.latest` 將原本的 portage tree 更名。 3. 參閱 [HOWTO Update Old Gentoo](https://wiki.gentoo.org/wiki/User:NeddySeagoon/HOWTO_Update_Old_Gentoo),執行 `git clone https://github.com/gentoo/gentoo.git portage`。 4. 執行 `cd /usr/portage` 進入 git clone 下來的 portage tree,然後執行下面的指令 checkout 到指定日期: ``` git checkout `git rev-list -n 1 --first-parent --before="2020-04-21" master` ``` 通常在 python 預設版本發生變動之前,portage tree 早就已經有新的預設版本可以安裝,因此切換到變動發生之前的時間點,再使用 `emerge` 或 `emerge --nodeps` 安裝指定版本的 python 並更新 portage 到當下的最新版本。以這邊的例子來說,2020-04-22 改變了系統預設的 python 版本到 3.7,那麼回到 2020-04-21 這一天通常能順利使用系統已安裝的 python 3.6 及當下的 portage 套件來安裝 python 3.7,這時間點最新版本的 portage 套件通常也做好了相應的準備。 5. 反覆進行上個步驟切換日期,安裝各時期預設的 python 版本以及當下最新版本的 portage 套件,emerge 指令就能恢復成正常狀態。過程中如果執行 emerge 遇到 python-exec 相關的問題,直接使用 `/usr/lib/python-exec/python<version>` 目錄下的 emerge 執行檔來更新套件即可解決。
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up