2021年8月15日日曜日

Kubernetesクラスタで、ノード起動後にDockerが起動せずにReadyにならない場合の確認と対処

Kubernetesクラスタに参加しているマシンを起動した直後に、kubectl get nodesで見えるステータスがNotReadyからReadyに変わるはずであるが、ごくまれにマシンは正常に起動しているにもかかわらず、Docker Daemonが正常に起動せず、それに引きずられてKubeletも起動しないため、Kubernetesクラスタ側からは認識されないという現象が起きるのでメモ書き程度に。

今回の題材にする環境は、おおよそ下記に示すソフトウェアや台数で構成しています。

  • Kubernetes 1.17.13
  • Ubuntu Server 18.04
  • Docker CE 19.03
  • Kubernetesクラスタの構築場所: オンプレミスのVMware ESXi ホスト上
  • Kubernetes Control-Planeノード x 3台
  • ワーカーノード x 5台

この事象が起きるクラスタはPrometheusで監視しているので、この現象が起きると毎回アラートが飛んでくるのであるが、大体いつもマシンは起動しているのに何故?と毎回焦るので…。
ここに書いたことで、この現象はそういえば書いたなという記憶に残ってくれてすぐに対処できたり、焦らなくなることに期待。


当該マシンにログイン後、下記コマンドでdockerとkubeletの動作状態を確認する。

sudo systemctl status docker
sudo systemctl status kubelet

docker / kubeletどちらのデーモンもinactiveになっているのであれば、dockerとkubeletを下記コマンドで手動で立ち上げてやることにより、とりあえずクラスタ内で機能する状態に戻せるはずです。

sudo systemctl start docker
sudo systemctl start kubelet

これらのコマンドで戻らない、あるいは起動してもinactiveに戻ってしまう場合などは、control-plane側で何か障害が起きているか、あるいはノード自体の情報がクラスタから飛んでしまっているなど別な要因も考えられます。


今回の現象がなぜ起こったのかを少し考えてみると、手作業でDocker Daemonを起動した際に時間が掛かっていたので、システム起動時の場合はタイムアウトとなり、Dockerが起動せずにそのまま立ち上がってしまうのが原因ではないかと考えております。
(systemctlコマンドから起動する際は人間が待っていれば良いのですが…)

Dockerが起動していない状態では、Kubeletも当然のように動作できないのでこのような現象が引き起こされるのではないかと推測しています。
(当該のKubernetesクラスタは、開発用の仮想サーバー20台程度を無理やり1台の仮想ホストに押し込んでいる環境下にあるので、多少動作遅延が出てもまぁあり得るよなあとしか思えないような状況)

Kubernetes + Containerdなど、Docker以外のCRIを使用している環境では、同じ現象が起きるかはまだ遭遇したことがありません。
(今回の現象の条件を考えると、似たようなことは起きる可能性はあるんじゃないかと思います)

2021年7月12日月曜日

TrueNAS 12.0でディスクを交換する

 TrueNAS (旧FreeNAS) を入れたマシンをNASとして4年ほど運用しているのですが、先日ディスク1台で不良セクタが見つかったのでディスク交換を行うことにしました。

修理を行う前のNASのだいたいのスペックは下記となります。

  • OS: TrueNAS-12.0-U3.1
    (FreeNAS 11.1からアップグレードし続けて運用中)
  • CPU: Celeron G3930
  • メモリ: 16GB
  • ディスク: 3TB HDD x 6 (WD Red)
  • ディスク構成: RAID-Z2 (6台すべて使用、スペアなし)

以下、自分自身の備忘録としても手順を書き残しておきます。


管理画面にログイン後、左側のメニューの「ストレージ」から「Pools」を開きます。



プールの一覧が表示されますので、交換したいディスクが含まれているプールを選び、右上の設定ボタンから「Status」を選びます。



Pool Statusが開きますので、交換したいディスク探します。
今回の例のように、すでに故障したディスクを取り外して新しいディスクに取り換えている場合は、以下の画面にあるように特定のディスクだけが「UNAVAIL」の表示になっているので見つけやすいと思います。



交換対象とするディスクの右側のメニューから「Replace」を選びます。



新しいディスクを選び、「REPLACE DISK」をクリックします。



交換が正常に完了すると、以下の画面が表示されます。

この画面は、ディスクの初期化等が完了すると表示されるため、時間はかからずに表示されます。
ですが、その後バックグラウンドでRAIDの再構築作業が行われておりますので、この画面が出たからと言って完了ではありませんので電源を入れっぱなしにしておきます。


また余談ですが、新しいディスクを選ぶ前に、先にディスクの一覧を確認しておいたほうが分かりやすく作業が行えるかもしれません。

左側メニューの「ストレージ」を開き、「ディスク」を開くとこの画面に辿り着けます。

この例では、ada2に新しいディスクを接続したため、この箇所だけ型番と容量が他のディスクと違うのがお分かりいただけるかと思います。


今回の故障をきっかけに、現在問題なく稼働しているディスクも順次入れ替えて容量を拡大することにしましたので、準備が整い次第Poolの容量拡大編も書こうと思います。

2021年5月16日日曜日

NEC IX2215でPPPoEとMAP-EによるIPv4接続を共存させてみた

外へのインターネット接続を、いい加減PPPoE方式による接続から、MAP-E方式による接続に切り替えたいと思っていたところ、思わぬ形でNECのIX2215というルーターをゲットしましたので早速やってみました。

NECの公式の方にMAP-E方式で接続する場合の設定例もアップされているため、MAP-Eでのインターネットへの接続自体は割とあっさりと行けました。

しかし、MAP-E方式では、一つのグローバルIPアドレスのうち、一部のポートのみが割り当てられる仕様のため、ポート開放は行えないためにサーバー用途での利用は事実上厳しいので、そのあたりをクリアするためには従来のPPPoE方式も併用する必要が出てきます。
(PPPoE方式ではプロバイダにもよりますが、グローバルIPアドレスが1つ割り当てられ、自由にポート開放したりできるため)

最初は、今回買ったIX2215でMAP-E接続を行い、外界との通信は基本的にそちらに流れるようにして、一部の通信のみは今までのルーター側に流してPPPoE接続側を通るようにしようかとも考えておりましたが、IX2215の設定をあれこれ弄り回すうちに、これって両方のセッションを一台で共存させて振り分けられるのでは?と思ったので試してみました。

イメージとしては下記となります。

  • GigaEthernet0 (GE0)をFlets回線へ接続
  • GigaEthernet1 (GE1)は外部公開しないマシン用のネットワークとして、別のスイッチに接続
  • GigaEthernet2 (GE2)をポートベースVLANで分割し、ポート1から4を外部公開するサーバー用に、ポート5から8を内部用に設定
  • 外部公開するサーバーは、「10.168.0.0/24」のネットワークに設置し、このネットワーク範囲から外部へのアクセスをIPv4アクセスリストで認識し、PPPoE側へと流す。
    (interface: GigaEthernet2:1.0 / route-map: pppoe-route / access list: local-filter)
  • それ以外のネットワークから外部にアクセスする場合、すべてIPoE側に流れるようにデフォルトルートを設定する。
    (デフォルトルート: Tunnel0.0)

大雑把に言うと、特定のネットワーク範囲のマシンから外部に通信する場合のみPPPoE側に流し、それ以外はすべてIPoE側に流すという動作をするように設定します。

構成例は下記となります。

ip ufs-cache max-entries 20000
ip ufs-cache enable
ip route default Tunnel0.0
ip dhcp enable

ipv6 ufs-cache max-entries 10000
ipv6 ufs-cache enable
ipv6 dhcp enable

proxy-dns ip enable
proxy-dns ip request both

ipv6 access-list block-list deny ip src any dest any
ipv6 access-list dhcpv6-list permit udp src any sport any dest any dport eq 546
ipv6 access-list dhcpv6-list permit udp src any sport any dest any dport eq 547
ipv6 access-list icmpv6-list permit icmp src any dest any
ipv6 access-list tunnel-list permit 4 src any dest any
ipv6 access-list other-list permit ip src any dest any
ipv6 access-list dynamic cache 65535
ipv6 access-list dynamic dflt-list access other-list

ip access-list reject-outgoing deny udp src any sport eq 135 dest any dport any
ip access-list reject-outgoing deny udp src any sport any dest any dport eq 135
ip access-list reject-outgoing deny tcp src any sport eq 135 dest any dport any
ip access-list reject-outgoing deny tcp src any sport any dest any dport eq 135
ip access-list reject-outgoing deny udp src any sport eq 445 dest any dport any
ip access-list reject-outgoing deny udp src any sport any dest any dport eq 445
ip access-list reject-outgoing deny tcp src any sport eq 445 dest any dport any
ip access-list reject-outgoing deny tcp src any sport any dest any dport eq 445
ip access-list reject-outgoing deny ip src any dest 10.0.0.0/8
ip access-list reject-outgoing deny ip src any dest 172.16.0.0/12
ip access-list reject-outgoing deny ip src any dest 192.168.0.0/16
ip access-list reject-outgoing permit ip src any dest any

ip access-list local-filter deny ip src any dest 10.0.0.0/8
ip access-list local-filter deny ip src any dest 172.16.0.0/12
ip access-list local-filter deny ip src any dest 192.168.0.0/16
ip access-list local-filter permit ip src any dest any

route-map pppoe-route permit 10
  match ip address access-list local-filter
  set default interface GigaEthernet0.1
  set interface GigaEthernet0.1

ip dhcp profile dhcpv4-sv
  dns-server 10.168.6.1
  

ipv6 dhcp client-profile dhcpv6-cl
  information-request
  option-request dns-servers

ipv6 dhcp server-profile dhcpv6-sv
  dns-server dhcp

ppp profile ppp_profile
  authentication myname hoge@fuga.com
  authentication password hoge@fuga.com password

interface GigaEthernet0.0
  no ip address
  ipv6 enable
  ipv6 address autoconfig receive-default
  ipv6 dhcp client dhcpv6-cl
  ipv6 filter dhcpv6-list 1 in
  ipv6 filter icmpv6-list 2 in
  ipv6 filter tunnel-list 3 in
  ipv6 filter block-list 100 in
  ipv6 filter dhcpv6-list 1 out
  ipv6 filter icmpv6-list 2 out
  ipv6 filter tunnel-list 3 out
  ipv6 filter dflt-list 100 out
  no shutdown

interface GigaEthernet0.1
  ppp binding ppp_profile
  ip address ipcp
  ip napt enable
  ip tcp adjust-mss auto
  no shutdown
  ip napt service http 10.168.0.80 none tcp 80
  ip napt service softether 10.168.0.30 none tcp 5555
  ip filter reject-outgoing 1 out

interface GigaEthernet1.0
  ip address 10.168.7.254/24
  no shutdown

device GigaEthernet2
  vlan-group 1 port 1 2 3 4
  vlan-group 2 port 5 6 7 8

interface GigaEthernet2:1.0
  ip address 10.168.0.254/24
  ip policy route-map pppoe-route
  no shutdown

interface GigaEthernet2:2.0
  ip address 10.168.6.1/24
  no shutdown

interface Tunnel0.0
  tunnel mode map-e
  ip address map-e
  ip tcp adjust-mss auto
  ip napt enable
  ip filter reject-outgoing 1 out
  no shutdown

ハマりやすいところとしては、GigaEthernet2:1.0からの通信をIPv4アクセスリストなしですべてroute-mapで処理してしまうと、外部公開するサーバーと内部のマシンがルーターを介して一切通信できなくなってしまいます。
そのため、アクセスリストでプライベートIPアドレスの範囲を検出して、route-map適用除外を行ってやる必要があります。

また、アクセスリストの最後に「ip access-list local-filter permit ip src any dest any」を書かないと、すべてのパケットがroute-map適用除外になってしまい、MAP-E側に流れてしまうのでこれまた失敗となってしまいます。

結果的にこのようになり、安定して稼働しております。

上記の設定に更に追加で、ポートベースVLANの上にタグVLANも乗っけて動くように構成してあります。

IX2105やIX2106など、ポート数が少ない機種で試す場合はインターフェース名などを適宜変更すれば動くかもしれません。




2021年2月7日日曜日

Kea DHCPv4 ServerをDocker上で動作させる

DHCPサーバーをローカルで立ち上げる場合、Linux上にISC DHCPやKea DHCPをインストールして運用することが多いかと思います。

今回はDHCPサーバーをコンテナ化してDocker上で動かし、ローカルネットワークにIPアドレスを配布できるようにします。

コンテナ化することで、使用するOSや環境ごとに微妙に異なる手順を統一して展開できたり、バックアップを取るのも設定ファイルだけで済んだり、あるいはマシンを変える場合も設定のみをtarで固めて、移行先のマシンで展開・起動するだけで済むなど、何かとメリットがあります。

今回使用するファイルはすべてgithubに置いてありますので、こちらを使用して進めていきます。

https://github.com/ytsurui/kea-dhcp4-docker-simple

前提条件

今回の記事は、下記のソフトウェアが事前にホスト上にインストールされていることを前提としています。

  • docker-ce
  • docker-compose
また、コマンドを実行する場合、必要に応じてsudoコマンドを併用してroot権限で行ってください。
docker、docker-composeコマンドの実行には、インストール後に権限を触ってない場合は、root権限で実行しないとエラーが出るかと思います。

動作確認は、ubuntu server 20.04 x64で取っていますが、arm版のubuntuや、CentOSなど他の環境にdockerをインストールした環境でも動くと思います。

ファイルの準備

最初に、gitコマンドで上記リポジトリの内容をすべてローカルにクローンするか、あるいは下記に示すファイルのみをテキストレベルでコピーします。

  • gitコマンドを使用する場合
git clone https://github.com/ytsurui/kea-dhcp4-docker-simple

  • ファイルをコピーする場合
    • Dockerfile
    • docker-compose.yaml
    • conf/kea-dhcp4.conf

設定の修正

ファイルの準備ができたら、conf/kea-dhcp4.confを自身の環境に適合するように、必要に応じて書き換えます。
初期状態では、下記に示す設定となっています。
  • DHCPリクエストを受け付けるネットワークインターフェイス名:
      ens192
  • IPアドレスの配布対象とするネットワーク: 192.168.4.0/24
  • プール範囲: 192.168.4.11 - 192.168.4.200
  • デフォルトゲートウェイ: 192.168.4.1
  • DNSサーバー: 192.168.4.1
  • ドメイン名: your-domain.local
それぞれ、下図で示す箇所に対応しています。


特に明言はされていませんが、設定ファイルの書式はJSON形式になっていますので、JSONの取り扱い経験がある場合はすんなりと触れると思います。

配布対象のネットワークを増やす場合は、31行目から始まるsubnet4の配列に含まれている配布対象とするネットワーク、IPアドレス配布プール、デフォルトゲートウェイの固まりを増やしていけば幾らでも追加できます。

また、ローカルドメイン名などが不要な場合は、その項目を中括弧ごと消し込むことで配布されなくなります。

ネットワークインターフェイス名の確認

ネットワークインターフェイス名は、DHCPコンテナを動作させるホストマシンのネットワークインターフェイス名を指定します。

最近のLinux環境では、ip addr showで入れるとマシン上で使用可能なネットワークインターフェイス一覧が出てきます。


環境によって、上図のようにens192と出てきたり、eth0と出てきたりしますので、必要に応じて書き換えます。

コンテナの起動

設定の変更が完了したら、DHCPコンテナを起動します。
今回は、docker-composeを利用してお手軽にコンテナを起動していきます。

下記の順番でコマンドを実行し、DHCPコンテナイメージのビルド、DHCPコンテナの起動を行います。

docker-compose build
docker-compose up -d

正しく起動できているかは、「ss -anu」を実行し、DHCPポート(UDP 67)が待ち受けを開始しているか見ることで確認が取れます。


赤枠で囲んだ箇所のように、UDP 67番ポートが待ち受けを開始していれば起動には成功しています。

コンテナ内部で動いているkea-dhcpの動作ログを見たい場合は、「docker-compose logs」で確認できます。
エラーで起動しない場合は、何か変なメッセージが出ているかと思います。

ファイアウォールの開放

dockerホスト上にファイアウォールがインストールされている場合、UDP 67番への着信を許可する必要があります。
firewalldで構成されている場合は、下記のコマンドを実行し、ポート開放を行います。

firewall-cmd --add-port 67/udp --permanent && firewall-cmd --reload