LoginSignup
71
56

More than 5 years have passed since last update.

Kubernetes クラスタの外からのアクセスに ClusterIP をロードバランサとして使う

Last updated at Posted at 2016-05-06

はじめに

Kubernetes を触り始めて困惑したのは、クラスタの外からどうやってアクセスするのか?ということでした。
GKE なら提供されているロードバランサを使えば良いですが、GKE に頼れない環境でも良い方法が欲しいものです。

ClusterIP はクラスタ内部からアクセスする際に使用するもので、外部からアクセスすることは意図されていませんが、
これをそのまま利用できればとても楽ができそうです。

ClusterIP へのアクセスは複数の Pod に対して振り分けられるので、IngressService Load Balancer が無くてもクラスタの外に対してロードバランサを提供することができます。
調べたところ Project Calicokube-proxy を利用するとクラスタの外から ClusterIP にアクセスできたので、やり方をまとめておきます。

テスト環境

テスト環境では 5つのホストを構築します。
すべて CentOS 7.2 で作成しています。

Use_ClusterIP+c.png

  • kubemaster ... kube-apiserveretcd などを動作させる Kubernetes の Master です
  • kubenode01 ... kubeletkube-proxy を動作させる Kubernetes の Node 1号機です
  • kubenode02 ... kubeletkube-proxy を動作させる Kubernetes の Node 2号機です
  • kubegw ... kube-proxy を動作させ、外部との通信を中継する ルータ兼ロードバランサ (L3 ルーティング + NAPT) です

Calico は上記すべてのホストで動作させます。
Client はクラスタの外に存在するホストです。ここから ClusterIP 宛てにリクエストを投げます。
Pod172.16.0.0/16 のアドレスレンジから割り当てます。
ClusterIP10.0.100.0/24 のアドレスレンジから割り当てます。

実環境に適用するなら既存のルータから kubegw に向けたスタティックルートを設定するか、kubegw を含める形でダイナミックルーティングを設定することになるでしょう。
ここでは Client に直接 kubegw に向けたスタティックルートを設定します。

Project Calico について

Project-Calico-logo-1000px.png

Kubernetes のドキュメント では僅かに触れられている程度ですが、
kubelet の Network Plugin として使用すると、クラスタで作成された Pod (コンテナ) 間で Pod の IP アドレスをそのまま使って通信できるようになります。
flannel で overlay network を作る代わりに使います。

各ホストに Docker コンテナとして calico/node をデプロイし、すべての calico/node はフルメッシュで BGP ピアリングします。

詳細は Calico のドキュメント を参照してください。

Kubernetes クラスタ構築

まずは Kubernetes のクラスタを構築します。大部分は yum でさくっといきます。
各ホストは hosts で名前解決できるようにしています。

192.168.100.10  kubemaster
192.168.100.1   kubenode01
192.168.100.2   kubenode02

Master 構築

バージョンは以下の通りでした

  • etcd-2.2.5-1.el7.x86_64
  • docker-1.9.1-25.el7.centos.x86_64
  • kubernetes-master-1.2.0-0.9.alpha1.gitb57e8bd.el7.x86_64
  • calico/node:v0.19.0
インストール
# yum install etcd docker kubernetes-master

## 後で使うので EPEL から jq をインストールしておく
# yum install http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-6.noarch.rpm
# yum install jq

まずは etcd を起動します。この例では etcd はクラスタを構成せず 1台で起動させています。
この etcdKubernetes だけでなく Calico の設定も保存させます。

/var/lib/etcd/etcd.conf
ETCD_NAME=default
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.100.10:2379"
etcd起動
# systemctl enable etcd
# systemctl start etcd

続いて Calico をセットアップします。Docker を使用するのでこの時点で起動させています。
storage driver は overlayfs にしていますが、何でもよいです。

/etc/sysconfig/docker
OPTIONS=
DOCKER_CERT_PATH=/etc/docker
/etc/sysconfig/docker-storage
DOCKER_STORAGE_OPTIONS='-s overlay'
calicoインストール
# systemctl enable docker
# systemctl start docker

# mkdir -p /opt/calico/bin
# wget https://github.com/projectcalico/calico-containers/releases/download/v0.19.0/calicoctl
# chmod +x calicoctl
# mv calicoctl /opt/calico/bin

## calico のパスを通しておく
# vi ~/.bash_profile
PATH=$PATH:$HOME/bin:/opt/calico/bin
# . ~/.bash_profile
# ETCD_AUTHORITY=127.0.0.1:2379 calicoctl node --ip=192.168.100.10
Pulling Docker image calico/node:v0.19.0

Running Docker container with the following command:

docker run -d --restart=always --net=host --privileged --name=calico-node -e HOSTNAME=kubemaster -e IP=192.168.100.10 -e IP6= -e CALICO_NETWORKING=true -e AS= -e NO_DEFAULT_POOLS= -e ETCD_AUTHORITY=127.0.0.1:2379 -e ETCD_SCHEME=http -v /var/log/calico:/var/log/calico -v /lib/modules:/lib/modules -v /var/run/calico:/var/run/calico calico/node:v0.19.0

Calico node is running with id: f6c2897855834f53d10626051197d22c35f46905c32e542c270ca52dc068b058
Waiting for successful startup
Calico node started successfully

完了すると calico/node のコンテナが起動します。
起動コマンドを表示してくれているので分かりますが、このコンテナは Restart Policy が always になっています。
起動後は以下のように見えてきます。

確認
# calicoctl node show
+------------+----------------+-----------+-------------------+--------------+--------------+
|  Hostname  |   Bird IPv4    | Bird IPv6 |       AS Num      | BGP Peers v4 | BGP Peers v6 |
+------------+----------------+-----------+-------------------+--------------+--------------+
| kubemaster | 192.168.100.10 |           | 64511 (inherited) |              |              |
+------------+----------------+-----------+-------------------+--------------+--------------+

デフォルトだと 192.168.0.0/16 をコンテナに割り当てるようですが
クラスC を他で使っていて見づらいので、ここでは 172.16.0.0/16 に変更しておきます。

poolアドレス変更
# calicoctl pool show --ipv4
+----------------+---------+
|   IPv4 CIDR    | Options |
+----------------+---------+
| 192.168.0.0/16 |         |
+----------------+---------+
# calicoctl pool add 172.16.0.0/16
# calicoctl pool remove 192.168.0.0/16
# calicoctl pool show --ipv4
+---------------+---------+
|   IPv4 CIDR   | Options |
+---------------+---------+
| 172.16.0.0/16 |         |
+---------------+---------+

kube-apiserver は手っ取り早く --insecure-bind-address=0.0.0.0 にして Admission Control も外します。
kube-schedulerkube-controller-manager はデフォルトで http://127.0.0.1:8080 に向いているのでそのままいきます。

/etc/kubernetes/apiserver
KUBE_API_ADDRESS="--insecure-bind-address=0.0.0.0"
KUBE_ETCD_SERVERS="--etcd-servers=http://127.0.0.1:2379"
KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=10.0.100.0/24"
KUBE_ADMISSION_CONTROL=""
KUBE_API_ARGS=""
Master起動
# systemctl enable kube-apiserver
# systemctl enable kube-controller-manager
# systemctl enable kube-scheduler
# systemctl start kube-apiserver
# systemctl start kube-controller-manager
# systemctl start kube-scheduler

私の環境では /var/run/kubernetes が作成されておらず、kube-apiserver の自己署名証明書も作られませんでした。
一度 OS を再起動してみると、今度は作成され 6443 が Listen されていました。

# systemctl reboot
# ss -nltp | grep 6443
LISTEN     0      128         :::6443                    :::*                   users:(("kube-apiserver",pid=1637,fd=13))

Node 構築

バージョンは以下の通りでした

  • docker-1.9.1-25.el7.centos.x86_64
  • kubernetes-node-1.2.0-0.9.alpha1.gitb57e8bd.el7.x86_64
  • calico/node:v0.19.0
インストール
# yum install docker kubernetes-node

Calico をインストールする部分は Master とほぼ同じで、IPアドレス指定だけ変更します。

/etc/sysconfig/docker
OPTIONS=
DOCKER_CERT_PATH=/etc/docker
/etc/sysconfig/docker-storage
DOCKER_STORAGE_OPTIONS='-s overlay'
calicoインストール
# systemctl enable docker
# systemctl start docker

# mkdir -p /opt/calico/bin
# wget https://github.com/projectcalico/calico-containers/releases/download/v0.19.0/calicoctl
# chmod +x calicoctl
# mv calicoctl /opt/calico/bin

## calico のパスを通しておく
# vi ~/.bash_profile
PATH=$PATH:$HOME/bin:/opt/calico/bin
# . ~/.bash_profile
## etcd は Master のアドレスを指定する
## Node 2号機 (kubenode02) は --ip=192.168.100.2 にする
# ETCD_AUTHORITY=192.168.100.10:2379 calicoctl node --ip=192.168.100.1
Pulling Docker image calico/node:v0.19.0

Running Docker container with the following command:

docker run -d --restart=always --net=host --privileged --name=calico-node -e HOSTNAME=kubenode01 -e IP=192.168.100.1 -e IP6= -e CALICO_NETWORKING=true -e AS= -e NO_DEFAULT_POOLS= -e ETCD_AUTHORITY=192.168.100.10:2379 -e ETCD_SCHEME=http -v /var/log/calico:/var/log/calico -v /lib/modules:/lib/modules -v /var/run/calico:/var/run/calico calico/node:v0.19.0

Calico node is running with id: bed0fa13d54064786450a90b5a1a8d1d2d98a80434367f756ad35bf245129854
Waiting for successful startup
Calico node started successfully

Node 2台が追加されたことを確認します。
この時点ではまだ Pod は存在しないので経路情報はアドバタイズされません。

確認
## kubenode01,02 から確認する場合は etcd の場所を指定する
# ETCD_AUTHORITY=192.168.100.10:2379 calicoctl node show
+------------+----------------+-----------+-------------------+--------------+--------------+
|  Hostname  |   Bird IPv4    | Bird IPv6 |       AS Num      | BGP Peers v4 | BGP Peers v6 |
+------------+----------------+-----------+-------------------+--------------+--------------+
| kubemaster | 192.168.100.10 |           | 64511 (inherited) |              |              |
| kubenode01 | 192.168.100.1  |           | 64511 (inherited) |              |              |
| kubenode02 | 192.168.100.2  |           | 64511 (inherited) |              |              |
+------------+----------------+-----------+-------------------+--------------+--------------+

# ETCD_AUTHORITY=192.168.100.10:2379 calicoctl status
calico-node container is running. Status: Up 5 minutes
Running felix version 1.4.0rc1

IPv4 BGP status
IP: 192.168.100.1    AS Number: 64511 (inherited)
+----------------+-------------------+-------+----------+-------------+
|  Peer address  |     Peer type     | State |  Since   |     Info    |
+----------------+-------------------+-------+----------+-------------+
| 192.168.100.10 | node-to-node mesh |   up  | 20:59:02 | Established |
| 192.168.100.2  | node-to-node mesh |   up  | 20:59:09 | Established |
+----------------+-------------------+-------+----------+-------------+

IPv6 BGP status
No IPv6 address configured.

それでは Calico を使用するように kubelet をセットアップします。

/etc/kubernetes/config
KUBE_LOGTOSTDERR="--logtostderr=true"
KUBE_LOG_LEVEL="--v=0"
KUBE_ALLOW_PRIV="--allow-privileged=false"
KUBE_MASTER="--master=http://192.168.100.10:8080"
/etc/kubernetes/kubelet
KUBELET_ADDRESS="--address=0.0.0.0"
KUBELET_HOSTNAME=
KUBELET_API_SERVER="--api-servers=http://192.168.100.10:8080"
KUBELET_ARGS="--network-plugin=cni --network-plugin-dir=/etc/cni/net.d"

kube-proxy は proxy mode を iptables にします。

/etc/kubernetes/proxy
KUBE_PROXY_ARGS="--proxy-mode=iptables"
network-plugin設定
# mkdir -p /etc/cni/net.d
# cat >/etc/cni/net.d/10-calico.conf <<EOF
{
    "name": "calico-k8s-network",
    "type": "calico",
    "etcd_authority": "192.168.100.10:2379",
    "log_level": "info",
    "ipam": {
        "type": "calico-ipam"
    }
}
EOF

# wget https://github.com/projectcalico/calico-cni/releases/download/v1.3.0/calico
# chmod +x calico
# mv calico /opt/calico/bin
起動
# systemctl enable kube-proxy
# systemctl enable kubelet
# systemctl start kube-proxy
# systemctl start kubelet

問題なく進んでいれば、Master で 2台の Node が登録されている様子が確認できます。

確認
# kubectl get node
NAME         LABELS                              STATUS    AGE
kubenode01   kubernetes.io/hostname=kubenode01   Ready     18m
kubenode02   kubernetes.io/hostname=kubenode02   Ready     16m

クラスタ内の通信試験

まずはクラスタ内で Pod, Service を作成して ClusterIP 宛てに通信できることを確認してみます。

適当に Nginx の Replication Controller を作ってみます。
kubectl の操作は Master で行います。

nginx-rc.yaml
apiVersion: v1
kind: ReplicationController
metadata:
  name: test01
spec:
  replicas: 2
  template:
    metadata:
      labels:
         test: test01
    spec:
      containers:
      - name: nginx-test01
        image: nginx
        ports:
        - containerPort: 80
# kubectl create -f nginx-rc.yaml
# kubectl get rc
CONTROLLER   CONTAINER(S)   IMAGE(S)   SELECTOR      REPLICAS   AGE
test01       nginx-test01   nginx      test=test01   2          5m
# kubectl get pod -o wide
NAME           READY     STATUS    RESTARTS   AGE       NODE
test01-chw8x   1/1       Running   0          5m        kubenode01
test01-qeftr   1/1       Running   0          5m        kubenode02
# kubectl get pod -o json | jq .items[].status.podIP
"172.16.0.64"
"172.16.0.0"

さて、Replication Controller を通して Pod がそれぞれの Node に作成されました。
この時点で各 Pod には /32 の IPアドレスがアサインされ、そのアドレスが BGP でアドバタイズされています。
Calico は 1号機・2号機の Pod にそれぞれ 172.16.0.64/32 172.16.0.0/32 をアサインし、1号機・2号機で使うアドレスレンジとしてそれぞれ 172.16.0.64/26 172.16.0.0/26 のブロックをアサインしたようです。
172.17.0.0/16 は消しておけばよかったですが、Docker がデフォルトで作成したものです。

Masterの経路情報
# ip r
default via 192.168.100.254 dev eno16777984
172.16.0.0/26 via 192.168.100.2 dev eno16777984  proto bird
172.16.0.64/26 via 192.168.100.1 dev eno16777984  proto bird
172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.0.1
192.168.100.0/24 dev eno16777984  proto kernel  scope link  src 192.168.100.10
Node1号機の経路情報
# ip r
default via 192.168.100.254 dev eno16777984
172.16.0.0/26 via 192.168.100.2 dev eno16777984  proto bird
172.16.0.64 dev calieca82516130  scope link
blackhole 172.16.0.64/26  proto bird
172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.0.1
192.168.100.0/24 dev eno16777984  proto kernel  scope link  src 192.168.100.1
Node2号機の経路情報
# ip r
default via 192.168.100.254 dev eno16777984
172.16.0.0 dev caliecb4366c130  scope link
blackhole 172.16.0.0/26  proto bird
172.16.0.64/26 via 192.168.100.1 dev eno16777984  proto bird
172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.0.1
192.168.100.0/24 dev eno16777984  proto kernel  scope link  src 192.168.100.2

経路があるので Pod の IP アドレスに対しては Master からでも Node からでも通信可能です。

# curl -s 172.16.0.64 | grep h1
<h1>Welcome to nginx!</h1>
# curl -s 172.16.0.0 | grep h1
<h1>Welcome to nginx!</h1>

Service も作ってみます。

nginx-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: test01
spec:
  selector:
    test: test01
  clusterIP: 10.0.100.80
  ports:
  - name: http
    port: 80
    protocol: TCP
# kubectl create -f nginx-svc.yaml
# kubectl get svc test01
NAME      CLUSTER_IP    EXTERNAL_IP   PORT(S)   SELECTOR      AGE
test01    10.0.100.80   <none>        80/TCP    test=test01   31s
# kubectl get ep test01
NAME      ENDPOINTS                      AGE
test01    172.16.0.0:80,172.16.0.64:80   41s

この ClusterIP 10.0.100.80 は、kube-proxy がいない Master からはアクセスできませんが、NodePod からはアクセス可能です。

# uname -n; curl -s 10.0.100.80 | grep h1
kubenode01
<h1>Welcome to nginx!</h1>

## nginx イメージに curl は無いので nsenter を使って Pod 内からアクセスできることを確認
## Pod はまだ Node に 1つずつしかないので単純に pgrep して pause と同じ Namespace に入る
# uname -n
kubenode01
# nsenter -t $(pgrep pause) -u -n
# ip -4 a show dev eth0
4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link-netnsid 0
    inet 172.16.0.64/32 scope global eth0
       valid_lft forever preferred_lft forever
# uname -n; curl -s 10.0.100.80 | grep h1
test01-chw8x
<h1>Welcome to nginx!</h1>

# uname -n
kubenode02
# nsenter -t $(pgrep pause) -u -n
# ip -4 a show dev eth0
4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link-netnsid 0
    inet 172.16.0.0/32 scope global eth0
       valid_lft forever preferred_lft forever
# uname -n; curl -s 10.0.100.80 | grep h1
test01-qeftr
<h1>Welcome to nginx!</h1>

ルータ兼ロードバランサ (kubegw) 構築

いよいよ、外部からアクセスさせるためのポイントになる ルータ兼ロードバランサ を構築します。

ルーティング可能にする
# echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.d/routing.conf
# systemctl restart systemd-sysctl

Dockerkube-proxy が必要なのでインストールします。バージョンは Node と同じです。
Dockercalico/node を動作させるために使用します。

インストール
# yum install docker kubernetes-node
/etc/sysconfig/docker
OPTIONS=
DOCKER_CERT_PATH=/etc/docker
/etc/sysconfig/docker-storage
DOCKER_STORAGE_OPTIONS='-s overlay'
calicoインストール
# systemctl enable docker
# systemctl start docker

# mkdir -p /opt/calico/bin
# wget https://github.com/projectcalico/calico-containers/releases/download/v0.19.0/calicoctl
# chmod +x calicoctl
# mv calicoctl /opt/calico/bin

## calico のパスを通しておく
# vi ~/.bash_profile
PATH=$PATH:$HOME/bin:/opt/calico/bin
# . ~/.bash_profile
# ETCD_AUTHORITY=192.168.100.10:2379 calicoctl node --ip=192.168.100.254
Pulling Docker image calico/node:v0.19.0

Running Docker container with the following command:

docker run -d --restart=always --net=host --privileged --name=calico-node -e HOSTNAME=kubegw -e IP=192.168.100.254 -e IP6= -e CALICO_NETWORKING=true -e AS= -e NO_DEFAULT_POOLS= -e ETCD_AUTHORITY=192.168.100.10:2379 -e ETCD_SCHEME=http -v /var/log/calico:/var/log/calico -v /lib/modules:/lib/modules -v /var/run/calico:/var/run/calico calico/node:v0.19.0

Calico node is running with id: 37955df4f7f99b59f4aec79ae7d8c5564d1ef3ee25af203853ca715c8d2c3212
Waiting for successful startup
Calico node started successfully

## 状態確認
# ETCD_AUTHORITY=192.168.100.10:2379 calicoctl status
calico-node container is running. Status: Up 18 seconds
Running felix version 1.4.0rc1

IPv4 BGP status
IP: 192.168.100.254    AS Number: 64511 (inherited)
+----------------+-------------------+-------+----------+-------------+
|  Peer address  |     Peer type     | State |  Since   |     Info    |
+----------------+-------------------+-------+----------+-------------+
| 192.168.100.10 | node-to-node mesh |   up  | 22:44:49 | Established |
| 192.168.100.1  | node-to-node mesh |   up  | 22:44:48 | Established |
| 192.168.100.2  | node-to-node mesh |   up  | 22:44:48 | Established |
+----------------+-------------------+-------+----------+-------------+

# ip r
172.16.0.0/26 via 192.168.100.2 dev eno33557248  proto bird
172.16.0.64/26 via 192.168.100.1 dev eno33557248  proto bird
172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.0.1
192.168.10.0/24 dev eno16777984  proto kernel  scope link  src 192.168.10.100
192.168.100.0/24 dev eno33557248  proto kernel  scope link  src 192.168.100.254

Calico が動作することで Pod への経路が作られます。
続いて kube-proxy を設定・起動します。

/etc/kubernetes/config
KUBE_LOGTOSTDERR="--logtostderr=true"
KUBE_LOG_LEVEL="--v=0"
KUBE_ALLOW_PRIV="--allow-privileged=false"
KUBE_MASTER="--master=http://192.168.100.10:8080"
/etc/kubernetes/proxy
KUBE_PROXY_ARGS="--proxy-mode=iptables"
起動
# systemctl enable kube-proxy
# systemctl start kube-proxy

kube-proxy が動作することで iptables のエントリが作成され、クラスタの外からも ルータ兼ロードバランサ を利用すれば ClusterIP 宛てにアクセスできるようになります。

iptables確認
# iptables -t nat -nL PREROUTING
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
felix-PREROUTING  all  --  0.0.0.0/0            0.0.0.0/0
KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL
# iptables -t nat -nL POSTROUTING
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
felix-POSTROUTING  all  --  0.0.0.0/0            0.0.0.0/0
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0
MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service traffic requiring SNAT */ mark match 0x4d415351
# iptables -t nat -nL KUBE-SERVICES
Chain KUBE-SERVICES (2 references)
target     prot opt source               destination
KUBE-SVC-BP3QRF6W53YFYJDU  tcp  --  0.0.0.0/0            10.0.100.80          /* default/test01:http cluster IP */ tcp dpt:80
KUBE-SVC-NPX46M4PTMTKRN6Y  tcp  --  0.0.0.0/0            10.0.100.1           /* default/kubernetes:https cluster IP */ tcp dpt:443
KUBE-NODEPORTS  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL
# iptables -t nat -nL KUBE-SVC-BP3QRF6W53YFYJDU
Chain KUBE-SVC-BP3QRF6W53YFYJDU (1 references)
target     prot opt source               destination
KUBE-SEP-M6FWVBZWU3TAHUXK  all  --  0.0.0.0/0            0.0.0.0/0            /* default/test01:http */ statistic mode random probability 0.50000000000
KUBE-SEP-3VEHY3E2FGHEBZJY  all  --  0.0.0.0/0            0.0.0.0/0            /* default/test01:http */
# iptables -t nat -nL KUBE-SEP-M6FWVBZWU3TAHUXK
Chain KUBE-SEP-M6FWVBZWU3TAHUXK (1 references)
target     prot opt source               destination
MARK       all  --  172.16.0.0           0.0.0.0/0            /* default/test01:http */ MARK set 0x4d415351
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            /* default/test01:http */ tcp to:172.16.0.0:80
# iptables -t nat -nL KUBE-SEP-3VEHY3E2FGHEBZJY
Chain KUBE-SEP-3VEHY3E2FGHEBZJY (1 references)
target     prot opt source               destination
MARK       all  --  172.16.0.64          0.0.0.0/0            /* default/test01:http */ MARK set 0x4d415351
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            /* default/test01:http */ tcp to:172.16.0.64:80

クラスタの外にいる Client から確認してみましょう。
このホストで ClusterIP である 10.0.100.0/24ルータ兼ロードバランサ に経路を向けておきます。
また、PodIP として使用される 172.16.0.0/16 の経路も向ければ Pod とも通信できます。(PodIP と通信するだけなら kube-proxy 無しでも可能です)

通信確認
# ip r add 10.0.100.0/24 via 192.168.10.100
# ip r add 172.16.0.0/16 via 192.168.10.100
# curl -s 10.0.100.80 | grep h1
<h1>Welcome to nginx!</h1>
# curl -s 172.16.0.64 | grep h1
<h1>Welcome to nginx!</h1>
# curl -s 172.16.0.0 | grep h1
<h1>Welcome to nginx!</h1>

無事、通信できました。実際の環境で使うなら ルータ兼ロードバランサ は冗長化する必要があるでしょう。

IPアドレスの変遷

Client から PublicIP (10.0.100.80) に通信する際に IP アドレスは以下のように変化します。

タイミング Src Address Dest Address
Client から出る時点 192.168.10.1 10.0.100.80
ルータ兼ロードバランサ 通過後 (往路) 192.168.10.1 172.16.0.64
または
172.16.0.0
Server (Pod) から戻る時点 172.16.0.64
または
172.16.0.0
192.168.10.1
ルータ兼ロードバランサ 通過後 (復路) 10.0.100.80 192.168.10.1

ClusterIP からどちらの Pod 宛てに DNAT されるかは、iptables の statistics モジュールでランダムに (各 Pod の確率は等しい) 決定されます。
パケット毎に宛先が選択されるのではなく、connection tracking によって同じ TCP コネクションの通信なら同じ Pod 宛てに転送されます。

71
56
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
71
56