Skip to content
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

Deep integration without the need for Docker #2

Closed
11 of 16 tasks
tale opened this issue Apr 2, 2024 · 7 comments
Closed
11 of 16 tasks

Deep integration without the need for Docker #2

tale opened this issue Apr 2, 2024 · 7 comments

Comments

@tale
Copy link
Owner

tale commented Apr 2, 2024

I realize that using Docker is a non-starter for a lot of people, so the goal is to support the configuration and ACL changes when Headscale is running outside of Docker. For now this thread will mostly serve as a list of potential solutions and the work needed. This will also be what holds back a 1.0 release for now.

Work that'll need to be done:

  • Supporting multiple different "control methods"
  • Better error handling on misconfigurations
  • Automatic detection where we can
  • Robust process signaling with Node's process.kill

Docker API:

  • Better handling of access to /var/run/docker.sock
  • Support different socket URLs (not just socket files)
  • Is it possible to detect the container automatically?
  • Support Docker API versions below v1.30

systemd Driver:

  • Use systemctl show --property MainPID --value headscale
  • Handle errors when invalid units or values or provided
  • Validate the responses from systemctl for pids

pidof/pgrep Method:

  • Ensure that pidof/pgrep is actually available on all systems
  • Not resorting to regex to parse the pid out of the output
  • Apparently it's actually unreliable?

DIY Method:

  • Support setting up raw bash scripts to run on trigger
  • Sanity checks, is the script executable, do we have permission?
@benmehlman
Copy link

benmehlman commented Apr 2, 2024

As mentioned on discord.. the headscale pid can be located within the /proc filesystem, this is probably the same or similar to what pidof does under the covers (I have not looked at the pidof source, just guessing).

Under '/proc` is a numeric directory for every pid. Iterate over those until you find one where /proc/n/cmdline contains /usr/bin/headscale, null, serve, null. That's the process id, send SIGHUP, done!

On my system right now:

root@headscale1:/proc/8641# hexdump -C cmdline
00000000  2f 75 73 72 2f 62 69 6e  2f 68 65 61 64 73 63 61  |/usr/bin/headsca|
00000010  6c 65 00 73 65 72 76 65  00                       |le.serve.|
00000019

That would not require executing anything at all, or being root. It just requires that headplane is running as the same uid or euid as headscale. A requirement that is easily met if both are running behind a reverse proxy.

@arcoast
Copy link

arcoast commented Apr 2, 2024

I'm very much a docker "fanboy" so can only really speak to that method,

Regarding better handling of /var/run/docker.sock I have a docker socket proxy installed for this purpose, so you can define what permissions or elements of the API are accessible. tecnativa/docker-socket-proxy is probably the most widely used, but there are more recent forks such as the one from ZoeyVid, so an option to use tcp connections rather than volume map /var/run/docker.sock would be most welcome from myself.

In terms of supporting docker api versions < v1.30, I'm wondering if that's necessary? As far as I can tell v1.30 was released with Docker Engine 17.06 which is now nearly 7 years old with the docker API v1.24 being the last supported version which was released about 12 months prior in June 2016.

One idea to cut down on support burden for docker container based installs would be to publish an entire stack including

  • headscale
  • headplane
  • docker-socket-proxy (if you wanted to go this route)

Projects such as Immich do, so using my own install as an (incomplete) example it means your README will be specifying a container name in the headscale container, making it a non-technical solution to the issue of grepping whatever random container name people might be using if you don't specify the full stack.

version: '3.9'

services:
   headscale:
       image: headscale/headscale:v0.23.0-alpha5
       container_name: headscale
       command: serve
       networks:
           - traefik
       # ports:
       #     - 8080:8080
       volumes:
           - ${CONFIG}/headscale/config.yml:/etc/headscale/config.yml
           - ${CONFIG}/headscale/acl.json:/etc/headscale/acl.json
           - ${CONFIG}/headscale/headscale:/var/lib/headscale    
       restart: unless-stopped

   headplane:
       image: ghcr.io/tale/headplane:latest
       container_name: headplane
       networks:
           - traefik
       ports:
           - 3000:3000
       environment:
           - COOKIE_SECRET=${HEADPLANE_COOKIE_SECRET}
           - API_KEY=${HEADPLANE_API_KEY}
           - HEADSCALE_CONTAINER=${HEADPLANE_HEADSCALE_CONTAINER}
           - DISABLE_API_KEY_LOGIN=${HEADPLANE_DISABLE_API_KEY_LOGIN}
           - HOST=${HEADPLANE_HOST}
           - PORT=${HEADPLANE_PORT}
           - HEADSCALE_URL=${HEADPLANE_HEADSCALE_URL}
           - CONFIG_FILE=${HEADPLANE_CONFIG_FILE}
           - ACL_FILE=${HEADPLANE_ACL_FILE}
           - OIDC_CLIENT_ID=${HEADPLANE_OIDC_CLIENT_ID}
           - OIDC_ISSUER=${HEADPLANE_OIDC_ISSUER}
           - OIDC_CLIENT_SECRET=${HEADPLANE_OIDC_CLIENT_SECRET}
       volumes:
           - ${CONFIG}/headscale/headscale:/var/lib/headscale 
           - ${CONFIG}/headscale:/etc/headscale
           - /var/run/docker.sock:/var/run/docker.sock:ro
       restart: unless-stopped

Just some random thoughts I had that might or might not help.

Loving the progress so far though!

@tale
Copy link
Owner Author

tale commented Apr 2, 2024

I mean, is the proxy 1:1? I was proposing just making a DOCKER_SOCK variable that let's you specify what to use (what ultimately gets passed to the fetch calls). Would that not be enough?

@arcoast
Copy link

arcoast commented Apr 2, 2024

I mean, is the proxy 1:1? I was proposing just making a DOCKER_SOCK variable that let's you specify what to use (what ultimately gets passed to the fetch calls). Would that not be enough?

Yeah, I think that'd be perfect, I was just throwing out ideas. As long as I can send requests to tcp://docker-socket-proxy:2375 I'm golden.

@tale
Copy link
Owner Author

tale commented May 23, 2024

@arcoast What you suggested is possible in the latest update 0.1.6

@tale
Copy link
Owner Author

tale commented May 23, 2024

#12 solves half of this issue by implementing the /proc method.

@tale tale pinned this issue Jun 2, 2024
@tale tale mentioned this issue Jun 17, 2024
@tale
Copy link
Owner Author

tale commented Aug 3, 2024

Now that everything else is implemented, I want to look at a systemd integration and a DIY one before I can call this finished.

@tale tale closed this as completed Sep 25, 2024
@tale tale unpinned this issue Sep 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants