牌类游戏使用微服务重构笔记(十二): 在k8s中部署

micro在k8s中部署是至关容易的,本文以项目1、项目2、公共项目为例详解部署方式git

helm

helm是k8s的软件包管理工具,简单阅读几分钟即可上手使用,具体参见文档连接github

配置

键入micro --help你会发现有许多的配置项,这些配置项在开发阶段和上线环境中可能会有不一样,例如开发阶段可能没有指定--registry, 那么micro默认使用了mdns进行服务发现,可是线上环境中通常不太会使用这个golang

好在micro在设计之初就考虑到了这些需求,因此这些配置项都是以插件方式提供的,例如etcd、etcdv三、kubernetes、nats、zookeeper、consul这些均可以轻易的接入到micro,而且使用一行代码进行切换 --registry=consulweb

micro中的broker(pub/sub)、transport拓展方式与registry相似,再次不作赘述,根据本身的需求进行选择便可api

  • 服务发现

既然是微服务框架,那么服务发现确定是比较重要的环节bash

  1. 使用k8s自带的服务发现

以前的博客中有对k8s service作过简单介绍 kubernetes学习笔记(二):k8s初体验,也是首推的服务发现方式。微信

服务的访问方式为k8s service => micro service(k8s pod),这样还能够利用到k8s service自带的健康检查。app

不过这种部署方式在笔者当时有命名空间问题还未解决,再加上部署较为复杂,所以我尚未在生产环境中使用,待项目后续更改成k8s service后再来完善这里cors

  1. 使用consul

个人项目中使用的是consul服务发现,比较简单。使用consul-helm软件包,便可在k8s中建立consul集群。一个命名空间建立一个consul集群便可,多个项目能够共用。框架

使用consul服务发现, 访问方式为 api网关(k8s pod) => api(k8s pod) => srv(k8s pod),至关于pod之间的访问,没有通过k8s service 天然也没法使用健康检查

helm install --name=ack-consul-prod --namespace=yourNamespace ./

  • 建立helm软件包

helm create yourChartName 建立一个空的软件包,包含如下文件列表

foo/
	  |
	  |- .helmignore   # 相似于.gitignore排除一些文件使用
	  |
	  |- Chart.yaml    # 软件包配置信息
	  |
	  |- values.yaml   # 软件包的各类数值
	  |
	  |- charts/       # 依赖
	  |
	  |- templates/    # 软件包使用的模板文件,+ values.yaml里的数值,组成k8s的yaml文件提供给 kubectl

复制代码

咱们主要须要编辑的就是 templates和values.yaml,能够先把templates文件夹清空,values.yaml数值都删掉。

  • 部署api网关

若是你的项目有对外提供的接口,那么就须要一个api 网关。在templates文件夹中添加api.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: micro-api
spec:
  replicas: {{ .Values.apiReplicaCount }}
  selector:
    matchLabels:
      app: micro-api-deployment
      env: {{ .Values.env }}
  template:
    metadata:
      labels:
        app: micro-api-deployment
        env: {{ .Values.env }}
    spec:
      imagePullSecrets:
        - name: {{ $.Values.imagePullSecretsName }}
      containers:
        - name: api
          args:
            - bin/micro
            - --registry={{ .Values.registry }}
            - --registry_address={{ .Values.registryAddress }}
            - --selector=cache
            - api
            - --namespace={{ .Values.microNameSpace }}.api
            - --handler={{ .Values.microHandler }}
            - --cors-allowed-headers={{ .Values.corsAllowedHeaders }}
            - --cors-allowed-origins={{ .Values.corsAllowedOrigins }}
            - --cors-allowed-methods={{ .Values.corsAllowedMethods }}
          image: {{ .Values.apiImage }}:{{ .Values.apiImagesVersion }}
          imagePullPolicy: Always
          ports:
            - containerPort: 8080
              name: api-port
---
apiVersion: v1
kind: Service
metadata:
  name: micro-api
  labels:
    name: micro-api-svc
spec:
  type: ClusterIP
  ports:
    - name: http
      port: 80
      targetPort: 8080
  selector:
    app: micro-api-deployment
    env: {{ .Values.env }}
复制代码
  1. 不难看出,其实就是发布了一组pod来启动 micro api,即api网关
  2. 出现了许多的 {{}},这是helm的插值语法,里面的数值都取自于 values.yaml, 所以要把template 尽量的作到配置化
  3. 还出现了一个service,这是由于集群外部访问集群,须要使用ingress路由,路由又访问服务,服务转发到pod(http 请求 => k8s ingress => k8s service => k8s pods),这里的pod 就是咱们部署的micro api,接下来才是micro内部的处理

此时已经能够发布一下试试看了,与发布consul集群相似

执行helm install --name=yourProjectName --namespace=yourNamespace ./ 观察下k8s集群的变化状况,添加k8s ingress,访问一下试试看

  • 部署api和srv

正如前文所说,若是不使用k8s service做为服务发现,那么micro内部的东西对于k8s来讲 就是一堆pod而已。因此不管是api层仍是srv层,部署只须要pod便可

这里以一个帐户中心的api和srv举例

{{- range .Values.versions }}
apiVersion: apps/v1
kind: Deployment
metadata:
  name: account-api-{{ .version | replace "." "" }}
  labels:
    name: {{ .name }}
    version: {{ .version }}
spec:
  replicas: {{ $.Values.accountApiReplicaCount }}
  selector:
    matchLabels:
      app: account-api-deployment
      env: {{ $.Values.env }}
      version: {{ .version }}
  template:
    metadata:
      labels:
        app: account-api-deployment
        env: {{ $.Values.env }}
        version: {{ .version }}
    spec:
      volumes:
        - name: host-time
          hostPath:
            path: /etc/localtime
      imagePullSecrets:
        - name: {{ $.Values.imagePullSecretsName }}
      containers:
        - name: account
          args:
            - bin/ccgame
            - --registry={{ $.Values.registry }}
            - --registry_address={{ $.Values.registryAddress }}
            - --selector=cache
            - --server_address=0.0.0.0:8080
            - start
            - --name=account
            - --resource=api
          image: {{ .image }}:{{ .version }}
          volumeMounts:
              - name: host-time
                mountPath: /etc/localtime
          imagePullPolicy: Always
          env:
            - name: ENV
              valueFrom:
                fieldRef:
                  fieldPath: metadata.labels['env']
            - name: VERSION
              valueFrom:
                fieldRef:
                  fieldPath: metadata.labels['version']
          ports:
            - containerPort: 8080
              name: account-port
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: account-srv-{{ .version | replace "." "" }}
  labels:
    name: {{ .name }}
    version: {{ .version }}
spec:
  replicas: {{ $.Values.accountSrvReplicaCount }}
  selector:
    matchLabels:
      app: account-srv-deployment
      env: {{ $.Values.env }}
      version: {{ .version }}
  template:
    metadata:
      labels:
        app: account-srv-deployment
        env: {{ $.Values.env }}
        version: {{ .version }}
    spec:
      volumes:
        - name: host-time
          hostPath:
            path: /etc/localtime
      imagePullSecrets:
        - name: {{ $.Values.imagePullSecretsName }}
      containers:
        - name: account
          args:
            - bin/ccgame
            - --registry={{ $.Values.registry }}
            - --registry_address={{ $.Values.registryAddress }}
            - --selector=cache
            - --server_address=0.0.0.0:8080
            - start
            - --name=account
            - --resource=srv
          image: {{ .image }}:{{ .version }}
          volumeMounts:
              - name: host-time
                mountPath: /etc/localtime
          imagePullPolicy: Always
          env:
            - name: ENV
              valueFrom:
                fieldRef:
                  fieldPath: metadata.labels['env']
            - name: VERSION
              valueFrom:
                fieldRef:
                  fieldPath: metadata.labels['version']
          ports:
            - containerPort: 8080
              name: account-port
---
{{ end }}
复制代码

添加了新的模板,再次发布时就属于更新了,执行helm upgrade yourProjectName ./更新这个软件包,再次观察集群的变化状况。

会发现,以前的api.yaml建立的api部署没有发生变化,集群新建立了 account-api、account-srv两个部署,以及一些pod。

helm的更新其实就是提交给kubectl去执行yaml文件,所以每次更新时集群将会发生什么变化,去思考kubectl执行这些文件会发生什么变化便可,这点很重要,每次发布前思考一下,避免出现问题

每次helm更新都会造成一个版本,执行helm history yourProjectName可查看。万一更新出错了,别慌。执行helm rollback yourProjectName 1,即可回滚上一个第1次发布的状态

values.yaml描述的是helm发布后的最终状态,例如如我想同时保留两套api和srv

# 多版本配置
versions:
  - name: stable # 目前正在使用的版本
    image: yourDockerImageAddress # 镜像
    version: 1.0.0
  - name: next # 目前正在使用的版本
    image: yourDockerImageAddress # 镜像
    version: 1.0.1
复制代码

更新时,若是有这样的helm语句 {{- range .Values.versions }},就至关于遍历了一下,造成了两个yaml提交给kubectl,天然会造成两套api和srv。具体可参照helm文档。

同理,若是我想下掉某一个版本, 只需更改

# 多版本配置
versions:
  - name: stable # 目前正在使用的版本
    image: yourDockerImageAddress # 镜像
    version: 1.0.1
复制代码
  • 多项目部署

有时候,免不了会出现一些公用的服务在不一样的项目中。对于我这种有强迫症的选手来讲,再发布一遍确定接受不了。那么就能够把公众的服务,抽离出来,做为单独的软件包来发布。

例如,项目1(game1)和项目2(game2)都有帐户相关的服务,那么我就能够把帐户中心抽出来当作一个单独的项目(account)。

按照以上步骤,作成3个helm软件包,game一、game二、account,使用同一个服务发现集群。发布好时候,观察micro web面板,你会发现3个项目的一堆服务都在里面。更新其中一个项目不会影响到另外的,达到了咱们的目标。

最后就是game一、game二、account,3个项目之间如何互相访问的问题。其实这根本不是一个问题,牌类游戏使用微服务重构笔记(四): micro框架使用经验中说过,micro是按照[命名空间].[资源类型].[服务名]定义服务的,那么提供完整的服务名字,就可建立这个服务的客户端。

例如:

game1项目使用game1做为micro命名空间, 有game1.api.user、game1.srv.user

game2项目使用game2做为micro命名空间, 有game1.api.user、game1.srv.user

account项目使用account做为micro命名空间, 有account.srv.account

game1须要访问account项目,只需使用account.srv.account和对应的proto建立客户端;须要访问game2项目,只需使用game2.srv.user和对应的proto建立客户端。即便他们之间不在同一个服务发现里,也没有关系,建立客户端时增长服务发现的选项便可。

这样的部署方式在多个项目有关联时,很是的方便,补一下结构图

本人学习golang、micro、k8s、grpc、protobuf等知识的时间较短,若是有理解错误的地方,欢迎批评指正,能够加我微信一块儿探讨学习

相关文章
相关标签/搜索