Add debug tool to image
This commit is contained in:
parent
5c4854b537
commit
9534f8bc43
7 changed files with 412 additions and 1 deletions
2
Makefile
2
Makefile
|
@ -105,7 +105,7 @@ container: clean-container .container-$(ARCH)
|
|||
@echo "+ Copying artifact to temporary directory"
|
||||
mkdir -p $(TEMP_DIR)/rootfs
|
||||
cp bin/$(ARCH)/nginx-ingress-controller $(TEMP_DIR)/rootfs/nginx-ingress-controller
|
||||
|
||||
cp bin/$(ARCH)/dbg $(TEMP_DIR)/rootfs/dbg
|
||||
@echo "+ Building container image $(MULTI_ARCH_IMG):$(TAG)"
|
||||
cp -RP ./* $(TEMP_DIR)
|
||||
$(SED_I) "s|BASEIMAGE|$(BASEIMAGE)|g" $(DOCKERFILE)
|
||||
|
|
|
@ -48,3 +48,11 @@ go build \
|
|||
-X ${PKG}/version.COMMIT=${GIT_COMMIT} \
|
||||
-X ${PKG}/version.REPO=${REPO_INFO}" \
|
||||
-o bin/${ARCH}/nginx-ingress-controller ${PKG}/cmd/nginx
|
||||
|
||||
go build \
|
||||
${GOBUILD_FLAGS} \
|
||||
-ldflags "-s -w \
|
||||
-X ${PKG}/version.RELEASE=${TAG} \
|
||||
-X ${PKG}/version.COMMIT=${GIT_COMMIT} \
|
||||
-X ${PKG}/version.REPO=${REPO_INFO}" \
|
||||
-o bin/${ARCH}/dbg ${PKG}/cmd/dbg
|
||||
|
|
203
cmd/dbg/main.go
Normal file
203
cmd/dbg/main.go
Normal file
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/ingress-nginx/internal/nginx"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
backendsPath = "/configuration/backends"
|
||||
generalPath = "/configuration/general"
|
||||
)
|
||||
|
||||
func main() {
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "dbg",
|
||||
Short: "dbg is a tool for quickly inspecting the state of the nginx instance",
|
||||
}
|
||||
|
||||
backendsCmd := &cobra.Command{
|
||||
Use: "backends",
|
||||
Short: "Inspect the dynamically-loaded backends information",
|
||||
}
|
||||
rootCmd.AddCommand(backendsCmd)
|
||||
|
||||
backendsAllCmd := &cobra.Command{
|
||||
Use: "all",
|
||||
Short: "Output the all dynamic backend information as a JSON array",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
backendsAll()
|
||||
},
|
||||
}
|
||||
backendsCmd.AddCommand(backendsAllCmd)
|
||||
|
||||
backendsListCmd := &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "Output a newline-separated list of the backend names",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
backendsList()
|
||||
},
|
||||
}
|
||||
backendsCmd.AddCommand(backendsListCmd)
|
||||
|
||||
backendsGetCmd := &cobra.Command{
|
||||
Use: "get [backend name]",
|
||||
Short: "Output the backend information only for the backend that has this name",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
backendsGet(args[0])
|
||||
},
|
||||
}
|
||||
backendsCmd.AddCommand(backendsGetCmd)
|
||||
|
||||
generalCmd := &cobra.Command{
|
||||
Use: "general",
|
||||
Short: "Output the general dynamic lua state",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
general()
|
||||
},
|
||||
}
|
||||
rootCmd.AddCommand(generalCmd)
|
||||
|
||||
confCmd := &cobra.Command{
|
||||
Use: "conf",
|
||||
Short: "Dump the contents of /etc/nginx/nginx.conf",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
readNginxConf()
|
||||
},
|
||||
}
|
||||
rootCmd.AddCommand(confCmd)
|
||||
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func backendsAll() {
|
||||
statusCode, body, requestErr := nginx.NewGetStatusRequest(backendsPath)
|
||||
if requestErr != nil {
|
||||
fmt.Println(requestErr)
|
||||
return
|
||||
}
|
||||
if statusCode != 200 {
|
||||
fmt.Printf("Nginx returned code %v", statusCode)
|
||||
return
|
||||
}
|
||||
|
||||
var prettyBuffer bytes.Buffer
|
||||
indentErr := json.Indent(&prettyBuffer, body, "", " ")
|
||||
if indentErr != nil {
|
||||
fmt.Println(indentErr)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(prettyBuffer.Bytes()))
|
||||
}
|
||||
|
||||
func backendsList() {
|
||||
statusCode, body, requestErr := nginx.NewGetStatusRequest(backendsPath)
|
||||
if requestErr != nil {
|
||||
fmt.Println(requestErr)
|
||||
return
|
||||
}
|
||||
if statusCode != 200 {
|
||||
fmt.Printf("Nginx returned code %v", statusCode)
|
||||
return
|
||||
}
|
||||
|
||||
var f interface{}
|
||||
unmarshalErr := json.Unmarshal(body, &f)
|
||||
if unmarshalErr != nil {
|
||||
fmt.Println(unmarshalErr)
|
||||
return
|
||||
}
|
||||
backends := f.([]interface{})
|
||||
|
||||
for _, backendi := range backends {
|
||||
backend := backendi.(map[string]interface{})
|
||||
fmt.Println(backend["name"].(string))
|
||||
}
|
||||
}
|
||||
|
||||
func backendsGet(name string) {
|
||||
statusCode, body, requestErr := nginx.NewGetStatusRequest(backendsPath)
|
||||
if requestErr != nil {
|
||||
fmt.Println(requestErr)
|
||||
return
|
||||
}
|
||||
if statusCode != 200 {
|
||||
fmt.Printf("Nginx returned code %v", statusCode)
|
||||
return
|
||||
}
|
||||
|
||||
var f interface{}
|
||||
unmarshalErr := json.Unmarshal(body, &f)
|
||||
if unmarshalErr != nil {
|
||||
fmt.Println(unmarshalErr)
|
||||
return
|
||||
}
|
||||
backends := f.([]interface{})
|
||||
|
||||
for _, backendi := range backends {
|
||||
backend := backendi.(map[string]interface{})
|
||||
if backend["name"].(string) == name {
|
||||
printed, _ := json.MarshalIndent(backend, "", " ")
|
||||
fmt.Println(string(printed))
|
||||
return
|
||||
}
|
||||
}
|
||||
fmt.Println("A backend of this name was not found.")
|
||||
}
|
||||
|
||||
func general() {
|
||||
statusCode, body, requestErr := nginx.NewGetStatusRequest(generalPath)
|
||||
if requestErr != nil {
|
||||
fmt.Println(requestErr)
|
||||
return
|
||||
}
|
||||
if statusCode != 200 {
|
||||
fmt.Printf("Nginx returned code %v", statusCode)
|
||||
return
|
||||
}
|
||||
|
||||
var prettyBuffer bytes.Buffer
|
||||
indentErr := json.Indent(&prettyBuffer, body, "", " ")
|
||||
if indentErr != nil {
|
||||
fmt.Println(indentErr)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(prettyBuffer.Bytes()))
|
||||
}
|
||||
|
||||
func readNginxConf() {
|
||||
conf, err := nginx.ReadNginxConf()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(conf)
|
||||
}
|
|
@ -93,6 +93,87 @@ kube-system kube-dns ClusterIP 10.96.0.10 <none>
|
|||
kube-system kubernetes-dashboard NodePort 10.103.128.17 <none> 80:30000/TCP 30m
|
||||
```
|
||||
|
||||
Use the `/dbg` Tool to Check Dynamic Configuration
|
||||
|
||||
```console
|
||||
$ kubectl exec -n <namespace-of-ingress-controller> nginx-ingress-controller-67956bf89d-fv58j /dbg
|
||||
dbg is a tool for quickly inspecting the state of the nginx instance
|
||||
|
||||
Usage:
|
||||
dbg [command]
|
||||
|
||||
Available Commands:
|
||||
backends Inspect the dynamically-loaded backends information
|
||||
conf Dump the contents of /etc/nginx/nginx.conf
|
||||
general Output the general dynamic lua state
|
||||
help Help about any command
|
||||
|
||||
Flags:
|
||||
-h, --help help for dbg
|
||||
|
||||
Use "dbg [command] --help" for more information about a command.
|
||||
|
||||
```
|
||||
|
||||
```console
|
||||
$ kubectl exec -n <namespace-of-ingress-controller> nginx-ingress-controller-67956bf89d-fv58j /dbg backends
|
||||
Inspect the dynamically-loaded backends information.
|
||||
|
||||
Usage:
|
||||
dbg backends [command]
|
||||
|
||||
Available Commands:
|
||||
all Output the all dynamic backend information as a JSON array
|
||||
get Output the backend information only for the backend that has this name
|
||||
list Output a newline-separated list of the backend names
|
||||
|
||||
Flags:
|
||||
-h, --help help for backends
|
||||
|
||||
Use "dbg backends [command] --help" for more information about a command.
|
||||
```
|
||||
|
||||
```console
|
||||
$ kubectl exec -n <namespace-of-ingress-controller> nginx-ingress-controller-67956bf89d-fv58j /dbg backends list
|
||||
coffee-svc-80
|
||||
tea-svc-80
|
||||
upstream-default-backend
|
||||
```
|
||||
|
||||
```console
|
||||
$ kubectl exec -n <namespace-of-ingress-controller> nginx-ingress-controller-67956bf89d-fv58j /dbg backends get coffee-svc-80
|
||||
{
|
||||
"endpoints": [
|
||||
{
|
||||
"address": "10.1.1.112",
|
||||
"port": "8080"
|
||||
},
|
||||
{
|
||||
"address": "10.1.1.119",
|
||||
"port": "8080"
|
||||
},
|
||||
{
|
||||
"address": "10.1.1.121",
|
||||
"port": "8080"
|
||||
}
|
||||
],
|
||||
"load-balance": "ewma",
|
||||
"name": "coffee-svc-80",
|
||||
"noServer": false,
|
||||
"port": 0,
|
||||
"secureCACert": {
|
||||
"caFilename": "",
|
||||
"pemSha": "",
|
||||
"secret": ""
|
||||
},
|
||||
"service": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null
|
||||
},
|
||||
"spec": {
|
||||
....
|
||||
```
|
||||
|
||||
## Debug Logging
|
||||
|
||||
Using the flag `--v=XX` it is possible to increase the level of logging. This is performed by editing
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/tv42/httpunix"
|
||||
|
@ -87,6 +88,21 @@ func NewPostStatusRequest(path, contentType string, data interface{}) (int, []by
|
|||
return res.StatusCode, body, nil
|
||||
}
|
||||
|
||||
// ReadNginxConf reads the nginx configuration file into a string
|
||||
func ReadNginxConf() (string, error) {
|
||||
confFile, err := os.Open("/etc/nginx/nginx.conf")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer confFile.Close()
|
||||
|
||||
contents, err := ioutil.ReadAll(confFile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(contents), nil
|
||||
}
|
||||
|
||||
func buildUnixSocketClient() *http.Client {
|
||||
u := &httpunix.Transport{
|
||||
DialTimeout: 1 * time.Second,
|
||||
|
|
102
test/e2e/dbg/main.go
Normal file
102
test/e2e/dbg/main.go
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dbg
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"k8s.io/ingress-nginx/test/e2e/framework"
|
||||
)
|
||||
|
||||
var _ = framework.IngressNginxDescribe("Debug Tool", func() {
|
||||
f := framework.NewDefaultFramework("debug-tool")
|
||||
host := "foo.com"
|
||||
|
||||
BeforeEach(func() {
|
||||
f.NewEchoDeploymentWithReplicas(1)
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
})
|
||||
|
||||
It("should list the backend servers", func() {
|
||||
annotations := map[string]string{}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.IngressController.Namespace, "http-svc", 80, &annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxConfiguration(func(cfg string) bool {
|
||||
return Expect(cfg).Should(ContainSubstring(host))
|
||||
})
|
||||
|
||||
cmd := "/dbg backends list"
|
||||
output, err := f.ExecIngressPod(cmd)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
// Should be 2: the default and the echo deployment
|
||||
numUpstreams := len(strings.Split(strings.Trim(string(output), "\n"), "\n"))
|
||||
Expect(numUpstreams).Should(Equal(2))
|
||||
|
||||
})
|
||||
|
||||
It("should get information for a specific backend server", func() {
|
||||
annotations := map[string]string{}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.IngressController.Namespace, "http-svc", 80, &annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxConfiguration(func(cfg string) bool {
|
||||
return Expect(cfg).Should(ContainSubstring(host))
|
||||
})
|
||||
|
||||
cmd := "/dbg backends list"
|
||||
output, err := f.ExecIngressPod(cmd)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
backends := strings.Split(string(output), "\n")
|
||||
Expect(len(backends)).Should(BeNumerically(">", 0))
|
||||
|
||||
getCmd := "/dbg backends get " + backends[0]
|
||||
output, err = f.ExecIngressPod(getCmd)
|
||||
|
||||
var f map[string]interface{}
|
||||
unmarshalErr := json.Unmarshal([]byte(output), &f)
|
||||
Expect(unmarshalErr).Should(BeNil())
|
||||
|
||||
// Check that the backend we've gotten has the same name as the one we requested
|
||||
Expect(backends[0]).Should(Equal(f["name"].(string)))
|
||||
})
|
||||
|
||||
It("should produce valid JSON for /dbg general", func() {
|
||||
annotations := map[string]string{}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.IngressController.Namespace, "http-svc", 80, &annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
cmd := "/dbg general"
|
||||
output, err := f.ExecIngressPod(cmd)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
var f interface{}
|
||||
unmarshalErr := json.Unmarshal([]byte(output), &f)
|
||||
Expect(unmarshalErr).Should(BeNil())
|
||||
})
|
||||
})
|
|
@ -32,6 +32,7 @@ import (
|
|||
|
||||
// tests to run
|
||||
_ "k8s.io/ingress-nginx/test/e2e/annotations"
|
||||
_ "k8s.io/ingress-nginx/test/e2e/dbg"
|
||||
_ "k8s.io/ingress-nginx/test/e2e/defaultbackend"
|
||||
_ "k8s.io/ingress-nginx/test/e2e/gracefulshutdown"
|
||||
_ "k8s.io/ingress-nginx/test/e2e/loadbalance"
|
||||
|
|
Loading…
Reference in a new issue