スタンドアロンKubernetesクラスタにIngressを設定しWebサーバを公開する

2020-01-31Kubernetes, Linux, Ubuntu

はじめに

余ったPC1台を使ってKubernetesクラスタを構築してみるでKubernetesの検証環境を構築できました。

せっかくできたこの環境を使って外部からアクセス可能なWebサーバを構築し、公開してみたいと思います。

Ingressとは

Ingressとは、Kubernetesで利用できるL7(HTTP/HTTPS)ロードバランサです。
クラスタ内のコンテナ(正確にはPod)を外部に公開できます。

似たようなものとしてLoad Balancer Serviceというものがあります。
こちらはL4(TCP/UDP)ロードバランサです。
後々やってみたいと思っているTLSターミネーションURLマップができません。

したがって、Ingressを使ってみたいと思います。

セットアップ

検証環境

前回のエントリの続きのため、Ubuntu環境を利用しました。

$ uname -v
40~18.04.1-Ubuntu SMP Thu Nov 14 12:06:39 UTC 2019

Ingress Nginx Controller

Ingressとは先程触れたとおり、Kubernetesで利用できるL7(HTTP/HTTPS)ロードバランサです。

Ingressの内部実装はIngress Controllerと呼ばれており、GCPで動作するもの、AWSで動作するものなど色々あります。

ここではオンプレミス環境でも利用できるIngress Nginx Controllerをインストールします。

Ingress Nginx ControllerHelmというツールを使ってセットアップを行います。
*Helm**を利用する理由は、クラスタ外からアクセスするためのIPアドレス(external_ip)の設定が容易なためです。

Helmのインストール

公式ページに記載されている方法でインストールします。

# Install
$ curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3
$ chmod 700 get_helm.sh
$ ./get_helm.sh

# Initialize
$ helm repo add stable https://kubernetes-charts.storage.googleapis.com/

次に外部からアクセスする際のクラスタのIPについて確認します。
スタンドアローンのクラスタなので、 マスタサーバip addr を実行した結果のIPアドレスを利用します。

$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp4s0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
    link/ether 50:e5:49:c3:03:57 brd ff:ff:ff:ff:ff:ff
3: wlx0024a54f427c: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:24:a5:4f:42:7c brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.201/24 brd 192.168.0.255 scope global noprefixroute wlx0024a54f427c
...(省略)...

今回構築したサーバは wifi 環境に接続させているため(サーバなのにwifi)、上記の一番下に表示されている 192.168.0.201 のIPアドレスを利用することになります。

それではHelmを使って、Ingress Nginx Controllerをインストールします。

# ネームスペースを作成しているが作成しなくても問題はない
kubectl create ns nginx-ingress

helm install stable/nginx-ingress \
  --namespace nginx-ingress \
  --generate-name \
  --set 'controller.service.externalIPs={192.168.0.201}'

一点だけ注意点として、ufwが有効になっていた場合、起動がうまくいきませんでした。
sudo ufw disable で無効にした上で実行したところうまくいきました。

Ingressを設定してみる

Ingressを利用できるようになったため、以下のような構成でWebサーバを公開してみます。

  1. sample-app という名前のWebサーバPod(ここではコンテナと読み替えてもOK)を作成
  2. sample-app Podを公開するためのServiceを作成(9000ポートで公開)
    • ここまでくれば、curlコマンドを使ってPodにアクセスできる
  3. sample-app.local というドメインでクラスタ外にServiceを公開するためのIngressを作成(80ポートで公開)
# Podを生成
$ kubectl run --port 80 --image=httpd --labels="app=sample-app" sample-app

# Serviceのマニフェスト(定義ファイル)を生成
$ cat <<EOF > service-sample-app.yml
apiVersion: v1
kind: Service
metadata:
  name: service-sample-app
spec:
  type: NodePort
  selector:
    app: sample-app
  ports:
    - name: "http-port"
      protocol: "TCP"
      port: 9000
      targetPort: 80
EOF

# Serviceを生成
$ kubectl apply -f service-sample-app.yml

この状態では、クラスタの外からはまだアクセスできないが、クラスタ内(サーバ自身)からはアクセスできます。
試してみます。

# Serviceで生成されたIPアドレスを取得
$ IP=$(kubectl describe service/service-sample-app | sed -n 's/^IP:\s*//p')

# IPアドレスが取得できたか確認
$ echo $IP
10.96.97.188

# アクセスしてみる
$ curl service-sample-app:9000
<html><body><h1>It works!</h1></body></html>

最後にIngressを作成します。
ここではApacheのVirtualHost方式を用います。
sample-app.local というホスト名でアクセスされた場合にのみ、Serviceへと転送させます。

$ cat <<EOF > ingress.yml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: ingress
spec:
  rules:
  - host: sample-app.local
    http:
      paths:
      - path:
        backend:
          serviceName: service-sample-app
          servicePort: 9000
EOF

$ kubectl apply -f ingress.yml

Ingressリソースが正しく作成されているかは以下のコマンドで確認できます。

$ kubectl get ing
NAME      HOSTS              ADDRESS   PORTS   AGE
ingress   sample-app.local             80      3s

それではクラスタ外のPCから以下のコマンドを実行して、正しいレスポンスが帰ってくるかを確認してみます。

$ curl -H 'Host: sample-app.local' 192.168.0.201

<html><body><h1>It works!</h1></body></html>

ホスト名が不明だった場合はどうなるでしょう?

$ curl 192.168.0.201
default backend - 404

これでクラスタ外からアクセスできるようになりました。

ひとこと

自分でもまだ用語が整理できていない部分もあり、きれいなエントリとなっていませんが、参考になれば幸いです。

2020-01-31Kubernetes, Linux, Ubuntu