-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Integrate tailscale into k3s #7352
Integrate tailscale into k3s #7352
Conversation
cfc3a7b
to
622c8fa
Compare
d938d1e
to
b0668be
Compare
b0668be
to
023514f
Compare
023514f
to
2a8954a
Compare
Can we get either an integration or an e2e test for this? |
From a community perspective it would be really nice to include the ability to setup a tailscale funnel at node deploy time to allow public access to the node at a targeted port or service address. This would come in particularly convenient in situations where public ingress is desired. A few example use-cases:
Perhaps a Kubernetes ingress integration could even be designed that instantiates a funnel as a CRD when ingress is created. The sky's the limit. |
2a8954a
to
60ce4b9
Compare
Codecov ReportPatch coverage has no change and project coverage change:
Additional details and impacted files@@ Coverage Diff @@
## master #7352 +/- ##
===========================================
- Coverage 47.55% 19.29% -28.27%
===========================================
Files 141 81 -60
Lines 14347 5463 -8884
===========================================
- Hits 6823 1054 -5769
+ Misses 6442 4187 -2255
+ Partials 1082 222 -860
Flags with carried forward coverage won't be shown. Click here to find out more.
☔ View full report in Codecov by Sentry. |
60ce4b9
to
c75499d
Compare
Hey @nikolaishields, how are you? Thanks for your suggestion :). There are several cool features that tailscale provides, such as funneling, but I decided to keep them outside of the integration (at least for the time being). I want to keep it dead simple and check what is the community reaction, typical bugs, etc before taking the next iteration. The CRD+ingress idea could be cool. I guess you mean having the ingress service as a nodePort service and offering that port with tailscale funnel. Kind of a "type: loadbalancer" service but without the loadbalancer, right? Wouldn't klipper-lb fulfill that use case too? Now I want/need to test it |
Yep, on it |
I'm doing well thanks for asking!
Makes perfect sense, if you ever want/need a hand on implementing any of these features let me know. Happy to help!
It probably could and then a user could just run a funnel against the node port. In theory I suppose one could also just funnel a service directly via local dns lookup (e.g. |
Actually, could we merge this PR and then work on the e2e test? It complicates things that the code is not yet part of upstream k3s |
I would defer to @cwayne18 on merging without tests. I think @dereknola might have some suggestions on how to add tests before the PR is merged? I have had some frustrations with that process as well. |
21ab427
to
a6e0809
Compare
I am adding them in the end |
a6e0809
to
4d285a4
Compare
b429d71
to
3d8540c
Compare
3d8540c
to
83c51d1
Compare
fab47fc
to
f171993
Compare
pkg/util/command.go
Outdated
var out bytes.Buffer | ||
|
||
cmd := exec.Command(command, args...) | ||
cmd.Stdout = &out | ||
err := cmd.Run() | ||
if err != nil { | ||
return "", err | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this, you get more info if there is an error, the err outs from exec are almost always just exit 1/2
, which isn't helpful.
var out bytes.Buffer | |
cmd := exec.Command(command, args...) | |
cmd.Stdout = &out | |
err := cmd.Run() | |
if err != nil { | |
return "", err | |
} | |
var out, errOut bytes.Buffer | |
cmd := exec.Command(command, args...) | |
cmd.Stdout = &out | |
cmd.Stderr = &errOut | |
err := cmd.Run() | |
if err != nil { | |
return errOut.String(), err | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice, thanks for that. The user of this function should then be aware that the interesting error is the string returned and not the error, right? I'll add a comment
pkg/util/file.go
Outdated
return "", nil | ||
} | ||
|
||
for { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest adding a failure state is after 5min or something, the path still does not exist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, good point, let me replace the infinite loop with something else using time. I copied/pasted this function from another place though, and it never happened before, but better safe than sorry
@@ -11,3 +14,21 @@ func SetFileModeForPath(name string, mode os.FileMode) error { | |||
func SetFileModeForFile(file *os.File, mode os.FileMode) error { | |||
return nil | |||
} | |||
|
|||
// ReadFile reads from a file | |||
func ReadFile(path string) (string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as in the linux version
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why this is OS-specific, there doesn't appear to be anything in either function that would differ across platforms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could remove it in another PR (just in case we need to revert) and see if things are still working
tests/e2e/tailscale/Vagrantfile
Outdated
node.vm.network "private_network", | ||
:ip => node_ip4, | ||
:netmask => "255.255.255.0", | ||
:libvirt__dhcp_enabled => false, | ||
:libvirt__forward_mode => "none" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need the special libvirt flags? Its not dualstack
node.vm.network "private_network", | |
:ip => node_ip4, | |
:netmask => "255.255.255.0", | |
:libvirt__dhcp_enabled => false, | |
:libvirt__forward_mode => "none" | |
vm.network "private_network", ip: node_ip, netmask: "255.255.255.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, I think we are using those flags in all the networking tests. We should remove it when not needed then. Thanks!
docs/adrs/integrat-vpns.md
Outdated
@@ -0,0 +1,76 @@ | |||
# Integrate vpn in k3s |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit on the filename - should it be integrate-vpns.md
? I'm not sure why the word was truncated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch, probably my mistake
pkg/cli/cmds/agent.go
Outdated
@@ -151,6 +153,18 @@ var ( | |||
Usage: "(agent/networking) Override default flannel cni config file", | |||
Destination: &AgentConfig.FlannelCniConfFile, | |||
} | |||
VPNAuth = &cli.StringFlag{ | |||
Name: "vpn-auth", | |||
Usage: "(agent/networking) (experimental) Credentials for the VPN provider. It must include the provider name and join key in the format name=tailscale,joinKey=<key>", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: be consistent with the format for vpn-auth-file
Usage: "(agent/networking) (experimental) Credentials for the VPN provider. It must include the provider name and join key in the format name=tailscale,joinKey=<key>", | |
Usage: "(agent/networking) (experimental) Credentials for the VPN provider. It must include the provider name and join key in the format name=<vpn-provider>,joinKey=<key>", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -11,3 +14,21 @@ func SetFileModeForPath(name string, mode os.FileMode) error { | |||
func SetFileModeForFile(file *os.File, mode os.FileMode) error { | |||
return nil | |||
} | |||
|
|||
// ReadFile reads from a file | |||
func ReadFile(path string) (string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why this is OS-specific, there doesn't appear to be anything in either function that would differ across platforms.
f171993
to
6147c87
Compare
6147c87
to
869e030
Compare
Proposed Changes
This PR adds the necessary code to integrate VPNs into k3s and incorporates tailscale as the first VPN option.
It also includes an ADR that explains the change
Types of Changes
New feature
Verification
1 - Install tailscale in the node
2 - Create a key in tailscale
3 - Deploy k3s with the flag:
4 - Verify that:
a) Tailscale interface exists and has an IP
b)
kubectl get endpoints
is using the tailscale IPc)
kubectl get nodes -o wide
shows the tailscale IP as the nodeIPTesting
Linked Issues
#7353
User-Facing Change
Further Comments