0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

初めてのk3d

Last updated at Posted at 2025-09-15

軽量なKubernetes環境が欲しいと思って調べていたところ、ChatGPTにk3dをオススメされたので色々試してみる。
また、ついでにKong Gatewayの起動まで試してみる。
なお、k3d部分は特に適当に作ってるので真面目に使う人はちゃんと自分で調べた方がいいかも。

k3dとは

元々Rancherがk3sという軽量なK8sディストリビューションを提供していたが、これをDockerで提供するのがk3dとなっている。
コンテナ起動するため、単一VM内にも複数台構成のクラスタが簡単に組めるっぽい。
近いものとしてはkindがあるが、軽さやk8s周辺周りの機能はk3dが揃っているるしい。

検証

前提

今回はEC2上に構築する。
EC2上には以下が用意されているものとする。

  • docker
  • kubectl

インストール

ドキュメントのインストール手順に従いインストールする。

wget -q -O - https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash

クラスタの作成

クラスタの作成はk3d cluster createで行う。--serversでControlPlaneノード、--agentでWorkerノードの数が指定できるようなので、1CP2Worker構成で立ててみる。

k3d cluster create dev \
  --servers 1 --agents 2 \
  --port "80:80@loadbalancer" --port "443:443@loadbalancer"

--portの部分はホストに公開するポートで、Ingress利用時にコンテナを起動している環境にアクセスして動作確認するために利用する。

実行後、自動で.kube/configに設定が反映される。

$ kubectl config view
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://0.0.0.0:39039
  name: k3d-dev
contexts:
- context:
    cluster: k3d-dev
    user: admin@k3d-dev
  name: k3d-dev
current-context: k3d-dev
kind: Config
users:
- name: admin@k3d-dev
  user:
    client-certificate-data: DATA+OMITTED
    client-key-data: DATA+OMITTED

構築は一瞬で終わり、ちゃんと3台構成で起動できた。

$ kubectl get node -o wide
NAME               STATUS   ROLES                  AGE   VERSION        INTERNAL-IP   EXTERNAL-IP   OS-IMAGE           KERNEL-VERSION    CONTAINER-RUNTIME
k3d-dev-agent-0    Ready    <none>                 44m   v1.31.5+k3s1   172.18.0.3    <none>        K3s v1.31.5+k3s1   6.14.0-1011-aws   containerd://1.7.23-k3s2
k3d-dev-agent-1    Ready    <none>                 44m   v1.31.5+k3s1   172.18.0.4    <none>        K3s v1.31.5+k3s1   6.14.0-1011-aws   containerd://1.7.23-k3s2
k3d-dev-server-0   Ready    control-plane,master   44m   v1.31.5+k3s1   172.18.0.2    <none>        K3s v1.31.5+k3s1   6.14.0-1011-aws   containerd://1.7.23-k3s2

なお、標準でIngressも使えるようになっている。

$ kubectl get ingressclass
NAME      CONTROLLER                      PARAMETERS   AGE
traefik   traefik.io/ingress-controller   <none>       45m
$ kubectl get svc -n kube-system
NAME                                                 TYPE           CLUSTER-IP     EXTERNAL-IP                        PORT(S)                        AGE
kube-dns                                             ClusterIP      10.43.0.10     <none>                             53/UDP,53/TCP,9153/TCP         45m
metrics-server                                       ClusterIP      10.43.18.115   <none>                             443/TCP                        45m
traefik                                              LoadBalancer   10.43.32.197   172.18.0.2,172.18.0.3,172.18.0.4   80:32072/TCP,443:32627/TCP     45m

ただし、type:LoadBalancerは使えず、利用するとIPが割り当てられず<pending>となる。
なのでMetalLBをインストールする。

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.2/config/manifests/metallb-native.yaml

通常のインストール手順だとkube-proxyのstrictARPtrueにする設定を挟むが、k3dではkube-proxyがいないのでその手順は割愛した。
なお、MetalLBを適用直後、Traefikに割り当てられているIPが<pending>になって作成済みのIngressがある場合はアクセスできなくなるので注意。

IPプールを作成してアドバタイズする。

cat <<'EOF' | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: default-pool
  namespace: metallb-system
spec:
  addresses:
    - 172.18.0.2-172.18.0.254
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: default-l2
  namespace: metallb-system
spec:
  ipAddressPools:
    - default-pool
EOF

指定するIPレンジはdocker network inspect k3d-dev | jq -r '.[0].IPAM.Config[0].Subnet'みたいな感じでdockerが使っているIPを引っ張ってくるとよさそう。
上述のコマンド実行後、TraefikのIPは再割当てされる。

$ kubectl get svc -n kube-system traefik
NAME      TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
traefik   LoadBalancer   10.43.37.226   172.18.0.2    80:31471/TCP,443:30750/TCP   20m

アクセスできることも確認できる。

$ curl 172.18.0.2 -i
HTTP/1.1 404 Not Found
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff
Date: Mon, 15 Sep 2025 01:36:09 GMT
Content-Length: 19

404 page not found

動作確認

最初にBookinfoでいくつか試してみる。
使うManifestは以下となる。
https://raw.githubusercontent.com/istio/istio/release-1.27/samples/bookinfo/platform/kube/bookinfo.yaml
これにはService, Deployment等は含まれるがIstioのリソースやIngress等は含まれない。
取り敢えずデプロイする。

kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.27/samples/bookinfo/platform/kube/bookinfo.yaml

構成としては以下のようになっており、Product pageが入口となる。
image.png

type:LoadBalancerの確認

最初にProduct pageにtype:LoadBalancerでIPを割り当ててアクセスしてみる。
kubectl patchtypeを変更する

$ kubectl patch service -p '{"spec":{"type":"LoadBalancer"}}' productpage -n default

無事にIPが割り当てられた。

$ kubectl get svc productpage -n default
NAME          TYPE           CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGE
productpage   LoadBalancer   10.43.20.48   172.18.0.3    9080:32463/TCP   12m

ただし、クラスタの起動時に9080ポートをホストに割り当てていなかったので、このポートへの動作確認が外部から出来ない。
しかし、k3dにはk3d cluster editというコマンドで稼働中のクラスタに対してポートを追加で公開する事ができる。
以下のような感じで公開するポートを追加する。

k3d cluster edit dev --port-add "9080:9080@loadbalancer"

公開後、ホストの9080ポートにブラウザでアクセスすると以下のようなページが確認できる。
image.png
/productpageにアクセスすればIstioユーザにはお馴染みの画面も確認できる。
image.png

確認後は設定を元に戻しておく。

kubectl patch service -p '{"spec":{"type":"ClusterIP"}}' productpage -n default

Ingressの確認

Ingressも作成する。

cat <<'EOF' | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: bookinfo
  namespace: default
spec:
  ingressClassName: traefik
  rules:
  - http:
      paths:
      - backend:
          service:
            name: productpage
            port:
              number: 9080
        path: /
        pathType: Prefix
EOF

今度は80ポートの/productpageに対してアクセスする。
image.png
問題なくアクセスできた。

PVの確認

PVはBookinfoだと確認しづらいので、PostgreSQLをHelmで立ててアクセスしてみる。
最初にBitnamiをHelmリポジトリとして追加する。

helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update

Postgresをインストールする。なおパラメータの説明は[こちら]。(https://github.com/bitnami/charts/tree/main/bitnami/postgresql)。

helm install postgres bitnami/postgresql --set service.type=LoadBalancer -n postgres --create-namespace --wait --debug

作成後、PVとPVCを確認する。

$ kubectl get pvc,pv -n postgres
NAME                                               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
persistentvolumeclaim/data-postgres-postgresql-0   Bound    pvc-1ca007f5-b49a-4671-8761-a7633a15fb4c   8Gi        RWO            local-path     <unset>                 81s

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                 STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
persistentvolume/pvc-1ca007f5-b49a-4671-8761-a7633a15fb4c   8Gi        RWO            Delete           Bound    postgres/data-postgres-postgresql-0   local-path     <unset>

作成は問題なさそうだ。
次にアクセスしてデータが書き込めるかも確認する。
Postgresのポートを公開する。

k3d cluster edit dev --port-add "5432:5432@loadbalancer"

パスワードを環境変数PGPASSWORDに設定する。

export PGPASSWORD=$(kubectl get secret postgres-postgresql -o jsonpath="{.data.postgres-password}" -n postgres | base64 -d)

アクセスしてみる。

psql -h <k3dのホストのIP> -U postgres -d postgres -p 5432 -c "SELECT version();"

問題なければ以下のようなバージョン情報が取得できる。

                                              version
---------------------------------------------------------------------------------------------------
 PostgreSQL 17.6 on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14+deb12u1) 12.2.0, 64-bit
(1 row)

次にデータを書き込んでみる。
対話型で起動する。

psql -h <k3dのホストのIP> -U postgres -d postgres -p 5432

DBを作成してデータをINSERTする。

CREATE TABLE test (id SERIAL PRIMARY KEY, msg TEXT);
INSERT INTO test (msg) VALUES ('hello from k3d');

\qで抜けて、Podを再起動してデータが永続化されていることを確認する。

kubectl delete pod --all -n postgres
psql -h <k3dのホストのIP> -U postgres -d postgres -p 5432 -c "SELECT * FROM test;"

以下が取得できればOK。

 id |      msg
----+----------------
  1 | hello from k3d
(1 row)

Kong Gatewayの起動

KongのChartリポジトリで配布されているサンプルを使ってKong Gatewayを起動してみる。
最初に使うManifestをダウンロードする。今回はminimal-k4k8s-with-kong-enterprise.yamlというものにした。

wget https://raw.githubusercontent.com/Kong/charts/refs/heads/main/charts/kong/example-values/minimal-k4k8s-with-kong-enterprise.yaml

次にNamespaceを作成し、Manifest内で参照しているSecretを作成する。

kubectl create ns kong
kubectl create secret generic kong-enterprise-license --from-file license=./license.json -n kong --dry-run=client -o yaml | kubectl apply -f -
kubectl create secret generic kong-enterprise-superuser-password --from-literal=password=kong -n kong

Helmのリポジトリを追加してインストールする。

helm repo add kong https://charts.konghq.com
helm repo update
helm install kong-minimal kong/kong -n kong --wait --debug -f ./minimal-k4k8s-with-kong-enterprise.yaml

デプロイ後、Proxyはtype:LoadBalancerでポート80、Admin APIとKong Managerはtype:NodePortで公開されている。

$ kubectl get svc -n kong
NAME                                   TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                         AGE
kong-minimal-kong-admin                NodePort       10.43.247.87    <none>        8001:30790/TCP,8444:30568/TCP   8m6s
kong-minimal-kong-manager              NodePort       10.43.36.6      <none>        8002:31873/TCP,8445:32335/TCP   8m6s
kong-minimal-kong-metrics              ClusterIP      10.43.6.97      <none>        10255/TCP,10254/TCP             8m6s
kong-minimal-kong-proxy                LoadBalancer   10.43.76.71     172.18.0.3    80:31959/TCP,443:31082/TCP      8m6s
kong-minimal-kong-validation-webhook   ClusterIP      10.43.233.125   <none>        443/TCP                         8m6s
kong-minimal-postgresql                ClusterIP      10.43.195.2     <none>        5432/TCP                        8m6s
kong-minimal-postgresql-hl             ClusterIP      None            <none>        5432/TCP                        8m6s

Proxyにアクセスすると、正常にKong Gatewayとしての応答が返ってくる。

$ curl <k3dのホストのIP>:80
{
  "message":"no Route matched with those values",
  "request_id":"5e42056c523e7b3661717d1151701664"
}

Kong Managerをtype:LoadBalancerに変更する。

kubectl patch service -p '{"spec":{"type":"LoadBalancer"}}' kong-minimal-kong-manager -n kong
k3d cluster edit dev --port-add "8002:8002@loadbalancer"

アクセスしてみる。
image.png
問題なさそうだ。

所感

起動が凄く簡単で、クラスタとしても使いづらいところはあまりなく、使い勝手は結構良かった。
ポートの追加が少し面倒だが、それもコマンドが用意されているのでそこまで不便ではなく、ちょっとしたクラスタを用意して検証する際にはかなり使えると思う。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?