Go微服務架構實戰(zhàn) 中篇:2. 基于k8s部署服務和注冊中心,驗證服務注冊和發(fā)現(xiàn)

Go微服務架構實戰(zhàn)-公粽號:堆棧future

本系列文章主要是針對云原生領域微服務架構的實戰(zhàn),包括網(wǎng)關,k8s,etcd以及grpc等相關技術的應用,同時也會把服務發(fā)現(xiàn)與注冊,熔斷,降級,限流以及分布式鎖等加入到系列當中作為補充,課程的最后也會安排分布式鏈路追蹤框架的學習,監(jiān)控平臺的搭建以及灰度發(fā)布等技術服務,所以總體來講,課程范圍涉及技術領域較廣,知識面比較寬,大家下來各取所需盡量做到熟悉和應用,之后有時間了在研究下源碼,樂哉!

上篇已經(jīng)完成,大家可以看下,我這里貼出來了,中篇從這周開始陸續(xù)為大家產(chǎn)出,因為太耗費精力,所以還望大家多多支持!

Go微服務架構實戰(zhàn)目錄

1. 微服務架構上篇

1. grpc技術介紹

2. grpc+protobuf+網(wǎng)關實戰(zhàn)

3. etcd技術介紹

4. 基于etcd的服務發(fā)現(xiàn)與注冊

5. 基于etcd的分布式鎖實戰(zhàn)

2. 微服務架構中篇

1. k8s架構介紹

2. 基于pod和deployment的容器化部署

對于k8s來說,所有資源對象都有yaml文件來創(chuàng)建,k8s提供一個工具kubectl來和API server交互,從而創(chuàng)建相應的資源對象。

我們的項目有一個服務端,有一個客戶端,還有一個服務發(fā)現(xiàn)和注冊中心etcd。

我們原來就是裸機用supervisor去托管各個服務進程,比較簡單直接,現(xiàn)在用k8s嘗試去部署一下。

1. 創(chuàng)建server pod的步驟

  1. 首先為了讓server進行容器化部署,得現(xiàn)有Dockerfile,我們來看看server的(Dockerfile):

<pre data-tool="mdnice編輯器" style="box-sizing: border-box !important; margin: 10px 0px; padding: 0px; outline: 0px; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 14px; overflow: auto; display: block; color: rgb(33, 37, 41); max-width: 100%; overflow-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.8px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0.8px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">`FROM golang AS build-env //從Docker鏡像倉庫找golang鏡像
ADD . /go/src/app
WORKDIR /go/src/app
RUN GOOS=linux GOARCH=386 go build -mod vendor cmd/svr/svr.go //構建鏡像

FROM alpine //構建二進制鏡像

COPY --from=build-env /go/src/app/svr /usr/local/bin/svr //從golang盡享copy到二進制鏡像內(nèi)

CMD [ "svr", "-port", "50009"] //運行服務 指定參數(shù)是端口` </pre>

  1. 用docker build構建鏡像docker build -t k8s-grpc-demo -f ./Dockerfile .

  2. 用剛才的鏡像創(chuàng)建server的yaml(server.yaml):

<pre data-tool="mdnice編輯器" style="box-sizing: border-box !important; margin: 10px 0px; padding: 0px; outline: 0px; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 14px; overflow: auto; display: block; color: rgb(33, 37, 41); max-width: 100%; overflow-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.8px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0.8px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">apiVersion: apps/v1 kind: Deployment //Deployment就是管理Pod資源的對象 metadata: name: k8sdemo-deploy //Pod名稱 labels: app: k8sdemo //Pod標簽 為service提供負載均衡使用 spec: replicas: 1 //副本為1 selector: matchLabels: app: k8sdemo template: metadata: labels: app: k8sdemo spec: containers: - name: k8sdemo //容器名稱 image: k8s-grpc-demo:latest //用剛才生成的本地鏡像 imagePullPolicy: Never //從本地構建 ports: - containerPort: 50007 //容器端口 </pre>

  1. 用kubectl創(chuàng)建podkubectl apply -f server.yaml沒有指定namespace,默認是在default空間。

  2. 創(chuàng)建之后看下pod是否起來kubectl get pod查看

    圖片

    發(fā)現(xiàn)server的pod已經(jīng)running了。

為了多測試幾個服務,我們復制創(chuàng)建相同的Dockerfile和server.yaml,比如Dockerfile1 Dockerfile2 以及server1.yaml和server2.yaml,這里就不把配置粘貼出來,可以從github地址查看哈。

2. 創(chuàng)建client的pod的步驟

  1. 創(chuàng)建Dockerfile(Dockerfile3)

<pre data-tool="mdnice編輯器" style="box-sizing: border-box !important; margin: 10px 0px; padding: 0px; outline: 0px; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 14px; overflow: auto; display: block; color: rgb(33, 37, 41); max-width: 100%; overflow-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.8px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0.8px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">`FROM golang AS build-env
ADD . /go/src/app
WORKDIR /go/src/app
RUN GOOS=linux GOARCH=386 go build -mod vendor cmd/cli/cli.go

FROM alpine

COPY --from=build-env /go/src/app/cli /usr/local/bin/cli

CMD [ "cli"]` </pre>

  1. 構建Dockerfiledocker build -t k8s-grpc-demo3 -f ./Dockerfile3 .

  2. 用剛才的鏡像創(chuàng)建client的yaml(client.yaml):

<pre data-tool="mdnice編輯器" style="box-sizing: border-box !important; margin: 10px 0px; padding: 0px; outline: 0px; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 14px; overflow: auto; display: block; color: rgb(33, 37, 41); max-width: 100%; overflow-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.8px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0.8px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">apiVersion: apps/v1 kind: Deployment metadata: name: k8sdemo-cli-deploy //客戶端pod名稱 labels: app: k8sdemo spec: replicas: 1 selector: matchLabels: app: k8sdemo template: metadata: labels: app: k8sdemo spec: containers: - name: k8sdemocli image: k8s-grpc-demo3:latest //用剛才構建的鏡像 imagePullPolicy: Never ports: - containerPort: 50010 </pre>

  1. 用kubectl創(chuàng)建podkubectl apply -f client.yaml沒有指定namespace,默認是在default空間。

  2. 創(chuàng)建之后看下pod是否起來kubectl get pod查看

    圖片

    發(fā)現(xiàn)client的pod已經(jīng)running了。

3. 創(chuàng)建etcd的pod的步驟

因為etcd鏡像我們用Docker官網(wǎng)里面的,所以不用自己構建了,這里直接把創(chuàng)建etcd的pod的yaml貼出來。

<pre data-tool="mdnice編輯器" style="box-sizing: border-box !important; margin: 10px 0px; padding: 0px; outline: 0px; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 14px; overflow: auto; display: block; color: rgb(33, 37, 41); max-width: 100%; overflow-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.8px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0.8px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">`apiVersion: apps/v1
kind: Deployment
metadata:
name: etcd3 //etcd名稱
labels:
name: etcd3
spec:
replicas: 1
selector:
matchLabels:
app: etcd3
template:
metadata:
labels:
app: etcd3
spec:
containers:
- name: etcd3 //容器名稱
image: quay.io/coreos/etcd:latest //etcd鏡像
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /data //數(shù)據(jù)存儲掛載路徑
name: etcd-data
env:
- name: host_ip
valueFrom:
fieldRef:
fieldPath: status.podIP
command: ["/bin/sh","-c"]
args: //啟動etcd
- /usr/local/bin/etcd //etcd的可執(zhí)行文件
--name etcd3 //etcd集群的名稱
--initial-advertise-peer-urls http://0.0.0.0:2380
--listen-peer-urls http://0.0.0.0:2380
--listen-client-urls http://0.0.0.0:2379
--advertise-client-urls http://0.0.0.0:2379
--initial-cluster-token etcd-cluster-1
--initial-cluster etcd3=http://0.0.0.0:2380
--initial-cluster-state new
--data-dir=/data

  volumes:
    - name: etcd-data
      emptyDir: {} //當前容器作為存儲路徑` </pre>

然后用kubectl命令直接創(chuàng)建pod

<pre data-tool="mdnice編輯器" style="box-sizing: border-box !important; margin: 10px 0px; padding: 0px; outline: 0px; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 14px; overflow: auto; display: block; color: rgb(33, 37, 41); max-width: 100%; overflow-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.8px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0.8px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">kubectl apply -f etc.yaml </pre>

kubectl get pod查看

圖片

發(fā)現(xiàn)etcd的pod是running了。

但是有pod不一定有對內(nèi)提供服注冊和發(fā)現(xiàn)能力,得需要service對內(nèi)pod提供服務,因此創(chuàng)建etcd的service如下:

<pre data-tool="mdnice編輯器" style="box-sizing: border-box !important; margin: 10px 0px; padding: 0px; outline: 0px; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 14px; overflow: auto; display: block; color: rgb(33, 37, 41); max-width: 100%; overflow-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.8px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0.8px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">apiVersion: v1 kind: Service metadata: name: etcd3 //service的名稱 服務注冊和發(fā)現(xiàn)的時候使用 很重要 spec: ports: - name: client port: 2379 //service對內(nèi)pod的client訪問端口 targetPort: 2379 - name: etcd3 port: 2380 //service對內(nèi)pod的server訪問端口 targetPort: 2380 selector: app: etcd3 //找到需要關聯(lián)的etcd pod 即上面創(chuàng)建的etcd pod </pre>

我們看下是否創(chuàng)建成功:
圖片

bingo。至此服務,客戶端以及以及etcd的服務注冊和發(fā)現(xiàn)中心部署好了。

接下來做點小改動,就可以實現(xiàn)服務注冊和發(fā)現(xiàn)了。

3. 服務注冊

因為我們的pod也是有ip的,所以服務注冊之前得先獲取pod的ip。代碼如下:

<pre data-tool="mdnice編輯器" style="box-sizing: border-box !important; margin: 10px 0px; padding: 0px; outline: 0px; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 14px; overflow: auto; display: block; color: rgb(33, 37, 41); max-width: 100%; overflow-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.8px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0.8px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">//獲取本地eth0 IP 大家下來在源碼中可以看到實現(xiàn)哈 func GetLocalIP() string </pre>

然后有兩個地方需要修改:

  1. 注冊中心的地址(etcd address) 從原來的localhost改為http://etcd3:2379,至于為什么,我可以做個簡單介紹,因為不同pod之間localhost是不通的,localhost只能在同一個Pod中的容器之間相互通信,不同pod是沒有辦法通信的。所以需要通信的pod必須通過etcd的svc名稱去訪問,k8s集群內(nèi)提供了相關dns自動會解析到svc ip的,所以pod就可以訪問etcd注冊中心。

  2. 把原來服務默認監(jiān)聽的localhost改為從本地獲取ip

1,2修改代碼如下:
圖片

4. 客戶端發(fā)現(xiàn)

客戶端也需要修改注冊中心地址:
圖片

5. 驗證

等以上修改完成之后,我們還需要經(jīng)歷上述的重新構建步驟和部署步驟,因為代碼改動了哦。

我們重新部署完成之后,在最后啟動客戶端的時候發(fā)現(xiàn)日志中有了多個服務端的請求,而且是RR輪循返回的響應,我們可以看下客戶端和服務的pod列表:
圖片

客戶端日志如下:
圖片

公粽號:堆棧future

至此我們基于k8s的服務部署和服務注冊中心就搭建起來了,后續(xù)為大家?guī)砉收限D移,滾動更新以及擴縮容等內(nèi)容,歡迎大家關注,分享和點贊。

github地址:

https://github.com/guojiangli/k8s-grpc-demo

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容