Posted at
MicroAdDay 8

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

More than 1 year has passed since last update.


はじめに

この記事は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