前言 开源项目Kong 是当下最火的API Gateway项目之一,官方也在Docker Hub 上提供了Kong的镜像。但我在使用官方镜像来部署Kong的过程中发现,我需要对官方镜像做一些改动来适应我的需求:
在Docker启动时只需要给定镜像、启动命令即可完成部署(包括初次部署),方便迁移k8s;
方便Kong切换不同的配置文件;
将Kong所有的日志存放在指定目录,方便挂载存储。
这篇文章记录的就是我改动的思路和过程。
注:本文所使用的运行环境为Ubuntu 18.04 LTS
+Docker 18.09.6
,Kong使用的数据库均为PostgreSQL
,使用的Kong镜像版本为1.1.2-alpine
官方镜像分析 Kong的官方文档(Docker Installation )给出了一个简单的Kong部署教程,记录如下:
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 # 创建docker网络 docker network create kong-net# 创建数据库 docker run -d --name kong-database \ --network=kong-net \ -p 5432:5432 \ -e "POSTGRES_USER=kong" \ -e "POSTGRES_DB=kong" \ postgres:9.6# 初始化数据库 docker run --rm \ --network=kong-net \ -e "KONG_DATABASE=postgres" \ -e "KONG_PG_HOST=kong-database" \ kong:latest kong migrations bootstrap# 启动Kong docker run -d --name kong \ --network=kong-net \ -e "KONG_DATABASE=postgres" \ -e "KONG_PG_HOST=kong-database" \ -e "KONG_PROXY_ACCESS_LOG=/dev/stdout" \ -e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" \ -e "KONG_PROXY_ERROR_LOG=/dev/stderr" \ -e "KONG_ADMIN_ERROR_LOG=/dev/stderr" \ -e "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl" \ -p 8000:8000 \ -p 8443:8443 \ -p 8001:8001 \ -p 8444:8444 \ kong:latest
从以上教程可以看出,我们可以通过为官方镜像设置环境变量来配置Kong;而且,该镜像还有一个默认的启动命令,可以直接启动Kong主进程。 然后,我们再来看看kong:1.1.2-alpine
这个官方镜像的Dockerfile :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 FROM alpine:3.6 LABEL maintainer="Kong Core Team <team-core@konghq.com>" ENV KONG_VERSION 1.1 .2 ENV KONG_SHA256 0 d7509fa2ef653b4aba14a1a1fd20339bccb4f8d386429102c42b7af6d8b6bdbRUN adduser -Su 1337 kong \ ... && chmod -R g=u /usr/local/kongCOPY docker-entrypoint.sh /docker-entrypoint.sh ENTRYPOINT ["/docker-entrypoint.sh" ] EXPOSE 8000 8443 8001 8444 STOPSIGNAL SIGTERMCMD ["kong" , "docker-start" ]
从Dockerfile可以看出,官方镜像默认的启动命令为ENTRYPOINT
+CMD
;再结合前文官方教程里初始化数据库的命令,我们可以知道:
初始化数据库的容器内启动命令为:/docker-entrypoint.sh kong migrations bootstrap
启动Kong主进程的容器内启动命令为:/docker-entrypoint.sh kong docker-start
有了这些信息,我们就可以对官方镜像进行修改了。
自定义Dockerfile、启动脚本 考虑到我有多套Kong配置分别用于不同环境(本地调试、测试、实际应用等),而这些配置中有许多重复的内容,所以我选择将这些重复的配置项放入Dockerfile中,不重复的配置项放入自定义启动脚本中。Dockerfile如下:
1 2 3 4 5 6 7 8 9 10 FROM kong:1.1 .2 -alpineLABEL maintainer="orange_wolf <orange_wolf@163.com>" COPY . /gateway WORKDIR /gateway ENV KONG_PREFIX=/gateway KONG_ADMIN_LISTEN=0.0 .0.0 :8001 KONG_DATABASE=postgresEXPOSE 8000 8001 ENTRYPOINT ["./run-kong.sh" ]
自定义启动脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # !/usr/bin/env sh case ${1} in "local") export KONG_PG_HOST=192.168.0.100 export KONG_PG_USER=xxxxxx export KONG_PG_PASSWORD=xxxxxx ... # 省略 ;; "pro") export KONG_PG_HOST=xxx.xxx.xxx.xxx export KONG_PG_USER=xxxxxx export KONG_PG_PASSWORD=xxxxxx ... # 省略 ;; ... # 省略 esac /docker-entrypoint.sh kong migrations bootstrap # 初始化数据库 /docker-entrypoint.sh kong docker-start # 启动Kong
于是,我用自定义的启动脚本代替了原有的启动脚本,这样就能让我通过在启动容器时输入不同指令来载入不同Kong配置,也能让Kong在连接到空数据库时自动实现初始化动作(而不是直接退出)。而这种部署方式也更灵活,更容易从Docker迁移到k8s等其它平台。实际部署流程如下:
1 2 3 4 docker build . -t my-kong-image docker run -d --name kong -p 8000:8000 -p 8001:8001 my-kong-image local # 载入本地调试配置 docker run -d --name kong -p 8000:8000 -p 8001:8001 my-kong-image test # 载入测试配置 docker run -d --name kong -p 8000:8000 -p 8001:8001 my-kong-image pro # 载入实际应用配置
以root命令启动Nginx 在自定义了Dockerfile和启动脚本后,似乎一切都能满足我的需求了。但不幸的时,以这个镜像启动容器时我遇到了如下错误:
1 nginx: [alert] could not open error log file : open () "/gateway/logs/error.log" failed (13: Permission denied)
很明显,nginx没有足够的权限将日志写入我指定的日志文件夹中。由于在不指定KONG_PREFIX
环境变量时,nginx和Kong能正常将日志文件写入默认的/usr/local/kong/logs/
目录下,所以我尝试在启动脚本run-kong.sh
中通过chmod
、chown
命令,将/gateway/logs/
目录的权限与/usr/local/kong/logs/
目录的权限同步,但还是出现了一样的错误提示。 上文提到,官方镜像的启动脚本为/docker-entrypoint.sh
。我找到了这份和官方Dockerfile放在一起的启动脚本 ,发现nginx是以kong
用户的身份运行的:
1 2 3 4 5 6 7 8 9 10 # !/bin/sh ... # 省略 exec su-exec kong /usr/local/openresty/nginx/sbin/nginx \ -p "$PREFIX" \ -c nginx.conf fi fi fi exec "$@"
既然是这样,那么我在自己的启动脚本内修改官方的启动脚本,让nginx以root权限运行就可以解决问题了。修改后的自定义启动脚本如下:
1 2 3 4 5 ... # 省略 sed -i 's/su-exec kong/su-exec root/g' /docker-entrypoint.sh # 修改启动脚本,以root身份启动nginx /docker-entrypoint.sh kong migrations bootstrap # 初始化数据库 /docker-entrypoint.sh kong docker-start # 启动Kong
顺便一提,如果想在容器内让Kong的默认端口由8000
变为80
(KONG_PROXY_LISTEN=0.0.0.0:80
)或其它低于1024
的端口,同样需要让nginx以root身份运行。
后记 开源项目官方提供的Docker镜像,往往要比自己用Alpine
、CentOS
、Debian
等基础镜像一步步安装项目构成的镜像来得方便、稳定、好用;但后者又往往拥有前者无可比拟的自由度。其实,通过分析并“继承
”官方Dockerfile、编写自己的启动脚本,往往能够同时拥有前两种镜像的优点——既方便,又自由。