余ったMacBook Pro 2015でUbuntuを動かすまでの地獄

はじめに

先日 Windows 11 のノートPCを手に入れた。会社でも WSL で Ubuntu 使ってるので喜び勇んで WSL をセットアップして満足。うちでも開発できる環境ができた。
それはそれでいいんだけど、それまでメインで使っていた MacBook Pro 2015 は完全に引退となった。

macOS はとっくに更新できなくなっているし、このまま眠らせておくのも勿体ない。

OpenClaw

最近、猫も杓子も OpenClaw という世の中の流れになっているらしい。中国ではセットアップするサービスに行列が出来たとか何とか。
自宅サーバーに置いてローカルで動き、WhatsApp や Telegram など使い慣れたチャットアプリから操作できる。メール管理やカレンダー操作、ファイル操作まで自動化できるというやつですね。 面白そうだし、試してみようかなーと思ったけど、いざ調べてみたら結構セキュリティやばそう。

  • RCE 脆弱性(CVE-2026-25253、CVSS 8.8)が報告されており、認証なしで公開されているインスタンスが世界に 42,000 件以上
  • プラグインマーケットプレイス(ClawHub)の約 12% が悪意あるスキル
  • メール・カレンダー・購入・ファイルと権限が広すぎるので、侵害されたときの被害が大きい

いや、これ普通にやったらやばいだろ。

nanoclaw

で、他のないかなと探していたら、nanoclaw を見つけた。コンテナで隔離して動かせる設計になっているし、これならホストへの影響も最小限になりそう。

ということで、MacBook Pro 2015 に Ubuntu を入れて、その上で nanoclaw をコンテナで動かすことにしたんだけど、そこからはまりまくった。

Claude の Pro プラン入ってなかったら確実に諦めてたわ。それが以下の話。

Ubuntu インストール

Ubuntu のインストール自体は公式のやり方にしたがって、Amazon ブランドの USB (なかなか評判いいんですね)にインストールイメージを焼いて起動、手順通りに進めるだけでOK。

apt update / upgrade も通る。linuxbrew, gh, fzf, ghq, oh-my-posh, google-chrome, claudecode などなどを入れ始めて、さあ nanoclaw いったるかーというところで様子がおかしくなった。

バイナリが壊れる

sudo apt upgrade がエラーで落ちる。
再起動すると gh, chrome などのバイナリが壊れている。
なんかおかしいなと思いつつ、復旧スクリプトを作って再インストールしてみるが、またしばらくすると壊れる。
おいこらちゃんと仕事しろや。
と思いつつ、Claude さんに相談。

相談しながらも事象は継続しており段々イライラしながらも更に相談。
最終的には、指示に従い dmesg を眺めていると、気になるログがあった。

ata1.00: exception Emask 0x20 SAct 0x0 SErr 0x0 action 0x6 frozen
ata1.00: irq_stat 0x20000000, host bus error
EXT4-fs (sda2): failed to convert unwritten extents to written extents -- potential data loss!

ストレージのエラーだ。しかも potential data loss と書いてある。なんすかこれ?

原因究明

Claude さんとともに調べていくと、これは MacBook Pro 2015 の Apple SSD 固有の問題だとわかった。 以下、Claude さんの見解。

Apple の PCIe-to-AHCI ブリッジは、4MB(8192セクタ)を超える単一の DMA 転送を処理できない。ところが Linux カーネルのデフォルト設定(max_sectors_kb=4096)はこの制限をはるかに超えた転送サイズを許容しているため、大きなファイルを書き込むたびに host bus error が発生し、ファイルシステムが壊れる。 特に被害を受けやすいのが大きなバイナリだ。claude(225MB)、gh(38MB)、oh-my-posh(19MB)といったファイルがインストールのたびに壊れていた。apt 管理のパッケージは dpkg が fsync を適切に処理するため相対的に安全なのだが、それ以外のバイナリはほぼ確実に壊れる。

ほーんって、そんなの分かるわけねーだろ!

解決策

Claude さんが最終的に提案してきた対策は以下の 1,2 でした。

1. udev ルールで DMA 転送サイズを制限

max_sectors_kb を 1024(1MB)に下げる udev ルールを作成する。これで 4MB 制限に引っかかる転送が発生しなくなる。

cat <<'EOF' | sudo tee /etc/udev/rules.d/60-ssd-scheduler.rules
ACTION=="add|change", KERNEL=="sda", ATTR{queue/scheduler}="bfq", ATTR{queue/max_sectors_kb}="1024"
EOF
sudo udevadm control --reload-rules && sudo udevadm trigger
# 確認
cat /sys/block/sda/queue/max_sectors_kb  # 1024 と表示されればOK

2. GRUB パラメータで ATA エラーを抑制

sudo sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="\(.*\)"/GRUB_CMDLINE_LINUX_DEFAULT="\1 libata.force=noncq libata.noacpi=1"/' /etc/default/grub
sudo update-grub

この2つを適用したら、それまで頻発していたバイナリ破損が嘘のようにぴたりと止まった。
おいまじか。だったら最初から正解を…
いや、プロンプト書いたの俺だからね、しょうがないよね。

気を取り直して、更に安全策に倒すなら以下もやっておいた方がいいよとの助言があり以下 3,4 の対策を実行。

3. 書き込みバーストを抑えるために sysctl の設定追加

cat <<'EOF' | sudo tee /etc/sysctl.d/99-apple-ssd.conf
vm.dirty_ratio=5
vm.dirty_background_ratio=2
EOF
sudo sysctl --system

4. 電源断時のダーティページ消失対策

あとはシャットダウン前に明示的に sync を走らせる systemd サービスも入れて、電源断時のダーティページ消失にも備えた。

cat <<'EOF' | sudo tee /etc/systemd/system/pre-shutdown-sync.service
[Unit]
Description=Sync filesystems before shutdown
DefaultDependencies=no
Before=shutdown.target reboot.target halt.target

[Service]
Type=oneshot
ExecStart=/bin/sync

[Install]
WantedBy=halt.target reboot.target shutdown.target
EOF
sudo systemctl enable pre-shutdown-sync.service

設定をすべて反映するために再起動する。

sudo reboot

これにて、すべて解決しました。
nanoclaw についてはまた別の記事で。

おわりに

Ubuntu のセットアップで一番苦労したのがこれなのでこの記事を書きました。
書いてないこととしては以下だけど、これに比べれば全然軽いもんでした。

  • 日本語入力の設定(fcitx5 + Mozc)
  • フォントインストールとシステムのモノスペースフォントに設定
  • バックグラウンドで定期的にI/Oを発生させるタイマーを無効化

で、かなり苦労したのでここまでの設定をすべて dotfiles にまとめて、次回以降は install.sh を実行するだけで済むようにしました。
とはいえ、Apple SSD 対策がかなりの量を占めているので、Claude さんとの会話でこんなこともありました。

Claudeさんとの愉快な会話

同じ MacBook Pro 2015 で Ubuntu を試みて躓いている人の参考になれば幸いです。