UPIインストールの場合のAPI通信
OpenShift(4.18時点)をUPI方式でインストールする場合、インストーラはLB/DNS/Compute等を自動構築しないため、API サーバ等に入ってくるトラフィックを負荷分散するLoadBlancerについても、OCP側では準備をしてくれず自前で準備する必要があります。
※IPI/UPI方式の違いについては以下参照
基本的な必要要素としては以下
・API Load Balancer(必須)
コンポーネント: kube-apiserver
用途: oc/kubectlコマンドやoperatorなど
port: TCP 6443
endpoint: control plane ノードに分散
例)
api.<cluster_name>.<base_domain>:6443
→ master-0:6443
→ master-1:6443
→ master-2:6443
・Ingress Load Balancer(必須)
コンポーネント: OpenShift Router(HAProxy router / ingress controller)
用途: console/oauth
port: TCP 80 / 443
endpoint: 全workerノード(routerPodが動くノード)
例)
*.apps.<cluster_name>.<base_domain>
→ worker-0:80/443
→ worker-1:80/443
・Machine Config Server(クラスタ作成時に必須)
コンポーネント: machine-config-server (namespace=openshift-machine-config-operator)
用途: ノード(RHCOS)が Ignition / MachineConfig を取得するためのサーバで、OS設定やkubelet設定、証明書、systemd unit などを配布
port: TCP 22623
endpoint: control plane ノードに分散
例)
Node (RHCOS)
→ https://api-int.<cluster>.<domain>:22623
主にノード側(RHCOS)が参照するOCP内部の通信。通常クライアントからは使われない
クラスタ作成時
bootstrap / master / worker の初回起動
RHCOS が起動し、IgnitionがAPI MCS(22623) にアクセスして初期設定を取得するため、22623 が通らないとインストールは失敗する
クラスタ作成直後〜運用中
以下のケースで 再び 22623 が使われる。
→Worker の追加
→Control-plane の追加
→OS / kubelet / CRI-O 更新(MachineConfig 更新)
→ノード再プロビジョニング
・DNS
OpenShiftは名前でアクセスするため、以下の名前解決が必要
api.<cluster>.<base_domain> → API LB
api-int.<cluster>.<base_domain> → API LB(内部通信用)
*.apps.<cluster>.<base_domain> → Ingress LB
IPI/Assisted Installerの場合
クラスタ内にhaproxyのpodがあり、そちらに含まれています。
Node上で動作させるデーモンのような働きであるため、podには hostnetwork: true によりNodeのアドレスが付与されています。
$ oc get pod -n openshift-kni-infra -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-worker01.internal 2/2 Running 24 178d 10.10.10.8 worker01.internal <none> <none>
coredns-worker02.internal 2/2 Running 22 178d 10.10.10.9 worker02.internal <none> <none>
coredns-master01.internal 2/2 Running 18 178d 10.10.10.5 master01.internal <none> <none>
coredns-master02.internal 2/2 Running 18 178d 10.10.10.6 master02.internal <none> <none>
coredns-master03.internal 2/2 Running 18 178d 10.10.10.7 master03.internal <none> <none>
haproxy-master01.internal 2/2 Running 18 178d 10.10.10.5 master01.internal <none> <none>
haproxy-master02.internal 2/2 Running 18 178d 10.10.10.6 master02.internal <none> <none>
haproxy-master03.internal 2/2 Running 19 178d 10.10.10.7 master03.internal <none> <none>
keepalived-worker01.internal 2/2 Running 215 178d 10.10.10.8 worker01.internal <none> <none>
keepalived-worker02.internal 2/2 Running 208 178d 10.10.10.9 worker02.internal <none> <none>
keepalived-master01.internal 2/2 Running 231 (54d ago) 178d 10.10.10.5 master01.internal <none> <none>
keepalived-master02.internal 2/2 Running 228 (54d ago) 178d 10.10.10.6 master02.internal <none> <none>
keepalived-master03.internal 2/2 Running 222 (54d ago) 178d 10.10.10.7 master03.internal <none> <none>
Openshiftとして、クラスタ全体の名前解決で使われるcoredns(namespace:openshift-dns)とは別で、
namespace:openshift-kni-infraでもcorednsのpodが全ノードに配布されていますが、こちらはノード自身(hostNetwork)、IPI BareMetal の内部経路で使用されているものです。
BareMetal IPI(KNI系)では openshift-kni-infra に haproxy/keepalived/coredns 相当が配置される一方で、UPIでは外部LB/DNSを自前で用意するため、これらのPodに依存しません。
外部LBとしてはいくつか方法がありますが、今回はHaproxyをAlmaLinuxのVM上にインストールし、API/Ingress用のvIPをもたせてMasterNodeに振り分けてみます。
また、Haproxyは2VMで冗長化しておきます。
外部のDNS登録
クライアントから参照するDNSで対象のクラスタの名前解決(haproxyのVIPアドレス)ができるようにしておく。
なお、IPIの場合は一般的にAPI用/ingress用で通常は分けるが、今回は外部HAProxyがポートで振り分けるため、VIPを共用しても成立する。
api.<cluster>.<base_domain> → API LB
api-int.<cluster>.<base_domain> → API LB(内部通信用)
*.apps.<cluster>.<base_domain> → Ingress LB
Haproxy/keepalived インストール
インストール
# dnf install -y haproxy keepalived
バージョン確認
# haproxy -v
HAProxy version 2.4.22-f8e3218 2023/02/14 - https://haproxy.org/
Status: long-term supported branch - will stop receiving fixes around Q2 2026.
Known bugs: http://www.haproxy.org/bugs/bugs-2.4.22.html
Running on: Linux 5.14.0-570.12.1.el9_6.x86_64 #1 SMP PREEMPT_DYNAMIC Tue May 13 06:11:55 EDT 2025 x86_64
# keepalived --version
Keepalived v2.2.8 (04/04,2023), git commit v2.2.7-154-g292b299e+
Copyright(C) 2001-2023 Alexandre Cassen, <acassen@gmail.com>
Built with kernel headers for Linux 5.14.0
Running on Linux 5.14.0-570.12.1.el9_6.x86_64 #1 SMP PREEMPT_DYNAMIC Tue May 13 06:11:55 EDT 2025
Distro: AlmaLinux 9.6 (Sage Margay)
Haproxy設定
振り分けの設定
127.0.0.1:8080はkeepalived用のヘルスチェック用,localhostからのみ待ち受ける
OCP向けの 6443/22623/80/443 はすべて mode tcp(TLS終端しない)
statsだけHTTP
global
log 127.0.0.1 local2 # syslog 経由でログファイルに出力
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
stats socket /var/lib/haproxy/stats
ssl-default-bind-ciphers PROFILE=SYSTEM
ssl-default-server-ciphers PROFILE=SYSTEM
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
listen api-server-6443
bind *:6443
mode tcp
server master01.internal 10.10.10.5:6443 check inter 60s
server master02.internal 10.10.10.6:6443 check inter 60s
server master03.internal 10.10.10.7:6443 check inter 60s
listen machine-config-server-22623
bind *:22623
mode tcp
server master01.internal 10.10.10.5:22623 check inter 60s
server master02.internal 10.10.10.6:22623 check inter 60s
server master03.internal 10.10.10.7:22623 check inter 60s
listen ingress-router-443
bind *:443
mode tcp
balance source
server worker01.internal 10.10.10.8:443 check inter 60s
server worker02.internal 10.10.10.9:443 check inter 60s
listen ingress-router-80
bind *:80
mode tcp
balance source
server worker01.internal 10.10.10.8:80 check inter 60s
server worker02.internal 10.10.10.9:80 check inter 60s
listen stats
bind 127.0.0.1:8080
mode http
stats enable
stats uri /status
stats refresh 10s
ログローテートの設定
1日毎で10日分保存。
/var/log/haproxy.log {
daily
rotate 10
missingok
notifempty
compress
sharedscripts
postrotate # ローテートした後、syslog/rsyslog に HUP シグナルを送る
/bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
/bin/kill -HUP `cat /var/run/rsyslogd.pid 2> /dev/null` 2> /dev/null || true
endscript
}
keepalivedの設定
keepalived で VRRP を使って “VIP(仮想IP) を2台以上のLBノード間で冗長化する” 設定
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL
vrrp_skip_check_adv_addr
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_script check_haproxy {
script "/opt/tool/keepalived/chk_haproxy.sh" # 0を返せば正常、0以外なら異常 と判定される
interval 5 # 5秒ごとにチェック
rise 1 # 1回成功したら “正常” とみなす
fall 1 # 1回失敗したら “異常” とみなす
}
vrrp_instance VI_1 {
state BACKUP
interface eth0 # VIP を付与する NIC を指定
nopreempt # 一度 BACKUP 側に切り替わった後、元の高優先度機が復帰しても MASTER を奪い返さない設定
virtual_router_id 51 # VRRPグループID。冗長化ペアの keepalived は 同じ値にする
priority 101 # priority の高い方が MASTER になる。2号機はpriorityを50にする
advert_int 1
vrrp_garp_interval 0
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress { # VIPアドレス
10.10.10.10
}
track_script { # vrrp_script↓ の結果が VRRP の状態に影響する
check_haproxy
}
}
vrrp_script check_haproxyで指定しているスクリプトを作成する。
HAProxy が“応答できる状態か”を HTTP レベルで確認する
#!/bin/bash
if ! timeout 2s curl -sf http://127.0.0.1:8080/status > /dev/null; then
exit 1
else
exit 0
fi
実行権付与
# chmod +x /opt/tool/keepalived/chk_haproxy.sh
確認
設定反映
# systemctl restart haproxy
# systemctl restart keepalived
確認
# systemctl status haproxy
● haproxy.service - HAProxy Load Balancer
Loaded: loaded (/usr/lib/systemd/system/haproxy.service; enabled; preset: disabled)
Active: active (running) since Tue 2025-08-26 07:53:59 UTC; 3 months 13 days ago
Main PID: 1268 (haproxy)
Tasks: 5 (limit: 101849)
Memory: 13.6M
CPU: 10h 55min 21.142s
CGroup: /system.slice/haproxy.service
tq1268 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -f /etc/haproxy/conf.d -p /run/haproxy.pid
mq1270 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -f /etc/haproxy/conf.d -p /run/haproxy.pid
# systemctl status keepalived
● keepalived.service - LVS and VRRP High Availability Monitor
Loaded: loaded (/usr/lib/systemd/system/keepalived.service; enabled; preset: disabled)
Active: active (running) since Tue 2025-08-26 07:54:10 UTC; 3 months 13 days ago
Main PID: 1278 (keepalived)
Tasks: 2 (limit: 101849)
Memory: 5.1M
CPU: 3h 55min 37.056s
CGroup: /system.slice/keepalived.service
tq1278 /usr/sbin/keepalived --dont-fork -D
mq1280 /usr/sbin/keepalived --dont-fork -D
# curl http://127.0.0.1:8080/status
→エラーがなく返ってくること.以下の情報がわかる
・HAProxy プロセスが生きているか
・各 listen / backend の状態
・各サーバ(master / worker)の UP / DOWN
・セッション数、エラー数
1号機がVIPを持っている
# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 08:60:1c:51:d5:9e brd ff:ff:ff:ff:ff:ff
altname enp3s0
inet 10.10.10.3/24 brd 10.10.10.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet 10.10.10.10/32 scope global eth0
valid_lft forever preferred_lft forever
参考
UPIの負荷分散要件
haproxyの設定
