[Raspberry pi4] Ubuntu 20.10 のヘッドレスインストール。 キーボード、ディスプレイなしでインストールする方法

RaspberryPi

概要

ラズパイ4にUbuntu 20.10をインストールしたという話。MicroHDMIを持っていなかったので、キーボードやディスプレイを接続せずに、インストールと初期設定を行います。
Ubuntuをインストールして、PCからSSHでログインできるようにしていますが、 Cloud-init(user-data)の仕組みを活用して、起動後の作業がなるべく発生しないようにしています。

以前の記事ではUbuntuのインストール、起動後にいろいろ設定が必要でしたが、その辺を自動化した手順となっています。:[Raspberry pi3] Ubuntu 18.04 LTS のインストール(キーボード、ディスプレイ不要)

用意するもの

Raspberry Pi 4 8GB RAM
ラズパイケース
USB Type-Cの電源
MicroSDカード 128GB

アルミ製のケースは見た目もオシャレで、ヒートシンクの役割もするので良いですね。トラブルがあったときに備えてMicroHDMIのケーブルもあったほうが良さそうです。

インストールした環境

Ubuntu Server 20.10 64bit (arm64)
RAM容量が増えてるので64bit版を選びます。
用途によっては Ubuntu Server 20.04.1 LTS (arm64) を選ぶのも良いですね。

Ubuntu のダウンロードとインストール

Raspberry Pi Imager を公式サイトからダウンロードして、作業用PCにインストールします。Raspberry Pi Imager は、OSのダウンロードからSDカードへの書き込みまでやってくれます。Raspbianだけでなく、UbuntuなどのOSにも対応しているすぐれものです。

Raspberry Pi Imagerを起動したら、Ubuntu Server 20.10 64-bit (arm64) と書き込み先のSDカードを選んで、「Write」をクリックするだけです。

しばらく待つとSDカードへの書き込みが完了します。以前までは自分でOSイメージと書き込みツールを用意する必要がありこの作業も面倒でした。

起動前の設定

まだRaspberryPiは使いません。UbuntuのOSイメージが書き込まれたSDカードをもう一度、作業用PCに差し込みます。
SDカードのSystem-bootにあるファイルに、事前設定を加えることで、初回の起動時から自宅サーバーとしての下地を作っておきます。

ネットワークの設定 : network-config

SDカードにある network-config というファイルを編集することで、あらかじめネットワークの設定をすることができます。私の環境では、ここにWIFIの設定(SSID、パスワード、固定IP、DNS、デフォルトゲートウェイ)を設定しました。有線LANを使う場合は、eth0を固定IPにすれば良いかと思います。

(公式ドキュメント) https://cloudinit.readthedocs.io/en/latest/topics/network-config-format-v2.html

# network-config の設定例

version: 2
ethernets:
  eth0:
    # Rename the built-in ethernet device to "eth0"
    match:
      driver: bcmgenet smsc95xx lan78xx
    set-name: eth0
    dhcp4: true
    optional: true

wifis:
  wlan0:
    access-points:
      MYWIFI-SSID:
        password: "MYWIFI-PASSWORD"
    addresses:
      - 192.168.68.20/24
    gateway4: 192.168.68.1
    nameservers:
      addresses:
        - 192.168.68.1
    dhcp4: no
    dhcp6: no
    optional: true

ネットワークに詳しくない人は、DHCP + 有線LAN が敷居が低いです。
ただ、モニタがないとラズパイに割り当てられたIPアドレスが簡単にわからないので、user-data のパッケージインストールのところで、avahi-daemon を入れしまうと良いかもしれません。そうしておけば、IPアドレスがわからなくても、「ホスト名.local」(例:pi4.local)でアクセスできるようになります。

## パッケージのインストール
packages:
- emacs-nox
- avahi-daemon

初期設定 : user-data

今回は user-data を使って以下の設定を行いました。
ホスト名をセット:pi4.your.hostname
タイムゾーンを”Asia/Tokyo”にセット
ロケールを”ja_JP.UTF-8″にセット
SSHのパスワードでのログインを禁止
デフォルトユーザ(ubuntu)は作成しない
自分用のユーザ(myuser)を作成
SSHの公開鍵をインポート(.ssh/authorized_keysに書き込む)
Emacsをインストール
SDカードの延命措置(/tmp、/var/tmp、/var/logのRAMDISK化)

Dockerをインストール
ファイアウォールの設定

#cloud-config
 の設定例

# ホスト名の設定
hostname: pi4.your.hostname
# タイムゾーン、ロケールの設定
timezone: "Asia/Tokyo"
locale: "ja_JP.UTF-8"

# SSH でのパスワードログインを禁止
ssh_pwauth: false

# グループの作成
groups:
  - docker

# ubuntuユーザの作成を止めて、自分用ユーザーを作る。複数ユーザ作りたい場合は、-name 以下をユーザ分追記する。
users:
#  - default # ここのコメントを外すと、デフォルトユーザ(ubuntu)が作られます。
  - name: myuser
    gecos: I am an user.
    primary_group: myuser
    groups: [adm, audio, cdrom, dialout, dip, floppy, lxd, netdev, plugdev, sudo, video]
    shell: /bin/bash
    sudo: ALL=(ALL) NOPASSWD:ALL
    # パスワードログインは使わない
    lock_passwd: true
    # githubのアカウントに設定してある公開鍵をインポートする(とても便利!)
    ssh_import_id:
    - gh:my_github_account
    # githubに設定していない場合は、直接公開鍵を書いておけば良い。
#    ssh_authorized_keys:
#    - ssh-rsa AAAAB3NzaC1yc2EXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    
## 初回起動時にパッケージのアップデートを行う。お好みで設定する。
#package_update: true
#package_upgrade: true

## パッケージのインストール
packages:
- emacs-nox
# - avahi-daemon # pi4.local みたいな感じで名前解決ができる

## サーバー用途ではSDカードがすぐ壊れるので、RAMDISKを使って対策をする
## /tmp,/var/tmp,/var/logをRAMDISK化する
mounts:
  - [ tmpfs, /tmp, tmpfs, "defaults,size=256m", "0", "0" ]
  - [ tmpfs, /var/tmp, tmpfs, "defaults,size=256m", "0", "0" ]
  - [ tmpfs, /var/log, tmpfs, "defaults,size=128m", "0", "0" ]

## Docker のインストールとfirewallの設定をする
## Docker はお好みで。Firewall は必須。
runcmd:
  - apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common
  - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
  - add-apt-repository "deb [arch=arm64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
  - apt-get update -y
  - apt-get install -y docker-ce docker-ce-cli containerd.io
  - ufw limit ssh
  - ufw enable

ラズパイを起動する

SDカードをラズパイにさしたら電源を入れましょう。数分待てばラズパイが使用できるようになります。SSHでログインできたらOKです。設定例に書いた User-data だとdockerのインストールも行なっているので、cloud-init の final ステージが終わるまでに10分程度かかりました。

.ssh/authorized_keys に公開鍵がセットされていますし、ufwの設定もされています。デフォルトの ubuntu ユーザは作られなくなりました。

$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     LIMIT       Anywhere
22/tcp (v6)                LIMIT       Anywhere (v6)

最初からRAMDISKも使われています。

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           782M   20M  762M   3% /run
/dev/mmcblk0p2  116G  3.5G  107G   4% /
tmpfs           3.9G     0  3.9G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           4.0M     0  4.0M   0% /sys/fs/cgroup
tmpfs           256M     0  256M   0% /tmp
tmpfs           128M  660K  128M   1% /var/log
tmpfs           256M     0  256M   0% /var/tmp
/dev/mmcblk0p1  253M  153M  100M  61% /boot/firmware
tmpfs           782M  4.0K  782M   1% /run/user/1000

user-data についての補足

お勧めはしませんが、SSHでパスワードログインを行いたい場合は、user-dataは以下の設定をします。

# パスワードの
変更
chpasswd:
  expire: false
  list:
  - myuser:MYUSER_PASSWORD

# SSHのパスワード認証を有効にする
ssh_pwauth: true

あと、ssh_import_idで、githubの公開鍵をインポートする場合、下記のURLで自分の公開鍵が見れます。公開鍵にアクセスできるかどうか、事前にチェックしておくと良いでしょう。

https://api.github.com/users/kitter11/keys
(アカウントkitter11のところは自分のGITHUBIDに置き換えてください。)

github等の仕組みが使えない場合は、ssh_import_id の部分を消して、代わりにssh_authorized_keys に直接公開鍵を書いてしまえばOKです。

  ssh_authorized_keys:
  - ssh-rsa AAAAB3NzaC1yc2EXXXXXXXXXXXXXXXXXXXXXXXXXXXX

cloud-config(user-data)のデバッグ

user-dataの設定については、下記の公式ドキュメントを見て追記・変更をしました。

https://cloudinit.readthedocs.io/en/stable/topics/examples.html
https://cloudinit.readthedocs.io/en/latest/topics/modules.html

user-dataのトライ・アンド・エラーのやり方

cloud-initについて、知識がなかったので、設定が固まるまではトライ・アンド・エラーの繰り返しでした。自分は下記の順序で設定を作りました。

・ネットワークの設定だけは済ませて、ラズパイにログインできるようにしておく。とりあえずはubuntu/ubuntuでも良い。

・公式ドキュメントで、できそうなことを調べる

・ラズパイにログインしてからもuser-data はいじれるので、適宜編集する。

$ sudo vi /boot/firmware/user-data

・cloud-initをリセットする。

$ sudo cloud-init clean
$ cloud-init status
status: not run

・cloud-init を再実行する。

$ sudo cloud-init init
$ sudo cloud-init modules --mode config
$ sudo cloud-init modules --mode final

cloud-init には、init/config/final の3つのステージがあり、各ステージは別々に実行することができます。どのステージでどのモジュールが実行されるかは、/etc/cloud/cloud.cfg で定義されています。

# init で実行されるモジュール
cloud_init_modules:
 - migrator
 - seed_random
 - bootcmd
 - write-files
 - growpart
 - resizefs
 - disk_setup
 - mounts
 - set_hostname
 - update_hostname
 - update_etc_hosts
 - ca-certs
 - rsyslog
 - users-groups
 - ssh

# cloud-init modules --mode config で実行されるモジュール
# The modules that run in the 'config' stage
cloud_config_modules:
# Emit the cloud config ready event
# this can be used by upstart jobs for 'start on cloud-config'.
 - emit_upstart
 - snap
 - ssh-import-id
 - locale
 - set-passwords
 - grub-dpkg
 - apt-pipelining
 - apt-configure
 - ubuntu-advantage
 - ntp
 - timezone
 - disable-ec2-metadata
 - runcmd
 - byobu

# cloud-init modules --mode final で実行されるモジュール
# The modules that run in the 'final' stage
cloud_final_modules:
 - package-update-upgrade-install
 - fan
 - landscape
 - lxd
 - ubuntu-drivers
 - puppet
 - chef
 - mcollective
 - salt-minion
 - reset_rmc
 - refresh_rmc_and_interface
 - rightscale_userdata
 - scripts-vendor
 - scripts-per-once
 - scripts-per-boot
 - scripts-per-instance
 - scripts-user
 - ssh-authkey-fingerprints
 - keys-to-console
 - phone-home
 - final-message
 - power-state-change

・うまく行かなかったら /var/log/cloud-init.log を見る

まとめ

電源を入れば、基本設定の済んだUbuntuが使えるようになりました。いままでインストール後にゴニョゴニョしていた作業がなくなりとても便利です。
cloud-init は汎用的な仕組みなので、AWSでの運用にも応用ができると思います。

ぜひお試しください。

今回使った設定ファイルはGithubに。https://github.com/kitter11/RaspberryPi

わし
わし

pi3のときには、インストール後の作業が盛りだくさんだったのに、ずいぶんとスッキリしたな。次はDockerでWordpressやPostfixなどを立ち上げてラズパイ4をメインの自宅サーバーへ置き換えるべし。

わし
わし

avahi-daemon も最初に入れちゃえば、DHCPでもとりあえずホスト名でアクセスできるようになるのかなぁ。試してみるべし。

コメント

タイトルとURLをコピーしました