kubernetesでクライアントのグローバルIPを取得する

kubernetesのデフォルト挙動では、podが取得するリモートIPがクラスターネットワークの内部IPになっています。
そのため、httpサーバーのログにも、10.0.0.1などのプライベートIPアクセスが記録されます。

k8s v1.5からGoogle Container Engine(GKE)向けに、クライアントのグローバルIPを取得できるオプションが追加されました。
( Loss of client source IP for external traffic)

GKE環境であれば、Serviceに設定を追加して再起動することで、アクセス元のIPを取得できます。
なお、ReplicationControllerの設定ではないことには注意が必要です。

※ v1.6あたりで、 リクエスト消失のネットワーク障害が起きることがあります。利用バージョンには注意が必要です。

Serviceの設定例は以下のとおりです。metadataセクションに、annotationsにservice.beta.kubernetes.io/external-traffic: OnlyLocalという設定を追加します。

v1.7でこのアノテーションは廃止され、フィールド指定に変更されています。

apiVersion: v1
kind: Service
metadata:
  labels:
    name: web
  name: web
  annotations:
    service.beta.kubernetes.io/external-traffic: OnlyLocal
spec:
  ports:
    - name: http
      port: 80
      targetPort: web-http
      protocol: TCP
  selector: 
    name: web
  type: LoadBalancer
  loadBalancerIP: 192.168.0.1

ネットワークアクセスの継続性に注意が必要

Serviceの再起動は、Replication Controllerと同様、

$ kubectl delete -f service_config.yml
$ kubectl create -f service_config.yml

で実行できます。

この処理は、Webサービスの玄関にあたる設定を変えるため、注意が必要です。

まず、ロードバランサーの再作成が走るため、しばらくネットワークアクセスが中断します。

また、再起動前にIPを固定する設定を追加しておかないと、再起動にあたり外部IPを新たに取得する挙動になる可能性があります。IPが変わると、DNS設定も変更しないと現行のホスト名でアクセスできなくなります。
外部IPの固定については、 Google Container Engine の外部IPを指定するで解説しています。

中馬崇尋
Chuma Takahiro