nginx in KubernetesにおいてK8sドメイン指定しているにも関わらずIPがキャッシュされる問題
1. 問題点
Kubernetes(K8s)環境で Nginx をリバースプロキシとして使用する際、例えば以下のような proxy_pass
設定を使うと、K8s 内のサービスへのリクエストを転送することができます:
proxy_pass http://<service>.<namespace>.svc.cluster.local;
しかし、Kubernetes の内部ドメイン名を直接 proxy_pass
に指定すると、Pod の再起動やスケール操作などによって IP アドレスが変更されたときに、その情報が Nginx にすぐに反映されず、古い IP アドレスにリクエストを送り続けてしまうことがあります。
2. 解決策
これを回避するために、以下の対策を取りましょう:
-
set
ディレクティブを使って変数化する:set
を使用し、サービス名を変数として定義します。これにより、Nginx は毎回変数を評価する際に DNS 解決を行い、最新の IP アドレスに転送するようになります。 -
resolver
の設定:resolver
を使用して、定期的にサービスの名前解決を行い、IP アドレスの更新を反映させるようにします。
これにより、サービスの再起動やスケールイン・スケールアウトによって Pod の IP が変更されても、Nginx はその変化をキャッチし、最新の状態を保持できます。
3. 具体例
以下は、その設定例です:
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
namespace: service
data:
nginx.conf: |
events {
}
http {
resolver kube-dns.kube-system.svc.cluster.local valid=5s;
server {
listen 443;
location / {
set $service_name_var <SERVICE_NAME>.namespace.svc.cluster.local;
rewrite ^/(.*) /$1 break;
proxy_pass http://$service_name_var;
}
}
}
rewrite
と proxy_pass
の組み合わせの解説
4.
rewrite
の基本
4.1. Nginx の rewrite
ディレクティブは、指定された正規表現に基づいてリクエスト URI を再構築(書き換え)するために使用されます。
- 例:
rewrite ^/(.*) /$1 break;
-
^/(.*)
:-
^
:リクエスト URI の先頭を示す。 -
/(.*)
:任意の文字列をキャプチャしてグループ化(.*
は任意の文字が 0 回以上繰り返されることを意味し、括弧で囲むことでその部分をキャプチャとして扱う)。
-
-
/$1
:- キャプチャした文字列を
$1
として参照し、最終的なリクエスト URI を/example/path
のように構成する。
- キャプチャした文字列を
-
break
の役割
4.2. rewrite
の最後に指定されている break
は、rewrite
のあとでさらに別の location
ブロックやリダイレクトを試みることなく、現在の location
ブロック内で処理を続行することを指示します。
-
break
がない場合:-
rewrite
のあと、Nginx が別のlocation
ディレクティブにマッチする可能性があるため、意図しない挙動になることがあります。
-
-
break
を使う場合:- 書き換えた URI を使用して、そのまま次のディレクティブ(ここでは
proxy_pass
)に渡すように処理を固定できます。
- 書き換えた URI を使用して、そのまま次のディレクティブ(ここでは
proxy_pass
の構成とオプション
4.3. proxy_pass
は、Nginx をリバースプロキシとして設定し、別のサーバ(サービス)にリクエストを転送するディレクティブです。
-
基本構成:
proxy_pass http://backend;
- ここで、
backend
は転送先のホスト(または変数)を指定しています。
-
rewrite
とproxy_pass
の相性:-
rewrite
によって書き換えた URI をそのままproxy_pass
に渡す場合、rewrite
のパターンが正しくマッチしないと意図しない URI が転送されることがあります。 - この問題を防ぐため、
proxy_pass http://backend/$1;
のように$1
を直接指定する方法もありますが、rewrite
+break
の組み合わせの方が、複雑な URI の変形やパスの管理が容易です。
-
proxy_pass
のパス指定方法の違い
4.4. proxy_pass
のパス指定には以下の二通りの方法があります:
-
proxy_pass http://backend;
- 転送先の URI は、書き換え後の URI をそのまま使用します。
- 例: 元のリクエストが
/foo/bar
なら、http://backend/foo/bar
に転送されます。
-
proxy_pass http://backend/some_path/;
- この形式では、
proxy_pass
に指定したパスがベースパスとして使用され、転送先のパスを構築します。 - 例: 元のリクエストが
/foo/bar
なら、転送先はhttp://backend/some_path/foo/bar
になります。
- この形式では、
5. 最適な設定の選択
Kubernetes 環境で安定した Nginx のリバースプロキシ設定をするには、以下の設定を推奨します:
-
set
を使って変数を定義:- 毎回 DNS を解決するようになるため、サービス名や内部ドメインが変更された場合でも柔軟に対応できます。
-
rewrite
とbreak
を組み合わせて URI を固定:- 書き換えた URI が内部で予期しない変更を起こさないようにするためです。
-
proxy_pass
はシンプルに記述:- できるだけベースパスを指定せず、変数を使ったリクエスト転送により、URI の扱いを明示的にする。
6. まとめ
上記の設定を用いることで、Kubernetes 環境における Nginx リバースプロキシの DNS 解決とリクエスト URI の管理を安定化できます。特に rewrite
の扱い方や proxy_pass
のオプションについて理解し、最適な設定を選択することが重要です。