mirror of
https://github.com/kubenetworks/kubevpn.git
synced 2025-10-05 07:16:54 +08:00
165 lines
7.0 KiB
Go
165 lines
7.0 KiB
Go
package cmds
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"syscall"
|
|
|
|
"github.com/docker/cli/cli"
|
|
"github.com/docker/cli/opts"
|
|
"github.com/docker/docker/api/types"
|
|
log "github.com/sirupsen/logrus"
|
|
"github.com/spf13/cobra"
|
|
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
|
"k8s.io/kubectl/pkg/util/completion"
|
|
"k8s.io/kubectl/pkg/util/i18n"
|
|
"k8s.io/kubectl/pkg/util/templates"
|
|
|
|
"github.com/wencaiwulue/kubevpn/pkg/config"
|
|
"github.com/wencaiwulue/kubevpn/pkg/dev"
|
|
"github.com/wencaiwulue/kubevpn/pkg/handler"
|
|
"github.com/wencaiwulue/kubevpn/pkg/util"
|
|
)
|
|
|
|
func CmdDev(f cmdutil.Factory) *cobra.Command {
|
|
var devOptions = dev.Options{
|
|
Factory: f,
|
|
Entrypoint: "",
|
|
Publish: opts.NewListOpts(nil),
|
|
Expose: opts.NewListOpts(nil),
|
|
Env: opts.NewListOpts(nil),
|
|
Volumes: opts.NewListOpts(nil),
|
|
ExtraHosts: opts.NewListOpts(nil),
|
|
NoProxy: false,
|
|
ExtraCIDR: []string{},
|
|
}
|
|
var sshConf = &util.SshConfig{}
|
|
cmd := &cobra.Command{
|
|
Use: "dev",
|
|
Short: i18n.T("Proxy kubernetes workloads inbound traffic into local PC and dev in docker container"),
|
|
Long: templates.LongDesc(i18n.T(`Proxy kubernetes workloads inbound traffic into local PC`)),
|
|
Example: templates.Examples(i18n.T(`
|
|
# Dev reverse proxy
|
|
- reverse deployment
|
|
kubevpn dev deployment/productpage
|
|
|
|
- reverse service
|
|
kubevpn dev service/productpage
|
|
|
|
# Reverse proxy with mesh, traffic with header a=1, will hit local PC, otherwise no effect
|
|
kubevpn dev service/productpage --headers a=1
|
|
|
|
# Dev reverse proxy api-server behind of bastion host or ssh jump host
|
|
kubevpn dev deployment/productpage --ssh-addr 192.168.1.100:22 --ssh-username root --ssh-keyfile /Users/naison/.ssh/ssh.pem
|
|
|
|
# it also support ProxyJump, like
|
|
┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌────────────┐
|
|
│ pc ├────►│ ssh1 ├────►│ ssh2 ├────►│ ssh3 ├─────►... ─────► │ api-server │
|
|
└──────┘ └──────┘ └──────┘ └──────┘ └────────────┘
|
|
kubevpn dev deployment/productpage --ssh-alias <alias>
|
|
|
|
`)),
|
|
Args: cli.ExactArgs(1),
|
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
|
if !util.IsAdmin() {
|
|
util.RunWithElevated()
|
|
os.Exit(0)
|
|
}
|
|
go http.ListenAndServe("localhost:6060", nil)
|
|
util.InitLogger(config.Debug)
|
|
return handler.SshJump(sshConf, cmd.Flags())
|
|
},
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
connect := handler.ConnectOptions{
|
|
Headers: devOptions.Headers,
|
|
Workloads: args,
|
|
ExtraCIDR: devOptions.ExtraCIDR,
|
|
}
|
|
|
|
if devOptions.ParentContainer != "" {
|
|
client, _, err := dev.GetClient()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var inspect types.ContainerJSON
|
|
inspect, err = client.ContainerInspect(context.Background(), devOptions.ParentContainer)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if inspect.State == nil {
|
|
return fmt.Errorf("can not get container status, please make contianer name is valid")
|
|
}
|
|
if !inspect.State.Running {
|
|
return fmt.Errorf("container %s status is %s, expect is running, please make sure your outer docker name is correct", devOptions.ParentContainer, inspect.State.Status)
|
|
}
|
|
}
|
|
|
|
if err := connect.InitClient(f); err != nil {
|
|
return err
|
|
}
|
|
err := connect.PreCheckResource()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(connect.Workloads) > 1 {
|
|
return fmt.Errorf("can only dev one workloads at same time, workloads: %v", connect.Workloads)
|
|
}
|
|
if len(connect.Workloads) < 1 {
|
|
return fmt.Errorf("you must provide resource to dev, workloads : %v is invaild", connect.Workloads)
|
|
}
|
|
|
|
devOptions.Workload = connect.Workloads[0]
|
|
// if no-proxy is true, not needs to intercept traffic
|
|
if devOptions.NoProxy {
|
|
if len(connect.Headers) != 0 {
|
|
return fmt.Errorf("not needs to provide headers if is no-proxy mode")
|
|
}
|
|
connect.Workloads = []string{}
|
|
}
|
|
defer func() {
|
|
handler.Cleanup(syscall.SIGQUIT)
|
|
select {}
|
|
}()
|
|
if err = connect.DoConnect(); err != nil {
|
|
log.Errorln(err)
|
|
return err
|
|
}
|
|
devOptions.Namespace = connect.Namespace
|
|
err = devOptions.Main(context.Background())
|
|
if err != nil {
|
|
log.Errorln(err)
|
|
}
|
|
return err
|
|
},
|
|
}
|
|
cmd.Flags().StringToStringVarP(&devOptions.Headers, "headers", "H", map[string]string{}, "Traffic with special headers with reverse it to local PC, you should startup your service after reverse workloads successfully, If not special, redirect all traffic to local PC, format is k=v, like: k1=v1,k2=v2")
|
|
cmd.Flags().BoolVar(&config.Debug, "debug", false, "enable debug mode or not, true or false")
|
|
cmd.Flags().StringVar(&config.Image, "image", config.Image, "use this image to startup container")
|
|
cmd.Flags().BoolVar(&devOptions.NoProxy, "no-proxy", false, "Whether proxy remote workloads traffic into local or not, true: just startup container on local without inject containers to intercept traffic, false: intercept traffic and forward to local")
|
|
cmdutil.AddContainerVarFlags(cmd, &devOptions.ContainerName, devOptions.ContainerName)
|
|
cmdutil.CheckErr(cmd.RegisterFlagCompletionFunc("container", completion.ContainerCompletionFunc(f)))
|
|
cmd.Flags().StringArrayVar(&devOptions.ExtraCIDR, "extra-cidr", []string{}, "Extra cidr string, eg: --extra-cidr 192.168.0.159/24 --extra-cidr 192.168.1.160/32")
|
|
|
|
// docker options
|
|
cmd.Flags().Var(&devOptions.ExtraHosts, "add-host", "Add a custom host-to-IP mapping (host:ip)")
|
|
cmd.Flags().StringVar(&devOptions.ParentContainer, "parent-container", "", "Parent container name if running in Docker (Docker in Docker)")
|
|
cmd.Flags().VarP(&devOptions.Volumes, "volume", "v", "Bind mount a volume")
|
|
cmd.Flags().Var(&devOptions.Mounts, "mount", "Attach a filesystem mount to the container")
|
|
cmd.Flags().Var(&devOptions.Expose, "expose", "Expose a port or a range of ports")
|
|
cmd.Flags().VarP(&devOptions.Publish, "publish", "p", "Publish a container's port(s) to the host")
|
|
cmd.Flags().BoolVarP(&devOptions.PublishAll, "publish-all", "P", false, "Publish all exposed ports to random ports")
|
|
cmd.Flags().VarP(&devOptions.Env, "env", "e", "Set environment variables")
|
|
cmd.Flags().StringVar(&devOptions.Entrypoint, "entrypoint", "", "Overwrite the default ENTRYPOINT of the image")
|
|
cmd.Flags().StringVar(&devOptions.DockerImage, "docker-image", "", "Overwrite the default K8s pod of the image")
|
|
//cmd.Flags().StringVar(&devOptions.Pull, "pull", container.PullImageMissing, `Pull image before creating ("`+container.PullImageAlways+`"|"`+container.PullImageMissing+`"|"`+container.PullImageNever+`")`)
|
|
cmd.Flags().StringVar(&devOptions.Platform, "platform", os.Getenv("DOCKER_DEFAULT_PLATFORM"), "Set platform if server is multi-platform capable")
|
|
cmd.Flags().StringVar(&devOptions.VolumeDriver, "volume-driver", "", "Optional volume driver for the container")
|
|
_ = cmd.Flags().SetAnnotation("platform", "version", []string{"1.32"})
|
|
|
|
addSshFlag(cmd, sshConf)
|
|
return cmd
|
|
}
|