如标题所说。
背景描述
在社区中闲逛时,我发现有用户对"如何在 APISIX Ingress 环境中使用多语言插件"感到困惑。我恰好是 go-plugin-runner 的用户,对 APISIX Ingress 项目也有一些了解,于是就有了这份文档。
方案描述
基于 go-plugin-runner 插件的 0.3 版本和 APISIX Ingress 的 1.4.0 版本,本文通过构建集群、构建镜像、自定义 helm chart 包,最后部署资源的步骤。保证完全基于本文档可以推导出最终结果。
bashgo-plugin-runner: 0.3APISIX Ingress: 1.4.0kind: kind v0.12.0 go1.17.8 linux/amd64kubectl version: Client Version: v1.23.5/Server Version: v1.23.4golang: go1.18 linux/amd64
开始
构建集群环境
选择 kind 来构建本地集群环境。命令如下:
bashcat <<EOF | kind create cluster --config=-kind: ClusterapiVersion: kind.x-k8s.io/v1alpha4nodes:- role: control-planekubeadmConfigPatches:- |kind: InitConfigurationnodeRegistration:kubeletExtraArgs:node-labels: "ingress-ready=true"extraPortMappings:- containerPort: 80hostPort: 80protocol: TCP- containerPort: 443hostPort: 443protocol: TCPEOF
构建 go-plugin-runner 可执行文件
如果你已经完成了插件的编写,就可以开始编译可执行文件来与 APISIX 一起运行。
本文推荐两种打包构建选项。
- 将打包过程放入 Dockerfile 中,在后续构建 docker 镜像时完成编译过程。
- 你也可以按照本文档使用的方案,先构建可执行文件,然后将打包的可执行文件复制到镜像中。
如何选择方案应该根据你的本地硬件考虑。这里选择第二种方案的原因是,我想依托我强大的本地硬件来提高构建速度,加快流程。
进入 go-plugin-runner 目录
选择一个文件夹地址 /home/chever/api7/cloud_native/tasks/plugin-runner,将我们的 apisix-go-plugin-runner 项目放置在这个文件夹中。
成功放置后,文件树如下所示:
bashchever@cloud-native-01:~/api7/cloud_native/tasks/plugin-runner$ tree -L 1.└── apisix-go-plugin-runner1 directory, 0 files
然后你需要进入 apisix-go-plugin-runner/cmd/go-runner/plugins 目录,在该目录中编写你需要的插件。本文将使用默认插件 say 进行演示。
bashchever@cloud-native-01:~/api7/cloud_native/tasks/plugin-runner/apisix-go-plugin-runner$ tree cmdcmd└── 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.go2 directories, 10 files
编写完插件后,正式开始编译可执行文件,这里注意应该构建静态可执行文件,而不是动态的。
包编译命令如下。
bashCGO_ENABLED=0 go build -a -ldflags '-extldflags "-static"' .
这样就成功打包了一个静态编译的 go-runner 可执行文件。
在 apisix-go-plugin-runner/cmd/go-runner/ 目录中,你可以看到当前文件树如下所示:
bashchever@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.go1 directory, 4 files
请记住路径 apisix-go-plugin-runner/cmd/go-runner/go-runner,我们稍后会用到它。
构建 Docker 镜像
这里构建镜像是为了后续使用 helm 安装 APISIX 做准备。
编写 Dockerfile
回到路径 /home/chever/api7/cloud_native/tasks/plugin-runner,在该目录中创建一个 Dockerfile,这里给出一个演示。
dockerfileARG ENABLE_PROXY=false# Build Apache APISIXFROM api7/apisix-base:1.19.9.1.5ADD ./apisix-go-plugin-runner /usr/local/apisix-go-plugin-runnerARG APISIX_VERSION=2.13.1LABEL apisix_version="${APISIX_VERSION}"ARG ENABLE_PROXYRUN 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.logWORKDIR /usr/local/apisixENV PATH=$PATH:/usr/local/openresty/luajit/bin:/usr/local/openresty/nginx/sbin:/usr/local/openresty/binEXPOSE 9080 9443CMD ["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 配置文档,来源于这个链接。我做的唯一修改如下:
bashARG ENABLE_PROXY=false# Build Apache APISIXFROM api7/apisix-base:1.19.9.1.5ADD ./apisix-go-plugin-runner /usr/local/apisix-go-plugin-runnerARG APISIX_VERSION=2.13.1LABEL 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 镜像中的最终位置如下。
bash/usr/local/apisix-go-plugin-runner/cmd/go-runner/go-runner
请记住这个地址。我们将在其余配置中使用它。
开始构建 Docker 镜像
基于 Dockerfile 开始构建 Docker 镜像。命令在 /home/chever/api7/cloud_native/tasks/plugin-runner 目录中执行。命令如下:
bashdocker build -t apisix/forrunner:0.1 .
命令解释:构建一个名为 apisix/forrunner 的镜像,并标记为 0.1 版本。
将镜像加载到集群环境
bashkind load docker-image apisix/forrunner:0.1
将镜像加载到 kind 集群环境中,以便在 helm 安装过程中拉取自定义本地镜像进行安装。
安装 APISIX Ingress
自定义 helm chart
这一部分重点是修改官方 helm 包中的 values.yaml 文件,使其能够安装本地打包的镜像,并正确运行 go-plugin-runner 可执行文件。
获取官方 helm chart
首先,用以下命令获取最新的 apisix helm chart 包:
bashhelm fetch apisix/apisix
文件树如下:
bashchever@cloud-native-01:~/api7/cloud_native/tasks/plugin-runner$ tree -L 1.├── apisix-0.9.1.tgz└── apisix-go-plugin-runner1 directory, 1 file
解压
解压 apisix-0.9.1.tgz 文件,准备重写配置。解压命令如下。
bashtar zxvf apisix-0.9.1.tgz
文件树如下:
bashchever@cloud-native-01:~/api7/cloud_native/tasks/plugin-runner$ tree -L 1.├── apisix├── apisix-0.9.1.tgz└── apisix-go-plugin-runner2 directories, 1 file
更改 values.yaml
进入 apisix 文件夹,修改 values.yaml 文件。两处更改如下:
yamlimage:repository: apisix/forrunnerpullPolicy: IfNotPresent# Overrides the image tag whose default is the chart appVersion.tag: 0.1
第一处更改将 helm 安装的镜像设置为你自己本地打包的镜像。
yamlextPlugin:enabled: truecmd: ["/usr/local/apisix-go-plugin-runner/cmd/go-runner/go-runner", "run"]
第二处更改设置了运行容器后 go-runner 在容器中的位置。
压缩修改后的 helm chart
配置完成后,压缩 apisix 文件。压缩命令如下:
bashtar zcvf apisix.tgz apisix/
获得压缩文件,此时文件树如下:
bashchever@cloud-native-01:~/api7/cloud_native/tasks/plugin-runner$ tree -L 1.├── apisix├── apisix-0.9.1.tgz├── apisix-go-plugin-runner└── apisix.tgz2 directories, 2 files
执行 helm 安装命令
创建命名空间
安装前,先用以下命令创建命名空间:
bashkubectl create ns ingress-apisix
然后使用 helm 安装 APISIX,命令如下:
bashhelm 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 服务:
bashkubectl run httpbin --image kennethreitz/httpbin --port 80
用以下命令暴露端口:
bashkubectl expose pod httpbin --port 80
创建 ApisixRoute 资源
创建 go-plugin-runner-route.yaml 文件来启用 ApisixRoute 资源,配置文件如下:
yamlapiVersion: apisix.apache.org/v2beta3kind: ApisixRoutemetadata:name: plugin-runner-demospec:http:- name: rule1match:hosts:- local.httpbin.orgpaths:- /getbackends:- serviceName: httpbinservicePort: 80plugins:- name: ext-plugin-pre-reqenable: trueconfig:conf:- name: "say"value: "{\"body\": \"hello\"}"
创建资源的命令如下:
bashkubectl apply -f go-plugin-runner-route.yaml
测试
用以下命令测试用 Golang 编写的插件是否正常工作:
bashkubectl 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,执行命令如下:
bashkubectl exec -it -n ingress-apisix apisix-55d476c64-s5lzw -- curl http://127.0.0.1:9080/get -H 'Host: local.httpbin.org'
期望得到的响应是:
bashchever@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
Comments