ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [개인 클러스터] Tailscale 을 쿠버네티스에 배포하기
    DevOps, 클라우드/Docker & Kubernetes 2024. 7. 5. 00:52

    서론


    인터넷에서 내 클러스터로 들어오는 인바운드는 모두 허용할 수 없었다.
    외부에 노출시킬 서비스를 제외하고는 VPN 등을 통해서 접근하게 해야했다.
    기존에는 Tailscale을 통해 각 노드에 직접 접근했으나 Calico와의 충돌 문제가 있었다.

     

    Tailscale은 쿠버네티스에 배포할 수 있다.


    이게 무슨 소리냐면 VPN 대역에서만 접근할 수 있는 Tailscale 서비스를 클러스터에 배포할 수 있다는 뜻이다.
    내 사설망에 일종의 VPN Ingress-Controller가 생기는 셈이다.

    배포 유형은 3가지를 지원한다고 한다.

    1. 프록시
      • Tailscale 프록시를 통해서 쿠버네티스 서비스와 통신할 수 있도록 해준다.
      • 다만, 통신하려는 '서비스' 외에 다른 쿠버네티스 리소스에 접근하거나 제어할 수 없다.
    2. 사이드카
      • 특정 파드에 사이드카 형태로 배포한다.
      • VPN 대역에서 파드를 토출할 수 있다.
    3. 서브넷 라우터
      • 쿠버네티스 클러스터 네트워크 전체를 VPN 대역에 노출한다.
      • 쿠버네티스 네트워크 정책이나 Tailscale의 접근 제어가 허용한다면 클러스터의 모든 포드 또는 서비스에 연결할 수 있다.

    위와 같은 배포 유형 중 어떤 배포 방식을 선택할지 고민했다.

    우선 (2.) 사이드카 방식의 경우, 작은 규모의 클러스터에 불필요한 부하를 더 줄 것이라 판단했다.
    (1.) 프록시 방식은 내가 가진 규모의 클러스터에서 좀 더 모범 사례에 가까울 것 같았다.
    다만, 아직 설정할 것이 많고 이미 구축된 서비스 외에 외부에서 접근할 일이 있다면 (3.) 서브넷 라우터가 좀 더 적합한 방식일 것이라 판단했다.

     

    Tailscale를 쿠버네티스 클러스터에 배포하기


    Tailscale 관리자 콘솔

    우선 Tailscale에서 인증키를 발급받자.


    관리자 콘솔에서 Settings 탭을 누르면 좌측의 Key 메뉴에서 인증키를 발급 받을 수 있다.

    우리의 클러스터에는 외부에 노출되지 않은 서비스가 있다고 가정한다.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
            - name: nginx
              image: nginx:latest
              ports:
                - containerPort: 80
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: nginxapp
    spec:
      selector:
        app: nginx
      ports:
        - port: 80
          targetPort: 80

     

    생성한 키를 쿠버네티스의 시크릿 리소스로 생성한다.

    apiVersion: v1
    kind: Secret
    metadata:
      name: ts_key
    type: Opaque
    data:
      TAILSCALE_KEY: <YOUR_BASE64_ENCODED_TAILSCALE_KEY>
    # 평문 키를 사용할 경우
    # stringData: 
    #   TAILSCALE_KEY: <YOUR_PLAIN_TAILSCALE_KEY>

     

    앞서 등록한 시크릿 키를 활용하는 서비스 어카운트를 생성한다.


    Tailscale 파드는 서비스 어카운트에 접근해 인증할 때 시크릿 키를 사용한다.

    이 서비스 어카운트로 Tailscale 파드를 동작시키며 RBAC에서 허용된 권한으로 클러스터에 접근할 수 있다.

     

    현재의 Role을 살펴보면...

    • ts_key 시크릿 리소스에 대한 일부 read/write 권한을 허용한다.
    • 이 Role은 tailscale 서비스 어카운트에 붙어있다.
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: tailscale
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: tailscale
    rules:
      - apiGroups: [""]
        resourceNames: ["ts_key"]
        resources: ["secrets"]
        verbs: ["get", "update", "patch"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: tailscale
    subjects:
      - kind: ServiceAccount
        name: tailscale
    roleRef:
      kind: Role
      name: tailscale
      apiGroup: rbac.authorization.k8s.io

     

    이제는 Tailscale 파드를 배포하자.
    앞서 말한 것처럼 서브넷 라우터 방식으로 배포할 것이다.

    apiVersion: v1
    kind: Pod
    metadata:
      name: tailscale-subnet
    spec:
      serviceAccountName: tailscale
      containers:
        - name: tailscale
          image: ghcr.io/tailscale/tailscale:v1.68.1
          env:
            - name: TS_KUBE_SECRET
              value: ts_key
            - name: TAILSCALE_KEY
              valueFrom:
                secretKeyRef:
                  name: ts_key
                  key: TAILSCALE_KEY
            - name: TS_ROUTES
              value: "<POD_CIDR>,<SERVICE_CIDR>"
            - name: TS_USERSPACE
              value: "true"
          securityContext:
            runAsUser: 1000
            runAsGroup: 1000
          resources:
            limits:
              memory: 512Mi
              cpu: "1"
            requests:
              memory: 256Mi
              cpu: "0.2"

     

    여기서 각 env를 살펴보면 다음과 같다.

    • TAILSCALE_KEY: 먼저 등록한 tailscale 시크릿이다.
    • TS_ROUTES: CNI가 지원하는 Pod 대역, 서비스 대역을 콤마로 구분한 문자열이다.
    • TS_USERSPACE: tailscale이 유저공간 네트워킹을 사용하도록 한다.

    위와 같이 파드를 배포하고 확인해보면 다음과 같이 tailscale-subnet 파드가 생성된 것을 확인할 수 있다.
    지금은 namespace를 설정하지 않아서 default ns에 생성되었다.

    kubectl  apply -f tailscale.deployment.yaml
    pod/tailscale-subnet created
    
    kubectl get pods 
    NAME               READY   STATUS   RESTARTS      AGE
    tailscale-subnet   1/1     Running  1 (68s ago)   2m21s

     

    Tailscale 콘솔에서 라우팅 설정하기


    이제 Tailscale 관리자 콘솔에서 Machine 목록을 확인하면 서브넷 라우터로 배포한 `tailscale-subnet` 파드가 등록된 것을 확인할 수 있다.

    이제 라우팅 설정을 하기 위해 해당 머신(파드)의 라우팅 설정에 들어간다.

    라우팅 설정에는 앞서 `TSROUTE` 로 설정한 파드 CIDR 대역과 서비스 CIDR 대역이 있다.

    이 대역으로 라우팅을 허용하자.

     

    Cluster-IP로 배포된 Internal 서비스 접근하기


    라우팅 설정까지 완료하면 우린 서비스의 Cluster-IP로 접근할 수 있다.

    물론 Tailscale VPN을 켜야한다.

    내부에서만 접근할 ArgoCD 서비스를 VPN를 통해서만 접근할 수 있도록 설정했다.

    VPN 자체도 구축해보고 싶었는데 우선 편의성과 내 시간을 지키기 위해서 이 방법을 선택했다.

     

    참고


    https://tailscale.com/learn/managing-access-to-kubernetes-with-tailscale

    댓글

Designed by Tistory.