Amazon EKS クラスターにある複数の Kubernetes サービスへの外部アクセスを提供する方法を教えてください。
最終更新日: 2021 年 10 月 11 日
Amazon Elastic Kubernetes Service (Amazon EKS) クラスターにある複数の Kubernetes サービスへの外部アクセスを提供したいと考えています。
簡単な説明
Amazon EKS クラスターにある複数の Kubernetes サービスへの外部アクセスを提供するには、NGINX Ingress Controller for Kubernetes を使用します。
注: NGINX Ingress Controller は、ロードバランサーよりも効率的でコスト効率が高い場合があります。さまざまなマイクロサービスにトラフィックを送信するために、ロードバランサーを予約する必要がある場合もあります。NGINX Ingress Controller は、主に NGINX によってメンテナンスされています。NGINX Ingress Controller で問題を確認するには、GitHub の問題の一覧をご参照ください。
重要: (Kubernetes ウェブサイトの) Ingress Controller は、(Kubernetes のウェブサイトの) Ingress とは異なります。Ingress は、クラスターの外部からクラスター内のサービスへの HTTP および HTTPS ルートを公開する Kubernetes リソースです。Ingress Controller が入力を実行します(通常はロードバランサーを使用します)。Ingress Controller なしで Ingress を使用することはできません。
解決方法
次の解決策では、NGINX GitHub ウェブサイトの nginxinc/kubernetes-ingress Ingress Controller を使用します。パブリックに使用できる他の Ingress Controller は、Kubernetes GitHub サイトの kubernetes/ingress-nginx です。
NGINX Ingress Controller for Kubernetes をデプロイする
1. NGINX Ingress Controller for Kubernetes をダウンロードします。
git clone https://github.com/nginxinc/kubernetes-ingress.git
2. Ingress Controller をデプロイするディレクトリを選択します。
cd kubernetes-ingress/deployments/
注: 次の手順のすべてのコマンドは、デプロイディレクトリから実行します。
3. エッジリリースではなく、NGINX Ingress Controller の安定版リリースを使用していることを確認します (2021 年 3 月時点で試験段階)。
git checkout v1.10.1
注: NGINX Ingress Controller リリースの詳細については、GitHub の NGINX Ingress Controller Releases をご参照ください。
4. デフォルトのサーバーの専用の名前空間、サービスアカウント、および (キー付き) TLS 証明書を作成します。
kubectl apply -f common/ns-and-sa.yaml
kubectl apply -f common/default-server-secret.yaml
注: デフォルトのサーバーは、Ingress ルールが定義されていないドメインのリクエストすべてに対して、404 ステータスコードを含む「見つかりません」ページを返します。テストの目的で生成した自己署名証明書とキーを使用します。本番環境では、独自の証明書とキーを使用することをお勧めします。
5. NGINX 設定をカスタマイズするための ConfigMap を作成します。
kubectl apply -f common/nginx-config.yaml
6. ロールベースのアクセス制御 (RBAC) を設定し、ClusterRole を作成してから、ステップ 3 の ClusterRole をサービスアカウントにバインドします。例:
kubectl apply -f rbac/rbac.yaml
注: ClusterRole は、Amazon EKS クラスターを操作するためのアクセス権限を Ingress Controller に付与します。
7. Kubernetes クラスターのバージョンが 1.18 以上の場合は、NGINX Ingress Class を作成します。
kubectl apply -f common/ingress-class.yaml
8. Ingress Controller をデプロイします。
kubectl apply -f deployment/nginx-ingress.yaml
kubectl get pods --namespace=nginx-ingress
注: Deployment または DaemonSet オプションを使って、Ingress Controller をデプロイできます。Deployment オプションでは、Ingress Controller のレプリカの数を動的に変更できます。DaemonSet オプションでは、すべてのノードまたはノードのサブセットに Ingress Controller をデプロイできます。前のステップ 7 では、[Deployment] (デプロイ) オプションを使用します。
出力例:
NAME READY STATUS RESTARTS AGE
nginx-ingress-fb4f4b44c-xmq6z 1/1 Running 0 12s
Ingress Controller が Ingress オブジェクトからのリクエストを受け入れることができるようになりました。
Ingress Controller にアクセスし、アプリケーションを実行する
Deployment ingress-controllerの場合、タイプ NodePort または LoadBalancer のサービスオブジェクトを使用します。次のステップでは、LoadBalancer タイプを使用します。
1. 設定を適用します。
kubectl apply -f service/loadbalancer-aws-elb.yaml
kubectl get svc --namespace=nginx-ingress
出力例:
NAME TYPE EXTERNAL-IP PORT(S)
nginx-ingress LoadBalancer aaa71bxxxxx-11xxxxx10.us-east-1.elb.amazonaws.com 80:32462/TCP,443:32226/TCP
注: Amazon EKS はクライアントの情報 (IP アドレスとポート) を渡すために PROXY プロトコルが有効になっている TCP モードで Classic Load Balancer を割り当てます。このプロキシ情報を Ingress Controller に渡す必要があります。
2. プロキシ情報を Ingress Controller に渡すため PROXY プロトコルを使用するように NGINX を設定します。次に、ステップ 1 の nginx-config.yaml ファイルに次のキーを追加します。例:
kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-config
namespace: nginx-ingress
data:
proxy-protocol: "True"
real-ip-header: "proxy_protocol"
set-real-ip-from: "0.0.0.0/0"
注: プロキシ情報は、前に作成した ConfigMap を介して Ingress Controller に渡されます。
3. ConfigMap を更新します。
kubectl apply -f common/nginx-config.yaml
4. デプロイまたはマイクロサービス(hostname-app や apache-app など)をセットアップします。以下の例をご覧ください。
注: このステップでは、(デモ用に)2 つのマイクロサービスを実行していることを前提としています。マイクロサービスは、デフォルトタイプとして Kubernetes を使用して内部に公開されます。
hostname-app の hostname-app-svc.yaml ファイルの例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hostname-app
spec:
replicas: 2
selector:
matchLabels:
app: hostname-app
template:
metadata:
labels:
app: hostname-app
spec:
containers:
- name: hostname-app
image: k8s.gcr.io/serve_hostname:1.1
---
apiVersion: v1
kind: Service
metadata:
name: hostname-svc
spec:
ports:
- port: 80
targetPort: 9376
protocol: TCP
selector:
app: hostname-app
apache-app の apache-app-svc.yaml ファイルの例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: apache-app
spec:
replicas: 2
selector:
matchLabels:
app: apache-app
template:
metadata:
labels:
app: apache-app
spec:
containers:
- name: apache-app
image: httpd:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: apache-svc
labels:
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: apache-app
設定を適用します。
kubectl apply -f hostname-app-svc.yaml
kubectl apply -f apache-app-svc.yaml
5. Ingress を実装して、Ingress Controller によって提供される単一のロードバランサーを使用してサービスとインターフェイスで接続します。次の micro-ingress.yaml の例を参照してください。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: micro-ingress
namespace: default
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: hostname.mydomain.com
http:
paths:
- backend:
serviceName: hostname-svc
servicePort: 80
- host: apache.mydomain.com
http:
paths:
- backend:
serviceName: apache-svc
servicePort: 80
注: 詳細については、Kubernetes ウェブサイトの Name based virtual hosting をご参照ください。
6. 設定を適用します。
kubectl apply -f micro-ingress.yaml
注: この Ingress リソースは、hostname.mydomain.com のすべてを hostname-svc にリダイレクトし、apache.mydomain.com のすべてを apache-svc にリダイレクトするルールを定義します。ルールに一致しないリクエストは、404「見つかりません」エラーメッセージを返します。
Ingress について説明すると、次のようなメッセージが表示されます。
kubectl describe ingress micro-ingress
Name: micro-ingress
Namespace: default
Address:
Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
Host Path Backends
---- ---- --------
hostname.mydomain.com
hostname-svc:80 (192.168.47.163:9376,192.168.70.76:9376)
apache.mydomain.com
apache-svc:80 (192.168.37.44:80,192.168.84.218:80)
Annotations: kubernetes.io/ingress.class: nginx
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal AddedOrUpdated 23s nginx-ingress-controller Configuration for default/micro-ingress was added or updated
NGINX Ingress Controller をテストする
1. コマンドラインから以前に取得したロードバランサーの DNS URL にアクセスします。
curl -I http://aaa71bxxxxx-11xxxxx10.us-east-1.elb.amazonaws.com/
注: ロードバランサーのエンドポイントは、前述の Ingress Controller にアクセスし、アプリケーションを実行するのセクションからのものです。
出力例:
HTTP/1.1 404 Not Found
Server: nginx/1.17.5
Date: Mon, 25 Nov 2019 20:50:58 GMT
Content-Type: text/html
Content-Length: 153
Connection: keep-alive
注: デフォルトのサーバーは、Ingress ルールが定義されていないドメインのリクエストすべてに対して、404 ステータスコードを含む「見つかりません」ページを返します。Ingress Controller は、定義されたルールに基づいて、リクエストが設定と一致しない限り、指定されたバックエンドサービスにトラフィックを振り分けることはありません。host フィールドは Ingress オブジェクト用に設定されているため、同じホスト名でリクエストの Host ヘッダーを指定する必要があります。テスト環境では、curl フラグを使用してホストヘッダーを指定します。本番環境では、ロードバランサーの DNS 名を Amazon Route 53 などの任意の DNS プロバイダーのホスト名にマッピングします。
2. Host ヘッダーにリクエストを追加します。
これは、最初に設定したドメインに基づくリクエストです。
curl -i -H "Host: hostname.mydomain.com" http://aaa71bxxxxx-11xxxxx10.us-east-1.elb.amazonaws.com/
出力例:
HTTP/1.1 200 OK
Server: nginx/1.19.8
Date: Thu, 30 Sep 2021 19:50:08 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 29
Connection: keep-alive
hostname-app-5bf66fcc9f-fr8kn
これは、2 番目に設定したドメインに基づくリクエストです。
curl -i -H "Host: apache.mydomain.com" http://aaa71bxxxxx-11xxxxx10.us-east-1.elb.amazonaws.com/
出力例:
HTTP/1.1 200 OK
Server: nginx/1.19.8
Date: Thu, 30 Sep 2021 19:44:22 GMT
Content-Type: text/html
Content-Length: 45
Connection: keep-alive
Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
ETag: "2d-432a5e4a73a80"
Accept-Ranges: bytes
<html><body><h1>It works!</h1></body></html>
Host ヘッダーを追加すると、Ingress Controller は Ingressで定義した設定と一致するため、トラフィックをバックエンドで設定されたサービスにリダイレクトできます。
同じドメイン名を維持したいが、アクセスしたパスに基づいてトラフィックを迂回させたい場合は、Ingress でパスベースのルーティングを追加する必要があります。例:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: path-ingress
annotations:
nginx.org/rewrites: "serviceName=apache-svc rewrite=/"
spec:
rules:
- host: mydomain.com
http:
paths:
- path: /hostname
backend:
serviceName: hostname-svc
servicePort: 80
- path: /apache
backend:
serviceName: apache-svc
servicePort: 80
前の例では、リクエストに mydomain.com がホストヘッダーとして含まれている場合、200 レスポンスのみを返します。リクエストは、/hostname または /apache パスでアクセスされます。他のすべてのリクエストでは、404 レスポンスが返されます。
curl -i -H "Host: mydomain.com" http://aaa71bxxxxx-11xxxxx10.us-east-1.elb.amazonaws.com/hostname
- または -
curl -i -H "Host: mydomain.com" http://aaa71bxxxxx-11xxxxx10.us-east-1.elb.amazonaws.com/apache