Debug a Kong Go Plugin Issue on Kubernetes
In my previous post (I know it has been a while…🐢) I talked about how to use Kong Go plugin. I was using Docker for my demo at the time and everything works just fine. Recently I run into an issue where my golden image failed to start on kubernetes but it works fine with docker. After debugging this issue, I think it is worthy to write down the debugging process in the hope that it will help someone in the future.
Let’s get start.
Preparation
I still use go-hello plugin from official repo in our example and build my golden image on top of kong 3.3.
Build golden Image
When it comes to custom plugins or custom nginx template, it is best to build custom images. This way the operation team does not need to worry about managing plugin code in their infrastructure deployment pipeline. Kong also provides an official doc to create this custom image. Let’s follow the official instructions to build our image this time.
Download docker-entrypoint.sh
Go to a folder and run1
wget https://raw.githubusercontent.com/Kong/docker-kong/master/docker-entrypoint.sh
Download Kong installation package
We will download the latest Kong package for alpine image. You can find their package here. I can download the package with1
wget https://download.konghq.com/gateway-3.x-ubuntu-focal/pool/all/k/kong/kong_3.3.0_amd64.deb -O kong.deb
Create Dockerfile
You can still use the Dockerfile on my previous post. I just want to show you the official way.
A few things to call out
- Use Ubuntu instead of Alpine as base image.
- Remove
/usr/local/bin/resty
first as there will be an existing symlink which points to/openresty/bin/resty
. - Add
RUN chmod +x /docker-entrypoint.sh
to make sure this entrypoint script is executable.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45FROM golang:latest as builder
RUN apt-get install git gcc libc-dev curl
RUN mkdir /go-plugins
RUN curl https://raw.githubusercontent.com/Kong/go-plugins/master/go-hello.go -o /go-plugins/go-hello.go
RUN cd /go-plugins && \
go mod init kong-go-plugin && \
go get github.com/Kong/go-pdk && \
go mod tidy && \
go build go-hello.go
FROM ubuntu:20.04
COPY kong.deb /tmp/kong.deb
RUN set -ex; \
apt-get update \
&& apt-get install --yes /tmp/kong.deb \
&& rm -rf /var/lib/apt/lists/* \
&& rm -rf /tmp/kong.deb \
&& chown kong:0 /usr/local/bin/kong \
&& chown -R kong:0 /usr/local/kong \
&& rm /usr/local/bin/resty \
&& ln -s /usr/local/openresty/bin/resty /usr/local/bin/resty \
&& ln -s /usr/local/openresty/luajit/bin/luajit /usr/local/bin/luajit \
&& ln -s /usr/local/openresty/luajit/bin/luajit /usr/local/bin/lua \
&& ln -s /usr/local/openresty/nginx/sbin/nginx /usr/local/bin/nginx \
&& kong version
COPY docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
COPY --from=builder /go-plugins/go-hello /usr/local/bin/
USER kong
ENTRYPOINT ["/docker-entrypoint.sh"]
EXPOSE 8000 8443 8001 8444
STOPSIGNAL SIGQUIT
HEALTHCHECK --interval=10s --timeout=10s --retries=10 CMD kong health
CMD ["kong", "docker-start"]Build image
Let’s build our our image with tagkong-go-hello:3.3-ubuntu
1
docker build --no-cache -t kong-go-hello:3.3-ubuntu .
Test golden image
Start container
To save us some time, I will deploy Kong in DBless mode with Docker. If you are not sure what are the options to deploy Kong with docker, please check this post.
1 | docker run --rm -d --name kong-demo \ |
Post Config
Let’s save below file to /tmp/kong.yaml
1 | _format_version: "3.0" |
Now we can apply the config to Kong with curl.
1 | curl -X POST http://localhost:8001/config -F config=@/tmp/kong.yaml |
Test
Let’s send a request to Kong curl http://localhost:8000/test
and we should see below response header.
1 | x-hello-from-go: Go says hello from kong Go plugin to localhost:8000 |
This means our golden image works.
Reproduce issue
Now let me deploy Kong on Kubernetes using this image to reproduce the issue.
1 | helm upgrade -i my-kong kong/kong \ |
We should see logs like below which suggests my go plugin server failed to start.
1 | ➜ kubectl logs -n kong deployments/my-kong-kong proxy |
Debugging process
As we can see I use the same go plugin settings, why did not it work on kubernetes?
The only hint we had was remove /usr/local/kong/go-hello.socket: read-only file system
.
If you are familiar with Kong, you will know that Kong stores temporary files and logs in prefix directory. The default prefix directory is /usr/local/kong/
so it makes sense the go-hello.socket
is stored in this folder. However, it did not seem right for this folder to be read-only and where did this read-only come from?
Check helm chart
At this point I suspect helm chart is responsible for read-only setting. Let’s check what the chart does.
Firstly, let’s find out the version I am running.
1 | ➜ helm show chart kong/kong |
On Kubernetes, we use security context to define privilege and access control to a pod or container. For more information, please check official doc.
We can see I am running 2.22.0 which is most up to date version. Next let’s search securityContext on value.yaml file. We can see from these line, Kong’s chart sets containers security context to read-only.
1 | # securityContext for Kong pods. |
I also notice that the chart use /kong_prefix/
as the prefix folder on kubernetes. (source) Why do they do it and how does this folder work when the container is read-only?
By searching keyword /kong_prefix
, we found below information from chart changelog.
1 | - Create and mount emptyDir volumes for `/tmp` and `/kong_prefix` to allow |
Test prefix folder
OK, now we know the prefix folder is /kong_prefix/
which means the socket file should be created in this folder, let’s tell kong where to find the socket with pluginserver_go_hello_socket: /kong_prefix/go-hello.socket
and see how it work.
1 | helm upgrade -i my-kong kong/kong \ |
Initially we see below in the log which suggest our setting works because kong was looking for the socket file from /kong_prefix/go-hello.socket
.
1 | 2023/06/04 05:08:19 [crit] 1272#0: *299 connect() to unix:/kong_prefix/go-hello.socket failed (2: No such file or directory), context: ngx.timer |
Then we started to get the same error as before and it seem Kong was still trying to find the socket from /usr/local/kong/
, why?
1 | 2023/06/04 05:09:01 [notice] 1272#0: *298 [kong] process.lua:252 Starting go-hello, context: ngx.timer |
Check official doc
On the official doc, I noticed there was a -kong-prefix
flag. From reading the description, it seems that we need to use this flag to allow go plugin to find the kong prefix folder.
Check Kong tests
To make sure my understanding is right, I also checked how Kong does tests for Go plugins. As we can see -kong-prefix " .. kong_prefix,
is used, it means we definitely need to tell go plugin where to find the prefix folder.
1 | assert(helpers.start_kong({ |
Test kong-prefix flag
Let’s add -kong-prefix
and deploy Kong again. Hooray! No more error complaining plugin servers.
1 | helm upgrade -i my-kong kong//kong \ |
Test custom plugin
Let’s test the plugin with CRD.
Preparation
First let’s prepare a httpbin deployment, service and an Ingress.
1 | kubectl create deployment httpbin --image=kennethreitz/httpbin |
When we send our request, we should see below.
1 | ➜ curl http://proxy.li.k8s/test/anything -I |
Apply plugin via CRD
Now let’s apply the plugin globally.
1 | kubectl apply -f - <<EOF |
Test plugin
Now when we send our request again, we should see the response headers as below which means our Go plugin works. 🎉
1 | ➜ curl http://proxy.li.k8s/test/anything -I |
That’s all I want to share with you today. See you next time.