こんにちは。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-Nginx Controller (https://kubernetes.github.io/ingress-nginx/)
- Traefik (https://github.com/traefik/traefik)
- contour (https://github.com/projectcontour/contour)
他にも様々な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
次に、内部に限定公開するサービスを作ります。
今回は、ingressClassName
に private-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で執筆されました)