Compare commits

...

14 Commits

Author SHA1 Message Date
Yuxing Deng
b9fb6a705b fix: the usage is not compatible with old version 2024-11-25 09:44:23 +08:00
Yuxing Deng
4f18ac4ae8 feat(ui): bump ui version to v2.9.2 2024-09-27 17:37:50 +08:00
Yuxing Deng
faee269cc1 feat(deps): bump golang & steve version 2024-09-27 17:37:50 +08:00
Yuxing Deng
9ce631d30f fix: use local version package 2024-09-26 10:29:40 +08:00
Yuxing Deng
2d512c0a72 fix: version is not parsed into build info 2024-09-26 09:49:16 +08:00
Yuxing Deng
5c987cd193 fix: Bump steve to fix the crd issue 2024-08-07 09:08:22 +08:00
Yuxing Deng
85925bbac7 fix: no need to new workflow file for release branch 2024-07-30 10:34:57 +08:00
Yuxing Deng
f435a24814 fix: Rename release branch ci name 2024-07-30 10:32:06 +08:00
Yuxing Deng
fb1f38e1ef feat: Add release branch ci 2024-07-30 10:31:00 +08:00
Yuxing Deng
67923822f5 fix: Container doesn't stop with signal 2024-07-29 17:24:10 +08:00
Yuxing Deng
1540341550 docs: Add docs for path prefix deploy example 2024-07-29 15:07:34 +08:00
Yuxing Deng
a5e53f2b17 feat: Support for nginx ingress path prefix
And validate should failed if git tree is dirty
2024-07-29 15:07:34 +08:00
Yuxing Deng
8f069c3b38 feat: Full support for proxy deploy
The index page will be handled correctly if the `XFF` and `X-API-URL-PREFIX` are set properly.
2024-07-25 17:32:01 +08:00
Yuxing Deng
568eda3e52 fix: Index content-type missing problem 2024-07-25 17:32:01 +08:00
18 changed files with 261 additions and 19 deletions

View File

@@ -3,6 +3,7 @@ name: Push to Master
on:
push:
branches:
- release/v*
- main
tags:
- 'v*.*.*' # Matches any tag that starts with 'v' and follows semantic versioning
@@ -50,6 +51,7 @@ jobs:
IMAGE_OVERRIDE: ${{ vars.IMAGE || 'kube-explorer' }}
run: |
tag_name=latest;
if [[ ${GITHUB_REF} == refs/heads/release/* ]]; then tag_name=${GITHUB_REF#refs/heads/release/}-head; fi;
if [[ ${GITHUB_REF} == refs/tags/* ]]; then tag_name=${GITHUB_REF#refs/tags/}; fi;
echo "image_name=${REPO_OVERRIDE}/${IMAGE_OVERRIDE}:${tag_name}" >> $GITHUB_OUTPUT;
-

View File

@@ -1,6 +1,6 @@
FROM aevea/release-notary:0.9.2 as tools
FROM registry.suse.com/bci/golang:1.22
FROM registry.suse.com/bci/golang:1.23
ARG PROXY
ARG GOPROXY
ARG DAPPER_HOST_ARCH
@@ -16,13 +16,13 @@ RUN curl -sL https://github.com/upx/upx/releases/download/v${UPX_VERSION}/upx-${
mv /tmp/upx /usr/bin/
RUN if [ "${ARCH}" == "amd64" ]; then \
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.54.2; \
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.61.0; \
fi
COPY --from=tools /app/release-notary /usr/local/bin/
ENV CATTLE_DASHBOARD_UI_VERSION="v2.8.0-kube-explorer-ui-rc3"
ENV CATTLE_DASHBOARD_UI_VERSION="v2.9.2-kube-explorer-ui-rc1"
ENV CATTLE_API_UI_VERSION="1.1.11"
ENV DAPPER_ENV REPO TAG DRONE_TAG CROSS GOPROXY SKIP_COMPRESS GITHUB_REPOSITORY GITHUB_TOKEN
ENV DAPPER_ENV REPO TAG DRONE_TAG CROSS GOPROXY SKIP_COMPRESS GITHUB_REPOSITORY GITHUB_TOKEN GITHUB_REF
ENV DAPPER_SOURCE /go/src/github.com/cnrancher/kube-explorer
ENV DAPPER_OUTPUT ./bin ./dist
ENV DAPPER_DOCKER_SOCKET true

View File

@@ -0,0 +1,34 @@
# Deploy kube-explorer behind proxy with path prefix
> Supported since v0.5.0
The kube-explorer dashboard can be exposed behind a proxy and path prefix like `http://your-domain.com/kube-explorer`.
The deployment examples in this folder are:
- `nginx ingress`
- `traefik ingress`
## Serve with ingress
When serving with nginx/traefik ingress controller, the template ingress file needs to be modified. In the `*.tpl` file, you can spot the missing hostname like:
```yaml
spec:
rules:
- host: "${MY_IP}.sslip.io" # Replace with your actual domain
```
Replace your ip to `${MY_UP}`, this will use the [sslip.io](https://sslip.io/) dns service to resolve the hostname to the ingress ip address.
For the traefik ingress, it is using `v2` version of the traefik ingress schema which use middlewares to modify the proxy request. Both `stripPrefix` and `headers` are used.
For the nginx ingress, the annotations `nginx.ingress.kubernetes.io/x-forwarded-prefix` and `nginx.ingress.kubernetes.io/rewrite-target` are used to strip prefix and to add proxy request header.
## Serve with self-hosted proxy
If serving the kube-explorer with self-hosted proxy, following modifications are required when proxying:
- Rewrite the proxy request to strip the path prefix like `rewrite "(?i)/kube-explorer(/|$)(.*)" /$2 break;` in nginx configuration.
- Add header `X-API-URL-Prefix` or `X-Forwarded-Prefix` with the path prefix when proxying request like `proxy_set_header X-Forwarded-Prefix "/kube-explorer";` in nginx configuration.
Then kube-explorer will response the index.html with modified content with path prefix to the browser.

View File

@@ -0,0 +1,24 @@
# Note: please replace the host first
# To use sslip.io: https://sslip.io/
# To get your public IP: curl ipinfo.io/ip
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/x-forwarded-prefix: "/kube-explorer"
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: kube-explorer-ingress
namespace: kube-system
spec:
rules:
- host: "${MY_IP}.sslip.io" # Replace with your actual domain
http:
paths:
- backend:
service:
name: kube-explorer
port:
name: http
path: /kube-explorer(/|$)(.*)
pathType: ImplementationSpecific

View File

@@ -0,0 +1,42 @@
# Note: please replace the host first
# To use sslip.io: https://sslip.io/
# To get your public IP: curl ipinfo.io/ip
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kube-explorer-ingress
namespace: kube-system
annotations:
traefik.ingress.kubernetes.io/router.middlewares: kube-system-prefix@kubernetescrd,kube-system-add-header@kubernetescrd
spec:
rules:
- host: "${MY_IP}.sslip.io" # Replace with your actual domain
http:
paths:
- path: /kube-explorer
pathType: Prefix
backend:
service:
name: kube-explorer
port:
name: http
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: prefix
namespace: kube-system
spec:
stripPrefix:
prefixes:
- /kube-explorer
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: add-header
namespace: kube-system
spec:
headers:
customRequestHeaders:
X-Forwarded-Prefix: "/kube-explorer" # Adds

2
go.mod
View File

@@ -7,7 +7,7 @@ replace k8s.io/client-go => k8s.io/client-go v0.30.1
require (
github.com/gorilla/mux v1.8.1
github.com/rancher/apiserver v0.0.0-20240708202538-39a6f2535146
github.com/rancher/steve v0.0.0-20240709130809-47871606146c
github.com/rancher/steve v0.0.0-20240911190153-79304d93b49b
github.com/rancher/wrangler/v3 v3.0.0
github.com/sirupsen/logrus v1.9.3
github.com/urfave/cli v1.22.15

4
go.sum
View File

@@ -1029,8 +1029,8 @@ github.com/rancher/norman v0.0.0-20240708202514-a0127673d1b9 h1:AlRMRs5mHJcdiK83
github.com/rancher/norman v0.0.0-20240708202514-a0127673d1b9/go.mod h1:dyjfXBsNiroPWOdUZe7diUOUSLf6HQ/r2kEpwH/8zas=
github.com/rancher/remotedialer v0.3.2 h1:kstZbRwPS5gPWpGg8VjEHT2poHtArs+Fc317YM8JCzU=
github.com/rancher/remotedialer v0.3.2/go.mod h1:Ys004RpJuTLSm+k4aYUCoFiOOad37ubYev3TkOFg/5w=
github.com/rancher/steve v0.0.0-20240709130809-47871606146c h1:PIaN0/KUyGcqEcT6GyjUidld2lgGkGxS4dmC3Je3dFs=
github.com/rancher/steve v0.0.0-20240709130809-47871606146c/go.mod h1:Za4nSt0V6kIHRfUo6jTXKkv6ABMMCHINA8EzhzygCfk=
github.com/rancher/steve v0.0.0-20240911190153-79304d93b49b h1:2DhkNKDgKPI2PcJRGacpJ9dX9SWgKuhwbz5GlpHS1No=
github.com/rancher/steve v0.0.0-20240911190153-79304d93b49b/go.mod h1:cXF0TFURkjN98p/0nt7Y8F1IEtT1nZTSYrQu6HQqL14=
github.com/rancher/wrangler/v3 v3.0.0 h1:IHHCA+vrghJDPxjtLk4fmeSCFhNe9fFzLFj3m2B0YpA=
github.com/rancher/wrangler/v3 v3.0.0/go.mod h1:Dfckuuq7MJk2JWVBDywRlZXMxEyPxHy4XqGrPEzu5Eg=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=

View File

@@ -7,7 +7,6 @@ import (
var InsecureSkipTLSVerify bool
var SystemDefaultRegistry string
var APIUIVersion = "1.1.11"
var ShellPodImage string
func Flags() []cli.Flag {

View File

@@ -6,6 +6,7 @@ import (
"strings"
"github.com/rancher/apiserver/pkg/types"
"github.com/rancher/apiserver/pkg/urlbuilder"
steveauth "github.com/rancher/steve/pkg/auth"
"github.com/rancher/steve/pkg/schema"
"github.com/rancher/steve/pkg/server"
@@ -61,7 +62,11 @@ func ToServer(ctx context.Context, c *cli.Config, sqlCache bool) (*server.Server
SQLCache: sqlCache,
// router needs to hack here
Router: func(h router.Handlers) http.Handler {
return rewriteLocalCluster(router.Routes(h))
return handleProxyHeader(
rewriteLocalCluster(
router.Routes(h),
),
)
},
})
if err != nil {
@@ -99,3 +104,12 @@ func rewriteLocalCluster(next http.Handler) http.Handler {
next.ServeHTTP(rw, req)
})
}
func handleProxyHeader(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
if value := req.Header.Get("X-Forwarded-Prefix"); value != "" {
req.Header.Set(urlbuilder.PrefixHeader, value)
}
next.ServeHTTP(rw, req)
})
}

View File

@@ -132,7 +132,6 @@ func (h *Handler) IndexFile() http.Handler {
http.NotFoundHandler().ServeHTTP(w, r)
return
}
w.WriteHeader(http.StatusOK)
_, _ = w.Write(rtn)
}))
}

116
internal/ui/proxy.go Normal file
View File

@@ -0,0 +1,116 @@
package ui
import (
"bufio"
"bytes"
"fmt"
"io"
"net"
"net/http"
"strconv"
"github.com/rancher/apiserver/pkg/urlbuilder"
"k8s.io/apimachinery/pkg/util/proxy"
)
type RoundTripFunc func(*http.Request) (*http.Response, error)
func (r RoundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
return r(req)
}
func proxyMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
scheme := urlbuilder.GetScheme(r)
host := urlbuilder.GetHost(r, scheme)
pathPrepend := r.Header.Get(urlbuilder.PrefixHeader)
if scheme == r.URL.Scheme && host == r.URL.Host && pathPrepend == "" {
next.ServeHTTP(w, r)
return
}
proxyRoundtrip := proxy.Transport{
Scheme: scheme,
Host: host,
PathPrepend: pathPrepend,
RoundTripper: RoundTripFunc(func(r *http.Request) (*http.Response, error) {
rw := &dummyResponseWriter{
next: w,
header: make(http.Header),
}
next.ServeHTTP(rw, r)
return rw.getResponse(r), nil
}),
}
//proxyRoundtripper will write the response in RoundTrip func
resp, _ := proxyRoundtrip.RoundTrip(r)
responseToWriter(resp, w)
})
}
var _ http.ResponseWriter = &dummyResponseWriter{}
var _ http.Hijacker = &dummyResponseWriter{}
type dummyResponseWriter struct {
next http.ResponseWriter
header http.Header
body bytes.Buffer
statusCode int
}
// Hijack implements http.Hijacker.
func (drw *dummyResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
if h, ok := drw.next.(http.Hijacker); ok {
return h.Hijack()
}
return nil, nil, fmt.Errorf("")
}
// Header implements the http.ResponseWriter interface.
func (drw *dummyResponseWriter) Header() http.Header {
return drw.header
}
// Write implements the http.ResponseWriter interface.
func (drw *dummyResponseWriter) Write(b []byte) (int, error) {
return drw.body.Write(b)
}
// WriteHeader implements the http.ResponseWriter interface.
func (drw *dummyResponseWriter) WriteHeader(statusCode int) {
drw.statusCode = statusCode
}
// GetStatusCode returns the status code written to the response.
func (drw *dummyResponseWriter) GetStatusCode() int {
if drw.statusCode == 0 {
return 200
}
return drw.statusCode
}
func (drw *dummyResponseWriter) getResponse(req *http.Request) *http.Response {
return &http.Response{
Status: strconv.Itoa(drw.GetStatusCode()),
StatusCode: drw.GetStatusCode(),
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
Request: req,
Header: drw.header,
Body: io.NopCloser(&drw.body),
}
}
func responseToWriter(resp *http.Response, writer http.ResponseWriter) {
for k, v := range resp.Header {
writer.Header()[k] = v
}
if resp.StatusCode != http.StatusOK {
writer.WriteHeader(resp.StatusCode)
}
_, _ = io.Copy(writer, resp.Body)
}

View File

@@ -27,5 +27,5 @@ func New(opt *Options) (http.Handler, APIUI) {
http.Redirect(rw, req, url, http.StatusFound)
})
return router, apiUI(opt)
return proxyMiddleware(router), apiUI(opt)
}

View File

@@ -3,9 +3,9 @@ package main
import (
"os"
"github.com/cnrancher/kube-explorer/internal/version"
"github.com/rancher/steve/pkg/debug"
stevecli "github.com/rancher/steve/pkg/server/cli"
"github.com/rancher/steve/pkg/version"
"github.com/rancher/wrangler/v3/pkg/signals"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"

View File

@@ -1,7 +1,7 @@
FROM registry.suse.com/bci/bci-minimal:15.6
FROM registry.suse.com/bci/bci-base:15.6
ARG TARGETARCH
ARG TARGETOS
ENV ARCH=${TARGETARCH:-"amd64"} OS=${TARGETOS:-"linux"}
COPY entrypoint.sh /usr/bin/
RUN zypper install -y catatonit
COPY kube-explorer-${OS}-${ARCH} /usr/bin/kube-explorer
ENTRYPOINT ["entrypoint.sh"]
ENTRYPOINT [ "/usr/bin/catatonit", "--", "kube-explorer" ]

View File

@@ -1,3 +0,0 @@
#!/bin/sh
kube-explorer "${@}"

View File

@@ -14,7 +14,7 @@ rm -rf internal/ui/ui/*
mkdir -p internal/ui/ui/dashboard
cd internal/ui/ui/dashboard || exit 1;
curl -sL https://pandaria-dashboard-ui.s3.ap-southeast-2.amazonaws.com/release-2.8-cn/kube-explorer-ui/${CATTLE_DASHBOARD_UI_VERSION}.tar.gz | $TAR_CMD xvzf - --strip-components=2
curl -sL https://pandaria-dashboard-ui.s3.ap-southeast-2.amazonaws.com/release-2.9-cn/kube-explorer-ui/${CATTLE_DASHBOARD_UI_VERSION}.tar.gz | $TAR_CMD xvzf - --strip-components=2
cp index.html ../index.html
mkdir ../api-ui

View File

@@ -18,3 +18,14 @@ go mod tidy
echo Verifying modules
go mod verify
dirty_files="$(git status --porcelain --untracked-files=no)"
if [ -n "$dirty_files" ]; then
echo "Encountered dirty repo! Aborting."
echo "If you're seeing this, it means there are uncommitted changes in the repo."
echo "If you're seeing this in CI, it probably means that your Go modules aren't tidy, or more generally that running"
echo "validation would result in changes to the repo. Make sure you're up to date with the upstream branch and run"
echo "'go mod tidy' and commit the changes, if any. The offending changed files are as follows:"
echo "$dirty_files"
exit 1
fi

View File

@@ -1,5 +1,9 @@
#!/bin/bash
if [[ ${GITHUB_REF} == refs/tags/* ]]; then
DRONE_TAG=${DRONE_TAG:-${GITHUB_REF#refs/tags/}}
fi
if [ -n "$(git status --porcelain --untracked-files=no)" ]; then
DIRTY="-dirty"
fi