APISIX용 Lua와 ChatGPT를 활용한 Custom Plugin 개발

Bobur Umurzokov

Bobur Umurzokov

June 12, 2023

Technology

Apache APISIX의 주요 기능 중 하나는 플러그인을 통해 확장 가능하다는 점입니다. APISIX는 사용자가 커스텀 플러그인을 만들어 추가 기능을 추가하고 API 트래픽을 더 효율적으로 관리할 수 있도록 합니다. 종종 Lua 프로그래밍 언어를 사용하여 새로운 플러그인을 구현하거나 플러그인 러너를 활용하여 선호하는 프로그래밍 언어로 플러그인을 개발할 수 있습니다. 그러나 APISIX는 Lua에 대한 최고의 지원을 제공합니다. Lua로 APISIX용 플러그인을 몇 개 작성해 본 후, Lua 프로그래밍의 기본을 알 필요가 없거나 이 언어에 전문가가 될 필요가 없다는 것을 깨달았습니다. ChatGPT 친구가 항상 함께하기 때문입니다. 예를 들어, Java와 C# 배경을 가진 저는 Lua로 작성된 코드와 논리를 이해할 수 있으며, 여러분도 그렇게 할 수 있다고 믿습니다.

이 글은 Lua와 ChatGPT를 사용하여 APISIX용 새로운 커스텀 플러그인인 file-proxy를 개발하는 과정을 안내합니다 (ChatGPT를 사용하여 일부 Lua 코드를 작성합니다). 이 플러그인은 정적 파일을 API를 통해 노출하고 지정된 URL에서 파일을 가져오는 데 사용됩니다.

APISIX는 Nginx의 기존 기능을 향상시키기 위해 구축되었으며, Nginx는 APISIX가 활용하는 재사용 가능한 Lua 모듈 컬렉션을 제공합니다.

학습 목표

이 글을 통해 다음을 배우게 됩니다:

  • 새로운 file-proxy 플러그인을 개발하는 방법.
  • ChatGPT를 효율적으로 사용하여 Lua 코드를 생성하는 방법.
  • APISIX용 플러그인을 직접 구축하는 단계.

새로운 file-proxy 플러그인 사용 사례

실제 플러그인 구현에 뛰어들기 전에, 왜 이 플러그인이 필요한지 먼저 이해해 봅시다. 이 글을 작성하는 시점에 APISIX는 유사한 사례를 위한 내장 플러그인을 제공하지 않을 수 있습니다. 그래서 우리가 새로운 플러그인을 만들려고 하는 것입니다. 종종 우리는 정적 파일 (Yaml, JSON, JavaScript, CSS 또는 이미지 파일)을 API를 통해 노출하고 싶어합니다.

예를 들어, APISIX API Gateway는 애플리케이션에서 라우팅을 통해 들어오는 요청을 여러 API 엔드포인트로 전달하는 프론트 도어 역할을 합니다. 이는 모든 서버 URL, 경로, 매개변수, 각 API 엔드포인트의 설명 및 입력과 출력을 정의하기에 적합한 장소입니다. 그리고 OpenAPI 스펙을 작성하여 API를 문서화합니다. OpenAPI .yaml 파일은 API 사용자가 API를 이해하고 상호 작용하는 데 도움을 주는 지도와 같습니다. 플러그인에 openapi.yaml 파일의 경로 (서버에 저장된 위치)를 제공하면 API 게이트웨이를 통해 파일을 직접 가져와 제공할 수 있으며, API 소비자에게 일관된 인터페이스를 제공합니다. 그러면 API 사용자는 지정된 URL (https://example.com/openapi.yaml)에서 .yaml 파일에 접근할 수 있습니다.

다른 사용 사례도 있습니다. 이 file-proxy 플러그인을 간단한 콘텐츠 전송 네트워크 (CDN) 대체로 사용할 수도 있습니다. 소규모 애플리케이션이 있고 완전한 CDN을 사용하고 싶지 않다면, file-proxy 플러그인을 사용하여 특정 위치에서 정적 파일을 제공할 수 있습니다. file-proxy 플러그인은 파일의 캐싱 레이어로 사용될 수도 있습니다. 가져오거나 생성하는 데 비용이 많이 드는 파일이 있다면, 플러그인을 사용하여 파일을 한 번 가져온 후 캐시된 버전을 후속 요청에 제공할 수 있습니다.

file-proxy 플러그인 개발 단계

우리는 APISIX를 로컬에서 실행하고 API Gateway는 http://localhost:9080에서 호스팅됩니다. 개발이 완료되면 서버나 클라우드 제공자에 배포할 수 있습니다. 기본적으로 우리는 openapi.yaml 파일을 http://localhost:9080/openapi.yaml 경로에 배치하려고 합니다. 이를 어떻게 달성할지 배우게 됩니다.

전제 조건

  • 시작하기 전에 APISIX에 대한 기본적인 이해가 있으면 좋습니다. API 게이트웨이와 라우트, 업스트림, Admin API, 플러그인과 같은 주요 개념에 익숙하면 도움이 됩니다. HTTP 프로토콜에 대한 기본적인 이해도 유익합니다.
  • Docker는 컨테이너화된 etcd와 APISIX를 설치하는 데 사용됩니다.
  • curl은 APISIX Admin API에 요청을 보내는 데 사용됩니다. Postman과 같은 도구를 사용하여 API와 상호 작용할 수도 있습니다.

데모 프로젝트 및 파일 이해

우리는 GitHub에 있는 기존 file-proxy 데모 프로젝트를 활용할 것입니다. 이 프로젝트는 기존 Apisix docker 예제 리포지토리와 매우 유사한 구조를 가지고 있으며, 데모를 간단하게 유지하기 위해 불필요한 파일을 제거했습니다. 프로젝트에는 3개의 폴더, docker-compose.yml, 그리고 샘플 openapi.yaml 파일이 있습니다.

  • docker-compose.yml은 APISIX와 etcd (APISIX의 구성 저장소)를 위한 두 개의 컨테이너를 정의합니다.
  • custom-plugins 폴더에는 Lua로 구현된 file-proxy 플러그인이 있습니다. 다음 섹션에서 이를 검토합니다.
  • openapi.yaml은 노출할 샘플 OpenAPI 스펙입니다.

file-proxy 플러그인 구현

우리는 ChatGPT에게 Lua로 APISIX용 커스텀 file-proxy 플러그인을 구현하는 방법을 물어봅니다. ChatGPT는 실제 구현과 거의 유사한 가이드를 생성하지만, 답변은 너무 추상적이며 프로세스를 따르면 작동하지 않는 플러그인으로 끝날 수 있습니다. 그러나 유용한 Lua 코드를 추출하는 데 도움이 됩니다. 플러그인 개발의 실제 프로세스를 알고 있다면, 이 두 지식을 실습에서 결합하는 것이 더 쉬울 것입니다.

ChatGPT로 file-proxy 플러그인 구현

1. Lua 파일 생성

프로젝트의 /custom-plugins 디렉토리에 새로운 빈 Lua 파일을 생성합니다. 파일 이름은 플러그인의 이름이어야 합니다. 예를 들어, 플러그인이 file-proxy라면 file-proxy.lua라는 파일을 생성해야 합니다.

2. APISIX에 플러그인 등록

APISIX는 이 플러그인 파일이 어디에 있는지 알고 플러그인을 실행할 수 있어야 합니다. 이를 위해 먼저 APISIX의 extra_lua_path 속성에 file-proxy.lua 파일을 찾을 수 있는 파일 경로를 정의해야 합니다. 이는 config.yaml에 추가됩니다.

apisix:
  extra_lua_path: "/opt/?.lua"
  node_listen: 9080

이제 파일 경로가 /opt/?.lua로 설정된 이유를 물어볼 수 있습니다. 왜냐하면 우리는 docker를 사용하여 APISIX를 실행하기 때문입니다. docker-compose.yml 파일에서 3개의 볼륨 ./custom-plugins:/opt/apisix/plugins:ro가 있음을 알 수 있습니다.

volumes:
      - ./apisix_conf/config.yaml:/usr/local/apisix/conf/config.yaml:ro
      - ./openapi.yaml:/usr/local/apisix/conf/openapi.yaml:ro
      - ./custom-plugins:/opt/apisix/plugins:ro

이것은 로컬 디렉토리 ./custom-plugins를 docker 컨테이너 내의 /opt/apisix/plugins 경로에 읽기 전용 볼륨으로 마운트합니다. 이렇게 하면 런타임에 APISIX에 커스텀 플러그인이 추가될 수 있습니다. 마찬가지로 다른 두 파일도 Docker 폴더에 복사됩니다.

다음 단계로, APISIX 플러그인 목록에서 플러그인을 활성화합니다. 이는 APISIX 구성 파일 (config.yaml)의 plugins 목록에 플러그인 이름을 추가하여 수행됩니다.

plugins:
  - file-proxy

이 작업은 config-default.yaml에 지정된 모든 기존 기본 플러그인을 재정의합니다. 커스텀 플러그인을 다른 플러그인과 함께 사용하려면 수동으로 추가해야 합니다.

3. File proxy 플러그인 Lua 코드 분석

지금까지 우리는 단순히 아무것도 하지 않는 플러그인을 등록했습니다. 이제 이를 구현할 시간입니다. 플러그인 로직은 Lua 함수로 구현됩니다. **file-proxy.lua**에서 어떻게 구현되었는지 확인할 수 있습니다.

file-proxy.lua 파일을 분석하여 코드 구조와 흐름을 더 잘 이해하고 새로운 플러그인을 직접 만들 수 있도록 도와줍니다. ChatGPT에게 Lua 코드를 설명하도록 요청할 수 있습니다.

ChatGPT로 Lua 코드 설명

실제로 우리는 코드에 대한 꽤 좋은 설명을 얻었습니다 (부분적으로 ChatGPT가 작성했기 때문입니다).

이미지 설명

저는 이 코드의 중요한 부분만 설명하여 여러분이 길을 잃거나 AI에 완전히 의존하지 않도록 하겠습니다.

4. 플러그인 파일 구조

모든 플러그인 Lua 파일은 다음과 같은 구조를 가져야 합니다.

1. 모듈: 플러그인에 필요한 모듈/라이브러리를 가져옵니다.

local core = require("apisix.core")
...

2. 플러그인 이름: 모든 플러그인은 고유한 이름을 가지며, Lua 파일 이름과 동일할 수 있습니다.

local plugin_name = "file-proxy"

3. 플러그인 스키마: 모든 플러그인은 플러그인 스키마를 가지며, 여기서 일반적으로 플러그인에 대한 입력을 지정합니다. 입력은 APISIX 라우트 구성에서 전달되며, 나중에 플러그인을 테스트할 때 볼 수 있습니다. file-proxy 플러그인의 경우, 플러그인은 파일을 읽고 응답을 반환하기 위해 파일 경로가 필요하므로 매개변수는 path이며 문자열 타입입니다. 스키마는 다른 프로그래밍 언어에서 매개변수를 가진 메서드 선언과 같이 이해할 수 있습니다.

local plugin_schema = {
    type = "object",
    properties = {
        path = {
            type = "string" -- 제공할 파일의 경로
        },
    },
    required = {"path"} -- 경로는 필수 필드입니다
}

4. 플러그인 정의: 플러그인 구현의 매우 중요한 부분으로, version, priority, name, schema 속성을 가진 테이블로 정의됩니다. nameschema는 앞서 정의한 플러그인의 이름과 스키마입니다. versionpriority는 APISIX가 플러그인을 관리하는 데 사용됩니다. 버전은 일반적으로 현재 사용 중인 버전을 나타냅니다. 플러그인 로직을 업데이트하면 1.1이 될 수 있습니다 (원하는 버전을 설정할 수 있습니다). 그러나 우선순위를 선택할 때 매우 주의해야 합니다. priority 필드는 플러그인이 실행될 순서와 단계를 정의합니다. 예를 들어, 우선순위가 3000인 'ip-restriction' 플러그인은 우선순위가 0인 'example-plugin'보다 먼저 실행됩니다. 이는 'ip-restriction' 플러그인의 더 높은 우선순위 값 때문입니다. 자신의 플러그인을 개발할 때 기존 플러그인의 순서를 따르지 않으면 순서가 엉망이 될 수 있으므로 주의해야 합니다. config-default.yaml 파일에서 기존 플러그인의 순서를 확인하고 Apache APISIX 플러그인 개발 가이드를 열어 확인할 수 있습니다.

local _M = {
    version = 1.0,
    priority = 1000,
    name = plugin_name,
    schema = plugin_schema
}

5. 스키마 검사: check_schema Lua 함수는 플러그인 스키마에 대해 라우트 구성 (테스트 섹션에서 곧 볼 수 있음)을 검증하는 데 사용됩니다.

-- 플러그인 구성이 올바른지 확인하는 함수
function _M.check_schema(conf)
  -- 스키마에 대해 구성 검증
  local ok, err = core.schema.check(plugin_schema, conf)
  -- 검증이 실패하면 false와 오류 반환
  if not ok then
      return false, err
  end
  -- 검증이 성공하면 true 반환
  return true
end

6. 플러그인 로직: access 함수는 주요 플러그인 로직을 작성할 수 있는 핵심 함수입니다. 이 함수는 Nginx 요청 처리 파이프라인의 액세스 단계에서 호출되며, 트래픽을 제어하고 사용자 정의 지시문을 작성합니다. file-proxy의 경우, 플러그인 구성에 지정된 파일을 열고 내용을 읽은 후 내용을 응답으로 반환해야 합니다. 파일을 열 수 없는 경우 오류를 기록하고 404 Not Found 상태를 반환합니다. 이 작업을 ChatGPT에게 맡겼습니다.

ChatGPT로 file-proxy 플러그인 Lua 코드 구현

코드를 구조화하고 리팩토링한 후, 아래와 같이 보입니다.

function _M.access(conf, ctx)
  -- 구성에 지정된 파일 열기
  local fd = io.open(conf.path, "rb")
  -- 파일이 성공적으로 열리면 내용을 읽고 응답으로 반환
  if fd then
    local content = fd:read("*all")
    fd:close()
    ngx.header.content_length = #content
    ngx.say(content)
    ngx.exit(ngx.OK)
  else
    -- 파일을 열 수 없는 경우 오류를 기록하고 404 Not Found 상태 반환
    ngx.exit(ngx.HTTP_NOT_FOUND)
    core.log.error("File is not found: ", conf.path, ", error info: ", err)
  end
end

7. 로깅 로직: 플러그인 구성을 로깅하는 것이 항상 선호됩니다. 이를 통해 플러그인이 예상대로 작동하는지 디버깅하고 확인할 수 있습니다. 플러그인에 대한 요청과 응답을 로깅할 수 있습니다.

-- 로그 단계에서 호출될 함수
function _M.log(conf, ctx)
    -- 플러그인 구성과 요청 컨텍스트 로깅
    core.log.warn("conf: ", core.json.encode(conf))
    core.log.warn("ctx: ", core.json.encode(ctx, true))
end

Apache APISIX 설치

커스텀 file-proxy 플러그인을 개발하고 APISIX에 등록하는 방법을 배웠으니, 이제 플러그인을 테스트할 시간입니다. apisix-file-proxy-plugin-demo 프로젝트를 포크/클론한 후 프로젝트 루트 폴더에서 docker compose up을 실행하여 쉽게 설치할 수 있습니다.

file-proxy 플러그인을 사용한 라우트 생성

새로운 file-proxy 플러그인을 사용하고 테스트하기 위해 APISIX에서 플러그인을 사용하는 라우트를 생성해야 합니다.

curl "http://127.0.0.1:9180/apisix/admin/routes/open-api-definition" -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
   "name":"OpenAPI Definition",
   "desc":"Route for OpenAPI Definition file",
   "uri":"/openapi.yaml",
   "plugins":{
      "file-proxy":{
         "path":"/usr/local/apisix/conf/openapi.yaml"
      }
   }
}'

ChatGPT에게 위 구성을 설명하도록 요청할 수 있습니다.

ChatGPT로 Lua 코드 설명

플러그인 테스트

그런 다음, 라우트에 cURL 요청을 보내거나 브라우저에서 http://127.0.0.1:9080/openapi.yaml 링크를 열 수 있습니다. 응답은 지정된 URL에 있는 openapi.yaml 파일의 내용이어야 합니다.

curl -i http://127.0.0.1:9080/openapi.yaml

플러그인은 예상대로 작동합니다. 이 플러그인 구성을 사용하면 이제 지정된 라우트를 사용하여 모든 파일에 접근할 수 있습니다.

요약

Lua로 APISIX용 커스텀 플러그인을 개발하는 것은 API 게이트웨이의 기능을 확장하는 강력한 방법입니다. 이 글에서는 file-proxy 플러그인을 만드는 방법을 보여주었고, 플러그인 정의와 스키마를 정의하고, 플러그인 구성을 검증하고, APISIX의 요청 처리 파이프라인의 액세스 및 로그 단계에서 사용자 정의 로직을 구현했습니다. ChatGPT는 이 프로그래밍 언어에 대한 지식이 부족한 부분을 채우는 데 도움을 주었습니다. 즐거운 코딩 되세요!

관련 자료

Tags: