个人单机服务器微服务实践

前言

  • 虽然去年就已经开始接触微服务, 并且在个人服务器运行了起来, 但是都是使用直连模式, 今天正好有空升级go-zero的代码, 同时更新架构

框架

  • 因为去年用的就是go-zero, 今天只是更新的版本 github.com/zeromicro/go-zero
  • 代码目录基本就是根目录app下会有双层服务, 根目录下有pkg公用代码,比如配置中心获取, 然后是公共构建Dockerfile(所有服务)

个人单机服务器微服务实践

  • Dockerfile使用双阶段构建, 然后构建的时候会传递参数SERVICE_PATH表示要构建的服务
    • docker build -t xxx:xx --build-arg SERVICE_PATH=${SERVICE_PATH} .
FROM golang:alpine3.18 AS builder

LABEL stage=gobuilder

## 定义项目的根目录
ARG SERVICE_PATH
ENV CGO_ENABLED 0

RUN echo -e 'https://mirrors.aliyun.com/alpine/v3.18/main/\nhttps://mirrors.aliyun.com/alpine/v3.18/community/' > /etc/apk/repositories && apk update --no-cache && apk add --no-cache tzdata

WORKDIR /build

COPY . .
RUN go env -w GO111MODULE=on
RUN go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/,direct
RUN go mod download
RUN go build -ldflags="-s -w" -o /build/main /build/app/${SERVICE_PATH}

## 使用空镜像构建
FROM scratch

## 定义项目的根目录
ARG SERVICE_PATH

COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai
ENV TZ Asia/Shanghai

WORKDIR /app
COPY --from=builder /build/main /app/main

ENTRYPOINT  ["./main"]
  • 单机部署同一个服务多份, 端口会占用, 所以会动态获取一个可用的端口, 然后在go-zero启动时使用这个生成的端口(而不是配置文件中的)
func GetAvailablePort() (int, error) {
    address, err := net.ResolveTCPAddr("tcp", "0.0.0.0:0")
    if err != nil {
        return 0, err
    }

    listener, err := net.ListenTCP("tcp", address)
    if err != nil {
        return 0, err
    }

    defer listener.Close()
    return listener.Addr().(*net.TCPAddr).Port, nil
}

服务注册发现 && 配置中心

  • 个人搭建最主要的就是追求低成本且能正常运行起来
  • 服务注册&&发现用的 github.com/etcd-io/etcd
  • 配置中心也用的 etcd (只在启动的时候拉取), 然后配置管理使用的 github.com/evildecay/etcdkeeper
  • etcdkeeper效果很不错, 内置支持json, yaml等配置

个人单机服务器微服务实践

  • docker-compose用来搭建基础服务
version: '3'

services:
 etcd: container_name: etcd image: bitnami/etcd:3 restart: always environment: - ETCDCTL_API=3 - ALLOW_NONE_AUTHENTICATION=yes - ETCD_ADVERTISE_CLIENT_URLS=http://127.0.0.1:2379 volumes: - "./data/etcd:/bitnami/etcd/data"#    ports:
#      - "2379:2379"
#      - "2380:2380"
 network_mode: host etcdkeeper: hostname: etcdkeeper image: evildecay/etcdkeeper:v0.7.6#    ports:
#      - "8080:8080"
 network_mode: host restart: always

CI

  • 我个人使用的是coding, 个人免费注册, 然后每个月有10小时的构建额度, 基本上够用了
  • 会在构建的时候注入环境变量SERVICE_PATHSERVICE_NUMBER, 标识本次构建的服务和部署的服务数量
  • SERVICE_PATH会在前面说的docker build参数使用
  • SERVICE_NUMBER 就是启动多少个容器, 伪代码如下
script {
  def count = SERVICE_NUMBER.toInteger();
  echo "部署: ${count} 个"
  for (int i = 0; i < count; i++) {
    sshCommand(
      remote: remoteConfig,
      command: "docker run -d --net=host --restart=always --name ${SERVICE_NAME}-${i} ${IMAGE_NAME}:${CI_BUILD_NUMBER}",
      sudo: true,
    )
    echo "${SERVICE_NAME}-${i}..."
  }
}

个人单机服务器微服务实践

End

  • 当我更新代码时, 会选择部署的服务, 最终部署后的效果如下图

个人单机服务器微服务实践

原文: www.shiguopeng.cn/posts/2023082711...

本作品采用《CC 协议》,转载必须注明作者和本文链接
当神不再是我们的信仰,那么信仰自己吧,努力让自己变好,不辜负自己的信仰!
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
42
粉丝
158
喜欢
713
收藏
347
排名:30
访问:22.2 万
私信
所有博文
社区赞助商