Contents
プラグインタイプと活用シーン
KrakenD が公式にサポートしているプラグインは 3 種類 です。リクエスト処理のどのフェーズでフックしたいかによって選択肢が決まります。
| タイプ | 主な用途 | インターフェース例 |
|---|---|---|
| Middleware | 認証・ロギング・リクエスト前処理 | func(*router.Handler) error |
| Request/Response Modifier | ペイロード変換、ヘッダー付与、レスポンス加工 | func([]byte) ([]byte, error) |
| Backend Proxy | バックエンド呼び出し前後のカスタムロジック | func(*proxy.BackendRequest) (*proxy.BackendResponse, error) |
これらを組み合わせれば、ほぼすべてのビジネス要件に対するプラグイン構成が実現します。
v2.6 系で追加された機能
v2.6 以降では コンフィギュレーション拡張 と 動的ロード が強化され、プラグインのバージョン管理や環境変数によるパス指定が公式にサポートされました。
plugin.pathに${KRAKEND_PLUGIN_PATH}などの環境変数を書けるようになり、CI/CD パイプラインでの柔軟なデプロイが可能に。Init関数へcontext.Contextが渡され、プラグイン側で実行時設定やシークレット情報を取得できる。- 公式ドキュメント: https://www.krakend.io/docs/extending/writing-plugins/
これにより、ビルド時にパスをハードコードする必要がなくなり、ステージごとのプラグイン差し替えがシンプルになります。
Go 環境の構築とモジュールバージョン合わせ
KrakenD v2.6.x は Go 1.22 系 と互換性があります。正しい Go バージョンと go.mod の設定を揃えることで、ビルドエラーやリンク不整合を防げます。
Go 1.22 のインストール方法
以下は Linux/macOS 環境で asdf を使って 1.22.4 以上を導入する手順です。goenv や公式バイナリでも同様に適用できます。
|
1 2 3 4 5 6 7 8 9 10 11 12 |
# asdf に golang プラグインを追加 asdf plugin-add golang https://github.com/asdf-community/asdf-golang.git # 1.22 系の最新版をインストール asdf install golang 1.22.4 # デフォルトバージョンとして設定 asdf global golang 1.22.4 # バージョン確認 go version # → go version go1.22.4 linux/amd64 |
インストール後は go env で GOROOT と GOPATH が期待通り設定されていることを必ず確認してください。
go.mod の記述例
プラグインプロジェクトの go.mod は KrakenD 本体と同一バージョンを明示し、Go バージョンは 1.22 系に固定します。これによりビルドモード c-shared 時のシンボルテーブル不整合が回避できます。
|
1 2 3 4 5 6 7 8 9 10 |
module github.com/yourorg/krakend-custom-plugin go 1.22 require ( github.com/devopsfaith/krakend v2.6.5 // 必要に応じて正確なリビジョンを指定 ) replace github.com/devopsfaith/krakend => github.com/devopsfaith/krakend v2.6.5 |
go mod tidy 後に go list -m all でバージョンが揃っていることを確認し、CI 環境でも同一モジュールキャッシュが使われるようにします。
プラグイン実装・ビルド手順 と Docker マルチステージ化
プラグインは Go の c‑shared ビルドで .so ファイルを生成し、Docker のマルチステージ構成でイメージサイズを最小化します。
.so ファイルの作成
プラグインは package main とエントリポイント Init を持ちます。以下は Middleware のシンプルな雛形です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
package main import ( "context" "net/http" "github.com/devopsfaith/krakend/router" "github.com/google/uuid" ) // Init は KrakenD 起動時に呼び出され、router.HandlerFactory を返す。 func Init(ctx context.Context, cfg map[string]interface{}) (router.HandlerFactory, error) { return func(h router.Handler) router.Handler { return router.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // リクエストヘッダーにトレーシング ID を付与 r.Header.Set("X-Trace-ID", uuid.New().String()) h.ServeHTTP(w, r) }) }, nil } |
ビルドコマンドは次の通りです(Linux/AMD64 用):
|
1 2 3 |
GOOS=linux GOARCH=amd64 CGO_ENABLED=1 \ go build -buildmode=c-shared -trimpath -o my_middleware.so . |
生成された .so は実行環境と同じアーキテクチャであればそのまま使用できます。
Dockerfile のマルチステージ例
以下は builder ステージでプラグインをビルドし、runtime ステージで KrakenD 本体に組み込む構成です。最終イメージは約 30 MB に抑えられます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# ---------- Builder ---------- FROM golang:1.22-alpine AS builder WORKDIR /src # モジュールキャッシュ用に go.mod と go.sum を先にコピー COPY go.mod go.sum ./ RUN go mod download # プラグインコードをコピーしてビルド COPY ./plugin ./plugin WORKDIR /src/plugin ENV CGO_ENABLED=1 GOOS=linux GOARCH=amd64 RUN go build -buildmode=c-shared -trimpath -o my_plugin.so . # ---------- Runtime ---------- FROM devopsfaith/krakend:2.6.5-alpine AS runtime WORKDIR /etc/krakend # 設定ファイルとプラグインを配置 COPY ./krakend.json ./ COPY --from=builder /src/plugin/my_plugin.so /opt/plugins/ ENV KRAKEND_PLUGIN_PATH=/opt/plugins EXPOSE 8080 ENTRYPOINT ["krakend", "run", "-c", "/etc/krakend/krakend.json"] |
ビルドは次のコマンドで完了します。
|
1 2 |
docker build -t myorg/krakend-custom:latest . |
KrakenD 設定へのプラグイン登録とエラー設計
プラグインを有効化するには krakend.json に plugin セクションを追加し、必要に応じてカスタムエラー型を実装します。
krakend.json の plugin 設定例
環境変数でパスを外部化すれば、ステージごとに異なるプラグインバイナリを差し替えることができます。以下は基本的な設定例です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
{ "version": 3, "plugin": { "folder": "/opt/plugins", "pattern": "${KRAKEND_PLUGIN_PATH}/*.so" }, "endpoints": [ { "endpoint": "/api/v1/users", "method": "GET", "backend": [ { "url_pattern": "/users", "host": ["http://user-service:8080"] } ], "extra_config": { "github.com/devopsfaith/krakend-middleware/plugin": { "name": "my_middleware" } } } ] } |
KRAKEND_PLUGIN_PATH は Dockerfile の ENV や Kubernetes の ConfigMap で設定できます。
環境変数でのパス動的設定
Docker と Kubernetes の両方で同一 krakend.json を使う場合は、コンテナ起動時に環境変数だけを書き換えるだけです。KrakenD は指定ディレクトリ内の .so ファイルを自動的にロードします。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
apiVersion: apps/v1 kind: Deployment metadata: name: krakend-gateway spec: replicas: 2 template: spec: containers: - name: krakend image: myorg/krakend-custom:latest env: - name: KRAKEND_PLUGIN_PATH value: "/opt/plugins" volumeMounts: - name: plugins mountPath: /opt/plugins volumes: - name: plugins configMap: name: krakend-plugins-cm # ConfigMap に .so バイナリを格納 |
この方式ならプラグインのバージョンアップや A/B テスト時に ConfigMap の内容だけ差し替えれば済みます。
カスタムエラー型の実装例
KrakenD は error インターフェースに加えて、StatusCode() int メソッドが定義されていると自動的に HTTP ステータスコードへ変換します。以下はシンプルなカスタムエラー構造体です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package errors import "fmt" type APIError struct { Code string // アプリケーション固有のエラーコード Message string // クライアント向けメッセージ HTTP int // 返すステータスコード } // Error implements the built‑in error interface. func (e *APIError) Error() string { return fmt.Sprintf("%s: %s", e.Code, e.Message) } // StatusCode は KrakenD が呼び出すメソッドで、HTTP コードにマッピングされる。 func (e *APIError) StatusCode() int { return e.HTTP } |
プラグイン内でエラーを返す例:
|
1 2 3 4 5 6 7 8 |
if err != nil { return &errors.APIError{ Code: "USER_NOT_FOUND", Message: "対象ユーザーが存在しません。", HTTP: 404, } } |
このパターンに従うと、エラーハンドリングが一元化され、テストもしやすくなります。
テスト戦略と CI/CD パイプライン
品質保証は ユニットテスト → 統合テスト → 自動デプロイ の流れで構築します。以下に具体的な実装例を示します。
ユニットテストの書き方(testing + gomock)
Init が正しくハンドラをラップできているかを検証するテストです。外部依存はモック化して高速に実行できます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
func TestInit_AddTraceID(t *testing.T) { ctx := context.Background() cfg := map[string]interface{}{} // プラグイン初期化 factory, err := Init(ctx, cfg) if err != nil { t.Fatalf("Init failed: %v", err) } // モックハンドラ called := false mockHandler := router.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { called = true if r.Header.Get("X-Trace-ID") == "" { t.Error("X-Trace-ID not set") } }) // ラップして実行 wrapped := factory(mockHandler) rr := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/", nil) wrapped.ServeHTTP(rr, req) if !called { t.Error("underlying handler was not called") } } |
go test ./... -cover でカバレッジを測定し、最低 80 % を目標にすると CI の信頼性が向上します。
Docker Compose での統合テスト
プラグインが実際にロードされ、エンドポイントが期待通りに動作するかを検証します。docker-compose.yml に KrakenD とモックバックエンドを定義し、スクリプトでリクエストを送ります。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
version: "3.8" services: krakend: image: myorg/krakend-custom:test ports: - "8080:8080" environment: KRAKEND_PLUGIN_PATH: /opt/plugins user-service-mock: image: stoplight/prism:4 command: mock -d ./mock/openapi.yaml ports: - "9090:4010" |
テストスクリプト(ci/integration_test.sh):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#!/usr/bin/env bash set -euo pipefail docker compose up -d # コンテナ起動待ち (簡易的に sleep) sleep 5 status=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/api/v1/users) if [ "$status" -ne 200 ]; then echo "Integration test failed (HTTP $status)" docker compose logs krakend exit 1 fi docker compose down echo "✅ Integration test passed" |
CI ジョブ内でこのスクリプトを実行すれば、プラグインのロード失敗や設定ミスを早期に検出できます。
GitHub Actions ワークフロー例
以下は テスト → Docker ビルド → イメージプッシュ → Helm デプロイ までを自動化した ci.yml の抜粋です。キャッシュとマトリクスを活用し、ビルド時間を最適化します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
name: CI/CD Pipeline on: push: branches: [ main ] pull_request: branches: [ main ] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Go uses: actions/setup-go@v5 with: go-version: '1.22' - name: Cache Go modules uses: actions/cache@v3 with: path: | ~/.cache/go-build ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('go.sum') }} - name: Run unit tests run: go test ./... -cover build-image: needs: test runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push Docker image uses: docker/build-push-action@v5 with: context: . file: Dockerfile push: true tags: | ghcr.io/${{ github.repository }}/krakend:${{ github.sha }} ghcr.io/${{ github.repository }}/krakend:latest helm-deploy: needs: build-image runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Helm run: | curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash - name: Deploy to Kubernetes env: KUBECONFIG: ${{ secrets.KUBE_CONFIG }} run: | helm upgrade --install krakend ./chart \ --set image.repository=ghcr.io/${{ github.repository }}/krakend \ --set image.tag=${{ github.sha }} \ --namespace production |
このフローにより、コード変更から本番デプロイまで 数分 で完了し、手作業によるミスを大幅に削減できます。
Helm デプロイとタグ戦略
OCI レジストリには latest とバージョン番号(例: v1.0.0)の二重タグを付与します。Helm の values.yaml で画像情報をパラメータ化すれば、ロールバックやステージング環境への差し替えが容易です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# values.yaml replicaCount: 2 image: repository: ghcr.io/yourorg/krakend tag: "latest" # CI が上書き pullPolicy: IfNotPresent pluginPath: "/opt/plugins" env: - name: KRAKEND_PLUGIN_PATH value: "{{ .Values.pluginPath }}" service: type: ClusterIP port: 80 |
ステージングにデプロイする際は --set image.tag=v1.2.3 と指定すれば、特定リビジョンのイメージだけを切り替えられます。
記事全体のまとめ
- プラグインタイプ:Middleware・Request/Response Modifier・Backend Proxy の三種が公式サポート。v2.6 以降は環境変数で動的ロード可能。
- Go 環境:Go 1.22 系を使用し、
go.modで KrakenD 本体と同一バージョンを明示することがビルド成功の鍵。 - ビルド手順:
go build -buildmode=c-sharedにより.soを生成し、マルチステージ Docker で軽量イメージ化。 - 設定とエラー設計:
krakend.jsonのpluginセクションに環境変数パスを記述し、カスタムエラーはStatusCode()を実装して HTTP コードへマッピング。 - テスト・CI/CD:Go ユニットテスト+Docker Compose 統合テストでプラグインロードを検証し、GitHub Actions と Helm で自動ビルド・デプロイを一貫化。
- デプロイ戦略:OCI タグ付けと Helm のパラメータ化により、バージョン管理とロールバックがシンプルになる。
上記の手順とベストプラクティスを踏めば、最新の KrakenD(v2.6 以降)向けカスタムプラグインを 安全・高速・自動 に開発・デプロイできるようになります。