10
7

More than 5 years have passed since last update.

MatchBoxを使ってCoreOS Container Linuxをベアメタルにプロビジョンする

Posted at

はじめに

この記事はMicroAd Advent Calendar 2017の8日目の記事です。

内容はMatchBoxを使ってCoreOS Container Linuxをベアメタルにプロビジョンする全体像の続きになります。
実際にCoreOSをベアメタル環境にデプロイするにあたり、必要な環境やら設定やらを整えます。

Matchboxサーバの用意

Machboxサーバを実際に構築します。SystemdがinitのLinux前提です。
大体、ここに書いてあることまんまです。
GithubからもろもろDLして解凍してディレクトリ内に移動します。

$ wget https://github.com/coreos/matchbox/releases/download/v0.6.1/matchbox-v0.6.1-linux-amd64.tar.gz
$ tar xvfz matchbox-v0.6.1-linux-amd64.tar.gz
$ cd matchbox-v0.6.1-linux-amd64

中身はこんな感じです。

$ ls   
CHANGES.md  LICENSE  README.md  contrib  docs  examples  matchbox  scripts

バイナリをパスが通る場所に配置します。

$ sudo cp matchbox /usr/local/bin

Systemdのユニットファイルを配置します。

$ sudo cp contrib/systemd/matchbox-local.service /etc/systemd/system/matchbox.service

中身はこんな感じです。

/etc/systemd/system/matchbox.service
[Unit]
Description=CoreOS matchbox Server
Documentation=https://github.com/coreos/matchbox

[Service]
User=matchbox
Group=matchbox
Environment="MATCHBOX_ADDRESS=0.0.0.0:8080"
ExecStart=/usr/local/bin/matchbox

# systemd.exec
ProtectHome=yes
ProtectSystem=full

[Install]
WantedBy=multi-user.target

matchbox実行ユーザやデータディレクトリを作成します。

$ sudo useradd -U matchbox
$ sudo mkdir -p /var/lib/matchbox/assets
$ sudo chown -R matchbox:matchbox /var/lib/matchbox

次にTerraformからの接続で使うTLS証明書を用意します。
scripts/tls/cert-genに証明書作成用のスクリプトが置いてあります。
環境変数SANにより、証明書のSANを設定できます。
使用するサーバのFQDN、あるいはIPを設定して、証明書を作成します。

$ export SAN=DNS.1:matchbox.microad.jp,IP.1:172.18.0.2
$ cd scripts/tls/
$ ./cert-gen

サーバ側の資格情報を配置します。

$ sudo mkdir -p /etc/matchbox
$ sudo cp ca.crt server.crt server.key /etc/matchbox

また、クライアント側の資格情報は後で使用するので保存します。
手元に持ってきておきましょう。client.crt,client.key,ca.crt

ここまで来れば、systemdのUnitを起動します。

$ sudo systemctl daemon-reload
$ sudo systemctl start matchbox
$ sudo systemctl enable matchbox

また、オプションですがCoreOSのイメージをネットワークブートサーバが直でインターネットからダウンロードする代わりにMatchBoxから配布することも可能です。

DLしたMatchboxのディレクトリ内に便利なDLスクリプトが付随しています。

$ cd ~/matchbox-v0.6.1-linux-amd64
$ sudo ./scripts/get-coreos beta 1590.2.0 /var/lib/matchbox/assets
Creating directory /var/lib/matchbox/assets/coreos/1590.2.0
Downloading CoreOS beta 1590.2.0 images and sigs to /var/lib/matchbox/assets/coreos/1590.2.0
CoreOS Image Signing Key
略

こんな感じにアセットファイルが配置されます。

$ ls /var/lib/matchbox/assets/coreos/1590.2.0/     
CoreOS_Image_Signing_Key.asc     coreos_production_image.bin.bz2.sig  coreos_production_pxe.vmlinuz.sig    coreos_production_pxe_image.cpio.gz.sig
coreos_production_image.bin.bz2  coreos_production_pxe.vmlinuz        coreos_production_pxe_image.cpio.gz

PXE環境の用意

PXE環境のセットアップについてはDHCP/TFTP/DNS全部乗せのコンテナイメージをCoreOS社が提供しており、これを使えば一発で環境準備できます。

sudo docker run --rm --cap-add=NET_ADMIN --net=host quay.io/coreos/dnsmasq \
  -d -q \
  --dhcp-range=172.18.1.2,172.18.1.254 \
  --enable-tftp --tftp-root=/var/lib/tftpboot \
  --dhcp-userclass=set:ipxe,iPXE \
  --dhcp-boot=tag:#ipxe,undionly.kpxe \
  --dhcp-boot=tag:ipxe,http://matchbox.microad.jp:8080/boot.ipxe \
  --address=/matchbox.microad.jp/172.18.0.2 \
  --log-queries \
  --log-dhcp

とりあえず検証で動かす分には上記のDockerImageで十分です。
注意点として
--dhcp-rangeは付加したいDHCPのIPレンジを渡しましょう
--dhcp-bootは使用するmatchboxサーバのアドレスを渡しましょう
--addressはmatchboxサーバのFQDNとIPを渡しましょう

以上でMatchboxサーバ、PXEサーバ側の設定は完了です。

Terraform pluginを準備

以後はTerraformを使って諸々の設定をデプロイする準備になります。

Matchbox用のTerraformプラグインはGithubからDLして、Terraformのpluginディレクトリに配置しましょう。
https://github.com/coreos/terraform-provider-matchbox/releases

また、Matchboxで作成したTLSのクライアン側の資格情報(client.crt,client.key,ca.crt)がTerraformデプロイに必要になるので、~/.matchboxに配置しましょう。

$  ls ~/.matchbox/
ca.crt  client.crt  client.key

tfファイルの作成

では実際にtfファイルを作成していきます。

とりあえずこんな感じのtree構造で作成してみます。

$ tree matchbox.microad.jp
matchbox.microad.jp
├── cl
│   ├── container-linux-install.yaml.tmpl
│   └── static.yaml.tmpl
├── container-linux-install.tf
├── provider.tf
├── static.tf
├── terraform.tfvars
└── variables.tf

clディレクトリにはContaine linux configのyamlをgoのtemplate形式でレンダリングしたものを配置します。

まずはprovider.tfですがこんな感じでmatchboxのエンドポイントとtlsの資格情報を記入します。

provider "matchbox" {
  endpoint    = "${var.matchbox_rpc_endpoint}"
  client_cert = "${file("~/.matchbox/client.crt")}"
  client_key  = "${file("~/.matchbox/client.key")}"
  ca          = "${file("~/.matchbox/ca.crt")}"
}

次に実際のCoreOSのインストールなんですが、最初PXEブートしてきた時、CoreOSのOSイメージはメモリ上に展開されます。
その後、メモリ上に展開されたCoreOSにバンドルされているcoreos-installを使ってディスクにインストールがされるという流れになります。

そのRAMにCoreOSを展開するための設定が以下になります。

container-linux-install.tf
resource "matchbox_profile" "container-linux-install" {
  name   = "container-linux-install"
  kernel = "/assets/coreos/${var.container_linux_version}/coreos_production_pxe.vmlinuz"

  initrd = [
    "/assets/coreos/${var.container_linux_version}/coreos_production_pxe_image.cpio.gz",
  ]

  args = [
    "initrd=coreos_production_pxe_image.cpio.gz",
    "coreos.config.url=${var.matchbox_http_endpoint}/ignition?uuid=$${uuid}&mac=$${mac:hexhyp}",
    "coreos.first_boot=yes",
    "console=tty0",
    "console=ttyS0",
  ]

  container_linux_config = "${data.template_file.container-linux-install-config.rendered}"
}

data "template_file" "container-linux-install-config" {
  template = "${file("./cl/container-linux-install.yaml.tmpl")}"

  vars {
    container_linux_channel = "${var.container_linux_channel}"
    container_linux_version = "${var.container_linux_version}"
    ignition_endpoint       = "${format("%s/ignition", var.matchbox_http_endpoint)}"
    install_disk            = "${var.install_disk}"

    baseurl_flag = "-b ${var.matchbox_http_endpoint}/assets/coreos"
  }
}

resource "matchbox_group" "default" {
  name    = "default"
  profile = "${matchbox_profile.container-linux-install.name}"

  metadata {
    ssh_authorized_key = "${var.ssh_authorized_key}"
  }
}

2つのリソースと1つのdataが定義されています。
matchbox_profileリソースはどんなclファイルをやイメージを使ってBootするか、といった設定のまとまりのリソースになります。
matchbox_groupはどのノードがどのmatchbox_profileを使うか?といったルーティングを行うリソースになります。
template_fileは単なるterrafomの機能のtemplateです。
ややこしいですがgoでtemplate化されたyamlファイルをterraformのtemplateにより生成しています。
中身は以下のような感じです。

cl/container-linux-install.yaml.tmpl
---
systemd:
  units:
    - name: installer.service
      enable: true
      contents: |
        [Unit]
        Requires=network-online.target
        After=network-online.target
        [Service]
        Type=simple
        ExecStart=/opt/installer
        [Install]
        WantedBy=multi-user.target
storage:
  files:
    - path: /opt/installer
      filesystem: root
      mode: 0500
      contents:
        inline: |
          #!/bin/bash -ex
          curl --retry 10 "${ignition_endpoint}?{{.request.raw_query}}&os=installed" -o ignition.json
          coreos-install \
            -d ${install_disk} \
            -C ${container_linux_channel} \
            -V ${container_linux_version} \
            ${baseurl_flag} \
            -i ignition.json
          udevadm settle
          systemctl reboot
passwd:
  users:
    - name: core
      ssh_authorized_keys:
        - {{.ssh_authorized_key}}

OSイメージが起動してくるとinstaller.serviceというSystemdのユニットが起動し、CoreOSをディスクにインストールします。
その際、Matchboxにignition設定を要求するhttpリクエストにos=installedというクエリパラメータを付けることで実際にディスクインストールされる際に、別のmatchbox_profileが適用されるようにします。

以下が実際にディスクにインストールされるCoreOSのmatchbox_profileになります。

static.tf
resource "matchbox_profile" "static" {
  name                   = "static"
  container_linux_config = "${file("./cl/static.yaml.tmpl")}"
}

resource "matchbox_group" "static" {
  count   = "${length(var.static_names)}"
  name    = "${element(var.static_names, count.index)}"
  profile = "${matchbox_profile.static.name}"

  selector {
    os  = "installed"
    mac = "${element(var.static_macs, count.index)}"
  }

  metadata {
    hostname = "${element(var.static_names, count.index)}"
    ssh_authorized_key = "${var.ssh_authorized_key}"
    ip_addr = "${element(var.static_ips, count.index)}"
  }
}

matchbox_groupのリソースのselectorセクションが、実際にそのGroupを適用させるための条件になるんですがここにMACアドレスを指定することで、特定のMACアドレスのサーバに対して任意の設定を設定する事が可能となります。
また、metadataセクションはclファイルをレンダリングする際に渡す事ができるパラメータになっています。

今回clファイルはstatic ipとhostnameをmetadataから埋め込めるシンプルなものを作成しました。

cl/static.yaml.tmpl
---
storage:
  files:
    - path: /etc/systemd/resolved.conf
      filesystem: root
      mode: 0644
      contents:
        inline: |
          [Resolve]
          DNS=172.18.0.1
          Domains=microad.jp
    - path: /etc/hostname
      filesystem: root
      mode: 0644
      contents:
        inline: |
          {{.hostname}}.microad.jp
    - path: /etc/systemd/network/en*f0.network
      filesystem: root
      mode: 0644
      contents:
        inline: |
          [Match]
          Name=enp*f0

          [Network]
          Address={{.ip_addr}}/24
          Gateway=172.18.0.254
passwd:
  users:
    - name: core
      ssh_authorized_keys:
        - {{.ssh_authorized_key}}
locksmith:
    reboot_strategy: "off"

変数はこんな感じになってます。

variables.tf

variable "matchbox_http_endpoint" {
  type        = "string"
  default     = "http://matchbox.microad.jp:8080"
  description = "Matchbox HTTP read-only endpoint (e.g. http://matchbox.example.com:8080)"
}

variable "matchbox_rpc_endpoint" {
  type        = "string"
  default     = "matchbox.microad.jp:8081"
  description = "Matchbox gRPC API endpoint, without the protocol (e.g. matchbox.example.com:8081)"
}

variable "ssh_authorized_key" {
  type        = "string"
  default     = "公開鍵"
}

variable "container_linux_version" {
  type        = "string"
  default     = "1590.2.0"
  description = "Container Linux version of the kernel/initrd to PXE or the image to install"
}

variable "container_linux_channel" {
  type        = "string"
  default     = "beta"
  description = "Container Linux channel corresponding to the container_linux_version"
}

variable "install_disk" {
  type        = "string"
  default     = "/dev/sda"
  description = "Disk device to which the install profiles should install Container Linux (e.g. /dev/sda)"
}

variable "static_names" {
  type = "list"
}

variable "static_macs" {
  type = "list"
}

variable "static_ips" {
  type = "list"
}

terraform.tfvars
static_names = ["coreos01", "coreos02", "coreos03"]
static_macs = ["52:2f:69:54:d0", "52:25:54:c5:5c:0e", "52:54:7a:80:8f:60"]
static_ips = ["172.18.0.3", "172.18.0.4", "172.18.5."]

この辺はHashにしたほうが良かったかも。。。
ちなみにTerraformですが本番で使う場合はremote storageを使いましょう。

デプロイ

ではplanとapplyを実際にしてみます。

$ terraform init
$ terraform plan
$ terraform apply

Matchboxサーバに展開された設定を確認します。

最終的にMatchboxサーバには以下のような設定が展開されます。

$ ls /var/lib/matchbox          
assets  groups  ignition  profiles

templateが配置されます。

$ ls /var/lib/matchbox/ignition/
container-linux-install.yaml.tmpl  static.yaml.tmpl

groupsにはルーティング設定が展開されます。

$ ls /var/lib/matchbox/groups/
coreos01.json  coreos02.json  coreos03.json  default.json
coreos01.json
{
    "id": "coreos01",
    "profile": "static",
    "selector": {
        "mac": "52:2f:69:54:d0",
        "os": "installed"
    },
    "metadata": {
        "hostname": "coreos01",
        "ip_addr": "172.18.0.3",
        "ssh_authorized_key": "公開鍵"
    }
}
default.json
{
    "id": "default",
    "profile": "container-linux-install",
    "metadata": {
        "ssh_authorized_key": "公開鍵"
    }
}

profilesにはどんなclファイルをやイメージを使ってBootするか、といった設定のまとまりが展開されてます。

$ ls /var/lib/matchbox/profiles/
container-linux-install.json  static.json
static.json
{
    "id": "static",
    "ignition_id": "static.yaml.tmpl",
    "boot": {}
}
ontainer-linux-install.json
{
    "id": "container-linux-install",
    "ignition_id": "container-linux-install.yaml.tmpl",
    "boot": {
        "kernel": "/assets/coreos/1590.2.0/coreos_production_pxe.vmlinuz",
        "initrd": [
            "/assets/coreos/1590.2.0/coreos_production_pxe_image.cpio.gz"
        ],
        "args": [
            "initrd=coreos_production_pxe_image.cpio.gz",
            "coreos.config.url=http://matchbox.microad.jp:8080/ignition?uuid=${uuid}\u0026mac=${mac:hexhyp}",
            "coreos.first_boot=yes",
            "console=tty0",
            "console=ttyS0"
        ]
    }
}

ぶっちゃけTerraform云々は必ずしも必要な訳ではなく、上記に置いてあるようなファイルがあれば良いだけです。
Terraformに慣れていなければ、Anisibleなどの既存の使い慣れたツールで配置する事も可能です。
とはいえTerraformによるワークフローの抽象化ってのは魅力なので、なるべくTerraformを使った方が良いとは思いますが。

起動

あとは対象MACアドレスの機器をIPMIツールなりなんなりで起動すれば、諸々設定されたCoreOSが立ち上がってきます!

おわりに

ちょっと試すには若干ハードルが高いのですが、一旦環境を整えてしまえば、Terraformの設定を書く→レビュー→Plan→Apply→Boot!のフローに載せる事ができるので、便利です。

またTerraformの公式サンプルは以下に色々のってます。
https://github.com/coreos/matchbox/tree/master/examples/terraform

10
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
7