3.4 Kubernetes下的构建执行
整理环境
上一章中,我们通过Docker Compose
已经创建了etcd
、account
、apigw
、Traefik
多个镜像对应的容器。为了不被干扰,并且我们改用Kubetnetes
作为容器编排,我们需要删除之前创建的容器。
docker rm -f apigw apigw2 account1 account2 account3 go_micro_traefik_proxy_1 etcd1
我们将Kubernetes
搭建在了同网段的Windows
下的Vmware
虚拟机中,使用的是桥接模式
。也就是我的Mac
可以直接与虚拟机通讯。还不会搭建Kubernetes
的小伙伴可以先看 Kubernetes 18.04集群安装教程(基于Centos7) 这篇文章进行搭建
网络配置与 1.2 环境的准备与安装 里的相同。
Kubernetes下搭建
由于配置有限,所以我只搭建了一个Master
节点,没有搭建Node
节点,并且通过污点,设置master
允许pod
创建
kubectl taint node k8s-master node-role.kubernetes.io/master-
以下操作都是在Kubetnetes
的Master
节点做的
私有仓库
如果你使用的是公开公共仓库镜像,即不需要登陆,就可以下载的镜像,则可以跳过私有仓库
这个步骤。
我的镜像已经开放了公有权限,可以直接下载,不需要进行验证。如果你想使用自己的镜像,请按照下面进行操作。
阿里云登陆
docker login --username=<your-name> registry.cn-shenzhen.aliyuncs.com
# <your-name> 是你在阿里云上的登陆名
在集群中创建保存授权令牌的 Secret
# 创建 Secret,命名为 regcred:
kubectl create secret docker-registry regcred --docker-server=<your-registry-server> --docker-username=<your-name> --docker-password=<your-pword> --docker-email=<your-email> -n <your-namespace>
# <your-registry-server> 是你的私有 Docker 仓库全限定域名(FQDN)
# <your-name> 是你的 Docker 用户名。
# <your-pword> 是你的 Docker 密码。
# <your-email> 是你的 Docker 邮箱。
# <your-namespace> 创建后的该密钥属于k8s集群中哪一个namespace的
举个栗子
kubectl create secret docker-registry regcred --docker-server=registry.cn-shenzhen.aliyuncs.com --docker-username=guaosi@vip.qq.com --docker-password=a123654 --docker-email=guaosi@vip.qq.com -n go-micro
# 注意: -n 后面是我想这个密钥归属于哪个namespace,即哪个namespace可以使用
在pod清单中加入使用密钥
apiVersion: v1
kind: Pod
metadata:
name: private-reg
namespace: <your-namespace>
spec:
containers:
- name: private-reg-container
image: <your-private-image>
imagePullSecrets: # 使用指定的密钥
- name: regcred # 与上面创建的secret名称相同
初始化
命名空间
创建名字为go-micro
的namespace
,我们把需要的pod
、deploy
、svc
、secret
等等都放在这个namespace
下方便管理。
deploy/k8s/k8s-namespace.yml
apiVersion: v1
kind: Namespace
metadata:
name: go-micro
namespace: go-micro
执行
kubectl create -f deploy/k8s/k8s-namespace.yml
给Pod创建RBAC权限
deploy/k8s/k8s-pod-rbac.yml
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: go-micro
name: micro-services
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: micro-registry
namespace: go-micro
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- patch
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: micro-registry
namespace: go-micro
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: micro-registry # 要被绑定的ClusterRole的name
subjects:
- kind: ServiceAccount
name: micro-services # 要被绑定的serviceAccount的name
namespace: go-micro
执行
kubectl create -f deploy/k8s/k8s-pod-rbac.yml
account
pod
account/deploy/k8s/k8s-pod-account.yml
apiVersion: apps/v1
kind: Deployment # pod部署
metadata:
namespace: go-micro # 都设置在一个命名空间下,相同网络
name: svc-account
spec:
replicas: 1 # pod 数量
selector:
matchLabels:
app: svc-account
template:
metadata:
labels:
app: svc-account
spec:
containers:
- name: svc-account
command: [
"/account",
"--registry=kubernetes",
]
image: registry.cn-shenzhen.aliyuncs.com/go_micro/account:v1.0
imagePullPolicy: Always
serviceAccountName: micro-services # serviceAccount的名称 用于权限
#imagePullSecrets: # 使用指定的密钥,才能下载私有镜像
# - name: regcred
执行
kubectl create -f account/deploy/k8s/k8s-pod-account.yml
关于
account
的负载均衡,只需要扩容deploy
的replicas
即可 kubectl scale –replicas=3 deployment/svc-account -n go-micro
svc
account/deploy/k8s/k8s-svc-account.yml
apiVersion: v1
kind: Service # 网络服务
metadata:
name: svc-account
namespace: go-micro # 都设置在一个命名空间下,相同网络
labels:
app: svc-account
spec:
ports:
- port: 8080 # 必须填写,否则报错
protocol: TCP
selector:
app: svc-account
执行
kubectl create -f account/deploy/k8s/k8s-svc-account.yml
apigateway
pod
apigateway/deploy/k8s/k8s-pod-apigw.yml
apiVersion: apps/v1
kind: Deployment # pod部署
metadata:
namespace: go-micro # 都设置在一个命名空间下,相同网络
name: svc-apigw
spec:
replicas: 1 # pod 数量
selector:
matchLabels:
app: svc-apigw
template:
metadata:
labels:
app: svc-apigw
spec:
containers:
- name: svc-apigw
command: [
"/apigw",
"--p=8091", # 只能用 = 不能用空格隔开
"--registry=kubernetes",
]
image: registry.cn-shenzhen.aliyuncs.com/go_micro/apigw:v1.0
imagePullPolicy: Always
ports:
- containerPort: 8091
name: apigw-port
serviceAccountName: micro-services # serviceAccount的名称 用于权限
#imagePullSecrets: # 使用指定的密钥,才能下载私有镜像
# - name: regcred
执行
kubectl create -f apigateway/deploy/k8s/k8s-pod-apigw.yml
关于
apigateway
的负载均衡,只需要扩容deploy
的replicas
即可 kubectl scale –replicas=3 deployment/svc-apigw -n go-micro
svc
apigateway/deploy/k8s/k8s-svc-apigw.yml
apiVersion: v1
kind: Service # 网络服务
metadata:
name: svc-apigw
namespace: go-micro # 都设置在一个命名空间下,相同网络
labels:
app: svc-apigw
spec:
type: NodePort
ports:
- port: 8091 # cluster模式访问的端口
nodePort: 30088 #设置 nodeport 端口 30000-32767 此时
# targetPort:访问容器内部的端口,与containerPort值相同。 当没有设置targetPort时,此时targetPort的值与port相同
selector:
app: svc-apigw
执行
kubectl create -f apigateway/deploy/k8s/k8s-svc-apigw.yml
验证
> curl -X POST -d "username=guaosi&password=guaosi" http://192.168.1.200
:30088/account/register
`{"code":0,"message":""}`
下面继续使用Traefik
来进行反向代理了。
Traefik
由于Kubernetes
的Ingress
只能支持四层的IP:Port
转发,所以我们需要使用Traefik
来代替Ingress
。
该部分参考 Kubernetes 部署 Ingress 控制器 Traefik v2.2 后运行成功后,总结得出。
创建 CRD 资源
在
Traefik v2.0
版本后,开始使用CRD
(Custom Resource Definition)来完成路由配置等,所以需要提前创建CRD
资源。
traefik/k8s/k8s-crd-traefik.yaml
## IngressRoute
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
namespace: go-micro
name: ingressroutes.traefik.containo.us
spec:
scope: Namespaced
group: traefik.containo.us
version: v1alpha1
names:
kind: IngressRoute
plural: ingressroutes
singular: ingressroute
---
## IngressRouteTCP
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
namespace: go-micro
name: ingressroutetcps.traefik.containo.us
spec:
scope: Namespaced
group: traefik.containo.us
version: v1alpha1
names:
kind: IngressRouteTCP
plural: ingressroutetcps
singular: ingressroutetcp
---
## Middleware
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
namespace: go-micro
name: middlewares.traefik.containo.us
spec:
scope: Namespaced
group: traefik.containo.us
version: v1alpha1
names:
kind: Middleware
plural: middlewares
singular: middleware
---
## TLSOption
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
namespace: go-micro
name: tlsoptions.traefik.containo.us
spec:
scope: Namespaced
group: traefik.containo.us
version: v1alpha1
names:
kind: TLSOption
plural: tlsoptions
singular: tlsoption
---
## TraefikService
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
namespace: go-micro
name: traefikservices.traefik.containo.us
spec:
scope: Namespaced
group: traefik.containo.us
version: v1alpha1
names:
kind: TraefikService
plural: traefikservices
singular: traefikservice
---
## TLSStore
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
namespace: go-micro
name: tlsstores.traefik.containo.us
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: TLSStore
plural: tlsstores
singular: tlsstore
scope: Namespaced
---
## IngressRouteUDP
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
namespace: go-micro
name: ingressrouteudps.traefik.containo.us
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: IngressRouteUDP
plural: ingressrouteudps
singular: ingressrouteudp
scope: Namespaced
执行
kubectl create -f traefik/k8s/k8s-crd-traefik.yaml
创建 RBAC 权限
traefik/k8s/k8s-rbac-traefik.yaml
## ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: go-micro
name: traefik-ingress-services
---
## ClusterRole
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: go-micro
name: traefik-ingress-controller
rules:
- apiGroups: [""]
resources: ["services","endpoints","secrets"]
verbs: ["get","list","watch"]
- apiGroups: ["extensions"]
resources: ["ingresses"]
verbs: ["get","list","watch"]
- apiGroups: ["extensions"]
resources: ["ingresses/status"]
verbs: ["update"]
- apiGroups: ["traefik.containo.us"]
resources: ["middlewares","ingressroutes","ingressroutetcps","tlsoptions","ingressrouteudps","traefikservices","tlsstores"]
verbs: ["get","list","watch"]
---
## ClusterRoleBinding
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: go-micro
name: traefik-ingress-controller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik-ingress-controller
subjects:
- kind: ServiceAccount
name: traefik-ingress-services
namespace: go-micro
执行
kubectl create -f traefik/k8s/k8s-rbac-traefik.yml
创建 Traefik 配置文件
下面配置中可以通过配置kubernetesCRD
与kubernetesIngress
两项参数,让Traefik
支持CRD
与Ingress
两种路由方式。traefik/k8s/k8s-config-traefik.yml
kind: ConfigMap
apiVersion: v1
metadata:
name: traefik-config
namespace: go-micro
data:
traefik.yaml: |-
ping: "" ## 启用 Ping
serversTransport:
insecureSkipVerify: true ## Traefik 忽略验证代理服务的 TLS 证书
api:
insecure: true ## 允许 HTTP 方式访问 API
dashboard: true ## 启用 Dashboard
debug: true ## 启用 Debug 调试模式
metrics:
prometheus: "" ## 配置 Prometheus 监控指标数据,并使用默认配置
entryPoints:
web:
address: ":80" ## 配置 80 端口,并设置入口名称为 web
websecure:
address: ":443" ## 配置 443 端口,并设置入口名称为 websecure
providers:
kubernetesCRD: "" ## 启用 Kubernetes CRD 方式来配置路由规则
kubernetesIngress: "" ## 启动 Kubernetes Ingress 方式来配置路由规则
log:
filePath: "" ## 设置调试日志文件存储路径,如果为空则输出到控制台
level: error ## 设置调试日志级别
format: json ## 设置调试日志格式
accessLog:
filePath: "" ## 设置访问日志文件存储路径,如果为空则输出到控制台
format: json ## 设置访问调试日志格式
bufferingSize: 0 ## 设置访问日志缓存行数
filters:
#statusCodes: ["200"] ## 设置只保留指定状态码范围内的访问日志
retryAttempts: true ## 设置代理访问重试失败时,保留访问日志
minDuration: 20 ## 设置保留请求时间超过指定持续时间的访问日志
fields: ## 设置访问日志中的字段是否保留(keep 保留、drop 不保留)
defaultMode: keep ## 设置默认保留访问日志字段
names: ## 针对访问日志特别字段特别配置保留模式
ClientUsername: drop
headers: ## 设置 Header 中字段是否保留
defaultMode: keep ## 设置默认保留 Header 中字段
names: ## 针对 Header 中特别字段特别配置保留模式
User-Agent: redact
Authorization: drop
Content-Type: keep
#tracing: ## 链路追踪配置,支持 zipkin、datadog、jaeger、instana、haystack 等
# serviceName: ## 设置服务名称(在链路追踪端收集后显示的服务名)
# zipkin: ## zipkin配置
# sameSpan: true ## 是否启用 Zipkin SameSpan RPC 类型追踪方式
# id128Bit: true ## 是否启用 Zipkin 128bit 的跟踪 ID
# sampleRate: 0.1 ## 设置链路日志采样率(可以配置0.0到1.0之间的值)
# httpEndpoint: http://localhost:9411/api/v2/spans ## 配置 Zipkin Server 端点
执行
kubectl create -f traefik/k8s/k8s-config-traefik.yml
部署 Traefik
下面将用DaemonSet
方式部署Traefik
,便于在多服务器间扩展,用hostport
方式绑定服务器80
、443
端口,方便流量通过物理机进入Kubernetes
内部。
traefik/k8s/k8s-pod-traefik.yml
apiVersion: v1
kind: Service # 这个svc主要用来跟rule转发规则里转到至的端口相对应
metadata:
namespace: go-micro
name: traefik
spec:
ports:
- name: web
port: 80
- name: websecure
port: 443
- name: admin
port: 8080
selector:
app: traefik
---
apiVersion: apps/v1
kind: DaemonSet # DaemonSet保证在每个Node上都运行一个Pod,如果 新增一个Node,这个Pod也会运行在新增的Node上,如果删除这个DadmonSet,就会清除它所创建的Pod。
metadata:
name: traefik-ingress-controller
namespace: go-micro
labels:
app: traefik
spec:
selector:
matchLabels:
app: traefik
template:
metadata:
name: traefik
labels:
app: traefik
spec:
serviceAccountName: traefik-ingress-services
terminationGracePeriodSeconds: 1
hostNetwork: true ## 将容器端口绑定所在服务器端口
containers:
- image: traefik:v2.2.1
name: traefik-ingress-lb
ports:
- name: web
containerPort: 80
- name: websecure
containerPort: 443
- name: admin
containerPort: 8080 ## Traefik Dashboard 端口
resources:
limits:
cpu: 2000m
memory: 1024Mi
requests:
cpu: 1000m
memory: 1024Mi
securityContext:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
args:
- --configfile=/config/traefik.yaml
volumeMounts:
- mountPath: "/config"
name: "config"
readinessProbe:
httpGet:
path: /ping
port: 8080
failureThreshold: 3
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
livenessProbe:
httpGet:
path: /ping
port: 8080
failureThreshold: 3
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
volumes:
- name: config
configMap:
name: traefik-config
执行
kubectl create -f traefik/k8s/k8s-pod-traefik.yml
注意
DaemonSet
保证在每个Node
都运行一个Pod
,如果 新增一个Node
,这个Pod
也会运行在新增的Node
上,如果删除这个DadmonSet
,就会清除它所创建的Pod
。
如果想指定只能在哪些node
上创建traefik
,则需要提前指定Label
,这样当程序部署时会自动调度到设置Label
的节点上。
# 格式:kubectl label nodes [节点名] [key=value]
kubectl label nodes docker-desktop IngressProxy=true
# 查看节点是否设置 Label 成功
kubectl get nodes --show-labels
同时,需要修改 traefik/k8s/k8s-pod-traefik.yml
volumes:
- name: config
configMap:
name: traefik-config
# 以上是已经存在的设置,下面为要添加的设置
tolerations: # 设置容忍所有污点,防止节点被设置污点
- operator: "Exists"
nodeSelector: # 设置node筛选器,在特定label的节点上启动
IngressProxy: "true"
我懒就没做了。。。
配置路由规则
Traefik 应用已经部署完成,但是想让外部访问Kubernetes
内部服务,还需要配置路由规则,上面部署Traefik
时开启了Traefik Dashboard
,这是Traefik
提供的视图看板,所以,首先配置基于HTTP
的Traefik Dashboard
路由规则,使外部能够访问 Traefik Dashboard
。这里使用CRD
进行演示。
想使用Ingress或者加上HTTPS认证,请参考这篇文章
使用 CRD 方式创建路由规则可言参考 Traefik 文档 Kubernetes IngressRoute
traefik/k8s/k8s-crd-router-traefik.yml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: traefik-dashboard-route
namespace: go-micro
spec:
entryPoints:
- web
routes:
- match: Host(`traefik.guaosi.com`)
kind: Rule
services:
- name: traefik # svc的名称
port: 8080 # cluster 访问
- match: Host(`apigw.guaosi.com`)
kind: Rule
services:
- name: svc-apigw # svc的名称
port: 8091 # cluster 访问
执行
kubectl create -f traefik/k8s/k8s-crd-router-traefik.yml
配置 Host 文件
客户端想通过域名访问服务,必须要进行DNS
解析,由于这里没有DNS
服务器进行域名解析,所以修改hosts
文件将Traefik
、apigw
所在节点服务器的IP
和自定义Host
绑定,。打开电脑的Hosts
配置文件,往其加入下面配置:
192.168.1.200 traefik.guaosi.com
192.168.1.200 apigw.guaosi.com
验证
Dashboard
打开浏览器输入地址:traefik.guaosi.com ,即可打开Traefik Dashboard
服务
> curl -X POST -d "username=guaosi&password=guaosi" http://apigw.guaosi.com/account/register
{"code":0,"message":""}
代码仓库
最终的代码和部署文件,已经传至github,欢迎star。