3.4 Kubernetes下的构建执行

未匹配的标注

整理环境#

上一章中,我们通过 Docker Compose 已经创建了 etcdaccountapigwTraefik 多个镜像对应的容器。为了不被干扰,并且我们改用 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-

以下操作都是在 KubetnetesMaster 节点做的

私有仓库#

如果你使用的是公开公共仓库镜像,即不需要登陆,就可以下载的镜像,则可以跳过私有仓库这个步骤。

我的镜像已经开放了公有权限,可以直接下载,不需要进行验证。如果你想使用自己的镜像,请按照下面进行操作。

阿里云登陆#

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-micronamespace, 我们把需要的 poddeploysvcsecret 等等都放在这个 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 的负载均衡,只需要扩容 deployreplicas 即可 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 的负载均衡,只需要扩容 deployreplicas 即可 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#

由于 KubernetesIngress 只能支持四层的 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 配置文件#

下面配置中可以通过配置 kubernetesCRDkubernetesIngress 两项参数,让 Traefik 支持 CRDIngress 两种路由方式。
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 方式绑定服务器 80443 端口,方便流量通过物理机进入 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 提供的视图看板,所以,首先配置基于 HTTPTraefik 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 文件将 Traefikapigw 所在节点服务器的 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。

github.com/guaosi/go-micro-build

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 查看所有版本


暂无话题~