20210112のLinuxに関する記事は9件です。

障害時に早く作業するためのノウハウ集

目的

障害が起きた時に早く

  • 原因特定
  • 暫定対応

するために、知っておいた方が良い知識をまとめる。

ここで言う「障害」は、Web/Batch サーバの負荷が上がることを指す。

原因特定

  • ロードアベレージから問題を切り分ける
    • 1以下であれば軽く、1〜3くらいだとやや重く、それ以上だとこれらがボトルネックの可能性が高い
    • ロードアベレージが高い場合
      • CPU使用率、メモリ使用率、ディスクI/O
    • ロードアベレージが低い場合
      • TCPコネクション数
      • 他サービスの遅延
        • ネットワーク I/O はロードアベレージに換算されないので
  • 下記でコマンド紹介しているけど、理想的にはモニタリングツールでさくっと見たい
    • Datadog
    • newrelic
    • Mackerel
    • ...
  • 後コマンドも色々書いたけど、sar コマンドで大部事足りそう

ロードアベレージ

  • top コマンド
    • load average 項目に 1分 5分 15分の値が表示される
    • Tasks 項目で各状態のタスクの数を見ることができる
      • 合計タスク数 , 稼働中, 待機中, 停止タスク, ゾンビタスク

CPU使用率

  • 全体の使用率
  • アプリケーション側とカーネル空間側の切り分け
    • top コマンド
      • userはユーザモード、sysはシステム(カーネル)モードのCPU使用時間
        • 後者は、ファイルへの書き込み時のカーネルのwrite()のシステムコールなど
    • sar コマンド
      • 過去タイミングでの値も確認できる
      • %userはユーザモード、%systemはシステムモードCPU使用率
  • 該当プロセスを特定する
    • top コマンド
      • Shift+p: CPU使用率順にソート
    • ps コマンド
      • ps aux
        • a->自分以外のユーザーのプロセスについても表示
        • u->ユーザー名と開始時刻を表示
        • x->デーモンプロセスを表示
      • ps -L
        • スレッド情報も合わせて確認
        • LWP列に軽量プロセスもしくはスレッドのID、NLWP列に総スレッド数
    • passenger-status コマンド
      • passenger で処理してるプロセス一覧が表示される
  • なぜそのプロセスがボトルネックなのか特定する
    • passenger-status --show=requests コマンド
      • passenger で処理してる内容をプロセス毎に確認できる
      • 適時 PID や path で絞り込む
    • プロファイラ(oprofile)
      • プログラム全体のどこに時間がかかっているか調べる
        • どんな関数が何回呼ばれ、どのくらい時間がかかっているのか

メモリ使用率(ディスク I/O 遅延)

  • 全体の使用率
    • free コマンド
      • メモリ総量(freeコマンド1行目のtotal列)
      • ページキャッシュも含んだ利用できるメモリ量(freeコマンド2行目のfree列)
        • 同期されていないページキャッシュを含むため、本当に利用可能なメモリ量より多めに見積もってしまっている
      • 実際に利用できるメモリ量(MemFree+Inactive)
        • 「MemFreeが少ない→利用可能な物理メモリ量が足りない」わけではない
        • Inactive: 既にストレージと同期済みの捨てられるページキャッシュ
          • cat /proc/meminfo | egrep -e "Active:|Inactive:|MemFree:"
    • ps コマンド
      • VSZ(Virtual Set Size)はプロセスが確保した仮想メモリ領域のサイズ
      • RSS(Resident Set Size)は物理メモリ領域
        • 値が高い場合、大量のスワップが発生している可能性がある
    • passenger-memory-stats コマンド
      • passengerのプロセスのメモリの使用状況が確認できる
      • VMSize: 仮想メモリ領域のサイズ
      • Private: 物理メモリの領域のサイズ
  • ディスク I/O 遅延が起きているか確認
    • top コマンド
      • Dの状態が続いてるプロセスがあればその可能性あり
        • D: 割り込み不能
        • R: 実行中
        • S: スリープ状態
        • T: 停止中
        • Z: ゾンビプロセス
    • vmstat コマンド
      • cpu項の「id」列ではアイドル(空いている)割合をパーセント
      • 「wa」列ではストレージのIO完了待ち
    • swapが多発/読み書き量が増えていないか確認
      • sar -W
        • pswpin/s 1秒間にスワップインしているページ数
        • pswpout/s 1秒間にスワップアウトしているページ数
      • sar -B
        • pgpgin/s 1秒間にスワップ領域からメモリへページ・インしたキロバイト数
        • pgpgout/s 1秒間にメモリからスワップ領域へページ・アウトしたキロバイト数
  • 該当プロセスを特定する
    • top コマンド
      • Shift+m: メモリ使用率順にソート
    • passenger-status コマンド
      • passenger で処理してるプロセス一覧が表示される
  • なぜそのプロセスがボトルネックなのか特定する
    • passenger-status --show=requests コマンド
    • プロファイラ(oprofile)

ディスク空き容量

  • df コマンド
    • Used:使用しているディスク容量
    • Available:ディスクの空き容量
    • Use%:ディスク使用率
    • Mounted on:ディレクトリ
    • df -h
      • 空き容量を人が見やすいようなGB,MB,KB表示にできる
    • df ディレクトリ名
      • 各ディレクトリの空き容量
      • du コマンド
        • du -s /home
          • /homeの合計容量のみ確認

TCPコネクション数

  • netstatコマンド
    • ホストのネットワーク接続状態やソケット/インターフェイスごとのネットワーク統計などを確認する
      • ESTABLISHED状態(接続中)のコネクションのみが表示
    • netstat -an
      • -a: 現在のすべての接続を表示する
        • TCP接続に加えて、UDPやRAWソケットについてもリストアップされる
      • -n: 出力をIPアドレスなど数値のみに抑制する
      • State
        • ESTABLISHEDとなっているのが現在有効な接続
        • LISTENである接続は、外部からの接続待ち受け(ソケットのLISTEN状態)を行っている
    • netstat -s
      • IPやTCP/UDP、ICMPといったプロトコルごとの統計情報が確認

ネットワーク I/0

  • I/O 遅延が起きているか確認
    • top コマンド
      • Sの状態が続いてるプロセスがあればその可能性あり
        • ネットワークを介したデータ送受信も含むため
  • 外部サービス間で遅延が起きてないか確認
    • スロークエリの特定
      • SELECT id, time, state, substring(info,1,200) FROM INFORMATION_SCHEMA.PROCESSLIST where time > 1 and info is not null order by time desc;
    • なぜ遅いのかは実行計画を確認
      • explain select a,b from abc;

ログ調査

  • アプリケーションログ
    • rails 前提だと、Rails.logger の出力先
  • apache ログ
    • /etc/httpd/conf/httpd.conf で設定内容を確認する
  • syslog
    • /var/log
      • /etc/rsyslog.conf で設定内容を確認する

暫定対応

よく使うものを記載する。

apache

  • apacheの再起動(停止させずに)
    • # /etc/rc.d/init.d/httpd graceful

ロードバランサ

  • 外部からのトラフィックを遮断する
    • ALBからインスタンスを切り離す
      • aws コンソールの ec2 画面に入る
      • 左メニューの「ターゲットグループ」をクリック
      • 対象のターゲットグループをクリック
      • Targetsタブからインスタンスを指定して「Deregister」をクリック

プロセス停止

  • kill -USR1 [PID]
    • 止まらなければ、止めて問題ないことを確認した上で kill -9 [PID]
  • 子プロセスを停止する
    • 親プロセスをkillしても、子プロセスが停止するとは限らない
      • その場合Linuxでは「initプロセスの養子」となる
      • 一般的なデーモンプログラムなどは自分が死ぬときは基本的に子プロセスをkillする場合が多い

ロールバック

アプリケーション依存

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DLしたLaravelの環境構築方法(Linux)

 【前提条件】composerがインストール済み Lamp環境が正常に構築できている。

    githubからDLしたLaravelプロジェクトをとりあえず動かせる
    用にするまでの設定します。 

1、laravelプロジェクトをDLしてみる

ギットハブにアクセスしてとりあえず適当なLaravelのプロジェクトをDLしてみましょう【プロジェクト名testlaravel】
laravel1.png

2、composerをインストールする

DLしたtestlaravelプロジェクトのserveを起動しようとするとこのようなエラーが出てきます。

/var/www/html/testlaravel$ php artisan serve
こんなエラーが出てきます↓
PHP Warning:  require(/var/www/html/testlaravel/vendor/autoload.php): failed to open stream: No such file or directory in /var/www/html/testlaravel/artisan on line 18

Warning: require(/var/www/html/testlaravel/vendor/autoload.php): failed to open stream: No such file or directory in /var/www/html/testlaravel/artisan on line 18
PHP Fatal error:  require(): Failed opening required '/var/www/html/testlaravel/vendor/autoload.php' (include_path='.:/usr/share/php') in /var/www/html/testlaravel/artisan on line 18

Fatal error: require(): Failed opening required '/var/www/html/testlaravel/vendor/autoload.php' (include_path='.:/usr/share/php') in /var/www/html/testlaravel/artisan on line 18

Composerが入っていないためLaravelプロジェクトが起動できないのでcomposerをインストールします

/var/www/html/testlaravel# composer install

3、composerのインストールが完了したら

composerのインストールが完了したら早速testlaravelプロジェクトを立ち上げてみましょう

 /var/www/html/testlaravel# php artisan serve

立ち上がることは立ち上がりますが、ここで必ず500サーバーエラーが発生します。
500serve.png

4、.envファイルとAPP_KEYの設定を行う

ここでエラーが発生する要因としてlaravelに.envファイルが作成されていない
APP_keyが作成されていない事が要因でサーバーエラーが発生しています。

まずは.envファイルを作成してみます。コマンドで以下の用に入力します

cp .env.example .env

この段階ではまだenvファイルは作成されてませんのでAPP_KEYの作成をしてみます

php artisan key:generate

vi .envと入力して無事.envファイルが作成されていれば完成です
↓こんな奴です

APP_NAME=
APP_ENV=
APP_KEY=
APP_DEBUG=
APP_URL=

LOG_CHANNEL=

DB_CONNECTION=
DB_HOST=
DB_PORT=
DB_DATABASE=
DB_USERNAME=
DB_PASSWORD=
(以下略)

改めてtestalaravelプロジェクトを立ち上げてみていつものあのページが出てきたら成功です。
thelaravel.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

マジョカアイリス細長液晶をラズパイで使う

この記事について

ラズパイのLinux framebuffer の仕組みを使ったfbtft にて、細長液晶へ映像を送ります。
今回の記事は、デスクトップ画面を縮小転送しています。
カーネル5.4以下での方法です。

環境

ラズパイ3B+ (カーネル5.4以下。 カーネル5.4~の場合は、下の方(できない場合)を参照)
マジョカアイリス細長液晶
電源(茶色基板液晶なら6V程、みどり基板液晶なら12V程?)
https://github.com/htlabnet/inside_magimajopures/wiki/sushi_chika

接続

@komikoni さんのが見やすいです。
https://github.com/htlabnet/inside_magimajopures/blob/main/640x48_LCD_ESP32/640x48_LCD_ESP32.ino

//  1   - GND   [to GND]
//  2   - RST   [to RSPI -  4]
//  3   - GND   [to GND]
//  4   - D0    [to RSPI -  5]
//  5   - D1    [to RSPI -  6]
//  6   - D2    [to RSPI - 13]
//  7   - D3    [to RSPI - 19]
//  8   - D4    [to RSPI - 26]
//  9   - D5    [to RSPI - 12]
//  10  - D6    [to RSPI - 16]
//  11  - D7    [to RSPI - 20]
//  12  - GND   [to GND]
//  13  - RD    [to 3.3V]
//  14  - WR    [to RSPI -  7]
//  15  - CS    [to RSPI -  2]
//  16  - DC    [to RSPI -  3]
//  17  - TE    [OPEN]
//  18  - VDD   [to 3.3V]
//  19  - VDDIO [to 3.3V]
//  20  - LED+  [to 5.5V~]
//  21  - LED-  [to GND]
//  22  - GND   [to GND]

コマンド

液晶をラズパイに接続後、下記コマンド2つを実行すると、液晶が黒い画面になり、映像転送の準備OKとなります。

sudo modprobe flexfb width=320 height=96 buswidth=8 init=\
-1,0xC8,0xFF,0x93,0x42,\
-1,0x2A,0x00,0x00,0x01,0x3F,\
-1,0x2B,0x00,0x00,0x00,0x5F,\
-1,0x36,0xC8,\
-1,0xC0,0x0E,0x0E,\
-1,0xC1,0x10,\
-1,0xC5,0xFA,\
-1,0x3A,0x55,\
-1,0xB1,0x00,0x18,\
-1,0xE0,0x00,0x1C,0x21,0x02,0x11,0x07,0x3D,0x79,0x4B,0x07,0x0F,0x0C,0x1B,0x1F,0x0F,\
-1,0xE1,0x00,0x1C,0x20,0x04,0x0F,0x04,0x33,0x45,0x42,0x04,0x0C,0x0A,0x22,0x29,0x0F,\
-1,0x11,-2,130,\
-1,0x29,-2,10,\
-3

sudo modprobe fbtft_device name=flexpfb speed=10000000  gpios=reset:4,dc:3,wr:7,cs:2,db00:5,db01:6,db02:13,db03:19,db04:26,db05:12,db06:16,db07:20

(できない場合)

この記事はカーネル5.4以下でのやり方です。5.4以上でやると、flexfb 等のモジュールのmodprobe で not found になります。
fbtft リポジトリのwiki によると、カーネル5.4以降ではfbtftという名前で、デバイスツリーでの管理になってるようです。

uname -r 

で5.4 以降のカーネルが稼働している場合、このページのやり方ではできなそう
https://github.com/notro/fbtft/wiki
fbtft_device and flexfb are gone in 5.4

下記ページが参考になりそうでした
https://akkiesoft.hatenablog.jp/entry/20201218/1608217260

デスクトップの映像を転送する

https://github.com/notro/fbtft/wiki/Framebuffer-use
こちらで紹介されていた、Framebuffer mirroring の仕組みを利用します。

https://github.com/tasanakorn/rpi-fbcp
こちらの、

sudo apt-get install cmake
git clone https://github.com/tasanakorn/rpi-fbcp
cd rpi-fbcp/
mkdir build
cd build/
cmake ..
make
sudo install fbcp /usr/local/bin/fbcp

make の前に、main.c の 57行目を

    screen_resource = vc_dispmanx_resource_create(VC_IMAGE_RGB565, vinfo.xres, vinfo.yres, &image_prt);

    screen_resource = vc_dispmanx_resource_create(VC_IMAGE_RGB565, vinfo.xres*2, vinfo.yres/2, &image_prt);

に修正して、make してください。
(1ラインごとにずれている仕様を補正しているつもりです。)

fbcp

ビルドした fbcp を実行すれば、映像が細長液晶に転送されています!

ラズパイのデスクトップそのまま送られるので、いろいろ出来そう?お楽しみください♪

(ちなみに、映像をまるっと縮小コピーしてるだけなので遅いです・・・)

補足

液晶をリセットしたいときは、液晶基板への3.3v電源を抜き差して、

sudo modprobe -r flexfb
sudo modprobe -r fbtft_device 
lsmod | grep fb

でドライバがアンロードされるので、再度ドライバを読み込んでください。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Raspberry Pi 4とWSL2を使ってYocto Project入門

はじめに

先日Raspberry Pi 4でUbuntuデスクトップを動かして遊ぶでラズパイを触ってみたのですが,今度はこのラズパイをYocto Projectを使って動かしてみました.
Yoctoをはじめて使ってみたのですが,いい入門になったと思うので内容をまとめます.

Ycto Projectとは?

主には組込みおよびIoT向けのLinuxディストリビューションを作成するための仕組み・ツールが用意されています.柔軟にカスタマイズしながら組込みLinuxイメージをビルドすることができます.多くの組込みLinuxプロバイダで採用されているようです.
Yocto Project - Wikipedia

やってみたこと

手もとにあったRaspberry Pi 4をYoctoでビルドしたイメージで起動してみました.

  • Raspberry Pi 4をターゲットにしてビルド
  • 簡単なレシピを用意してHello world!
  • Wi-FiでSSH接続できるように設定
  • Pythonを追加して開発環境の構築
  • ツールチェーンを作成してクロスコンパイル環境構築

今回の開発環境

YoctoのビルドはWSL2のUbuntu 20.04 LTSで行いました.ターゲットは前述のとおりRaspberry Pi 4です.

  • Windows 10 Pro(20H2)
  • Ubuntu 20.04 LTS(WSL2)
  • Yocto Project(3.2 Gatesgarth)
  • Raspberry Pi 4(4GB)

前準備

まずはWSL2をインストールします.ディストリビューションは今回はUbuntu 20.04 LTSを使っています.
手順は例えばこちらを参考にしてください.
https://docs.microsoft.com/ja-jp/windows/wsl/install-win10

環境が立ち上がったら,とりあえずパッケージの更新を行っておきます.

$ sudo apt update && sudo apt upgrade -y

次にYocto Project Quick Startを参考にして必要なパッケージのインストールを行います.

$ sudo apt install -y gawk wget git-core diffstat unzip texinfo gcc-multilib build-essential chrpath socat cpio python python3 python3-pip python3-pexpect xz-utils debianutils iputils-ping libsdl1.2-dev xterm

Raspberry Pi 4をターゲットにしてビルド

まずはPoky(リファレンス・ディストリビューション)をGitでクローンします.
バージョンはこの時点で最新のGatesgarth(Yocto 3.2)を指定しています.
Releases - Yocto Project

$ mkdir ~/yocto && cd ~/yocto
$ git clone git://git.yoctoproject.org/poky
$ cd poky
$ git checkout -b gatesgarth-24.0.1 refs/tags/gatesgarth-24.0.1

次にRaspberry Pi用のBSPレイヤーを追加します.
OpenEmbedded Layer Indexmeta-raspberrypiというのがあるので,これをクローンします.ブランチはPokyに合わせてgatesgarthを指定しています.

$ cd ~/yocto/poky
$ git clone git://git.yoctoproject.org/meta-raspberrypi
$ cd meta-raspberrypi
$ git checkout -b gatesgarth origin/gatesgarth

meta-raspberrypiのREADMEに書かれている手順を参考にします.

Dependencies
This layer depends on:
* URI: git://git.yoctoproject.org/poky
 - branch: master
 - revision: HEAD
* URI: git://git.openembedded.org/meta-openembedded
 - layers: meta-oe, meta-multimedia, meta-networking, meta-python
 - branch: master
 - revision: HEAD

Quick Start
1. source poky/oe-init-build-env rpi-build
2. Add this layer to bblayers.conf and the dependencies above
3. Set MACHINE in local.conf to one of the supported boards
4. bitbake core-image-base
5. Use bmaptool to copy the generated .wic.bz2 file to the SD card
6. Boot your RPI

まずはoe-init-build-envを読み込んで環境をセットアップします.実行するとrpi-buildディレクトリが作成されて移動しています.ビルドはこのディレクトリで行います.

$ cd ~/yocto/poky
$ source oe-init-build-env rpi-build

次にこのレイヤーの追加設定を行います.add-layerするとconf/bblayers.confmeta-raspberrypiが追加されます.

$ bitbake-layers add-layer ../meta-raspberrypi/
$ cat conf/bblayers.conf
:
BBLAYERS ?= " \
  /home/user/yocto/poky/meta \
  /home/user/yocto/poky/meta-poky \
  /home/user/yocto/poky/meta-yocto-bsp \
  /home/user/yocto/poky/meta-raspberrypi \
  "

次にREADMEに書かれている依存レイヤーも同様に追加します.こちらもブランチはgatesgarthを指定します.またadd-layer実行する順番によってエラーが出てしまうので,下記の順で追加を行ってください.

$ cd ~/yocto/poky
$ git clone git://git.openembedded.org/meta-openembedded
$ cd meta-openembedded
$ git checkout -b gatesgarth origin/gatesgarth
$ cd ~/yocto/poky/rpi-build
$ bitbake-layers add-layer ../meta-openembedded/meta-oe/
$ bitbake-layers add-layer ../meta-openembedded/meta-python/
$ bitbake-layers add-layer ../meta-openembedded/meta-multimedia/
$ bitbake-layers add-layer ../meta-openembedded/meta-networking/
$ cat conf/bblayers.conf
:
BBLAYERS ?= " \
  /home/user/yocto/poky/meta \
  /home/user/yocto/poky/meta-poky \
  /home/user/yocto/poky/meta-yocto-bsp \
  /home/user/yocto/poky/meta-raspberrypi \
  /home/user/yocto/poky/meta-openembedded/meta-oe \
  /home/user/yocto/poky/meta-openembedded/meta-python \
  /home/user/yocto/poky/meta-openembedded/meta-multimedia \
  /home/user/yocto/poky/meta-openembedded/meta-networking \
  "

次にlocal.confMACHINEを設定します.指定するマシン名はこちらのMachinesを参考にしてください.今回は下記のように設定しています.

~/yocto/poky/rpi-build/conf/local.conf
MACHINE ?= "raspberrypi4-64"

最後にWSL2を使った場合に下記のエラーがビルド時に出てしまいました.(VMwareにインストールしたUbuntu 18.04ではこのエラーは発生しませんでした.)Stack Overflowにあった対処で解決しました.

ERROR: Task (/home/user/yocto/poky/meta/recipes-kernel/linux-libc-headers/linux-libc-headers_5.8.bb:do_install) failed with exit code '134'
~/yocto/poky/rpi-build/conf/local.conf
PSEUDO_IGNORE_PATHS_append = ",/run/"

ここまでで設定は完了です.bitbakeコマンドでビルドを実行します.ビルドにはかなり時間がかかりますし,PCもフルで動きます.気長に待ちましょう.
参考に自分のノートPC(CPU:Core i7-8550U,メモリ:16.0 GB)では3~4時間ほどかかりました.またSSDは50GBほど使用します.

$ cd ~/yocto/poky/rpi-build
$ bitbake core-image-base

またWSL2を使用している場合は下記の警告が表示されます.対処はこちらの「6. Optimize your WSLv2 storage often」参照してください.

WARNING: You are running bitbake under WSLv2, this works properly but you should optimize your VHDX file eventually to avoid running out of storage space

ビルドが完了するとrpi-build/tmp/deploy/images/raspberrypi4-64にOSイメージができあがっています.
bmaptoolコマンドを使ってcore-image-base-raspberrypi4-64.wic.bz2をSDカードに書き込みます.ただ今回使用しているWSL2環境ではSDカードのデバイス名をどのように指定するのかが分かりませんでした.

$ cd ~/yocto/poky/rpi-build/tmp/deploy/images/raspberrypi4-64
$ sudo apt install -y bmap-tools
$ sudo bmaptool copy core-image-base-raspberrypi4-64.wic.bz2 /dev/sdX  # SDカードのデバイス名をどのように指定できるのか不明

そこで今回はwic.bz2を解凍してからWindows上でRaspberry Pi Imagerを使ってSDカードに書き込みました.

$ cd ~/yocto/poky/rpi-build/tmp/deploy/images/raspberrypi4-64
$ cp core-image-base-raspberrypi4-64.wic.bz2 /tmp/.  # シンボリックリンクになっているので適当な場所にコピー
$ bunzip2 /tmp/core-image-base-raspberrypi4-64.wic.bz2
$ mv /tmp/core-image-base-raspberrypi4-64.wic /mnt/c/Users/user/Downloads/.  # Windows側の適当なディレクトリに移動

Operating SystemでUse customからcore-image-base-raspberrypi4-64.wicを選択してSDカードに書き込みます.
他にもEtcherやDD for Windowsなどで書き込んでも問題ないと思います.
image.png
作成したSDカードをラズパイに挿して電源を入れるとOSが起動します.
コンソールへの出力が止まってEnterキーを押すとlog in:と表示されるのでrootでログインします.パスワードはありません.
成功すれば最小限の環境ですがしっかりとターミナルで操作が可能です.

raspberrypi4-64 log in: root
root@raspberrypi4-64:~# uname -mnr
raspberrypi4-64 5.4.72-v8 aarch64
root@raspberrypi4-64:~# cat /etc/issue
Poky (Yocto Project Reference Distro) 3.2.1 \n \l

簡単なレシピを作成してHello world!

次は自前の簡単なソースコードを書いて,コンパイルしてできた実行バイナリをインストールする手順をまとめます.
下記が参考になります.
Creating a General Layer Using the bitbake-layers Script

まずはレイヤーを作成します.下記のコマンドを実行するとmeta-helloディレクトリとその中に雛形が作成されます.

$ cd ~/yocto/poky
$ bitbake-layers create-layer meta-hello
$ ls meta-hello/
COPYING.MIT  README  conf  recipes-example

続けて作成したレイヤーの追加設定を行います.

$ cd ~/yocto/poky/rpi-build
$ bitbake-layers add-layer ../meta-hello/
$ cat conf/bblayers.conf
:
BBLAYERS ?= " \
  /home/user/yocto/poky/meta \
  /home/user/yocto/poky/meta-poky \
  /home/user/yocto/poky/meta-yocto-bsp \
  /home/user/yocto/poky/meta-raspberrypi \
  /home/user/yocto/poky/meta-openembedded/meta-oe \
  /home/user/yocto/poky/meta-openembedded/meta-python \
  /home/user/yocto/poky/meta-openembedded/meta-multimedia \
  /home/user/yocto/poky/meta-openembedded/meta-networking \
  /home/user/yocto/poky/meta-hello \

次にソースコードを用意します.下記のようにfilesディレクトリを作成しソースコードを配置します.

$ cd ~/yocto/poky/meta-hello
$ mkdir -p recipes-hello/hello && cd recipes-hello/hello
$ mkdir files && cd files
$ vim hello.c

用意したのはC言語のHello worldです.

hello.c
#include <stdio.h>

int main(int argc, char const *argv[])
{
    printf("Hello, world!\n");
    return 0;
}

次にレシピ(パッケージのビルドのために使用されるメタデータ)を作成します.

$ cd ~/yocto/poky/meta-hello/recipes-hello/hello
$ vim hello_1.0.bb

レシピファイルの書き方はこちらが参考になります.
Single .c File Package (Hello World!)
ただし,このままではビルドに失敗するのでTARGET_CC_ARCH += "${LDFLAGS}"を追加します.
Default Linker Hash Style Changed
またLIC_FILES_CHKSUMmd5が分からない場合は空白にしておくと,ビルド時に正しい値がエラーで表示されます.

hello_1.0.bb
SUMMARY = "Simple helloworld application"
SECTION = "hello"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

TARGET_CC_ARCH += "${LDFLAGS}"

SRC_URI = "file://hello.c"

S = "${WORKDIR}"

do_compile() {
    ${CC} hello.c -o hello
}

do_install() {
    install -d ${D}${bindir}
    install -m 0755 hello ${D}${bindir}
}

最終的に次のようなディレクトリ・ファイル構成になります.

meta-hello/
├── COPYING.MIT
├── README
├── conf
│   └── layer.conf
├── recipes-example
│   └── example
│       └── example_0.1.bb
└── recipes-hello
    └── hello
        ├── files
        │   └── hello.c
        └── hello_1.0.bb

最後にlocal.confIMAGE_INSTALL_appendでイメージの追加を指定します.

~/yocto/poky/rpi-build/conf/local.conf
IMAGE_INSTALL_append = " hello"  # 先頭の空白文字が必要なので注意

ここまで準備ができたらビルドを行います.

$ cd ~/yocto/poky/rpi-build/
$ bitbake core-image-base

できあがったOSイメージをSDカードに書き込んでラズパイで起動します.ログインしてhelloコマンドが実行できることを確認します.うまくいくとHello, world!が表示されます.

raspberrypi4-64 log in: root
root@raspberrypi4-64:~# hello
Hello, world!

Wi-FiでSSH接続できるように設定

次はWi-Fi経由でSSH接続できるように設定します.
ここまでの環境で,ipコマンドで確認するとwlan0は認識されているようです.

root@raspberrypi4-64:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc mq qlen 1000
    link/ether dc:a6:32:b8:2b:4a brd ff:ff:ff:ff:ff:ff
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP8000> mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether dc:a6:32:b8:2b:4b brd ff:ff:ff:ff:ff:ff

Wi-Fi接続を行うにはConnManを使用するのが簡単そうです.local.confでイメージの追加設定を行います.
またSSH接続を行うためにOpenSSHの追加を行います.こちらを参考にしてIMAGE_FEATURESに指定するとよさそうです.

~/yocto/poky/rpi-build/conf/local.conf
IMAGE_INSTALL_append = " connman connman-client"
IMAGE_FEATURES_append = " ssh-server-openssh"

ここまででbitbake core-image-baseしてOSイメージをビルドして,SDカードからラズパイを起動します.
connmanctlコマンドを使って次の手順でWi-Fi接続設定を行います.

root@raspberrypi4-64:~# connmanctl
connmanctl> enable wifi
connmanctl> scan wifi
connmanctl> services
    Buffalo-A-0F20       wifi_dca632b82b4b_42756666616c6f2d412d30463230_managed_psk
    Buffalo-G-0F20       wifi_dca632b82b4b_42756666616c6f2d472d30463230_managed_psk
    WARPSTAR-D56FD6      wifi_dca632b82b4b_57415250535441522d443536464436_managed_psk
connmanctl> agent on
connmanctl> connect wifi_dca632b82b4b_42756666616c6f2d412d30463230_managed_psk
Passphrase?
connmanctl> exit

パスフレーズの入力まで完了したらconnmanctlを終了し,再度ipコマンドで確認するとwlan0にIPアドレスが割り振られています.
このIPアドレスにSSH接続を試すとrootでログインができるはずです.

$ ssh root@192.168.1.8  # ラズパイのwlan0に割当たっているIPアドレス
Last login: Sun Jan 10 02:06:14 2021 from 192.168.1.7
root@raspberrypi4-64:~#

SSH接続とは直接関係ないですが,手もとの開発環境でSFTPが使えると便利だったので追加しています.
ついでにrootのパスワード設定とpiユーザの新規作成も行っておきます.あわせてsudoコマンドも追加します.
またOpenSSHの追加で調べているとsystemdを有効にする設定をよく見かけたのでこれも入れておきます.

~/yocto/poky/rpi-build/conf/local.conf
IMAGE_INSTALL_append = " openssh-sftp-server sudo"
IMAGE_FEATURES_append = " ssh-server-openssh"

# user settings
INHERIT_append = " extrausers"
EXTRA_USERS_PARAMS = "useradd -P raspberry pi;usermod -P raspberry root;"

# systemd settings
DISTRO_FEATURES_append = " systemd"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_initscripts = ""
IMX_DEFAULT_DISTRO_FEATURES_append = " systemd"

ここまででビルドして,ラズパイで起動してSSH接続を確認します.(今回のビルドはまた時間がそこそこかかります.)
rootの他にpiユーザでもSSHでログインできます.パスワードは新規に設定したものを使用します.(この例だとraspberry

piユーザでsudoを使えるようにするにはrootからvisudoコマンドで設定します.

/etc/sudoers
root ALL=(ALL) ALL
pi   ALL=(ALL) ALL  # ここを追記

Pythonを追加して開発環境の構築

開発環境としてPythonを追加します.ラズパイを使っているのでrpi-gpioを追加してGPIOの制御を簡単に行ってみます.また手元にLEDなどがなかったので,raspi-gpioというGPIOを制御するコマンドを使って確認をします.

~/yocto/poky/rpi-build/conf/local.conf
IMAGE_INSTALL_append = " python3 python3-pip rpi-gpio raspi-gpio"

OSイメージをビルドしてラズパイで起動します.rootユーザで確認をしています.
Pythonとpipが使用できるか確認してみます.下記のように出力されてrpi-gpioが追加されていることも確認できます.

# python3 --version
Python 3.8.5
# python3 -m pip list
Package    Version
---------- -------
pip        20.0.2
RPi.GPIO   0.7.0
setuptools 49.6.0

raspi-gpioコマンドが使えることも確認しておきます.helpで簡単な使い方が確認できると思います.
GPIO1番ピンはデフォルトだと入力でプルアップになっているようです.

# raspi-gpio help
# raspi-gpio get 1
GPIO 1: level=1 fsel=0 func=INPUT pull=UP

PythonでGPIOを制御する簡単なサンプルコードを書きます.GPIO1番ピンを出力設定にして,1秒ごとにON/OFFを切り替えます.

gpio.py
import time
import RPi.GPIO as GPIO

def main():
    pin_num = 1
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(pin_num, GPIO.OUT)
    for i in range(10):
        GPIO.output(pin_num, i % 2)
        print(f'GPIO {"ON" if i % 2 else "OFF"}')
        time.sleep(1)
    GPIO.cleanup(pin_num)

if __name__ == '__main__':
    main()

上記のPythonコードを実行しながらraspi-gpioを繰り返し実行してGPIO1番ピンを確認すると,funcが出力に切り替わってlevelが0/1と切り替わっている様子が確認できます.

# python3 gpio.py  # 実行中に下記を別セッションで確認
# raspi-gpio get 1
GPIO 1: level=0 fsel=1 func=OUTPUT pull=NONE
# raspi-gpio get 1
GPIO 1: level=1 fsel=1 func=OUTPUT pull=NONE
# raspi-gpio get 1
GPIO 1: level=0 fsel=1 func=OUTPUT pull=NONE
# raspi-gpio get 1
GPIO 1: level=1 fsel=1 func=OUTPUT pull=NONE

GPIOをデバイスファイルから制御する方法

raspi-gpioを使わずにGPIOをデバイスファイルから制御する方法についても簡単にまとめておきます.
下記の手順で確認するとGPIO1番ピンがデフォルトでは入力になっているのが分かります.この方法でもPythonのサンプルコードを実行して出力に切り替わってON/OFFしている様子が確認できます.

# cd /sys/class/gpio
# ls
export       gpiochip0    gpiochip504  unexport
# echo 1 > export
# ls
export       gpio1        gpiochip0    gpiochip504  unexport
# cd gpio1
# ls
active_low  device      direction   edge        power       subsystem   uevent      value
# cat active_low direction value
0
in
1

ツールチェーンを作成してクロスコンパイル環境構築

最後にツールチェーンをビルドして,ローカルのPCにクロスコンパイル環境を構築します.
今回はC++のコードをビルドして動かしたのですが,実行するとlibstdc++.so.6が見つからないというエラーが出ました.C++標準ライブラリがデフォルトでは入っていなさそうなので,追加の設定を行います.

~/yocto/poky/rpi-build/conf/local.conf
IMAGE_INSTALL_append = " libstdc++"
TOOLCHAIN_TARGET_TASK_append = " libstdc++-staticdev"

ここまでの内容をまとめると,最終的にlocal.confは次の内容になっています.

~/yocto/poky/rpi-build/conf/local.conf
MACHINE ?= "raspberrypi4-64"

# for WSL2
PSEUDO_IGNORE_PATHS_append = ",/run/"

# image
IMAGE_INSTALL_append = " hello connman connman-client openssh-sftp-server sudo python3 python3-pip rpi-gpio raspi-gpio libstdc++"
IMAGE_FEATURES_append = " ssh-server-openssh"

# user settings
INHERIT_append = " extrausers"
EXTRA_USERS_PARAMS = "useradd -P raspberry pi;usermod -P raspberry root;"

# systemd settings
DISTRO_FEATURES_append = " systemd"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_initscripts = ""
IMX_DEFAULT_DISTRO_FEATURES_append = " systemd"

# for c++
TOOLCHAIN_TARGET_TASK_append = " libstdc++-staticdev"

local.confを書き終えたらOSイメージとツールチェーンのビルドを行います.ツールチェーンのビルドにはまた時間がかかりますのでゆっくりと待ちましょう.またSSDもこれまでの手順で80GBほど使用しますので注意してください.

$ cd ~/yocto/poky/rpi-build
$ bitbake core-image-base
$ bitbake core-image-base -c populate_sdk  # ツールチェーンのビルド

ビルドが完了するとrpi-build/tmp/deploy/sdkにツールチェーンができあがっています.この中の.shファイルを実行するとインストールを行うことができます.インストール先はデフォルトでは/opt/poky/3.2.1になっています.
environment-setup-cortexa72-poky-linuxを読み込むとクロスコンパイル環境を使うことができます.

$ cd ~/yocto/poky/rpi-build/tmp/deploy/sdk
$ sudo ./poky-glibc-x86_64-core-image-base-cortexa72-raspberrypi4-64-toolchain-3.2.1.sh
$ source /opt/poky/3.2.1/environment-setup-cortexa72-poky-linux

今回はC++のHello world!をCMakeを使ってビルドしてラズパイで動かしてみます.

$ mkdir ~/hello && cd ~/hello
$ vim hello.cpp
$ vim CMakeLists.txt
$ mkdir build && cd build
$ cmake ..
$ make

今回使用したhello.cppCMakeLists.txtは次の内容です.

hello.cpp
#include <iostream>

int main(int argc, char const *argv[])
{
    std::cout << "Hello, world!" << std::endl;
    return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.0.0)
project(hello VERSION 0.1.0)

set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "limited configs" FORCE)

add_executable(hello
    hello.cpp
)

target_compile_features(hello
    PRIVATE cxx_std_17
)

ビルドしてできあがった実行バイナリをreadelfコマンドで確認してみます.MachineがAArch64になっており,クロスコンパイルができていることが分かります.(今回ビルドを実施したPCはx86_64

$ readelf -h hello
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           AArch64
  Version:                           0x1
  :
$ uname -m
x86_64

実行バイナリをscpコマンドでラズパイにコピーして動かすと,Hello, world!が表示されます.

ローカルPC
$ scp ./hello root@192.168.1.8:/home/root/.
RaspberryPi
# ~/hello
Hello, world!

おわりに

今回はRaspberry Pi 4をターゲットにして,Yocto Projectを使ってLinuxをビルドし実際に動かしました.基本的な手順についてある程度は確認することができたと思います.Yoctoは日本語の情報が少ないのと,とにかくビルドに時間がかかってしまうため,初心者にはとっつきにくいところがあると感じました.この記事は,はじめてYoctoを触ってみる人にとって,ちょうどいいチュートリアルになると思います.Yoctoをはじめて触ってみる人たちの参考にしてもらえるとありがたいです.

参考にした書籍

最後に参考にした書籍の紹介です.とっかかりはYocto Project入門を参考にさせてもらいました.Yoctoをはじめて触ったので大変助かりました.今回まとめている内容も,特に前半はこちらの書籍の内容を参考にして自分の開発環境に合わせて動かし,また追加で調べながらまとめていきました.

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Shell】文字列分解の様々なパターン

はじめに

  • 用途は少ないが、文字列を1文字ずつ分解して処理する場合がある。
  • その際に、各環境で利用できるオプションや日本語問題に対応する必要がある。
  • 今回は、文字列分解コマンドの複数パターン紹介と無難パターンを記録する。

環境

  • Mac OS X 10.15.6
  • ZSH 5.7.1

結果

  • 以下、結果の内容。
# パターン1 : foldとgrep(v)の利用
# ※全角の場合は、空行が入るためgrepで削除。
echo "Good" | fold -1 | grep -v '^$'

# パターン2 : sedとtrの利用
# ※最終行が追加されるので、最後のsedで削除
echo "Good" | sed 's!.!& !g' | tr ' ' '\n' | sed '$d'

# パターン3 : sedとxargsの利用(無難)
echo "Good" | sed 's/./& /g' | xargs -n1

# パターン4 : grep(o)の利用
# ※grepのoオプションは、環境によって利用できない。(POSIX未対応のため)
echo "Good" | grep -o .
# 各パターンの出力結果
G
o
o
d

内容

パターン1

  • 主に以下のような処理。
    • foldを利用して、出力幅を1文字に限定。
    • grepのvオプションを利用して、不要な空行を削除。
      • ※半角のみであれば、foldのみで問題ない。

パターン2

  • 主に以下のような処理。
    • sedで一文字ずつ後ろにスペースを追加。
    • trで追加された改行へ置換。
    • sedで最後に追加された不要な改行を削除

パターン3

  • 主に以下のような処理。
    • sedで一文字ずつ後ろにスペースを追加。
    • xargsのnオプションを利用して、入力引数の最大値指定。

パターン4

  • 主に以下のような処理。
    • grepのoオプションを利用して、1文字ずつマッチする毎に出力。
    • ※oオプションは、環境によって利用できない場合がある。自身の環境は可能。

まとめ

  • 上記のことから、環境および全角対応等の点からパターン3のsedとxargsの利用を無難とする。
  • ただ、短述的で不要処理の無さという点から、パターン4の利用も検討する。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

KVM をインストールする

新しい PC を買って KVM をインストールしたので手順のまとめてみました。

1. Linux のインストール

まずは Linux をインストールします。今回は Ubuntu 20.04 をインストールしました。

参照: Ubuntu 20.04 LTS インストール

自分の使っている PC で仮想化をサポートしているか確認します。結果が 0 などとなる場合は CPU の BIOS の設定を確認してください。

$ egrep -c '(vmx|svm)' /proc/cpuinfo
12

これはやらなくて構いませんデフォルトのエディタを vi にして sudo をパスワードなしで実行できるようにします。

$ sudo update-alternatives --config editor
$ sudo visudo
[ユーザー名]  ALL=(ALL:ALL) NOPASSWD:ALL

上記の行を以下の行より後ろに追加します。[ユーザー名] は自分が使っているユーザー名に変更します。

%sudo   ALL=(ALL:ALL) ALL

参考: Set Vim as your default editor for Unix

2. KVM のインストール

KVM ホストに VM に関連するパッケージをインストールします。

$ sudo apt update
$ sudo apt install -y qemu qemu-kvm libvirt-daemon libvirt-clients bridge-utils virt-manager
$ sudo reboot

次に自分が使用しているユーザーを libvirt と kvm グループに追加します。既に追加されている場合は必要ありません。

$ sudo adduser `id -un` libvirt
Adding user '<username>' to group 'libvirt' ...
$ sudo adduser `id -un` kvm
Adding user '<username>' to group 'kvm' ...

virt-top や virt-df などのツールもインストールしても良いかもしれません。Python や jq なども必要あであればインストールします。

参照: KVM/Installation

libvirtd が active か、QEMU 上でもハードウェア仮想化が有効かを確認します。

$ sudo systemctl is-active libvirtd
active
$ virt-host-validate
  QEMU: Checking for hardware virtualization                                 : PASS
  QEMU: Checking if device /dev/kvm exists                                   : PASS
<snip>
  QEMU: Checking for secure guest support                                    : WARN (AMD Secure Encrypted Virtualization appears to be disabled in kernel. Add kvm_amd.sev=1 to the kernel cmdline arguments)

参照: KVM: Bare metal virtualization on Ubuntu with KVM

AMD Secure Encrypted Virtualization は仮想マシンで使用しているメモリ暗号化をハードウェアでサポートする技術のようですが KVM ホストを共有する使い方はしないのでここでは一旦無視します。

参照: AMD Secure Encrypted Virtualization (SEV)

3. ディスクの構成

例えば qcow2 イメージ用にシステムディスクとは別のディスクを使用する場合はディスクのフォーマットなどを行います。まずパーティション作成で使用する parted はここら辺が参考になりました。

参照: Parted

KVM に swap が必要かという話。あっても良いようです。

参照: 第7章 KVM でのオーバーコミット

ファイルシステムの比較をここで軽くしてみました。ここら辺は好みだと思います。

以下では KVM でのストレージプールの設定を変更しデフォルトで使用するディレクトリを変更しています。

現在の pool のストレージプールのリストを表示します。

$ virsh pool-list
 Name      State    Autostart
-------------------------------
 default   active   yes

default を削除します。

$ virsh pool-destroy default
Pool default destroyed

~$ virsh pool-undefine default
Pool default has been undefined

$ virsh pool-list
 Name     State    Autostart
------------------------------

新しく default を作成します。ここでは新しいストレージプールのディレクトリを /datasotore1/images としています。

$ virsh pool-define-as --name default --type dir --target /datastore1/images
Pool default defined

$ virsh pool-autostart default
Pool default marked as autostarted

$ virsh pool-start default
Pool default started

$ virsh pool-list
 Name      State    Autostart
-------------------------------
 default   active   yes

参照: デフォルトのストレージプールをlibvirtから変更するにはどうすればよいですか?

対象のディレクトリのパーミッションは以下の通りとなっていました。

drwxrwxr-x 2 libvirt-qemu kvm    247 Jan 11 18:10 images

この作業はもしかすると virsh pool-edit --pool default として既存の設定を変更したほうが早いかもしれません。

4. ネットワークの確認

デフォルトでは KVM インストール時に virbr0 と言う仮想ブリッジが作成されます。

$ ip addr show virbr0
4: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether 52:54:00:5e:9e:a2 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
       valid_lft forever preferred_lft forever
$ brctl show
bridge name     bridge id               STP enabled     interfaces
virbr0          8000.5254005e9ea2       yes             virbr0-nic
$ virsh net-list
 Name      State    Autostart   Persistent
--------------------------------------------
 default   active   yes         yes

このブリッジを NAT として利用して仮想マシンは外のネットワークにアクセスできます。使わない場合は消してしまっても良いと思います。もちろん消さなくても良いと思います。消すならこのあたり。

$ virsh net-destroy default
$ virsh net-undefine default

参照: https://www.cyberciti.biz/faq/linux-kvm-disable-virbr0-nat-interface/

こことか見ると以下の sysctl のパラメータを 0 にするように書かれています。

net.bridge.bridge-nf-call-ip6tables=0
net.bridge.bridge-nf-call-iptables=0
net.bridge.bridge-nf-call-arptables=0

これは恐らく br_netfilter というモジュールがロードされている場合の話。Ubuntu 20.04 ではデフォルトではロードされて無かったので必要ないと思います。多分w

5. ネットワークの設定

仮想マシンに割り当てた IP アドレス宛に外から通信したい場合は Linux 上でブリッジを作成します。Ubuntu 20.04 で netplan を使用する場合はこんな感じ。

$ cat /etc/netplan/60-eno1-config.yaml
network:
    version: 2
    ethernets:
        eno1:
            dhcp4: false
            dhcp6: false
    bridges:
        br0:
            interfaces:
                - eno1
            dhcp4: false
            dhcp6: false
            addresses:
                - 10.0.0.249/24
            gateway4: 10.0.0.1
            nameservers:
                addresses:
                    - 1.1.1.1
                    - 1.0.0.1
            parameters:
                forward-delay: 0
                stp: false
            optional: true

上記を明示的に KVM に登録することもできるが KVM ホストでブリッジを作った時点で KVM ゲストは見えるようになります。STP をどうするかは文章に寄って違ったりしますが多いのは無効。有効でも動かない落ちうことはないみたいです。

参考: CentOSのKVMで使う仮想ネットワークについて調べてみた

CentOS ではデフォルトで使用されているためと思いますが、Network Manager を使った例も沢山あります。ここら辺もお好みで。

作成したブリッジは brctl コマンドで確認することができます。

$ brctl show
bridge name     bridge id               STP enabled     interfaces
br0             8000.a0369fa9f098       no              enp4s0f0

上記で作成したブリッジを KVM ゲストに割り当てて IP アドレスを割り振れば該当の IP に対して KVM 環境の外からもアクセスすることができます。

6. 内部ネットワークを作成する

KVM の内部で使用するネットワークを作成します。virt-manager でも作れますがここでは xml ファイルから作成してみます。

まずは xml ファイルを作成します。恐らく以下が一番シンプルな記述だと思います。ここで IP アドレスや DHCP などの設定もできます。

$ cat virbr1.xml
<network>
  <name>virbr1</name>
  <bridge name='virbr1' stp='on' delay='0' />
</network>

参照: KVM (Kernel-based Virtual Machine) による仮想環境の構築手順(KVMのインストールと仮想ネットワーク作成手順)

以下のコマンドで KVM にブリッジを作成し起動時に自動で構成されるようにします。

$ virsh net-define ./virbr1.xml
Network virbr1 defined from ./virbr1.xml

$ virsh net-autostart virbr1
Network virbr1 marked as autostarted

$ virsh net-start virbr1
Network virbr1 started

正常に作成されたかは以下のコマンドで確認ができます。

$ brctl show
bridge name     bridge id               STP enabled     interfaces
virbr1          8000.525400a99a82       yes             virbr1-nic
$ virsh net-list
 Name      State    Autostart   Persistent
--------------------------------------------
 default   active   yes         yes
 virbr1    active   yes         yes

実際の設定ファイルはここにあります。uuid や mac address は自動で付与してくれます。一度登録したものは virsh net-edit コマンドで編集することができます。

$ sudo cat /etc/libvirt/qemu/networks/virbr1.xml
<!--
WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:
  virsh net-edit virbr1
or other application using the libvirt API.
-->

<network>
  <name>virbr1</name>
  <uuid>379d3199-365e-4c99-b331-77d50ed7b2ac</uuid>
  <bridge name='virbr1' stp='on' delay='0'/>
  <mac address='52:54:00:a9:9a:82'/>
</network>

参照: net-define

7. virsh をリモートで実行する

KVM ホストに直接 ssh などでログインするのはあまり好ましくない場合もあります。virsh や virt-manager で KVM の設定をしますがリモートでの実行も可能です。

virsh をリモートから実行するにはまずクライアントに libvirt-clients をインストールします。

$ sudo apt install libvirt-clients

次に以下のようなコマンドを実行します。

$ virsh -c qemu+ssh://test@10.0.0.250/system list
 Id   Name   State
----------------------
 1    c20h   running

上記の場合は ssh で接続しているため ssh の公開鍵認証などの設定をする必要があります。また .bash_aliases などに以下のように書いておくと便利かもしれません。

$ cat .bash_aliases | grep vir
alias virsh='virsh -c qemu+ssh://test@10.0.0.250/system'
$ virsh list
 Id   Name   State
----------------------
 1    c20h   running

virt-manager は GUI の File > Add Connection から設定が可能です。virsh, virt-manager 共に Windows Subsystem for Linux(WSL)上の Linux でも実行できるので便利です。

参照: SSHSetup

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GCPのUbuntuでDiskをマウントする。

現状のFilesystemを確認

dfはマウントされたファイルシステムのみを表示します。

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root        16G  4.0G   12G  26% /
devtmpfs        2.0G     0  2.0G   0% /dev
tmpfs           2.0G     0  2.0G   0% /dev/shm
tmpfs           394M  960K  393M   1% /run
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           2.0G     0  2.0G   0% /sys/fs/cgroup
/dev/sda15      105M  9.2M   96M   9% /boot/efi
/dev/loop0       56M   56M     0 100% /snap/core18/1932
/dev/loop1       56M   56M     0 100% /snap/core18/1944
/dev/loop2      130M  130M     0 100% /snap/google-cloud-sdk/161
/dev/loop3      130M  130M     0 100% /snap/google-cloud-sdk/162
/dev/loop4       71M   71M     0 100% /snap/lxd/16922
/dev/loop5       68M   68M     0 100% /snap/lxd/18150
/dev/loop6       32M   32M     0 100% /snap/snapd/10238
/dev/loop7       32M   32M     0 100% /snap/snapd/10492
tmpfs           394M     0  394M   0% /run/user/1005

新たに追加したDiskを見つける。

GCPにおいてはDiskの名前が末尾に書いてます。
(この例ではsdbが新たなに作成したディスクです。)

ll /dev/disk/by-id
lrwxrwxrwx 1 root root   9 Jan 11 16:46 scsi-0Google_PersistentDisk_mysql-2-backup -> ../../sdb

現在利用できるブロックデバイスを一覧表示する。

$ sudo lsblk
NAME    MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
loop0     7:0    0  55.3M  1 loop /snap/core18/1885
loop1     7:1    0 128.8M  1 loop /snap/google-cloud-sdk/160
loop3     7:3    0  70.6M  1 loop /snap/lxd/16922
loop4     7:4    0  55.4M  1 loop /snap/core18/1932
loop5     7:5    0 128.8M  1 loop /snap/google-cloud-sdk/159
loop6     7:6    0    31M  1 loop /snap/snapd/9607
loop7     7:7    0    31M  1 loop /snap/snapd/9721
loop8     7:8    0  67.8M  1 loop /snap/lxd/18150
sda       8:0    0    16G  0 disk 
├─sda1    8:1    0  15.9G  0 part /
├─sda14   8:14   0     4M  0 part 
└─sda15   8:15   0   106M  0 part /boot/efi
sdb       8:16   0    16G  0 disk 

フォーマット

mkfs.ext4 -F -E lazy_itable_init=0,lazy_journal_init=0,discard /dev/disk/by-id/scsi-0Google_PersistentDisk_mysql-2-backup
# mkfs.ext4 -F -E lazy_itable_init=0,lazy_journal_init=0,discard /dev/disk/by-id/scsi-0Google_PersistentDisk_mysql-2-backup
mke2fs 1.45.5 (07-Jan-2020)
Discarding device blocks: done
Creating filesystem with 4194304 4k blocks and 1048576 inodes
Filesystem UUID: a9b02fa8-593b-4ee4-9764-0bff20b8b558
Superblock backups stored on blocks:
    32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
    4096000

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

mount

$ mkdir -p /mnt/mysql-2-backup
$ mount -o discard,defaults /dev/disk/by-id/scsi-0Google_PersistentDisk_mysql-2-backup /mnt/mysql-2-backup

再起動時の自動マウント設定

/etc/fstabに下記を追加する

/dev/disk/by-id/scsi-0Google_PersistentDisk_mysql-2-backup /mnt/mysql-2-backup ext4 defaults 1 1

デバイスへの書き込みアクセスをすべてのユーザーに付与します。

chmod a+w /mnt/mysql-2-backup

fstabをバックアップ

cp /etc/fstab /etc/fstab.backup

Filesystemが認識されているか確認

sdbが増えてます。

# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root        16G  3.7G   12G  24% /
devtmpfs        2.0G     0  2.0G   0% /dev
tmpfs           2.0G     0  2.0G   0% /dev/shm
tmpfs           394M  960K  393M   1% /run
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           2.0G     0  2.0G   0% /sys/fs/cgroup
/dev/sda15      105M  9.2M   96M   9% /boot/efi
/dev/loop0       56M   56M     0 100% /snap/core18/1932
/dev/loop1       56M   56M     0 100% /snap/core18/1944
/dev/loop2      130M  130M     0 100% /snap/google-cloud-sdk/161
/dev/loop3      130M  130M     0 100% /snap/google-cloud-sdk/162
/dev/loop4       71M   71M     0 100% /snap/lxd/16922
/dev/loop5       68M   68M     0 100% /snap/lxd/18150
/dev/loop6       32M   32M     0 100% /snap/snapd/10238
/dev/loop7       32M   32M     0 100% /snap/snapd/10492
tmpfs           394M     0  394M   0% /run/user/1005
/dev/sdb         16G   45M   15G   1% /mnt/mysql-2-backup
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GCPのUbuntuでDiskをマウント、フォーマットする。

現状のFilesystemを確認

dfはマウントされたファイルシステムのみを表示します。

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root        16G  4.0G   12G  26% /
devtmpfs        2.0G     0  2.0G   0% /dev
tmpfs           2.0G     0  2.0G   0% /dev/shm
tmpfs           394M  960K  393M   1% /run
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           2.0G     0  2.0G   0% /sys/fs/cgroup
/dev/sda15      105M  9.2M   96M   9% /boot/efi
/dev/loop0       56M   56M     0 100% /snap/core18/1932
/dev/loop1       56M   56M     0 100% /snap/core18/1944
/dev/loop2      130M  130M     0 100% /snap/google-cloud-sdk/161
/dev/loop3      130M  130M     0 100% /snap/google-cloud-sdk/162
/dev/loop4       71M   71M     0 100% /snap/lxd/16922
/dev/loop5       68M   68M     0 100% /snap/lxd/18150
/dev/loop6       32M   32M     0 100% /snap/snapd/10238
/dev/loop7       32M   32M     0 100% /snap/snapd/10492
tmpfs           394M     0  394M   0% /run/user/1005

新たに追加したDiskを見つける。

GCPにおいてはDiskの名前が末尾に書いてます。
(この例ではsdbが新たなに作成したディスクです。)

ll /dev/disk/by-id
lrwxrwxrwx 1 root root   9 Jan 11 16:46 scsi-0Google_PersistentDisk_mysql-2-backup -> ../../sdb

現在利用できるブロックデバイスを一覧表示する。

$ sudo lsblk
NAME    MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
loop0     7:0    0  55.3M  1 loop /snap/core18/1885
loop1     7:1    0 128.8M  1 loop /snap/google-cloud-sdk/160
loop3     7:3    0  70.6M  1 loop /snap/lxd/16922
loop4     7:4    0  55.4M  1 loop /snap/core18/1932
loop5     7:5    0 128.8M  1 loop /snap/google-cloud-sdk/159
loop6     7:6    0    31M  1 loop /snap/snapd/9607
loop7     7:7    0    31M  1 loop /snap/snapd/9721
loop8     7:8    0  67.8M  1 loop /snap/lxd/18150
sda       8:0    0    16G  0 disk 
├─sda1    8:1    0  15.9G  0 part /
├─sda14   8:14   0     4M  0 part 
└─sda15   8:15   0   106M  0 part /boot/efi
sdb       8:16   0    16G  0 disk 

フォーマット

mkfs.ext4 -F -E lazy_itable_init=0,lazy_journal_init=0,discard /dev/disk/by-id/scsi-0Google_PersistentDisk_mysql-2-backup
# mkfs.ext4 -F -E lazy_itable_init=0,lazy_journal_init=0,discard /dev/disk/by-id/scsi-0Google_PersistentDisk_mysql-2-backup
mke2fs 1.45.5 (07-Jan-2020)
Discarding device blocks: done
Creating filesystem with 4194304 4k blocks and 1048576 inodes
Filesystem UUID: a9b02fa8-593b-4ee4-9764-0bff20b8b558
Superblock backups stored on blocks:
    32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
    4096000

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

mount

$ mkdir -p /mnt/mysql-2-backup
$ mount -o discard,defaults /dev/disk/by-id/scsi-0Google_PersistentDisk_mysql-2-backup /mnt/mysql-2-backup

再起動時の自動マウント設定

/etc/fstabに下記を追加する

/dev/disk/by-id/scsi-0Google_PersistentDisk_mysql-2-backup /mnt/mysql-2-backup ext4 defaults 1 1

デバイスへの書き込みアクセスをすべてのユーザーに付与します。

chmod a+w /mnt/mysql-2-backup

fstabをバックアップ

cp /etc/fstab /etc/fstab.backup

Filesystemが認識されているか確認

sdbが増えてます。

# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root        16G  3.7G   12G  24% /
devtmpfs        2.0G     0  2.0G   0% /dev
tmpfs           2.0G     0  2.0G   0% /dev/shm
tmpfs           394M  960K  393M   1% /run
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           2.0G     0  2.0G   0% /sys/fs/cgroup
/dev/sda15      105M  9.2M   96M   9% /boot/efi
/dev/loop0       56M   56M     0 100% /snap/core18/1932
/dev/loop1       56M   56M     0 100% /snap/core18/1944
/dev/loop2      130M  130M     0 100% /snap/google-cloud-sdk/161
/dev/loop3      130M  130M     0 100% /snap/google-cloud-sdk/162
/dev/loop4       71M   71M     0 100% /snap/lxd/16922
/dev/loop5       68M   68M     0 100% /snap/lxd/18150
/dev/loop6       32M   32M     0 100% /snap/snapd/10238
/dev/loop7       32M   32M     0 100% /snap/snapd/10492
tmpfs           394M     0  394M   0% /run/user/1005
/dev/sdb         16G   45M   15G   1% /mnt/mysql-2-backup
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Cloud9+Railsでmysqlを導入する際に手間取った記録

・Cloud9+Rails+MySQLでRailsアプリケーションを作成を試みる。
・MySQLの導入に手間取る。
・rails newをすでに実行していたため、Gemfileにmysqlを記述し、bundle installを実行するとエラー

An error occurred while installing mysql2 (0.5.2), and Bundler cannot continue.
Make sure that `gem install mysql2 -v '0.5.2' --source 'https://rubygems.org/'` succeeds before bundling.

手順

https://qiita.com/kumas/items/e2c647dca08fd46b5c7a
こちらを参考にアプリケーションの作成をしましたが、知識不足のため、手間取りました。

①作成したディレクトリに移動して、rails newを実行

②Gemfileにて

gem 'sqlite'
#デフォルトのsqliteをMySQLへ変更

gem 'mysql'

③bundle installを実行すると上記エラー

sudo yum install mysql-devel

で解決するとのことだが、これもエラーで返されてお手上げ。。

解決した方法

sudo apt-get install libmysqld-dev

「そういや、cloud9のenvironments作成時にUbuntu選択してたなぁ。そのエラーかな?」
調べるとそうでした。というか基本的なことがわかってなかった。

https://qiita.com/ryota-0906/items/2da9dcd54a6840b59364
https://qiita.com/hal-bo/items/1e0568120c545bf723c6

Ubuntu環境でパッケージ形式の違うRedHut系のyumコマンド使っていたら、そりゃエラーを返されますよね。
超絶基本的な話ですが、Linuxのパッケージファイルの形式は理解しておかないといけない。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む