🥰

kind環境でIngressを動かす

に公開

はじめに

Kubernetesの勉強の一環としてkind(Kubernetes in Docker)でIngressを使ってみたので、その際にうまくいった手順やつまづいたことを記録しておく。

前提知識

  • Dockerが使える
  • kubectlでdeploymentとserviceを作れる
  • KubernetesのNamespaceの概念が分かる
  • kindを使える
  • Ingressの概要が分かる

環境

  • WSL上のUbuntu 24.04.1 LTS
  • Docker Desktop, kubectl, kindをインストール済み

手順

手順1. kindでクラスターを作成する

kind create cluster --config=./cluster-manifest.yaml
# ./cluster-manifest.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 80
    hostPort: 8080
    protocol: TCP
  - containerPort: 443
    hostPort: 443
    protocol: TCP

クラスターなどと言っておきながら、ノード数は1つだけである。最終的にはIngressを使ってノード(実体はホスト上で動く1つのDockerコンテナ)の80番ポートでアプリケーションを公開するので、ホストの8080番ポートとノードの80番ポートを接続する。ちなみにノード数を2つ以上にする場合、「ホストのポートと接続されたノード」と「Ingressが動いているノード」が一致する必要があり、そのためには追加の設定が必要になる。詳細はkindの公式サイトを参照。

手順2. deploymentを作成

ここでは、使用するコンテナイメージは自分で用意することとする。

まずはアプリケーションで使用するコンテナイメージをビルドする。

docker build . -t prac/api

通常であれば使用するコンテナイメージはDocker Hubなどにアップロードしてから参照させるのだが、今回はローカルでビルドしたコンテナイメージをローカルで使うだけであり、それなのにDocker Hubなどを経由するのは明らかに非効率である。以下のコマンドを実行することで、ローカルに保存されているprac/apiというコンテナイメージをkindクラスターに読み込ませることができる。ちなみに意外と時間がかかる。

kind load docker-image prac/api

deploymentを作成する。

kubectl apply -f ./deployment-manifest.yaml
# ./deployment-manifest.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: api
  name: api-dep
spec:
  replicas: 1
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
      - image: prac/api
        name: api
        imagePullPolicy: Never #注意!
        resources: {}

注意すべきなのはimagePullPolicy: Neverの部分。これを設定すると、インターネット上からコンテナイメージをpullしなくなる。今回のように事前にkindクラスタに読み込ませておいたコンテナイメージを使いたい場合はこの設定が必要になる。逆に、普通にDocker Hubなどからコンテナイメージをpullしたい場合はこの設定は記述してはならない。

手順3. Serviceの作成

kubectl apply -f ./service-manifest.yaml
# ./service-manifest.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app: api
  name: api-service
spec:
  type: ClusterIP
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: api

シンプルなService設定である。なお、今回使用するコンテナイメージでは、コンテナを作成すると自動的に80番ポートでアプリケーションを公開するようになっている。

このServiceは直接外部に公開するわけではない(Ingress経由で公開する)ので、typeはClusterIPとする。Ingressの設定がうまくいかないときに上記ServiceのtypeをNodePortなどに変更すると外部からアクセスできるようになって成功したように感じるかもしれないが、ServiceをIngressを介さずに公開してしまっただけであるので浮かれてはならない。

手順4. Ingressの設定

Ingress Controllerを作成

ここが一番つまづいた部分。通常であればIngress ControllerはHelmを使って作成することが多いようだが、kindではHelmを使ってIngress Controllerをインストールしてもうまく動かなかった(理由は不明)。代わりに、kindの公式サイトに書いてあるコマンドでIngress Controllerを作成する。

kubectl apply -f https://kind.sigs.k8s.io/examples/ingress/deploy-ingress-nginx.yaml

これで、ingress-nginxというNamespaceにIngressのdeploymentやらServiceやらが良い感じに作成され、80番ポートと443ポートで公開される。

Ingressリソースを作成

kubectl apply -f ./ingress-manifest.yaml
# ./ingress-manifest.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
spec:
  ingressClassName: nginx
  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 80

シンプルなIngressの設定。全てのhttpリクエストを、先ほど作っておいたapi-serviceの80番ポートに投げる。

ちなみに、Ingress Controllerの作成が終わってからコマンドを実行しないとエラーが起きるので注意。

手順5. 結果を確認

http://localhost:8080にアクセス。正常にレスポンスが返ってくれば成功。

Discussion