なにかの技術メモ置き場

なにかの技術メモ置き場

@インフラエンジニア

自作 systemd サービスのログに severity を付与する(bash, python)

画像準備中

概要

自作スクリプトbash, python)を systemd に登録してサービス化している。
スクリプト内で出力するログに severity を付けるのに苦労したため、まとめた。

条件

  • systemd のサービス単位でまとめてログを見たい(journalctl -u <サービス名> の実行結果に表示されること)
  • ログを severity 付きで syslog サーバに転送したい

結論

echo "<SEVERITY_NUMBER>MESSAGE"
print("<SEVERITY_NUMBER>MESSAGE")

環境

概要図

画像準備中

※取り急ぎこんな感じ

 -----------------------------------------------------        -------------------
| bash --> systemd --> journald --> rsyslogd (client) | ---> | rsyslogd (server) |
 -----------------------------------------------------        -------------------

構成

ホスト名 IPアドレス OS 用途 備考
server - CentOS 8.5.2111 検証用サーバ -

前提

  • bash のコードで説明する。

事象とか困っていることとか

step 1

まずは echo するだけの bash スクリプトを作成し、systemd のサービスに登録した。

設定

#!/bin/bash
echo "This is info message."
echo "This is err message."
[Unit]
Description=logging-test

[Service]
Type=simple
ExecStart=bash /tmp/logging-test.bash

[Install]
WantedBy=multi-user.target

実行

[root@server ~]# systemctl start logging-test.service

確認

[root@server ~]# journalctl -u logging-test.service
-- Logs begin at Sun 2024-02-25 22:21:52 JST, end at Tue 2024-02-27 20:56:20 JST. --
 2月 27 20:56:20 server systemd[1]: Started logging-test.
 2月 27 20:56:20 server bash[441780]: This is info message.
 2月 27 20:56:20 server bash[441780]: This is err message.
 2月 27 20:56:20 server systemd[1]: logging-test.service: Succeeded.

※ info 抜粋

[root@server ~]# journalctl -u logging-test.service -p info..info
-- Logs begin at Sun 2024-02-25 22:21:52 JST, end at Tue 2024-02-27 20:56:20 JST. --
 2月 27 20:56:20 server systemd[1]: Started logging-test.
 2月 27 20:56:20 server bash[441780]: This is info message.
 2月 27 20:56:20 server bash[441780]: This is err message.
 2月 27 20:56:20 server systemd[1]: logging-test.service: Succeeded.

※ err 抜粋

[root@server ~]# journalctl -u logging-test.service -p err..err
-- Logs begin at Sun 2024-02-25 22:21:52 JST, end at Tue 2024-02-27 20:56:20 JST. --
-- No entries --

どちらのログも severity は info になっている。

step 2

ここからが本題。This is err message. のログの severity を err にしたい。logger で試してみた。

設定

#!/bin/bash
logger -p info "This is info message."
logger -p err "This is err message."

実行

[root@server ~]# systemctl start logging-test.service

確認

[root@server ~]# journalctl -u logging-test.service
-- Logs begin at Sun 2024-02-25 22:21:52 JST, end at Tue 2024-02-27 20:59:11 JST. --
--- snip ---
 2月 27 20:59:09 server systemd[1]: Started logging-test.
 2月 27 20:59:09 server systemd[1]: logging-test.service: Succeeded.

ログが記録されていない。
systemd のユニット(サービス)のログに記録されるのは、あくまでスクリプト内の標準出力と標準エラー出力のみ。logger は直接 journald (rsyslogd) にログを送っているため、ここには記録されない。
なお、syslog サーバ側では severity 付きでログを受信できている。

調査

systemd のユニット(サービス)としてログを出力しつつ、 severity を指定する方法を探したところ、以下が見つかった。Thank you so much ! 0pointer.de

echo コマンドの頭に severity の識別子を付与するらしい。なんだ、そんな書式聞いたことがない。

echo "<SEVERITY_NUMBER>MESSAGE"

SEVERITY_NUMBER と severity の対応は以下。

SEVERITY_NUMBER severity
0 Emergency
1 Alert
2 Critical
3 Error
4 Warning
5 Notice
6 Informational
7 Debug

検証

設定

#!/bin/bash
echo "<6>This is info message."
echo "<3>This is err message."

実行

[root@server ~]# systemctl start logging-test.service

確認

[root@server ~]# journalctl -u logging-test.service
-- Logs begin at Sun 2024-02-25 22:21:52 JST, end at Tue 2024-02-27 21:11:26 JST. --
--- snip ---
 2月 27 21:11:24 server systemd[1]: Started logging-test.
 2月 27 21:11:24 server bash[441844]: This is info message.
 2月 27 21:11:24 server bash[441844]: This is err message.
 2月 27 21:11:24 server systemd[1]: logging-test.service: Succeeded.

※ info 抜粋

[root@server ~]# journalctl -u logging-test.service -p info..info
-- Logs begin at Sun 2024-02-25 22:21:52 JST, end at Tue 2024-02-27 21:11:26 JST. --
--- snip ---
 2月 27 21:11:24 server systemd[1]: Started logging-test.
 2月 27 21:11:24 server bash[441844]: This is info message.
 2月 27 21:11:24 server systemd[1]: logging-test.service: Succeeded.

※ err 抜粋

[root@server ~]# journalctl -u logging-test.service -p err..err
-- Logs begin at Sun 2024-02-25 22:21:52 JST, end at Tue 2024-02-27 21:11:26 JST. --
 2月 27 21:11:24 server bash[441844]: This is err message.

おお、<3><6> の文字がログから消えている。面白い。
そして、 severity が付与されている。
syslog サーバ側でも severity 付きで受信できている。

補足

  • bash の printf だと以下。
printf "<6>This is info message.\n"
printf "<3>This is err message.\n"
print("<6>This is info message.")
print("<3>This is err message.")
  • ちなみにログインシェルで実行しても意味はない。
[root@server ~]# echo "<3>This is err message."
<3>This is err message.
  • journalctl コマンドに -o verbose を付けると severity が見える(PRIORITY という項目) 。
[root@server ~]# journalctl -u logging-test.service -o verbose
Tue 2024-02-27 21:57:10.029831 JST [s=e9efc3fea5734e74aa01d2375b257426;i=5b55;b=783be12125304676a886445aea612545;m=27e368ef58;t=6125c90734a>
    SYSLOG_FACILITY=3
    _UID=0
    _GID=0
    _CAP_EFFECTIVE=1ffffffffff
    _BOOT_ID=xxx
    _MACHINE_ID=xxx
    _HOSTNAME=server
    _TRANSPORT=stdout
    PRIORITY=3
    _COMM=bash
    SYSLOG_IDENTIFIER=bash
    _SYSTEMD_UNIT=logging-test.service
    MESSAGE=This is err message.
    _STREAM_ID=xxx
    _PID=442722
    _SYSTEMD_INVOCATION_ID=xxx

あとがき

狐につままれた気分。設定やコーディングで解決するイメージしか持っていなかった。まさか OS の既存の実装に答えがあるとは。。。

参考記事

https://0pointer.de/blog/projects/journal-submit.html

※検索用ワード シビアリティ/セベリティ/プライオリティ/ログレベル

自作キーボード「TBK Mini」を作ってみた

目次

概要

自作キーボードTBK Miniのビルドログ。

経緯

Corne Cherry V3で親指が押しっぱなしになるキーマップを使っていたところ、親指と手首が痛くなった。「親指のポジション」と「手首の角度」を改善するため、3Dケースを使用したキーボードを選択した。

構成

今回作成したキーボードの主要パーツは以下。

  • Keyboard: TBK Mini with 30 degrees tents
  • Keyswitch: Gateron Caps V2 Switches 3 Pins Milkey Brown
  • Keycap: KBDfans NP PBT ブランク キーキャップセット(124キー/ブラック)

準備

以下の工具一式を揃えた。 none06.hatenadiary.org

部材購入

部材 製品名 価格 入力先 備考
キット TBK Mini – DIY Kit with case and electronics × 1 uni_cpo_optminikit: Tents (30 degrees) 28,991(€198.55*1) https://bastardkb.com/product/tbk-mini-diy-kit-with-case-and-electronics/ -
キースイッチ(MX互換) Gateron Caps V2 Switches 3 Pins(10個) Milkey Brown 2,475(495*5) https://shop.yushakobo.jp/products/2808?variant=40821007286433 -
キーキャップ(MX互換) KBDfans NP PBT ブランク キーキャップセット(124キー/ブラック) 残り2点 3,500(3,500*1) https://talpkeyboard.net/items/60f7ac3d7291346ddba3f390 -
TRRSケーブル TRRSケーブル 50cm 600(600*1) https://shop.dailycraft.jp/products/trrs_cable_50 -
USBケーブル(TypeA凸-TypeC凸) - - 家に転がっていたもの -
合計 - 35,566 - -

手順書(ビルドガイド)

製作者であるBastard Keyboardsさんのビルドガイドを参照。 docs.bastardkb.com

作業ログ(ビルドログ)

キットと工具の確認

参照:Kit contents and required tools – Bastard Keyboards
テントはオプション。

ケースの準備

参照:Prepare the case – Bastard Keyboards
ネジ穴をケースに取り付ける。

PCBの準備

参照:Prepare the plate and thumb cluster PCBs – Bastard Keyboards
ダイオードをメインPCBとサムクラスターPCBにはんだ付けする。

リボンケーブルのはんだ付け

参照:Install the ribbon cables – Bastard Keyboards
リボンケーブルをはんだ付けする。

Elite-Cの準備

参照:Prepare the Elite-C – Bastard Keyboards

Elite-C

Elite-CをMCU取り付け用PCBにはんだ付けする。 ビルドガイドを読み間違えてElite-C(v1)の手順ではんだ付けしてしまったた。Elite-C(v2)の手順はこちらを参照。
v1では12ピン×1本のピンヘッダを6ピン×2本に折ってはんだ付けする。(写真は誤りなので注意) v2では12ピン×2本と5ピン×1本のピンヘッダをはんだ付けする。
なお、ケースに収納する際の干渉を軽減させるため、一部のピンヘッダを短くカットしている(全部短くしても良かったかもしれない)。

リセットボタン

リセットボタンをMCU取り付け用PCBにはんだ付けする。

オーディオジャック

オーディオジャックをMCU取り付け用PCBにはんだ付けする。 オーディオジャックの穴とUSB端子の穴の位置がシビアなので、一度ケースに取り付けた状態ではんだ付けを微調整すると良い。

リボンケーブルの接続

参照:Connect the cables to the Elite-C – Bastard Keyboards
メインPCBから伸びるリボンケーブルをMCU取り付け用PCBとサムクラスターPCBにはんだ付けする。

キースイッチの取り付け

参照:Install the switches – Bastard Keyboards
ケースにキースイッチを取り付ける。 PCBにキースイッチをはんだ付けする。スイッチソケットを使わず直接はんだ付けする方式。PCBを曲げながらはんだ付けするのはなかなか大変だった。

仕上げ

参照:Install the keyboard – Bastard Keyboards

キーの認識テスト

キーの認識テストをする。
https://keyboardchecker.com/

ボトムプレートまたはテントの取り付け

オプションで購入したテントを取り付ける。標準のボトムプレートについては後述。

キーキャップの取り付け

キーキャップを取り付ける。

キーマップのカスタマイズ(オプション)

Vialをインストールし、キーマップをカスタマイズする。
https://get.vial.today/

完成!

リストレスト探し中。当面はそのへんに転がっていた木材の切れ端でしのぐ。

おまけ

オプションのテントではなく標準のボトムプレートを取り付けるとこんな感じ。リボンケーブルを収納しないといけないが、ピンヘッダがリボンケーブルに干渉するので工夫が必要。

あとがき

親指と手首がとても楽になった。
課題として、テントが思ったより高いため、リストレストを高くしないと指が届きにくいキーがある。

参考記事

github.com

Kubernetes環境でDNSサービスを構築してみた

全編目次

none06.hatenadiary.org

概要

  • Kubernetes環境でDNSサービスを構築する。
  • DNSサービスとしてCoreDNSを使用する。

環境

概要図

構成

ホスト名 IPアドレス OS 用途 備考
k8sctrpln01 172.16.0.11/24 CentOS 7.9.2009 コントロールプレーンノード QEMU+KVM仮想ゲスト
k8sworker01 172.16.0.12/24 CentOS 7.9.2009 ワーカノード QEMU+KVM仮想ゲスト
k8sworker02 172.16.0.13/24 CentOS 7.9.2009 ワーカノード QEMU+KVM仮想ゲスト
dns02 172.16.0.2/24 CoreDNS-1.9.3 DNSサービス MetalLB 仮想IP
file01 172.16.0.5/24 TrueNAS-12.0-U6 NFSサーバ -

前提

  • なるべく公式ドキュメントを参照するようにする。
  • マニフェストの作成やkubectlコマンドの実行は、クライアントマシン(Windows 10)上で行う。Windowsへのkubectlコマンドのインストールは以下を参照。 kubernetes.io
  • Pod間のデータ共有の手段として、NFSサーバを使用する。当環境では以下の領域を使用する。
NFSサーバホスト名 NFS公開領域 備考
file01 /mnt/data-pool0/nfs/k8s/coredns -

構築

Corefileの作成

NFSサーバ上に、CoreDNS起動時に読み込ませる設定ファイルを作成する。

. {
    whoami
    errors
    log . "{remote} is Request: {name} {type} {>id}"
    hosts /etc/coredns/hosts {
      fallthlough
    }
    reload
}
  • パラメータ(Plugins)の詳細はこちらを参照。 coredns.io

hostsファイルの作成

NFSサーバ上に、CoreDNSで名前解決に使用するファイルを作成する。

172.16.0.11     k8sctlpln011.tmpdomain.local    k8sctlpln01.tmpdomain.local     k8sctlpln011     k8sctlpln01
172.16.0.12     k8sworker011.tmpdomain.local    k8sworker01.tmpdomain.local     k8sworker011     k8sworker01
172.16.0.13     k8sworker021.tmpdomain.local    k8sworker02.tmpdomain.local     k8sworker021     k8sworker02
  • いわゆるhostsファイルの形式で記載できるのでわかりやすい。例えばBINDではAレコード(正引き)とPTRレコード(逆引き)とでそれぞれの定義ファイルが必要だったが、便利な時代になった。
  • 内容はサンプル。

PV、PVCの作成

Podにマウントする永続ボリューム(PV、PVC)を作成する。

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs-coredns
  labels:
    volume: volume-nfs-coredns
spec:
  capacity:
    storage: 10Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: slow
  mountOptions:
  - hard
  - nfsvers=3
  nfs:
    path: "/mnt/data-pool0/nfs/k8s/coredns"
    server: file01
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-nfs-coredns
spec:
  accessModes:
  - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 2Gi
  storageClassName: slow
  selector:
    matchLabels:
      volume: volume-nfs-coredns
  • 容量は適当。
  • PV(PersistentVolume)、PVC(PersistentVolumeClaim)の詳細は公式ドキュメントを参照。 kubernetes.io

マニフェストを適用する。

$ kubectl apply -f pv-nfs-coredns.yaml
persistentvolume/pv-nfs-coredns created
persistentvolumeclaim/pvc-nfs-coredns created

PV、PVCが作成されていることを確認する。

$ kubectl get pv pv-nfs-coredns 
NAME             CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                     STORAGECLASS   REASON   AGE
pv-nfs-coredns   10Gi       RWO            Retain           Bound    default/pvc-nfs-coredns   slow                    67s
$ kubectl get pvc pvc-nfs-coredns
NAME              STATUS   VOLUME           CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc-nfs-coredns   Bound    pv-nfs-coredns   10Gi       RWO            slow           72s

Deploymentの作成

CoreDNSのPodをデプロイするDeploymentを作成する。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: coredns-deployment
spec:
  selector:
    matchLabels:
      app: coredns
  replicas: 2
  template:
    metadata:
      labels:
        app: coredns
    spec:
      containers:
      - name: coredns
        image: coredns/coredns
        ports:
        - name: tcp
          containerPort: 53
          protocol: TCP
        - name: udp
          containerPort: 53
          protocol: UDP
        volumeMounts:
        - name: volume-nfs-coredns
          mountPath: /etc/coredns
        command: ["/coredns", "-conf", "/etc/coredns/Corefile"]
      volumes:
      - name: volume-nfs-coredns
        persistentVolumeClaim:
          claimName: pvc-nfs-coredns
  • corednsコマンドのオプションについては公式ドキュメントを参照。 coredns.io

マニフェストを適用する。

$ kubectl apply -f coredns-deployment.yaml 
deployment.apps/coredns-deployment created

Podが作成されていることを確認する。

$ kubectl get pods 
NAME                                     READY   STATUS    RESTARTS   AGE
coredns-deployment-5bc79b5c88-4bdd5      1/1     Running   0          18s
coredns-deployment-5bc79b5c88-9fn7h      1/1     Running   0          17s

PodのログからCoreDNSが起動していることを確認できる。

$ kubectl logs coredns-deployment-5bc79b5c88-4bdd5
.:53
[INFO] plugin/reload: Running configuration SHA512 = d433a10a6209646b978eee6a091811a1a8779e9f06a96524a2b55b702985c2f1820f17c5990fc38cb2fc14926f241ee50b07d7fffe3352ef979d98ac74973581   
CoreDNS-1.9.3
linux/amd64, go1.18.2, 45b0a11

補足だが、Podを作成したタイミングでワーカノード上にPVがNFSマウントされていることを確認できる。

[root@k8sworker01 ~]# df -t nfs
ファイルシス                              1K-ブロック      使用     使用可 使用% マウント位置
file01:/mnt/data-pool0/nfs/k8s/coredns     2163180544 357269504 1805911040   17% /var/lib/kubelet/pods/2fc83d0c-3884-4eab-b59e-3c5b265821f3/volumes/kubernetes.io~nfs/pv-nfs-coredns
[root@k8sworker01 ~]# ls -l /var/lib/kubelet/pods/2fc83d0c-3884-4eab-b59e-3c5b265821f3/volumes/kubernetes.io~nfs/pv-nfs-coredns
合計 9
-rw-r--r--. 1 root 65533   136  6月  7 23:46 Corefile
-rw-r--r--. 1 root 65533 13147  6月  8 00:05 hosts

Serviceの作成

CoreDNSのPodをKubernetesクラスタ外部に公開するためのServiceを作成する。当環境ではServiceのtypeLoadBalancerとし、ソフトウェアロードバランサであるMetalLBを使用する。

apiVersion: v1
kind: Service
metadata:
  name: coredns-service-tcp
  annotations:
    metallb.universe.tf/allow-shared-ip: "coredns-service-ip"
spec:
  type: LoadBalancer
  loadBalancerIP: 172.16.0.2
  ports:
    - name: tcp
      port: 53
      targetPort: 53
      protocol: TCP
  selector:
    app: coredns
---
apiVersion: v1
kind: Service
metadata:
  name: coredns-service-udp
  annotations:
    metallb.universe.tf/allow-shared-ip: "coredns-service-ip"
spec:
  type: LoadBalancer
  loadBalancerIP: 172.16.0.2
  ports:
    - name: udp
      port: 53
      targetPort: 53
      protocol: UDP
  selector:
    app: coredns
  • MetalLBは1つのServiceにおけるマルチプロトコルTCP/UDP)動作に非対応のため、TCPUDPとで別々のServiceを作成し、metallb.universe.tf/allow-shared-ipannotationを設定することで対処する。このannotationを定義しないと、TCPUDPとで別々のIPアドレスが割り当てられてしまう(loadBalancerIPで固定IPを宣言した場合は、例えばTCPにはIPが割り当てられるがUDPにはPendingになる)。詳細は公式ドキュメントを参照。 metallb.universe.tf

マニフェストを適用する。

$ kubectl apply -f coredns-service-loadbalancer.yaml 
service/coredns-service-tcp created
service/coredns-service-udp created

サービスが作成されていることを確認する。EXTERNAL-IPTCP/UDPとも172.16.0.2であることが確認できる。

$ kubectl get services
NAME                    TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                    AGE
coredns-service-tcp     LoadBalancer   10.99.184.19     172.16.0.2    53:31670/TCP               33s
coredns-service-udp     LoadBalancer   10.108.126.55    172.16.0.2    53:31803/UDP               32s

動作確認

任意のマシンから名前解決できることを確認する。

$ nslookup.exe k8sctrpln01 172.16.0.2
サーバー:  dns021.tmpdomain.local
Address:  172.16.0.2

名前:    k8sctrpln01
Address:  172.16.0.11

CoreDNSのログにリクエストが記録されていることが確認できる。

$ kubectl logs -f coredns-deployment-5bc79b5c88-4bdd5
.:53
[INFO] plugin/reload: Running configuration SHA512 = d433a10a6209646b978eee6a091811a1a8779e9f06a96524a2b55b702985c2f1820f17c5990fc38cb2fc14926f241ee50b07d7fffe3352ef979d98ac74973581
CoreDNS-1.9.3
linux/amd64, go1.18.2, 45b0a11
[INFO] 10.244.0.0 is Request: k8sctrpln01. A 5587

あとがき

あれ、53/TCPって必要なんだっけ・・・?

参考記事

coredns.io github.com zenn.dev blog.vpantry.net

Kubernetes環境でアプリケーションの外部公開をしてみた

全編目次

none06.hatenadiary.org

概要

  • Kubernetes環境でアプリケーションを作成する(Podを作成する)。
  • アプリケーションを外部に公開する(Serviceを作成する)。

環境

構成

ホスト名 IPアドレス OS 用途 備考
k8sctrpln01 172.16.0.11/24 CentOS 7.9.2009 コントロールプレーンノード QEMU+KVM仮想ゲスト
k8sworker01 172.16.0.12/24 CentOS 7.9.2009 ワーカノード QEMU+KVM仮想ゲスト
k8sworker02 172.16.0.13/24 CentOS 7.9.2009 ワーカノード QEMU+KVM仮想ゲスト
- 172.16.0.21/24 MetalLB ソフトウェアロードバランサ address pool: 172.16.0.21-172.16.0.25/24
client01 172.16.0.100/24 Windows 10 クライアント CLI: Git Bash
Web UI: Google Chrome

前提

  • 原則として公式ドキュメントに沿って進めていく。
  • マニフェストの作成やkubectlコマンドの実行は、クライアントマシン(Windows 10)上で行う。Windowsへのkubectlコマンドのインストールは以下を参照。 kubernetes.io

STEP1 - Podの作成

ソース

kubernetes.io

概要図

概要

nginxコンテナ1つで構成されるPodを2つ作成する。Podの数は任意。

実践

Deploymentを作成する。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      run: nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
$ kubectl apply -f nginx-deployment.yaml
deployment.apps/nginx-deployment created

Podに割り当てられたIPアドレスを確認する。

$ kubectl get pods -o wide
NAME                               READY   STATUS    RESTARTS   AGE   IP            NODE    
      NOMINATED NODE   READINESS GATES
nginx-deployment-89b88cd64-6dbwl   1/1     Running   0          14s   10.244.1.21   k8sworker01   <none>           <none>
nginx-deployment-89b88cd64-r6mhd   1/1     Running   0          14s   10.244.2.18   k8sworker02   <none>           <none>

このIPアドレスKubernetesクラスタ内部のものなので、クラスタ外部からのアクセスは通らない。以下はノードと同一ネットワークに所属するWindowsマシンからcurlを実行した例。
※当環境のプロキシが邪魔をしたので--noproxyオプションを使用。

$ curl.exe --noproxy "*" -o /dev/null -w '%{http_code}\n' -s http://10.244.1.21:80
000

クラスタ内部からのアクセスは通る。以下はPodnginx-deployment-89b88cd64-6dbwlから10.244.1.2110.244.2.18curlを実行した例。

$ kubectl exec nginx-deployment-89b88cd64-6dbwl -- curl -o /dev/null -w '%{http_code}\n' -s http://10.244.1.21:80
200
$ kubectl exec nginx-deployment-89b88cd64-6dbwl -- curl -o /dev/null -w '%{http_code}\n' -s http://10.244.2.18:80
200

STEP2 - Serviceの作成

CASE1 - ClusterIPタイプのServiceを使用した構成

ソース

kubernetes.io

概要図

概要

先に結論だが、この構成ではクラスタ外部にアプリケーションを公開できない。ClusterIPはクラスタ内部からのみアクセス可能。

実践

ClusterIPタイプのServiceを作成する。

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  labels:
    run: nginx
spec:
  type: ClusterIP # 公式ドキュメントでは省略している(省略時はClusterIPになる)
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: nginx
$ kubectl apply -f nginx-service-clusterip.yaml 
service/nginx-service created

クラスタ内部からアクセス可能なClusterIPが割り当てられた。

$ kubectl get services nginx-service
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
nginx-service   ClusterIP   10.109.120.89   <none>        80/TCP    68s

Endpointsが各PodのIPアドレスとなっている。Serviceにアクセスが来るとkube-proxyによりEndpointsに分散される。

$ kubectl describe services nginx-service
Name:              nginx-service
Namespace:         default
Labels:            run=nginx
Annotations:       <none>
Selector:          run=nginx
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.109.120.89
IPs:               10.109.120.89
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.21:80,10.244.2.18:80
Session Affinity:  None
Events:            <none>

念のためクラスタ外部からはアクセスできないことを確認。

$ curl.exe --noproxy "*" -o /dev/null -w '%{http_code}\n' -s http://10.109.120.89:80
000

クラスタ内部からはアクセスできる。

$ kubectl exec nginx-deployment-89b88cd64-6dbwl -- curl -o /dev/null -w '%{http_code}\n' -s http://10.109.120.89:80
200

CASE2 - NodePortタイプのServiceを使用した構成

未稿

CASE3 - LoadBalancerタイプのServiceを使用した構成

ソース

kubernetes.io metallb.universe.tf

概要図

概要

クラウド環境においてLoadBalancerタイプのServiceをデプロイすると、クラウド環境上にロードバランサを作成し、クラスタ外部のIPアドレスを割り当ててくれるらしい。
オンプレ環境ではロードバランサの作成処理が進まないため、ソフトウェアロードバランサであるMetalLBをインストールすることで代替することができる。

実践

MetalLBの作成

MetalLBのインストール準備をする。

$ kubectl describe configmap -n kube-system kube-proxy | grep strictARP
  strictARP: false
$ kubectl get configmap kube-proxy -n kube-system -o yaml | sed -e "s/strictARP: false/strictARP: true/" | kubectl diff -f - -n kube-system
diff -u -N "C:\\Users\\root\\AppData\\Local\\Temp\\LIVE-1938845299/v1.ConfigMap.kube-system.kube-proxy" "C:\\Users\\root\\AppData\\Local\\Temp\\MERGED-1255996808/v1.ConfigMap.kube-system.kube-proxy"
--- "C:\\Users\\root\\AppData\\Local\\Temp\\LIVE-1938845299/v1.ConfigMap.kube-system.kube-proxy"    2022-06-04 01:33:37.477912900 +0900
+++ "C:\\Users\\root\\AppData\\Local\\Temp\\MERGED-1255996808/v1.ConfigMap.kube-system.kube-proxy"  2022-06-04 01:33:37.479487200 +0900
@@ -33,7 +33,7 @@
       excludeCIDRs: null
       minSyncPeriod: 0s
       scheduler: ""
-      strictARP: false
+      strictARP: true
       syncPeriod: 0s
       tcpFinTimeout: 0s
       tcpTimeout: 0s
@@ -100,9 +100,9 @@
     fieldsV1:
       f:data:
         f:config.conf: {}
-    manager: kubectl-edit
+    manager: kubectl-client-side-apply
     operation: Update
-    time: "2022-06-03T12:03:26Z"
+    time: "2022-06-03T16:33:36Z"
   name: kube-proxy
   namespace: kube-system
   resourceVersion: "667909"
$ kubectl get configmap kube-proxy -n kube-system -o yaml | sed -e "s/strictARP: false/strictARP: true/" | kubectl apply -f - -n kube-system
Warning: resource configmaps/kube-proxy is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
configmap/kube-proxy configured
$ kubectl describe configmap -n kube-system kube-proxy | grep strictARP
  strictARP: true

MetalLBをインストールする。

$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/namespace.yaml
namespace/metallb-system created
$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/metallb.yaml
Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
podsecuritypolicy.policy/controller created
podsecuritypolicy.policy/speaker created
serviceaccount/controller created
serviceaccount/speaker created
clusterrole.rbac.authorization.k8s.io/metallb-system:controller created
clusterrole.rbac.authorization.k8s.io/metallb-system:speaker created
role.rbac.authorization.k8s.io/config-watcher created
role.rbac.authorization.k8s.io/pod-lister created
role.rbac.authorization.k8s.io/controller created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:controller created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:speaker created
rolebinding.rbac.authorization.k8s.io/config-watcher created
rolebinding.rbac.authorization.k8s.io/pod-lister created
rolebinding.rbac.authorization.k8s.io/controller created
daemonset.apps/speaker created
deployment.apps/controller created
$ kubectl -n metallb-system get pods
NAME                          READY   STATUS                       RESTARTS      AGE
controller-7476b58756-dp7hd   0/1     CrashLoopBackOff             1 (12s ago)   18s
speaker-427rt                 0/1     CreateContainerConfigError   0             18s
speaker-mkbcr                 0/1     CreateContainerConfigError   0             18s

なにやらつまづいている様子。

$ kubectl -n metallb-system logs controller-7476b58756-dp7hd
{"branch":"HEAD","caller":"level.go:63","commit":"v0.12.1","goversion":"gc / go1.16.14 / amd64","level":"info","msg":"MetalLB controller starting version 0.12.1 (commit v0.12.1, branch HEAD)","ts":"2022-06-04T13:35:16.862838665Z","version":"0.12.1"}
{"caller":"level.go:63","error":"Get \"https://10.96.0.1:443/api/v1/namespaces/metallb-system/secrets?fieldSelector=metadata.name%3Dmemberlist\": dial tcp 10.96.0.1:443: connect: no route to host","level":"error","msg":"failed to create memberlist secret","op":"startup","ts":"2022-06-04T13:35:17.865843229Z"}

dial tcp 10.96.0.1:443: connect: no route to hostとのことで、以下のServiceへの疎通ができていないように見える。

$ kubectl get services kubernetes
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   6d3h

暫定対処として、

の順に試したが状況変わらず。最終的に

ことで解消した。追って必要なポートを調査せねば。

$ ssh k8sctrpln03 systemctl stop firewalld
$ ssh k8sworker01 systemctl stop firewalld
$ ssh k8sworker02 systemctl stop firewalld
$ kubectl -n metallb-system get pods
NAME                          READY   STATUS    RESTARTS        AGE
controller-7476b58756-dp7hd   1/1     Running   8 (6m50s ago)   17m
speaker-427rt                 1/1     Running   0               17m
speaker-mkbcr                 1/1     Running   0               17m

MetalLBをLayer2モードで設定する。

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 172.16.0.21-172.16.0.25
$ kubectl apply -f metallb-config.yaml 
configmap/config created
$ kubectl -n metallb-system get configmap config
NAME     DATA   AGE
config   1      6s

Serviceの作成

LoadBalancerタイプのServiceを作成する。

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  labels:
    run: nginx
spec:
  type: LoadBalancer
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: nginx
$ kubectl delete services nginx-service
service "nginx-service" deleted
$ kubectl apply -f nginx-service-loadbalancer.yaml
service/nginx-service created

EXTERNAL-IPが割り当てられている。

$ kubectl get services nginx-service
NAME            TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
nginx-service   LoadBalancer   10.96.239.88   172.16.0.21   80:32191/TCP   8s
$ kubectl describe services nginx-service
Name:                     nginx-service
Namespace:                default
Labels:                   run=nginx
Annotations:              <none>
Selector:                 run=nginx
Type:                     LoadBalancer
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.96.239.88
IPs:                      10.96.239.88
LoadBalancer Ingress:     172.16.0.21
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  32191/TCP
Endpoints:                10.244.1.30:80,10.244.2.28:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:
  Type    Reason        Age   From                Message
  ----    ------        ----  ----                -------
  Normal  IPAllocated   22s   metallb-controller  Assigned IP ["172.16.0.21"]
  Normal  nodeAssigned  22s   metallb-speaker     announcing from node "k8sworker02"

クラスタ外部のIPにアクセスできた。

$ curl.exe --noproxy "*" -o /dev/null -w '%{http_code}\n' -s http://172.16.0.21:80
200

※アクセスできないこともあったが、Serviceを再作成したらうまくいった。しかしそれは正常とは言えないので、原因を調査する必要がある。

CASE4 - IngressとClusterIPタイプのServiceを使用した構成

未稿

CASE5 - ExternalIPsとClusterIPタイプのServiceを使用した構成

未稿

あとがき

LoadBalancerかIngressが実用性がありそう。

参考記事

kubernetes.io metallb.universe.tf blog.framinal.life blog.yumenomatayume.net

Kubernetes環境を構築してみた

全編目次

none06.hatenadiary.org

概要

Kubernetes環境を構築する。当記事の範囲はコンテナを載せるための基盤を構築するところまで。

経緯

実務経験としてのスキルがオンプレの物理/仮想マシンくらいしかなく、焦りを感じているこの頃。今回はコンテナおよびコンテナオーケストレーションの学習としてKubernetesを触ってみた。

環境

概要図

※赤い箇所が当記事で扱う範囲。

構成

ホスト名 IPアドレス OS 用途 備考
k8sctrpln01 172.16.0.11 CentOS 7.9.2009 コントロールプレーンノード QEMU+KVM仮想ゲスト
k8sworker01 172.16.0.12 CentOS 7.9.2009 ワーカノード QEMU+KVM仮想ゲスト
k8sworker02 172.16.0.13 CentOS 7.9.2009 ワーカノード QEMU+KVM仮想ゲスト
dns01 172.16.0.1 CentOS 8.5.2111 DNSサーバ QEMU+KVM仮想ゲスト
dns02 172.16.0.2 coredns/coredns DNSサーバ コンテナサービス
proxy01 172.16.0.3 CentOS 8.5.2111 プロキシサーバ QEMU+KVM仮想ゲスト

前提

原則として公式ドキュメントに沿って進めていく。 kubernetes.io ※すんなり行くなら二番煎じになるので記事にしないつもりだったが、すんなり行かないから記事にした・・・

構築

kubeadmのインストール

始める前に

コントロールプレーンノードについてのみ確認する。後述するがワーカノードはコントロールプレーンノードを複製して構築する。

  • 対象のOSであることを確認する。
[root@k8sctrpln01 ~]# cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)
  • メモリが2GB以上であることを確認する。
[root@k8sctrpln01 ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:           2.0G        128M        1.7G        8.6M        123M        1.7G
Swap:          2.0G          0B        2.0G
  • CPUが2コア以上であることを確認する。
[root@k8sctrpln01 ~]# cat /proc/cpuinfo | grep processor
processor       : 0
processor       : 1
  • コントロールプレーンノード とワーカノードが通信可能であることを確認する。ワーカノードは未構築のため割愛する。
  • ホスト名、MACアドレス、product_uuidがノード間で重複が無いことを確認する。 後述。
  • ポートを開放する。 後述。
  • Swapをオフにする。
[root@k8sctrpln01 ~]# swapon -s
Filename                                Type            Size    Used    Priority
/dev/vda2                               partition       2097148 0       -2
[root@k8sctrpln01 ~]# swapoff -a
[root@k8sctrpln01 ~]# swapon -s
[root@k8sctrpln01 ~]# cp -p /etc/fstab{,_`date +%Y%m%d`}
[root@k8sctrpln01 ~]# ls -l /etc/fstab*
-rw-r--r--. 1 root root 501  2月 26  2020 /etc/fstab
-rw-r--r--  1 root root 501  2月 26  2020 /etc/fstab_20220529
[root@k8sctrpln01 ~]# sed -i /swap/s/^/#/g /etc/fstab
[root@k8sctrpln01 ~]# diff /etc/fstab{,_`date +%Y%m%d`}
11c11
< #UUID=ea60423d-e182-4843-a7fa-393d738a20d1 swap                    swap    defaults        0 0
---
> UUID=ea60423d-e182-4843-a7fa-393d738a20d1 swap                    swap    defaults        0 0

MACアドレスとproduct_uuidが全てのノードでユニークであることの検証

[root@k8sctrpln01 ~]# uname -n
k8sctrpln01
[root@k8sctrpln01 ~]# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:f9:d5:4d brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:25:ca:02 brd ff:ff:ff:ff:ff:ff
4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:15:69:ca brd ff:ff:ff:ff:ff:ff
[root@k8sctrpln01 ~]# cat /sys/class/dmi/id/product_uuid
BB935834-A266-4B61-A591-4589BFE06A62

ネットワークアダプタの確認

インターフェースを1つしか使用しないためルーティングの考慮は不要。

iptablesがブリッジを通過するトラフィックを処理できるようにする

[root@k8sctrpln01 ~]# lsmod | grep ^br_netfilter
[root@k8sctrpln01 ~]# modprobe br_netfilter
[root@k8sctrpln01 ~]# lsmod | grep ^br_netfilter
br_netfilter           22256  0
[root@k8sctrpln01 ~]# sysctl -n net.bridge.bridge-nf-call-ip6tables -n net.bridge.bridge-nf-call-iptables
1
1
[root@k8sctrpln01 ~]# cat <<EOF > /etc/sysctl.d/k8s.conf
> net.bridge.bridge-nf-call-ip6tables = 1
> net.bridge.bridge-nf-call-iptables = 1
> EOF
[root@k8sctrpln01 ~]# sysctl --system
* Applying /usr/lib/sysctl.d/00-system.conf ...
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-arptables = 0
* Applying /usr/lib/sysctl.d/10-default-yama-scope.conf ...
kernel.yama.ptrace_scope = 0
* Applying /usr/lib/sysctl.d/50-default.conf ...
kernel.sysrq = 16
kernel.core_uses_pid = 1
kernel.kptr_restrict = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.promote_secondaries = 1
net.ipv4.conf.all.promote_secondaries = 1
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
* Applying /etc/sysctl.d/99-sysctl.conf ...
* Applying /etc/sysctl.d/disable_ipv6.conf ...
net.ipv6.conf.all.disable_ipv6 = 1
* Applying /etc/sysctl.d/k8s.conf ...
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
* Applying /etc/sysctl.conf ...
[root@k8sctrpln01 ~]# sysctl -n net.bridge.bridge-nf-call-ip6tables -n net.bridge.bridge-nf-call-iptables
1
1

iptablesがnftablesバックエンドを使用しないようにする

CentOS7はnftablesを導入していないので対象外。

必須ポートの確認

[root@k8sctrpln01 ~]# grep -R -e 6443 -e 2379 -e 2380 -e 10250 -e 10251 -e 10252 /lib/firewalld/services/
/lib/firewalld/services/etcd-client.xml:  <port port="2379" protocol="tcp"/>
/lib/firewalld/services/etcd-server.xml:  <port port="2380" protocol="tcp"/>
[root@k8sctrpln01 ~]# firewall-cmd --list-services
dhcpv6-client snmp ssh
[root@k8sctrpln01 ~]# firewall-cmd --list-ports
[root@k8sctrpln01 ~]# firewall-cmd --add-service={etcd-client,etcd-server} --permanent
success
[root@k8sctrpln01 ~]# firewall-cmd --add-port={6443/tcp,10250/tcp,10251/tcp,10252/tcp} --permanent
success
[root@k8sctrpln01 ~]# firewall-cmd --reload
success
[root@k8sctrpln01 ~]# firewall-cmd --list-services
dhcpv6-client etcd-client etcd-server snmp ssh
[root@k8sctrpln01 ~]# firewall-cmd --list-ports
6443/tcp 10250/tcp 10251/tcp 10252/tcp
  • ワーカノード 後述する。

ランタイムのインストール

Containerdを選択した。
実は、公式ドキュメントに

Dockerとcontainerdの両方が同時に検出された場合、Dockerが優先されます。

の記述があるため、当初はDockerを選択していた。しかし、Kubernetesのバージョンv1.24以降はContainerdが優先される仕様に変わっているらしく、Containerdを選択して再構築した。 github.com

補足だが、気づいたのはkubeadm initトラブルシューティング中。公式ドキュメントが追い付いていないので事前に気づけない。

[root@k8sctrpln01 ~]# kubeadm init --pod-network-cidr 10.244.0.0/16 --v=5
I0528 00:23:59.899926   26554 initconfiguration.go:117] detected and using CRI socket: unix:///var/run/containerd/containerd.sock

Containerd

必要な設定の追加
[root@k8sctrpln01 ~]# cat > /etc/modules-load.d/containerd.conf <<EOF
> overlay
> br_netfilter
> EOF
[root@k8sctrpln01 ~]# lsmod | grep -e ^overlay -e ^br_netfilter
br_netfilter           22256  0
[root@k8sctrpln01 ~]# modprobe overlay
[root@k8sctrpln01 ~]# modprobe br_netfilter
[root@k8sctrpln01 ~]# lsmod | grep -e ^overlay -e ^br_netfilter
overlay                91659  0
br_netfilter           22256  0
[root@k8sctrpln01 ~]# cat > /etc/sysctl.d/99-kubernetes-cri.conf <<EOF
> net.bridge.bridge-nf-call-iptables  = 1
> net.ipv4.ip_forward                 = 1
> net.bridge.bridge-nf-call-ip6tables = 1
> EOF
[root@k8sctrpln01 ~]# sysctl -n net.bridge.bridge-nf-call-iptables -n net.ipv4.ip_forward -n net.bridge.bridge-nf-call-ip6tables
1
0
1
[root@k8sctrpln01 ~]# sysctl --system
* Applying /usr/lib/sysctl.d/00-system.conf ...
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-arptables = 0
* Applying /usr/lib/sysctl.d/10-default-yama-scope.conf ...
kernel.yama.ptrace_scope = 0
* Applying /usr/lib/sysctl.d/50-default.conf ...
kernel.sysrq = 16
kernel.core_uses_pid = 1
kernel.kptr_restrict = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.promote_secondaries = 1
net.ipv4.conf.all.promote_secondaries = 1
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
* Applying /etc/sysctl.d/99-kubernetes-cri.conf ...
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
* Applying /etc/sysctl.d/99-sysctl.conf ...
* Applying /etc/sysctl.d/disable_ipv6.conf ...
net.ipv6.conf.all.disable_ipv6 = 1
* Applying /etc/sysctl.d/k8s.conf ...
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
* Applying /etc/sysctl.conf ...
[root@k8sctrpln01 ~]# sysctl -n net.bridge.bridge-nf-call-iptables -n net.ipv4.ip_forward -n net.bridge.bridge-nf-call-ip6tables
1
1
1
containerdのインストール
[root@k8sctrpln01 ~]# yum install -y yum-utils device-mapper-persistent-data lvm2
---snip---
[root@k8sctrpln01 ~]# yum list installed -q yum-utils device-mapper-persistent-data lvm2
インストール済みパッケージ
device-mapper-persistent-data.x86_64                          0.8.5-3.el7_9.2                                @updates
lvm2.x86_64                                                   7:2.02.187-6.el7_9.5                           @updates
yum-utils.noarch                                              1.1.31-54.el7_8                                @base
[root@k8sctrpln01 ~]# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
読み込んだプラグイン:fastestmirror
adding repo from: https://download.docker.com/linux/centos/docker-ce.repo
grabbing file https://download.docker.com/linux/centos/docker-ce.repo to /etc/yum.repos.d/docker-ce.repo
repo saved to /etc/yum.repos.d/docker-ce.repo
[root@k8sctrpln01 ~]# yum update -y
---snip---
[root@k8sctrpln01 ~]# yum install -y containerd.io
---snip---
[root@k8sctrpln01 ~]# yum list -q containerd.io
インストール済みパッケージ
containerd.io.x86_64                                 1.6.4-3.1.el7                                  @docker-ce-stable
[root@k8sctrpln01 ~]# mkdir -p /etc/containerd
[root@k8sctrpln01 ~]# mv /etc/containerd/config.toml /etc/containerd/config.toml_org
[root@k8sctrpln01 ~]# containerd config default > /etc/containerd/config.toml
[root@k8sctrpln01 ~]# systemctl restart containerd
[root@k8sctrpln01 ~]# systemctl is-active containerd
active

公式ドキュメントでは自動起動の有効化はしていないが、試しに無効のままでOS再起動したら各種サービスが起動しなかったので有効化しておく。

[root@k8sctrpln01 ~]# systemctl is-enabled containerd
disabled
[root@k8sctrpln01 ~]# systemctl enable containerd
Created symlink from /etc/systemd/system/multi-user.target.wants/containerd.service to /usr/lib/systemd/system/containerd.service.
[root@k8sctrpln01 ~]# systemctl is-enabled containerd
enabled
systemd

systemdのcgroupドライバーを使うには、/etc/containerd/config.toml内でplugins.cri.systemd_cgroup = trueを設定してください。

plugins.cri.systemd_cgroupgrepしても見つからなくて、どこのセクションに書けば良いかわからず困ったが、以下の構造らしい。わからんわ。

[root@k8sctrpln01 ~]# cat -n /etc/containerd/config.toml | grep systemd_cgroup
    67      systemd_cgroup = false
[root@k8sctrpln01 ~]# cat -n /etc/containerd/config.toml
---snip---
    45    [plugins."io.containerd.grpc.v1.cri"]
    46      device_ownership_from_security_context = false
    47      disable_apparmor = false
    48      disable_cgroup = false
    49      disable_hugetlb_controller = true
    50      disable_proc_mount = false
    51      disable_tcp_service = true
    52      enable_selinux = false
    53      enable_tls_streaming = false
    54      enable_unprivileged_icmp = false
    55      enable_unprivileged_ports = false
    56      ignore_image_defined_volumes = false
    57      max_concurrent_downloads = 3
    58      max_container_log_line_size = 16384
    59      netns_mounts_under_state_dir = false
    60      restrict_oom_score_adj = false
    61      sandbox_image = "k8s.gcr.io/pause:3.6"
    62      selinux_category_range = 1024
    63      stats_collect_period = 10
    64      stream_idle_timeout = "4h0m0s"
    65      stream_server_address = "127.0.0.1"
    66      stream_server_port = "0"
    67      systemd_cgroup = false
    68      tolerate_missing_hugetlb_controller = true
    69      unset_seccomp_profile = ""
---snip---
[root@k8sctrpln01 ~]# sed -i 's/systemd_cgroup = false/systemd_cgroup = true/g' /etc/containerd/config.toml
[root@k8sctrpln01 ~]# cat -n /etc/containerd/config.toml | grep systemd_cgroup
    67      systemd_cgroup = true

kubeadmを使う場合はkubeletのためのcgroupドライバーを手動で設定してください。

後ほど設定する。

kubeadm、kubelet、kubectlのインストール

[root@k8sctrpln01 ~]# cat <<EOF > /etc/yum.repos.d/kubernetes.repo
> [kubernetes]
> name=Kubernetes
> baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
> enabled=1
> gpgcheck=1
> repo_gpgcheck=1
> gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
> EOF
[root@k8sctrpln01 ~]# setenforce 0
[root@k8sctrpln01 ~]# getenforce
Permissive
[root@k8sctrpln01 ~]# sed -i '/^SELINUX=/s/.*/SELINUX=permissive/' /etc/selinux/config
[root@k8sctrpln01 ~]# grep "^SELINUX=" /etc/selinux/config
SELINUX=permissive
[root@k8sctrpln01 ~]# yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
読み込んだプラグイン:fastestmirror
Loading mirror speeds from cached hostfile
 * base: ftp.iij.ad.jp
 * extras: ftp.iij.ad.jp
 * updates: ftp.iij.ad.jp
base                                                                                          | 3.6 kB  00:00:00
extras                                                                                        | 2.9 kB  00:00:00
kubernetes/signature                                                                          |  844 B  00:00:00
https://packages.cloud.google.com/yum/doc/yum-key.gpg から鍵を取得中です。
Importing GPG key 0x6B4097C2:
 Userid     : "Rapture Automatic Signing Key (cloud-rapture-signing-key-2022-03-07-08_01_01.pub)"
 Fingerprint: e936 7157 4236 81a4 7ec3 93c3 7325 816a 6b40 97c2
 From       : https://packages.cloud.google.com/yum/doc/yum-key.gpg
https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg から鍵を取得中です。
kubernetes/signature                                                                          | 1.4 kB  00:00:00 !!!
https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64/repodata/repomd.xml: [Errno -1] repomd.xml signature could not be verified for kubernetes
他のミラーを試します。


 One of the configured repositories failed (Kubernetes),
 and yum doesn't have enough cached data to continue. At this point the only
 safe thing yum can do is fail. There are a few ways to work "fix" this:

     1. Contact the upstream for the repository and get them to fix the problem.

     2. Reconfigure the baseurl/etc. for the repository, to point to a working
        upstream. This is most often useful if you are using a newer
        distribution release than is supported by the repository (and the
        packages for the previous distribution release still work).

     3. Run the command with the repository temporarily disabled
            yum --disablerepo=kubernetes ...

     4. Disable the repository permanently, so yum won't use it by default. Yum
        will then just ignore the repository until you permanently enable it
        again or use --enablerepo for temporary usage:

            yum-config-manager --disable kubernetes
        or
            subscription-manager repos --disable=kubernetes

     5. Configure the failing repository to be skipped, if it is unavailable.
        Note that yum will try to contact the repo. when it runs most commands,
        so will have to try and fail each time (and thus. yum will be be much
        slower). If it is a very temporary problem though, this is often a nice
        compromise:

            yum-config-manager --save --setopt=kubernetes.skip_if_unavailable=true

failure: repodata/repomd.xml from kubernetes: [Errno 256] No more mirrors to try.
https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64/repodata/repomd.xml: [Errno -1] repomd.xml signature could not be verified for kubernetes

GPGチェックが失敗した様子。 github.com

repo_gpgcheck=0でチェックをスキップする。

[root@k8sctrpln01 ~]# sed -i 's/^repo_gpgcheck=1/repo_gpgcheck=0/g' /etc/yum.repos.d/kubernetes.repo
[root@k8sctrpln01 ~]# yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
[root@k8sctrpln01 ~]# yum list -q kubelet kubeadm kubectl
インストール済みパッケージ
kubeadm.x86_64                                          1.24.1-0                                          @kubernetes
kubectl.x86_64                                          1.24.1-0                                          @kubernetes
kubelet.x86_64                                          1.24.1-0                                          @kubernetes
[root@k8sctrpln01 ~]# systemctl enable --now kubelet
Created symlink from /etc/systemd/system/multi-user.target.wants/kubelet.service to /usr/lib/systemd/system/kubelet.service.
[root@k8sctrpln01 ~]# systemctl is-enabled kubelet
enabled
[root@k8sctrpln01 ~]# systemctl is-active kubelet
activating

この時点ではまだactiveにならなくて正しい。

kubeadmが何をすべきか指示するまで、kubeletはクラッシュループで数秒ごとに再起動します。

コントロールプレーンノードのkubeletによって使用されるcgroupドライバーの設定

[root@k8sctrpln01 ~]# cat /etc/sysconfig/kubelet
KUBELET_EXTRA_ARGS=
[root@k8sctrpln01 ~]# sed -i "s/^KUBELET_EXTRA_ARGS=/KUBELET_EXTRA_ARGS=--cgroup-driver=systemd/g" /etc/sysconfig/kubelet
[root@k8sctrpln01 ~]# cat /etc/sysconfig/kubelet
KUBELET_EXTRA_ARGS=--cgroup-driver=systemd
[root@k8sctrpln01 ~]# systemctl daemon-reload
[root@k8sctrpln01 ~]# systemctl restart kubelet

次の項目

次のページへ。

kubeadmを使用したクラスターの作成

始める前に

さっき見た。

目的

へい。

手順

ホストへのkubeadmのインストール

さっきやった。

コントロールプレーンノードの初期化

[root@k8sctrpln01 ~]# kubeadm init --pod-network-cidr 10.244.0.0/16
W0529 05:32:54.020100   15143 version.go:103] could not fetch a Kubernetes version from the internet: unable to get URL "https://dl.k8s.io/release/stable-1.txt": Get "https://dl.k8s.io/release/stable-1.txt": dial tcp: lookup dl.k8s.io on 172.16.0.2:53: server misbehaving
W0529 05:32:54.020248   15143 version.go:104] falling back to the local client version: v1.24.1
[init] Using Kubernetes version: v1.24.1
[preflight] Running pre-flight checks
        [WARNING Firewalld]: firewalld is active, please ensure ports [6443 10250] are open or your cluster may not function correctly
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
error execution phase preflight: [preflight] Some fatal errors occurred:
        [ERROR ImagePull]: failed to pull image k8s.gcr.io/kube-apiserver:v1.24.1: output: E0529 05:32:55.259199   15185 remote_image.go:238] "PullImage from image service failed" err="rpc error: code = Unknown desc = failed to pull and unpack image \"k8s.gcr.io/kube-apiserver:v1.24.1\": failed to resolve reference \"k8s.gcr.io/kube-apiserver:v1.24.1\": failed to do request: Head \"https://k8s.gcr.io/v2/kube-apiserver/manifests/v1.24.1\": dial tcp: lookup k8s.gcr.io on 172.16.0.2:53: server misbehaving" image="k8s.gcr.io/kube-apiserver:v1.24.1"
time="2022-05-29T05:32:55+09:00" level=fatal msg="pulling image: rpc error: code = Unknown desc = failed to pull and unpack image \"k8s.gcr.io/kube-apiserver:v1.24.1\": failed to resolve reference \"k8s.gcr.io/kube-apiserver:v1.24.1\": failed to do request: Head \"https://k8s.gcr.io/v2/kube-apiserver/manifests/v1.24.1\": dial tcp: lookup k8s.gcr.io on 172.16.0.2:53: server misbehaving"
, error: exit status 1
---snip---
[preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`
To see the stack trace of this error execute with --v=5 or higher

うまくいかない。エラー抜粋。

        [ERROR ImagePull]: failed to pull image k8s.gcr.io/kube-apiserver:v1.24.1: output: E0529 05:32:55.259199   15185 remote_image.go:238] "PullImage from image service failed" err="rpc error: code = Unknown desc = failed to pull and unpack image \"k8s.gcr.io/kube-apiserver:v1.24.1\": failed to resolve reference \"k8s.gcr.io/kube-apiserver:v1.24.1\": failed to do request: Head \"https://k8s.gcr.io/v2/kube-apiserver/manifests/v1.24.1\": dial tcp: lookup k8s.gcr.io on 172.16.0.2:53: server misbehaving" image="k8s.gcr.io/kube-apiserver:v1.24.1"

さらに抜粋。

dial tcp: lookup k8s.gcr.io on 172.16.0.2:53: server misbehaving

k8s.gcr.ioの名前解決に失敗している。
原因はプロキシの設定不足。当環境はプロキシサーバを経由してインターネットにアクセスする構成のため、設定が必要だった。

こちらを参考に Containerdサービスの起動パラメータにプロキシを設定することで解決した。

[root@k8sctrpln01 ~]# mkdir /etc/systemd/system/containerd.service.d
[root@k8sctrpln01 ~]# cat <<EOF > /etc/systemd/system/containerd.service.d/http-proxy.conf
[Service]
Environment='HTTP_PROXY=http://proxy01:3128'
Environment='HTTPS_PROXY=http://proxy01:3128'
EOF
[root@k8sctrpln01 ~]# systemctl daemon-reload
[root@k8sctrpln01 ~]# systemctl restart containerd
[root@k8sctrpln01 ~]# kubeadm init --pod-network-cidr 10.244.0.0/16
W0529 06:12:34.627517   17351 version.go:103] could not fetch a Kubernetes version from the internet: unable to get URL "https://dl.k8s.io/release/stable-1.txt": Get "https://dl.k8s.io/release/stable-1.txt": dial tcp: lookup dl.k8s.io on 172.16.0.2:53: server misbehaving
W0529 06:12:34.627588   17351 version.go:104] falling back to the local client version: v1.24.1
[init] Using Kubernetes version: v1.24.1
[preflight] Running pre-flight checks
        [WARNING Firewalld]: firewalld is active, please ensure ports [6443 10250] are open or your cluster may not function correctly
error execution phase preflight: [preflight] Some fatal errors occurred:
        [ERROR CRI]: container runtime is not running: output: E0529 06:12:34.648929   17359 remote_runtime.go:925] "Status from runtime service failed" err="rpc error: code = Unimplemented desc = unknown service runtime.v1alpha2.RuntimeService"
time="2022-05-29T06:12:34+09:00" level=fatal msg="getting status of runtime: rpc error: code = Unimplemented desc = unknown service runtime.v1alpha2.RuntimeService"
, error: exit status 1
[preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`
To see the stack trace of this error execute with --v=5 or higher

が、別のエラーが出た。抜粋。

        [ERROR CRI]: container runtime is not running: output: E0529 06:12:34.648929   17359 remote_runtime.go:925] "Status from runtime service failed" err="rpc error: code = Unimplemented desc = unknown service runtime.v1alpha2.RuntimeService"

まずは自力で調査。Containerdサービスは起動している。

[root@k8sctrpln01 ~]# systemctl is-active containerd
active

しかし、Containerdのユーティリティであるcrictlコマンドが使えない。

[root@k8sctrpln01 ~]# crictl version
WARN[0000] runtime connect using default endpoints: [unix:///var/run/dockershim.sock unix:///run/containerd/containerd.sock unix:///run/crio/crio.sock unix:///var/run/cri-dockerd.sock]. As the default settings are now deprecated, you should set the endpoint instead.
ERRO[0000] unable to determine runtime API version: rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial unix /var/run/dockershim.sock: connect: no such file or directory"
E0529 06:36:10.222225   18569 remote_runtime.go:168] "Version from runtime service failed" err="rpc error: code = Unimplemented desc = unknown service runtime.v1alpha2.RuntimeService"
FATA[0000] getting the runtime version: rpc error: code = Unimplemented desc = unknown service runtime.v1alpha2.RuntimeService

WARNはendpointを指定することで回避できたが、エラーは解消せず。

[root@k8sctrpln01 ~]# crictl --runtime-endpoint unix:///run/containerd/containerd.sock version
E0529 06:36:44.521051   18602 remote_runtime.go:168] "Version from runtime service failed" err="rpc error: code = Unimplemented desc = unknown service runtime.v1alpha2.RuntimeService"
FATA[0000] getting the runtime version: rpc error: code = Unimplemented desc = unknown service runtime.v1alpha2.RuntimeService

ググる/etc/containerd/config.tomlを削除すれば良い的な記事が見つかった。解せないが他に対処方法も見つからないため、実施する。 github.com

[root@k8sctrpln01 ~]# rm /etc/containerd/config.toml
rm: 通常ファイル `/etc/containerd/config.toml' を削除しますか? y
[root@k8sctrpln01 ~]# systemctl restart containerd
[root@k8sctrpln01 ~]# systemctl is-active containerd
active

crictlコマンドが使えるようになった。

[root@k8sctrpln01 ~]# crictl --runtime-endpoint unix:///run/containerd/containerd.sock version
Version:  0.1.0
RuntimeName:  containerd
RuntimeVersion:  1.6.4
RuntimeApiVersion:  v1

/etc/containerd/config.tomlにわざわざsystemd_cgroup = trueを設定したが、あればなんだったのか・・・

本題に戻りkubeadm initをリトライ。ようやく突破した。

[root@k8sctrpln01 ~]# kubeadm init --pod-network-cidr 10.244.0.0/16
W0529 07:07:11.390743   20256 version.go:103] could not fetch a Kubernetes version from the internet: unable to get URL "https://dl.k8s.io/release/stable-1.txt": Get "https://dl.k8s.io/release/stable-1.txt": dial tcp: lookup dl.k8s.io on 172.16.0.2:53: server misbehaving
W0529 07:07:11.390884   20256 version.go:104] falling back to the local client version: v1.24.1
[init] Using Kubernetes version: v1.24.1
[preflight] Running pre-flight checks
        [WARNING Firewalld]: firewalld is active, please ensure ports [6443 10250] are open or your cluster may not function correctly
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [k8sctrpln01 kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 172.16.0.11]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [k8sctrpln01 localhost] and IPs [172.16.0.11 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [k8sctrpln01 localhost] and IPs [172.16.0.11 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[apiclient] All control plane components are healthy after 39.505506 seconds
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config" in namespace kube-system with the configuration for the kubelets in the cluster
[kubelet-check] Initial timeout of 40s passed.
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node k8sctrpln01 as control-plane by adding the labels: [node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers]
[mark-control-plane] Marking the node k8sctrpln01 as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule node-role.kubernetes.io/control-plane:NoSchedule]
[bootstrap-token] Using token: 1alk8n.8haf7p9cszxh2kw1
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] Configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] Configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 172.16.0.11:6443 --token 1alk8n.8haf7p9cszxh2kw1 \
        --discovery-token-ca-cert-hash sha256:fc839a2ff1689c9af8f302670a51c1c44e5a16b7d89304931b7cc9052a192caf

apiserver-advertise-addressとControlPlaneEndpointに関する検討

コントロールプレーンノードをクラスタ構成にする場合は対処が必要。今回はシングルノード構成なのでスキップ。

詳細な情報

[root@k8sctrpln01 ~]# mkdir -p $HOME/.kube
[root@k8sctrpln01 ~]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@k8sctrpln01 ~]# sudo chown $(id -u):$(id -g) $HOME/.kube/config
[root@k8sctrpln01 ~]# export KUBECONFIG=/etc/kubernetes/admin.conf

Podネットワークアドオンのインストール

Podネットワークアドオンが未インストールの状態だと、corednsがPending状態のままになっている。

[root@k8sctrpln01 ~]# kubectl get pods --all-namespaces
NAMESPACE     NAME                                  READY   STATUS    RESTARTS   AGE
kube-system   coredns-6d4b75cb6d-66hl2              0/1     Pending   0          3m1s
kube-system   coredns-6d4b75cb6d-vnw7j              0/1     Pending   0          3m1s
kube-system   etcd-k8sctrpln01                      1/1     Running   0          3m30s
kube-system   kube-apiserver-k8sctrpln01            1/1     Running   0          3m16s
kube-system   kube-controller-manager-k8sctrpln01   1/1     Running   0          3m31s
kube-system   kube-proxy-cktd6                      1/1     Running   0          3m1s
kube-system   kube-scheduler-k8sctrpln01            1/1     Running   0          3m30s

アドオンはいくつかあるが、とくに根拠も無くflannelを使用する。 入手先のURLはkubeadm initの標準出力に記載されている(普通に見逃す)。さらに、後述するが、flannelのバージョンが最新のv0.18.0では正常動作せず、v0.16.3を使用した。

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

以下にたどり着く。 github.com Deploying flannel manuallyを参考にインストールする。

[root@k8sctrpln01 ~]# kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
Unable to connect to the server: dial tcp: lookup raw.githubusercontent.com on 172.16.0.2:53: server misbehaving

ここでもプロキシの壁が。

[root@k8sctrpln01 ~]# cat <<EOF > /etc/profile.d/k8s.sh
> export http_proxy=http://proxy01:3128
> export https_proxy=http://proxy01:3128
> EOF
[root@k8sctrpln01 ~]# source /etc/profile.d/k8s.sh
[root@k8sctrpln01 ~]# env | grep proxy
http_proxy=http://proxy01:3128
https_proxy=http://proxy01:3128

改めてインストール。

[root@k8sctrpln01 ~]# kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
podsecuritypolicy.policy/psp.flannel.unprivileged created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
serviceaccount/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created

まずkube-flannelの状態がInitRunningに遷移する。次いでcorednsの状態がContainerCreatingに遷移するのだが、Runningまで遷移しない。そしてkube-flannelはErrorになる始末。

[root@k8sctrpln01 ~]# kubectl get pods --all-namespaces
NAMESPACE     NAME                                  READY   STATUS              RESTARTS     AGE
kube-system   coredns-6d4b75cb6d-66hl2              0/1     ContainerCreating   0            5m21s
kube-system   coredns-6d4b75cb6d-vnw7j              0/1     ContainerCreating   0            5m21s
kube-system   etcd-k8sctrpln01                      1/1     Running             0            5m50s
kube-system   kube-apiserver-k8sctrpln01            1/1     Running             0            5m36s
kube-system   kube-controller-manager-k8sctrpln01   1/1     Running             0            5m51s
kube-system   kube-flannel-ds-vdwnm                 0/1     Error               1 (9s ago)   56s
kube-system   kube-proxy-cktd6                      1/1     Running             0            5m21s
kube-system   kube-scheduler-k8sctrpln01            1/1     Running             0            5m50s

kube-flannelのPodのログを確認する。

[root@k8sctrpln01 ~]# kubectl -n kube-system logs kube-flannel-ds-vdwnm
Defaulted container "kube-flannel" out of: kube-flannel, install-cni-plugin (init), install-cni (init)
I0528 22:14:46.576077       1 main.go:207] CLI flags config: {etcdEndpoints:http://127.0.0.1:4001,http://127.0.0.1:2379 etcdPrefix:/coreos.com/network etcdKeyfile: etcdCertfile: etcdCAFile: etcdUsername: etcdPassword: version:false kubeSubnetMgr:true kubeApiUrl: kubeAnnotationPrefix:flannel.alpha.coreos.com kubeConfigFile: iface:[] ifaceRegex:[] ipMasq:true ifaceCanReach: subnetFile:/run/flannel/subnet.env publicIP: publicIPv6: subnetLeaseRenewMargin:60 healthzIP:0.0.0.0 healthzPort:0 iptablesResyncSeconds:5 iptablesForwardRules:true netConfPath:/etc/kube-flannel/net-conf.json setNodeNetworkUnavailable:true}
W0528 22:14:46.576246       1 client_config.go:614] Neither --kubeconfig nor --master was specified.  Using the inClusterConfig.  This might not work.
I0528 22:14:46.773989       1 kube.go:121] Waiting 10m0s for node controller to sync
I0528 22:14:46.774494       1 kube.go:398] Starting kube subnet manager
I0528 22:14:47.774698       1 kube.go:128] Node controller sync successful
I0528 22:14:47.774727       1 main.go:227] Created subnet manager: Kubernetes Subnet Manager - k8sctrpln01
I0528 22:14:47.774733       1 main.go:230] Installing signal handlers
I0528 22:14:47.774886       1 main.go:463] Found network config - Backend type: vxlan
I0528 22:14:47.775008       1 match.go:195] Determining IP address of default interface
E0528 22:14:47.775135       1 main.go:270] Failed to find any valid interface to use: failed to get default interface: protocol not available

flannnelが通信するインターフェースを自動検出する処理が、Failed to find any valid interface to use: failed to get default interface: protocol not availableで失敗しているのが直接原因の様子。色々と調べたり試したりしたが、解消できなかった。
/run/flannel/subnet.envを手動作成してみたり、kubeadm resetしてみたり、kube-flannel.ymlを編集してインターフェースを指定してみたり。

切り分けとして手元にあった古いバージョンのkube-flannel.ymlを使用したところ解消。とりあえずこれでいいや・・・

  • 最新のバージョン
[root@k8sctrpln01 ~]# curl -s https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.
yml | grep image | grep -v "#"
        image: rancher/mirrored-flannelcni-flannel-cni-plugin:v1.1.0
        image: rancher/mirrored-flannelcni-flannel:v0.18.0
        image: rancher/mirrored-flannelcni-flannel:v0.18.0
  • 古いバージョン
[root@k8sctrpln01 ~]# cat kube-flannel.yml | grep image | grep -v "#"
        image: rancher/mirrored-flannelcni-flannel-cni-plugin:v1.0.1
        image: rancher/mirrored-flannelcni-flannel:v0.16.3
        image: rancher/mirrored-flannelcni-flannel:v0.16.3
[root@k8sctrpln01 ~]# kubectl apply -f kube-flannel.yml
Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
podsecuritypolicy.policy/psp.flannel.unprivileged configured
clusterrole.rbac.authorization.k8s.io/flannel unchanged
clusterrolebinding.rbac.authorization.k8s.io/flannel unchanged
serviceaccount/flannel unchanged
configmap/kube-flannel-cfg unchanged
daemonset.apps/kube-flannel-ds configured
[root@k8sctrpln01 ~]# kubectl get pods --all-namespaces
NAMESPACE     NAME                                  READY   STATUS    RESTARTS   AGE
kube-system   coredns-6d4b75cb6d-66hl2              1/1     Running   0          20m
kube-system   coredns-6d4b75cb6d-vnw7j              1/1     Running   0          20m
kube-system   etcd-k8sctrpln01                      1/1     Running   0          20m
kube-system   kube-apiserver-k8sctrpln01            1/1     Running   0          20m
kube-system   kube-controller-manager-k8sctrpln01   1/1     Running   0          20m
kube-system   kube-flannel-ds-vdzrd                 1/1     Running   0          68s
kube-system   kube-proxy-cktd6                      1/1     Running   0          20m
kube-system   kube-scheduler-k8sctrpln01            1/1     Running   0          20m

なお、この時点でコントロールプレーンノードがReadyになっている。

[root@k8sctrpln01 ~]# kubectl get node
NAME          STATUS   ROLES           AGE   VERSION
k8sctrpln01   Ready    control-plane   21m   v1.24.1

コントロールプレーンノードの隔離

Podはワーカノードのみで起動させたいので対象外。

ノードの追加

当環境のノードは仮想ゲストマシンのため、コントロールプレーンノードからワーカノードを複製し、ワーカノード向けに設定変更する方式で構築する。
ノードの複製、ホスト名やIPアドレスの変更が完了したところから記載する。

Kubernetes環境を初期化する。

[root@k8sworker01 ~]# yes | kubeadm reset
[reset] Reading configuration from the cluster...
[reset] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
W0527 20:08:44.001097    2944 preflight.go:55] [reset] WARNING: Changes made to this host by 'kubeadm init' or 'kubeadm join' will be reverted.
[reset] Are you sure you want to proceed? [y/N]: [preflight] Running pre-flight checks
[reset] Stopping the kubelet service
[reset] Unmounting mounted directories in "/var/lib/kubelet"
W0527 20:09:23.058909    2944 cleanupnode.go:93] [reset] Failed to remove containers: [failed to remove running container 32ffc7801249a8077520b4876f5cd27f49929bb048ccb679d2387f012a9a2da8: output: E0527 20:08:53.857270    3260 remote_runtime.go:274] "RemovePodSandbox from runtime service failed" err="rpc error: code = DeadlineExceeded desc = context deadline exceeded" podSandboxID="32ffc7801249a8077520b4876f5cd27f49929bb048ccb679d2387f012a9a2da8"
removing the pod sandbox "32ffc7801249a8077520b4876f5cd27f49929bb048ccb679d2387f012a9a2da8": rpc error: code = DeadlineExceeded desc = context deadline exceeded
, error: exit status 1, failed to remove running container f10a6ab2bba52dd9212ae35d13b4347a939d81df8d65a75b6e8509d3d7908784: output: E0527 20:08:57.084978    3347 remote_runtime.go:274] "RemovePodSandbox from runtime service failed" err="rpc error: code = DeadlineExceeded desc = context deadline exceeded" podSandboxID="f10a6ab2bba52dd9212ae35d13b4347a939d81df8d65a75b6e8509d3d7908784"
removing the pod sandbox "f10a6ab2bba52dd9212ae35d13b4347a939d81df8d65a75b6e8509d3d7908784": rpc error: code = DeadlineExceeded desc = context deadline exceeded
, error: exit status 1, failed to stop running pod 208e167da6667e0dcf577d1cca0c57f44d8b698eaaaad96941d7bfdac26100f5: output: E0527 20:08:59.095956    3352 remote_runtime.go:248] "StopPodSandbox from runtime service failed" err="rpc error: code = DeadlineExceeded desc = failed to stop container \"0807cc39ba94fdbce032437b78e9ff4306bf3eed3b33b21292bedacacd1a5a86\": an error occurs during waiting for container \"0807cc39ba94fdbce032437b78e9ff4306bf3eed3b33b21292bedacacd1a5a86\" to be killed: wait container \"0807cc39ba94fdbce032437b78e9ff4306bf3eed3b33b21292bedacacd1a5a86\": context deadline exceeded" podSandboxID="208e167da6667e0dcf577d1cca0c57f44d8b698eaaaad96941d7bfdac26100f5"
time="2022-05-27T20:08:59+09:00" level=fatal msg="stopping the pod sandbox \"208e167da6667e0dcf577d1cca0c57f44d8b698eaaaad96941d7bfdac26100f5\": rpc error: code = DeadlineExceeded desc = failed to stop container \"0807cc39ba94fdbce032437b78e9ff4306bf3eed3b33b21292bedacacd1a5a86\": an error occurs during waiting for container \"0807cc39ba94fdbce032437b78e9ff4306bf3eed3b33b21292bedacacd1a5a86\" to be killed: wait container \"0807cc39ba94fdbce032437b78e9ff4306bf3eed3b33b21292bedacacd1a5a86\": context deadline exceeded"
, error: exit status 1, failed to stop running pod 9d3c0e0634883d65e2dde44ecf40c2c7d31a2dc24a2063e48af923433840e2f8: output: E0527 20:09:01.107616    3388 remote_runtime.go:248] "StopPodSandbox from runtime service failed" err="rpc error: code = DeadlineExceeded desc = context deadline exceeded" podSandboxID="9d3c0e0634883d65e2dde44ecf40c2c7d31a2dc24a2063e48af923433840e2f8"
time="2022-05-27T20:09:01+09:00" level=fatal msg="stopping the pod sandbox \"9d3c0e0634883d65e2dde44ecf40c2c7d31a2dc24a2063e48af923433840e2f8\": rpc error: code = DeadlineExceeded desc = context deadline exceeded"
, error: exit status 1, failed to remove running container 830472a335e3e7438337679bcfc7a16813f336eff1905e4f9111a56819ee5623: output: E0527 20:09:16.298865    3753 remote_runtime.go:274] "RemovePodSandbox from runtime service failed" err="rpc error: code = DeadlineExceeded desc = context deadline exceeded" podSandboxID="830472a335e3e7438337679bcfc7a16813f336eff1905e4f9111a56819ee5623"
removing the pod sandbox "830472a335e3e7438337679bcfc7a16813f336eff1905e4f9111a56819ee5623": rpc error: code = DeadlineExceeded desc = context deadline exceeded
, error: exit status 1, failed to remove running container e0ce40c26ba17869724471443fcc7b0af25356e883fd1ab6753c2c2dcd0ecae4: output: E0527 20:09:23.058159    3807 remote_runtime.go:274] "RemovePodSandbox from runtime service failed" err="rpc error: code = DeadlineExceeded desc = context deadline exceeded" podSandboxID="e0ce40c26ba17869724471443fcc7b0af25356e883fd1ab6753c2c2dcd0ecae4"
removing the pod sandbox "e0ce40c26ba17869724471443fcc7b0af25356e883fd1ab6753c2c2dcd0ecae4": rpc error: code = DeadlineExceeded desc = context deadline exceeded
, error: exit status 1]
[reset] Deleting contents of directories: [/etc/kubernetes/manifests /etc/kubernetes/pki]
[reset] Deleting files: [/etc/kubernetes/admin.conf /etc/kubernetes/kubelet.conf /etc/kubernetes/bootstrap-kubelet.conf /etc/kubernetes/controller-manager.conf /etc/kubernetes/scheduler.conf]
[reset] Deleting contents of stateful directories: [/var/lib/etcd /var/lib/kubelet /var/lib/dockershim /var/run/kubernetes /var/lib/cni]

The reset process does not clean CNI configuration. To do so, you must remove /etc/cni/net.d

The reset process does not reset or clean up iptables rules or IPVS tables.
If you wish to reset iptables, you must do so manually by using the "iptables" command.

If your cluster was setup to utilize IPVS, run ipvsadm --clear (or similar)
to reset your system's IPVS tables.

The reset process does not clean your kubeconfig files and you must remove them manually.
Please, check the contents of the $HOME/.kube/config file.

手動でのクリーンアップも必要。

[root@k8sworker01 ~]# ls -l $HOME/.kube/config
-rw-------. 1 root root 5635  5月 27 17:03 /root/.kube/config
[root@k8sworker01 ~]# rm -f $HOME/.kube/config
[root@k8sworker01 ~]# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:17:78:f8 brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:8d:4c:c5 brd ff:ff:ff:ff:ff:ff
4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:07:f1:85 brd ff:ff:ff:ff:ff:ff
5: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN mode DEFAULT group default 
    link/ether 12:d2:03:a5:d2:5a brd ff:ff:ff:ff:ff:ff
6: cni0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000
    link/ether 6a:55:d4:30:30:97 brd ff:ff:ff:ff:ff:ff
[root@k8sworker01 ~]# ip link delete cni0
[root@k8sworker01 ~]# ip link delete flannel.1
[root@k8sworker01 ~]# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:17:78:f8 brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:8d:4c:c5 brd ff:ff:ff:ff:ff:ff
4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:07:f1:85 brd ff:ff:ff:ff:ff:ff

ワーカノード用にファイアウォールを設定する。

[root@k8sworker01 ~]# firewall-cmd --list-services
dhcpv6-client etcd-client etcd-server snmp ssh
[root@k8sworker01 ~]# firewall-cmd --list-ports
6443/tcp 10250/tcp 10251/tcp 10252/tcp
[root@k8sworker01 ~]# firewall-cmd --add-port=30000-32767/tcp --permanent
success
[root@k8sworker01 ~]# firewall-cmd --remove-service={etcd-client,etcd-server} --permanent
success
[root@k8sworker01 ~]# firewall-cmd --remove-port={6443/tcp,10251/tcp,10252/tcp} --permanent
success
[root@k8sworker01 ~]# firewall-cmd --reload
success
[root@k8sworker01 ~]# firewall-cmd --list-services
dhcpv6-client snmp ssh
[root@k8sworker01 ~]# firewall-cmd --list-ports
10250/tcp 30000-32767/tcp

コントロールプレーンノードでkubeadm initした際の標準出力に、ワーカノードをクラスタに参加させるkubeadm joinコマンドが表示されている。それを使っても構わないが、トークンの期限が24時間で更新が面倒なので、ここで無期限のトークンを作成してしまう。 zaki-hmkc.hatenablog.com

[root@k8sctrpln01 ~]# kubeadm token list
TOKEN                     TTL         EXPIRES                USAGES                   DESCRIPTION                                                EXTRA GROUPS
pbwo6h.lk8hjvpfuqroxf9u   20h         2022-05-28T08:27:45Z   authentication,signing   The default bootstrap token generated by 'kubeadm init'.   system:bootstrappers:kubeadm:default-node-token
[root@k8sctrpln01 ~]# kubeadm token delete 1alk8n.8haf7p9cszxh2kw1
bootstrap token "1alk8n" deleted
[root@k8sctrpln01 ~]# kubeadm token create --ttl 0 --print-join-command
kubeadm join 172.16.0.11:6443 --token o133rw.oyma9inaboa1ra9w --discovery-token-ca-cert-hash sha256:fc839a2ff1689c9af8f302670a51c1c44e5a16b7d89304931b7cc9052a192caf
[root@k8sctrpln01 ~]# kubeadm token list
TOKEN                     TTL         EXPIRES   USAGES                   DESCRIPTION                                                EXTRA GROUPS
o133rw.oyma9inaboa1ra9w   <forever>   <never>   authentication,signing   <none>                                                     system:bootstrappers:kubeadm:default-node-token
[root@k8sworker01 ~]# kubeadm join 172.16.0.11:6443 --token o133rw.oyma9inaboa1ra9w --discovery-token-ca-cert-hash sha256:fc839a2ff1689c9af8f302670a51c1c44e5a16b7d89304931b7cc9052a192caf
[preflight] Running pre-flight checks
        [WARNING HTTPProxy]: Connection to "https://172.16.0.11" uses proxy "http://proxy01:3128". If that is not intended, adjust your proxy settings
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

ワーカノードがクラスタに参加できたことを確認する。

[root@k8sctrpln01 ~]# kubectl get node
NAME          STATUS   ROLES           AGE     VERSION
k8sctrpln01   Ready    control-plane   65m     v1.24.1
k8sworker01   Ready    <none>          3m23s   v1.24.1

せっかくなのでワーカノードをもう1台参加させた。

[root@k8sctrpln01 ~]# kubectl get node
NAME          STATUS   ROLES           AGE     VERSION
k8sctrpln01   Ready    control-plane   69m     v1.24.1
k8sworker01   Ready    <none>          6m42s   v1.24.1
k8sworker02   Ready    <none>          55s     v1.24.1

おまけ。-o wideオプションが何かと便利。

[root@k8sctrpln01 ~]# kubectl get node -o wide
NAME          STATUS   ROLES           AGE     VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION                CONTAINER-RUNTIME
k8sctrpln01   Ready    control-plane   69m     v1.24.1   172.16.0.11   <none>        CentOS Linux 7 (Core)   3.10.0-1160.66.1.el7.x86_64   containerd://1.6.4
k8sworker01   Ready    <none>          6m53s   v1.24.1   172.16.0.12   <none>        CentOS Linux 7 (Core)   3.10.0-1160.66.1.el7.x86_64   containerd://1.6.4
k8sworker02   Ready    <none>          66s     v1.24.1   172.16.0.13   <none>        CentOS Linux 7 (Core)   3.10.0-1160.66.1.el7.x86_64   containerd://1.6.4

(オプション)コントロールプレーンノード以外のマシンからのクラスター操作

とりあえずスキップ。

(オプション)APIサーバーをlocalhostへプロキシする

とりあえずスキップ。

クリーンアップ

原則不要。環境再構築時など必要に応じて。

次の手順

見たところ必須ではなさそう。

あとがき

構築は2回目だったが、半日程度かかった。
トラブルの要因はいずれもパッケージのバージョンに起因するものだった。バージョンアップを躊躇させてくるね・・・

参考記事

本文中に記載。

Kubernetes記事まとめ

概要

目次

参考記事

qiita.com

TIPS: はんだ付けのために揃えた工具一式

f:id:none06:20220113234211j:plain

目次

概要

はんだ付けを始めるにあたり揃えたツールの記録。

はんだごて

  • FX600-02
    温度調節機能はマスト。

こて先

  • T18-D16
    汎用性が高く、ほとんどの素子に対応した。
  • T18-CF1
    切断面にしかはんだが付かないので引きはんだがやりやすいと思い購入。しかし使いこなせず。先端が丸くないので狭い場所に有利。
  • T18-CF2
    T18-CF2の少し太いバージョン。

こて台

  • 633-01
    金属のクリーナーなのでこて先の温度を下げにくい。

はんだ(φ0.3mm)

  • SE-06003RMA
    かなり細い。

はんだ(φ0.6mm)

  • SD-60
    やや細い。

はんだ吸い取り線

  • CP-2015
    使いやすい太さのものを選定。

フラックス

  • H-722
    ピッチが狭い場所に極めて有効。熱しすぎてフラックスが蒸発したはんだの復活にも使える。

フラックスクリーナー

  • BS-T20B
    フラックスの掃除に必要。

ピンセット

  • PT-06
    真っ直ぐのものや、逆作用ピンセットとも迷った。

ニッパー

  • NS-04
    まだ出番はないが、スルーホール実装で素子の足を切るシーンで使う予定。

ペンチ

手持ちの適当なもの。

ドライバー

手持ちの適当なもの。

テスター

  • TST-KJ830
    導通チェックができてコンパクトなものを選択。

作業マット

  • KaiYi
    青い製品が多かったので黒い製品にしてみた。