Tailscale Mesh กับ GreenOps Sustainability —
Tailscale Mesh VPN
Tailscale เป็น Mesh VPN ที่สร้างบน WireGuard ให้อุปกรณ์เชื่อมต่อกันโดยตรง ไม่ต้องผ่าน Central Server ติดตั้งง่าย ไม่ต้อง Config Firewall รองรับทุก Platform
GreenOps นำ Sustainability เข้ามาใน IT Operations ลดพลังงานและ Carbon Emissions ใช้ Carbon-aware Computing Right-sizing Auto-scaling เลือก Green Regions
Tailscale Setup และ Configuration
# === Tailscale Installation และ Configuration ===
# 1. ติดตั้ง Tailscale
# Linux
curl -fsSL https://tailscale.com/install.sh | sh
# macOS
brew install tailscale
# Docker
docker run -d --name=tailscale \
--hostname=my-server \
-v /var/lib/tailscale:/var/lib/tailscale \
-v /dev/net/tun:/dev/net/tun \
--cap-add=NET_ADMIN \
--cap-add=NET_RAW \
tailscale/tailscale:latest
# 2. เชื่อมต่อ
sudo tailscale up
# เชื่อมต่อพร้อม Options
sudo tailscale up \
--advertise-routes=10.0.0.0/24,192.168.1.0/24 \
--accept-dns=true \
--hostname=web-server-1
# 3. ตรวจสอบสถานะ
tailscale status
tailscale ip -4
tailscale netcheck
tailscale ping other-device
# 4. Exit Node (Route Internet Traffic)
# บน Exit Node Server
sudo tailscale up --advertise-exit-node
# บน Client
sudo tailscale up --exit-node=exit-node-hostname
# 5. Tailscale SSH
# เปิด Tailscale SSH
sudo tailscale up --ssh
# SSH โดยไม่ต้อง Config Keys
ssh user@device-name
# 6. ACL Policy (tailscale admin console)
# {
# "acls": [
# // Dev team สามารถเข้าถึง Dev servers
# {
# "action": "accept",
# "src": ["group:dev"],
# "dst": ["tag:dev-server:*"]
# },
# // Ops team เข้าถึงทุก Server
# {
# "action": "accept",
# "src": ["group:ops"],
# "dst": ["tag:server:*"]
# },
# // ทุกู้คืนเข้าถึง DNS
# {
# "action": "accept",
# "src": ["*"],
# "dst": ["*:53"]
# }
# ],
# "groups": {
# "group:dev": ["user1@example.com", "user2@example.com"],
# "group:ops": ["admin@example.com"]
# },
# "tagOwners": {
# "tag:dev-server": ["group:ops"],
# "tag:server": ["group:ops"]
# }
# }
echo "Tailscale configured"
echo " Mesh VPN: WireGuard-based P2P"
echo " Exit Node: Route internet traffic"
echo " SSH: Passwordless via Tailscale"
echo " ACL: Role-based access control"
GreenOps Automation
# greenops.py — GreenOps Automation สำหรับ Cloud
# pip install boto3 requests
from dataclasses import dataclass, field
from typing import List, Dict, Optional
from datetime import datetime, timedelta
import json
@dataclass
class CloudResource:
id: str
name: str
type: str # ec2, rds, eks, lambda
region: str
instance_type: str
cpu_avg: float # % average CPU utilization
monthly_cost: float
carbon_kg: float # estimated monthly CO2 kg
tags: Dict[str, str] = field(default_factory=dict)
@dataclass
class GreenRecommendation:
resource_id: str
action: str # rightsize, shutdown, migrate, spot
current_cost: float
projected_cost: float
carbon_saved_kg: float
priority: str # high, medium, low
class GreenOpsAnalyzer:
"""GreenOps Analyzer สำหรับ Cloud Resources"""
# Carbon intensity per region (gCO2/kWh)
CARBON_INTENSITY = {
"us-east-1": 379, # Virginia
"us-west-2": 78, # Oregon (hydro)
"eu-west-1": 296, # Ireland
"eu-north-1": 8, # Stockholm (hydro+wind)
"ap-northeast-1": 462, # Tokyo
"ap-southeast-1": 408, # Singapore
"ca-central-1": 22, # Canada (hydro)
}
GREEN_REGIONS = ["eu-north-1", "ca-central-1", "us-west-2"]
def __init__(self):
self.resources: List[CloudResource] = []
self.recommendations: List[GreenRecommendation] = []
def add_resource(self, resource: CloudResource):
self.resources.append(resource)
def analyze(self):
"""วิเคราะห์ Resources สำหรับ GreenOps"""
self.recommendations = []
for r in self.resources:
# 1. Right-sizing: CPU < 10% = oversized
if r.cpu_avg < 10 and r.type == "ec2":
self.recommendations.append(GreenRecommendation(
resource_id=r.id,
action=f"Rightsize {r.instance_type} -> smaller",
current_cost=r.monthly_cost,
projected_cost=r.monthly_cost * 0.5,
carbon_saved_kg=r.carbon_kg * 0.5,
priority="high",
))
# 2. Idle Resources: CPU < 2%
if r.cpu_avg < 2:
self.recommendations.append(GreenRecommendation(
resource_id=r.id,
action=f"Shutdown idle {r.name}",
current_cost=r.monthly_cost,
projected_cost=0,
carbon_saved_kg=r.carbon_kg,
priority="high",
))
# 3. Region Migration
if r.region not in self.GREEN_REGIONS:
green_region = "eu-north-1"
carbon_ratio = self.CARBON_INTENSITY.get(green_region, 100) / \
self.CARBON_INTENSITY.get(r.region, 400)
self.recommendations.append(GreenRecommendation(
resource_id=r.id,
action=f"Migrate {r.region} -> {green_region}",
current_cost=r.monthly_cost,
projected_cost=r.monthly_cost * 1.05,
carbon_saved_kg=r.carbon_kg * (1 - carbon_ratio),
priority="medium",
))
def dashboard(self):
"""แสดง GreenOps Dashboard"""
self.analyze()
total_cost = sum(r.monthly_cost for r in self.resources)
total_carbon = sum(r.carbon_kg for r in self.resources)
potential_savings = sum(r.current_cost - r.projected_cost for r in self.recommendations)
potential_carbon = sum(r.carbon_saved_kg for r in self.recommendations)
print(f"\n{'='*60}")
print(f"GreenOps Dashboard — {datetime.now().strftime('%Y-%m-%d')}")
print(f"{'='*60}")
print(f" Resources: {len(self.resources)}")
print(f" Monthly Cost: ")
print(f" Monthly Carbon: {total_carbon:,.0f} kg CO2")
print(f"\n Potential Savings:")
print(f" Cost: /month")
print(f" Carbon: {potential_carbon:,.0f} kg CO2/month")
# By Region
print(f"\n Carbon by Region:")
region_carbon = {}
for r in self.resources:
region_carbon[r.region] = region_carbon.get(r.region, 0) + r.carbon_kg
for region, carbon in sorted(region_carbon.items(), key=lambda x: -x[1]):
intensity = self.CARBON_INTENSITY.get(region, 0)
green = " (GREEN)" if region in self.GREEN_REGIONS else ""
print(f" {region:<20} {carbon:>8,.0f} kg ({intensity} gCO2/kWh){green}")
# Top Recommendations
print(f"\n Top Recommendations:")
high = [r for r in self.recommendations if r.priority == "high"]
for rec in high[:5]:
print(f" [{rec.priority:>6}] {rec.action}")
print(f" Save: /mo, "
f"{rec.carbon_saved_kg:,.0f} kg CO2")
# ตัวอย่าง
analyzer = GreenOpsAnalyzer()
resources = [
CloudResource("i-001", "web-prod-1", "ec2", "us-east-1", "m5.xlarge", 45, 140, 35),
CloudResource("i-002", "web-prod-2", "ec2", "us-east-1", "m5.xlarge", 42, 140, 35),
CloudResource("i-003", "dev-server", "ec2", "us-east-1", "m5.2xlarge", 3, 280, 70),
CloudResource("i-004", "staging", "ec2", "ap-northeast-1", "m5.large", 8, 90, 28),
CloudResource("i-005", "ml-training", "ec2", "us-west-2", "p3.2xlarge", 65, 2200, 120),
]
for r in resources:
analyzer.add_resource(r)
analyzer.dashboard()
Tailscale + GreenOps Monitoring
# === Monitoring Stack สำหรับ Tailscale + GreenOps ===
# docker-compose.yml
# version: '3.8'
# services:
# prometheus:
# image: prom/prometheus:latest
# ports:
# - "9090:9090"
# volumes:
# - ./prometheus.yml:/etc/prometheus/prometheus.yml
#
# grafana:
# image: grafana/grafana:latest
# ports:
# - "3000:3000"
# environment:
# GF_SECURITY_ADMIN_PASSWORD: admin
#
# tailscale-exporter:
# image: custom/tailscale-exporter:latest
# environment:
# TAILSCALE_API_KEY:
# prometheus.yml
# scrape_configs:
# - job_name: tailscale
# static_configs:
# - targets: ['tailscale-exporter:9100']
# - job_name: node
# static_configs:
# - targets: ['node-exporter:9100']
# === Tailscale API Client ===
# tailscale_monitor.py
import json
from datetime import datetime
class TailscaleMonitor:
"""Monitor Tailscale Network"""
def __init__(self):
self.devices = []
def add_device(self, name, ip, os, online, last_seen, rx_bytes, tx_bytes):
self.devices.append({
"name": name, "ip": ip, "os": os,
"online": online, "last_seen": last_seen,
"rx_bytes": rx_bytes, "tx_bytes": tx_bytes,
})
def network_status(self):
print(f"\n{'='*55}")
print(f"Tailscale Network Status")
print(f"{'='*55}")
online = sum(1 for d in self.devices if d["online"])
total = len(self.devices)
print(f" Devices: {online}/{total} online")
total_rx = sum(d["rx_bytes"] for d in self.devices)
total_tx = sum(d["tx_bytes"] for d in self.devices)
print(f" Traffic: RX {total_rx/1e9:.1f} GB | TX {total_tx/1e9:.1f} GB")
for d in self.devices:
status = "ONLINE" if d["online"] else "offline"
print(f" [{status:>7}] {d['name']:<20} {d['ip']:<16} {d['os']}")
monitor = TailscaleMonitor()
monitor.add_device("web-prod-1", "100.64.0.1", "linux", True, "now", 5e9, 3e9)
monitor.add_device("web-prod-2", "100.64.0.2", "linux", True, "now", 4e9, 2e9)
monitor.add_device("dev-laptop", "100.64.0.3", "macos", True, "now", 2e9, 1e9)
monitor.add_device("ci-runner", "100.64.0.4", "linux", False, "2h ago", 1e9, 0.5e9)
monitor.network_status()
Best Practices
- ACL First: ตั้ง ACL Policy ก่อนเพิ่ม Devices กำหนดสิทธิ์ตาม Role
- MagicDNS: เปิด MagicDNS ใช้ Hostname แทน IP เช่น ssh web-prod-1
- Exit Nodes: ใช้ Exit Nodes สำหรับ Route Traffic ผ่าน Region ที่ต้องการ
- Green Regions: เลือก Cloud Region ที่ใช้พลังงานสะอาด เช่น eu-north-1, ca-central-1
- Right-sizing: Review Instance Sizes ทุกเดือน ลดขนาดที่ CPU ต่ำกว่า 10%
- Auto-shutdown: ตั้ง Schedule ปิด Dev/Staging นอกเวลาทำงาน
Tailscale คืออะไร
Mesh VPN บน WireGuard อุปกรณ์เชื่อมต่อ P2P ไม่ผ่าน Central Server ติดตั้งง่าย ไม่ต้อง Port Forwarding รองรับทุก Platform SSO Login ACL ควบคุมสิทธิ์