はじめに
Kubernetesでコンテナで動かしているサービスを公開する方法としてIngressがあります。
Ingressを動かすにはIngress Controllerが必要です。この記事ではNginxのIngress Controllerのコンテナイメージをビルドしてデプロイ(Kubernetesクラスタ上に作成)してみます。
使用するIngress Controller
Ingressではクラスタ内のサービスへのアクセス制御できます。
Ingressを動かすにはIngress Controllerが必要です。
Ingress Controllerにはオープンソースなもの、クラウド毎に提供しているものなどがあります。
今回はNginxを基にした無料版のIngress Controllerを使ってみます。
有料版ではWAFの機能を備えたNginx App Protectが使えます。
作成する構成図
以下の構成を作成します。
今回はminikubeでクラスタを作成します。インストール手順は省略しますがalias kubectl="minikube kubectl --"
としています。
NginxのPODを作成し、Serviceでポート80を使ってアクセスできるようにします。VirtualServerはIngressと同じ役割で、ホスト名を定義してServiceへルーティングします。NodePort Serviceにてクラスタを動かしているノードのポートにマッピングして、クラスタ外からアクセスできるようにします。
VirtualServerではIngressよりも詳細にNginxの設定を行うことができるようになっています。
実践
Nginxサービスをデプロイする
$ kubectl create ns myns
namespace/myns created
$ kubectl run nginx --image=bitnami/nginx --port=8080 --namespace=myns
pod/nginx created
$ kubectl expose pod nginx -n myns --name=mysvc --port=80 --target-port=8080
service/mysvc exposed
$ kubectl get all -n myns
NAME READY STATUS RESTARTS AGE
pod/nginx 1/1 Running 0 116m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/mysvc ClusterIP 10.96.165.72 <none> 80/TCP 20s
それますが、今回はyamlファイルを作成せずデプロイする練習をしています。Kubernetesの試験の勉強のためです。
この段階ではクラスタ内からアクセスできるようになっています。
以下のコマンドで一時的にPODを立ち上げてクラスタ内からアクセスできます。
$ kubectl run busybox --image busybox -it --rm --restart=Never -- wget -O - mysvc.myns
Ingress Controllerのコンテナイメージをビルドする
ドキュメントに従ってビルドします。ビルド方法は複数種類あるので必要に応じてベースイメージ、ツールなどを変更します。今回はローカルにgoをインストールしてビルドしてみます。
gitをインストールします。
$ sudo yum install -y git-2.38.1
goをインストールします。
$ sudo amazon-linux-extras install epel -y
$ sudo yum install -y golang-1.18.8
gitリポジトリをクローンしてビルドします。
$ git clone https://github.com/nginxinc/kubernetes-ingress.git --branch v2.4.2
$ cd kubernetes-ingress
$ make debian-image TARGET=local
ビルドする方法はTARGETにて選べます。
TARGETの値 | 説明 |
---|---|
local | ローカルのgoを使ってビルドする |
container | goコンテナを使ってビルドする |
download | バイナリファイルのコンパイルを行わずにビルドする |
NginxのIngress ControllerのGithubは以下の通りです。
minikubeでビルドしたイメージを使うため、ロードする。
$ minikube image load nginx/nginx-ingress:$(docker images | grep nginx-ingress | awk '{print $2}')
Ingress Controller関連リソースをデプロイする
コンテナやサービスなどのリソースを以下のドキュメントに従って作成する。
複数の方法がありますが、今回はyamlファイルから作成します。
また、ロードバランサーは作成しないため、ノードポートを使用します。
cd kubernetes-ingress
kubectl apply -f deployments/common/ns-and-sa.yaml
kubectl apply -f deployments/rbac/rbac.yaml
kubectl apply -f deployments/rbac/apdos-rbac.yaml
kubectl apply -f deployments/common/default-server-secret.yaml
kubectl apply -f deployments/common/nginx-config.yaml
kubectl apply -f deployments/common/ingress-class.yaml
kubectl apply -f deployments/common/crds/k8s.nginx.org_virtualservers.yaml
kubectl apply -f deployments/common/crds/k8s.nginx.org_virtualserverroutes.yaml
kubectl apply -f deployments/common/crds/k8s.nginx.org_transportservers.yaml
kubectl apply -f deployments/common/crds/k8s.nginx.org_policies.yaml
kubectl apply -f deployments/deployment/nginx-ingress.yaml
kubectl apply -f deployments/service/nodeport.yaml
コマンドが多いのでミスがないか確認したい場合は、Ingress ControllerのPODのログを見るとよいと思います。
$ kubectl logs -n nginx-ingress $(kubectl get pod -n nginx-ingress | grep nginx-ingress | awk '{print $1}')
注意点として、コンテナはminikube本体のコンテナ上で動いています。そのため、ノードポートはminikube本体のコンテナのポートにマッピングしています。
どのポートにマッピングしているかはNodePort Serviceを見るとわかります。
下記の場合、HTTPは32440ポート、HTTPSは30230ポートにマッピングしています。
$ kubectl get svc -n nginx-ingress
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-ingress NodePort 10.104.212.55 <none> 80:32440/TCP,443:30230/TCP 62s
まだバックエンドの設定ができていませんが、404のレスポンスは取得できます。
$ sudo docker exec minikube curl -s localhost:32440
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.23.2</center>
</body>
</html>
VirtualServerをデプロイする
NginxのService用のVirtualServerのyamlファイルを作成します。
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
name: mynginx-co-jp-vs #リソース名の定義
namespace: myns
spec:
host: mynginx.co.jp #ホスト名の定義
tls:
secret: mynginx-co-jp-cert #HTTPSで用いる証明書を入れたSecret名
ingressClassName: nginx #使用するIngressClass名
upstreams:
- name: mynginx-co-jp #バックエンド名の定義
service: mysvc #バックエンドのサービス名
port: 80 #使用するポート
routes:
- path: / #パス「/」の場合にバックエンド「mynginx-co-jp」に送信する。
action:
pass: mynginx-co-jp
HTTPSのアクセスを受け付けるため、自己証明書を用意します。
$ openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout private.key \
-out server.crt \
-subj "/CN=mynginx.co.jp/O=mynginx.co.jp" &> /dev/null
$ kubectl create secret -n myns tls mynginx-co-jp-cert \
--key private.key \
--cert server.crt
その後、VirtualServerを作成します。
$ kubectl apply -f virtualserver.yaml
エラーが出ていないか確認します。VirtualServerのSTATEがValidになっていることを確認します。なっていない場合はdescribeコマンドで原因を調べます。
$ kubectl get vs -n myns
NAME STATE HOST IP PORTS AGE
mynginx-co-jp-vs Valid mynginx.co.jp 2m40s
これでNodePort Serviceを通してNginxのServiceにアクセスできるようになっているはずです。
HTTPSでアクセスしてみます。
$ sudo docker exec minikube curl -sk https://localhost:30230 -H"Host:mynginx.co.jp"
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
できました。
HTTPでも以下のようにアクセスできます。
$ sudo docker exec minikube curl -s http://localhost:32440 -H"Host:mynginx.co.jp"
おわりに
勉強するまでよくわからなかったNginxとIngress Controllerについて触れました。
まだまだ理解しきれていませんが、Nginxがわかればネットワーク関連でできることが増えるので勉強していきたいです。