mirror of
https://github.com/jbowdre/tailscale-docker.git
synced 2024-12-22 05:32:18 +00:00
Version 1.0 (#2)
* Adds @rhjensen79 k8s example * Instructions in README instead of Makefile * Adds optional TAILSCALE_HOSTNAME instead of hardcoding in tailscale.sh * TAILSCALE_STATE_ARG env variable, to enable stateful-example which reuses the same ip between deployments * Fix tailscale.sh for proper `tailscale logout` on container SIGTERM * Adds github action to build image * all docker images are in the images folder. Instead of repeating in each example Co-authored-by: Robert Jensen <robert@robert-jensen.dk>
This commit is contained in:
parent
39dc4c1692
commit
7c146ab113
16 changed files with 201 additions and 43 deletions
3
.envrc_template
Normal file
3
.envrc_template
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Rename to .envrc
|
||||
export TAILSCALE_AUTH_KEY=""
|
||||
# export TAILSCALE_HOSTNAME=""
|
71
.github/workflows/build.yaml
vendored
Normal file
71
.github/workflows/build.yaml
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
name: Build Containers
|
||||
|
||||
# Controls when the workflow will run
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
- "dev"
|
||||
- "v*.*.*"
|
||||
paths:
|
||||
- "k8s/**"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Get the repositery's code
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# https://github.com/docker/setup-qemu-action
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
# https://github.com/docker/setup-buildx-action
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Login to the Container registry
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
with:
|
||||
images: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
# generate Docker tags based on the following events/attributes
|
||||
tags: |
|
||||
type=schedule
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=sha
|
||||
flavor: |
|
||||
latest=true
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: images/tailscale/.
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.envrc
|
55
README.md
55
README.md
|
@ -1,18 +1,59 @@
|
|||
# Tailscale in Docker without elevated privileges
|
||||
|
||||
See associated blog post: https://asselin.engineer/tailscale-docker
|
||||
See associated blog post: <https://asselin.engineer/tailscale-docker>
|
||||
|
||||
**Replace TAILSCALE_AUTH_KEY in `*/tailscale/start.sh` with your own**: https://login.tailscale.com/admin/settings/keys
|
||||
**Set the TAILSCALE_AUTH_KEY with your own ephemeral auth key**: <https://login.tailscale.com/admin/settings/keys>
|
||||
|
||||
## simple-example
|
||||
The `Makefile` contains all commands to launch the various examples. Refer to it to understand which commands are used.
|
||||
|
||||
## docker-compose
|
||||
|
||||
By default, no state is saved. The nodes are removed from the network when the tailscale container is terminated. This means the ip address is never the same.
|
||||
The `stateful-example` does save the tailscale node state to a docker volume.
|
||||
|
||||
Usage:
|
||||
````bash
|
||||
export TAILSCALE_AUTH_KEY="your-key"
|
||||
# set which project is used
|
||||
export PROJECT_DIRECTORY="docker-compose/simple-example"
|
||||
# Sart with rebuild if necessary:
|
||||
docker-compose --project-directory=${PROJECT_DIRECTORY} up -d --build
|
||||
# Show logs and tail (follow):
|
||||
docker-compose --project-directory=${PROJECT_DIRECTORY} logs --follow
|
||||
# Stop:
|
||||
docker-compose --project-directory=${PROJECT_DIRECTORY} down
|
||||
````
|
||||
|
||||
### simple-example
|
||||
|
||||
As explained in the blog post, uses a docker-compose service to add the container in the VPN.
|
||||
|
||||
## complex-example
|
||||
### complex-example
|
||||
|
||||
Not complex but more complex than the simple-example.
|
||||
A nginx layer is added. It manages two services in independent containers at locations `/service-one` and `/service-two`.
|
||||
A nginx layer is added. It manages two services in independent containers at urls `/service-one` and `/service-two`.
|
||||
|
||||
## TODO
|
||||
### stateful-example
|
||||
|
||||
- force reuse hostname in tailscale instead of adding suffix. Example: first container is assigned `hostname`. Then, if container is recreated, Tailscale assigns `hostname-1`. Possibly helpful [info](https://tailscale.com/kb/1111/ephemeral-nodes/#can-i-create-an-ephemeral-node-without-an-auth-key).
|
||||
Same as simple-example but uses a volume to save state. The goal is to be able to reuse the same tailscale hostname _and ip address_.
|
||||
Useful in situations where the tailscale magic DNS cannot be used.
|
||||
|
||||
## K8S
|
||||
|
||||
Same as the simple-example but on kubernetes.
|
||||
|
||||
Requirements:
|
||||
|
||||
- [Kind](https://kind.sigs.k8s.io/docs/user/quick-start/#installing-with-a-package-manager)
|
||||
- [Kubectl](https://kubernetes.io/docs/tasks/tools/)
|
||||
|
||||
Usage:
|
||||
````bash
|
||||
# Create cluster
|
||||
kind create cluster --name tailscale
|
||||
kubectl get nodes
|
||||
# Deploy tailscale and demo webpage:
|
||||
kubectl apply -f k8s/simple-example/deployment.yaml
|
||||
# Delete cluster:
|
||||
kind delete cluster --name tailscale
|
||||
````
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
FROM tailscale/tailscale:v1.29
|
||||
COPY start.sh /usr/bin/start.sh
|
||||
RUN chmod +x /usr/bin/start.sh
|
||||
CMD "start.sh"
|
|
@ -1,9 +0,0 @@
|
|||
#!/bin/ash
|
||||
echo "Starting TS daemon"
|
||||
tailscaled --tun=userspace-networking &
|
||||
PID=$!
|
||||
until tailscale up --authkey=${TAILSCALE_AUTH_KEY} --hostname=complex-example; do
|
||||
sleep 0.1
|
||||
done
|
||||
tailscale status
|
||||
wait ${PID}
|
|
@ -2,12 +2,14 @@ version: "3.9"
|
|||
services:
|
||||
tailscale:
|
||||
build:
|
||||
context: ./tailscale
|
||||
context: images/tailscale
|
||||
environment:
|
||||
- TAILSCALE_AUTH_KEY
|
||||
TAILSCALE_AUTH_KEY: ${TAILSCALE_AUTH_KEY:?err}
|
||||
TAILSCALE_HOSTNAME: ${TAILSCALE_HOSTNAME:-tailscale-docker-complex-example}
|
||||
TAILSCALE_STATE_ARG: "mem:"
|
||||
nginx:
|
||||
build:
|
||||
context: ./nginx
|
||||
context: images/nginx
|
||||
depends_on:
|
||||
- service-one
|
||||
- service-two
|
12
docker-compose/simple-example/docker-compose.yml
Normal file
12
docker-compose/simple-example/docker-compose.yml
Normal file
|
@ -0,0 +1,12 @@
|
|||
version: "3.9"
|
||||
services:
|
||||
tailscale:
|
||||
build:
|
||||
context: ../../images/tailscale
|
||||
environment:
|
||||
TAILSCALE_AUTH_KEY: ${TAILSCALE_AUTH_KEY:?err}
|
||||
TAILSCALE_HOSTNAME: ${TAILSCALE_HOSTNAME:-tailscale-docker-simple-example}
|
||||
TAILSCALE_STATE_ARG: "mem:"
|
||||
some-service-1:
|
||||
image: nginxdemos/hello
|
||||
network_mode: "service:tailscale"
|
15
docker-compose/stateful-example/docker-compose.yml
Normal file
15
docker-compose/stateful-example/docker-compose.yml
Normal file
|
@ -0,0 +1,15 @@
|
|||
version: "3.9"
|
||||
services:
|
||||
tailscale:
|
||||
build:
|
||||
context: ../../images/tailscale
|
||||
environment:
|
||||
TAILSCALE_AUTH_KEY: ${TAILSCALE_AUTH_KEY:?err}
|
||||
TAILSCALE_HOSTNAME: ${TAILSCALE_HOSTNAME:-tailscale-docker-stateful-example}
|
||||
TAILSCALE_STATE_ARG: "/var/lib/tailscale_state/tailscale.state" # a file
|
||||
volumes:
|
||||
# a volume is used but it could be a local directory.
|
||||
- /var/lib/tailscale_state/
|
||||
some-service-1:
|
||||
image: nginxdemos/hello
|
||||
network_mode: "service:tailscale"
|
|
@ -1,4 +1,4 @@
|
|||
FROM tailscale/tailscale:v1.29
|
||||
FROM tailscale/tailscale:v1.30
|
||||
COPY start.sh /usr/bin/start.sh
|
||||
RUN chmod +x /usr/bin/start.sh
|
||||
CMD "start.sh"
|
12
images/tailscale/start.sh
Normal file
12
images/tailscale/start.sh
Normal file
|
@ -0,0 +1,12 @@
|
|||
#!/bin/ash
|
||||
trap 'kill -TERM $PID' TERM INT
|
||||
echo "Starting Tailscale daemon"
|
||||
# -state=mem: will logout and remove ephemeral node from network immediately after ending.
|
||||
tailscaled --tun=userspace-networking --state=${TAILSCALE_STATE_ARG} &
|
||||
PID=$!
|
||||
until tailscale up --authkey="${TAILSCALE_AUTH_KEY}" --hostname="${TAILSCALE_HOSTNAME}"; do
|
||||
sleep 0.1
|
||||
done
|
||||
tailscale status
|
||||
wait ${PID}
|
||||
wait ${PID}
|
33
k8s/simple-example/deployment.yaml
Normal file
33
k8s/simple-example/deployment.yaml
Normal file
|
@ -0,0 +1,33 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: tailscale
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: tailscale
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: tailscale
|
||||
spec:
|
||||
containers:
|
||||
- name: tailscale
|
||||
image: ghcr.io/lpasselin/tailscale-docker:latest
|
||||
env:
|
||||
- name: TAILSCALE_AUTH_KEY
|
||||
value: "${TAILSCALE_AUTH_KEY:-err}"
|
||||
- name: TAILSCALE_HOSTNAME
|
||||
value: "tailscale-docker-k8s-simple"
|
||||
- name: TAILSCALE_STATE_ARG
|
||||
value: "mem:"
|
||||
resources:
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "500m"
|
||||
- name: nginx
|
||||
image: nginxdemos/hello
|
||||
resources:
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "500m"
|
|
@ -1,10 +0,0 @@
|
|||
version: "3.9"
|
||||
services:
|
||||
tailscale:
|
||||
build:
|
||||
context: ./tailscale
|
||||
environment:
|
||||
- TAILSCALE_AUTH_KEY
|
||||
some-service-1:
|
||||
image: nginxdemos/hello
|
||||
network_mode: "service:tailscale"
|
|
@ -1,9 +0,0 @@
|
|||
#!/bin/ash
|
||||
echo "Starting TS daemon"
|
||||
tailscaled --tun=userspace-networking &
|
||||
PID=$!
|
||||
until tailscale up --authkey=${TAILSCALE_AUTH_KEY} --hostname=complex-example; do
|
||||
sleep 0.1
|
||||
done
|
||||
tailscale status
|
||||
wait ${PID}
|
Loading…
Reference in a new issue