Skip to content

Instantly share code, notes, and snippets.

@hodagi
Forked from jacobweinstock/1-walkthrough.md
Last active June 17, 2023 12:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hodagi/9e372a603034d771d6c035c897f8ab52 to your computer and use it in GitHub Desktop.
Save hodagi/9e372a603034d771d6c035c897f8ab52 to your computer and use it in GitHub Desktop.
Tinkerbell machine provisioning demo

デモ手順

  • Tinkerbellを使ってIntel NUCにUbuntu 20.04 LTSをインストールします。

環境

  • Target Server

    • LANケーブルのポートがあり、NVMe対応M.2 SSDが刺さっているPC
      • SATA, SASストレージでもできますが、後述するhardware.yamlの修正が必要です
      • 検証機には、第七世代のIntel NUCを使用しました
    • 既にOSがインストールしてあった場合、全部消えるのでご注意ください
  • Tinkerbell Stack Server

    • Tinkerbellをk3dで動かします
    • PXE Boot用のDHCPサーバーとしても振舞います
  • Bastion Host

    • 操作用の踏み台サーバーです
  • Router

    • フレッツ光のレンタルルーターです
  • Switch

    • スイッチハブです

構成

Tinkerbellスタックのインストール

事前準備

手順

基本的にTinkerbell Stack Server上で作業します。

  1. Tinkerbellを動かすための土台としてk3dを動かします
    • k3d cluster create --network host --no-lb --k3s-arg "--disable=traefik,servicelb" --k3s-arg "--kube-apiserver-arg=feature-gates=MixedProtocolLBService=true" --host-pid-mode
    • sandboxリポジトリのコマンドを参考にしています

Note

  • k3dはDocker上でk3s(Rancherが開発している軽量なkubernetesディストリビューション)を動かすためのラッパーです。k3dを動かす際に各種オプションを忘れないでください。
  • --no-lb --k3s-arg "--disable=traefik,servicelb"
    • CNI(kubernetesのネットワークを支えるコンポーネント。k3dではデフォルトでtraefikがCNIとして入ってます)やネットワークサービスを無効化します。
    • 代わりにTinkerbellではmacvlan network driverを利用して、ホストと同じIP空間にあるIPアドレスを割り当てます。
  • --network host --host-pid-mode
    • 同じくmacvlanを使うために必要な設定です。
  • --k3s-arg "--kube-apiserver-arg=feature-gates=MixedProtocolLBService=true"
    • Kubernetes上のLoad Balancerに対して、同じポートで異なるプロトコル(UDP、TCP)に対応できるようにします。
    • 元々β機能だったのでフィーチャーフラグの設定として必要でしたが、Kubernetes 1.26でGAになったのでそのうち要らなくなると思います。
  1. Tinkerbellのchartリポジトリを git clone します
    • git clone https://github.com/tinkerbell/charts.git
  2. テンプレートファイル values.yaml を自分の環境に合わせて変更します。
    • cd chart/tinkerbell
    • README.mdのガイダンスに従ってください
    • テンプレートファイルで通常設定する箇所
      • stack.loadBalancerIP: Tinker Stack ServerのIPアドレスを設定します。
      • stack.relay.sourceInterface: Tinker Stack ServerのNIC(ネットワーク名)を設定します。
      • boots.remoteIp: PXE Boot用DHCPサーバーのIPアドレスです。コメントにあるようにサブネットの範囲内で未使用のIPアドレスを割り振ってください。
      • boots.tinkServer: tink serverコンポーネント用のIPアドレスです。stack.loadBalancerIPと同じ値にしてください。
      • boots.osieBase: hookと呼ばれるOSイメージを配布するためのIPアドレスです。stack.loadBalancerIPと同じ値にしてください。

Note stack.relay.sourceInterface (NIC)の修正を忘れないでください。
これを間違えるとインストール対象のサーバーからTinkerbellのDHCPサーバーに到達できないため、PXE Bootが成功しません。
おじさんはeth0と思い込んでいました...今どきはこういう名前なんですね。

  1. Tinkerbellスタックをインストールします
    • # charts/tinkerbellフォルダ配下で...
      
      # stack/Chart.lockファイルを更新します
      helm dependency build stack/
      # PodのCIDRを設定します
      trusted_proxies=$(kubectl get nodes -o jsonpath='{.items[*].spec.podCIDR}' | tr ' ' ',')
      # Tinkerbellスタックをインストールします
      helm install stack-release stack/ --create-namespace --namespace tink-system --wait --set "boots.trustedProxies=${trusted_proxies}" --set "hegel.trustedProxies=${trusted_proxies}"

Note helm install 実行後、しばらく時間がかかるのでターミナルで別タブを開き、 次の確認コマンドを実行します

  1. Tinkerbellスタックが起動したか検証します
    • 全てのpodが動作しているか確認します: kubectl get pods -n tink-system
    • values.yaml で指定したIPアドレスが EXTERNAL-IP カラムに設定されているかtink-stack のサービスリソースを確認します: kubectl get svc -n tink-system
      • podがすべて running の状態になっていてもIPアドレスが既存のデバイスと被っている場合、 pending のまま変わりません。その場合は values.yaml を再修正して helm uninstall stack-release -n tink-system 後、再度インストールしてください。
  2. Ubuntu 20.04 (Focal) .img ファイルをダウンロード、変換、ファイルサーバー上に公開します
    • git clone https://github.com/tinkerbell/sandbox.git && kubectl apply -n tink-system -f ~/sandbox/deploy/stack/helm/manifests/ubuntu-download.yaml
    • これにより、FocalファイルがTinkerbellスタックのウェブサーバー経由で利用可能となり、template.yamlファイルで使用することができます。
    • wget http://${EXTERNAL-IP}:8080/focal-server-cloudimg-amd64.raw.gz でファイルがDLできることを確認してください。EXTERNAL-IPには values.yaml で指定したTinkerbellスタックサーバーのIPアドレス(例では192.168.1.13)が入ります
    • 他のOSをインストールしたい場合、 ubuntu-download.yaml を調べてもいいし、Tinkerbellのドキュメントを読むことで、このダウンロードと変換を手動で実行する手順を確認することができます。

Tinkerbell CRDsをapplyします

  1. 3つのCRDs(hardware, template, workflow)を自分の環境に合わせてカスタマイズします
    • TinkリポジトリにCRDの例があります。
    • もし quay.io/tinkerbell-actions/image2disk:v1.0.0 を使用するなら IMG_URL: "http://EXTERNAL-IP:8080/focal-server-cloudimg-amd64.raw.gz" という環境変数を template.yaml に追加してください
    • workflow.yaml が正しい templateRef および hardwareRef CRD の名前を参照し、 device_1 がターゲットマシンのMACアドレスと一致していることを確認してください。
    • hardware.yamltemplate.yaml ならびに workflow.yaml ファイルの例を下に載せます。
  2. ターゲットのサーバーをPXE Bootモードで起動して、DHCPサーバーを検索中の状態にします
  3. 即座にTinkerbell CRDsをクラスタにapplyします
    • kubectl apply -f hardware.yaml
      kubectl apply -f template.yaml
      kubectl apply -f workflow.yaml

Note sandboxリポジトリのsandbox->deploy->stack->helm->manifestsをベースに手直しした例を添付します。
2~3番の流れですが、Tinkerbell CRDsをクラスタにapplyした後でサーバーをPXE Bootモードで起動するとOSのインストールが安定しなかったため、この手順にしています。

プロビジョニング

  1. ワークフローの状態を見ます
    • kubectl get workflow -n tink-system --watch
  2. ワークフローの状態が STATE_SUCCESS になったら再度ターゲットのサーバーをリブートします。
  3. サーバーにログインします。SSHでコンソール画面にアクセスできます。

Note OSインストール後、単純に再起動するとまたPXE Bootの画面になるため、起動中にF2を連打してUEFIの画面を立ち上げて、Bootの優先度をストレージに変更するとうまくいきます。
プロビジョニングの間、ターゲットのサーバーの画面はLinuxKitの起動後、表示が変わらず、スタックしているのかインストールがうまくいっているのか判別がつきません。
gettyによりターミナルの操作ができるため、 dockerコマンドを使ってtink-workerのコンテナのログを直接見ると良いでしょう。
具体的には docker pstink-worker コンテナのIDを確認し、docker logs -f ${tink-workerのコンテナID} でログを出力することで電子の妖精が働いている様子を見ることができます。

apiVersion: "tinkerbell.org/v1alpha1"
kind: Hardware
metadata:
name: nuc-demo
namespace: tink-system
spec:
# ターゲットのサーバーに刺したストレージ種類に応じてデバイスファイルのパスが変わるので必ず確認してください
disks:
- device: /dev/nvme0n1
metadata:
facility:
facility_code: onprem
manufacturer:
slug: hp
instance:
userdata: ""
hostname: "nuc-demo"
id: "1c:69:7a:11:22:33"
operating_system:
distro: "ubuntu"
os_slug: "ubuntu_20_04"
version: "20.04"
interfaces:
# 紛らわしいですが、この項目はターゲットのサーバーに関する設定です
# IPアドレスにはTinkerbell Stack ServerのDHCPではなく、ターゲットのサーバーの設定値を入力してください
- dhcp:
arch: x86_64
hostname: nuc-demo
# 既存の自宅LANと同じネットワークにターゲットのサーバーをぶら下げます
ip:
address: 192.168.1.8
gateway: 192.168.1.1
netmask: 255.255.255.0
lease_time: 86400
mac: 1c:69:7a:11:22:33
name_servers:
- 1.1.1.1
- 8.8.8.8
uefi: true
netboot:
allowPXE: true
allowWorkflow: true
apiVersion: "tinkerbell.org/v1alpha1"
kind: Template
metadata:
name: ubuntu-focal-nvme
namespace: tink-system
spec:
data: |
version: "0.1"
name: ubuntu-focal-nvme
global_timeout: 9800
tasks:
- name: "os-installation"
worker: "{{.device_1}}"
volumes:
- /dev:/dev
- /dev/console:/dev/console
- /lib/firmware:/lib/firmware:ro
actions:
- name: "stream-ubuntu-image"
image: quay.io/tinkerbell-actions/image2disk:v1.0.0
timeout: 9600
environment:
DEST_DISK: {{ index .Hardware.Disks 0 }}
IMG_URL: "http://192.168.1.13:8080/focal-server-cloudimg-amd64.raw.gz"
COMPRESSED: true
- name: "grow-partition"
image: quay.io/tinkerbell-actions/cexec:v1.0.0
timeout: 90
environment:
BLOCK_DEVICE: {{ index .Hardware.Disks 0 }}p1
FS_TYPE: ext4
CHROOT: y
DEFAULT_INTERPRETER: "/bin/sh -c"
CMD_LINE: "growpart {{ index .Hardware.Disks 0 }} 1 && resize2fs {{ index .Hardware.Disks 0 }}p1"
- name: "install-openssl"
image: quay.io/tinkerbell-actions/cexec:v1.0.0
timeout: 90
environment:
BLOCK_DEVICE: {{ index .Hardware.Disks 0 }}p1
FS_TYPE: ext4
CHROOT: y
DEFAULT_INTERPRETER: "/bin/sh -c"
CMD_LINE: "apt -y update && apt -y install openssl"
- name: "create-user"
image: quay.io/tinkerbell-actions/cexec:v1.0.0
timeout: 90
environment:
BLOCK_DEVICE: {{ index .Hardware.Disks 0 }}p1
FS_TYPE: ext4
CHROOT: y
DEFAULT_INTERPRETER: "/bin/sh -c"
CMD_LINE: "useradd -p $(openssl passwd -1 tink) -s /bin/bash -d /home/tink/ -m -G sudo tink"
- name: "enable-ssh"
image: quay.io/tinkerbell-actions/cexec:v1.0.0
timeout: 90
environment:
BLOCK_DEVICE: {{ index .Hardware.Disks 0 }}p1
FS_TYPE: ext4
CHROOT: y
DEFAULT_INTERPRETER: "/bin/sh -c"
CMD_LINE: "ssh-keygen -A; systemctl enable ssh.service; sed -i 's/^PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config"
- name: "disable-apparmor"
image: quay.io/tinkerbell-actions/cexec:v1.0.0
timeout: 90
environment:
BLOCK_DEVICE: {{ index .Hardware.Disks 0 }}p1
FS_TYPE: ext4
CHROOT: y
DEFAULT_INTERPRETER: "/bin/sh -c"
CMD_LINE: "systemctl disable apparmor; systemctl disable snapd"
- name: "write-netplan"
image: quay.io/tinkerbell-actions/writefile:v1.0.0
timeout: 90
environment:
DEST_DISK: {{ index .Hardware.Disks 0 }}p1
FS_TYPE: ext4
DEST_PATH: /etc/netplan/config.yaml
CONTENTS: |
network:
version: 2
renderer: networkd
ethernets:
id0:
match:
name: en*
dhcp4: true
UID: 0
GID: 0
MODE: 0644
DIRMODE: 0755
# いきなりPXEブートでOSインストールするのが怖い場合、こちらのテンプレートファイルをお使いください。
# TinkerbellスタックはPXEブート後、メモリ上に展開されるため、ストレージに影響が及びません。
# 注意事項としては、PXEブート中の画面はなんも変わったように見えません。
# 代わりに手順の一番最後に書いた方法でdockerコマンドを使ってログを出力するとアザラシのAAが見えるはずです。
apiVersion: "tinkerbell.org/v1alpha1"
kind: Template
metadata:
name: ubuntu-focal-nvme
namespace: tink-system
spec:
data: |
version: "0.1"
name: ubuntu-focal-nvme
global_timeout: 300
tasks:
- name: "os-installation"
worker: "{{.device_1}}"
actions:
- name: "hello_world"
image: quay.io/podman/hello
timeout: 60
apiVersion: "tinkerbell.org/v1alpha1"
kind: Workflow
metadata:
name: demo-wf
namespace: tink-system
spec:
templateRef: ubuntu-focal-nvme
hardwareRef: hp-demo
hardwareMap:
device_1: 1c:69:7a:11:22:33
# charts->tinkerbell->stack->values.yaml
stack:
enabled: true
name: tink-stack
service:
enabled: true
type: LoadBalancer
selector:
app: tink-stack
# Tinkerbell stack serverと同じIPアドレスにします
loadBalancerIP: 192.168.1.13
lbClass: kube-vip.io/kube-vip-class
image: nginx:1.23.1
hook:
enabled: true
name: hook-files
port: 8080
image: alpine
downloadsDest: /opt/hook
downloads:
- url: https://github.com/tinkerbell/hook/releases/download/v0.8.0/hook_x86_64.tar.gz
sha512sum: 498cccba921c019d4526a2a562bd2d9c8efba709ab760fa9d38bd8de1efeefc8e499c9249af9571aa28a1e371e6c928d5175fa70d5d7addcf3dd388caeff1a45
- url: https://github.com/tinkerbell/hook/releases/download/v0.8.0/hook_aarch64.tar.gz
sha512sum: 56e3959722c9ae85aec6c214448108e2dc1d581d2c884ca7a23265c1ae28489589481730fbb941fac8239f6222f9b5bb757987a5238f20194e184ae7e83b6a5b
kubevip:
enabled: true
name: kube-vip
image: ghcr.io/kube-vip/kube-vip:v0.5.7
imagePullPolicy: IfNotPresent
roleName: kube-vip-role
roleBindingName: kube-vip-rolebinding
# KubeVIPがアドバタイズするインターフェイスをカスタマイズします。設定されていない場合、KubeVIPはインターフェイスを自動的に検出します。
#interface: enp0s8
relay: # リレーにより、ブロードキャストによるDHCPリクエストの受信、応答ができるようになります
name: dhcp-relay
enabled: true
# 素の `dhcrelay` はPID 1として実行された場合、シグナルを適切に認識しないため、このDockerイメージ(ghcr.io/jacobweinstock/dhcrelay)を使用します
image: ghcr.io/jacobweinstock/dhcrelay
maxHopCount: 10
# sourceInterfaceは、DHCPブロードキャストバケットの受信に使用するホスト/ノードのインターフェースです。要はNIC名です。
# eth0かと思ったらそんなことなかったぜよ...
sourceInterface: enp3s0 # TODO(jacobweinstock): investigate autodetecting a default
# -- Overrides
# ここで定義された値は、各チャート内の値を上書きします。これらの中には、環境に依存するため、デプロイ前に調整が必要なものもあります。
# また、便宜上APIとして表示しているものもあります。
#
# 追加の詳細については、各チャートのドキュメントを参照してください。
boots:
image: quay.io/tinkerbell/boots:v0.8.0
tinkWorkerImage: quay.io/tinkerbell/tink-worker:v0.8.0
trustedProxies: []
# これは、ネットブートのためにDHCP経由でユニキャストでBootsに到達するためにマシンが使用するIPアドレスになります。未使用のIPアドレスを設定してください
remoteIp: 192.168.1.72
# Kubernetes Gateway API(Ingress Resourceの後継)が安定版になったら、すべてのTinkerbellサービスに対して単一のIPアドレスでいけるようになるでしょう
tinkServer:
# `stack.loadBalancerIP` と同じ値にするべきです
ip: 192.168.1.13
osieBase:
# `stack.loadBalancerIP` と同じ値にするべきです
ip: 192.168.1.13
hegel:
image: quay.io/tinkerbell/hegel:v0.10.1
trustedProxies: []
rufio:
image: quay.io/tinkerbell/rufio:v0.1.0
tink:
controller:
image: quay.io/tinkerbell/tink-controller:v0.8.0
server:
image: quay.io/tinkerbell/tink:v0.8.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment