λ컀 컨ν μ΄λ Go μλ²κ° SIGTERM μ 무μν μ΄μ (feat. PID 1)
λ°°κ²½
Go μ ν리μΌμ΄μ μ μ’ λ£ν λ νΉμ λ‘μ§μ μννκ³ μ νμ΅λλ€.
μ¬μ©μκ° μλμΌλ‘ (λ‘컬) μλ²λ₯Ό μ’ λ£νλ©΄ syscall.SIGINT κ°μ΄ channel μ ν λΉλλ©΄μ goroutine λ΄λΆκ° μ€νλμ΄
λ‘μ§ μν ν μ ν리μΌμ΄μ μ΄ μ’ λ£(os.Exit(1)
) λ©λλ€.μ€μ λ‘ λ‘컬μμ μλ²λ₯Ό μ€ννκ³
ctrl + C
λͺ λ Ήμ΄λ‘ μλ²λ₯Ό μ’ λ£νλ©΄ goroutine λ΄λΆ λ‘μ§μ΄ μ μ€νλμ΅λλ€.func (s *Server) StartServer() error { s.setServerInfo() channel := make(chan os.Signal, 1) signal.Notify(channel, syscall.SIGINT) // (1) λ¨μ μ’ λ£ μκ·Έλ go func() { <-channel // ... λ‘μ§ μν os.Exit(1) }() return s.engine.Listen(s.port) }
λ컀 컨ν μ΄λν νμλ μ λμν κΉ?
μ ν리μΌμ΄μ μ 컨ν μ΄λλ‘ λ§μμ¬λ € μ€ννλλΌλ μμ λ‘μ§μ΄ μ λμν κΉμ? κ·Έλ μ§ μμ΅λλ€. μ€νμ€μΈ 컨ν μ΄λλ₯Ό
stop
νλλΌλ μμ goroutine μ μνλμ§ μμ΅λλ€.μ΄λ λ컀 컨ν μ΄λμμ μ νΈ μ²λ¦¬ λ°©μμ΄ λ‘컬 νκ²½κ³Ό λ€λ₯΄κΈ° λλ¬ΈμΈλ°,
λ컀μμλ 컨ν μ΄λλ₯Ό stop ν λ, κΈ°λ³Έμ μΌλ‘SIGTERM
μ νΈλ₯Ό 보λ λλ€. (κ·Έ νμ μΌμ μκ° λμ 컨ν μ΄λκ° μ’ λ£λμ§ μμΌλ©΄SIGKILL
μ νΈλ₯Ό 보λ λλ€.)κΈ°μ‘΄ μ½λμμλ
signal.Notify(channel, syscall.SIGINT)
λ₯Ό μ¬μ©νκ³ μμ΄ μ΄ν리μΌμ΄μ μ’ λ£ μ¬μΈμΌλ‘ SIGINT μ νΈλ§μ μ²λ¦¬νκ³ μμ΅λλ€.
μ¦docker stop <container id>
λͺ λ Ή μ¬μΈμ μ²λ¦¬νμ§ λͺ»νκΈ° λλ¬Έμ, νμ¬ μ½λμμλ docker container κ° λ΄λ €κ°λ goroutine λ‘μ§μ΄ μ μμ μΌλ‘ μνλμ§ μμ΅λλ€.λ컀 컨ν μ΄λκ° κ° stop λ λλ λ‘μ§μ μννκΈ° μν΄μ signal.Notify() μ½λ λ΄λΆμ λ컀 컨ν μ΄λκ° stop λ λμ μκ·Έλμ μΈμλ‘ μΆκ°νλ©΄ λ©λλ€. κ°μ λ μ½λλ μλμ κ°μ΅λλ€.
func (s *Server) StartServer() error {
s.setServerInfo()
channel := make(chan os.Signal, 1)
signal.Notify(channel, syscall.SIGINT, syscall.SIGTERMμ) // λ¨μ μ’
λ£ μκ·Έλ + Docker container stop μκ·Έλ
go func() {
<-channel
// λ‘μ§ μν
os.Exit(1)
}()
return s.engine.Listen(s.port)
}
μ΄μ λ¬Έμ κ° λͺ¨λ ν΄κ²°λμκΉμ? μ΄λ‘ μμΌλ‘λ κ·Έλ μ΅λλ€. νμ§λ§ μ κ° μ€ννμ λ μ¬μ ν λ¬Έμ κ° νλ¦¬μ§ μλλΌκ΅¬μ. (μ§λ¦¬μ μ μ»΄μμ μλΌμ γ )
GPT μ λμμ λ°μμ΅λλ€.
Docker PID κ° 1μ΄ μλ μ μλ? λΌλ μκ°μ΄ λ€μμ§λ§, νμ€μΉ μμκΈ°μ μ€ν μ€μΈ 컨ν μ΄λμ PID λ₯Ό νμΈνμ΅λλ€.
μλλ λ€λ₯ΌκΉ PID λ 1μ΄ μλμμ΅λλ€. π₯²π₯²
$ docker top <container id> # container PID νμΈ
컨ν μ΄λμ PID 1μ΄ μ€μν μ΄μ :
PID 1 νλ‘μΈμ€λ 리λ μ€μμ μ€μν μν μ ν©λλ€. 리λ μ€ μμ€ν μμ PID 1μ
μ΅μμ νλ‘μΈμ€
μ΄λ©° μμ€ν μμ λ°μνλ μ νΈλ₯Ό μ²λ¦¬νκ³ μμ νλ‘μΈμ€κ° μ’ λ£λ λ μ’λΉ νλ‘μΈμ€λ₯Ό μ²μνλ μν μ ν©λλ€.컨ν μ΄λ νκ²½μμλ `PID 1 νλ‘μΈμ€λ λμ»€κ° μ λ¬νλ μ νΈ(SIGTERM, SIGINT λ±)λ₯Ό μ²λ¦¬νκ³ , 컨ν μ΄λ μ’ λ£ μ μ λλ‘ λ μ 리 μμ μ μνν©λλ€.
λ°λΌμ μ ν리μΌμ΄μ μ΄ PID 1λ‘ μ€νλμ§ μμΌλ©΄ μ νΈλ₯Ό μ λλ‘ μμ ν μ μκΈ° λλ¬Έμ μμνλλ‘ λ‘μ§μ΄ μ€νλμ§ μμλ κ²μ΄μμ΅λλ€.
컨ν μ΄λμ PID κ° 1μ΄ μλμλ μ΄μ
μ λ 컨ν μ΄λλ₯Ό λ컀 μ»΄ν¬μ¦λ‘ μ€ννκ³ μμμ΅λλ€.
μ»΄ν¬μ¦λ‘ μ€ννλ건 λ¬Έμ κ° μλμ§λ§ 컨ν μ΄λμ PID λ₯Ό 1λ‘ μ€ννκΈ° μν΄μ μ»΄ν¬μ¦ νμΌ λ΄λΆμ λͺ λ Ήμ΄ μμ μ΄ νμνμ΅λλ€. κΈ°μ‘΄ λ컀 μ»΄ν¬μ¦ νμΌμ μλμ κ°μ΅λλ€.
version: '3'
services:
chat_backend_1:
build:
context: ./chat_backend
dockerfile: Dockerfile
ports:
- "1011:1010"
volumes:
- ./chat_backend:/go/src/app
working_dir: /go/src/app
environment:
- GO111MODULE=on
command: sh -c "go build -o main . && ./main" # << λ³κ²½μ΄ νμν μ§μ
# ... μ΄ν μλ΅
컨ν μ΄λκ° μ€νλλ νλ‘μΈμ€κ° PID 1μ΄ λλλ‘ νλ €λ©΄, command μΉμ μμ μ μ€ν¬λ¦½νΈλ λͺ λ Ήμ΄λ₯Ό μ€νν λ
exec
λͺ λ Ήμ μ¬μ©ν΄μΌ ν©λλ€.exec
λ νμ¬ μ νλ‘μΈμ€λ₯Ό λ체νκΈ° λλ¬Έμ, μ€νλλ μ ν리μΌμ΄μ μ PID λ₯Ό 1λ‘ μ€μ ν μ μμ΅λλ€.
version: '3'
services:
chat_backend_1:
build:
context: ./chat_backend
dockerfile: Dockerfile
ports:
- "1011:1010"
volumes:
- ./chat_backend:/go/src/app
working_dir: /go/src/app
environment:
- GO111MODULE=on
command: sh -c "go build -o main . && exec ./main" # << exec μΆκ°
# ... μ΄ν μλ΅
λ³κ²½λ μ»΄ν¬μ¦ νμΌμ λΉλνμ¬ λ컀 μ»΄ν¬μ¦λ₯Ό μ€ννμ΅λλ€. κ²°κ³Όμ μΌλ‘ PID κ° 1λ‘ μ μΆλ ₯λλ κ±Έ νμΈν μ μμκ³ ,
PID 1 λ‘ μ»¨ν μ΄λλ₯Ό μ€νν νμλ μ goroutine μ½λκ° μ μμ μΌλ‘ λμνλκ±Έ νμΈν μ μμμ΅λλ€.
κ²°λ‘ :
Go μ ν리μΌμ΄μ μ λ컀 컨ν μ΄λλ‘ μ΄μν λ λ°μν μ μλ μμμΉ λͺ»ν λ¬Έμ μ ν΄κ²° κ³Όμ μ λν΄ μμ±νμ΅λλ€.
μ νΈ μ²λ¦¬μ μ€μμ±
: UNIX κ³μ΄ μ΄μ체μ μμ μ¬μ©λλ μ νΈ SIGINT μ SIGTERM μ μ°¨μ΄λ₯Ό μ΄ν΄νκ³ , 컨ν μ΄λ νκ²½μμ μ²λ¦¬νκΈ° μν΄ μ μ ν λͺ λ Ήμ΄λ₯Ό μμ§ν΄μΌ νλ μ μ λ°°μ μ΅λλ€. νΉν λ컀 컨ν μ΄λμμλ SIGTERM μ νΈ μ²λ¦¬κ° νμ!PID 1μ μν
: 컨ν μ΄λ λ΄μμ μ ν리μΌμ΄μ μ΄ PID 1λ‘ μ€νλμ΄μΌ μ νΈλ₯Ό μ λλ‘ λ°μ μ²λ¦¬ν μ μμ΅λλ€.λ컀 μ»΄ν¬μ¦ μ€μ
: exec λͺ λ Ήμ΄λ₯Ό μ¬μ©νμ¬ μ ν리μΌμ΄μ μ PID 1λ‘ μ€νν΄μΌ νλ μ μ λ°°μ μ΅λλ€. 컨ν μ΄λ μ΄μμ μμ΄ μ€μν νμ΄λΌ μκ°ν©λλ€.