電通総研 テックブログ

電通総研が運営する技術ブログ

オンプレミス環境のIngressで社内向けサービスと社外向けサービスを公開したい

こんにちは。X(クロス)イノベーション本部 ソフトウェアデザインセンター の山下です。
皆さんkubernetes(以降k8s)は使っていますか?
今回はGKEなどのマネージドなk8sではなく、オンプレミス環境でのk8s向けのノウハウを紹介する記事になります。

オンプレミス環境のIngressで社内向けサービスと社外向けサービスを公開したい

k8sで様々なサービスを提供していると、特定のサービスの公開先を制限したい場合があります。
認証などで制限を行うことも可能ですが、IPアドレスなどで制限したい場合もあります。具体的には、社外向けサービスと社内向けサービスでアクセスする先のIPアドレスが違うように設定することで、ファイアウォールなどの設定を行えるような状況が望ましいです。

マネージドサービスであれば、EKSだと標準のIngress(Application LoadBalancer)を使って簡単に実現できる話だと思います。今回は同じようなことをIngress-Nginx Controllerを使って実現する方法について紹介します。

オンプレミス環境におけるIngress Controller

k8sには公式の機能としてIngress Controllerは提供されていません。例えば、kubeadm というk8sの公式なインストーラがあります。 このkubeadmで構築されたk8sにはIngress Controllerはインストールされていません。Ingress Controlerが存在しない状態だとユーザーはIngressのリソースを作っても上手く動きません。IngressリソースをデプロイしてもControllerがないためPendingのまま起動しないといった結果になります。

マネージドなk8sの環境だとインフラとして、LoadBalancerが提供されておりそれらをk8sに統合するようなIngress Controllerの提供がされていることが多いです。例えば、AWSではApplication LoadBalancerを利用するIngress ControlerのAWS Load Balancer Controllerが提供されており、ユーザーは自前でそれをインストールして使うといった具合です。

オンプレミス環境で利用可能なIngress Controllerも存在しています。ソフトウェアのLoadBalancerとk8sを統合するような仕組みになっているものが多いようです。例えば、以下のようなものが比較的利用されていることが多い印象です。

他にも様々なIngress Controllerがあります。
Learnk8sという企業の方が、Ingress Controllerを比較した資料(Google Spread Sheets)があります。
もし、これからIngress Controllerを選択するという場合には参考になるかもしれません。
https://docs.google.com/spreadsheets/d/191WWNpjJ2za6-nbG4ZoUMXMpUK8KlCIosvQB0f-oq3k/

今回は、このなかの Ingress-Nginx Controllerについてのノウハウを公開するものになります。

また、Ingress-Nginx Controllerは Type: Loadbalancer を指定した Service を作ることができる
k8sでなければ上手く動作しません。今回は、MetalLBを採用している環境を想定しています。

Ingress-Nginx Controllerのインストール

Ingress-Nginx Controller は helm を使ってインストールすることが出来ます。

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx --create-namespace -n ingress-system

上記の手順で、ingress-systemというnamespaceにingress-nginxがインストールされます。
インストール後、kubectl get pod -n ingress-system などを実行すると
動作が確認できるかと思います。また、ingressclass というリソースも作成されます。

上記の手順では、nginx という名前のingressclassが作られるかと思います。

Ingress-Nginx でIngressを複数作った場合の動作

さて、これで Ingress を利用できる k8s 環境になりました。
例えば以下のような形で Ingress を作ることができる様になりました。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: public-service-ingress
  namespace: public-service
spec:
  ingressClassName: nginx
  rules:
    - host: public.example.com
      http:
        paths:
        - backend:
            service:
              name: nginx
              port:
                number: 80
          path: /
          pathType: Prefix

これで、外部公開しても良いサービスをIngressで公開できました。

次に、内部に限定公開するサービスを同様にIngressで作ろうとします。
例えば、以下のようなリソースになるでしょうか。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: private-service-ingress
  namespace: private-service
spec:
  ingressClassName: nginx
  rules:
    - host: private.example.com
      http:
        paths:
        - backend:
            service:
              name: nginx
              port:
                number: 80
          path: /
          pathType: Prefix

うまく動くように思いますが、実際に適用すると問題があります。
何が問題なのでしょうか? kubectl get ingress -A などで ingressの状況を確認してみます。
以下のような結果が得られます。(若干編集してあります)

NAMESPACE          NAME                          CLASS                    HOSTS                                               ADDRESS        PORTS     AGE
public-service    public-service-ingress        nginx                    public.example.com                                   192.168.1.10   80, 443   XXd
private-service   private-service-ingress       nginx                    private.example.com                                  192.168.1.10   80, 443   XXd

ADDRESSのところを見てみると、なんと同じIPアドレスが使われていますね。
IPアドレスなども含めて社外と社内のサービスを分けたいと考えていたのでこれは困ります。

これは、Ingress-Nginxの仕様でingressclassが同じものは同一のnginxにまとめてしまう動作によるものです。
マネージドなk8sだとIngressに対応してロードバランサが払い出されるものが多いです。これと同じ挙動を期待してはいけないようです。

IPが別のIngressを作成するには?

Ingress-NginxでIPが異なるNginxを払い出すにはどうすればいいのでしょうか?
公式のマニュアルに解説があります。
https://docs.nginx.com/nginx-ingress-controller/installation/running-multiple-ingress-controllers/

Ingress-NginxはIngressClassが別に指定されているControllerを追加で起動する必要があるようです。
controllerから完全に別のものをインストールする必要があるので、helmを使って別途インストールするのが手っ取り早そうです。
private-ingress-nginx という ingressclass を指定した ingress-nginx をhelmでインストールします。

helm install -n private-ingress \
             --set controller.ingressClass="private-ingress-nginx" \
             --set controller.ingressClassResource.name="private-ingress-nginx" \
             --set controller.ingressClassResource.controllerValue="k8s.io/private-ingress-nginx" \
             --create-namespace \
             private-ingress-nginx \
             ingress-nginx/ingress-nginx

インストール後、kubectl get pod -n private-ingress-system などを実行してコントローラが動作していることを確認します。さらに、ingressclassが新しく生成されているかを kubectl get ingressclass で確認します。
ingressclassが2種類出力されれば無事設定できています。

NAME                     CONTROLLER                      PARAMETERS   AGE
private-ingress-nginx   k8s.io/private-ingress-nginx     <none>       XXXd
nginx                    k8s.io/ingress-nginx            <none>       XXXd

この環境で先ほどと同じように複数Ingressを作成してみましょう。
まずは、publicな Ingress です。これは前回と同じものを作成します。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: public-service-ingress
  namespace: public-service
spec:
  ingressClassName: nginx
  rules:
    - host: public.example.com
      http:
        paths:
        - backend:
            service:
              name: nginx
              port:
                number: 80
          path: /
          pathType: Prefix

次に、内部に限定公開するサービスを作ります。
今回は、ingressClassNameprivate-ingress-nginx を指定します。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: private-service-ingress
  namespace: private-service
spec:
  ingressClassName: private-ingress-nginx
  rules:
    - host: private.example.com
      http:
        paths:
        - backend:
            service:
              name: nginx
              port:
                number: 80
          path: /
          pathType: Prefix

さて、ingressにちゃんと別のIPアドレスが付与されたか確認してみます。
kubectl get ingress -A を実行してみます。

NAMESPACE          NAME                        CLASS                    HOSTS                                                ADDRESS        PORTS     AGE
public-service     public-service-ingress      nginx                    public.example.com                                   192.168.1.10   80, 443   XXXd
private-service    private-service-ingress     private-ingress-nginx    private.example.com                                  192.168.1.11   80, 443   XXXd

ちゃんと別のIPアドレスが付与されていることを確認できました!
これで、アクセス先のIPアドレスが社外サービスと社内サービスで違う状態になったので、アクセス制御などが実施しやすくなりました。

まとめ

今回は、オンプレミス環境のk8s上でIngressを使う方法、Ingress-Nginx controllerを使う場合に社外向け、社内向けといった区分けで異なるIPを持っているIngressを作成する方法について紹介しました。オンプレミス環境でk8sを運用している方の参考になれば幸いです。


私たちは同じチームで働いてくれる仲間を探しています。今回のエントリで紹介したような仕事に興味のある方、ご応募お待ちしています。

ソリューションアーキテクト

執筆:@yamashita.tsuyoshi、レビュー:@wakamoto.ryosuke
Shodoで執筆されました