事象
preStop.httpGetに以下のような指定をした場合に、実際のhttpリクエストのpathがhttp://{podip:port}//prestop
になる。
lifecycle:
preStop:
httpGet:
scheme: HTTP
port: 80
path: "/prestop"
少なくともgojiではpat.Get("/prestop", ...)
にマッチせず404が返り、結果いきなりpodがterminateされる。
※net/httpだと//prestop
を/prestop
にリダイレクトする(go1.15.3で確認)ので結果的に到達できているかも。
原因とworkaround
こんな感じでpreStopに対するURLの組み立ての中でスラッシュが2つになってしまうようだ。
なので、pathの値から先頭のスラッシュを削って/prestop
→prestop
とすることでリクエストが到達するようになる。
github.com/kubernetes/kubernetes/pkg/kubelet/lifecycle/handlers.go@v1.19.1
func (hr *handlerRunner) runHTTPHandler(pod *v1.Pod, container *v1.Container, handler *v1.Handler) (string, error) {
// 略
url := fmt.Sprintf("http://%s/%s", net.JoinHostPort(host, strconv.Itoa(port)), handler.HTTPGet.Path)
resp, err := hr.httpGetter.Get(url)
return getHTTPRespBody(resp), err
}
ここにissueがあるけど放置されてる。
https://github.com/kubernetes/kubernetes/issues/24803
ちなみにprobeの方は
以下のような実装になっており/ping
ならhttp://{podip:port}/ping
になる。
github.com/kubernetes/kubernetes/pkg/probe/http/http.go@v1.19.1
func formatURL(scheme string, host string, port int, path string) *url.URL {
u, err := url.Parse(path)
// Something is busted with the path, but it's too late to reject it. Pass it along as is.
if err != nil {
u = &url.URL{
Path: path,
}
}
u.Scheme = scheme
u.Host = net.JoinHostPort(host, strconv.Itoa(port))
return u
}
環境
- kind 0.9.0
- k8s 1.19.1