コンテンツにスキップ

インフラストラクチャ

KanjiIQはHetzner上のセルフホストKubernetesクラスターで動作し、IngressにTraefik、自動TLSにcert-managerを使用しています。

ホスティング:Hetzner専用サーバー

本番環境全体が単一のHetzner専用サーバーで動作しています:

  • Kubernetesディストリビューション:k3s(軽量、単一バイナリのKubernetes)
  • OS:Linux
  • ネットワーキング:Cloudflare DNS付きパブリックIPv4

なぜHetznerなのか?

  • 予測可能な月額料金(リクエスト単位や時間単位の課金なし)
  • ヨーロッパのデータセンター(GDPRフレンドリー)
  • 優れたコストパフォーマンス
  • k3sインストールのためのフルルートアクセス

Kubernetes:k3s

k3sは、以下をバンドルした軽量でCNCF認定のKubernetesディストリビューションです:

  • コンテナランタイム:containerd
  • Ingressコントローラー:Traefik(プリインストール)
  • サービスロードバランサー:Klipper
  • ストレージ:Local path provisioner
  • DNS:CoreDNS

k3sはマルチコンポーネントのkubeadmセットアップの代わりに、単一バイナリ(約100MB)でKubernetesを動作させます。標準のKubernetes APIと完全に互換性があり、すべてのkubectlコマンドとマニフェストが同様に動作します。

Ingress:Traefik

Traefikはクラスターのingressコントローラーとして以下を処理します:

  • TLS終端:すべてのドメインの自動HTTPS
  • ルーティング:サービスへのホストベースルーティング(kanjiiq.com → frontend、api.kanjiiq.com → backend)
  • レート制限:CRDミドルウェアによるIPごとのリクエストスロットリング
  • セキュリティヘッダー:ミドルウェアチェーンによるHSTS、X-Frame-Options、CSP

ミドルウェア設定

# Public traffic: rate limit + security headers
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: public-security-chain
spec:
  chain:
    middlewares:
      - name: rate-limit        # 100 req/min, burst 50
      - name: security-headers  # HSTS, X-Frame-Options, etc.
# Admin traffic: stricter rate limit + auth
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: admin-security-chain
spec:
  chain:
    middlewares:
      - name: api-rate-limit    # 50 req/min, burst 25
      - name: security-headers
      - name: admin-auth

TLS:cert-manager + Let's Encrypt

自動TLS証明書管理:

graph LR
    I[Ingress with<br/>cert-manager annotation] --> CM[cert-manager]
    CM --> LE[Let's Encrypt<br/>ACME challenge]
    LE --> C[TLS Certificate]
    C --> S[Kubernetes Secret]
    S --> T[Traefik uses cert<br/>for HTTPS]
  • ClusterIssuerletsencrypt-prod(クラスター全体の認証局)
  • チャレンジタイプ:Traefik経由のHTTP-01
  • 更新:有効期限前に自動更新
  • ストレージ:証明書はKubernetes Secretとして保存

Ingressリソースは単一のアノテーションで証明書をリクエストします:

annotations:
  cert-manager.io/cluster-issuer: letsencrypt-prod

DNS:Cloudflare

ドメインDNSはCloudflareで管理されています:

  • Aレコード:HetznerサーバーIPを指定
  • プロキシ:オプションのCloudflare CDN/WAFレイヤー
  • CF-IPCountryヘッダー:IPデータベースなしでバックエンドがジオロケーションに使用

コンテナレジストリ:Forgejo

DockerイメージはForgejo Container Registry(<registry>)に保存されています:

  • ソースコードと同じ場所に配置(単一プラットフォーム)
  • Kubernetesでイメージプルシークレットを設定(forgejo-registry
  • タグ:各ビルドで:latest + :COMMIT_SHA
  • 外部レジストリへの依存なし(Docker Hub、GHCRなど)

リソース割り当て

コンポーネント CPUリクエスト CPU上限 メモリリクエスト メモリ上限
Backend 250m 500m 256Mi 512Mi
Frontend 100m 200m 128Mi 256Mi
PostgreSQL 250m 500m 256Mi 512Mi
Docs 10m 100m 32Mi 64Mi