K3s に イングレスコントローラーとして Ingress Nginx をインストールし、接続元のIPアドレスをリクエストヘッダーとして取得できるようにする

kubernetes
2025-03-09 15:43 (2日前) ytyng
View in English

K3s をシングルノードとして起動してイングレスコントローラーとして Ingress Nginx を使い、接続元のIPアドレスをリクエストヘッダー (x-real-ip, x-forwarded-for) として取得する設定です。

ラズベリーパイや類するシングルボードコンピューターに K8s 環境を構築するのに良い方法となります。

課題としては

の2つがあり、今回のプラクティスで両方を解決します。

課題

K3s は、デフォルトだとイングレスコントローラーとして Traefik をインストールします。

設定項目が Nginx と違うため、Nginx と同じ感覚で使っていると思い通りに動作しない可能性があります。

Ingress Nginx をインストールし、K3s のロードバランサー (デフォルトでは Service LB) から接続を受けるようにすると、Nginx で接続元の IP アドレスをリクエストヘッダーとして扱うことができません。 つまり、アプリ側で接続元IPアドレスをロギングしたり、アクセス制御に使うことができません。

関連課題:

Getting Real Client IP with k3s · k3s-io/k3s · Discussion #2997

方針

今回は、Ingress Nginx を Deployment + Service ではなく、DaemonSet として起動して、ポートを HostPort の 80, 443 としてバインドすることで、ホストマシンへのパケットを直接 Ingress Nginx へ渡すようにします。 これは MicroK8s のデフォルトの Ingress Nginx と同じアプローチであり、適用後の Ingress の使用感は MicroK8s のようになります。

この場合、Ingress Nginx 自体を冗長化できないとか、権限的な課題はあります。 また、マルチノード運用には向きません。

結果として、MicroK8s をよりコンパクトにしたようなシングルノードクラスタが完成します。

マシンの状態の確認

$ cat /proc/cgroups
$ cat /proc/cgroups
#subsys_name    hierarchy   num_cgroups enabled
cpuset  0   88  1
cpu 0   88  1
cpuacct 0   88  1
blkio   0   88  1
memory  0   88  1
devices 0   88  1
freezer 0   88  1
net_cls 0   88  1
perf_event  0   88  1
net_prio    0   88  1
hugetlb 0   88  1
pids    0   88  1
rdma    0   88  1

memoryenabled1 になっていない場合は対応が必要です。 Raspberry Pi を Raspbian で起動した場合は、デフォルトでは 0 になっているはずです。

その場合、下記の対応をします。

$ vim /boot/firmware/cmdline.txt

末尾に cgroup_memory=1 cgroup_enable=memory を追記

マシンをリブートする

k3s のインストール

参考: クイックスタートガイド | K3s

$ curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable=traefik --disable=servicelb" sh -s - --write-kubeconfig-mode 644

traefikservicelb を無効化して、K3s をインストールします。

起動状態の確認

$ k3s kubectl get all --all-namespaces
NAMESPACE     NAME                                          READY   STATUS    RESTARTS   AGE
kube-system   pod/coredns-ccb96694c-txhmg                   1/1     Running   0          42s
kube-system   pod/local-path-provisioner-5b5f758bcf-v5rln   1/1     Running   0          42s
kube-system   pod/metrics-server-7bf7d58749-nqqpn           1/1     Running   0          42s

NAMESPACE     NAME                     TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                  AGE
default       service/kubernetes       ClusterIP   10.43.0.1     <none>        443/TCP                  60s
kube-system   service/kube-dns         ClusterIP   10.43.0.10    <none>        53/UDP,53/TCP,9153/TCP   55s
kube-system   service/metrics-server   ClusterIP   10.43.58.13   <none>        443/TCP                  55s

NAMESPACE     NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/coredns                  1/1     1            1           56s
kube-system   deployment.apps/local-path-provisioner   1/1     1            1           55s
kube-system   deployment.apps/metrics-server           1/1     1            1           55s

NAMESPACE     NAME                                                DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/coredns-ccb96694c                   1         1         1       42s
kube-system   replicaset.apps/local-path-provisioner-5b5f758bcf   1         1         1       42s
kube-system   replicaset.apps/metrics-server-7bf7d58749           1         1         1       42s

1分ほどで、3つのPod が起動します。

Ingress Nginx のインストール

Ingress Nginx の最新バージョンを確認する

https://github.com/kubernetes/ingress-nginx/releases このページを見て、Ingress Nginx の最新バージョンのバージョン番号を確認します。

インストールする

さきほどのバージョン番号のマニフェストを使ってインストールします。

$ k3s kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/baremetal/deploy.yaml

起動状態の確認

$ k3s kubectl get all --all-namespaces
NAMESPACE       NAME                                            READY   STATUS      RESTARTS   AGE
ingress-nginx   pod/ingress-nginx-admission-create-wc54d        0/1     Completed   0          2m43s
ingress-nginx   pod/ingress-nginx-admission-patch-lgd2t         0/1     Completed   1          2m43s
ingress-nginx   pod/ingress-nginx-controller-6887c6d764-4whjs   1/1     Running     0          2m43s
kube-system     pod/coredns-ccb96694c-txhmg                     1/1     Running     0          6m5s
kube-system     pod/local-path-provisioner-5b5f758bcf-v5rln     1/1     Running     0          6m5s
kube-system     pod/metrics-server-7bf7d58749-nqqpn             1/1     Running     0          6m5s

NAMESPACE       NAME                                         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
default         service/kubernetes                           ClusterIP   10.43.0.1      <none>        443/TCP                      6m24s
ingress-nginx   service/ingress-nginx-controller             NodePort    10.43.13.194   <none>        80:31119/TCP,443:32508/TCP   2m45s
ingress-nginx   service/ingress-nginx-controller-admission   ClusterIP   10.43.17.117   <none>        443/TCP                      2m45s
kube-system     service/kube-dns                             ClusterIP   10.43.0.10     <none>        53/UDP,53/TCP,9153/TCP       6m19s
kube-system     service/metrics-server                       ClusterIP   10.43.58.13    <none>        443/TCP                      6m19s

NAMESPACE       NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
ingress-nginx   deployment.apps/ingress-nginx-controller   1/1     1            1           2m44s
kube-system     deployment.apps/coredns                    1/1     1            1           6m20s
kube-system     deployment.apps/local-path-provisioner     1/1     1            1           6m19s
kube-system     deployment.apps/metrics-server             1/1     1            1           6m19s

NAMESPACE       NAME                                                  DESIRED   CURRENT   READY   AGE
ingress-nginx   replicaset.apps/ingress-nginx-controller-6887c6d764   1         1         1       2m44s
kube-system     replicaset.apps/coredns-ccb96694c                     1         1         1       6m6s
kube-system     replicaset.apps/local-path-provisioner-5b5f758bcf     1         1         1       6m6s
kube-system     replicaset.apps/metrics-server-7bf7d58749             1         1         1       6m6s

NAMESPACE       NAME                                       STATUS     COMPLETIONS   DURATION   AGE
ingress-nginx   job.batch/ingress-nginx-admission-create   Complete   1/1           16s        2m44s
ingress-nginx   job.batch/ingress-nginx-admission-patch    Complete   1/1           18s        2m44s

ingress-nginx の、 Service と Deployment が作られます。

下記コマンドを実行して、 404 レスポンスが取得できることを確認しておきます。

$ curl https://127.0.0.1:32508 --insecure

※ 32508 となっている箇所は、service が 443 を NodePort として公開しているポートを指定します。ランダムで変わります。

$ curl https://127.0.0.1:32508 --insecure
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>

Ingress Nginx の Deployment と Service の削除

さきほど、Deployment と Service を作り動作検証しましたが、今回は使わないので削除します。

$ k3s kubectl delete service -n ingress-nginx ingress-nginx-controller
$ k3s kubectl delete deployment -n ingress-nginx ingress-nginx-controller

DaemonSet の作成

先ほどインストールしたマニフェスト の deployment を元に、daemonset のマニフェストを作ってファイルとして保存します。

修正内容

修正後のマニフェスト

v1.12.0 の場合、下記のようになりました。

ingress-nginx-daemonset.yaml

apiVersion: apps/v1
kind: DaemonSet  # 修正
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.12.0
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  minReadySeconds: 0
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app.kubernetes.io/component: controller
      app.kubernetes.io/instance: ingress-nginx
      app.kubernetes.io/name: ingress-nginx
  # strategy:  # 消す
  #   rollingUpdate:
  #     maxUnavailable: 1
  #   type: RollingUpdate
  template:
    metadata:
      labels:
        app.kubernetes.io/component: controller
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.12.0
    spec:
      hostNetwork: true  # 追加
      containers:
      - args:
        - /nginx-ingress-controller
        - --election-id=ingress-nginx-leader
        - --controller-class=k8s.io/ingress-nginx
        - --ingress-class=nginx
        - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
        - --validating-webhook=:8443
        - --validating-webhook-certificate=/usr/local/certificates/cert
        - --validating-webhook-key=/usr/local/certificates/key
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: LD_PRELOAD
          value: /usr/local/lib/libmimalloc.so
        image: registry.k8s.io/ingress-nginx/controller:v1.12.0@sha256:e6b8de175acda6ca913891f0f727bca4527e797d52688cbe9fec9040d6f6b6fa
        imagePullPolicy: IfNotPresent
        lifecycle:
          preStop:
            exec:
              command:
              - /wait-shutdown
        livenessProbe:
          failureThreshold: 5
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        name: controller
        ports:
        - containerPort: 80
          hostPort: 80  # 追加
          name: http
          protocol: TCP
        - containerPort: 443
          hostPort: 443  # 追加
          name: https
          protocol: TCP
        - containerPort: 8443
          hostPort: 8443  # 追加
          name: webhook
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        resources:
          requests:
            cpu: 100m
            memory: 90Mi
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            add:
            - NET_BIND_SERVICE
            drop:
            - ALL
          readOnlyRootFilesystem: false
          runAsGroup: 82
          runAsNonRoot: true
          runAsUser: 101
          seccompProfile:
            type: RuntimeDefault
        volumeMounts:
        - mountPath: /usr/local/certificates/
          name: webhook-cert
          readOnly: true
      dnsPolicy: ClusterFirst
      nodeSelector:
        kubernetes.io/os: linux
      serviceAccountName: ingress-nginx
      terminationGracePeriodSeconds: 300
      volumes:
      - name: webhook-cert
        secret:
          secretName: ingress-nginx-admission

適用

$ sudo k3s kubectl apply -f ingress-nginx-daemonset.yaml

確認

$ k3s kubectl get all --all-namespaces
NAMESPACE       NAME                                          READY   STATUS      RESTARTS   AGE
ingress-nginx   pod/ingress-nginx-admission-create-wc54d      0/1     Completed   0          10m
ingress-nginx   pod/ingress-nginx-admission-patch-lgd2t       0/1     Completed   1          10m
ingress-nginx   pod/ingress-nginx-controller-lbptk            1/1     Running     0          31s
kube-system     pod/coredns-ccb96694c-txhmg                   1/1     Running     0          13m
kube-system     pod/local-path-provisioner-5b5f758bcf-v5rln   1/1     Running     0          13m
kube-system     pod/metrics-server-7bf7d58749-nqqpn           1/1     Running     0          13m

NAMESPACE       NAME                                         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)                  AGE
default         service/kubernetes                           ClusterIP   10.43.0.1      <none>        443/TCP                  14m
ingress-nginx   service/ingress-nginx-controller-admission   ClusterIP   10.43.17.117   <none>        443/TCP                  10m
kube-system     service/kube-dns                             ClusterIP   10.43.0.10     <none>        53/UDP,53/TCP,9153/TCP   13m
kube-system     service/metrics-server                       ClusterIP   10.43.58.13    <none>        443/TCP                  13m

NAMESPACE       NAME                                      DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
ingress-nginx   daemonset.apps/ingress-nginx-controller   1         1         1       1            1           kubernetes.io/os=linux   31s

NAMESPACE     NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/coredns                  1/1     1            1           13m
kube-system   deployment.apps/local-path-provisioner   1/1     1            1           13m
kube-system   deployment.apps/metrics-server           1/1     1            1           13m

NAMESPACE     NAME                                                DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/coredns-ccb96694c                   1         1         1       13m
kube-system   replicaset.apps/local-path-provisioner-5b5f758bcf   1         1         1       13m
kube-system   replicaset.apps/metrics-server-7bf7d58749           1         1         1       13m

NAMESPACE       NAME                                       STATUS     COMPLETIONS   DURATION   AGE
ingress-nginx   job.batch/ingress-nginx-admission-create   Complete   1/1           16s        10m
ingress-nginx   job.batch/ingress-nginx-admission-patch    Complete   1/1           18s        10m
$ curl 'https://127.0.0.1' --insecure
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>

:443 をリッスンするようになりました。

これで、本題は終了です。

試しに、簡単なエコーサーバーを起動し、HTTPリクエストを発行してみると、x-real-ipx-forwarded-for が期待通りにリモートクライアントのIPアドレスになっているのが確認できます。

画像

補足

kubeconfig の取得方法

$ cat /etc/rancher/k3s/k3s.yaml

リモートから使う場合は、server: https://127.0.0.1:6443 となっている箇所の IPアドレスを、外部から見た IPアドレスに変更してください。

K3s のアンインストール

$ /usr/local/bin/k3s-uninstall.sh

確認無しで全部消えるので注意してください。

現在未評価
タイトルとURLをコピー
著者は、アプリケーション開発会社 Cyberneura を運営しています。
開発相談をお待ちしています。

コメント

アーカイブ

2025
2024
2023
2022
2021
2020
2019
2018
2017
2016
2015
2014
2013
2012
2011