logo

2026510

Kubernetesの自宅サーバー公開をCloudflare Tunnelに移行した(VPS廃止)

以前の記事 IPoE回線の自宅のWebサービスをVPN経由で固定IPのクラウドから公開する では、IPoE 回線の自宅 Kubernetes クラスタを AWS Lightsail の VPS 経由(HAProxy + WireGuard)で外部公開する方法を紹介しました。あれから約3年、Cloudflare Tunnel を使った構成に切り替えたので、その記録を残しておきます。

困っていたこと

  • 自宅 Kubernetes を外部公開するために Lightsail の VPS を経由していた
  • 月額 $5 の固定費がかかっていた
  • cert-manager による証明書管理はできていたが、VPS を挟む構成をもっとシンプルにしたかった

変更前の構成

UML

変更後の構成

UML

Cloudflare Tunnel は、cloudflared というクライアントがアウトバウンド接続で Cloudflare のエッジサーバーへトンネルを張り続ける仕組みです。以前の WireGuard と同様に、ポート開放なしに外部からアクセスできます。さらに VPS が不要になるので固定費がゼロになり、Cloudflare が TLS 終端してくれるため cert-manager の管理も不要になります。

移行手順

1. DNS を Cloudflare に移行

Cloudflare Tunnel は Cloudflare DNS を使う構成が一般的なので、今回は DNS を Cloudflare に移行しました。ドメインレジストラの設定でネームサーバーを Cloudflare のものに変更し、既存の DNS レコードが正しく移行されているか確認します。

移行前に使っていた DNS レコードと同じ内容が Cloudflare 側にも登録されていることを確認します。この時点ではまだ VPS の静的 IP を向き先にしているので、Proxy status は Proxied ではなく DNS only にしておきます。

2. Cloudflare Tunnel を作成

Cloudflare の管理画面で操作します。

  1. NetworkingTunnels を開く
  2. Create Tunnel をクリック
  3. 任意のトンネル名を入力して作成
    • ドメイン毎ではなく拠点や環境毎に作るものなので、場所がわかる命名がよさそう
    • 例: home, kubernetes, k3s...
  4. Operating System として Docker を選択し、表示されるコマンドに含まれるトンネルトークン(--token の後ろ)をメモしておく
    docker run cloudflare/cloudflared:latest tunnel --no-autoupdate run --token ey...

3. Kubernetes に cloudflared をデプロイ

トンネルトークンを Kubernetes の Secret として登録します。

kubectl create namespace cloudflare
kubectl create secret generic cloudflared-credentials \
  --from-literal=token=<トンネルトークン> \
  -n cloudflare

次に Deployment を作成します。replicas: 2 にすることで cloudflared の Pod が複数起動し、 Cloudflare との接続が冗長化されるため可用性が高まります。1

私は Helm chart 化してデプロイしましたが、以下に同等の内容の YAML を置いておきます。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: cloudflared
  namespace: cloudflare
spec:
  replicas: 2
  selector:
    matchLabels:
      app: cloudflared
  template:
    metadata:
      labels:
        app: cloudflared
    spec:
      containers:
        - name: cloudflared
          image: cloudflare/cloudflared:latest
          args:
            - tunnel
            - --no-autoupdate
            - run
            - --token
            - $(TUNNEL_TOKEN)
          env:
            - name: TUNNEL_TOKEN
              valueFrom:
                secretKeyRef:
                  name: cloudflared-credentials
                  key: token

Cloudflare Tunnel の画面で接続確認が取れれば OK です。

4. cloudflared の転送先を Traefik の Service に変更

Cloudflare Tunnel の管理画面の Routes で、公開するドメイン名とバックエンドサービスを紐付けます。

Service URL にはクラスタ内の Ingress controller の URL を指定します。
例えば k3s 環境だと kube-system namespace に traefik という 80 番ポートの Service がある 2 ので、http://traefik.kube-system.svc.cluster.local:80 を指定すれば OK です。

  1. Add route をクリック
  2. Published application をクリック
  3. 必要な項目を入力
    • Subdomain: 任意。必要なければ空
    • Domain: Cloudflare のゾーン
    • Path: 任意。必要なければ空
    • Service URL: クラスタ内の Ingress controller の URL
  4. ルートを追加
    • 対応する DNS レコード(<UUID>.cfargotunnel.com)が追加されます

ルートドメインと任意のサブドメインをまとめて転送したければ、Subdomain が空のルートとワイルドカード (*) のルートの 2 つを作っておきます。

5. 動作確認

ブラウザで各サービスにアクセスして問題がないか確認します。

Traefik の Ingress ルーティング自体は変わらないので、ホスト名が一致していれば問題なく動くはずです。

6. cert-manager の TLS 設定を Ingress から削除

Cloudflare が TLS を終端するため、今回は Kubernetes 側の cert-manager を削除しました。Ingress リソースの spec.tls セクションおよび cert-manager のアノテーションを削除します。

# 変更前
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
    - hosts:
        - app.example.com
      secretName: app-tls
  rules:
    - host: app.example.com
      http:
        paths: ...
# 変更後
spec:
  rules:
    - host: app.example.com
      http:
        paths: ...

おわりに

Cloudflare Tunnel への移行は想像より簡単で、サービスを止めることなくスムーズに切り替えられました。固定費ゼロ・構成シンプル・cert-manager 不要は嬉しいですね。

参考文献

Footnotes

  1. Cloudflare のドキュメントでは最低2レプリカを推奨しています。レプリカ数を増やすほど接続が安定しますが、個人利用であれば2で十分でしょう。

  2. ネットワーキングサービス | K3s