作業ログ源泉垂れ流し

しがないIT技術者の作業ログを垂れ流す

DRBDの練習 4 〜LVM / DRBD / LVM〜

DRBDの下位デバイスと、DRBDのデバイスにLVMを使ってみる。

DRBDの公式ドキュメントを参考に作業する。

まずはDRBDの下位デバイスとして使う論理ボリューム vg01/r0 を作成する。

drbd1# pvcreate /dev/vdb
  Physical volume "/dev/vdb" successfully created.
drbd1# pvs
  PV         VG       Fmt  Attr PSize   PFree 
  /dev/vda5  drbd1-vg lvm2 a--   <4.52g     0 
  /dev/vdb   vg01     lvm2 a--  <10.00g <9.51g
drbd1# vgcreate vg01 /dev/vdb
  Volume group "vg01" successfully created
drbd1# vgs vg01
  VG   #PV #LV #SN Attr   VSize   VFree 
  vg01   1   1   0 wz--n- <10.00g <9.51g
drbd1# lvcreate -n r0 -L 500M vg01
  Logical volume "r0" created.
drbd1# lvs vg01
  LV   VG   Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  r0   vg01 -wi-ao---- 500.00m                                                    

全く同じことをdrbd2でも行う。

続いて、DRBDの設定ファイルを編集する。 diskには先ほど作成した論理ボリューム /dev/vg01/r0 を指定する。

resource r0 {
        on drbd1 {
                device          /dev/drbd1;
                disk            /dev/vg01/r0;
                address         192.168.122.166:7776;
                meta-disk       internal;
        }
        on drbd2 {
                device          /dev/drbd1;
                disk            /dev/vg01/r0;
                address         192.168.122.45:7776;
                meta-disk       internal;
        }
}

以前の記事と同様に、リソースの初回有効化を行う。

drbd1# drbdadm create-md r0
drbd1# drbdadm up r0

ここまではdrbd2でも実行する。

ここからはdrbd1だけで実行。

drbd1# drbdadm new-current-uuid --clear-bitmap r0/0
drbd1# drbdadm primary r0

これで、論理ボリューム vg01/r0 が、DRBDで同期される。

次に、今使えるようになった/dev/drbd1をLVMのPVとして、その上にVG vg_drbd, LV lv0 を作る。

drbd1# pvcreate /dev/drbd1
  Physical volume "/dev/drbd1" successfully created.
drbd1# pvs
  PV         VG       Fmt  Attr PSize   PFree  
  /dev/drbd1 vg_drbd  lvm2 a--  496.00m 496.00m
  /dev/vda5  drbd1-vg lvm2 a--   <4.52g      0 
  /dev/vdb   vg01     lvm2 a--  <10.00g  <9.51g
drbd1# vgcreate vg_drbd /dev/drbd1
  Volume group "vg_drbd" successfully created
drbd1# vgs vg_drbd
  VG      #PV #LV #SN Attr   VSize   VFree  
  vg_drbd   1   0   0 wz--n- 496.00m 496.00m
drbd1# lvcreate -n lv0 -L 200M vg_drbd
  Logical volume "lv0" created.
drbd1# lvs vg_drbd
  LV   VG      Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  lv0  vg_drbd -wi-a----- 200.00m                                                    

今作った`lv0'にファイルシステムを作り、マウントして、ファイルを作成してみる。

drbd1# mkfs.ext4 /dev/vg_drbd/lv0 
mke2fs 1.46.2 (28-Feb-2021)
Discarding device blocks: done                            
Creating filesystem with 204800 1k blocks and 51200 inodes
Filesystem UUID: 2d5a478b-f48d-475d-9f3a-3feff10c6fb8
Superblock backups stored on blocks: 
        8193, 24577, 40961, 57345, 73729

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done 

drbd1# mount /dev/vg_drbd/lv0 /mnt
drbd1# echo 'Test File' > /mnt/test
drbd1# ls /mnt
lost+found  test
drbd1# cat /mnt/test
Test File

アクティブ系をdrbd1からdrbd2に切り換えてみる。
まずdrbd1で、lv0をアンマウントし、vg_drbdを非アクティブ化して、セカンダリに降格する。

drbd1# umount /mnt
drbd1# vgchange -a n vg_drbd
  0 logical volume(s) in volume group "vg_drbd" now active
drbd1# drbdadm secondary r0
drbd1# drbdadm status r0
r0 role:Secondary
  disk:UpToDate
  peer role:Secondary
    replication:Established peer-disk:UpToDate

続いてdrbd2をプライマリに昇格する。

drbd2# drbdadm primary r0
drbd2# drbdadm status r0
r0 role:Primary
  disk:UpToDate
  peer role:Secondary
    replication:Established peer-disk:UpToDate

drbd2# pvs
  PV         VG       Fmt  Attr PSize   PFree  
  /dev/drbd1 vg_drbd  lvm2 a--  496.00m 296.00m
  /dev/vda5  drbd2-vg lvm2 a--   <4.52g      0 
  /dev/vdb   vg01     lvm2 a--  <10.00g  <9.51g
drbd2# vgs vg_drbd
  VG      #PV #LV #SN Attr   VSize   VFree  
  vg_drbd   1   1   0 wz--n- 496.00m 296.00m
drbd2# lvs vg_drbd
  LV   VG      Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  lv0  vg_drbd -wi------- 200.00m                                                    

ちゃんとdrbd1で作ったPV, VG, LVが見えている。
drbd2で、vg_drbdをアクティブ化し、マウントしてファイルを確認。

drbd2# vgchange -a y vg_drbd
  1 logical volume(s) in volume group "vg_drbd" now active
drbd2# mount /dev/vg_drbd/lv0 /mnt
drbd2# ls /mnt
lost+found  test
drbd2# cat /mnt/test 
Test File

DRBDで入れ子LVが同期できた!

DRBDの練習 3 〜障害対応での切換〜

前回に続いてDRBDの練習。

障害が発生したときの切換をシミュレーションしてみる。

現時点での状態を確認。

drbd1# drbdadm status r0
r0 role:Primary
  disk:UpToDate
  peer role:Secondary
    replication:Established peer-disk:UpToDate

drbd2# drbdadm status r0
r0 role:Secondary
  disk:UpToDate
  peer role:Secondary
    replication:Established peer-disk:UpToDate

プライマリがdrbd1で、セカンダリdrbd2

drbd1で、テスト用にddを使ってファイルに書き込みつづける。

drbd1# dd if=/dev/zero of=/mnt/test bs=1 oflag=sync status=progress
507 bytes copied, 3 s, 0.2 kB/s

この状態で、KVMのホスト環境から強制的にdrbd1を停止してみる。

host$ virsh destroy drbd1
Domain drbd1 destroyed

drbd2で、状態を確認。

drbd2# drbdadm status r0
r0 role:Secondary
  disk:UpToDate
  peer connection:Connecting

接続が切れている。
そこで、drbd2をプライマリに昇格してみる。

drbd2# drbdadm primary r0
drbd2# drbdadm status r0
r0 role:Primary
  disk:UpToDate
  peer connection:Connecting

プライマリに昇格できたので、マウントして中身を確認。

drbd2# mount /dev/drbd1 /mnt
drbd2# ls /mnt
lost+found  test
drbd2# ls -l /mnt/test 
-rw-r--r-- 1 root root 656 Jun 27 23:25 /mnt/test

一旦アンマウントしてセカンダリに降格。

drbd2# umount /mnt
drbd2# drbdadm secondary r0
drbd2# drbdadm status r0
r0 role:Secondary
  disk:UpToDate
  peer connection:Connecting

そして、drbd1を起動してみる。

host$ virsh start --console drbd1

drbd1# drbdadm status r0
r0 role:Secondary
  disk:UpToDate
  peer role:Secondary
    replication:Established peer-disk:UpToDate

drbd1をプライマリに昇格して、マウントする。

drbd1# drbdadm primary r0
drbd1# mount /dev/drbd1 /mnt
drbd1# drbdadm status r0
r0 role:Primary
  disk:UpToDate
  peer role:Secondary
    replication:Established peer-disk:UpToDate

drbd1# ls /mnt
lost+found  test
drbd1# ls -l /mnt/test
-rw-r--r-- 1 root root 656 Jun 27 23:25 /mnt/test

今回のテスト条件では、問題なく同期が取れていたことが確認できた!

DRBDの練習 2 〜アクティブ系の切換〜

前回に続いてDRBDの練習。

計画的にアクティブ系を切り替える状況をシミュレーションしてみる。ただし、ここではサービス無停止までは考慮しない。

現時点での状態を確認。

drbd1# drbdadm status r0
r0 role:Primary
  disk:UpToDate
  peer role:Secondary
    replication:Established peer-disk:UpToDate

drbd2# drbdadm status r0
r0 role:Secondary
  disk:UpToDate
  peer role:Secondary
    replication:Established peer-disk:UpToDate

プライマリがdrbd1で、セカンダリdrbd2

テスト用にファイルを作る。 /dev/drbd1drbd1/mntmountされている。

drbd1# echo 'Test File 1' > /mnt/test1
drbd1# ls /mnt
lost+found  test1
drbd1# cat /mnt/test1  
Test File 1

まずは、現在プライマリのdrbd1をシャットダウンしてみる。

drbd1# shutdown -P now

この状態でdrbd2でステータスを確認。

drbd2# drbdadm status r0
r0 role:Secondary
  disk:UpToDate
  peer connection:Connecting

peer connectionConnectingとなっていて接続が切れていることがわかる。
この状態でdrbd2をプライマリに昇格してみる。

drbd2# drbdadm primary r0
drbd2# drbdadm status r0
r0 role:Primary
  disk:UpToDate
  peer connection:Connecting

プライマリに昇格できたので、マウントして中身を確認。

drbd2# mount /dev/drbd1 /mnt
drbd2# ls /mnt
lost+found  test1
drbd2# cat /mnt/test1 
Test File 1

先ほど作ったファイルが存在している。
さらにファイルを作成してみる。

drbd2# echo 'Test File 2' > /mnt/test2
drbd2# ls /mnt 
lost+found  test1  test2
drbd2# cat /mnt/test2
Test File 2

この状態でdrbd1を起動してみる。

host$ virsh start --console drbd1

drbd1# drbdadm status r0
r0 role:Secondary
  disk:UpToDate
  peer role:Primary
    replication:Established peer-disk:UpToDate

drbd1セカンダリになっている。

drbd2でアンマウントして、セカンダリに戻す。

drbd2# umount /mnt
drbd2# drbdadm secondary r0
drbd2# drbdadm status r0
r0 role:Secondary
  disk:UpToDate
  peer role:Secondary
    replication:Established peer-disk:UpToDate

そして、drbd1をプライマリに昇格する。

drbd1# drbdadm primary r0
drbd1# drbdadm status r0
r0 role:Primary
  disk:UpToDate
  peer role:Secondary
    replication:Established peer-disk:UpToDate

マウントして中身を確認。

drbd1# mount /dev/drbd1 /mnt
drbd1# ls /mnt
lost+found  test1  test2
drbd1# cat /mnt/test2
Test File 2

drbd2で作成したファイルも確認できた!

DRBDの練習 1 〜DRBDのシステム構築〜

DRBD (Distributed Replicated Block Device) を使ってディスクをミラーリングしたシステムを作ってみる。

The DRBD User’s Guideを参考に作業する。
日本語版もあるが、訳が少し怪しいところがあるので、なるべく英語版を参照することにする。

テスト環境としてKVM上にDebian bullseyeのVMを2台作る。 以前の自動インストールの記事を参照。

host$ virt-install --name drbd1 --memory 4096 --vcpus 1 --location $PWD/debian-bullseye-DI-rc1-amd64-netinst.iso --os-variant debiantesting --disk path=drbd1-vda.img,size=5,format=qcow2 --disk path=drbd1-vdb.img,size=10,format=qcow2 --network network=default --graphics none --serial pty --console pty --initrd-inject preseed.cfg --extra-args 'console=ttyS0,115200n8 serial hostname=drbd1 netcfg/get_ipaddress=192.168.122.129 netcfg/get_nameservers=192.168.122.1'
host$ virt-install --name drbd2 --memory 4096 --vcpus 1 --location $PWD/debian-bullseye-DI-rc1-amd64-netinst.iso --os-variant debiantesting --disk path=drbd2-vda.img,size=5,format=qcow2 --disk path=drbd2-vdb.img,size=10,format=qcow2 --network network=default --graphics none --serial pty --console pty --initrd-inject preseed.cfg --extra-args 'console=ttyS0,115200n8 serial hostname=drbd2 netcfg/get_ipaddress=192.168.122.130 netcfg/get_nameservers=192.168.122.1'

OSはvdaにインストールして、10 GiBのvdbは手つかずのまま置いておく。
ホスト名とIPアドレスはマニュアル設定する。

ここからはVM上での作業。

一番最初に、DRBDパッケージをインストールして、有効化する。
Debianの場合

# apt install drbd-utils
# systemctl enable drbd

DRBDの設定ファイルを編集する。 両方のホストで全く同じ内容にする必要がある。

/etc/drbd.d/global_common.confは書き換えなくても使えるが、今回は次のように、レプリケーションのモードに「プロトコルB」を指定した。

common {
        net {   
                protocol B;
        }
}

プロトコルBとは、プライマリノードでの書き込みについて、レプリケーションパケットが対向ノードに届いた時点で書き込み完了とするというもので、

両方のノードに同時に電源障害が起き、かつ、プライマリノードのデータストアに回復不能な破壊があった場合には、最後の書き込みが失われるかもしれない

とのこと (参考)。

続いて、リソース設定ファイル /etc/drbd.d/r0.res を作成する。

resource r0 {
        device          /dev/drbd1;
        disk            /dev/vdb;
        meta-disk       internal;
        on drbd1 {
                address 192.168.122.129:7789;
        }
        on drbd2 {
                address 192.168.122.130:7789;
        }
}

今回はdiskに、2番目の仮想ディスクvdb全体を使う。
IPアドレスは事前に確認しておく。ポート番号は、使われていなければ何でも構わない。

設定ファイルの詳細はマニュアルを参照のこと。

定義したリソース r0 について、はじめて有効化する場合は、最初にデバイスメタデータを作成する。

drbd1# drbdadm create-md r0

次に、リソース r0 を有効化する。

drbd1# drbdadm up r0

リソース r0 のステータスを確認してみる。

drbd1# drbdadm status r0
r0 role:Secondary
  disk:Inconsistent
  peer connection:Connecting

この段階ではInconsistentとなるが問題ない。

drbd2でも全く同じことを行い、 再びステータスを確認してみる。

drbd1# drbdadm status r0
r0 role:Secondary
  disk:Inconsistent
  peer role:Secondary
    replication:Established peer-disk:Inconsistent

依然としてInconsistentだが、replicationEstablishedになっている。

ここまでで、ひとまずリソースr0が準備できたので、サービスを起動する。

drbd1# systemctl start drbd

既に下位デバイスに同期したい内容が書かれている場合には初回のフル同期が必要だが、今回は新しい(仮想)ディスクを使っていて、初回にフル同期する必要はないので、強制的に同期状態に変える。

drbd1# drbdadm new-current-uuid --clear-bitmap r0

この処理は片方のホストだけでやればよい。

再度ステータスを確認してみる。

drbd1# drbdadm status r0
r0 role:Secondary
  disk:UpToDate
  peer role:Secondary
    replication:Established peer-disk:UpToDate

drbd2で確認しても、UpToDateになっている。 しかし、どちらのホストもSecondaryになっている。

そこで、書き込みを行いたい側のホストで、プライマリに昇格する。

drbd1# drbdadm primary r0
drbd1# drbdadm status r0
r0 role:Primary
  disk:UpToDate
  peer role:Secondary
    replication:Established peer-disk:UpToDate

drbd2でもステータスを確認してみる。

drbd2# drbdadm status r0
r0 role:Secondary
  disk:UpToDate
  peer role:Primary
    replication:Established peer-disk:UpToDate

drbd1がプライマリ、drbd2セカンダリとして同期されている。

DRBDで作られたデバイスの状態を確認してみる。

drbd1# fdisk -l /dev/drbd1
Disk /dev/drbd1: 10 GiB, 10737053696 bytes, 20970808 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

プライマリのdrbd1では、ちゃんとディスクデバイスとして見えている。

drbd2# fdisk -l /dev/drbd1
fdisk: cannot open /dev/drbd1: Wrong medium type

セカンダリdrbd2だと怒られた。

プライマリのdrbd1/dev/drbd1ファイルシステムを作って、マウントする。

drbd1# mkfs.ext4 /dev/drbd1
mke2fs 1.46.2 (28-Feb-2021)
Discarding device blocks: done                            
Creating filesystem with 2621351 4k blocks and 655360 inodes
Filesystem UUID: bd340ca5-5981-4ba6-8bf3-94c61c16b7b4
Superblock backups stored on blocks: 
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done 

drbd1# mount /dev/drbd1 /mnt

書き込み性能をddを使って簡単にテストしてみる。

drbd1# dd if=/dev/zero of=/tmp/test bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 0.6066 s, 1.8 GB/s
drbd1# dd if=/dev/zero of=/mnt/test bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 1.58761 s, 676 MB/s

DRDBを使っていない/tmpへの書き込みに比べて約4割ほどの速度。

同期されていることを確認する。
まずdrbd1セカンダリに降格する。

drbd1# umount /mnt
drbd1# drbdadm secondary r0
drbd1# drbdadm status r0
r0 role:Secondary
  disk:UpToDate
  peer role:Secondary
    replication:Established peer-disk:UpToDate

次にdrbd2をプライマリに昇格する。

drbd2# drbdadm primary r0
drbd2# drbdadm status r0
r0 role:Primary
  disk:UpToDate
  peer role:Secondary
    replication:Established peer-disk:UpToDate

マウントしてファイルを確認。

drbd2# mount /dev/drbd1 /mnt
drbd2# ls /mnt/
lost+found  test

先ほどの性能テストで作られたファイルが存在している。
testファイルを削除して、セカンダリに戻す。

drbd2# rm /mnt/test 
drbd2# umount /mnt
drbd2# drbdadm secondary r0
drbd2# drbdadm status r0
r0 role:Secondary
  disk:UpToDate
  peer role:Secondary
    replication:Established peer-disk:UpToDate

そして再びdrbd1をプライマリに昇格して中身を確認。

drbd1# drbdadm primary r0
drbd1# drbdadm status r0
r0 role:Primary
  disk:UpToDate
  peer role:Secondary
    replication:Established peer-disk:UpToDate

drbd1# mount /dev/drbd1 /mnt
drbd1# ls /mnt/
lost+found

DRBDで2ホスト間のディスクが同期できた!

Fedora CoreOSのインストール練習 4 〜podの自動起動〜

前回作ったKubernetesマニフェストで作ったpodをIgnitionで自動起動するように、Fedora CoreOSインストールしてみる。

まずは、Butane config wp-pod.buを用意する。

variant: fcos
version: 1.3.0
passwd:
  users:
    - name: core
      ssh_authorized_keys:
        - (ssh公開鍵)
systemd:
  units:
    - name: wp-pod.service
      enabled: true
      contents: |
        [Unit]
        Description=Play WordPress pod
        After=network-online.target
        Wants=network-online.target
        [Service]
        Type=oneshot
        RemainAfterExit=yes
        ExecStartPre=-/bin/podman pod kill wp-pod
        ExecStartPre=-/bin/podman pod rm wp-pod
        ExecStartPre=/bin/podman build -t pod-wordpress:latest /var/home/wp-pod
        ExecStart=/bin/podman play kube /var/home/wp-pod/wp-pod.yaml
        ExecStop=/bin/podman pod stop wp-pod
        [Install]
        WantedBy=multi-user.target
storage:
  files:
    - path: /var/home/wp-pod/Dockerfile
      contents:
        inline: |
          FROM docker.io/library/wordpress:latest
          ENV WORDPRESS_DB_NAME='wp' WORDPRESS_DB_HOST='127.0.0.1' WORDPRESS_DB_USER='wordpress' WORDPRESS_DB_PASSWORD='wordpress-password'
    - path: /var/home/wp-pod/wp-pod.yaml
      contents:
        inline: |
          apiVersion: v1
          kind: Pod
          metadata:
            labels:
              app: wp-pod
            name: wp-pod
          spec:
            containers:
            - name: web
              image: localhost/pod-wordpress:latest
              ports:
              - containerPort: 80
                hostPort: 80
                protocol: TCP
              securityContext:
                allowPrivilegeEscalation: true
                capabilities:
                  drop:
                  - CAP_MKNOD
                  - CAP_NET_RAW
                  - CAP_AUDIT_WRITE
                privileged: false
                readOnlyRootFilesystem: false
                seLinuxOptions: {}
            - name: db
              image: docker.io/library/mariadb:latest
              env:
              - name: MYSQL_ROOT_PASSWORD
                value: mysql-root-password
              - name: MYSQL_DATABASE
                value: wp
              - name: MYSQL_USER
                value: wordpress
              - name: MYSQL_PASSWORD
                value: wordpress-password
              securityContext:
                allowPrivilegeEscalation: true
                capabilities:
                  drop:
                  - CAP_MKNOD
                  - CAP_NET_RAW
                  - CAP_AUDIT_WRITE
                privileged: false
                readOnlyRootFilesystem: false
                seLinuxOptions: {}
              volumeMounts:
              - mountPath: /var/lib/mysql
                name: wp-mysql-pvc
            restartPolicy: Always
            volumes:
            - name: wp-mysql-pvc
              persistentVolumeClaim:
                claimName: wp-mysql

pod自動起動させるsystemdサービスwp-pod.serviceを定義している。
podman play kubeはpodが起動するとコマンドが終了するので、 Type=oneshotRemainAfterExit=yesを指定する。
ExecStartPreで独自コンテナイメージをビルドさせている。

Butane config wp-pod.buをIgnition config wp-pod.ignに変換する。

host$ docker run -i --rm quay.io/coreos/butane:release < wp-pod.bu > wp-pod.ign

生成されたwp-pod.ignを使ってFedora CoreOSをインストールする。

インストールが終了したらログインして、podが起動するまで少し待ってから、podの起動を確認してみる。

$ systemctl status wp-pod.service
● wp-pod.service - Play WordPress pod
     Loaded: loaded (/etc/systemd/system/wp-pod.service; enabled; vendor preset>
     Active: active (exited) since Wed 2021-06-16 08:08:23 UTC; 6s ago
    Process: 1944 ExecStartPre=/bin/podman pod kill wp-pod (code=exited, status>
    Process: 2000 ExecStartPre=/bin/podman pod rm wp-pod (code=exited, status=1>
    Process: 2026 ExecStartPre=/bin/podman build -t pod-wordpress:latest /var/h>
    Process: 2210 ExecStart=/bin/podman play kube /var/home/wp-pod/wp-pod.yaml >
   Main PID: 2210 (code=exited, status=0/SUCCESS)
      Tasks: 6 (limit: 2280)
     Memory: 1.0G
     CGroup: /system.slice/wp-pod.service
             ├─2429 /usr/bin/conmon --api-version 1 -c a0017f7e8221da59cd409527>
             ├─2435 /usr/bin/conmon --api-version 1 -c 4d71c1b65740a07e2b8fca3f>
             └─2463 /usr/bin/conmon --api-version 1 -c 7b4edae69fe2dbbace2b2ab2>

Jun 16 08:08:23 localhost podman[2210]: 2021-06-16 08:08:23.270676058 +0000 UTC>
Jun 16 08:08:23 localhost podman[2210]: 2021-06-16 08:08:23.460813506 +0000 UTC>
Jun 16 08:08:23 localhost podman[2210]: 2021-06-16 08:08:23.466814111 +0000 UTC>
Jun 16 08:08:23 localhost podman[2210]: 2021-06-16 08:08:23.466855117 +0000 UTC>
Jun 16 08:08:23 localhost podman[2210]: Pod:
Jun 16 08:08:23 localhost podman[2210]: 2b836abed04bc8069f5186b64b01b19d3cc2bee>
Jun 16 08:08:23 localhost podman[2210]: Containers:
Jun 16 08:08:23 localhost podman[2210]: 7b4edae69fe2dbbace2b2ab2c44dd01b3d50ab9>
$ sudo podman pod ps
POD ID        NAME    STATUS   CREATED         INFRA ID      # OF CONTAINERS
2b836abed04b  wp-pod  Running  36 seconds ago  a0017f7e8221  3
$ sudo podman ps
CONTAINER ID  IMAGE                             COMMAND               CREATED         STATUS             PORTS               NAMES
a0017f7e8221  k8s.gcr.io/pause:3.5                                    39 seconds ago  Up 23 seconds ago  0.0.0.0:80->80/tcp  2b836abed04b-infra
7b4edae69fe2  localhost/pod-wordpress:latest    apache2-foregroun...  39 seconds ago  Up 23 seconds ago  0.0.0.0:80->80/tcp  wp-pod-web
4d71c1b65740  docker.io/library/mariadb:latest  mysqld                23 seconds ago  Up 23 seconds ago  0.0.0.0:80->80/tcp  wp-pod-db

無事wp-podが起動している。
ブラウザでもWordPressが起動していることを確認。

いちおうサービス停止も確認しておく。

$ sudo systemctl stop wp-pod.service
$ sudo podman pod ps
POD ID        NAME    STATUS  CREATED        INFRA ID      # OF CONTAINERS
2b836abed04b  wp-pod  Exited  3 minutes ago  a0017f7e8221  3
$ sudo podman ps
CONTAINER ID  IMAGE   COMMAND  CREATED  STATUS  PORTS   NAMES

Kubernetesマニフェストを使ってPodmanでpodを自動起動するようにFedora CoreOSを構成できた!

Podmanで独自コンテナイメージとボリュームを使うpodの作成

Fedora CoreOS上でpodを動かすのが目標だけど、その前にまず手動でpodを作って動かしてみる。

Podmanのコマンドリファレンスを参照しながら作業を進める。

まずは独自コンテナイメージを作成する。 今回はサンプルとしてWordPress環境変数を設定しただけのコンテナにする。
最初にDockerfileを作成。

$ cat <<EOF > Dockerfile
FROM docker.io/library/wordpress:latest

ENV WORDPRESS_DB_NAME='wp' WORDPRESS_DB_HOST='127.0.0.1' \
    WORDPRESS_DB_USER='wordpress' WORDPRESS_DB_PASSWORD='wordpress-password'
EOF

続いてpodmanでpod-wordpress:latestというタグを付けてビルド。

$ sudo podman build -t pod-wordpress:latest .
STEP 1: FROM docker.io/library/wordpress:latest
Getting image source signatures
Copying blob 69692152171a done  
Copying blob ac1fe7c6d966 done  
Copying blob 9b4ca5ae9dfa done  
Copying blob 5b26fc9ce030 done  
Copying blob 2040822db325 done  
Copying blob 3492f4769444 done  
Copying blob 1dec05775a74 done  
Copying blob 77107a42338e done  
Copying blob f58e4093c52a done  
Copying blob d32715f578d3 done  
Copying blob 7a73fb2558ce done  
Copying blob 75e2da936ffe done  
Copying blob 759622df3a7b done  
Copying blob 667b573fcff7 done  
Copying blob c2f98ef02756 done  
Copying blob 50e11300b0a6 done  
Copying blob de37513870b9 done  
Copying blob f25501789abc done  
Copying blob 0cf8e3442952 done  
Copying blob d45ce270a7e6 done  
Copying blob 534cdc5a6ea6 done  
Copying config c2dd1984ad done  
Writing manifest to image destination
Storing signatures
STEP 2: ENV WORDPRESS_DB_NAME='wp' WORDPRESS_DB_HOST='127.0.0.1'     WORDPRESS_DB_USER='wordpress' WORDPRESS_DB_PASSWORD='wordpress-password'
STEP 3: COMMIT pod-wordpress:latest
--> ed133c15e36
ed133c15e364cb72b5a93626a43e38316237eb291c5f9f18bec647db111ad58e

次に、wp-podという名前のpodを手動で作成する。

$ sudo podman pod create -n wp-pod -p 80:80
29004378ddfbf605c11e8a916066336627d14e8d9fd82d2ac7c6d898d3790503
$ sudo podman pod ps
POD ID        NAME    STATUS   CREATED         INFRA ID      # OF CONTAINERS
29004378ddfb  wp-pod  Created  16 seconds ago  8bc8772c5324  1

MariaDB/var/lib/mysqlを永続化するためのボリュームを作成。

$ sudo podman volume create wp-mysql
wp-mysql

MariaDBコンテナwp-pod-dbwp-pod内で実行。

$ sudo podman run -d --restart=always --pod=wp-pod -e MYSQL_ROOT_PASSWORD='mysql-root-password' -e MYSQL_DATABASE='wp' -e MYSQL_USER='wordpress' -e MYSQL_PASSWORD='wordpress-password' -v wp-mysql:/var/lib/mysql --name wp-pod-db docker.io/library/mariadb
Trying to pull docker.io/library/mariadb:latest...
Getting image source signatures
Copying blob 345e3491a907 done  
Copying blob 5e9250ddb7d0 done  
Copying blob 57671312ef6f done  
Copying blob 2d512e2ff778 done  
Copying blob b846f4f4774a done  
Copying blob 57c1a7dc2af9 done  
Copying blob 55edbf0f673e done  
Copying blob 82d8723e99d8 done  
Copying blob 66409f940bd2 done  
Copying blob c34793730ad6 done  
Copying blob 8f1925a0d734 done  
Copying blob 72904fb5fd0b done  
Copying config eff6290896 done  
Writing manifest to image destination
Storing signatures
824fdae25e81491d0b04f0d30cde7131cd986d47e522e6078f0c84c65ac505ac

続いて、先ほどビルドしたコンテナイメージpod-wordpress:latestwp-pod-webコンテナとしてwp-pod内で実行。

$ sudo podman run -d --restart=always --pod=wp-pod --name wp-pod-web localhost/pod-wordpress:latest
31f5d2b2a9c16d6a945242c363c5209ddea7c8563c2f720265f0a7bc4c95c6a2

wp-podWordPressが稼働したはず。

podとコンテナの状態を確認。

$ sudo podman pod ps
POD ID        NAME    STATUS   CREATED        INFRA ID      # OF CONTAINERS
29004378ddfb  wp-pod  Running  4 minutes ago  8bc8772c5324  3
$ sudo podman ps
CONTAINER ID  IMAGE                             COMMAND               CREATED         STATUS             PORTS               NAMES
8bc8772c5324  k8s.gcr.io/pause:3.5                                    4 minutes ago   Up 50 seconds ago  0.0.0.0:80->80/tcp  29004378ddfb-infra
824fdae25e81  docker.io/library/mariadb:latest  mysqld                50 seconds ago  Up 50 seconds ago  0.0.0.0:80->80/tcp  wp-pod-db
31f5d2b2a9c1  localhost/pod-wordpress:latest    apache2-foregroun...  32 seconds ago  Up 33 seconds ago  0.0.0.0:80->80/tcp  wp-pod-web

期待通りに動いている。

実際に別ホストから接続してみる。

remote$ curl -v http://192.168.152.2:80/
*   Trying 192.168.152.2:80...
* TCP_NODELAY set
* Connected to 192.168.152.2 (192.168.152.2) port 80 (#0)
> GET / HTTP/1.1
> Host: 192.168.152.2
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 302 Found
< Date: Tue, 15 Jun 2021 08:23:13 GMT
< Server: Apache/2.4.38 (Debian)
< X-Powered-By: PHP/7.4.20
< Expires: Wed, 11 Jan 1984 05:00:00 GMT
< Cache-Control: no-cache, must-revalidate, max-age=0
< X-Redirect-By: WordPress
< Location: http://192.168.152.2/wp-admin/install.php
< Content-Length: 0
< Content-Type: text/html; charset=UTF-8
< 
* Connection #0 to host 192.168.152.2 left intact

問題なく動いているみたい。 実際にブラウザでアクセスするとちゃんとWordPressの初期設定画面が表示された!

ここまででpodを手動で動かすことはできたけど、Ignitionでインストールすることを考えると、明示的に実行するコマンドはなるべく減らしてシンプルにしたい。
そこで、Kubernetesマニフェストファイルを作ってpodを自動構成するようにしてみる。
マニフェストファイルはゼロから自力で作るのは手間なので、先ほど作ったpodの構成をpodmanで出力させる。

$ sudo podman generate kube wp-pod > wp-pod.yaml

こうやって出力されたファイルには、コンテナのデフォルト設定なども含まれているので、編集して不要な設定を削ってやる。
整理した後のマニフェストファイルwp-pod.yamlがこれ。

apiVersion: v1
kind: Pod
metadata:
  labels:
    app: wp-pod
  name: wp-pod
spec:
  containers:
  - name: web
    image: localhost/pod-wordpress:latest
    ports:
    - containerPort: 80
      hostPort: 80
      protocol: TCP
    securityContext:
      allowPrivilegeEscalation: true
      capabilities:
        drop:
        - CAP_MKNOD
        - CAP_NET_RAW
        - CAP_AUDIT_WRITE
      privileged: false
      readOnlyRootFilesystem: false
      seLinuxOptions: {}
  - name: db
    image: docker.io/library/mariadb:latest
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: mysql-root-password
    - name: MYSQL_DATABASE
      value: wp
    - name: MYSQL_USER
      value: wordpress
    - name: MYSQL_PASSWORD
      value: wordpress-password
    securityContext:
      allowPrivilegeEscalation: true
      capabilities:
        drop:
        - CAP_MKNOD
        - CAP_NET_RAW
        - CAP_AUDIT_WRITE
      privileged: false
      readOnlyRootFilesystem: false
      seLinuxOptions: {}
    volumeMounts:
    - mountPath: /var/lib/mysql
      name: wp-mysql-pvc
  restartPolicy: Always
  volumes:
  - name: wp-mysql-pvc
    persistentVolumeClaim:
      claimName: wp-mysql

マニフェストファイルでのpod作成を試すために、さっき作ったwp-podを一旦消す。

$ sudo podman pod stop wp-pod
29004378ddfbf605c11e8a916066336627d14e8d9fd82d2ac7c6d898d3790503
$ sudo podman pod rm wp-pod
29004378ddfbf605c11e8a916066336627d14e8d9fd82d2ac7c6d898d3790503
$ sudo podman pod ps
POD ID  NAME    STATUS  CREATED  INFRA ID  # OF CONTAINERS
$ sudo podman ps
CONTAINER ID  IMAGE   COMMAND  CREATED  STATUS  PORTS   NAMES
$ sudo podman volume rm wp-mysql
wp-mysql
$ sudo podman volume ls

そして、マニフェストファイルwp-pod.yamlを使ってpodを再生。

$ sudo podman play kube ./wp-pod.yaml
Trying to pull docker.io/library/mariadb:latest...
Getting image source signatures
Copying blob b846f4f4774a skipped: already exists  
Copying blob 345e3491a907 skipped: already exists  
Copying blob 57671312ef6f skipped: already exists  
Copying blob 5e9250ddb7d0 skipped: already exists  
Copying blob 2d512e2ff778 skipped: already exists  
Copying blob 57c1a7dc2af9 skipped: already exists  
Copying blob 66409f940bd2 skipped: already exists  
Copying blob 82d8723e99d8 skipped: already exists  
Copying blob 55edbf0f673e skipped: already exists  
Copying blob c34793730ad6 skipped: already exists  
Copying blob 8f1925a0d734 [--------------------------------------] 0.0b / 0.0b
Copying blob 72904fb5fd0b [--------------------------------------] 0.0b / 0.0b
Copying config eff6290896 done  
Writing manifest to image destination
Storing signatures
Pod:
5c7741db9e2e4c8ae2a253f6568aa61b018de93d032be7c4377ce91f2dca30f4
Containers:
f83e8b9be5fec747f59a86e5a9d1fae0ac4b6fc3e44f18e1c79d35f9dc8dae55
44914870bab7da18a1cbd87e7adcc2169a88ea2d1b83f580d41440b30d92976e

きちんと実行されているか確認。

$ sudo podman pod ps
POD ID        NAME    STATUS   CREATED         INFRA ID      # OF CONTAINERS
5c7741db9e2e  wp-pod  Running  20 seconds ago  c0b859f1cf3e  3
$ sudo podman ps
CONTAINER ID  IMAGE                             COMMAND               CREATED         STATUS             PORTS               NAMES
c0b859f1cf3e  k8s.gcr.io/pause:3.5                                    27 seconds ago  Up 23 seconds ago  0.0.0.0:80->80/tcp  5c7741db9e2e-infra
f83e8b9be5fe  localhost/pod-wordpress:latest    apache2-foregroun...  27 seconds ago  Up 22 seconds ago  0.0.0.0:80->80/tcp  wp-pod-web
44914870bab7  docker.io/library/mariadb:latest  mysqld                23 seconds ago  Up 23 seconds ago  0.0.0.0:80->80/tcp  wp-pod-db
$ sudo podman volume ls
DRIVER      VOLUME NAME
local       59378a373f5dcd7e01a03425bfeec23c6632c203918ead50a4d81eb1b49054bc
local       wp-mysql

ブラウザでもWordPressが動いていることを確認した。

Podmanで独自コンテナとボリュームを使うpodを構成できた!

Fedora CoreOSのインストール練習 4 〜ディレクトリ配置〜

今回はFedora CoreOSというよりはIgnitionとButaneの話。
Ignitionで手元のディレクトリに下を丸ごとFedora CoreOS上に配置してみる。

まずは配置するディレクトリ構造を作る。

$ mkdir test
$ mkdir test/dir1
$ mkdir test/dir2
$ echo 'Test file 1' > test/dir1/file1
$ dd if=/dev/urandom of=test/dir1/file2 bs=512 count=1
$ chmod +x test/dir1/file2
$ echo 'Test file 3' > test/dir2/file3
$ chmod 600 test/dir2/file3

test1は普通のテキストファイル、test2は実行権限を付けたバイナリファイル、test3パーミッション600に設定したテキストファイルを作成している。
作ったディレクトリ構造を確認。

$ ls -lR test/
test/:
total 8
drwxr-xr-x 2 user group 4096 Jun 12 17:08 dir1
drwxr-xr-x 2 user group 4096 Jun 12 17:08 dir2

test/dir1:
total 8
-rw-r--r-- 1 user group  12 Jun 12 17:07 file1
-rwxr-xr-x 1 user group 512 Jun 12 17:17 file2

test/dir2:
total 4
-rw------- 1 user group 12 Jun 12 17:08 file3

次に、作ったtestディレクトリの下を配置するためのButan configファイルtree-embed.buを、 Butan configの仕様を参考に作成する。
ここでは、手元のtest配下を/var/home/core/targetに配置するように指定している。

variant: fcos
version: 1.3.0
passwd:
  users:
    - name: core
      password_hash: (ハッシュ)
storage:
  trees:
    - path: /var/home/core/target
      local: test

そして、作ったButan configをIgnition configファイルに変換する。

$ docker run -i --rm -v $PWD:/data quay.io/coreos/butane:release --files-dir /data < tree-embed.bu > tree-embed.ign

生成されたtree-embed.ignの中身を整形したものがこちら。

{
  "ignition": {
    "version": "3.2.0"
  },
  "passwd": {
    "users": [
      {
        "name": "core",
        "passwordHash": "(ハッシュ)"
      }
    ]
  },
  "storage": {
    "files": [
      {
        "path": "/var/home/core/target/dir1/file1",
        "contents": {
          "source": "data:,Test%20file%201%0A"
        },
        "mode": 420
      },
      {
        "path": "/var/home/core/target/dir1/file2",
        "contents": {
          "source": "data:;base64,wTMSSxSVQHkEHeJdfqBKd8e9E0TyQReFqkTeXPydW7oCy83Em8GAOUGDDYeuTpZBZVOIcVkuFowrKeWpmnXIsGOt5g1CmWEDSw9dKbziFs7ASonrNaoVTmcl3k18Y45/oaIOmQx+i9/YZ9rAofZbaeIuqiCTputWB8COCoFZEEP1iRLOgw5AIM5Z2XcZD6b8fp5++jwu0h3VWdKW+xN9NHxQIPzz4J4fIK8Jpw5Lcrkzl0Yu0SAqV0xLgeQWtwNrmvihzxFqjhpqCE1QOb4zPsavfvTOUdbGzd7bW595n0MIBvvqcV0PqgX4OkjihqBwYhWECaakNVy3BVFtTgif4IPpgc2Qm8JMy7rpJwNFCPBleTf8Sys+LsXoXvyimDe2vRo0whKjSkWGO+TfoYl618g5p4gmWERVzC/oq35E2egcbN9Fy8gqssheJQwfVNQQ7viDLRdc7fY/i8zDBm+GGgsgrCMsuqUKerechAnw6UqNKtX10mu5KuQIWfZSGZKzb1bzAHCX4wl/DdWs4LIXnZfPe5F1gnWkC52eSNBFfNvzZqIaLIuZWHpAR4VnVfUNW0BRbgNgSWMkTt+7b0VWHpeMSADdDvEGCiUg9V4E6B60qLxTwFMj2oRdLzdErf5/OkXzzWXI7GafCBOmiWJvz1Lpbne74gJlrHKDd705iYQ="
        },
        "mode": 493
      },
      {
        "path": "/var/home/core/target/dir2/file3",
        "contents": {
          "source": "data:,Test%20file%203%0A"
        },
        "mode": 420
      }
    ]
  }
}

テキストファイルはそのまま、バイナリファイルはbase64エンコードされて埋め込まれている。ファイルの中身がIgnition configに埋め込まれるので、当然ながら配置元ファイルの内容を変更したら、(Butane configを変更していなくても)Ignition configを変換し直す必要がある。
modeの4200644を、4930755を整数値にしたもの。 Butane configの仕様に書かれている通り、実行可能ファイルは0755、それ以外は0644に設定されている。

tree-embed.ignを使ってFedora CoreOSをインストールして確認してみる。

$ ls -lR /var/home/core/target
target/:
total 0
drwxr-xr-x. 2 root root 32 Jun 12 08:33 dir1
drwxr-xr-x. 2 root root 19 Jun 12 08:33 dir2

target/dir1:
total 8
-rw-r--r--. 1 root root  12 Jun 12 08:33 file1
-rwxr-xr-x. 1 root root 512 Jun 12 08:33 file2

target/dir2:
total 4
-rw-r--r--. 1 root root 12 Jun 12 08:33 file3

手元のディレクトリ構造がFedora CoreOSに配置できた!