micro在k8s中部署是至关容易的,本文以项目1、项目2、公共项目为例详解部署方式git
helm是k8s的软件包管理工具,简单阅读几分钟即可上手使用,具体参见文档连接github
键入micro --help
你会发现有许多的配置项,这些配置项在开发阶段和上线环境中可能会有不一样,例如开发阶段可能没有指定--registry
, 那么micro默认使用了mdns进行服务发现,可是线上环境中通常不太会使用这个golang
好在micro在设计之初就考虑到了这些需求,因此这些配置项都是以插件方式提供的,例如etcd、etcdv三、kubernetes、nats、zookeeper、consul这些均可以轻易的接入到micro,而且使用一行代码进行切换 --registry=consul
web
micro中的broker(pub/sub)、transport拓展方式与registry相似,再次不作赘述,根据本身的需求进行选择便可api
既然是微服务框架,那么服务发现确定是比较重要的环节bash
以前的博客中有对k8s service作过简单介绍 kubernetes学习笔记(二):k8s初体验,也是首推的服务发现方式。微信
服务的访问方式为k8s service => micro service(k8s pod),这样还能够利用到k8s service自带的健康检查。app
不过这种部署方式在笔者当时有命名空间问题还未解决,再加上部署较为复杂,所以我尚未在生产环境中使用,待项目后续更改成k8s service后再来完善这里cors
个人项目中使用的是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 create yourChartName
建立一个空的软件包,包含如下文件列表
foo/
|
|- .helmignore # 相似于.gitignore排除一些文件使用
|
|- Chart.yaml # 软件包配置信息
|
|- values.yaml # 软件包的各类数值
|
|- charts/ # 依赖
|
|- templates/ # 软件包使用的模板文件,+ values.yaml里的数值,组成k8s的yaml文件提供给 kubectl
复制代码
咱们主要须要编辑的就是 templates和values.yaml,能够先把templates文件夹清空,values.yaml数值都删掉。
若是你的项目有对外提供的接口,那么就须要一个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 }}
复制代码
此时已经能够发布一下试试看了,与发布consul集群相似
执行helm install --name=yourProjectName --namespace=yourNamespace ./
观察下k8s集群的变化状况,添加k8s ingress,访问一下试试看
正如前文所说,若是不使用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等知识的时间较短,若是有理解错误的地方,欢迎批评指正,能够加我微信一块儿探讨学习