それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

pdoのprepareで名前に数字を入れると、bindValue出来ないエラー

php の pdo でエラーがでるので数日ずっと頭を抱えてた

出てくるエラー

: Invalid parameter number: number of bound variables does not match number of tokens

エラーは、php pdo の prepare statement で、execした時にエラーになる。

<?php
/// できる
$stmt->bindValue(":n1", $val );
$stmt->bindValue("n1", $val );
$stmt->bindValue("123n", $val );
///  出来ない
$sth->bindValue(':123', $val );
$sth->bindValue('123', $val );

エラーに気づかないわけ。

bindValue( $key, $value ) は $key が文字列だと、文字列インデックスでバインドし、ハッシュ :name から文字列キーを探す。

ところが、「数字に解釈できる文字列」だと、数字だと思って疑問符( = ? )に入れようと、該当の疑問符の数字インデックスを探す→見つからない→bindParamがありません。エラーとなる。

<?php
$sth->bindValue('123', $calories);   //
$sth->bindValue(':123', $calories);  // 123 番目を探しに行く

内部で$params[123] を探しに行く。そんなものあるわけがない。探してほしいのは $params[":123"] なんだよね 指定したけどintになる文字列だと、? を探しちゃってbindValue指定時のキーに入れられない。だからエラーになる。

しかもexecするまでわからない。(←ここが辛い)

コード作者はちゃんと値を入れてるから、値がないなんて考えないよね。でもbindValueエラーが出るんだよね。頭抱えるよね。

対策

文字列であることを明確にする

<?php
$key="123"
$sth->bindValue($key.'__', $v ); 

型変換怖い

原因がわかればなんてことないが、php7以降は「型」に強いと思ってると痛い目に遭う。

組み込み関数の型は相変わらず、自動変換される。phpは自動型推測で動いたのに、いまはソースコードに型を明示するようになったので、本当に気づかない。

とくに、SQLを自動生成してるとこのバグを踏みまくる。 随分前にこの仕様を踏んでめっちゃ頭を抱えた記憶があるのだが、7−8年越しにまた踏んで頭を抱えたので、メモ。

ここ数年はLaravelしか使わないし、PDOを素で使うことなんてないからこういうのすっかり忘れてハマりました。

systemdでネットワーク待ちを何とかする。Failed to start Wait for Network to be Configured.

ubuntu が起動時にエラーを吐いてネットワーク待ちで時間がかかる。

Failed to start Wait for Network to be Configured.

ネットワークを見てみる。

基本的に、networkdに管理させてないが、念のために確認する。

takuya@:~$ networkctl
IDX LINK            TYPE     OPERATIONAL SETUP
  1 lo              loopback carrier     unmanaged
  2 eth0            ether    carrier     unmanaged
  3 br0             bridge   routable    unmanaged
  4 lxcbr0          bridge   no-carrier  unmanaged
  5 docker0         bridge   no-carrier  unmanaged
 52 br-8938dceff93b bridge   routable    unmanaged
 54 veth61a80a4     ether    carrier     unmanaged

network-onlineを編集

systemd で上記のネットワークを無視してあげる

takuya@:~$ /lib/systemd/systemd-networkd-wait-online --help
systemd-networkd-wait-online [OPTIONS...]

Block until network is configured.

  -h --help                 Show this help
     --version              Print version string
  -q --quiet                Do not show status information
  -i --interface=INTERFACE[:MIN_OPERSTATE[:MAX_OPERSTATE]]
                            Block until at least these interfaces have appeared
     --ignore=INTERFACE     Don't take these interfaces into account
  -o --operational-state=MIN_OPERSTATE[:MAX_OPERSTATE]
                            Required operational state
     --any                  Wait until at least one of the interfaces is online
     --timeout=SECS         Maximum time to wait for network connectivity

See the systemd-networkd-wait-online.service(8) man page for details.
takuya@:~$

設定を編集

sudo systemctl edit systemd-networkd-wait-online

無視を追加

[Service]
ExecStart=/lib/systemd/systemd-networkd-wait-online \
  --ignore=docker0 \
  --ignore=lxcbr0 \
  --ignore=eth0 \
  --timeout=20

後は様子見。

参考資料

https://qiita.com/tsuru2_mitsuru/items/f3041cdb11dff18eb5c3

btrfs 内部にスワップ・ファイルを設置する

btrfs はカーネル5 からswap をサポートした

## 空のファイル
sudo truncate -s 0 /swap.img
## CoW / 圧縮を無効に
sudo chattr +C /swap.img
sudo btrfs property set /swap.img compression none
## chmod 
sudo chmod 600 /swap.img
## swap サイズため容量確保
sudo fallocate -l 1G /swap.img
### 容量確認
sudo ls -ald /swap.img
### SWAPを有効に
sudo mkswap   /swap.img
sudo swapon /swap.img
### swap を無効に
sudo swapoff /swap.img

状態確認

swapon
NAME      TYPE  SIZE USED PRIO
/swap.img file 1024M   0B   -2

一通りできたら、fstabへ

sudo vim /etc/fstab 

マウントを書く

/swap.img swap swap default 0 0

https://www.unixtutorial.org/create-swap-from-file-on-btrfs-filesystem/ https://wiki.archlinux.jp/index.php/Btrfs#.E3.82.B9.E3.83.AF.E3.83.83.E3.83.97.E3.83.95.E3.82.A1.E3.82.A4.E3.83.AB

パーティションをディスクに仕立てる(壊れたパーティションの先頭を作り直す)

達成したい目的。

LVM から ext4を取り出して、単独でブートするように作り直したい。

言い換えると

パーティションなんて、HDDの先頭にセクタ位置を書いてるだけだろ?とおもって調べたらやっぱりそうだった。

準備。

新規インストールで実験環境を整える。

サクッとインストールして、ext4 on LVM を用意する。 ext4 on LVM でインストールしたLinux仮想マシンで作成。

sudo virt-install \
  --connect=qemu:///system  \
  --name lc01   \
  --ram 8192   \
  --disk path=/var/lib/libvirt/images/lc01.qcow2,size=5  \
  --vcpus 8  \
  --virt-type kvm   \
  --os-variant debian10   \
  --graphics none   \
  --location http://ftp.kddilabs.jp/pub/Linux/distributions/Debian/debian/dists/buster/main/installer-amd64/   \
  --extra-args="console=ttyS0" \
  --check all=off

ext4 を取り出す。

qcow2 から raw ファイルを取り出す。

sudo qemu-img convert -p -f qcow2 le01.qcow2 -O raw le01.img

ループバックにつなぐ

sudo losetup -P -f le01.img --show

LVMが接続されるのを確認する。

pvs
vgs
lvs 

接続されたLVMから ext4 を抜き出す。

sudo ddrescue /dev/mapper/le01--vg-root vgroot.img

後片付けする。

vgchange -an le01-vg
sudo losetup -d /dev/loopX

取り出したext4

取り出したファイルがEXT4なことを確認

$ file vgroot.img
vgroot.img: Linux rev 1.0 ext4 filesystem data, UUID=33cc43c6-b3f7-4001-9460-d6d28f11d91f (extents) (64bit) (large files) (huge files)

ext4 パーティションをディスクイメージに変換する。

取り出したパーティションをディスクイメージに変換する。

ext4 の先頭に1Mを追加する。

ext4のイメージファイルの先頭に1MBを足せばいいのですが。

ファイルの先頭に1Mを追加するという処理は面倒です。

そこで、1Mのファイルを作って末尾にExt4を追記するという逆のアプローチでやります。

パーティションヘッダを作る

dd または truncate で1MiB のファイルを作る。

dd if=/dev/zero of=new-hdd.img count=1 bs=1MiB

パーティションとは、ファイルシステムの先頭に、1MBがあるだけです。 bs=1MiB と書くのに注意。

先頭に16kがあり、どのセクタにファイルシステムがあるか書いてる。 GPTは16k-1M までの領域にEFIとかUUIDとか色々書いてるらしい。

1MB+ext4 => ディスクイメージ

pv とリダイレクトを用いて追記します。

pv vgroot.img  >> new-hdd.img

ディスクイメージをコピーすると時間がかかるのでcp よりもpv の方が扱いやすい。

これで、パーティションがぶっ壊れたHDDイメージの出来上がり。

パーティションを作り直す。

先頭が空っぽなので、パーティションとして認識されません。

パーティションが消えた状態になっています。

takuya@:images$ fdisk -l new-hdd.img
Disk new-hdd.img: 3.56 GiB, 3826253824 bytes, 7473152 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

fdisk を使ってパーティションを作り直します。

takuya@:images$ sudo fdisk  new-hdd.img

Welcome to fdisk (util-linux 2.36.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0xb2368926.

Command (m for help): p # ← print
Disk new-hdd.img: 3.56 GiB, 3826253824 bytes, 7473152 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xb2368926

Command (m for help): n # ← new
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p # ← primary
Partition number (1-4, default 1):
First sector (2048-7473151, default 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-7473151, default 7473151):

Created a new partition 1 of type 'Linux' and of size 3.6 GiB.
Partition #1 contains a ext4 signature.

Do you want to remove the signature? [Y]es/[N]o: no # ←既存を使うのでno

The signature will be removed by a write command.

Command (m for help): p # ← print
Disk new-hdd.img: 3.56 GiB, 3826253824 bytes, 7473152 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xb2368926

Device       Boot Start     End Sectors  Size Id Type
new-hdd.img1       2048 7473151 7471104  3.6G 83 Linux

Filesystem/RAID signature on partition 1 will be wiped.

Command (m for help): a # ← Make MBR bootable flag on
Selected partition 1
The bootable flag on partition 1 is enabled now.

Command (m for help): w # ← Write and Quit
The partition table has been altered.
Syncing disks.

これでパーティションとして認識されるはずです。

takuya@:images$ fdisk -l new-hdd.img
Disk new-hdd.img: 3.56 GiB, 3826253824 bytes, 7473152 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xb2368926

Device       Boot Start     End Sectors  Size Id Type
new-hdd.img1 *     2048 7473151 7471104  3.6G 83 Linux

ファイルを確認

ext4 が壊れてないか確認しておきます。

イメージファイルををループバックで接続してみます。

losetup -P -f new-hdd.img --show

接続できたのでパーティションが認識されるはずです。確認しておきます。

takuya@:images$ lsblk
NAME            MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINT
loop11            7:11   0   3.6G  0 loop
└─loop11p1      259:4    0   3.6G  0 part

マウントしてみます。あらら失敗です

sudo mount /dev/loop11p1 test
mount: /var/lib/libvirt/images/test: wrong fs type, bad option, bad superblock on /dev/loop11p1, missing codepage or helper program, or other error.

dmesg を確認してみます。どこか失敗した模様(ddのbsミス でした)

$ sudo dmesg
[694912.138454] EXT4-fs (loop11p1): bad geometry: block count 933888 exceeds size of device (933883 blocks)
[694917.971654] EXT4-fs (loop11p1): bad geometry: block count 933888 exceeds size of device (933883 blocks)
[695308.681524] EXT4-fs (loop11p1): bad geometry: block count 933888 exceeds size of device (933883 blocks)
[695314.313132] EXT4-fs (loop11p1): bad geometry: block count 933888 exceeds size of device (933883 blocks)
[695351.389589] EXT4-fs (loop11p1): mounted filesystem with ordered data mode. Opts: (null)
[695371.450113] EXT4-fs (loop11p1): mounted filesystem with ordered data mode. Opts: (null)

やり直しました。問題なさそうです。

$ sudo fsck /dev/loop11p1
fsck from util-linux 2.36.1
e2fsck 1.46.2 (28-Feb-2021)
/dev/loop11p1: clean, 28743/233856 files, 286271/933888 blocks
$ sudo e2fsck -f /dev/loop11p1
e2fsck 1.46.2 (28-Feb-2021)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/loop11p1: 28743/233856 files (0.2% non-contiguous), 286271/933888 blocks
$ sudo resize2fs /dev/loop11p1
resize2fs 1.46.2 (28-Feb-2021)
The filesystem is already 933888 (4k) blocks long.  Nothing to do!

GPTに変更する

今どきのディスクはGPTなのでGPTでもできるが、、EFIパーティションとか、MBRハイブリッドとか考えることが多いので今回はパス。

ブートの修正

ブート修正は取り出したイメージをマウントして修正します。

マウント

losetup -f -P --show new.img
mount /dev/loop11p1 /mnt

chrootする

cd /mnt
sudo mount -t proc proc proc/
sudo mount -t sysfs sys sys/
sudo mount -o bind /dev dev/
#
sudo chroot . /bin/bash

ブート修正。

grub-install /dev/loop11
## 作業PCの boot を拾ってマルチブートになるのを避ける
chmod a-x /etc/grub.d/30_os-prober 
update-grub
update-initramfs -u

作業が終わったら後片付けする

sudo umount -lf ./sys
sudo umount -lf ./proc
sudo umount -lf ./dev
cd 
umount /mnt
losetup -d /dev/loopX

update-grub は次が出れば成功

Found linux image: /boot/vmlinuz-xxxx-generic
Found initrd image: /boot/initrd.img-xxx-generic

出てこない場合は、 /boot にファイルがないはずなので、/bootが別パーティションにありddできてない可能性がある。/bootを取り損ねていないか確認。見つけ次第コピー

LVMを停止関連

LVM を停止してデータを取り出したので、以前のLVM関連の設定が残らないようにする。

lvm バックアップを削除

rm /etc/lvm/backup/le01-vg

スワップファイル

LVM のスワップがあるときは、スワップファイルを作り直してlvmスワップを除去

sudo vim  /etc/initramfs-tools/conf.d/resume 

スワップファイル再生成

sudo dd if=/dev/zero of=/swap.img bs=1M count=1000
sudo chmod 600 /swap.img 
mkswap /swap.img 

fstab のスワップ設定を変える

sudo vim /etc/fstab

LVM除去が終わったら

update-grub
update-initramfs -u

その他の問題 btrfs

btrfs の場合 update-initramfs -uが次のエラーになるので。

/sbin/fsck.btrfs doesn't exist, can't install to initramfs

ダミーで対応する。

sudo  cp /bin/true /sbin/fsck.btrfs

その他の問題 GRUB /boot

/boot の中身をコピーし忘れたときは、単純に grub だけが起動する。

grub で、not found になるときはコピーし忘れ

grub > ls 
grub > set root=(hd0,1)
grub > ls /vmlinuz
file not found 

その他の問題 GRUB lvm 除去漏れ

lvm → ext4 に変えたとき、update-initramfs をせずに起動すると、LVMを探しに行ってgrub 付近でエラーになることが有る。

そのときは、手作業で起動してみる

ディスクの確認

grub > ls 

root の設定

grub > set root=(hd0,1)

uuidを確認

grub > ls (hd0,1)
        Partition hd1,3: Filesystem type ext4- Last modification time...
2022-05-23 07:49:05 Sunday, UUID FFEXXX-5X23456

カーネルを起動する

grub > linux /vmlinuz quiet s root=UUID-FFEXXX-5X23456
grub > initrd /boot/initrd.img
grub > boot
grub メモ

MBRパーティションは次のように表示される。dosが入ってるわけでなくDOS/V用のMBRパーティションの意味である。

(hd0,msdos1)

これは、msdosを省略でアクセスできる

set root=(hd0,1)
set root=(hd0,msdos1) # 同じ

gpt ( (hd0,gpt1) ) についても同じだと思う。

まとめ

ディスク内のパーティションの管理は、先頭1MiBで行っている。

単純なext4 イメージに先頭1MiBをつければディスクイメージに変えられるとわかった。

lvm の内部にあるパーティションも強引に取り出して先頭をつければ、単純なディスクイメージに変更できるとわかった。

先頭1MiB について

先頭の1MiBが使われているのは fdisk で確認できます。

sudo sgdisk -p /dev/nvme0n1
Sector size (logical/physical): 512/512 bytes


Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048         1050623   512.0 MiB   EF00
   3         3147776      4000794623   1.9 TiB     8300

ssd/HDDの中身は、2048 セクタから書きます。

1セクタは、512 バイトです。

パーティション1は2048セクタから開始してます。先頭-2047にはext4 は存在しません

先頭-2047セクタ分、つまり2048セクタが管理用に予約され使われているわけです。

この2048セクタのバイトサイズを計算すると・・・1セクタ=512バイトだから

2048 セクタ
⇔ 512バイトx 2048 
⇔ 512 x 2x 1024 バイト 
⇔  1024x 1024 バイト
⇔ 1048576 バイト
⇔ 1MiB

だから先頭に1MiBをつけておけば、ext4のシンプルボリュームをディスクイメージとして使えるってことなんだろうな。

大昔のFDDの頃は容量節約のために1セクタ=128/256/512バイトなど、サイズは自分で決められたらしい。むかし先輩にちらっと聞いたけど、当時はよくわからんけどなんか便利な単位なんですねって聞き流してた。が、まさか今更役に立つなんて。

参考資料

btrfs resize で進捗を見たい

btrfs filesystem resize をしてると、ちゃんと動いてるのか不安になる。

大きいデータファイルだと余計に不安になる。

dmesg を見ればいいらしい

dmesg  | grep BTRFS | tail

watch とかやっておけばいい

実際にやってみた例

Every 2.0s: dmesg  | grep BTRFS | tail                                                                                                                                                                                     host: Sat May 21 18:28:18 2022

[575124.384097] BTRFS info (device dm-2): relocating block group 761060179968 flags data
[575224.816851] BTRFS info (device dm-2): found 549 extents
[575226.307604] BTRFS info (device dm-2): found 549 extents
[575227.461641] BTRFS info (device dm-2): relocating block group 759986438144 flags data
[575334.728443] BTRFS info (device dm-2): found 1375 extents
[575336.185406] BTRFS info (device dm-2): found 1375 extents
[575337.135120] BTRFS info (device dm-2): relocating block group 758912696320 flags data
[575438.211646] BTRFS info (device dm-2): found 48 extents
[575439.111490] BTRFS info (device dm-2): found 48 extents
[575439.794408] BTRFS info (device dm-2): relocating block group 757838954496 flags data

終了したら

[575641.955655] BTRFS info (device dm-2): new size for /dev/mapper/vgubuntu-root is 214748364800

などと出てくくる。

まぁ終了したらコマンド見たらわかるんだけど。

参考資料

https://unix.stackexchange.com/questions/398115/btrfs-filesystem-resize-doesnt-do-anything

ext4 → btrfs にファイルシステムを変換する。

ext4 → btrfs に変更

gitlabストレージに使ってるHDDが、よく考えたら大量のwordpressだらけで、はっきり言って容量の無駄使いなので、btrfs に変えて重複ファイルの排除機能を使えば節約になりそうな気がした。

手順1

fsck でエラーを修正しておく

fsck /dev/mapper/storage-root

手順2変換する

使うコマンドはbtrfs-convert である。進捗をだすために -p を見ている

btrfs-convert -p /dev/mapper/vgubuntu-root

create btrfs filesystem:
        blocksize: 4096
        nodesize:  16384
        features:  extref, skinny-metadata (default)
        checksum:  crc32c
creating ext2 image file
creating btrfs metadata
copy inodes [O] [    698961/    313176]
conversion complete

ただし、一時ファイルが必要みたい 進捗を見る限り直接ファイルシステムを変更するわけではなく、一時ファイルを経由するみたいだから、多少の空き容量が必要であると予想される。

creating ext2 image file

変換結果の確認

変換された結果を閲覧する。btrfs はマウントしてデータを見る。

sudo mount /dev/mapper/vgubuntu-root ./disk
sudo btrfs filesystem show ./disk

実際の動作例。

sudo btrfs filesystem show disk
[sudo] password for takuya:
Label: none  uuid: 7f7eb691-81a0-4184-89cb-a8d3b67c8672
        Total devices 1 FS bytes used 90.58GiB
        devid    1 size 498.54GiB used 117.37GiB path /dev/mapper/vgubuntu-root

btrfs の機能である重複排除や透過圧縮が聞いてるとディスクサイズがガラッと変わってくる。

df を見る

btrfsdf がつかえなくなる(あてにならない)ので、btrfs df コマンドを代わりに使う。

sudo btrfs filesystem df ./disk

実際の例。

sudo btrfs filesystem df ./disk
Data, single: total=115.22GiB, used=90.81GiB
System, single: total=4.00MiB, used=112.00KiB
Metadata, single: total=1.45GiB, used=450.69MiB
GlobalReserve, single: total=110.61MiB, used=0.00B

df よりusage のほうが見やすいので私はこっちが好き

sudo btrfs filesystem usage ./disk
Overall:
    Device size:                 498.54GiB
    Device allocated:            115.60GiB
    Device unallocated:          382.94GiB
    Device missing:                  0.00B
    Used:                         90.65GiB
    Free (estimated):            406.87GiB      (min: 406.87GiB)
    Data ratio:                       1.00
    Metadata ratio:                   1.00
    Global reserve:              110.33MiB      (used: 16.00KiB)

Data,single: Size:114.14GiB, Used:90.21GiB (79.03%)
   /dev/mapper/vgubuntu-root     114.14GiB

Metadata,single: Size:1.45GiB, Used:450.42MiB (30.27%)
   /dev/mapper/vgubuntu-root       1.45GiB

System,single: Size:4.00MiB, Used:112.00KiB (2.73%)
   /dev/mapper/vgubuntu-root       4.00MiB

Unallocated:
   /dev/mapper/vgubuntu-root     382.94GiB

マウントを変更する ext4 → btrfs

btrfs に変更されると、ディスクのUUIDが変わるので、マウントを変えてあげないとだめなことがある。

私の場合は、/dev/mapperで指定してたので、UUIDは使ってないので特にUUID変更の必要はなかった。

ただし、ファイルシステムについては、fstabext4 を記載部分を btrfs に変更する必要があった。

before

# /etc/fstab: static file system information.
# <file system> <mount point>   <type>  <options>       <dump>  <pass>

# /dev/mapper/vgubuntu-root /               ext4    errors=remount-ro 0       1
/dev/mapper/vgubuntu-root /               btrfs   errors=remount-ro 0       1

UUIDでマウントをしている場合は、uuidも手動で変更してあげる。

mount /dev/mapper/xxx-root disk
blkid 
vim disk/etc/fstab

マウントオプション

btrfs にはいくつかオプションがあるので、マウントオプションを検討する。(後述)

通常は変換後は、ただ何も考えずに使えばいい。

サイズを調整する。

任意。btrfs でディスクサイズがいい感じに節約されたときは、リサイズを掛けたくなるとおもう。

縮小

btrfs filesystem resize -100GB ./disk

拡大

btrfs filesystem resize +10GB ./disk

指定サイズへ

btrfs filesystem resize 300GB ./disk

パーティション最大へ

btrfs filesystem resize  max ./disk

マウントオプションによるチューニング

CoW の有効無効に注意する

CoWを有効化するかどうか。Raspberry Pi のようなSDカードメインだとCoWは著しく寿命を縮める可能性があるが、ログファイルなどは、journalctl で volalite(揮発性)にしてしまえばCoWがenabledでも問題なさそうだ。DBストレージの場合は、DBが入ってるディレクトリだけchattr してあげたほうが良さそう。

圧縮の有効無効

圧縮を透過圧縮にするかどうか、これも検討した方がいい。テキストファイルを扱うことが多いなら透過圧縮はストレージ容量を大幅に節約することができると思う。とくにgitlab のようなテキストファイルを大量に扱うストレージなら、btrfs で重複排除されるうえに、文字列が多いので圧縮が非常に効くと思う。ただし物理的破損がおきたらデータ喪失量も膨大になりそうだ。ちょっと諸刃の剣。CPU負荷も少し上がりそうだよね。書き込み総量が少なくなるので、SSDの寿命に優しくなるので、電気代・書き込み量・扱うデータを考えて、こちらも少し思案したほうが良さそう。設計に困ったら、特定のディレクトリだけを圧縮するchattr が使えるのでbtrfs は強い。

ext4→btrfs変換後に再圧縮(初期圧縮)をかける

btrfs filesystem defragment -r -v -c XXX /

trim で SSD TRIM
マウントオプション discard=asyncで、自動的にtrim が実行される。コミット待ちが発生するので、メモリ量と書き込み頻度と相談。

その他のマウントオプション

  • ssdSSD最適化された動作の一部をオンにします
  • ssd_spread: 大きな空き領域を一括で割り当てることでパフォーマンスの向上を図るらしい。
  • inode_cache: 空きinode番号のキャッシュを有効にします。

メンテナンス

最低限のメンテナンス手順だけ覚えておく

btrfs filesystem defragment -r ./disk
btrfs scrub ./disk
#  btrfs check ./disk # 普通はやらない

参考資料

UbuntuのUSBメモリの作り方と起動

UbuntuUSBメモリの作り方

unetbootinを使う場合

unetbootin を起動します。

ディストリビューション選択し、インストールするUSBメモリを選びます。

リブート後の保存領域のサイズを決めます。

UbuntuのISOファイルが自動的にダウンローされます。

Ubuntuのダウンロードが遅い場合は、自分で最速ミラーを探せば問題ないでしょう。

Rufus を使う場合

他のソフトウェアとしてRufusをインストールします。

ISOファイルの準備

Rufusを使う場合。さきに、UbuntuのISOファイルを入手しておきます。

Windows コマンドプロンプトを起動します。

ダウンロードコマンドは次のとおりです。

curl -LJO http://ftp.jaist.ac.jp/pub/Linux/ubuntu-releases/22.04/ubuntu-22.04-live-server-amd64.iso

ダウンロードが終わるのを待ちます。

Rufusを起動します。

ISOファイルを選び、Persistentサイズ(永続化サイズ)を数GB確保しておきます。

USBメモリをパソコンに差し込みます。

電源をいれ、F12連打します。

F12は、起動するHDD/SSD選択画面を表示するキーです。機種によってはF1/F2/F8であることもあります。

最上位のもの選んでEnter

最初に表示されるのは、USBメモリ内部にあるOS選択画面です。

特に選択は必要ありませんが、一番上を選びます。

Ubuntuが起動します。

以上

Ubuntu が起動するUSBメモリは、15分ほどで作ることができます。

サイズは8GB程度あれば十分です。32GBは多いくらいですが、500円-1000円までで購入可能であれば問題ないと思います。

UbuntuのUSBメモリ起動でHDDのクローンとバックアップを作る

UbuntuUSBメモリ起動でHDDのクローンとバックアップを作る

作業前の注意

練習すること。 実際にバックアップを取得する前に、練習すること。

練習は、データが消えてもいいUSB-HDDや安いUSBメモリを使う。SDカードでもいいので練習しておく。

ubuntu の起動

USBメモリを挿し込んでパソコンを起動します。 パソコンにUSBメモリを差し込み、USBメモリから起動を選びます。

起動するストレージを選択するキーを連打して電源を入れます。(F12など)

Ubuntu の起動を待つ

選択したら、起動を待ちます。 起動しました

gparted を使う場合

gparted は Linux で一般的に使われるHDD・SSDの管理ツールです。

ディスクのクローンやイメージ化吸い出し、コピー、初期化、サイズ変更などメンテナンスが行なえます。

gparted を起動します。

バックアップ(クローン)を作成ディスクを選びます。 どこのディスクをどこへクローンするか選びます。

ddrescue を使う場合

コマンドからやるほうが、作業が明確になりミスが減ると思います。

ddrescueの準備(インストール)

ddrescue は自分でインストールする必要があります。

Terminalを起動します。

すべてのプログラムから、ターミナルを起動します

universe レポジトリを追加します。

sudo add-apt-repository universe

ddrescue をインストールします。

sudo apt install gddrescue

ddrescue でバックアップ

ターミナルで次のコマンドを実行

lsblk で接続しているディスクの一覧を見れます。

lsblk 

ddrescue を実行します。

ddrescue /dev/sdX /dev/sdY

以上

バックアップは、UbuntuUSBメモリがあれば手軽に作ることができます。

緊急時に備えて、避難訓練をやっておいて損はないと思います。

lxc で hostnamectl が動かない。

lxc rename の問題。

lxc rename でインスタンス名を変更したが、ホストにログインしたときの名前が変わってない。

hostnamectl が動かない。

ホスト名を変えようと思ったけど動いてない。

root@lxc-instance01:~# hostnamectl set-hostname myserver01
Could not set property: Connection timed out

hostnamectl は systemd なので、そっちを見に行く。

root@lxc-instance01:~# systemctl status systemd-hostnamed
● systemd-hostnamed.service - Hostname Service
     Loaded: loaded (/lib/systemd/system/systemd-hostnamed.service; static)
     Active: failed (Result: exit-code) since Tue 2022-05-17 22:33:53 JST; 49s ago
       Docs: man:systemd-hostnamed.service(8)
             man:hostname(5)
             man:machine-info(5)
             man:org.freedesktop.resolve1(5)
    Process: 902 ExecStart=/lib/systemd/systemd-hostnamed (code=exited, status=226/NAMESPACE)
   Main PID: 902 (code=exited, status=226/NAMESPACE)

May 17 22:33:52 lxc-instance01 systemd[1]: Starting Hostname Service...
May 17 22:33:53 lxc-instance01 systemd[902]: systemd-hostnamed.service: Failed to set up mount namespacing: /run/systemd/unit-root/proc: Permission denied
May 17 22:33:53 lxc-instance01 systemd[902]: systemd-hostnamed.service: Failed at step NAMESPACE spawning /lib/systemd/systemd-hostnamed: Permission denied
May 17 22:33:53 lxc-instance01 systemd[1]: systemd-hostnamed.service: Main process exited, code=exited, status=226/NAMESPACE
May 17 22:33:53 lxc-instance01 systemd[1]: systemd-hostnamed.service: Failed with result 'exit-code'.
May 17 22:33:53 lxc-instance01 systemd[1]: Failed to start Hostname Service.

だめっぽい。

非特権コンテナなので、ファイルにアクセスできないので、変えられない。LXCの設計上の問題っぽいですね。ファイルを編集するかホスト側から制御しなくちゃだめなのかも。

root@:~# ls -alt /run/systemd/unit-root/proc
ls: cannot access '/run/systemd/unit-root/proc': No such file or directory

対応、直接ファイルを編集

昔ながらの方法で、ファイルを編集して対応する。

vim /etc/hostname
vim /etc/hosts
shutdown -r 

debian で発生した。ubuntu の場合発生しなかった。

rclone の sftp で接続エラーになる

rclone の sftp が接続できない

rclone で sftp が接続エラーになる。

接続ログを見ながら接続

rclone -vvv lsd test:

接続エラー

2022/05/17 16:12:41 DEBUG : Using config file from "/root/.config/rclone/rclone.conf"
2022/05/17 16:12:41 DEBUG : pacer: low level retry 1/10 (error couldn't connect SSH: ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain)

sftp コマンドではつながる

sftp test
sftp> ls /

接続できる。

サーバー側のエラーを見る

userauth_pubkey: key type ssh-rsa not in PubkeyAcceptedAlgorithms [preauth]

rclone はrsaの接続方式の一部をスキップしてる。SSHサーバ側ではRSA鍵をAccept出来ない。

サーバー側で設定を追加

/etc/ssh/sshd_config

#PubkeyAuthentication yes
PubkeyAcceptedKeyTypes=+ssh-rsa

再起動

systemctl reload sshd

よくわからない。。。

rclone の接続は通常のSFTPライブラリをどう使ってるんですかねぇ。

sftp のコマンドでつながるし、同じ鍵を使ってるんですけどねぇ。

vim 追加コピー

vim で追加コピーをやる方法

過去の調べているだが、すっかり忘れている。

以前のエントリ

vim で追加カット・追加コピー - それマグで!

vim で追加コピー

追加切り取り

:map dEd "edd
:map ded "Edd

追加コピー

:map yEe "eyy
:map yee "Eyy

ヤンクレジスタ に登録して、追加コピーする。

vimdiff と組み合わせると便利すぎてやばい。

map して使うのが一番いい。

lxc の btrfs ストレージがぶっ壊れたときの記録

lxc のインスタンスの動作が微妙におかしいので、停止してみみてみた。

srubでエラーになる。

there are uncorrectable errors

エラーを見てくる。、

dmesg| grep -e "BTRFS warning.*path:"
dmesg| grep -e "BTRFS warning.*path:" | sed -e 's/^.*path\: //'

LXCのログも見る。

lxc monitor --type=logging --pretty

ログを見ながらscrubする

btrfs scrub start /mnt
journalctl --dmesg -f --grep 'BTRFS'
-- Logs begin at Thu 2020-09-10 14:48:11 JST. --

May 13 04:37:05 m75q-1 kernel: BTRFS error (device loop1): bdev /dev/loop1 errs: wr 704175, rd 69641, flush 0, corrupt 0, gen 0
May 13 04:37:05 m75q-1 kernel: BTRFS error (device loop1): bdev /dev/loop1 errs: wr 704175, rd 69642, flush 0, corrupt 0, gen 0
May 13 04:37:05 m75q-1 kernel: BTRFS error (device loop1): bdev /dev/loop1 errs: wr 704175, rd 69643, flush 0, corrupt 0, gen 0
May 13 04:37:05 m75q-1 kernel: BTRFS error (device loop1): unable to fixup (regular) error at logical 221216776192 on dev /dev/loop1
May 13 04:37:05 m75q-1 kernel: BTRFS error (device loop1): unable to fixup (regular) error at logical 221216247808 on dev /dev/loop1
May 13 04:37:05 m75q-1 kernel: BTRFS error (device loop1): unable to fixup (regular) error at logical 221216903168 on dev /dev/loop1
May 13 04:37:05 m75q-1 kernel: BTRFS error (device loop1): unable to fixup (regular) error at logical 221216780288 on dev /dev/loop1
May 13 04:37:05 m75q-1 kernel: BTRFS warning (device loop1): i/o error at logical 221216641024 on dev /dev/loop1, physical 193282576384, root 4115, inode 103249193, offset 76156928, length 4096, links 1 (path: rootfs/var/log/journal/67abe395f45b472>
May 13 04:37:05 m75q-1 kernel: BTRFS warning (device loop1): i/o error at logical 221215981568 on dev /dev/loop1, physical 193281916928, root 4115, inode 103249193, offset 75497472, length 4096, links 1 (path: rootfs/var/log/journal/67abe395f45b472>
May 13 04:37:05 m75q-1 kernel: BTRFS info (device loop1): scrub: finished on devid 1 with status: 0
May 13 04:49:16 m75q-1 kernel: BTRFS info (device loop1): scrub: started on devid 1

ハードウェアエラーだって・・・・

Ideally, a corrupt checksum only happens due to hardware issues (e.g., "bit rot" on disk). 

その状態でもbtrfs restore はできるので、btrfs のスナップショットとサブボリュームの管理がlxdからうまく行えてないんじゃないかと疑問を感じた。

btrfsの場合、マウントできるのでファイルを取り出した。

lxc storage list | grep default 
pv /var/snap/lxd/common/lxd/disks/default.img | pigz default.img.gz
losetup -f --show /var/snap/lxd/common/lxd/disks/default.img
mount /dev/loopX /mnt
snap stop lxd
btrfs scrub /mnt
btrfs restore /dev/loopX

gzip ファイルの圧縮率を変える。

圧縮率をbestに変えたい

圧縮率を変えるには、再圧縮が必要

gzip -cd old.gz | gzip > new.gz

伸長(展開)してからやるとストレージが無駄になる。

gzip -cd dump.gz 
gzip -best dump

そこで、直接パイプしてあげればいい

gzip -cd dump.gz  | gzip > dump.gz.2

巨大ファイルで時間のかかるとき

pv と組み合わせて、進捗を表示しつつ

pigz で CPUパワーをフルパワーで使ってやる。

pv -cN read dump.gz | pigz -d -p4 | pigz --best -p 4 | pv -cN compress >  dump.gz.2

インストール

sudo apt install pv pigz 

圧縮アルゴリズムを変更するときも同様

gzipからxz に変えたいときも同様にできる。

gzip -cd old.gz | xz > new.gz

圧縮アルゴリズムの選定基準

圧縮アルゴリズムを「圧縮時間」「圧縮率」だけで比較するのは、だめ。

xz は圧縮には時間が掛かるが、展開は速い。そのため。「XZは、誰か一人がCPU時間を提供して、多くの利用者が展開で使う」ようなときに大変メリットがある。だからリナックスカーネルとかに使われてたりする。

gzip は圧縮時間も圧縮率もそこそこで、使いやすい。「gzipはどこでも使えるオールラウンダ」ってことだし。

圧縮は、繰り返しデータの出現に対し行われるので、ディスクイメージに空き容量があればとても圧縮が効く。

だけど、CD-ROMやUbuntuのインストールUSBのような重複コンテンツは殆どなく容量いっぱいまで使われているストレージには、圧縮は殆ど効果を発揮しない。時間を掛けてXZで圧縮してもGzipでサクッと圧縮してもgzip/xzの結果で数MBも変わらない。

圧縮がどれくらい効くファイルなのか、ちゃんと予想くらいは立てて圧縮作業の展望を持っておかないと、圧縮率を変えても、圧縮アルゴリズムを変更しても電気の無駄遣いになるだけなので注意です。

「完全なランダムデータ」は圧縮が効かないってことをちゃんとわかった上で、ランダムデータに近いものほど圧縮効果が無いことを忘れないでほしいのです。

snap lxd のbtrfsストレージの中に入る

snap lxd の中に入りたい。

BTRFSの場合単純にマウントしてもいいんだけど。

lxc storage list | grep default
losetup -l | grep default.img
/dev/loop10         0      0         1  0 /var/snap/lxd/common/lxd/disks/default.img   1     512
mount /dev/loop10   /mnt

マウントもちょっと怖い。とかZFSの場合どうするんだろうか考えた。

本来lxd のストレージはそのままアクセスできるはずなんだけど、snap の場合はlxdはsnap内部に閉じ込められているんで外部からアクセスで規範い。

snap の中へ chroot してみる

snap の環境の中にlxd

root@#  chroot /var/snap/lxd/common/mntns  /bin/bash

これでsnapでもlxdで使ってるストレージを直接見ることができたわ

各種コマンドをPATH通す

sudo chroot /var/snap/lxd/common/mntns /bin/bash
export PATH=$PATH:/snap/lxd/current/bin
### インスタンスのなかを直接もみる。
cd /var/snap/lxd/common/lxd/containers/nginx/

btrfs を修正したり。

btrfs property set -ts /var/snap/lxd/common/mntns/var/snap/lxd/common/lxd/storage-pools/bt01/containers/nginx ro false

snap のlxdの問題

snap環境にセパレートされていて、管理も楽だし最新版が提供されるので便利だけど、トラブル時に通常LXD違うのでちょっとめんどくさかった。

lxc delete 時間かかりすぎるのでストレージまるごと消したい。

lxc delete 時間かかりすぎる

lxc ストレージのbtrfsのrestore(load)に失敗したので。強制的に消す方法を模索する

うっかり、コンテナに200GBも入れてしまったので、時間がかかって仕方ない。

いっそのこと先にストレージをけしたらどうなるのか。1Gのコンテナで試してみることにした。

ストレージとインスタンスを作成する

lxc storage create bt02 btrfs
lxc launch images:debian/11 d11 --storage=bt02

ストレージを消してやる

sudo rm   /var/snap/lxd/common/lxd/disks/bt02.img

ファイルはもうない

sudo ls -alt  /var/snap/lxd/common/lxd/disks/bt02.img
ls: cannot access '/var/snap/lxd/common/lxd/disks/bt02.img': No such file or directory

参照は残ってる。

losetup
NAME        SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE                                         DIO LOG-SEC
/dev/loop10         0      0         1  0 /var/snap/lxd/common/lxd/disks/bt02.img (deleted)   1     512
lxc storage list
+---------+--------+--------------------------------------------+-------------+---------+---------+
|  NAME   | DRIVER |                   SOURCE                   | DESCRIPTION | USED BY |  STATE  |
+---------+--------+--------------------------------------------+-------------+---------+---------+
| bt02    | btrfs  | /var/snap/lxd/common/lxd/disks/bt02.img    |             | 2       | CREATED |
+---------+--------+--------------------------------------------+-------------+---------+---------+

ストレージは消したけど、新規起動できてしまう。

ある意味正しいけどある意味怖い。

lxc launch images:debian/11 d12 --storage=bt02
Creating d12
Starting d12

ストレージが消えたのを反映させる。

ストレージの存在と状態はSQLiteで管理しているらしく、起動にチェックするらしい。 SQLiteを操作して消す以外に方法が見当たらない、

lxd を再起動して、エラーにしてやる。

sudo snap restart lxd

再起動すると UNAVAILABLE にななる。.

 lxc storage list
+---------+--------+--------------------------------------------+-------------+---------+-------------+
|  NAME   | DRIVER |                   SOURCE                   | DESCRIPTION | USED BY |    STATE    |
+---------+--------+--------------------------------------------+-------------+---------+-------------+
| bt02    | btrfs  | /var/snap/lxd/common/lxd/disks/bt02.img    |             | 3       | UNAVAILABLE |
+---------+--------+--------------------------------------------+-------------+---------+-------------+

インスタンスはストレージがないので起動していない。

lxc list
+------+---------+------+------+-----------+-----------+
| NAME |  STATE  | IPV4 | IPV6 |   TYPE    | SNAPSHOTS |
+------+---------+------+------+-----------+-----------+
| d11  | STOPPED |      |      | CONTAINER | 0         |
+------+---------+------+------+-----------+-----------+
| d12  | STOPPED |      |      | CONTAINER | 0         |
+------+---------+------+------+-----------+-----------+

インスタンスを消してみる

lxc delete d12
lxc delete d11

特にエラーなく消せる。

ストレージを一覧から削除する

lxc storage delete bt02

無事消えました。

結論

ストレージ・ファイルを消しても、起動中なら参照は残ってるので、そのまま使える。

再起動すると、ストレージがが見つからいためUNAVAILABLEになる。インスタンスも起動しない。

その状態でインスタンスを消すことはできる。

この方法でbtrfsエラーが出て、消せなくなったコンテナを消すことができるようになった。

インスタンスを直接消す事ができるので、エラーがでたストレージは切り離せませすね。

複数のインスタンスでストレージを使ってる場合は、インスタンスlxc move で移動させておけば、影響なく消せますね。やったね。

btrfs 怖すぎるだろほんと。