はじめに
この記事は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
中身はこんな感じです。
[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を展開するための設定が以下になります。
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により生成しています。
中身は以下のような感じです。
---
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
になります。
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から埋め込めるシンプルなものを作成しました。
---
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"
変数はこんな感じになってます。
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"
}
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
{
"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": "公開鍵"
}
}
{
"id": "default",
"profile": "container-linux-install",
"metadata": {
"ssh_authorized_key": "公開鍵"
}
}
profilesにはどんなclファイルをやイメージを使ってBootするか、といった設定のまとまりが展開されてます。
$ ls /var/lib/matchbox/profiles/
container-linux-install.json static.json
{
"id": "static",
"ignition_id": "static.yaml.tmpl",
"boot": {}
}
{
"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