개요

K8s에 Stateful Set으로 Pod를 띄우는 경우, 각 Pod IP로 접근해야 할 필요성이 있을 수 있다. 가령 EKS의 경우 Pod가 ENI와 매핑되어 같은 VPC 내부에서 Pod IP를 통해 Pod에 접근이 가능한데, Pod의 IP를 특정하기 위해 headless 서비스를 만들 수 있다. RBAC등이 필요한 kubectl 대신 k8s 네트워크 내부에서 nslookup을 통해 IP들을 확인할 수 있다. 

golang으로 간단한 컨테이너를 생성하여 특정 서비스에 속한 pod ip를 리턴받는 도구를 만들어 본다.

 


모듈

REST API 서버를 만들기 위해 gorilla/mux 모듈을 사용하고, DNS lookup이 가능한 net 모듈을 임포트한다. \

import (
        "log"
        "net/http"
        "net"
        "fmt"
        "os"
        "time"
        "github.com/gorilla/mux"
)

API 서버

router의 handlefunc 메소드를 사용하여 api 요청을 받는다. {query} 파라미터를 GET 요청을 통해 받는다. 

func apiServer(){
        router := mux.NewRouter().StrictSlash(true)
        router.HandleFunc("/lookup/{query}", ipLookUp).Methods("GET")
        log.Fatal(http.ListenAndServe(":28080", router))
}

DNS Lookup

headless 서비스를 배포하면, k8s 네트워크 내부에서 DNS 레코드가 <SERVICE_NAME>.headless.svc.cluster.local과 같이 생성된다. 예를 들어, 8개의 statefulset nginx pod를 서비스로 expose 하고 nslookup nginx를 클러스터 네트워크 내부에서 수행하면 다음과 같은 결과를 얻을 수 있다. 

/app # nslookup nginx
Server:       10.96.0.10
Address:   10.96.0.10:53

** server can't find nginx.cluster.local: NXDOMAIN

Name:  nginx.headless.svc.cluster.local
Address: 10.1.25.109
Name:  nginx.headless.svc.cluster.local
Address: 10.1.25.111
Name:  nginx.headless.svc.cluster.local
Address: 10.1.25.112
Name:  nginx.headless.svc.cluster.local
Address: 10.1.25.116
Name:  nginx.headless.svc.cluster.local
Address: 10.1.25.107
Name:  nginx.headless.svc.cluster.local
Address: 10.1.25.106
Name:  nginx.headless.svc.cluster.local
Address: 10.1.25.119
Name:  nginx.headless.svc.cluster.local
Address: 10.1.25.108

이 과정을 golang 서버에서 수행할 수 있도록 다음과 같이 작성한다. 

func ipLookUp(w http.ResponseWriter, r *http.Request){
        vars := mux.Vars(r)
        lookUpQuery := vars["query"]
        ips, err := net.LookupIP(lookUpQuery)
        if err != nil {
                fmt.Fprintf(os.Stderr, "Could not get IPs: %v\n", err)
                fmt.Fprintf(w,"No IP Found\n")
        }
        for _, ip := range ips {
                fmt.Println("%s\n", ip.String())
                fmt.Fprintf(w,ip.String()+"\n")
        }
}

parameter로 설정한 query값을 받아 net 모듈의 LookupIP를 활용하여 lookup을 수행하고, 결과로 IP 값을 받아 리턴한다. 

서버 실행

작성한 go 애플리케이션을 컨테이너로 빌드하고 pod로 띄운 뒤, nodeport로 오픈한다. . 

(빌드 과정은  참고)

실행하여 요청을 보내면 정상적으로 ip를 리턴한다. 

$ k run lookup --image=iplookup:v1 -n headless
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/lookup created

$ k expose deploy lookup --type=NodePort -n headless --port=28080
service/lookup exposed

$ curl http://localhost:30418/lookup/nginx
10.1.25.116
10.1.25.107
10.1.25.119
10.1.25.111
10.1.25.106
10.1.25.108
10.1.25.109
10.1.25.112