이전의 포스팅Zappa와 함께하는 Serverless Microservice - 희망편이었다면

이번의 포스팅은 Zappa와 함께하는 Serverless Microservice - 파멸편이라고 할 수 있다.

Zappa를 도입하면서 삽질했던 것들을 적어보려한다.

삽질 1. Package

Lambda에서는 순수 Python으로 작성된 모듈만 사용할 수 있다. 별도의 컴파일 과정이 불가능하기 때문이다.

그래서 MySQL-Python 모듈도 쓰지못하는 문제가 있었다.

이럴 때는 Lambda가 돌아가는 환경과 제일 비슷한 Amazon Linux에서 패키지를 빌드해서 사용하는 방법과

같은 기능을 하는 다른 모듈로 대체하는 방법(MySQL-Python -> pymysql)이 있다.

하지만 Zappa에서는 미리 컴파일된 패키지를 제공해서 이를 가능하게 해준다. 모든 패키지는 아니고 사람들이 자주 쓰는 일부 지원하는 패키지가 있다.

찾아보니 docker-lambda라는 프로젝트도 있어서 활용할 수 있을 것 같다. Amazon Linux의 도커 이미지로 도커 컨테이너 안에서 Lambda에 사용할 패키지를 구성해서 테스트해볼 수 있다고 한다.

삽질 2. VPC 설정

배포는 성공했다. 하지만 여전히 500 Server Error 만 뱉어대고 있다.

로그를 살펴보니 DB에 접근을 하지 못하고 있었다.

지금 사용하고 있는 DB는 AWS RDS를 VPC안에서 사용하고 있기 때문에 Lambda에서 접근하지 못했던 것이다.

따라서 Lambda에서도 VPC를 사용하면 문제해결이었다. DB에서 사용하고 있는 VPC의 Subnet과 적절한 Securety Group을 zappa_settings.json 파일에 다음과 같이 설정을 추가하자.

{
  "vpc_config": {
      "SubnetIds": [ "subnet-12345678" ],
      "SecurityGroupIds": [ "sg-12345678" ]
  }
}

이제 DB에도 잘 연결되고 만사형통인 줄 알았지만 그게 아니었다.

삽질 3. Internet Gateway 설정

보통의 기능은 정상적으로 동작하지만 외부 망으로 요청을 보내면 연결을 하지 못해서 에러가 났다.

구글링을 해보니 VPC를 사용하는 Lambda는 Public Internet에 접속하지 못한다고 한다. 하지만 역시 방법이 있었다.

해결과정

  1. VPC 설정
    VPC를 하나 생성하자. 이미 있다면 그것을 사용하면 된다.
    CIDR Block은 충분히 크게 잡는 것이 좋다.(ex. 192.168.0.0/16)

  2. Subnet 설정
    2개의 Subnet이 필요하다. CIDR Block이 겹치지 않게 설정하자.
    하나는 Public Subnet 으로, 다른 하나는 Private Subnet 으로 사용할 것이다.

  3. Internet Geteway 설정
    1번에서 생성(사용)한 VPC를 attach한 Internet Gateway를 생성한다.

  4. NAT Gateway 설정
    2번에서 생성한 Public subnet 을 선택하고 생성함(Elastic IP 필요)

  5. Route Table 설정
    1번에서 생성(사용)한 VPC를 사용하는 2개의 Route Table이 필요하다.
    이 역시 Public Route Table, Private Route Table 이다.

  • Public Route Table 의 Routes 탭에서 Destination: 0.0.0.0/0, Target을 3번에서 생성한 Internet Gateway로 설정하고, Public VPC를 연결한다.
  • Private Route Table 의 Routes 탭에서 Destination: 0.0.0.0/0, Target을 4번에서 생성한 NAT Gateway로 설정하고, Private VPC를 연결한다.

여기까지하면 AWS에서 설정은 완료된다.

  1. zappa_settings.json 파일을 수정한다. SubnetIdsPrivate SubnetSubnet Id를 넣는다.
{
  "vpc_config": {
      "SubnetIds": [ "subnet-privateSubnetId" ],
      "SecurityGroupIds": [ "sg-12345678" ]
  }
}

설정이 다 되었다면 zappa update로 다시 배포를 하면 된다.

삽질 4. 잔잔한 버그들!

아주 간헐적으로 배포를 하면 "TypeError: 'NoneType' object is not callable" 이런 에러를 뱉으면서 에러를 내뿜었다.

zappa tail로 로그를 확인해보니 ModuleNotFoundError: No module named 'numpy' Import 에러가!!

로컬에서 잘 동작했고 virtualenv에 패키지가 설치되어 있는지 확인했는데도 뭐가 문제인지 잘 몰랐다.

그래서 혹시 나와 같은 이슈가 있을까 싶어서 찾아봤더니 이런 이슈가 등록되어 있었다.

나와 같은 고민의 냄새가 난다...

평소같았으면 그저 누군가가 해결해주기를 기다렸겠지만 뭔가 파보고 싶었다.

조금 파보니 Zappa가 패키징을 할 때 로컬에서 .whl 파일을 캐싱해서 쓰는데, 나중에 다시 쓰려할 때 파일이 손상되어 있다면 exception이 발생하는 버그를 발견했다.

그래서 버그를 잡고 구글 번역기의 힘을 빌려 아래처럼 코멘트를 달았다.

Thanks to Google Translate! 👍

그리고 조금후에 PR을 달라는 답변이와서 그렇게 난 Zappa의 contributor가 될 수 있었다.(막 엄청 대단한 일은 아니지만 처음이라...)

그렇게 내가 기여한 부분이 포함되어 새 버젼이 릴리즈 되어서 사용해보는데 이번엔 다른 버그를 발견했다.

그래서 바로 다시 PR을 보냈다.(뭐든 처음이 어렵지 두번째는 아니다.)

그러다가 Zappa 슬랙을 눈팅하던 중 나처럼 버그를 발견한 사람이 나왔다.

zappa_03

이 떄다 싶어 바로 리액션을 줬다.

zappa_04

그렇게 머지가 되서 핫픽스로 릴리즈 되었다. Change Log에 내 이름이!

zappa_05

삽질기라고 시작은 했지만

사실 꽤나 재미있었던 과정이었다.

이번 삽질로 AWS 기반의 네트워크 환경에 대해서 좀 더 알게되었고, 그동안 오픈소스에 관심은 많았지만 어떻게 시작을 해야할지 몰랐었는데 이렇게 좋은 오픈소스 프로젝트에 기여도 해볼 수 있어서

뭔가 삽질기보단 성장기라고 해야 더 적절할 것 같다.

앞으로 더 성장(삽질)해야겠다.