From ac3c7c218fe583a49a411b3f66aa9c408981c74c Mon Sep 17 00:00:00 2001 From: fengcaiwen Date: Thu, 16 Mar 2023 15:21:08 +0800 Subject: [PATCH] feat: use network instead of parent-container --- Makefile | 2 +- README.md | 20 +++++++++++++++---- README_ZH.md | 16 +++++++++++++--- build/Dockerfile | 2 +- build/local.Dockerfile | 2 +- cmd/kubevpn/cmds/dev.go | 36 ++++++++++++++++++++++++----------- cmd/kubevpn/cmds/duplicate.go | 21 +++++++++++--------- cmd/kubevpn/cmds/proxy.go | 6 +++--- pkg/cp/cp.go | 16 ++++++++++++---- pkg/dev/main.go | 33 ++++++++++++++++++-------------- pkg/dev/option.go | 5 +++++ pkg/util/pod.go | 2 +- 12 files changed, 109 insertions(+), 52 deletions(-) diff --git a/Makefile b/Makefile index 91da3f79..32ae347a 100644 --- a/Makefile +++ b/Makefile @@ -89,7 +89,7 @@ container: ############################ build local .PHONY: container-local container-local: kubevpn-linux-amd64 - docker buildx build --platform linux/amd64 -t docker.io/naison/kubevpn:latest -f $(BUILD_DIR)/local.Dockerfile . + docker buildx build --platform linux/amd64 -t docker.io/naison/kubevpn:latest -f $(BUILD_DIR)/local.Dockerfile --push . .PHONY: container-test container-test: kubevpn-linux-amd64 diff --git a/README.md b/README.md index 9aacd152..8b91683d 100644 --- a/README.md +++ b/README.md @@ -333,7 +333,7 @@ as `--entrypoint "tail -f /dev/null"`, for more parameters, see `kubevpn dev --h If you want to start the development mode locally using Docker in Docker (DinD), because the program will read and write the `/tmp` directory, you need to manually add the parameter `-v /tmp:/tmp` (outer docker) and other thing is you -need to special parameter `--parent-container` (inner docker) for sharing network and pid +need to special parameter `--network` (inner docker) for sharing network and pid Example: @@ -345,7 +345,7 @@ docker run -it --privileged -v /var/run/docker.sock:/var/run/docker.sock -v /tmp ➜ ~ docker run -it --privileged -c authors -v /var/run/docker.sock:/var/run/docker.sock -v /tmp:/tmp -v /Users/naison/.kube/vke:/root/.kube/config -v /Users/naison/Desktop/kubevpn/bin:/app naison/kubevpn:v1.1.21 root@4d0c3c4eae2b:/# hostname 4d0c3c4eae2b -root@4d0c3c4eae2b:/# kubevpn dev deployment/authors -n kube-system --image naison/kubevpn:v1.1.21 --headers user=naison --parent-container 4d0c3c4eae2b --entrypoint "tail -f /dev/null" +root@4d0c3c4eae2b:/# kubevpn dev deployment/authors -n kube-system --image naison/kubevpn:v1.1.21 --headers user=naison --network container:4d0c3c4eae2b --entrypoint "tail -f /dev/null" ---------------------------------------------------------------------------------- Warn: Use sudo to execute command kubevpn can not use user env KUBECONFIG. @@ -507,7 +507,7 @@ pod [kubevpn-traffic-manager] status is Running ... ``` -- When use kubevpn dev, but got error code 137, how to resolve ? +- When use `kubevpn dev`, but got error code 137, how to resolve ? ```text dns service ok @@ -526,4 +526,16 @@ clean up successful ``` This is because of your docker-desktop required resource is less than pod running request resource, it OOM killed, so -you can add more resource in your docker-desktop setting `Preferences --> Resources --> Memory` \ No newline at end of file +you can add more resource in your docker-desktop setting `Preferences --> Resources --> Memory` + +- I am using WSL( Windows Sub Linux ) Docker, when use mode `kubevpn dev`, can not connect to cluster network, how to + solve this problem? + +Answer: this is because WSL'Docker using Windows's Network, so if even start a container in WSL, this container will +not use WSL network, but use Windows network +Solution: + +- 1): install docker in WSL, not use Windows Docker-desktop +- 2): use command `kubevpn connect` on Windows, and then startup `kubevpn dev` in WSL +- 3): startup a container using command `kubevpn connect` on Windows, and then + startup `kubevpn dev --network container:$CONTAINER_ID` in WSL \ No newline at end of file diff --git a/README_ZH.md b/README_ZH.md index c38c7f0f..c59293fd 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -325,7 +325,7 @@ de9e2f8ab57d nginx:latest "/docker-entrypoint.…" 5 seconds ### DinD ( Docker in Docker ) 在 Docker 中使用 kubevpn 如果你想在本地使用 Docker in Docker (DinD) 的方式启动开发模式, 由于程序会读写 `/tmp` 目录,您需要手动添加参数 `-v /tmp:/tmp`, 还有一点需要注意, 如果使用 DinD -模式,为了共享容器网络和 pid, 还需要指定参数 `--parent-container` +模式,为了共享容器网络和 pid, 还需要指定参数 `--network` 例如: @@ -337,7 +337,7 @@ docker run -it --privileged -v /var/run/docker.sock:/var/run/docker.sock -v /tmp ➜ ~ docker run -it --privileged -c authors -v /var/run/docker.sock:/var/run/docker.sock -v /tmp:/tmp -v /Users/naison/.kube/config:/root/.kube/config naison/kubevpn:v1.1.21 root@4d0c3c4eae2b:/# hostname 4d0c3c4eae2b -root@4d0c3c4eae2b:/# kubevpn dev deployment/authors -n kube-system --image naison/kubevpn:v1.1.21 --headers user=naison --parent-container 4d0c3c4eae2b --entrypoint "tail -f /dev/null" +root@4d0c3c4eae2b:/# kubevpn dev deployment/authors -n kube-system --image naison/kubevpn:v1.1.21 --headers user=naison --network container:4d0c3c4eae2b --entrypoint "tail -f /dev/null" ---------------------------------------------------------------------------------- Warn: Use sudo to execute command kubevpn can not use user env KUBECONFIG. @@ -516,4 +516,14 @@ clean up successful ``` 这是因为你的 `Docker-desktop` 声明的资源, 小于 container 容器启动时所需要的资源, 因此被 OOM 杀掉了, 你可以增加 `Docker-desktop` 对于 resources -的设置, 目录是:`Preferences --> Resources --> Memory` \ No newline at end of file +的设置, 目录是:`Preferences --> Resources --> Memory` + +- 我在使用 WSL( Windows Sub Linux ) Docker, 当我在使用命令 `kubevpn dev` 进入开发模式的时候, 在 terminal 中无法提示链接集群网络, 这是为什么, 如何解决? + +答案: 这是因为 WSL 的 Docker 使用的是 主机 Windows 的网络, 所以即便在 WSL 中启动 container, 这个 container 不会使用 WSL 的网络,而是使用 Windows 的网络。 +解决方案: + +- 1): 在 WSL 中安装 Docker, 不要使用 Windows 版本的 Docker-desktop +- 2): 在主机 Windows 使用命令 `kubevpn connect`, 然后在 WSL 中使用 `kubevpn dev` 进入开发模式 +- 3): 在主机 Windows 上启动一个 container,在 container 中使用命令 `kubevpn connect`, 然后在 WSL + 中使用 `kubevpn dev --network container:$CONTAINER_ID` \ No newline at end of file diff --git a/build/Dockerfile b/build/Dockerfile index 76580678..02189b45 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -16,7 +16,7 @@ ARG BASE=github.com/wencaiwulue/kubevpn RUN sed -i s@/security.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list \ && sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list RUN apt-get clean && apt-get update && apt-get install -y wget dnsutils vim curl \ - net-tools iptables iputils-ping lsof iproute2 tcpdump binutils + net-tools iptables iputils-ping lsof iproute2 tcpdump binutils traceroute WORKDIR /app diff --git a/build/local.Dockerfile b/build/local.Dockerfile index a6f47e21..4bd1e3af 100644 --- a/build/local.Dockerfile +++ b/build/local.Dockerfile @@ -4,7 +4,7 @@ FROM ubuntu:latest RUN sed -i s@/security.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list \ && sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list RUN apt-get clean && apt-get update && apt-get install -y wget dnsutils vim curl \ - net-tools iptables iputils-ping lsof iproute2 tcpdump binutils + net-tools iptables iputils-ping lsof iproute2 tcpdump binutils traceroute WORKDIR /app diff --git a/cmd/kubevpn/cmds/dev.go b/cmd/kubevpn/cmds/dev.go index 4a325c9a..9b518b68 100644 --- a/cmd/kubevpn/cmds/dev.go +++ b/cmd/kubevpn/cmds/dev.go @@ -10,6 +10,7 @@ import ( "github.com/docker/cli/cli" "github.com/docker/cli/opts" "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" cmdutil "k8s.io/kubectl/pkg/cmd/util" @@ -32,26 +33,30 @@ func CmdDev(f cmdutil.Factory) *cobra.Command { Env: opts.NewListOpts(nil), Volumes: opts.NewListOpts(nil), ExtraHosts: opts.NewListOpts(nil), + Aliases: 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`)), + Short: i18n.T("Startup your workloads in local Docker container use same volume、env、and network with cluster"), + Long: templates.LongDesc(i18n.T(`Startup your workloads in local Docker container use same volume、env、and network with cluster`)), Example: templates.Examples(i18n.T(` - # Dev reverse proxy - - reverse deployment + # Develop workloads + - develop deployment kubevpn dev deployment/productpage - - reverse service + - develop service kubevpn dev service/productpage - # Reverse proxy with mesh, traffic with header a=1, will hit local PC, otherwise no effect + # Develop workloads 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 + # Develop workloads without proxy traffic + kubevpn dev service/productpage --no-proxy + + # Develop workloads which 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 @@ -78,13 +83,14 @@ func CmdDev(f cmdutil.Factory) *cobra.Command { ExtraCIDR: devOptions.ExtraCIDR, } - if devOptions.ParentContainer != "" { + mode := container.NetworkMode(devOptions.NetMode.NetworkMode()) + if mode.IsContainer() { client, _, err := dev.GetClient() if err != nil { return err } var inspect types.ContainerJSON - inspect, err = client.ContainerInspect(context.Background(), devOptions.ParentContainer) + inspect, err = client.ContainerInspect(context.Background(), mode.ConnectedContainer()) if err != nil { return err } @@ -92,7 +98,7 @@ func CmdDev(f cmdutil.Factory) *cobra.Command { 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) + return fmt.Errorf("container %s status is %s, expect is running, please make sure your outer docker name is correct", mode.ConnectedContainer(), inspect.State.Status) } } @@ -145,7 +151,15 @@ func CmdDev(f cmdutil.Factory) *cobra.Command { // 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().StringVar(&devOptions.ParentContainer, "parent-container", "", "Parent container name if running in Docker (Docker in Docker)") + // We allow for both "--net" and "--network", although the latter is the recommended way. + cmd.Flags().Var(&devOptions.NetMode, "net", "Connect a container to a network") + cmd.Flags().Var(&devOptions.NetMode, "network", "Connect a container to a network") + cmd.Flags().MarkHidden("net") + // We allow for both "--net-alias" and "--network-alias", although the latter is the recommended way. + cmd.Flags().Var(&devOptions.Aliases, "net-alias", "Add network-scoped alias for the container") + cmd.Flags().Var(&devOptions.Aliases, "network-alias", "Add network-scoped alias for the container") + cmd.Flags().MarkHidden("net-alias") 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") diff --git a/cmd/kubevpn/cmds/duplicate.go b/cmd/kubevpn/cmds/duplicate.go index a8706620..f4099e3c 100644 --- a/cmd/kubevpn/cmds/duplicate.go +++ b/cmd/kubevpn/cmds/duplicate.go @@ -28,26 +28,29 @@ func CmdDuplicate(f cmdutil.Factory) *cobra.Command { var sshConf = &util.SshConfig{} cmd := &cobra.Command{ Use: "duplicate", - Short: i18n.T("Connect to kubernetes cluster network, and duplicate workloads to target-kubeconfig cluster with same volume、env、and network"), - Long: templates.LongDesc(i18n.T(`Connect to kubernetes cluster network, and duplicate workloads to target-kubeconfig cluster with same volume、env、and network`)), + Short: i18n.T("Duplicate workloads to target-kubeconfig cluster with same volume、env、and network"), + Long: templates.LongDesc(i18n.T(`Duplicate workloads to target-kubeconfig cluster with same volume、env、and network`)), Example: templates.Examples(i18n.T(` # duplicate - - duplicate deployment + - duplicate deployment in current cluster and current namespace kubevpn duplicate deployment/productpage - - duplicate service - kubevpn proxy service/productpage + - duplicate deployment in current cluster with different namespace + kubevpn duplicate deployment/productpage -n test + + - duplicate deployment to another cluster + kubevpn duplicate deployment/productpage --target-kubeconfig ~/.kube/other-kubeconfig - duplicate multiple workloads kubevpn duplicate deployment/authors deployment/productpage or kubevpn duplicate deployment authors productpage - # Reverse duplicate with mesh, traffic with header a=1, will hit local PC, otherwise no effect - kubevpn duplicate service/productpage --headers a=1 + # duplicate with mesh, traffic with header a=1, will hit duplicate workloads, otherwise hit origin workloads + kubevpn duplicate deployment/productpage --headers a=1 - # Connect to api-server behind of bastion host or ssh jump host and proxy kubernetes resource traffic into local PC - kubevpn duplicate --ssh-addr 192.168.1.100:22 --ssh-username root --ssh-keyfile /Users/naison/.ssh/ssh.pem service/productpage --headers a=1 + # duplicate workloads which api-server behind of bastion host or ssh jump host + kubevpn duplicate deployment/productpage --ssh-addr 192.168.1.100:22 --ssh-username root --ssh-keyfile /Users/naison/.ssh/ssh.pem --headers a=1 # it also support ProxyJump, like ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌────────────┐ diff --git a/cmd/kubevpn/cmds/proxy.go b/cmd/kubevpn/cmds/proxy.go index a7a66686..e176bf49 100644 --- a/cmd/kubevpn/cmds/proxy.go +++ b/cmd/kubevpn/cmds/proxy.go @@ -25,8 +25,8 @@ func CmdProxy(f cmdutil.Factory) *cobra.Command { var sshConf = &util.SshConfig{} cmd := &cobra.Command{ Use: "proxy", - Short: i18n.T("Connect to kubernetes cluster network and proxy kubernetes workloads inbound traffic into local PC"), - Long: templates.LongDesc(i18n.T(`Connect to kubernetes cluster network, or proxy kubernetes workloads inbound traffic into local PC`)), + Short: i18n.T("Proxy kubernetes workloads inbound traffic into local PC"), + Long: templates.LongDesc(i18n.T(`Proxy kubernetes workloads inbound traffic into local PC`)), Example: templates.Examples(i18n.T(` # Reverse proxy - proxy deployment @@ -44,7 +44,7 @@ func CmdProxy(f cmdutil.Factory) *cobra.Command { kubevpn proxy service/productpage --headers a=1 # Connect to api-server behind of bastion host or ssh jump host and proxy kubernetes resource traffic into local PC - kubevpn proxy --ssh-addr 192.168.1.100:22 --ssh-username root --ssh-keyfile /Users/naison/.ssh/ssh.pem service/productpage --headers a=1 + kubevpn proxy deployment/productpage --ssh-addr 192.168.1.100:22 --ssh-username root --ssh-keyfile /Users/naison/.ssh/ssh.pem --headers a=1 # it also support ProxyJump, like ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌────────────┐ diff --git a/pkg/cp/cp.go b/pkg/cp/cp.go index 075f55c7..f41d3517 100644 --- a/pkg/cp/cp.go +++ b/pkg/cp/cp.go @@ -7,10 +7,11 @@ import ( "fmt" "io" "os" + "runtime" "strings" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/client-go/kubernetes" restclient "k8s.io/client-go/rest" @@ -52,7 +53,10 @@ func extractFileSpec(arg string) (fileSpec, error) { if i == 0 { return fileSpec{}, errFileSpecDoesntMatchFormat } - if i == -1 { + + // C:\Users\ADMINI~1\AppData\Local\Temp\849198392506502457 + // disk name C is not a pod name + if i == -1 || (runtime.GOOS == "windows" && strings.Contains("ABCDEFGHIJKLMNOPQRSTUVWXYZ", arg[:i])) { return fileSpec{ File: newLocalPath(arg), }, nil @@ -178,7 +182,9 @@ func (o *CopyOptions) copyToPod(src, dest fileSpec, options *exec.ExecOptions) e go func(src localPath, dest remotePath, writer io.WriteCloser) { defer writer.Close() - cmdutil.CheckErr(makeTar(src, dest, writer)) + if err := makeTar(src, dest, writer); err != nil { + log.Error(err) + } }(srcFile, destFile, writer) var cmdArr []string @@ -259,7 +265,9 @@ func (t *TarPipe) initReadFrom(n uint64) { go func() { defer t.outStream.Close() - cmdutil.CheckErr(t.o.execute(options)) + if err := t.o.execute(options); err != nil { + log.Error(err) + } }() } diff --git a/pkg/dev/main.go b/pkg/dev/main.go index 88d61ee2..1206d05f 100644 --- a/pkg/dev/main.go +++ b/pkg/dev/main.go @@ -13,6 +13,7 @@ import ( "github.com/docker/cli/cli/flags" "github.com/docker/cli/opts" "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" containertypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/mount" "github.com/docker/docker/client" @@ -43,17 +44,18 @@ type Options struct { // docker options Platform string //Pull string // always, missing, never - PublishAll bool - Entrypoint string - DockerImage string - Publish opts.ListOpts - Expose opts.ListOpts - ExtraHosts opts.ListOpts - ParentContainer string - Env opts.ListOpts - Mounts opts.MountOpt - Volumes opts.ListOpts - VolumeDriver string + PublishAll bool + Entrypoint string + DockerImage string + Publish opts.ListOpts + Expose opts.ListOpts + ExtraHosts opts.ListOpts + NetMode opts.NetworkOpt + Aliases opts.ListOpts + Env opts.ListOpts + Mounts opts.MountOpt + Volumes opts.ListOpts + VolumeDriver string } func (d Options) Main(ctx context.Context) error { @@ -124,12 +126,15 @@ func (d Options) Main(ctx context.Context) error { if outOfMemory { return fmt.Errorf("your pod resource request is bigger than docker-desktop resource, please adjust your docker-desktop resource") } - if d.ParentContainer != "" { + mode := container.NetworkMode(d.NetMode.NetworkMode()) + if mode.IsUserDefined() { for _, config := range list[:] { // remove expose port config.config.ExposedPorts = nil - config.hostConfig.NetworkMode = containertypes.NetworkMode("container:" + d.ParentContainer) - config.hostConfig.PidMode = containertypes.PidMode("container:" + d.ParentContainer) + config.hostConfig.NetworkMode = mode + if mode.IsContainer() { + config.hostConfig.PidMode = containertypes.PidMode(d.NetMode.NetworkMode()) + } config.hostConfig.PortBindings = nil // remove dns diff --git a/pkg/dev/option.go b/pkg/dev/option.go index 30ffcc3b..e4b8b525 100644 --- a/pkg/dev/option.go +++ b/pkg/dev/option.go @@ -148,6 +148,11 @@ func fillOptions(r Run, copts Options) error { config.hostConfig.Binds = binds + // todo + if copts.Aliases.Len() != 0 { + //config.networkingConfig.EndpointsConfig + } + return nil } diff --git a/pkg/util/pod.go b/pkg/util/pod.go index afea2dc4..ecf98912 100644 --- a/pkg/util/pod.go +++ b/pkg/util/pod.go @@ -146,7 +146,7 @@ func GetVolume(ctx context.Context, f util.Factory, ns, pod string) (map[string] } err = copyOptions.Run() if err != nil { - _, _ = fmt.Fprintf(os.Stderr, "Can not download volume %s path %s, err: %v, ignore...\n", volumeMount.Name, volumeMount.MountPath, err) + _, _ = fmt.Fprintf(os.Stderr, "failed to download volume %s path %s to %s, err: %v, ignore...\n", volumeMount.Name, remotePath, join, err) continue } m = append(m, mount.Mount{