Ready to speed up your Kong Lua custom plugin development process?
1. Before diving into this post, make sure you’re familiar with the basics of plugin development and have gone through the basics described in our Kong documentation.
Plugin Development Environments
Now, let’s dive in…here are the best practices for Kong custom plugins that will help you standardize processes and speed up development.
2. Two crucial pieces of tooling will help you get started with custom plugin development. I recommend that developers use these two projects to jump-start the development of their custom plugins. Those include:
- Pongo allows you to run automated tests against custom plugins simply. In addition to unit and integration testing, you can also perform code linting and packaging of plugins. Here are the various operations you can perform using Pongo.
- Kong provides a plugin template as a starting point for developing custom plugins for Kong. It includes a readily working custom plugin, unit and integration tests, as well as all the default configuration files.
3. Nothing should be hardcoded in the plugin. You should provide all external configurations for a plugin via plugin configuration.
4. You should perform validation for all fields in the plugin configuration. All fields should have appropriate types and default values (as applicable) and be specified as optional or mandatory.
5. You should configure entity checks to validate fields using the various field validators that Kong provides or using custom validators validators only if necessary. Always make sure that your plugin schema is declarative.
6. A common mistake here is that a field in the schema.lua is given a default value, but a required flag is not specified. This will allow users to configure a JSON null value and set the field to an empty value.
Implementing Custom Logic
7. Use the Plugin Development Kit (PDK) for calling Kong internal functions when implementing custom logic. Do not call Nginx variables directly unless absolutely necessary. The Kong PDK is guaranteed to be forward compatible and provides various helper functions to manipulate the API request and response.
8. Do not block when performing your operations because it will add latency to your API request. Any non-blocking I/O will also incur the same latency, and these result in requests sitting on the CPU, blocking other requests as well, impacting Kong’s performance as a whole. When calling any external entities, configure a timeout for the call. Ensure that any libraries used work with OpenResty/Nginx; do not use libraries designed to work with standalone Lua.
9. Every plugin feature should be accompanied by unit and integration tests with high coverage of the plugin functionality. Define unit tests for testing sub-modules of your plugin and integration tests for end-to-end testing against various Kong versions, data sources and requests.
10. Ensure that tests cover all possible flows or plugin usage. Use luacov for test coverage analysis.
11. Ensure performance/load testing with the plugin enabled. You can use various tools for load testing; one example is k6. Load tests should cover multiple test cases such as performance under load, single users, multiple users, low to high request rates. Capture and report on the load test scripts above using Kong latency metrics HTTP Header “X-Kong-Proxy-Latency.”
12. Follow a test-driven approach. That means you should define the tests first, implement your plugin and make the tests pass.
13. Kong comes with a set of test-helpers that make testing easier. Use Pongo to generate the help files using pongo docs.
Logging and Error Handling
14. Use appropriate levels when logging. The happy path of plugin execution should have minimal logs at the notice/info level, while error flows should log all warnings and errors at their respective log levels. All plugins should log a good amount of information at a debug level that can be used for troubleshooting purposes when required.
15. Catch and Log errors in plugin execution, especially flows that involve calling external systems.
16. Consider using (x)pcall for protected execution https://www.lua.org/pil/8.4.html when making function calls.
17. Make use of the kong.log and kong.inspect() PDK functions to log information in your plugins. Ensure that the various log entries use appropriate log levels based on the severity of the log message.
18. Full access to the Kong datastore in custom plugins is only available in the classic mode of deployment. Learn more about storing and accessing custom entities. We encourage using Redis as a datastore for custom plugins, as your plugins will also be compatible with Hybrid and DB-less modes.
19. In hybrid mode, you can create custom entities from a control plane but not from a data plane. So configuring Kong on the CP (adding a basic-auth credential, for example) is available, but writing in-band data (like a rate-limiting counter) is unavailable.
20. When using the Hybrid deployment mode, use Redis for accessing data in-band between data plane nodes.
21. Optimizing frequently accessed data by custom plugins by using:
- The plugin context to share objects between phases of a plugin execution
- Nginx shared dictionaries for sharing objects between workers. Use locks to prevent concurrent access issues.
- The Kong cache to access database entities or store custom entities (classic mode only).
- Redis as a shared cache between various Kong nodes (applicable to Hybrid or Classic Mode).
22. Depending on the Kong deployment platform, there are various mechanisms for deploying custom plugins:
23. For deployments on Docker and Kubernetes, create a custom image from the Kong image, which installed the custom plugin. This will ensure that all Kong instances from this image already have the custom plugin installed. You could build a custom image using docker-kong.
24. When distributing plugins, there are two options;
- Distributing Kong and each plugin individually. Each component can have its own version, but you can make many different combinations that you might want to test.
- Create a “golden image/package” containing the Kong distro and the custom plugins. This limits the number of possible combinations, but now the underlying artifacts create one new artifact that also needs a version.
CI for Custom Plugins
25. Pongo can be used for automated builds, testing and packaging for Kong custom plugins. The Kong plugin template consists of a reference travis.yml file for performing CI using Kong:
- Run pongo up and pongo build to bring up the pongo dependencies
- Run pongo lint to check for static errors
- Run pongo run to run automated tests
- Run pongo pack to produce a rock file
- docker kong script to create a custom Kong image from this rock file with the plugin embedded
26. Add comments to code, including function headers.
27. If a single Lua file becomes too big, separate functions into a separate Lua file for re-usability.
28. Write a Readme for the plugin that includes:
- Install instructions for all target Kong deployments (Ubuntu, Docker, K8S)
- Provide example curl/httpie commands to enable and configure the plugin.
- Document details for each parameter defined in the plugin schema
- Usage examples
- Known issues
- Version history/changelog
- Any other helpful information for this particular plugin
Follow this tutorial to create your custom Lua plugin for Kong Gateway.
Have questions or want to stay in touch with the Kong community? Join us wherever you hang out: