티스토리 뷰

본문을 읽기 전에 Zombie, Orphan 프로세스란 무엇인지 알고 있을 필요가 있다. 관련된 내용은 다음 글에 매우 잘 정리가 되어 있으니 참고하기 바란다. - Zombie process reaping 에 대하여, Container에서 고려할 부분들

컨테이너를 생성할 때 한 개의 일만 처리하게 설계하면 좋겠지만 그렇지 못한 경우도 분명 생길 수 있다. 간혹 자식(child process)을 만들어서 일을 시켜야 하는 경우가 있는데 새로운 컨테이너를 생성하거나 API 통신으로 동작시키는 것보다 나은 상황이 있기 때문이다. 아무튼, 이렇게 자식 프로세스를 만들어서 일을 시켜보면 의도치 않게 자식이 고아가 되는 경우가 발생한다. 자식의 자식의 자식 이라던가... 뭐 물론 좋은 설계는 아니지만. 

이런 경우가 발생했을 때 컨테이너 내부에서 프로세스 리스트를 보면 처참하다. 혹시 ps 명령어가 컨테이너 상에 존재하지 않는다면 apt-get install procps로 설치해서 확인하도록 하자.

root     20615  0.0  0.0      0     0 ?        Zs   01:01   0:00 [python] <defunct>
root     20616  0.0  0.0      0     0 ?        Z    01:01   0:00 [python] <defunct>
root     20632  0.0  0.0      0     0 ?        Zs   Mar21   0:00 [python] <defunct>
root     20633  0.0  0.0      0     0 ?        Z    Mar21   0:00 [python] <defunct>
root     20682  0.0  0.0      0     0 ?        Zs   11:57   0:00 [python] <defunct>
root     20683  0.0  0.0      0     0 ?        Z    11:57   0:00 [python] <defunct>
root     20781  0.0  0.0      0     0 ?        Zs   11:59   0:00 [python] <defunct>
root     20782  0.0  0.0      0     0 ?        Z    11:59   0:00 [python] <defunct>
root     20879  0.0  0.0      0     0 ?        Zs   12:01   0:00 [python] <defunct>
root     20880  0.0  0.0      0     0 ?        Z    12:01   0:00 [python] <defunct>
root     21088  0.0  0.0      0     0 ?        Zs   12:05   0:00 [python] <defunct>
root     21089  0.0  0.0      0     0 ?        Z    12:05   0:00 [python] <defunct>
root     21189  0.0  0.0      0     0 ?        Zs   12:07   0:00 [python] <defunct>
root     21190  0.0  0.0      0     0 ?        Z    12:07   0:00 [python] <defunct>
root     21288  0.0  0.0      0     0 ?        Zs   12:09   0:00 [python] <defunct>
root     21289  0.0  0.0      0     0 ?        Z    12:09   0:00 [python] <defunct>
root     21387  0.0  0.0      0     0 ?        Zs   12:11   0:00 [python] <defunct>
root     21388  0.0  0.0      0     0 ?        Z    12:11   0:00 [python] <defunct>
root     21389  0.0  0.0      0     0 ?        Zs   Mar21   0:00 [python] <defunct>
root     21390  0.0  0.0      0     0 ?        Z    Mar21   0:00 [python] <defunct>
root     21910  0.0  0.0      0     0 ?        Zs   12:21   0:00 [python] <defunct>
root     21911  0.0  0.0      0     0 ?        Z    12:21   0:00 [python] <defunct>
root     22010  0.0  0.0      0     0 ?        Zs   12:23   0:00 [python] <defunct>
root     22011  0.0  0.0      0     0 ?        Z    12:23   0:00 [python] <defunct>
root     22062  0.0  0.0      0     0 ?        Zs   01:31   0:00 [python] <defunct>
root     22063  0.0  0.0      0     0 ?        Z    01:31   0:00 [python] <defunct>
root     22089  0.0  0.0      0     0 ?        Zs   12:25   0:00 [python] <defunct>
root     22090  0.0  0.0      0     0 ?        Z    12:25   0:00 [python] <defunct>
root     22189  0.0  0.0      0     0 ?        Zs   12:27   0:00 [python] <defunct>
root     22190  0.0  0.0      0     0 ?        Z    12:27   0:00 [python] <defunct>

 

자, 이 문제를 해결하기 위해 찾아보면 대부분의 글을 kubernetes 기반으로 설명한다. 하지만 우리가 지금 사용하는 건 AWS ECS 환경이다. 이 환경에서 가장 쉬운 대처는 위의 글에 있는 Docker 1.13.0부터 사용 가능한 --init option을 사용하도록 한다. 설정은 간단하다. Task definition Parameters에 initProcessEnabled를 true로 설정해주면 된다. Terraform 설정 기준으로는 다음과 같다.

  container_definitions    =<<EOF
[
  {
    ....
    "logConfiguration": {
      "logDriver": "awslogs",
      "options": {
        "awslogs-group": "/aws/ecs/${var.name}/${var.service_name}",
        "awslogs-region": "ap-northeast-2",
        "awslogs-stream-prefix": "ecs"
      }
    },
    ....
    "linuxParameters": {
      "initProcessEnabled": true
    }
  }
]
EOF

 

설정이 완료됐으면 컨테이너 안에서 프로세스의 변화를 살펴보도록 하자. 우선, 설정을 하기 이전 상태의 모습이다.

# ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  3.7 242868 75524 ?        Ss   Mar16   1:18 python -m app.main.foo
root        12  0.3  0.1   5752  3664 pts/0    Ss   22:55   0:00 /bin/bash

python 커맨드가 직접 실행되어 있는 모습이다. 다음은 initProcessEnabled 설정을 하고 나서의 모습이다.

# ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.1  0.0    940     4 ?        Ss   23:12   0:00 /sbin/docker-init -- python -m app.main.foo
root         6  0.3  0.3 137924 49312 ?        Sl   23:12   0:01 python -m app.main.foo
root        10  3.0  0.0   5752  3576 pts/0    Ss   23:19   0:00 /bin/bash

 

docker-init 프로세스로 한번 감싸져 있는 것을 확인할 수 있고 고아가 된 프로세스는 이제 init 에 의해 깔끔하게 처리된다. 애플리케이션 내에서 고아 프로세스를 찾아서 SIGKILL 하는 로직을 추가해야 하나 고민이 있었는데 간단한 설정으로 해결되었다.

 

# 마무리

고아 프로세스를 그대로 두면 시스템에서 할당 가능한 PID가 고갈되기 때문에 문제가 심각해진다. 심한 경우 시스템 구동에 필요한 프로세스가 PID 할당을 받지 못해서 구동되지 못하는 경우가 발생할 수 있기 때문이다. 혹시 여러분의 컨테이너에 같은 문제가 없는지 확인해보고 처리될 수 있기를 바란다.

댓글
최근에 올라온 글
최근에 달린 댓글
글 보관함
Total
Today
Yesterday