动手系列之部署APISIX到K8S
为更好的理论与实践相结合,后续计划不定期开展一些动手实验并记录其过程,实践执行标准将尽量满足合理的工程性要求,其最终目标是拥有一个完整微服务K8S集群,包括微服务模块(业务)、网关(路由,限流,灰度等)、链路追踪、日志平台、监控、大数据平台等。
开始
APISIX是一个与KONG基本功能相同的网关技术选型方案,但作为后来者似乎有更多优点,这两者最重要的作用是提供插件开发框架定义与生态,让网关能力扩展任性而为。
第一次实践本应是搭建K8S集群,但笔者之前在本地WSL中搭建K8S集群时解决的各种问题未做记录,因此后续实践将以K8S集群存在为前提进行。
实践若以云服务K8S集群进行,作为个人较难承担相关资源成本,因而选择使用本地K8S集群进行实验,这将导致部分行为与实际工作有所差异,尤其集中在运维方面
实践
有K8S集群后以部署APISIX到K8S集群作为第一次实践,本次实践完成后应达到能从浏览器可访问K8S中APISIX的目标,而考虑后续需进行插件开发,笔者选择使用Dockerfile构建镜像部署APISIX到K8S集群这种方式。
首先通过命令kubectl create namespace lab
在K8S中创建一个专门用于实践的namespace,此后的实践内容也将部署在此namespace下。
Etcd
APISIX需要使用Etcd进行配置存储,先部署一个Etcd:
# etcd.yaml
apiVersion: v1
kind: Pod
metadata:
name: etcd
namespace: lab
labels:
app: etcd
etcd_node: etcd
spec:
containers:
- command:
- etcd
- --name=etcd
- --data-dir=/var/k8s-lab/etcd
- --advertise-client-urls=http://etcd:2379
- --initial-advertise-peer-urls=http://etcd:2380
- --listen-client-urls=http://0.0.0.0:2379
- --listen-peer-urls=http://0.0.0.0:2380
- --initial-cluster=etcd=http://etcd:2380
image: k8s.gcr.io/etcd:3.5.0-0
imagePullPolicy: IfNotPresent
name: etcd
volumeMounts:
- mountPath: /var/k8s-lab/etcd
name: etcd
ports:
- containerPort: 2379
name: client
protocol: TCP
- containerPort: 2380
name: server
protocol: TCP
volumes:
- hostPath:
path: /var/k8s-lab/etcd
type: DirectoryOrCreate
name: etcd
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: etcd-client
namespace: lab
spec:
ports:
- name: etcd-client-port
port: 2379
protocol: TCP
targetPort: 2379
selector:
app: etcd
将上述内容保存为etcd.yaml
,然后执行kubectl apply -f etcd.yaml
完成Etcd部署,此处可参考文章验证部分的内容,提前确认Etcd正确部署。
此处映射了主机目录
/var/k8s-lab/etcd
作为容器的数据目录
网关代码
为了扩展与可维护性,网关需要有自己的配置文件、Dockerfile、插件等内容,因此先为网关设计一个Git仓库,目录结构暂设计如下:
$ tree .
.
└── apisix // 网关内容,平级目录可能还会加入其他实践内容
├── Dockerfile // build Docker镜像
├── conf // 配置文件目录
│ └── apisix.yaml // 定义apisix配置信息如etcd、prometheus、admin等
└── extra // 插件开发
相关文件内容:
# apisix.yaml
etcd:
host:
- http://etcd-client.lab.svc.cluster.local:2379
apisix:
allow_admin:
- 0.0.0.0/0
# Dockerfile
FROM apache/apisix:2.13.0-alpine
copy conf/apisix.yaml /usr/local/apisix/conf/config.yaml
expose 9080 9091 9443
构建镜像
有了Git仓库后,可配置CICD用于自动构建镜像与部署,但此处笔者没有稳定的云K8S环境因而无法实现自动部署,暂时只是借助CICD构建镜像再使用手动方式部署到K8S集群。对于个人开发者笔者推荐使用Gitlab的CICD集成,此处不过多描述如何安装gitlab-runner,只是把构建APISIX镜像的CICD配置文件内容贴一下供参考:
# .gitlab-ci.yml
image: docker:stable
before_script:
- docker login -u $REGISTRY_USER -p $REGISTRY_PASSWORD $REGISTRY
stages:
- build
- push
build:
stage: build
script:
- docker build --pull -t $REGISTRY/$SPACE_NAME:$CI_COMMIT_REF_NAME apisix
only:
refs:
- /^release.apisix.+/
tags:
- xxx
push:
stage: push
script:
- docker push $REGISTRY/$SPACE_NAME:$CI_COMMIT_REF_NAME
only:
refs:
- /^release.apisix.+/
when: manual
tags:
- xxx
通过此配置文件与已注册好的gitlab-runner可达到效果:“当推送的分支格式如release.apisix.xxx
时,build过程会自动运行并得到一个Docker镜像,而push过程则是手动触发将得到的Docker镜像推送到远端仓库”。由此每次发布网关版本时将得到一个Docker镜像,而后可通过手动操作将此镜像部署到K8S集群。
此处笔者将push过程指定为手动触发,是因为一些个人项目中用于build镜像的VPS即是运行的VPS,这样做可以节省带宽以及加快发布速度,避免push=>pull=>run
部署镜像到K8S集群
# apisix.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: apisix
namespace: lab
labels:
app: apisix
spec:
replicas: 2
selector:
matchLabels:
app: apisix
template:
metadata:
labels:
app: apisix
spec:
initContainers:
- command:
- /bin/sh
- -c
- |
sysctl -w net.core.somaxconn=65535
sysctl -w net.ipv4.ip_local_port_range="1024 65535"
sysctl -w net.ipv4.tcp_max_syn_backlog=8192
sysctl -w fs.file-max=1048576
sysctl -w fs.inotify.max_user_instances=16384
sysctl -w fs.inotify.max_user_watches=524288
sysctl -w fs.inotify.max_queued_events=16384
image: busybox:latest
imagePullPolicy: IfNotPresent
name: init-sysctl
resources: {}
securityContext:
privileged: true
procMount: Default
restartPolicy: Always
containers:
- env:
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
image: "" # 此处配置前部分构建的网关镜像地址
imagePullPolicy: IfNotPresent
name: apisix
ports:
- containerPort: 9080
name: http
protocol: TCP
- containerPort: 9443
name: https
protocol: TCP
- containerPort: 9091
name: prometheus
protocol: TCP
readinessProbe:
failureThreshold: 6
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
tcpSocket:
port: 9080
timeoutSeconds: 1
volumeMounts:
- mountPath: /etc/localtime
name: localtime
readOnly: true
volumes:
- hostPath:
path: /etc/localtime
type: File
name: localtime
---
apiVersion: v1
kind: ConfigMap
metadata:
name: apisix-dashboard-config
namespace: lab
data:
conf.yaml: |
conf:
listen:
port: 9000
allow_list:
- 0.0.0.0/0
etcd:
endpoints:
- etcd-client.lab.svc.cluster.local:2379
authentication:
secret: secret
expire_time: 2592000
users:
- username: admin
password: admin
---
apiVersion: v1
kind: Pod
metadata:
name: apisix-dashboard
namespace: lab
labels:
app: apisix-dashboard
spec:
containers:
- image: apache/apisix-dashboard:2.11-alpine
name: apisix-dashboard
ports:
- containerPort: 9000
name: client
protocol: TCP
volumeMounts:
- name: apisix-dashboard-config
mountPath: /usr/local/apisix-dashboard/conf/conf.yaml
subPath: conf.yaml
volumes:
- name: apisix-dashboard-config
configMap:
name: apisix-dashboard-config
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: apisix
namespace: lab
labels:
app: apisix
spec:
ports:
- name: http
port: 9080
protocol: TCP
targetPort: 9080
- name: https
port: 9443
protocol: TCP
targetPort: 9443
- name: prometheus
port: 9091
protocol: TCP
targetPort: 9091
selector:
app: apisix
---
apiVersion: v1
kind: Service
metadata:
name: apisix-dashboard
namespace: lab
spec:
ports:
- name: apisix-dashboard-port
port: 9000
protocol: TCP
targetPort: 9000
selector:
app: apisix-dashboard
上述内容描述了APISIX的K8S相关资源:
- Deployment apisix,调度部署两个Pod运行APISIX
- ConfigMap apisix-dashboard-config,用于配置apisix-dashboard的行为
- Pod apisix-dashboard,暂时部署到集群中起辅助作用,后续管理路由、插件、服务等不一定会使用
- Service apisix & apisix-dashboard,暴露Pod的可访问入口
将内容保存为apisix.yaml
并执行命令kubectl apply -f apisix.yaml
,接着K8S会完成部署运行。
验证
等待一段时间后执行命令进行验证:
$ kubectl -n lab get pods
NAME READY STATUS RESTARTS AGE
apisix-b47bff658-6wx2l 1/1 Running 0 88m
apisix-b47bff658-g4v55 1/1 Running 0 88m
apisix-dashboard 1/1 Running 0 31m
etcd 1/1 Running 0 166m
$ kubectl -n lab get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
apisix ClusterIP 10.109.76.252 <none> 9080/TCP,9443/TCP,9091/TCP 88m
apisix-dashboard ClusterIP 10.99.158.192 <none> 9000/TCP 86m
etcd-client ClusterIP 10.108.69.57 <none> 2379/TCP 166m
执行命令验证各服务访问:
$ curl http://10.108.69.57:2379/version
{"etcdserver":"3.5.0","etcdcluster":"3.5.0"}#
$ curl http://10.109.76.252:9080
{"error_msg":"404 Route Not Found"}
$ curl http://10.99.158.192:9000
...
至此笔者达成了部署APISIX到本地K8S集群的目标,且留下了扩展APISIX的途径,下一次实践笔者将尝试在APISIX内实现一个自定义插件以及配置网关路由规则。
主机访问APISIX
笔者的K8S集群搭建在WSL中,从Windows主机访问WSL的网络存在一些约束(未理论学习),且WSL中K8S网络也还是一个独立的网络空间,因此在WLS的K8S中部署APISIX后还不能从浏览器访问相关服务,为解决此问题笔者做了如下两个措施:
- 固定主机访问WSL的IP
通过网上搜索的一行命令:
netsh interface ip add address "vEthernet (WSL)" 192.168.168.188 255.255.255.0
,在Windowns下执行此命令后可以使用192.168.168.188访问到WSL
- 在WSL中安装Nginx转发流量到K8S服务
主机能访问WSL网络但无法直接访问K8S服务,选择安装Nginx进行请求转发,类似云服务接入商的Load Balancer
另外笔者修改了本地hosts文件让Nginx支持更灵活的转发以及可在浏览器中通过域名访问服务。
hosts:
192.168.168.168 lab.com
192.168.168.168 admin.lab.com
Nginx转发:
server {
listen 80;
server_name lab.com;
location / {
proxy_pass http://10.109.76.252:9080;
}
}
server {
listen 80;
server_name admin.lab.com;
location / {
proxy_pass http://10.99.158.192:9000;
}
}
经过上述措施后主机能顺利通过浏览器访问http://lab.com
与http://admin.lab.com
。