Tailscale trong Docker lỗi TS_STATE, logged out: cách sửa

Chia sẻ bài viết

Mục lục
Tailscale trong Docker lỗi TS_STATE, logged out: cách sửa

Trả lời nhanh: Ba lỗi Docker kinh điển: couldn't detect persistent docker directory for TS_STATE, thiếu volume cho /var/lib/tailscale; you are logged out sau mỗi lần recreate, cùng gốc (state không được giữ) hoặc auth key ephemeral hết hạn; không tạo được tun, thiếu --device=/dev/net/tun --cap-add=NET_ADMIN. Mẫu compose chuẩn trong bài chặn cả ba từ gốc.

Chạy Tailscale trong container hấp dẫn, mỗi dịch vụ một danh tính, cả stack trong một compose file, nhưng cũng đẻ ra lớp lỗi riêng mà môi trường cài thẳng không có: container là sinh vật phù du, recreate là mất sạch những gì không nằm trong volume, và không có sẵn quyền đụng tầng mạng. Bài này mổ ba lỗi được tìm nhiều nhất, chốt bằng cấu hình chuẩn đã né hết mìn.

Tóm tắt nhanh
  • Danh tính node nằm ở /var/lib/tailscale: không mount volume là mỗi lần recreate thành máy mới + lỗi TS_STATE
  • you are logged out sau recreate: kiểm volume trước, auth key sau
  • Key ephemeral tạo node tự xóa khi offline, tiện cho CI, tai họa nếu dùng nhầm cho dịch vụ bền
  • Không có /dev/net/tun: tailscaled trong container chết ngay từ log đầu
  • Node rác chồng chất trong console là triệu chứng điển hình của state không bền

couldn't detect persistent docker directory for TS_STATE

Thông báo này là image chính chủ đang cảnh cáo bạn: tôi không thấy chỗ lưu state bền vững. Danh tính node (khóa máy, cấu hình serve) sống ở /var/lib/tailscale trong container, không mount volume vào đó thì mỗi lần docker compose up -d --force-recreate, container sinh ra tay trắng: đăng nhập lại từ đầu, node cũ thành rác trong admin console. Sửa bằng một dòng:

volumes:
  - ts-state:/var/lib/tailscale   # named volume, song qua moi recreate

Biến thể TS_STATE_DIR=/var/lib/tailscale khai tường minh cũng được. Dấu hiệu nhận biết đã dính từ lâu: mở console thấy chuỗi node trùng tên đánh số, dọn node rác và mount volume là hết vĩnh viễn.

you are logged out sau mỗi recreate: hai nghi phạm

Nghi phạm một, volume (chiếm đa số): như phần trên, state mất theo container. Kiểm nhanh: docker volume ls có volume state không, và docker inspect xem nó có thực sự mount vào /var/lib/tailscale. Nghi phạm hai, auth key ephemeral: key loại ephemeral tạo ra node tự xóa khi offline một lúc, chủ đích cho CI/job ngắn hạn. Dùng nhầm nó cho dịch vụ bền thì mỗi lần container nghỉ dài (deploy, reboot host) là node bị control server dọn, sống lại thành logged out. Kiểm loại key trong admin console → Keys; dịch vụ bền dùng key reusable, không ephemeral, gắn tag, node theo tag không hết hạn theo user.

Container không lên nổi: chuyện /dev/net/tun

Log container hiện đại loại can't create tun device hay tailscaled thoát ngay: container mặc định không có quyền tạo giao diện mạng. Cặp bắt buộc:

cap_add: [NET_ADMIN]
devices: [/dev/net/tun]

Host không cấp được tun (một số môi trường LXC, host bị bó) thì còn đường lui: chế độ userspace networking (TS_USERSPACE=true), chậm hơn nhưng chạy không cần tun; serve/funnel và outbound vẫn ổn, một số tính năng route hạn chế. Riêng Proxmox LXC có mẹo cấp tun riêng, xem bài Proxmox.

Compose mẫu đã né hết mìn

services:
  ts-app:
    image: tailscale/tailscale
    hostname: ten-dich-vu
    cap_add: [NET_ADMIN]
    devices: [/dev/net/tun]
    volumes:
      - ts-app-state:/var/lib/tailscale
    environment:
      - TS_AUTHKEY=${TS_AUTHKEY}   # key reusable + tag, nam trong .env
    restart: unless-stopped

  app:
    image: app-cua-ban
    network_mode: service:ts-app
    depends_on: [ts-app]

volumes:
  ts-app-state:

So với mẫu ở bài sidecar, đây là bản đã cài đủ dây an toàn: state bền, key qua biến môi trường, restart policy. Update image: docker compose pull && docker compose up -d: nhờ volume, node giữ nguyên danh tính.

Dọn dẹp hậu quả: node rác trong console

Sau chuỗi ngày chạy sai, console thường đầy node trùng tên offline. Dọn: admin console → Machines → xóa các bản offline (giữ bản đang active, nhìn cột Last seen). Muốn khỏi dọn tay lần sau: node nào đúng nghĩa phù du (CI runner, job) thì chủ động dùng key ephemeral để nó tự biến mất; node bền thì volume + key thường. Phân loại đúng ngay từ lúc tạo key là hết rác.

Đính chính quan trọng: image mặc định chạy userspace

Theo mã nguồn containerboot của Tailscale, biến TS_USERSPACE mặc định là bật, tức là image chạy ở chế độ userspace networking nếu bạn không khai gì. Điều đó có ba hệ quả thực tế:

  • Container vẫn lên và vào được tailnet dù không có /dev/net/tun và không có NET_ADMIN. Nhiều người tưởng thiếu hai thứ này là chắc chắn chết, không phải vậy.
  • Ở chế độ userspace, container gọi ra được và dùng được tailscale serve, nhưng không làm được subnet router và không làm được exit node. Đây mới là lúc bắt buộc phải có tun.
  • Muốn chế độ kernel, phải khai đủ ba thứ: TS_USERSPACE=false, cap_add: [NET_ADMIN], và devices: [/dev/net/tun]. Thiếu dòng đầu thì hai dòng sau không có tác dụng.

Bảng biến môi trường của image chính chủ

BiếnTác dụng
TS_AUTHKEYKhóa xác thực để đăng nhập. Cũng nhận tên TS_AUTH_KEY
TS_AUTH_ONCEChỉ đăng nhập khi chưa đăng nhập. Nên bật khi state đã bền, tránh đăng nhập lại thừa
TS_STATE_DIRThư mục lưu state của tailscaled. Đây là thứ phải nằm trên volume
TS_HOSTNAMETên node yêu cầu cấp
TS_USERSPACEChạy userspace networking, mặc định là bật
TS_ROUTESCác dải mạng con muốn quảng bá, cần chế độ kernel
TS_ACCEPT_DNSDùng cấu hình DNS của tailnet hay không
TS_SERVE_CONFIGĐường dẫn tệp cấu hình serve, dùng để phơi dịch vụ ra tailnet
TS_EXTRA_ARGSTham số thêm cho lệnh tailscale up, ví dụ --advertise-tags
TS_TAILSCALED_EXTRA_ARGSTham số thêm cho tiến trình tailscaled
TS_ENABLE_HEALTH_CHECKBật điểm kiểm tra sức khỏe tại đường dẫn /healthz
TS_LOCAL_ADDR_PORTĐịa chỉ và cổng phục vụ số liệu và điểm kiểm tra sức khỏe
TS_SOCKS5_SERVERĐịa chỉ lắng nghe cho proxy SOCKS5, hữu ích ở chế độ userspace

Mẫu compose cho hai chế độ

Chế độ kernel, dùng khi cần quảng bá mạng con hoặc làm exit node:

services:
  ts-app:
    image: tailscale/tailscale:latest
    hostname: ten-dich-vu
    environment:
      - TS_AUTHKEY=${TS_AUTHKEY}
      - TS_AUTH_ONCE=true
      - TS_USERSPACE=false
      - TS_STATE_DIR=/var/lib/tailscale
      - TS_ENABLE_HEALTH_CHECK=true
      - TS_LOCAL_ADDR_PORT=0.0.0.0:9002
    volumes:
      - ts-app-state:/var/lib/tailscale
    cap_add: [NET_ADMIN]
    devices: [/dev/net/tun]
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://localhost:9002/healthz"]
      interval: 30s
      timeout: 5s
      retries: 3
volumes:
  ts-app-state:

Chế độ userspace, dùng khi host không cấp được tun, ví dụ một số LXC hoặc nền tảng container hạn chế: bỏ ba dòng TS_USERSPACE=false, cap_add, devices. Giữ nguyên phần volume và biến còn lại.

Ba lệnh kiểm nhanh

docker exec ts-app tailscale status       # thay doi trang thai va danh sach node
docker exec ts-app tailscale netcheck     # kiem NAT va relay dang dung
docker volume inspect ts-app-state        # xac nhan volume that su ton tai
docker exec ts-app ls -la /var/lib/tailscale   # phai thay tep tailscaled.state

Thấy tệp tailscaled.state trong thư mục đó là state đang bền. Không thấy nghĩa là volume chưa gắn đúng chỗ, và lần recreate tới bạn lại mất danh tính node.

Về khóa: node dịch vụ chạy dài dùng khóa loại tái sử dụng có gắn thẻ, và trong danh sách kiểm soát truy cập cho phép thẻ đó tự cấp quyền, thì node không hết hạn theo người tạo. Đây là cách tránh việc node đột ngột rơi khỏi tailnet sau 90 ngày, một lỗi rất hay gặp mà log không nói rõ.

Câu hỏi thường gặp

Named volume hay bind mount cho TS_STATE tốt hơn?

Named volume gọn và tránh rắc rối quyền file; bind mount (./ts-state:/var/lib/tailscale) tiện backup theo thư mục dự án. Cả hai đều đạt, quan trọng là CÓ, và đừng đặt trong thư mục bị .dockerignore hay CI dọn mất.

Một compose nhiều sidecar có dùng chung một volume state được không?

Không, mỗi node một danh tính, chung state là dẫm nhau kiểu duplicate node key. Mỗi sidecar một named volume riêng.

TS_AUTHKEY bị lộ trong docker inspect thì sao?

Ai đọc được Docker socket là đọc được env, vậy nên key phải là loại quyền hẹp (tag riêng, ACL giới hạn), xoay định kỳ, và revoke được ngay trong console khi nghi lộ. Cân nhắc Docker secrets nếu chạy Swarm.

Watchtower tự update image có làm mất đăng nhập không?

Không, miễn volume state đã mount, update chỉ thay image, volume giữ nguyên danh tính. Đây chính là phép thử tốt: sau một lần auto-update mà node vẫn nguyên tên trong console nghĩa là cấu hình của bạn đã chuẩn.

Hạ tầng VPS tại Việt Nam của TND
Cloud VPS linh hoạt và VPS NVMe xung cao, IP công cộng riêng, đặt tại Việt Nam
Stack Docker + sidecar chạy sướng nhất trên máy có I/O khỏe: hàng chục container ghi log, state, database cùng lúc là đúng bài của VPS NVMe TND ổ Enterprise U.2 RAID 10. Stack nhẹ chọn Cloud VPS phổ thông, đều IP riêng, đặt tại Việt Nam, bàn giao 5 phút.
Xem VPS ổ Enterprise U.2 NVMe tại Việt NamNhu cầu nhẹ hơn? Xem VPS giá rẻ từ 129K

Bài viết liên quan