리눅스 데몬 만들기(python) #2

Kim Seung Su
8 min readMay 4, 2018

--

지난번 포스트에서 기본적인 데몬을 만들어 봤다. 이번에는 여러 워커를 기동해서 성능을 높여보고 로그 수집도 해보고 컨테이너라이즈도 해보자.

지난번 포스트는 여기서 볼 수 있다. 리눅스 데몬 만들기(python) #1

마찬가지로 전체 소스코드는 https://github.com/HatsuneMiku3939/python3-daemon 여기서 볼 수 있다.

마지막 수정으로 백드라운드 데몬 형태로 동작하도록 수정이 되었다. 이 상태로는 개발할 때 너무 불편하니까 포어그라운드로도 동작할 수 있도록 main.py 를 수정하자.

전체 소스코드는 4-basic-daemon-foreground 디렉토리에서 볼 수 있다. 이렇게 실행 할 수 있다.

$ python3 main.py --foreground
Start Singing, PID 26710
Miku Miku Ni Shite Ageru
World is Mine
39
Miku Miku Ni Shite Ageru
World is Mine

foreground 옵션을 지정하면 pid, log 옵션이 무시된다. pid 파일은 생성되지 않고 로그를 전부 표준 출력으로 출력된다. 이제 복수의 워커를 실행 할 수 있게 수정해보자.

마스터-워커 스타일로 변경하려면 지금까지와는 다르게 수정을 많이 해야 된다. 단계적으로 수정을 해보자. 전체 소스코드는 5-daemon-multiple-worker 디렉토리에서 볼 수 있다.

먼제 우리의 서비스 로직이 들어있는 miku.py 파일을 수정하자. 시그널 핸들링과 관련된 코드를 삭제했다.

다음으로 SingingMiku 클래스를 대신해서 시그널 핸들링을 담당할 Woker 클래스를 만들자.

워커 프로세스를 포크하고 관리할 Master 클래스도 만든다.

너무 길어져서 일부분을 생략했다. 중간에 워커 프로세스를 로크하고 워커의 main 함수가 종료된 다음 바로 exit 를 하는 부분이 중요한하다.

포크를 하게되면 시그널 핸들러를 포함한 거의 모든것이 자식 프로세스로 복사되는데 exit 를 하지 않으면 워커의 main 함수가 종료되서 포크 루프의 중간으로 복귀되면서 우리가 의도 하지 않은 포크가 일어난다. 정상적으로 데몬이 종료되지 않게 되니 주의하자.

로그 파일을 지정할 경우 워커 수 만큼 로그 파일이 생성되서 읽어 어려운데 그냥 넘어가자. 나중에 해결된다.

main.py 는 거의 바뀐것이 없다. SingingMiku 인스턴스를 생성해서 서비스 로직을 바로 호출하는 대신에 Master 인스턴스를 생성하도록 수정하고 워커수를 파라메터로 받을 수 있도록 했다.

시험삼아서 100워커 쯤 뛰워보자.

$ python3 main.py --foreground --workers 100
Start Master, PID 29813
Start worker-0 PID 29814
Miku Miku Ni Shite Ageru
Start worker-2 PID 29816
... 생략
Start worker-99 PID 29913
Start Singing, PID 29913
... 생략 ...
Send Signal 15 to worker-99 PID 29913
Stop Singing, PID 29913

무지 잘된다. 로그가 너무 많아서 이제 눈으로 직접 보는건 거의 불가능해졌지만 이건 차차 해결하자. 마스터 프로세스가 SIGCHLD 를 핸들링 할 수 있게해서 의도치 않게 워커 프로세스가 종료될 경우 다시 실행할 수 있도록 하는등의 작업이 더 필요한데 하지말고 다음으로 넘어가자. 마지막까지 가면 결국 필요 없어진다.

슬슬 로그양이 늘어나서 눈으로 보는게 어려워지고 있다. 로그를 기계가 읽어들일 수 있는 형태로 바꾸자. 수십 인스턴스 이상을 운용하려면 필요한 작업이다. 먼저 로그 포멧이랑 스키마를 정한다.

모든 로그는 JSON 형태로 남기자. 가장 쉽우면서 좋은 방법이다. 스키마는 이런 형태로 할꺼다.

{
"timestamp": 타임존 정보를 포함한 밀리세컨드 단위의 시간,
"component": 로그를 출력한 컴포넌트 이름 ex) master, worker-1...etc,
"log": {
... 실제 로그(JSON) ...
}
}

타임스템프에 타임존이 없으면 나중에 크게 고생한다. 미리미리 넣어두자. 실제로는 다음과 같이 화이트스페이스가 없는 형태로 로그가 출력된다.

{"timestamp":"2018-05-04T15:20:13.445789+09:00","component":"worker-1","log":{"event":"sing","event_value":{"song":"Miku Miku Ni Shite Ageru"}}}

정의한 스키마로 로그를 남기는 Logger 클래스를 만들자.

만든 Logger 클래스는 이런 식으로 사용한다.

완성된 소스코드는 6-daemon-structured-log 디렉토리에 있다. pip 로 필요한 패키지를 설치하고 실행시켜보면 JSON 형태로 로그가 주르륵 출력된다. 눈으로 읽는건 포기하고 다음으로 넘어가자.

$ pip3 install -r requirement.txt
$ python3 main.py --foreground --workers 100

이제 컨테이너라이즈를 해보고 로그를 수집해보자. 컨테이너라이즈를 하게되면 지금까지 만들었던 백그라운드에서 데몬형태로 동작시킬 필요가 없다. Master 클래스를 완전히 삭제해버리고 main.py 도 이렇게 간단한 형태로 수정한다. 무조건 포어그라운드에서 동작시킬꺼고 워커수도 항상 1으로 고정할꺼니 불필요한 옵션들을 전부다 삭제했다.

간단하고 좋다. 컨테이너를 빌드할 때 사용할 Dockerfile 은 이렇게 생겼다. docker 랑 docker-compose 를 미리 설치해두자.

7-docker-single-process 디렉토리에 준비해돈 make 스크립트를 실행해서 컨테이너를 빌드하고 일단 실행 시켜보자.

$ make
$ docker run --rm -ti miku:latest

로그의 수집은 docker 의 로그 드라이버를 사용하자. fluentd 로 로그 드라이버를 지정하면 docker 가 알아서 로그를 fluentd 로 전송해준다. 그럼 fluentd 도 실행시키고 수집한 로그를 저장할 시스템들도 필요하다. 미리 스크립드로 전부 만들어 뒀다. docker-compose 로 자질구래한 시스템들을 실행하자.

$ make
$ sudo sysctl -w vm.max_map_count=262144
$ docker-compose up

fluentd, elasticserach, kibana가 실행된다. 중간의 sysctl 명령어는 elasticsearch 를 실행하기 위해서 필요하다. 리부팅하면 설정이 원래대로 돌아가니 걱정말고 실행하자. docker-compose 를 실행하고 10초 정도 기다렸다가 다음 명령어로 미쿠 컨테이너를 뛰우자. 10개가 켜진다.

$ make start-service

브라우저로 localhost:5601 에 접속해보면 멋들어진 화면이 나온다.

Management -> Index patterns 메뉴에서 다음과 같이 인텍스 패턴을 등록하자. 자세한 사용법은 '키바나 사용법' 같은 키워드로 검색하면 엄청나게 많이 나온다.

Time field 는 @timestampe 를 선택하고 show advanced options를 선택해서 커스텀 인택스 페턴 아이디를 miku-index-pattern 이라고 등록하자. 커스텀 인텍스 패턴은 대시보드를 불러들여올때 필요하다.

그리고 Management -> Save Objects -> import 를 선택해서 미리 만들어둔 dashboard.json를 임포트하자. 임포트 한 후 Dashboard 메뉴를 선택하면 '미쿠미쿠'라는 대시보드가 보일꺼다. 선택하면 멋들어진 대시보드가 나온다.

훌륭하다. 익셉션을 전부 캐치해서 스택 트레이스등을 로그로 뿜어내면 에러 로그도 자동으로 수집할 수 있다. 라이브 서비스라면 필요할꺼라고 생각한다. elastic-alert 등을 이용하면 더욱 좋다.

다음 명령어를 입력하면 10개나 뛰운 미쿠 컨테이너를 전부 종료할 수 있다. 물론 종료 로그들도 전부 수집된다.

$ make stop-service

docker-compose 로 뛰운 서비스들을 별도 클러스터를 구성하고 k8s 나 ECS 같은걸로 미쿠 컨테이너를 운용하면 100 인스턴스 이상 운용하면서 감시하는것도 꿈은 아니다. 이제 돈을 갈퀴로 긁어 모으는 일만 남았다.

--

--