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等知識的時間較短,若是有理解錯誤的地方,歡迎批評指正,能夠加我微信一塊兒探討學習