GitHub ActionsでカスタマイズしたUbuntuのISOイメージを作る

Ubuntu使ってますか？

Linuxのディストリビューションには数え切れないものがあります。Ubuntuはその一つで最も大きなものの一つです。
私は限られた環境でどのディストリビューションがコンセプトにマッチするのか試すために数か月おきにインストールしなおすのですが、同じアプリケーションを何度も入れなおすのは面倒くさいです。
今使っているデスクトップ環境もDockerの上にたってくれないかなとさえ思います。aptを使っている場合は特に。

[リポジトリ](https://github.com/misogihagi/misogihagi-OSs)

下のリンクから試すことはできます。

https://github.com/misogihagi/misogihagi-OSs/releases/download/v1.0.3/ubuntu-misogihagi-20.04.3-desktop-amd64.iso-00
https://github.com/misogihagi/misogihagi-OSs/releases/download/v1.0.3/ubuntu-misogihagi-20.04.3-desktop-amd64.iso-01
https://github.com/misogihagi/misogihagi-OSs/releases/download/v1.0.3/ubuntu-misogihagi-20.04.3-desktop-amd64.iso-02
https://github.com/misogihagi/misogihagi-OSs/releases/download/v1.0.3/ubuntu-misogihagi-20.04.3-desktop-amd64.iso-03

linuxの場合

```bash
cat ubuntu-misogihagi-20.04.3-desktop-amd64.iso-* > ubuntu-misogihagi-20.04.3-desktop-amd64.iso
```

windowsの場合

```sh
copy /b ubuntu-misogihagi-20.04.3-desktop-amd64.iso-* ubuntu-misogihagi-20.04.3-desktop-amd64.iso
```

# やりたいこと

UbuntuであれなんであれOSをインストールするときはISOイメージからブータブルなメディアを作成し、そこからOSを起動することが多いと思いますが、ここに展開されるファイルの中によく使うアプリケーションを入れれば何度もインストールする必要はないのではないかと考えました。
そしてそうするスクリプトをGitHubに置けばGitHub Actionsで自動的にデプロイされるのではないかと考えました。

Ubuntuはデフォルトの状態ではgitやcurlが入っていないのでそれらのパッケージがインストールされた状態のUbuntuのISOイメージを作ることを目指します。

# 実装
[コミュニティのライブCDの作成方法](https://help.ubuntu.com/community/LiveCDCustomization)から必要なGitHub Actionsのワークフローを生成します。
以下のようになります。

```yaml

on:
  push:
    tags:
      - 'v*'

name: Create Release
env:
  CUSTOM_IMAGE_NAME: misogihagi_ubuntu
  CUSTOM_IMAGE_ISO: ubuntu-misogihagi-20.04.3-desktop-amd64.iso
jobs:
  build:
    name: Create Release
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
      - name: pull base image
        run: curl -LO https://releases.ubuntu.com/20.04.3/ubuntu-20.04.3-desktop-amd64.iso
      - name: install essential package
        run: sudo apt install -y squashfs-tools genisoimage
      - name: mount base image
        run: mkdir mnt && sudo mount -o loop ./ubuntu-20.04.3-desktop-amd64.iso mnt
      - name: rsync
        run: mkdir extract-cd && rsync --exclude=mnt/casper/filesystem.squashfs -a mnt/ extract-cd
      - name: unsquash
        run: sudo unsquashfs mnt/casper/filesystem.squashfs && mv squashfs-root edit
      - name: copy network
        run: sudo cp /etc/resolv.conf edit/etc/resolv.conf && sudo cp /etc/hosts edit/etc/
      - name: bind
        run: sudo mount -o bind /run/ edit/run && sudo mount --bind /dev/ edit/dev 
      - name: under chroot environment
        run: |
          cat << EOF |  script -e -c 'sudo chroot edit' 
          sudo mount -t proc none /proc && sudo mount -t devpts none /dev/pts
          export HOME=/root && export LC_ALL=C
          dbus-uuidgen | sudo tee /var/lib/dbus/machine-id && sudo dpkg-divert --local --rename --add /sbin/initctl && sudo ln -s /bin/true /sbin/initctl
          sudo mv /etc/apt/apt.conf.d/90_zsys_system_autosnapshot /etc/apt/apt.conf.d/90_zsys_system_autosnapshot.disabled
          sudo apt upgrade -y && sudo apt update -y
          #ここに好きな処理をいれる
          echo -e "\n" | sudo apt install -y git curl
          sudo apt clean && sudo rm -rf /tmp/* ~/.bash_history && sudo rm /etc/resolv.conf && sudo rm /var/lib/dbus/machine-id && sudo rm /sbin/initctl && sudo dpkg-divert --rename --remove /sbin/initctl
          sudo umount /proc || sudo umount -lf /proc && sudo umount /dev/pts
          exit
          EOF
      - name: chmod
        run: chmod +w extract-cd/casper/filesystem.manifest
      - name: renew manifest
        run: sudo dpkg-query -W --showformat='${Package} ${Version}\n' > extract-cd/casper/filesystem.manifest
      - name: modify file
        run: sudo cp extract-cd/casper/filesystem.manifest extract-cd/casper/filesystem.manifest-desktop && sudo sed -i '/ubiquity/d' extract-cd/casper/filesystem.manifest-desktop && sudo sed -i '/casper/d' extract-cd/casper/filesystem.manifest-desktop
      - name: remove file
        run: sudo rm extract-cd/casper/filesystem.squashfs
      - name: mksquashfs
        run: sudo mksquashfs edit extract-cd/casper/filesystem.squashfs -b 4096
      - name: file size
        run: printf $(du -sx --block-size=1 edit | cut -f1) | sudo tee extract-cd/casper/filesystem.size
      - name: md5sum
        run: sudo rm md5sum.txt && find -type f -print0 | sudo xargs -0 md5sum | grep -v isolinux/boot.cat | sudo tee md5sum.txt
        working-directory: ./extract-cd
      - name: mkisofs
        run: sudo mkisofs -D -r -V ${{ env.CUSTOM_IMAGE_NAME }} -cache-inodes -J -l -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -o ../${{ env.CUSTOM_IMAGE_ISO }} .
        working-directory: ./extract-cd
      - name: split iso
        run: split -b 1G -d ${{ env.CUSTOM_IMAGE_ISO }} ${{ env.CUSTOM_IMAGE_ISO }}-
      - name: Create Release
        run: |
            gh release create ${GITHUB_REF##*/} -t "Releases ${GITHUB_REF##*/}"
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - name: Upload Release Asset
        run: |
            gh release upload ${GITHUB_REF##*/} ./${{ env.CUSTOM_IMAGE_ISO }}-*
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

# はまりどころ

1. ローカルでchrootがノンインタラクションで使えない

    パイプで渡してあげればいけた

2. Github Actionsでできない

    [こういうハック](https://github.com/actions/runner/issues/241#issuecomment-577360161)があるらしい

3. sudo apt install -y git curlで止まる
    echo -e "\n"を渡さないとだめっぽい

4. mksquashfsの反応が返ってこなくなる

    -b 4096を渡してあげたら返ってくるようになった？いまだにわからない

5. githubにアップロードできない
 2GBの制限がある。ファイルを分けないといけない。