ページ

2020-06-30

virt-install + cloud-initでUbuntu 20.04をインストールする

Ubuntu 20.04 (focal)のVMをいつもの通りvirt-installと--locationを使ってセットアップしていたら、WARNINGに遭遇したので、気になっていたcloud-initでインストールしてみたところうまくいったのでまとめる。
sudo virt-install (略) --location 'http://ftp.jaist.ac.jp/pub/Linux/ubuntu/dists/focal/main/installer-amd64/' --extra-args 'console=ttyS0,115200n8 serial'
WARNING  Using legacy d-i based installer, that has been deprecated and will be removed in the future. https://discourse.ubuntu.com/c/server

概要

Ubuntu 20.04 ServerのVM「cloudtest」をUbuntu Cloud Imagesのイメージを使って、virt-installでセットアップする。 ディスクは、"vg0"というLVM volume groupにroot用, swap用のvolumeを作成して利用する。

LVMでボリュームの作成

lvcreateでボリュームを作る。
$ sudo lvcreate -n cloudtest-root -L 8G vg0
$ sudo lvcreate -n cloudtest-swap -L 4G vg0

イメージのダウンロードと展開

cloud-images.ubuntu.comからイメージをダウンロードする。QCOW2 Image (v2)形式らしいので、qemu-img convertを使って、rawイメージに変換しつつLVM volumeに流し込む。
$ wget https://cloud-images.ubuntu.com/releases/20.04/release/ubuntu-20.04-server-cloudimg-amd64.img
$ sudo qemu-img convert ubuntu-20.04-server-cloudimg-amd64.img -O raw /dev/vg0/cloudtest-root

cloud-init用の設定ファイルの作成

Ubuntu Cloud Imagesでは、インストーラでの設定入力ではなく、cloud-initで初期設定を行う。 NoCloudデータソースでは、設定内容をイメージから読んでくれるので、それを使う。そのイメージのための設定ファイルをまず用意する。 (詳しくは第561回 ローカルインストール時もcloud-initを活用する:Ubuntu Weekly Recipeを参照)

 今回の主な設定内容は以下の通り。
  • ホスト名
  • ユーザー名・初期パスワード
  • パーティションテーブルの作成
  • ファイルシステムの作成
  • マウントポイントの設定
  • ネットワーク
(その他の例はCloud config examplesを参照)

ファイルにするとこんな感じ。 ここで注意すべきなのは、networkは別ファイルだということと、disk_setupに罠があるということ。

 examplesによく出てくるdisk_setupのlayout: Trueは ドキュメントを読むと、
The layout option specifies how partitions on the device are to be arranged. If layout is set to true, a single partition using all the space on the device will be created.
とのことだが、新しめの環境とmbrでは機能しないので、Trueと同じように100%の領域を使いたい場合は以下のように指定する。
disk_setup:
  /dev/vdb:
    table_type: 'mbr'
    layout:
      - [100]
    overwrite: False
詳しくはBug #1851438 “cloud-init disk_setup fails to partition disk for ...” : Bugs : cloud-initを参照。

設定ファイルが並ぶ感じになると思うので、gitで並べる用のテンプレートを作った。hosts/{hostname}以下にconfigファイルを書いて./build-images.shするとbuild/にできる。 https://github.com/sunnyone/cloud-init-configs

cloud-init用のイメージの作成

cloud-init用のイメージの作成にはcloud-localdsコマンドが便利なので、cloud-image-utilsパッケージをインストールして使う。
$ sudo apt install cloud-image-utils
$ cloud-localds --network-config network-config.yaml user-data.img user-data

virt-installの実行

これで準備できたので、virt-installを実行してVMを作る。
sudo virt-install \
    --name cloudtest --ram 512 --arch x86_64 --vcpus 1 \
    --os-type linux --os-variant ubuntu20.04 \
    --disk path=/dev/vg0/cloudtest-root \
    --disk path=/dev/vg0/cloudtest-swap \
    --disk path=$PWD/user-data.img,device=cdrom \
    --network bridge=br0,model=virtio \
    --graphics none --serial pty --console pty \
    --import
しばらくしたら設定が完了して、sshでログインできる。

cloud-init設定のデバッグ

インストーラと違って対話的でないので、うまくいかないときは積極的なデバッグが必要。 基本的にはログを見ると良くて、ログは以下の場所にある。
  • /var/log/cloud-init-output.log
  • /var/log/cloud-init.log
詳しくはFAQを参照。 イメージごときれいにしなおしても良いが、/var/lib/cloudをきれいにするともう1度走らせることができる。
$ sudo rm -rf /var/lib/cloud/*

cloud-init用のイメージのeject

最後にuser-data.imgを外してあげておしまい。
$ sudo virsh change-media cloudtest sda --eject --config

2020-06-16

AWS Lambda + TypeScript の構成メモ

AWS Lambda の関数を Node.js + TypeScriptで書くとき、どのような構成にすると便利かまとめたメモ。デプロイにはAWS SAMを使うことを想定。

ディレクトリ構造

src/ts/functions/(スタック名)/(関数名).ts をwebpackのエントリポイントとして、以下のようなディレクトリ構造にする。
src/
  templates/        # CloudFormationテンプレート
  ts/
    functions/
      (スタック名)/
        (関数名).ts # エントリポイント
    cli/
      (関数).ts     # コマンドラインでの動作確認
    lib/            # 共通コード群(AWS Lambdaのランタイムに依存しない部分)
      foo/
        bar.ts
スタック名があるのは、デプロイパッケージ(zip)をスタック単位にすることを想定。デプロイツールの都合でここは調整したほうがいいかも。

コマンドラインで動作確認できるようにする

AWSのリソースを操作する系のLambda関数を実装する場合、その処理をコマンドラインで実行できるようにしておくと便利。 cli/にコードを配置し、ts-nodeを使ってpackage.jsonの"scripts"で呼び出せるようにしておく。
  "scripts": {
    "cli:my-operation": "ts-node src/ts/cli/my-operation.ts",
  }
コードとしては、yargsでコマンドライン引数を解析して、関数に渡すだけのイメージ。
$ yarn cli:my-operation -a my-arg

webpack設定

node_modulesを持っていけば動くのだが、productionのみにしたりと面倒なので、webpackする。 例としては、こんな感じ。 ポイントは、externals: ["aws-sdk"]。標準のものやLambda Layerで提供しているものはここで除外する。ネイティブモジュールは、Lambda Layerで提供すると良いと思う。minimize: falseはコンソールで読む用。どっちでもいい。

tsconfig.json

Node v12のときはtarget: es2019。moduleはcommonjs。

source-map-supportを入れる

webpackするとスタックトレースが不便になるので、source-map-supportを入れる。
yarn add -D source-map-support @types/source-map-support
して、各エントリポイントファイルの先頭で
import "source-map-support/register";
する感じで。

必要に応じてnpm moduleにしてシェア

CloudFormation templateと、ビルドしたjsをnpm moduleにしてnpm registryにpublishしておくと、同一構成を作りやすくて便利。