Summary

Our demo Card application deployed as here in has OpenAPI yaml. Such specs should be published (https://deck-api.api.kambur.ie/shuffledDeck.yaml) and for convenience, easily testable using Swagger UI (https://deck-api.api.kambur.ie/swagger-ui.html).

We want to avoid exposing OpenAPI yaml from our application container as static content, generally, should be exposed separate from API. We will also want to keep in mind that this yaml file we will use later for validation using APISIX oas-validation plugin. Similarly, we want to keep Swagger UI separate from APIs like we did with yaml file.

Expose static files

Controversially, we will put both Swagger yaml and the files to K8s ConfigMap as they are small and attach to a sidecar container of our ramblings-api container, running NGINX. These files aren’t terribly large. In a hindsight, it would have been easier to have a separate container running NGINX but anyway…

Sidecar below but also requires changes to service also to expose port 80.

        - name: api-docs-sidecar
          image: nginx:latest
          ports:
            - containerPort: 80
              name: http
          volumeMounts:
            - name: api-docs
              mountPath: /usr/share/nginx/html
              readOnly: true
          resources:
            requests:
              memory: "32Mi"
              cpu: "10m"
            limits:
              memory: "64Mi"
          readinessProbe:
            httpGet:
              path: /health
              port: 80
            initialDelaySeconds: 5
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /health
              port: 80
            initialDelaySeconds: 10
            periodSeconds: 10
      volumes:
        - name: api-docs
          configMap:
            name: api-docs

---
apiVersion: v1
kind: Service
metadata:
  name: ramblings-app
  namespace: ramblings
spec:
  type: NodePort
  selector:
    app: ramblings-app
  ports:
    - name: http
      protocol: TCP
      port: 8080
      targetPort: 8080
    - name: api-docs
      protocol: TCP
      port: 80
      targetPort: 80

Then, small change to the build pipeline to make sure ConfigMap is created:

      - name: Deploy to Kubernetes
        run: |
          export IMAGE_TAG IMAGE_NAME
          # Generate ConfigMap from source files
          kubectl create configmap api-docs \
            --from-file=shuffledDeck.yaml=src/main/resources/swagger/api-docs/shuffledDeck.yaml \
            --from-file=swagger-ui.html=src/main/resources/swagger/api-docs/swagger-ui.html \
            --from-file=health=src/main/resources/swagger/health \
            -n ramblings \
            --dry-run=client -o yaml | kubectl apply -f -
          # Apply deployment with envsubst
          envsubst < kubernetes/k8s-deployment.yaml | kubectl apply -f -

AI will quickly generate Swagger HTML - minor tweaks of paths have been needed.

Deploy.

Fix up the upstream

Changing the name of the service to http will break the upsteam which now needs be fixed:

curl -sS -X PUT \
  -H "X-API-KEY: ${APISIX_ADMIN_KEY}" \
  -H 'Content-Type: application/json' \
  'http://127.0.0.1:9180/apisix/admin/upstreams/1' \
  --data '{
    "id": "1",
    "type": "roundrobin",
    "discovery_type": "kubernetes",
    "service_name": "ramblings/ramblings-app:http",
    "pass_host": "rewrite",
    "upstream_host": "ramblings-app.ramblings.svc.cluster.local"
  }'
curl -sS -X PUT \
  -H "X-API-KEY: ${APISIX_ADMIN_KEY}" \
  -H 'Content-Type: application/json' \
  'http://127.0.0.1:9180/apisix/admin/routes/api-docs-html' \
  --data '{
    "id": "api-docs-html",
    "uri": "/swagger-ui.html",
    "upstream": {
      "type": "roundrobin",
      "scheme": "http",
      "pass_host": "pass",
      "nodes": {
        "shuffled-deck-docs.ramblings.svc.cluster.local:80": 1
      }
    }
  }' 
curl -sS -X PUT \
  -H "X-API-KEY: ${APISIX_ADMIN_KEY}" \
  -H 'Content-Type: application/json' \
  'http://127.0.0.1:9180/apisix/admin/routes/api-docs-yaml' \
  --data '{
    "id": "api-docs-yaml",
    "uri": "/shuffledDeck.yaml",
    "upstream": {
      "type": "roundrobin",
      "scheme": "http",
      "pass_host": "pass",
      "nodes": {
        "shuffled-deck-docs.ramblings.svc.cluster.local:80": 1
      }
    }
  }'

Resulting links

https://deck-api.api.kambur.ie/swagger-ui.html https://deck-api.api.kambur.ie/shuffledDeck.yaml