[toc]
背景描述
当我在社区闲逛的时候,发现有一位用户对“如何在 APISIX Ingress 的环境下使用多语言插件”这个问题存在困惑。而我正好同时是 go-plugin-runner 的使用者,以及对 APISIX Ingress 项目有一点了解,于是便诞生了这篇文档。
方案描述
本文基于 0.3 版本的 go-plugin-runner 插件和 1.4.0 版本的 APISIX Ingress,详细讲述了从构建集群到构建镜像,再到自定义helm chart 包以及最后部署资源的全部过程。可以保证的是,根据这篇文档,可以完整的得出最后的结果。
go-plugin-runner: 0.3
APISIX Ingress: 1.4.0
kind: kind v0.12.0 go1.17.8 linux/amd64
kubectl version: Client Version: v1.23.5/Server Version: v1.23.4
golang: go1.18 linux/amd64
正文
构建集群环境
首先选择 kind 构建本地集群环境。命令如下:
cat <<EOF | kind create cluster --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
extraPortMappings:
- containerPort: 80
hostPort: 80
protocol: TCP
- containerPort: 443
hostPort: 443
protocol: TCP
EOF
打包构建 go-plugin-runner 的可执行文件
如果你插件写完了的话,就可以开始编译可执行文件以搭配 APISIX 运行了。
本文推荐两种打包构建方案:
- 将打包流程放进 Dockerfile,在之后构建 docker 镜像的时候顺道将编译过程完成。
- 也可以按照本文档采用的方案,先打包可执行文件,再将打包好的可执行文件复制到镜像中去。
如何选择方案,我认为这取决于你本地硬件的考量。此处选择第二种方案的原因是想要依靠本地强大的硬件提高打包速度,加快流程。
进入到 go-plugin-runner 目录
选择一个的文件夹地址 /home/chever/api7/cloud_native/tasks/plugin-runner
,并将我们的 apisix-go-plugin-runner
项目置于此文件夹下。
放置成功后,文件树如下所示:
chever@cloud-native-01:~/api7/cloud_native/tasks/plugin-runner$ tree -L 1
.
└── apisix-go-plugin-runner
1 directory, 0 files
然后你需要进入到 apisix-go-plugin-runner/cmd/go-runner/plugins
目录,并在该目录下编写你所需要的插件。本文章将使用默认插件 say
作演示。
chever@cloud-native-01:~/api7/cloud_native/tasks/plugin-runner/apisix-go-plugin-runner$ tree cmd
cmd
└── go-runner
├── main.go
├── main_test.go
├── plugins
│ ├── fault_injection.go
│ ├── fault_injection_test.go
│ ├── limit_req.go
│ ├── limit_req_test.go
│ ├── say.go
│ └── say_test.go
└── version.go
2 directories, 10 files
写完插件后,开始正式编译可执行文件,此处需要注意,你应该编写静态的可执行文件,非动态。
打包编译命令如下:
CGO_ENABLED=0 go build -a -ldflags '-extldflags "-static"' .
这样便成功打包了一个静态编译的 go-runner
可执行文件。
在 apisix-go-plugin-runner/cmd/go-runner/
目录下,可以看到当前文件树是这样的
chever@cloud-native-01:~/api7/cloud_native/tasks/plugin-runner/apisix-go-plugin-runner/cmd/go-runner$ tree -L 1
.
├── go-runner
├── main.go
├── main_test.go
├── plugins
└── version.go
1 directory, 4 files
请记住 apisix-go-plugin-runner/cmd/go-runner/go-runner
这个路径,我们将在之后用到它。
构建镜像
此处构建镜像是为了后面使用 helm
安装 APISIX 做准备。
编写 Dockerfile 文件
返回到路径 /home/chever/api7/cloud_native/tasks/plugin-runner
,在该目录下建立一个 Dockerfile 文件,此处给出一个示范。
ARG ENABLE_PROXY=false
# Build Apache APISIX
FROM api7/apisix-base:1.19.9.1.5
ADD ./apisix-go-plugin-runner /usr/local/apisix-go-plugin-runner
ARG APISIX_VERSION=2.13.1
LABEL apisix_version="${APISIX_VERSION}"
ARG ENABLE_PROXY
RUN set -x \
&& (test "${ENABLE_PROXY}" != "true" || /bin/sed -i 's,http://dl-cdn.alpinelinux.org,https://mirrors.aliyun.com,g' /etc/apk/repositories) \
&& apk add --no-cache --virtual .builddeps \
build-base \
automake \
autoconf \
make \
libtool \
pkgconfig \
cmake \
unzip \
curl \
openssl \
git \
openldap-dev \
&& luarocks install https://github.com/apache/apisix/raw/master/rockspec/apisix-${APISIX_VERSION}-0.rockspec --tree=/usr/local/apisix/deps PCRE_DIR=/usr/local/openresty/pcre \
&& cp -v /usr/local/apisix/deps/lib/luarocks/rocks-5.1/apisix/${APISIX_VERSION}-0/bin/apisix /usr/bin/ \
&& (function ver_lt { [ "$1" = "$2" ] && return 1 || [ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ]; }; if [ "$APISIX_VERSION" = "master" ] || ver_lt 2.2.0 $APISIX_VERSION; then echo 'use shell ';else bin='#! /usr/local/openresty/luajit/bin/luajit\npackage.path = "/usr/local/apisix/?.lua;" .. package.path'; sed -i "1s@.*@$bin@" /usr/bin/apisix ; fi;) \
&& mv /usr/local/apisix/deps/share/lua/5.1/apisix /usr/local/apisix \
&& apk del .builddeps \
&& apk add --no-cache \
bash \
curl \
libstdc++ \
openldap \
tzdata \
# forward request and error logs to docker log collector
&& ln -sf /dev/stdout /usr/local/apisix/logs/access.log \
&& ln -sf /dev/stderr /usr/local/apisix/logs/error.log
WORKDIR /usr/local/apisix
ENV PATH=$PATH:/usr/local/openresty/luajit/bin:/usr/local/openresty/nginx/sbin:/usr/local/openresty/bin
EXPOSE 9080 9443
CMD ["sh", "-c", "/usr/bin/apisix init && /usr/bin/apisix init_etcd && /usr/local/openresty/bin/openresty -p /usr/local/apisix -g 'daemon off;'"]
STOPSIGNAL SIGQUIT
这份 Dockerfile 配置文档,来源于这个链接。我做的唯一修改如下:
ARG ENABLE_PROXY=false
# Build Apache APISIX
FROM api7/apisix-base:1.19.9.1.5
ADD ./apisix-go-plugin-runner /usr/local/apisix-go-plugin-runner
ARG APISIX_VERSION=2.13.1
LABEL apisix_version="${APISIX_VERSION}"
ARG ENABLE_PROXY
将目录 /home/chever/api7/cloud_native/tasks/plugin-runner
下的 /apisix-go-plugin-runner
文件全部打包进 Docker 镜像。请记录下可执行文件的位置 apisix-go-plugin-runner/cmd/go-runner/go-runner
,与上文 Dockerfile 中的 /usr/local/apisix-go-plugin-runner
目录位置,最终得出可执行文件在 Docker 镜像中的位置如下:
/usr/local/apisix-go-plugin-runner/cmd/go-runner/go-runner
请记录下这个地址。我们将在接下来的配置中使用到它。
开始构建镜像
开始根据 Dockerfile 构建 Docker 镜像。命令执行目录于 /home/chever/api7/cloud_native/tasks/plugin-runner
。命令如下:
docker build -t apisix/forrunner:0.1 .
命令解释:构建一个名字叫作 apisix/forrunner
的镜像,并将其标记为 0.1 版本。
加载镜像到集群环境中
kind load docker-image apisix/forrunner:0.1
将镜像加载进 kind 集群环境中去,以便让之后 helm 安装的时候能拉取到这个自定义的镜像进行安装。
helm 安装部署 Apisix Ingress
修改官方包
本小节主要是修改 helm 官方包中的 values.yaml
文件,以使其可以安装本地打包的镜像以及正常运行 go-plugin-runner
可执行文件。
拉取官方包
首先拉取最新的 apisix helm chart 包,命令如下:
helm fetch apisix/apisix
文件树如下:
chever@cloud-native-01:~/api7/cloud_native/tasks/plugin-runner$ tree -L 1
.
├── apisix-0.9.1.tgz
└── apisix-go-plugin-runner
1 directory, 1 file
解压官方包
解压 apisix-0.9.1.tgz
文件,准备改写配置。解压命令如下:
tar zxvf apisix-0.9.1.tgz
得到文件树如下:
chever@cloud-native-01:~/api7/cloud_native/tasks/plugin-runner$ tree -L 1
.
├── apisix
├── apisix-0.9.1.tgz
└── apisix-go-plugin-runner
2 directories, 1 file
修改 values.yaml
文件
进入apisix
文件夹,修改 values.yaml
文件。两处修改如下:
image:
repository: apisix/forrunner
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: 0.1
第一处修改将helm 安装的镜像设置为本地自己打包的镜像。
extPlugin:
enabled: true
cmd: ["/usr/local/apisix-go-plugin-runner/cmd/go-runner/go-runner", "run"]
第二处命令设置好运行容器后,go-runner 在容器中的位置。
压缩修改后的包
配置好后,压缩 apisix
文件。压缩命令如下:
tar zcvf apisix.tgz apisix/
得到压缩文件,此时文件树如下:
chever@cloud-native-01:~/api7/cloud_native/tasks/plugin-runner$ tree -L 1
.
├── apisix
├── apisix-0.9.1.tgz
├── apisix-go-plugin-runner
└── apisix.tgz
2 directories, 2 files
执行 helm 安装命令
创建 namespace
在正式安装之前,先创建 namespaces,命令如下
kubectl create ns ingress-apisix
然后使用 helm 安装 APISIX,命令如下:
helm install apisix ./apisix.tgz --set gateway.type=NodePort --set ingress-controller.enabled=true --namespace ingress-apisix --set ingress-controller.config.apisix.serviceNamespace=ingress-apisix
创建 httpbin 服务以及 ApisixRoute 资源
创建 httpbin 后端资源,以配合部署的 ApisixRoute 资源运行测试功能是否正常生效。
创建 httpbin 服务
创建一个 httpbin 服务,命令如下:
kubectl run httpbin --image kennethreitz/httpbin --port 80
将端口暴露出去,命令如下:
kubectl expose pod httpbin --port 80
创建 ApisixRoute 资源
创建 go-plugin-runner-route.yaml
文件以开启 ApisixRoute 资源,配置文件如下:
apiVersion: apisix.apache.org/v2beta3
kind: ApisixRoute
metadata:
name: plugin-runner-demo
spec:
http:
- name: rule1
match:
hosts:
- local.httpbin.org
paths:
- /get
backends:
- serviceName: httpbin
servicePort: 80
plugins:
- name: ext-plugin-pre-req
enable: true
config:
conf:
- name: "say"
value: "{\"body\": \"hello\"}"
创建资源命令如下:
kubectl apply -f go-plugin-runner-route.yaml
测试
测试 Golang 编写的插件是否正常运行,命令如下:
kubectl exec -it -n ${namespace of Apache APISIX} ${Pod name of Apache APISIX} -- curl http://127.0.0.1:9080/get -H 'Host: local.httpbin.org'
此处我根据 kubectl get pods --all-namespaces
命令得出这里的 ${namespace of Apache APISIX}
和 ${Pod name of Apache APISIX}
参数分别为ingress-apisix
和 apisix-55d476c64-s5lzw
,执行命令如下:
kubectl exec -it -n ingress-apisix apisix-55d476c64-s5lzw -- curl http://127.0.0.1:9080/get -H 'Host: local.httpbin.org'
得到的正常响应为:
chever@cloud-native-01:~/api7/cloud_native/tasks/plugin-runner$ kubectl exec -it -n ingress-apisix apisix-55d476c64-s5lzw -- curl http://127.0.0.1:9080/get -H 'Host: local.httpbin.org'
Defaulted container "apisix" out of: apisix, wait-etcd (init)
hello
总结
这篇文档的得来,是很不容易的。我学习了很多知识,dockerfile 打包镜像。helm chart 自定义。很痛苦,但是也很快乐。也知道了要注意打包的可执行 文件是静态链接还是应该动态链接
Containerize Your Go Developer Environment – Part 1: 看了但是没啥用
Dockerfile 中的 COPY 与 ADD 命令: 这个确实很有用啊!
打开 httpbin 后端服务: 这个起到一点用处
搭配上面一起使用: 与上面的方法搭配使用,效果更佳
APISIX Ingress issues: How to use apisix-python-plugin-runner: 很有用哦!
Helm 修改后该如何部署: 这个也很有用!
判错命令
此外,有一些帮助我判断状况的命令也非常需要记住,非常感谢哈:
查询日志
kubectl logs apisix-5b9788797c-f8lrv -n ingress-apisix
查看pod 状态
kubectl describe pod apisix-7cdf9cbf6f-gh5bw -n apisix
如果是 alpine 的容器,安装命令是
apk add file
进入到容器里,运行 file 命令,查看可执行文件的基本信息
file some_execuable
其他命令
helm uninstall apisix ./apisix.tgz
Upgrade 安装
helm upgrade --install apisix ./apisix.tgz --set gateway.type=NodePort --set ingress-controller.enabled=true --namespace ingress-apisix --set ingress-controller.config.apisix.serviceNamespace=ingress-apisix