モニタなしでUbuntu Serverを起動する

新しい PC に Ubuntu Server をインストールしてから、もう3週間以上も経ってしまった。モニタなしで起動させるのにだいぶ苦労したけど、なんとか解決した。

どういうことかというと、インストールが問題なく終わって別の PC から SSH で接続できるのを確認したあと、もう必要ないと思ってモニタとキーボードを外して電源を入れても OS が起動しないのだ。

モニタを繋いでいれば1分もかからないくらいでちゃんと起動するのに、モニタなしだとダメ(キーボードはなくても大丈夫だった)。たっぷり5分は待ってみても SSH で接続できないし、ping も返ってこない。この状態でモニタを接続すると、起動プロセスのログ(っていうのか?)が流れて、やがてログイン待ち画面になる。どうもモニタが繋がってないせいで起動プロセスの何処かで止まってるみたいに見える。

ググってみると、GRUB っていうブートローダの設定を変えたらモニタなしでも起動できた、というブログ記事をいくつか見つけた。ただ、Ubuntu のバージョンが古かったり Raspberry Pi での話だったりして、Ubuntu Server 20.04 でも同じなのかわからなかった。とはいえ、ほかに手がかりもないので試してみた。でもダメ。そうこうしてるあいだに(週末しか作業ができなかったとはいえ)3週間以上も時間が過ぎてしまった。

で、今日見つけた情報でやっと解決したわけだ。それがこれ、Ubuntu 日本語フォーラムのページ。

このページを参考にして GRUB の設定を変更したらうまく行った。

GRUB の設定は /etc/default/grub ファイルを編集して行う。結果として次のようにした。

# If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.
# For full documentation of the options in this file, see:
#   info -f grub -n 'Simple configuration'

GRUB_DEFAULT=0
GRUB_TIMEOUT_STYLE=hidden
GRUB_TIMEOUT=0
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT=""
GRUB_CMDLINE_LINUX="nomodeset"

# Uncomment to enable BadRAM filtering, modify to suit your needs
# This works with Linux (no patch required) and with any kernel that obtains
# the memory map information from GRUB (GNU Mach, kernel of FreeBSD ...)
#GRUB_BADRAM="0x01234567,0xfefefefe,0x89abcdef,0xefefefef"

# Uncomment to disable graphical terminal (grub-pc only)
#GRUB_TERMINAL=console

# The resolution used on graphical terminal
# note that you can use only modes which your graphic card supports via VBE
# you can see them in real GRUB with the command `vbeinfo'
#GRUB_GFXMODE=640x480

# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux
#GRUB_DISABLE_LINUX_UUID=true

# Uncomment to disable generation of recovery mode menu entries
#GRUB_DISABLE_RECOVERY="true"

# Uncomment to get a beep at grub start
#GRUB_INIT_TUNE="480 440 1"

もとのファイルと diff を取るとこう(.orig がついてるのがもとのファイルのコピー)。

takatoh@navanax:~$ diff /etc/default/grub.orig /etc/default/grub
11c11
< GRUB_CMDLINE_LINUX=""
---
> GRUB_CMDLINE_LINUX="nomodeset"

/etc/default/grub ファイルを修正したら、これを反映するために sudo update-grub コマンドを実行する。

takatoh@navanax:~$ sudo update-grub

で、再起動する。

これでモニタなしでも起動するようになった。

いやー、時間がかかった。というか、モニタなしで使うことも多いであろう Server 版なのになんでモニタなしで起動できない設定になってるの?今まで使ってた Desktop 版(16.04 や 18.04)はモニタなしでもそのままでちゃんと起動してるのに。

Ubuntu Server 20.04.1 LTSのインストール

ローカルネットワークのサーバ OS 一新計画、その第一弾。新しく購入した PC に Ubuntu Server 20.04.1 LTS をインストール。

今回は先日作った USB メモリのインストールメディアからインストールした。今までは DVD を使ってたけど特に変わったことはない。もっと前から USB メモリにしときゃよかった。

Ubuntu Server のインストールは初めて。インストーラが GUI じゃないけど、基本的には Desktop 版と同じような手順。ただ一点、デフォルトでは LVM(後述)が有効になってて、使えるディスクスペースが小さい。なので LVM を無効にしてインストールをやり直した。

  • 言語の選択肢に日本語がないので「English」を選択
  • Guided storage configuration の画面で「Set up this disk as LVM group」のチェックを外す
  • ユーザー名とホスト名入力
  • 途中で OpenSSH をインストールできる
  • SSH のキーを GitHub から取得できる
  • Featured Server Snaps の画面でいろいろ追加インストールできるようだけど Docker だけ選択

ほかはデフォルトのまま。最後にリブートして終了。

LVM

LVM というのは Logical Volume Manager の略で、日本語でいうと「論理ボリュームマネージャー」。複数の物理ボリューム(HDDやSSD)をまとめてひとつの論理ボリュームを作る機能だ。本格的なサーバなんかを運用するときには、あとからディスクを追加しても LVM があれば既存の論理ボリュームを大きくすることができたりするらしいので、そういうのには便利なんだろう。だけど個人で使うだけのサーバでは不要と言っていい機能だ。なしでいいと思う。↓ここの記事が参考になった。

ローカルネットワークのサーバを置き換えるんだけど、古いRailsアプリはどうすりゃいいんだ……

置き換え用にと新しく買ったサーバ用の PC が明日届く、とメールがきた。まあ、届いたからって平日なのですぐに作業できるわけでもないんだけど……

それはさておき。現状でローカルネットワークで運用してるサーバ3台を順繰りに押し出すように置き換えていって、最後に押し出される一番古い PC は万が一のときの予備にまわす。この際だからサーバは全部 Ubuntu Server 20.04 に統一しようと、すでにインストールメディアの準備は済んでいる。

で、さて。その一番古いサーバでもいくつかの web アプリを動かしているんだけど、そのひとつがだいぶ前に Ruby on Rails で作ったものなんだ。なんと Rails 4.1.4。ちなみに OS やなんかのバージョンは次の通り:

  • Ubuntu 16.04
  • Ruby 2.3.1
  • Ruby on Rails 4.1.4
  • unicorn 5.4.1

これを最新の Ubuntu 20.04 の環境に置き換えようとしてるんだけど……

とにかく、開発用マシン(Ubuntu 20.04,Ruby 2.7.1)で動かせるかどうか試してみたら、案の定ダメだった。アプリを動かすどころか bundle install の途中でコケる。どうも json とか therubyracer の gem をインストールするところでうまく行かないみたいだ。なら DockerHub にある Ubuntu 公式イメージの一番古いバージョン 16.04 の上でならどうか、と試してみたけどやっぱりダメ。

新しい OS のサーバに移行するのに合わせてアプリもバージョンアップしなきゃな、とは思ってたんだけど、開発環境で動作させられないんじゃそれも難しい。どうすりゃいいんだか…… 

USBメモリにUbuntuのインストールメディアを作る

CentOS 8 の開発終了のニュースを受けて、ローカルネットワークのサーバ OS を置き換える計画をしてる。Ubuntu をインストールして使ってるサーバもバージョンが 16.04 で EOL が今年の4月と迫っている。そういうわけなので、この際まとめて Ubuntu 20.04 LTS に置き換えようと考えた。

今日はその準備としてインストール用メディアを作る。これまではダウンロードした ISO イメージを DVD-R に焼いてたんだけど、サーバにしてる PC は DVD ドライブついてないし(インストール時には外付けドライブを繋いだ)、せっかくなので USB メモリのインストールメディアを作ってみることにした。

作業環境は次の通り:

  • 作業用マシン:Windows 10
  • インストール用USBメモリ作成:Rufus

Rufus (ルーファス) ってのは起動可能な USB フラッシュドライブを作るソフト。↓ここからダウンロードした。

同様のソフトはほかにもあるようだけど、下調べした感じではこれが一番使いやすそうだった。メニューも日本語だし。バージョンは 3.13。

USB メモリは余ってた 16GB のもの。インストール用メディアとしてはもっと容量が小さくてもよさそうだけど、余ってるんだからそれを使う。

あと、肝心の OS は、Ubuntu Server 20.04.1 LTS。https://jp.ubuntu.com/download からダウンロードした ISO イメージを用意した。

さあ、始めよう。Rufus はインストールの必要はなく、ダウンロードしたファイルをダブルクリックして実行すればいい。

書き込み先(デバイス)と書き込む ISO イメージ(ブートの種類)の設定をしたところがこの画面。デバイスが「回復(G:) [16 GB]」ってなってるのは Windows の回復ドライブに使ってた USB メモリだから。ISO イメージは「選択」ボタンをクリックしてファイルを選択した。他はデフォルトのまま。

これで「スタート」をクリックすると

と表示されて追加のファイルをダウンロードするらしい。「はい」をクリック。

これもこのまま「OK」。

最終確認。問題なければ「OK」をクリックして書き込み開始。2分ほどで終わって↓の画面になる。

状態が「準備完了」になってるけど、これで書き込み終了してる。

試しに作ったばかりの USB メディアから PC を起動してみたら、ちゃんと Ubuntu のインストーラが起動した。

というわけで今日の任務完了。

aptあるいはDockerの怪

apt コマンドのせいなのか Docker のせいなのかわからないけど、とにかく不可解な現象に遭遇したので記録しておく。

TL;DR

  • 先月から自宅のサーバで動かしている web サービスを少しずつ Docker 上に移行する作業をしている。
  • 開発用のマシン(Ubuntu 20.04 LTS)で期待通り動作する設定(Dockerfile と docker-compose.yml)ができたのでサーバ(Ubuntu 18.04 LTS)に持っていったら Docker イメージのビルドでコケた。
  • Dockerfile の中の apt update を apt-get update に変えたら通った。

開発用のマシンにて

開発用の環境は次の通り:

  • Ubuntu 20.04.1 LTS
  • Docker version 19.03.8
  • docker-compose version 1.25.0

で、期待通り動作するように書き上げた Dockerfile はこう:

FROM ubuntu:20.04

LABEL maintainer="takatoh"

RUN apt update
RUN apt install -y \
    ruby \
    ruby-dev \
    gcc \
    g++ \
    make \
&& rm -rf /var/lib/apt/lists/*

ENV GEM_HOME /usr/local/bundle
ENV PATH $GEM_HOME/bin:$GEM_HOME/gems/bin:$PATH
RUN gem install bundler unicorn

ADD ./files/lcstorage-2.1.0.tar.gz /usr/
WORKDIR /usr/lcstorage
RUN bundle install

CMD [ "unicorn", "-c", "/var/lcstorage/unicorn.conf" ]

Ruby で書いた web アプリを unicorn で動かしている。この Dockerfile でイメージをビルドして、ちゃんと期待通りに動作するのを確認した。

サーバにて

サーバの環境は次の通り:

  • Ubuntu 18.04.5 LTS
  • Docker version 19.03.6
  • docker-compose version 1.17.1

開発用の環境よりもバージョンが旧いといえばそのとおりだけど、OS はともかく Docker や docker-compose はそんなに旧いわけではない。実際、別の web アプリを同じようにサーバで動かしていて、それをビルドしたときには何の問題もなかった。

ところが、今回この Dockerfile をもとにサーバでイメージをビルドすると途中でエラーが発生した。どうも apt コマンドでパッケージをインストールしている途中でコケるようだ。

仕方がないので手順をひとつずつ手動でやってみることにした。ubuntu:20.04 のイメージからコンテナを起動して、apt update し、パッケージを順にひとつずつ apt install した。が、なんの問題もなくすべてのパッケージのインストールができてしまった。

どういうこと?

Dockerfile を使ってビルドしたときにはパッケージのインストールのところでエラーが出てたんだから、手動でひとつずつインストールすればどのパッケージのインストールでエラーが出るのか判断できる、と考えてた。けど、手動でやったらエラーが出ずに終わってしまった。これじゃ手がかりがない。

唯一の手がかりは Dockerfile でビルドしたときのエラーログだ。次のように出ていた。

E: Failed to fetch http://security.ubuntu.com/ubuntu/pool/main/l/linux/linux-libc-dev_5.4.0-56.62_amd64.deb  404  Not Found [IP: 91.189.88.152 80]
 E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?

http://security.ubuntu.com/ubuntu/pool/main/l/linux/linux-libc-dev_5.4.0-56.62_amd64.deb が見つからない、と言ってるけど、ブラウザで見てみると確かにこの URL が示すファイルがない。

でも、じゃあなんで開発用のマシンでは問題なかったんだ?

いろいろググってはみたものの、有力な手掛かりは見つからなかった。

と、もういちどエラーメッセージを見ると、apt-get update を実行しろみたいなことが書いてある。apt じゃなくて apt-get だ。apt コマンドは apt-get コマンドの置き換えなんだからそんなの関係あるか?と思いながら、他に手掛かりがないので Dockerfile を修正してみた。こうだ:

- RUN apt update
+ RUN apt-get update

すると、どういうわけかエラーなくビルドできてしまった。

はぁ?

結論

何が起きたのかよくわからん。いや、さっぱりわかんない。

でも、とにかく動くようになったのでひとまずは良しとする。が、やっぱり釈然としない。原因を追求してみたいけど、手に負えるかなぁ……

docker-composeでMediaWikiを動かす

ローカルネットワークで wiki を運用してるんだけど、Docker 上に移行すべく、今日はそのテスト。

環境

  • Ubuntu 20.04
  • Docker 19.03.8
  • docker-compose 1.25.0

Dockerイメージ

MediaWiki も MariaDB も Docker Hub に公式イメージが有るのでそれを使わせてもらう。データベースは、はじめは MySQL を試したんだけどうまく動かなかった(原因不明)ので MariaDB に変えた。

  • mediawiki:1.35.0
  • mariadb:10.5.6-focal

ディレクトリ構成とファイル

用意した構成はこんなの:

takatoh@apostrophe:testwiki$ tree .
.
├── docker-compose.yml
├── mysql
│   └── db
└── wiki
    └── images

docker-compose.yml はこう:

version: '3'

services:
  testwiki:
    container_name: testwiki
    image: mediawiki:1.35.0
    restart: always
    ports:
      - 8888:80
    volumes:
      - ./wiki/images:/var/www/html/images
#      - ./wiki/LocalSettings.php:/var/www/html/LocalSettings.php

  mysql:
    container_name: db
    image: mariadb:10.5.6-focal
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: rootpasswd
      MYSQL_DATABASE: testwiki
      MYSQL_USER: mysqluser
      MYSQL_PASSWORD: mypassword
    ports:
      - 3306:3306
    volumes:
      - ./mysql/db:/var/lib/mysql

コメントアウトしてある行は MediaWiki の設定ファイル。これはインストールが済んでから使う。

コンテナの起動とMediaWikiのインストール

docker-compose コマンドでコンテナを起動する。

takatoh@apostrophe:testwiki$ docker-compose up -d

ブラウザで http://localhost:8888/ にアクセスして MediaWiki のインストール(というかセットアップというか)をする。その際、データベース関係は docker-compose.yml の記述に合わせる。

  • データベースのホスト:db
  • データベース名:testwiki
  • インストールで使用する利用者アカウント→データベースのユーザ名:mysqluser
  • インストールで使用する利用者アカウント→データベースのパスワード:mypassword

その他はそれなりに設定すればいい。最後に LocalSettings.php ファイル(設定ファイル)をダウンロードしてインストールは終わり。

設定の反映

いったんコンテナを止める。

takatoh@apostrophe:testwiki$ docker-compose down

ダウンロードした設定ファイルを配置。

takatoh@apostrophe:testwiki$ cp ~/Downloads/LocalSettings.php wiki

docker-compose.yml のコメントをはずす(該当行だけ示す)。

      - ./wiki/LocalSettings.php:/var/www/html/LocalSettings.php

コンテナを再起動。

takatoh@apostrophe:testwiki$ docker-compose up -d

これで無事起動した。

参考にしたページ

[追記:2020/11/5] データベースの移行

旧い wiki からデータを移行する手順。

  • データは wiki.sql ファイルにダンプしてあるものとする
  • 旧いほうの MediaWiki のバージョンは 1.27.1

wiki.sql ファイルを Docker コンテナと共有しているディレクトリにコピーする。

takatoh@apostrophe:testwiki$ cp wiki.sql ./mysql/db

./mysql/db ディレクトリは、データベースの Docker コンテナ(コンテナ名は db)からは /var/lib/mysql として認識されている(前述の docker-compose.yml ファイルを参照)。なのでデータベースのコンテナに接続して、データを流し込む。

takatoh@apostrophe:testwiki$ docker exec -it db bash
root@007d71dfcb37:/# cd /var/lib/mysql
root@007d71dfcb37:/var/lib/mysql# ls *.sql
wiki.sql
root@007d71dfcb37:/var/lib/mysql# mysql -u mysqluser -p testwiki < wiki.sql
Enter password:
root@007d71dfcb37:/var/lib/mysql# exit
exit

これでデータベース側での作業は終了。ただ、このままだと MediaWiki でエラーになる。バージョンが上がっているので MediaWiki の使用するデータベーススキーマとかも変わっているからだ。

そこで、MediaWiki のコンテナに接続して更新スクリプトを実行する。更新スクリプトは /var/www/html/maintenance/update.php だ。

takatoh@apostrophe:testwiki$ docker exec -it testwiki bash
root@f92dd50471e5:/var/www/html# cd maintenance
root@f92dd50471e5:/var/www/html/maintenance# php update.php

これで完了。

[追記]

11/7、本番環境も無事 Docker 上に移行した。

Ubuntu 20.04に最新のGolangをインストール

といっても公式サイトからダウンロードして展開して PATH を通すだけ。バージョンは 1.15.2 だった。

インストール手順。まずはダウンロードした tarball を /usr/local 以下に展開。

takatoh@apostrophe:Downloads$ sudo tar -C /usr/local -xzf go1.15.2.linux-amd64.tar.gz

/usr/loca/go/bin に PATH を通す。

export PATH=$PATH:/usr/local/go/bin

ついでに GOPATH を設定しておく。

export GOPATH=$HOME/go/thirdparty:$HOME/go/projects

go version コマンドでバージョンが表示されれば OK。

takatoh@apostrophe:~$ go version
go version go1.15.2 linux/amd64

すんごい楽だな。

新しいPCにUbuntu 20.04 LTSをインストール

メインに使っている PC を買い替えた。

先日ダウンロードしておいた Ubuntu 20.04 LTS 日本語 Remix を DVD に焼いて(この作業は別の Windows マシンでやった)、プリインストールされていた Windows 10 は起動すらせずに上書きインストールした。ホスト名は替える前と同じ apostrophe。

OS のインストールが終わったら、とりあえずすぐに使いそうなソフトウェアだけインストールした。

  • rbenv と Ruby (2.7.1)
  • pyenv と Python (3.8.2)
  • Git
  • Sublime text
  • Dropbox
  • Tweaks
  • Docker

Python はデフォルトで入っていた(コマンドとしては python3)けど、今後を考えて pyenv を使った。Tweaks というのは、参考にした web ページにあった設定ツール。デスクトップまわりの設定ができる。

Docker についてはインストール方法を書いておこう。最初は先日 16.04 にインストールしたのを参考に作業をしたんだけどダメだった。えぇっ?と思いながらググってみると、apt コマンドでインストールできるようになっていた。

takatoh@apostrophe:~$ sudo apt install -y docker.io
takatoh@apostrophe:~$ sudo systemctl start docker
takatoh@apostrophe:~$ sudo systemctl enable docker

ついでに docker-compose もインストール(今後使う予定なので)。

takatoh@apostrophe:~$ sudo apt install -y docker-compose

あとはいくつか設定をカスタマイズして、データをバックアップサーバからコピーしてきて、ひとまずは完了。のこりは必要に応じてやっていこう。

参考にしたページ:

Ubuntu 16.04にDockerをインストール

公式サイトのドキュメントを参考にした。

下準備

まずは古いバージョンの Docker Engine をアンインストールせよ、とのことだけど、今回ははじめてインストールするのでこの作業はパス。

なので最初にするのは apt-get update

takatoh@apostrophe $ sudo apt-get update

必要なパッケージをインストール。

takatoh@apostrophe $ sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common

すでに全部インストールされていたようだ。

つぎに Docker 公式の GPG key をインストール。

takatoh@apostrophe $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
OK

ちゃんとインストールできたか確認。

takatoh@apostrophe $ sudo apt-key fingerprint 0EBFCD88
pub 4096R/0EBFCD88 2017-02-22
    フィンガー・プリント = 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88
uid Docker Release (CE deb) [email protected]
sub 4096R/F273FCD8 2017-02-22

なんかドキュメントの例と出力が違うけど、日付とフィンガー・プリントが合ってるから大丈夫なんだろう。

リポジトリを登録。

takatoh@apostrophe $ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

途中に出てくる lsb_release -cs コマンドは Ubuntu ディストリビューションの名前を返す。↓こんな感じ。

takatoh@apostrophe $ lsb_release -cs
xenial

Docker Engineのインストール

takatoh@apostrophe $ sudo apt-get update
takatoh@apostrophe $ sudo apt-get install docker-ce docker-ce-cli containerd.io

最後に hello-world イメージを走らせてみて、ちゃんとインストールできてるかを確認。

takatoh@apostrophe $ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete
Digest: sha256:8e3114318a995a1ee497790535e7b88365222a21771ae7e53687ad76563e8e76
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

大丈夫そうだ。