0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

autoinstallでUbuntu Server 24.04を入れるための備忘録

Posted at

モチベーション

kubeadmでKubernetesクラスタ建ててぇなァ~って思っても、自前Proxmox環境に毎回Ubuntuを建てるのがだるい。
ということで、autoinstallを使ってUbuntu VM作成をKubeadmでコンテナ環境をデプロイする手前まで一気に進めてみる。
VagrantとかTerraformとかは知らん。

TL;DR

  1. user-dataを作る

    kubeadmを実行できる直前までのサンプル
    #cloud-config
    autoinstall:
      version: 1
      identity:
        hostname: autoinstall-test
        password: (snip)
        username: thrust2799
        realname: 'thrust2799'
      network:
        version: 2
        ethernets:
          ens18:
            dhcp4: false
            addresses:
              - 192.168.100.1/24
            nameservers:
              addresses:
                - 192.168.100.254
              search:
                - mylab.home
          ens19:
            dhcp4: true
          ens20:
            addresses:
              - 172.16.1.1/24
      storage:
        config:
          - type: disk
            id: disk-0
            name: ''
            match:
              size: smallest
            ptable: gpt
            wipe: superblock
            preserve: false
          - type: partition
            id: partition-0
            device: disk-0
            number: 1
            size: 512M
            flag: boot
            preserve: false
            grub_device: true
          - type: partition
            id: partition-1
            device: disk-0
            number: 2
            size: 1G
            flag: ''
            preserve: false
            grub_device: false
          - type: partition
            id: partition-2
            device: disk-0
            number: 3
            size: -1
            flag: ''
            preserve: false
            grub_device: false
          - type: lvm_volgroup
            id: lvm_volgroup-0
            name: ubuntu-vg
            devices:
              - partition-2
            preserve: false
          - type: lvm_partition
            id: lvm_partition-0
            name: ubuntu-lv
            volgroup: lvm_volgroup-0
            size: -1
            sipe: superblock
            preserve: false
          - type: format
            id: format-0
            volume: partition-0
            fstype: fat32
            label: ESP
          - type: format
            id: format-1
            volume: partition-1
            fstype: ext4
            label: BOOT
          - type: format
            id: format-2
            volume: lvm_partition-0
            fstype: ext4
            label: ROOT
          - type: mount
            id: mount-0
            device: format-0
            path: /boot/efi
          - type: mount
            id: mount-1
            device: format-1
            path: /boot
          - type: mount
            id: mount-2
            device: format-2
            path: /
        swap:
          size: 0
      locale: "en_US.UTF-8"
      keyboard:
        layout: "jp"
      timezone: "Asia/Tokyo"
      ssh:
        install-server: true
        authorized-keys: 
          - ssh-ed25519 (snip)
        allow-pw: false
      debconf-selections: |
        openssh-server openssh-server/permit-root-login boolean false
      packages:
        - curl
        - ca-certificates
        - gpg
        - apt-transport-https
      apt:
        preserve_source_list: false
        mirror-selection:
          primary:
            - country-mirror
        geoip: true
      updates: all
      shutdown: reboot
      late-commands:
        - echo overlay | tee -a /target/etc/modules-load.d/kubernetes.conf > /dev/null
        - echo br_netfilter | tee -a /target/etc/modules-load.d/kubernetes.conf > /dev/null
        - echo net.bridge.bridge-nf-call-iptables = 1 | tee -a /target/etc/sysctl.d/kubernetes.conf > /dev/null
        - echo net.bridge.bridge-nf-call-ip6tables = 1 | tee -a /target/etc/sysctl.d/kubernetes.conf > /dev/null
        - echo net.ipv4.ip_forward = 1 | tee -a /target/etc/sysctl.d/kubernetes.conf > /dev/null
        - curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /target/etc/apt/keyrings/docker.asc
        - curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/deb/Release.key | gpg --dearmor -o /target/etc/apt/keyrings/kubernetes.gpg
        - chmod a+r /target/etc/apt/keyrings/docker.asc
        - echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu noble stable"
          | tee /target/etc/apt/sources.list.d/docker.list > /dev/null
        - echo "deb [signed-by=/etc/apt/keyrings/kubernetes.gpg] https://pkgs.k8s.io/core:/stable:/v1.32/deb /"
          | tee /target/etc/apt/sources.list.d/kubernetes.list > /dev/null
        - curtin in-target --target=/target -- apt update
        - curtin in-target --target=/target -- apt upgrade -y
        - curtin in-target --target=/target -- apt install -y containerd.io kubelet kubeadm kubectl
        - curtin in-target --target=/target -- apt-mark hold kubelet kubeadm kubectl
        - curtin in-target --target=/target -- containerd config default | tee /target/etc/containerd/config.toml > /dev/null
        - echo "KUBELET_EXTRA_ARGS=--cgroup-driver=systemd" | tee -a /target/etc/default/kubelet > /dev/null
        - sed -ie "s/SystemdCgroup = false/SystemdCgroup = true/" /target/etc/containerd/config.toml
    
  2. httpでuser-dataを配信できるようにする

  3. Ubuntu ServerのインストーラのGrubで起動パラメータをいじる

    linux /casper/vmlinuz autoinstall ip=192.168.100.1:::255.255.255.0::ens18:off ds=nocloud-net\;s=http://192.168.100.253/autoinstall-test
    

autoinstallとは

Ubuntuをインストールするときに使える自動化の仕組みとして「autoinstall」が用意されている。
RedHat系でいうところの「Kickstart」に相当する。

Ubuntu Server 20.04以降、およびUbuntu Desktop 23.04以降でサポートされている。
Cloud-Initの仕組みを利用してインストールデータを与えられるほか、インストールメディアに同梱して読み込むこともできる。

今回インストールメディアは特に加工せず、Cloud-Initの仕組みを利用して進める。

なお、Cloud-InitやYamlの仕様を概ね理解している前提とする。

user-dataを作る

前提

  • インストール対象のホスト
    • NIC1 / ens18: Cloud-Initが使えるNW、静的にアドレス割当て(192.168.100.1/24とする)
    • NIC2 / ens19: インターネット向けのNW、DHCPでアドレス自動割当て
    • NIC3 / ens20: 内部のテキトーNW
  • Cloud-Init用のホスト
    • Cloud-Initが使えるNWに接続(192.168.100.253/24とする)
  • Gateway
    • 192.168.100.254/24とする
  • インターネット向けのNW
    • OSのアップデートやパッケージ取得などのために用意しておく

大まかな構造

今回作ったuser-data大体は次の通り。
#cloud-configからversion: 1までは固定で冒頭に含める。
autoconfigは唯一のトップレベルなキー要素となる。

#cloud-config
autoinstall:
  version: 1
  identity:
    # ホスト系の設定
  network:
    # Netplanの設定
  storage:
    # インストール先ディスクの設定
  locale: # ロケール
  keyboard:
    # キーボード設定
  timezone: # タイムゾーン設定
  ssh:
    # `identity`で規定するユーザ用のSSH設定
  debconf-selections:
    # debconf関連
  packages:
    # 追加パッケージ設定
  apt:
    # aptリポジトリ設定
  updates: # インストール後のアップデート設定
  shutdown: # インストール完了後の動作
  late-commands:
    # その他、インストール完了後に併せて実施するコマンド群

identity要素

この要素へはホスト系の設定を記載する。

    hostname: autoinstall-test
    password: (snip)
    username: thrust2799
    realname: 'thrust2799'

hostnameはインストールするUbuntuのホスト名。
passwordusernameは初期ユーザとして設定する項目で、特にpasswordは平文でなくshadowで投入する必要がある。(セキュア)
realnameはオプションで、初期ユーザの本名を入れたりする。

shadow生成方法はいろいろあるが、今回はOpenSSLを利用する方法で生成する。

$ openssl password -6 -salt=<random string> <password>

network要素

この要素へはNetplanの設定を記載する。
NetplanやCloud-Init(network-config)と同じ内容になる。

  network:
    version: 2
    ethernets:
      ens18:
        dhcp4: false
        addresses:
          - 192.168.100.1/24
        nameservers:
          addresses:
            - 192.168.100.254
          search:
            - mylab.home
      ens19:
        dhcp4: true
      ens20:
        addresses:
          - 172.16.1.1/24

このあたり、本当はあまりよろしくないが自前環境では確実にens18から始まることが分かっているので、それを前提にProxmox VE側と設定を合わせている。

IF名は基本的にudevで制御されるので、たとえ物理IFだったとしてもPCIスロット番号やポート番号からある程度の予想ができる。また、その他の仮想化環境上のVMでもIF名の法則性が見られることもある。

仮想化環境のバージョンアップやLinuxカーネルのバージョンアップでNICの命名規則が変わることもあるため、本当に設定を固定したいときはMACアドレスを利用してIF名を固定すると良い。

storage要素

この要素はインストール先ディスクの設定を記載する。
省略した場合はデフォルト動作が実行されるが、複数のディスクがある場合や大容量のディスクをすべて使い切りたい場合などは個別に設定する。

今回は2本のディスクをアタッチしている状態なので、詳細なパーティション構成も含めて設定していく。
なお、おおらかに設定したいときはconfig:の代わりにlayout:が使える。
※詳細はリファレンス参照

長すぎるので折り畳み
  storage:
    config:
      - type: disk
        id: disk-0
        name: ''
        match:
          size: smallest
        ptable: gpt
        wipe: superblock
        preserve: false
      - type: partition
        id: partition-0
        device: disk-0
        number: 1
        size: 512M
        flag: boot
        preserve: false
        grub_device: true
      - type: partition
        id: partition-1
        device: disk-0
        number: 2
        size: 1G
        flag: ''
        preserve: false
        grub_device: false
      - type: partition
        id: partition-2
        device: disk-0
        number: 3
        size: -1
        flag: ''
        preserve: false
        grub_device: false
      - type: lvm_volgroup
        id: lvm_volgroup-0
        name: ubuntu-vg
        devices:
          - partition-2
        preserve: false
      - type: lvm_partition
        id: lvm_partition-0
        name: ubuntu-lv
        volgroup: lvm_volgroup-0
        size: -1
        sipe: superblock
        preserve: false
      - type: format
        id: format-0
        volume: partition-0
        fstype: fat32
        label: ESP
      - type: format
        id: format-1
        volume: partition-1
        fstype: ext4
        label: BOOT
      - type: format
        id: format-2
        volume: lvm_partition-0
        fstype: ext4
        label: ROOT
      - type: mount
        id: mount-0
        device: format-0
        path: /boot/efi
      - type: mount
        id: mount-1
        device: format-1
        path: /boot
      - type: mount
        id: mount-2
        device: format-2
        path: /
    swap:
      size: 0

type: disk:物理ディスク設定

match:でどのディスクを対象にするか制御できるが、今回は2台のみなので小さいほう(smallest)を対象にする。
GPTディスクとして使用する。

      - type: disk
        id: disk-0
        name: ''
        match:
          size: smallest
        ptable: gpt
        wipe: superblock
        preserve: false

type: partition:パーティション設定

device:で対象のディスクIDを設定し、パーティション番号とサイズ、その他設定を記載する。
size:にはfdiskで使うような補助記号(MGなど)が使えるほか、末尾のパーティションのみ-1で最大容量の割当てができる。
flag:にはパーティションに与える起動ディスクフラグなどを設定する。空の時は''を設定する。

      - type: partition
        id: partition-0
        device: disk-0
        number: 1
        size: 512M
        flag: boot
        preserve: false
        grub_device: true

type: lvm_volgroup:LVM VG設定

devices:でVGに含めるパーティションをリスト形式で追加する。

      - type: lvm_volgroup
        id: lvm_volgroup-0
        name: ubuntu-vg
        devices:
          - partition-2
        preserve: false

`type: lvm_partition:LVM LV設定

volgroup:でLVとして切り出すVGを記載する。
size:の考え方はパーティション設定と同じ。

      - type: lvm_partition
        id: lvm_partition-0
        name: ubuntu-lv
        volgroup: lvm_volgroup-0
        size: -1
        wipe: superblock
        preserve: false

type: format:ファイルシステム設定

volume:に設定対象のパーティションを記載する。lvm_partitionも設定可能。
fstype:にはフォーマット形式のファイスシステム名を記載する。(EFIならfat32固定)
label:でラベルを付けることもできる。

      - type: format
        id: format-0
        volume: partition-0
        fstype: fat32
        label: ESP

`type: mount``:マウントパス設定

device:でマウント対象のファイルシステムを記載する。
path:にはマウント先のディレクトリを記載する。

      - type: mount
        id: mount-0
        device: format-0
        path: /boot/efi

マウントオプションの指定はないっぽい。特殊なことがしたい場合はlate-command/etc/fstabをいじる方が良さそう?

その他の主要設定

ロケール設定、キーボード設定、タイムゾーン設定、SSH設定を記載している。
SSH設定については、サーバをインストールした上で初期ユーザへのログインに使用する公開鍵を登録しパスワードログインを無効化している。
また、debconf-selections:でRootユーザのログインを無効している。

  locale: "en_US.UTF-8"
  keyboard:
    layout: "jp"
  timezone: "Asia/Tokyo"
  ssh:
    install-server: true
    authorized-keys: 
      - (snip)
    allow-pw: false
  debconf-selections: |
    openssh-server openssh-server/permit-root-login boolean false

パッケージ関連設定

aptの関連設定と、追加で入れる設定だったり更新の設定だったりを記載する。
追加パッケージについてはpackages:へリスト形式で指定する。(今回はKubernetesを入れるために必要とされるものを記載している。)

apt:にはリポジトリ設定を入れているが、正直ここはデフォルトでも良さそう。
プライベートミラーや追加リポジトリがある場合はここに記載するかlate-commandで設定する。

updates:はインストール後の更新有無を記載する。
securityだとセキュリティパッチのみ、allだとすべて更新となる。

  packages:
    - curl
    - ca-certificates
    - gpg
    - apt-transport-https
  apt:
    preserve_source_list: false
    mirror-selection:
      primary:
        - country-mirror
    geoip: true
  updates: all

インストール後の挙動について

shutdown:ですべての処理が完了した後の動作を記載する。
poweroffにするとシャットダウンして電源を切る動作となる。
デフォルトはreboot(再起動)。

late-commandはインストール完了後にユーザ指定で実行するコマンドリストを与える。

  shutdown: reboot
  late-commands:
    - echo overlay | tee -a /target/etc/modules-load.d/kubernetes.conf > /dev/null
    - echo br_netfilter | tee -a /target/etc/modules-load.d/kubernetes.conf > /dev/null
    - echo net.bridge.bridge-nf-call-iptables = 1 | tee -a /target/etc/sysctl.d/kubernetes.conf > /dev/null
    - echo net.bridge.bridge-nf-call-ip6tables = 1 | tee -a /target/etc/sysctl.d/kubernetes.conf > /dev/null
    - echo net.ipv4.ip_forward = 1 | tee -a /target/etc/sysctl.d/kubernetes.conf > /dev/null
    - curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /target/etc/apt/keyrings/docker.asc
    - curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/deb/Release.key | gpg --dearmor -o /target/etc/apt/keyrings/kubernetes.gpg
    - chmod a+r /target/etc/apt/keyrings/docker.asc
    - echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu noble stable"
      | tee /target/etc/apt/sources.list.d/docker.list > /dev/null
    - echo "deb [signed-by=/etc/apt/keyrings/kubernetes.gpg] https://pkgs.k8s.io/core:/stable:/v1.32/deb /"
      | tee /target/etc/apt/sources.list.d/kubernetes.list > /dev/null
    - curtin in-target --target=/target -- apt update
    - curtin in-target --target=/target -- apt upgrade -y
    - curtin in-target --target=/target -- apt install -y containerd.io kubelet kubeadm kubectl
    - curtin in-target --target=/target -- apt-mark hold kubelet kubeadm kubectl
    - curtin in-target --target=/target -- containerd config default | tee /target/etc/containerd/config.toml > /dev/null
    - echo "KUBELET_EXTRA_ARGS=--cgroup-driver=systemd" | tee -a /target/etc/default/kubelet > /dev/null
    - sed -ie "s/SystemdCgroup = false/SystemdCgroup = true/" /target/etc/containerd/config.toml

late-commandについて

インストーラ環境からコマンド実行する内容を記載する。
基本的にインストーラのシェルで実行可能な内容のみが指定できるので、追加パッケージが必要なものはインストールした環境に入って(chrootして)から実行すると良い。

user-data要素を与えることで、再起動後のCloud-Init動作を制御することができる。
こちらで追加パッケージに関連する動作を入れても良いかもしれない。

インストールした環境でコマンドを動かす際は、動かしたいコマンドの先頭に下記を追加する。

  - curtin in-target --target=/target -- <command>

user-dataに問題がないか(最低限)確認する

これを参考にVlidationスクリプトを用意する。

依存パッケージの導入まで完了したら、./scripts/validate-autoinstall-user-data.pyにファイルを渡して問題がないか確認する。

$ ./scripts/validate-autoinstall-user-data.py ~/manifests/autoinstall-test/user-data 
Success: The provided autoinstall config validated successfully

ここでの確認は構文チェックや必須条件を満たすかの確認にとどまる。
late-commandに不備があったりnetwork要素に誤りがあっても検知してくれないので注意する。(2敗)

httpでuser-dataを配信できるようにする

作成したuser-dataファイルをUbuntuのインストーラからアクセスできるようにする。
いろいろ選択肢はあるけど、今回はDocker ComposeでHTTPサーバを建てて配信する方式を採用した。

用意したファイル

compose.yml

name: nginx-autoinstall
services:
  nginx:
    build:
      context: .
      dockerfile: dockerfile
    volumes:
      - ./manifests:/webroot # `./manifests/<hostname>/user-data`の構造で格納する
      - ./nginx.conf:/etc/nginx/conf.d/nginx.conf # Nginxの設定
    ports:
      - "80:8080"

dockerfile

FROM nginxinc/nginx-unprivileged:stable-alpine # rootless nginx

EXPOSE 8080
USER nginx

nginx.conf

server {
    listen  8080;
    server_name 192.168.100.253;

    location / {
        root    /webroot;
        index   index.html;
    }
}

Ubuntu ServerのインストーラのGrubで起動パラメータをいじる

Ubuntu ServerのISOからOSをインストールする。
この時、cmdlineとしてCloud-Initを動作させるためのパラメータを渡す必要がある。

cmdline変更方法

まずは通常通り起動し、Grubのメニュー表示を待つ。
↓この画面になったら、Try or Install Ubuntu Serverを選択した状態で「E」キーを押下する。
image.png

するとテキストエディタが表示されるので、linuxから始まる行の末尾を編集する。
image.png

cmdlineに与える情報

最終的にはこれを与える。

linux /casper/vmlinuz autoinstall ip=192.168.100.1:::255.255.255.0::ens18:off ds=nocloud-net\;s=http://192.168.100.253/autoinstall-test
  • linux /casper/vmlinuz
    • 起動するvmlinuzの指定
  • autoinstall
    • autoinstallを有効にする
  • ip=192.168.100.1:::255.255.255.0::ens18:off
    • ホストのIPアドレス設定する
    • ens18に対して静的に192.168.100.1/24を割当て
  • ds=nocloud-net\;s=http://192.168.100.253/autoinstall-test/
    • Cloud-Initの動作設定
      • nocloud-net環境での動作
      • http://192.168.100.253/autoinstall-test/user-dataなどを取りに行く
        • 先に設定したnginxコンテナの接続先を指定する
      • セミコロン(;)はエスケープする

最後に

これでautoinstallによりUbuntu Server 24.04が自動インストールされる。
再起動が完了すればSSH接続もできるようになるので、煩わしいインストール作業から解放され快適なUbuntu Server構築が実現した。
あとはkubeadmを叩くだけでKubernetesクラスタができる。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?