K8S SIGTERM

Graceful Shutdown

λŒ€λΆ€λΆ„μ˜ μ„œλ²„/엔진을 κ΅¬ν˜„ν•  λ•Œ, 무쀑단 λ°°ν¬μ‹œ ν˜Ήμ€ μž„μ˜ μ’…λ£Œμ‹œμ— μ •μƒμ μœΌλ‘œ μ’…λ£Œλ˜λ„λ‘ ν•˜λŠ” 것이 μ’‹λ‹€.

Graceful shutdown 은 ν”„λ‘œκ·Έλž¨μ΄ μ’…λ£Œλ  λ•Œ μ΅œλŒ€ν•œ Side effect κ°€ 없도둝 λ‘œμ§λ“€μ„ 잘 κ°ˆλ¬΄λ¦¬ν•˜κ³  μ’…λ£Œν•˜λ„λ‘ ν•˜λŠ” 것을 λœ»ν•œλ‹€.

둜직이 μ§„ν–‰λ˜κ³  μžˆλŠ” 와쀑에 ν”„λ‘œμ„ΈμŠ€κ°€ μ’…λ£Œλ˜μ–΄λ²„λ¦¬λ©΄ μ²˜λ¦¬μ€‘μΈ 데이터가 μ¦λ°œν•  μˆ˜λ„ 있고, μ–΄λ””κΉŒμ§€ μ²˜λ¦¬μ€‘μ— λ©ˆμΆ”μ—ˆλŠ”μ§€ μΆ”μ ν•˜κΈ° νž˜λ“€μ–΄μ§€λŠ” κ²½μš°λ„ μžˆλ‹€.

보톡 SIGTERM 을 μ΄μš©ν•΄μ„œ κ΅¬ν˜„ν•œλ‹€. μ•„λž˜λŠ” graceful shutdown 을 μœ„ν•΄ Go μ—μ„œ 주둜 μ‚¬μš©ν•˜λŠ” 방법이닀.

func main() {
  stop := make(chan os.Signal, 1)
  signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)
  <-stop
  // ... 
}

μœ„μ™€ 같이 κ΅¬ν˜„ν•˜λ©΄, SIGINT 와 SIGTERM μ‹ ν˜Έκ°€ μ™”μ„λ•Œ λ°”λ‘œ μ’…λ£Œλ˜λŠ” 것이 μ•„λ‹ˆλΌ Catch ν•΄μ„œ 이후 λ‘œμ§μ„ μ΄μ–΄κ°€κ² λ‹€λŠ” λœ»μ΄λ‹€.

졜근 νšŒμ‚¬μ—μ„œ EKS ν™˜κ²½μ—μ„œ λ‹€μŒκ³Ό 같은 상황이 μžˆμ—ˆλ‹€.

A μ„œλ²„λŠ” multi pod 둜 λ™μž‘ν•˜λ©°, 일반적으둜 3개의 podκ°€ ν•­μ‹œ λ™μž‘ν•¨.

이 λ•Œ, ν•˜λ‚˜μ˜ pod μ—μ„œλ§Œ νŠΉμ • μž‘μ—…μ„ μˆ˜ν–‰ν•΄μ•Ό ν•˜κ³ , ν•΄λ‹Ή pod κ°€ μ’…λ£Œλ˜μ§€ μ•ŠλŠ” ν•œ λ‹€λ₯Έ pod λŠ” κ·Έ μž‘μ—…μ„ μ‹œλ„ν•˜λ©΄ μ•ˆλ¨.

이λ₯Ό 보μž₯ν•˜κΈ° μœ„ν•΄ redis 의 SETNX λ₯Ό μ΄μš©ν•΄ 락을 μ§‘λŠ” 방식.

μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” μ„œλ²„λŠ” SIGTERM μ‹ ν˜Έλ₯Ό λ°›μœΌλ©΄ ν•΄λ‹Ή 락을 μ‚­μ œν•˜κ³  os.Exit(1) μ’…λ£Œ.

λ¬Έμ œλŠ” μ—¬κΈ°μ„œ μ‹œμž‘λλŠ”λ°, pod κ°€ κ΅μ²΄λ˜λ©΄μ„œ ν•΄λ‹Ή μž‘μ—…μ„ μˆ˜ν–‰ν•˜μ§€ λͺ»ν•˜κ³  λ°”λ‘œ μ’…λ£Œλ˜μ—ˆλ‹€.

μ• μ΄ˆμ— λ‘œκ·Έμ‘°μ°¨λ„ μ°νžˆμ§€ μ•Šμ•˜κΈ°λ•Œλ¬Έμ—, SIGKILL 을 λ°›μ€κ²ƒμœΌλ‘œ λ³΄μ˜€λ‹€.

k8s λŠ” SIGTERM 을 보낸지 30μ΄ˆκ°€ μ§€λ‚˜λ„ ν•΄λ‹Ή μ»¨ν…Œμ΄λ„ˆκ°€ μ’…λ£Œλ˜μ§€ μ•ŠμœΌλ©΄ SIGKILL을 보낸닀.

μ„œλ²„κ°€ SIGTERM 을 λ°›μ§€ λͺ»ν–ˆλ‹€κ³  κ°€μ •ν•˜κ³  디버깅을 μ‹œμž‘ν–ˆλ‹€.

μ™œ SIGTERM 을 λͺ»λ°›μ•˜μ„κΉŒ?

μš°μ„  μ•„λž˜ λͺ…λ Ήμ–΄λ₯Ό μ΄μš©ν•΄μ„œ 싀행쀑인 pod μ—μ„œ μƒνƒœλ₯Ό μ²΄ν¬ν•΄λ³΄κΈ°λ‘œ ν–ˆλ‹€.

kubectl exec -it "..." -- /bin/sh 

$ > ps -ef

ν™•μΈν•΄λ³΄λ‹ˆ μ΄μƒν•œ 점이 λ³΄μ˜€λ‹€.

1번 ν”„λ‘œμ„ΈμŠ€κ°€ /bin/sh ./run

1번 ν”„λ‘œμ„ΈμŠ€λ₯Ό λΆ€λͺ¨λ‘œ κ°€μ§€λŠ” μžμ‹ ν”„λ‘œμ„ΈμŠ€ /bin/bash ./server

1번 ν”„λ‘œμ„ΈμŠ€μ˜ 손주(μœ„μ˜ μžμ‹ ν”„λ‘œμ„ΈμŠ€) ./server

./server λŠ” 컴파일 ν›„ λ‚˜μ˜¨ outfile (binary)

k8s λŠ” SIGTERM 을 1번 ν”„λ‘œμ„ΈμŠ€μ— 보낸닀.

λ‚΄ μ„œλ²„λŠ” 손주 ν”„λ‘œμ„ΈμŠ€κ°€ λ˜μ–΄μžˆκΈ° λ•Œλ¬Έμ— λ°›μ§€ λͺ»ν•œ 것이고, Dockerfile 을 ν™•μΈν•΄λ³΄λ‹ˆ νšŒμ‚¬μ˜ λͺ¨λ“  μ„œλ²„λŠ” μ•„λž˜μ™€ 같이 μ‹€ν–‰λ˜κ³  μžˆμ—ˆλ‹€.

...

CMD ./run

run μ΄λΌλŠ” 슀크립트λ₯Ό CMD λ₯Ό μ΄μš©ν•΄μ„œ μ‹€ν–‰ν•˜κΈ° λ•Œλ¬Έμ—, 1번 ν”„λ‘œμ„ΈμŠ€κ°€ /bin/sh κ°€ λ˜λŠ” 것.

사싀 ν•΄λ‹Ή μŠ€ν¬λ¦½νŠΈλŠ” λ ˆκ±°μ‹œμ— 가깝고 ν”„λ‘œμ„ΈμŠ€ μ‹€ν–‰ 외에 역할이 μ•„μ˜ˆ μ—†μ—ˆκΈ° λ•Œλ¬Έμ— μ•„λž˜μ™€ 같이 λ°”κΎΈκ³  μ‹€ν–‰ν•΄λ³΄μ•˜λ‹€.

...

ENTRYPOINT ./server

μœ„μ™€ 같이 ENTRYPOINT 둜 μ‹€ν–‰ν•˜κ²Œ 되면 1번 ν”„λ‘œμ„ΈμŠ€κ°€ λ‚˜μ˜ μ„œλ²„κ°€ 되기 λ•Œλ¬Έμ—, SIGTERM 을 받을 수 있게 λœλ‹€.

사싀 ν•΄κ²° λ°©λ²•μœΌλ‘œ Helm chart μ—μ„œ preStop 등을 μ΄μš©ν•΄ SIGTERM 을 μ „νŒŒν• κΉŒλ„ μ‹Άμ—ˆμ§€λ§Œ, ꡳ이 그럴 ν•„μš”κ°€ μžˆλ‚˜ μ‹Άμ–΄μ„œ ν•„μžλŠ” μœ„μ™€ 같이 ν•΄κ²°ν–ˆλ‹€.

ν…ŒμŠ€νŠΈ ν•˜κ³  μ‹Άλ‹€λ©΄ 직접 배포λ₯Ό λ‹€μ‹œ 해봐도 되고 kubectl delete pod β€œβ€¦β€ μ»€λ§¨λ“œλ₯Ό μ‹€ν–‰ν•΄μ„œ 둜그λ₯Ό μ‚΄νŽ΄λ΄λ„ 되고, deployment λ₯Ό μˆ˜μ •ν•˜λ©΄μ„œ ν…ŒμŠ€νŠΈ ν•˜λ˜κ°€β€¦ 뭐 방법이야 λ§Žμ„ 것 κ°™λ‹€.

νŽΈν•œ λ°©μ‹λŒ€λ‘œ ν•˜μž.

Last updated