イメージの扱い

イントロダクション

LXD はイメージをベースとしたワークフローを使用します。 LXD にはビルトイン のイメージ・ストアがあり、ユーザーが外部のツールがそこからイメージをインポート できます。

その後、それらのイメージからコンテナーが起動されます。

ローカルのイメージを使ってリモートのインスタンスを起動できますし、リモートの イメージを使ってローカルのインスタンスを起動することもできます。こういった ケースではイメージはターゲットの LXD にキャッシュされます。

キャッシュ

リモートのイメージからインスタンスを起動する時、リモートのイメージが ローカルのイメージ・ストアにキャッシュ・ビットをセットした状態で ダウンロードされます。イメージは、 images.remote_cache_expiry に 設定された日数だけ使われない (新たなインスタンスが起動されない) か、 イメージが期限を迎えるか、どちらか早いほうが来るまで、プライベートな イメージとしてローカルに保存されます。

LXD はイメージから新しいインスタンスが起動される度にイメージの last_used_at プロパティを更新することで、イメージの利用状況を記録しています。

自動更新

LXD はイメージを最新に維持できます。デフォルトではエイリアスで指定し リモートサーバから取得したイメージは LXD によって自動更新されます。 これは images.auto_update_cached という設定で変更できます。

(images.auto_update_interval が設定されない限り) 起動時とその後 6 時間毎に、 LXD デーモンはイメージ・ストア内で自動更新対象となっていて ダウンロード元のサーバが記録されている全てのイメージのより新しい バージョンがあるかを確認します。

新しいイメージが見つかったら、イメージ・ストアにダウンロードされ、 古いイメージを指していたエイリアスは新しいイメージを指すように変更され、 古いイメージはストアから削除されます。

リモート・サーバからイメージを手動でコピーする際に、特定のイメージを 最新に維持するように設定することもできます。

ユーザーがイメージのキャッシュから新しいインスタンスを作成しようとした時に、 アップストリームの新しいイメージ更新が公開されており、ローカルの LXD が キャッシュに古いイメージを持っている場合は、 LXD はインスタンスの作成を 遅らせるのではなく、古いバージョンのイメージを使います。

この振る舞いは現在のイメージが自動更新されるように設定されている時のみに 発生し、 images.auto_update_interval を 0 にすることで無効にできます。

プロファイル

lxc image edit コマンドを使ってイメージにプロファイルのリストを関連付けできます。 イメージにプロファイルを関連付けた後に起動したインスタンスはプロファイルを順番に適用します。 プロファイルのリストとして nil を指定すると default プロファイルのみがイメージに関連付けされます。 空のリストを指定すると、 default プロファイルも含めて一切のプロファイルをイメージに適用しません。 イメージに関連付けされたプロファイルは lxc launch--profile--no-profiles オプションを使ってインスタンス起動時にオーバーライドできます。

イメージの形式

LXD は現状 2 つの LXD に特有なイメージの形式をサポートします。

1 つめは統合された tarball で、単一の tarball がインスタンスの root と 必要なメタデータの両方を含みます。

2 つめは分離されたモデルで、 2 つのファイルを使い、 1 つは root を 含み、もう一つはメタデータを含みます。

LXD 自身によって生成されるのは前者の形式で、 LXD 特有のイメージを使う 際はこちらの形式を使うべきです。

後者は、今日既に利用可能なものとして存在している LXD 以外の rootfs tarball を使ってイメージを簡単に作成できるように想定されているものです。

統合された tarball

tarball は圧縮できます。そして次のものを含みます。

  • rootfs/
  • metadata.yaml
  • templates/ (省略可能)

このモードではイメージの識別子は tarball の SHA-256 です。

分離された tarball

2 つの (圧縮しても良い) tarball 。 1 つはメタデータ、もう 1 つは rootfs です。

metadata.tar は以下のものを含みます。

  • metadata.yaml
  • templates/ (省略可能)

rootfs.tar は、そのルートに Linux の root ファイルシステムを含みます。

このモードではイメージの識別子はメタデータと rootfs の tarball を(この順番で) 結合したものの SHA-256 です。

サポートされている圧縮形式

tarball は bz2, gz, xz, lzma, tar (非圧縮) で圧縮することができ、あるいは squashfs のイメージでも構いません。

中身

コンテナーでは rootfs のディレクトリ (あるいは tarball) は完全なファイルシステムのツリーを含み、それが / になります。 VM ではこれは代わりに root.img ファイルでメインのディスクデバイスになります。

テンプレートのディレクトリはコンテナー内で使用される pongo2 形式のテンプレート・ファイルを含みます。

metadata.yaml はイメージを (現状は) LXD で稼働されるために必要な情報を 含んでおり、これは以下のものを含みます。

architecture: x86_64
creation_date: 1424284563
properties:
  description: Ubuntu 18.04 LTS Intel 64bit
  os: Ubuntu
  release: bionic 18.04
templates:
  /etc/hosts:
    when:
      - create
      - rename
    template: hosts.tpl
    properties:
      foo: bar
  /etc/hostname:
    when:
      - start
    template: hostname.tpl
  /etc/network/interfaces:
    when:
      - create
    template: interfaces.tpl
    create_only: true

architecturecreation_date の項目は必須です。 properties は 単にイメージのデフォルト・プロパティの組です。 os, release, namedescription の項目は必須ではないですが、記載されることが多いでしょう。

テンプレートで when キーは以下の 1 つあるいは複数が指定可能です。

  • create (そのイメージから新しいインスタンスが作成されたときに実行される)
  • copy (既存のインスタンスから新しいインスタンスが作成されたときに実行される)
  • start (インスタンスが開始される度に実行される)

テンプレートは常に以下のコンテキストを受け取ります。

  • trigger: テンプレートを呼び出したイベントの名前 (string)
  • path: テンプレート出力先のファイルのパス (string)
  • container: インスタンスのプロパティ (name, architecture, privileged そして ephemeral) の key/value の map (map[string]string) (廃止予定。代わりに instance を使用してください)
  • instance: インスタンスのプロパティ (name, architecture, privileged そして ephemeral) の key/value の map (map[string]string)
  • config: インスタンスの設定の key/value の map (map[string]string)
  • devices: インスタンスに割り当てられたデバイスの key/value の map (map[string]map[string]string)
  • properties: metadata.yaml に指定されたテンプレートのプロパティの key/value の map (map[string]string)

create_only キーを設定すると LXD が存在しないファイルだけを生成し、 既存のファイルを上書きしないようにできます。

一般的な規範として、パッケージで管理されているファイルをテンプレートの 生成対象とすべきではないです。そうしてしまうとインスタンスの通常の操作で 上書きされてしまうでしょう。

利便性のため、以下の関数が pongo のテンプレートで利用可能となっています。

  • config_get("user.foo", "bar") => user.foo の値か、未設定の場合は "bar" を返します。