美文网首页
Go微服务架构实战 中篇:2. 基于k8s部署服务和注册中心,验

Go微服务架构实战 中篇:2. 基于k8s部署服务和注册中心,验

作者: stackfuture | 来源:发表于2022-01-04 20:02 被阅读0次

    Go微服务架构实战-公粽号:堆栈future

    本系列文章主要是针对云原生领域微服务架构的实战,包括网关,k8s,etcd以及grpc等相关技术的应用,同时也会把服务发现与注册,熔断,降级,限流以及分布式锁等加入到系列当中作为补充,课程的最后也会安排分布式链路追踪框架的学习,监控平台的搭建以及灰度发布等技术服务,所以总体来讲,课程范围涉及技术领域较广,知识面比较宽,大家下来各取所需尽量做到熟悉和应用,之后有时间了在研究下源码,乐哉!

    上篇已经完成,大家可以看下,我这里贴出来了,中篇从这周开始陆续为大家产出,因为太耗费精力,所以还望大家多多支持!

    Go微服务架构实战目录

    1. 微服务架构上篇

    1. grpc技术介绍

    2. grpc+protobuf+网关实战

    3. etcd技术介绍

    4. 基于etcd的服务发现与注册

    5. 基于etcd的分布式锁实战

    2. 微服务架构中篇

    1. k8s架构介绍

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

    对于k8s来说,所有资源对象都有yaml文件来创建,k8s提供一个工具kubectl来和API server交互,从而创建相应的资源对象。

    我们的项目有一个服务端,有一个客户端,还有一个服务发现和注册中心etcd。

    我们原来就是裸机用supervisor去托管各个服务进程,比较简单直接,现在用k8s尝试去部署一下。

    1. 创建server pod的步骤

    1. 首先为了让server进行容器化部署,得现有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到二进制镜像内

    CMD [ "svr", "-port", "50009"] //运行服务 指定参数是端口` </pre>

    1. 用docker build构建镜像docker build -t k8s-grpc-demo -f ./Dockerfile .

    2. 用刚才的镜像创建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创建podkubectl apply -f server.yaml没有指定namespace,默认是在default空间。

    2. 创建之后看下pod是否起来kubectl get pod查看

      图片

      发现server的pod已经running了。

    为了多测试几个服务,我们复制创建相同的Dockerfile和server.yaml,比如Dockerfile1 Dockerfile2 以及server1.yaml和server2.yaml,这里就不把配置粘贴出来,可以从github地址查看哈。

    2. 创建client的pod的步骤

    1. 创建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. 用刚才的镜像创建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创建podkubectl apply -f client.yaml没有指定namespace,默认是在default空间。

    2. 创建之后看下pod是否起来kubectl get pod查看

      图片

      发现client的pod已经running了。

    3. 创建etcd的pod的步骤

    因为etcd镜像我们用Docker官网里面的,所以不用自己构建了,这里直接把创建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 //数据存储挂载路径
    name: etcd-data
    env:
    - name: host_ip
    valueFrom:
    fieldRef:
    fieldPath: status.podIP
    command: ["/bin/sh","-c"]
    args: //启动etcd
    - /usr/local/bin/etcd //etcd的可执行文件
    --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命令直接创建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查看

    图片

    发现etcd的pod是running了。

    但是有pod不一定有对内提供服注册和发现能力,得需要service对内pod提供服务,因此创建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的名称 服务注册和发现的时候使用 很重要 spec: ports: - name: client port: 2379 //service对内pod的client访问端口 targetPort: 2379 - name: etcd3 port: 2380 //service对内pod的server访问端口 targetPort: 2380 selector: app: etcd3 //找到需要关联的etcd pod 即上面创建的etcd pod </pre>

    我们看下是否创建成功: 图片

    bingo。至此服务,客户端以及以及etcd的服务注册和发现中心部署好了。

    接下来做点小改动,就可以实现服务注册和发现了。

    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 大家下来在源码中可以看到实现哈 func GetLocalIP() string </pre>

    然后有两个地方需要修改:

    1. 注册中心的地址(etcd address) 从原来的localhost改为http://etcd3:2379,至于为什么,我可以做个简单介绍,因为不同pod之间localhost是不通的,localhost只能在同一个Pod中的容器之间相互通信,不同pod是没有办法通信的。所以需要通信的pod必须通过etcd的svc名称去访问,k8s集群内提供了相关dns自动会解析到svc ip的,所以pod就可以访问etcd注册中心。

    2. 把原来服务默认监听的localhost改为从本地获取ip

    1,2修改代码如下: 图片

    4. 客户端发现

    客户端也需要修改注册中心地址: 图片

    5. 验证

    等以上修改完成之后,我们还需要经历上述的重新构建步骤和部署步骤,因为代码改动了哦。

    我们重新部署完成之后,在最后启动客户端的时候发现日志中有了多个服务端的请求,而且是RR轮循返回的响应,我们可以看下客户端和服务的pod列表: 图片 客户端日志如下: 图片

    公粽号:堆栈future

    至此我们基于k8s的服务部署和服务注册中心就搭建起来了,后续为大家带来故障转移,滚动更新以及扩缩容等内容,欢迎大家关注,分享和点赞。

    github地址:

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

    相关文章

      网友评论

          本文标题:Go微服务架构实战 中篇:2. 基于k8s部署服务和注册中心,验

          本文链接:https://www.haomeiwen.com/subject/tbkccrtx.html