Programming/Django

[Django, Docker] gunicorn에 vscode debugger 붙이기

stein 2021. 10. 20. 10:54

※ gunicorn을 쓰지 않더라도 적용가능하니, 읽은 후 게시글 하단을 참고

What I want.

django 작업을 하다보면 당연히 에러가 생기고, 어떤 변수에 어떤 값이 들어있는지 확인하는 경우가 많다. 현재 필자는 django가 docker container 내부에 있기 때문에 다음과 같은 일련의 과정을 거친다.

 

1. 해당 컨테이너의 로그를 띄워놓음(또는 docker-compose log)

2. 에러가 발생하는 지점 근처에 "감으로" 변수를 출력하는 print문을 출력

3. 코드를 저장 -> 코드를 실행 -> 코드를 저장(저장을 해야 로그가 다시 뜬다)

4. 변수 확인후 "아 이게 아니구나" 후 다른 변수 출력하는 print 추가

5. 2~5무한반복

 

꽤나 귀찮고 은근히 시간이 많이 드는 일이다. 이런 와중에 vscode의 django debugger의 존재를 알게 되었고, container에 붙여보았다. 

 

나름 까다로운 부분들이 있던 작업이었다. 한 번 살펴보자.

※현재 필자는 (django, gunicorn)->nginx->외부 연결로 docker container들이 구성되어있다. 


개요 설명

필자가 생각한 이상적인 시나리오는

 

django가 debug 모드로 실행되면 vscode의 debugger가 새로운 창을 바로 여는 것(attach visual studio code)

 

이었다.

하지만 아직까지 vscode의 debugger를 실행시키는 과정자체는 필요해 보였다. 따라서 다음과 같이 시나리오를 수정했다.

 

django가 debug 모드로 실행되면 vscode로 접속해서 debugger를 작동시킬 수 있는 것

 

여기서 문제들은

1. django에 debugger가 붙으려면 debuger가 django를 실행시켜야한다. 하지만 이미 container 내부에는 django(gunicorn)가 돌고 있는데, django container는 django(gunicorn)가 꺼지면 container 자체가 내려간다.

2. gunicorn 종료 방법

3. vscode debugger 실행시 참고할 launch.json 생성

 

하나씩 살펴보자

 

django(gunicorn)을 종료 하면서 container를 유지시키는 방법

 

Docker container will automatically stop after "docker run -d"

According to tutorial I read so far, use "docker run -d" will start a container from image, and the container will run in background. This is how it looks like, we can see we already have container...

stackoverflow.com

docker container는 선언된 작업이 모두 종료되면 container 자체가 내려간다. 따라서 sh를 열어두거나 tail로 dev/null을 출력하는 형태로 꺼지지 않는 작업을 추가해준다. 필자는 docker-compose에 다음과 같은 코드를 사용했다

모든 작업 뒤에 tail -F /dev/null을 추가한다. (tail: 파일의 끝을 출력, -F: follow 계속해서 출력, /dev/null: 읽을 파일, 리눅스의 휴지통(완전삭제))

실행될 명령어 앞에 추가하면 그 뒤 명령어가 돌지 않으니 주의하자.

 

자 이러면 저기 실행된 gunicorn이 꺼지더라도 container는 살아있다. 하지만 여기서 gunicorn을 어떻게 끄는가?

많은 stackoverflow가 ps로 gunicorn을 실행하는 프로세스의 pid를 찾아

kill -9 pid

를 시도하라고 한다. 현재 container가 slim-buster라 ps 가 없기 때문에 

apt-get update && apt-get install -y procps

로 ps 를 설치해준다. 그래도 필자는 gunicorn이 종료되지 않고 계속 살아났는데(!) 다음의 명령어는 작동했다

pkill gunicorn

vscode debugger를 위한 launch.json

자 이제 debugging mode로 debugger를 실행시키면 된다. 다음 코드를 django container에 vscode가 접속할 때의 root 폴더에 .vscode/launch.json에 추가해주자

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Python: gunicorn",
      "type": "python",
      "request": "launch",
      "cwd": "{manage.py가 위치하는 경로}",
      "program": "/usr/local/bin/gunicorn",
      "args": [
        "{django app이름}.wsgi:application", "--bind=0.0.0.0:8000", "--timeout=300"
      ],
    },
  ]
}

 

1. program

gunicorn의 위치를 적어주면 된다.

whereis gunicorn

whereis gunicorn

으로 확인할 수 있다

 

2. cwd

gunicorn 명령어가 app을 실행하려면 해당 django가 존재하는 경로로 이동해야하는데 이를 설정해 주는게 cwd이다.

 

3. args

gunicorn에 전달할 인자들이다. 평소에 작성하듯 넣어준뒤 --timeout={응답이 없더라도 대기할 시간}을 추가하자.

debugging중 breakpoint를 걸면 gunicorn이 오류로 인지하여 timeout 시간에 맞춰 재부팅하는 것을 막을 수 있다.

(※bind 옵션을 줄때 --bind 0.0.0.0:8000이면 작동하지 않고 --bind=0.0.0.0:8000과 같이 "="을 붙여주어야한다.)

 

사용

에러가 발생하거나 breakpoint가 걸린 지점에 코드가 도달하면 debugger가 해당 파일, 코드로 이동하여 에러를 띄워주고 그 주변 변수들의 값을 모두 보여준다!

편-안

 

이 방법으로 조금 더 편안한 debug 경험을 느낄 수 있기를 바란다.

 

주저리

어차피 debugging이기 때문에 gunicorn에 붙이지 않고 django를 manage.py runserver 로 실행해도 큰 문제는 없을 것으로 예상된다. 위와 같은 방법으로 하면 gunicorn까지 포함된 debugging을 할 수 있다는 정도의 이점이 있다. 각자의 상황에 맞춰 사용하자.

 

gunicorn->manage.py는 launch.json에서 변경하면 된다.