牌類遊戲使用微服務重構筆記(十二): 在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等知識的時間較短,若是有理解錯誤的地方,歡迎批評指正,能夠加我微信一塊兒探討學習

相關文章
相關標籤/搜索