개요
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