Go-Zero项目开发2: 用户服务构建与部署自动化 📅 2026/7/17 20:09:05 纲要项目结构规划apps/所有微服务集合user/用户服务包含api与rpc子服务im/、social/后续服务预留deploy/部署相关脚本与配置dockerfile/各服务 Dockerfilemakefile/服务构建 Makefilescripts/容器部署 Shell 脚本common/公共工具包docker-compose.yml、Makefile项目级统一入口用户服务基础定义Proto文件编写user.protogo-zero代码生成goctl rpc构建自动化Dockerfile参数化构建不同环境的容器镜像Makefile编译、镜像构建、推送至私有仓库部署 Shell 脚本容器启停、镜像清理与重新拉取测试环境部署与验证etcd、Redis、MySQL基础服务启动注意etcd服务发现地址配置通过gRPC调用Ping方法确认服务可用用户服务业务回顾本项目为即时通讯系统用户服务处于基础地位主要承担以下职责用户注册与登录支持用户名/手机号等方式用户信息查询与搜索为其他服务社交、IM提供用户基本信息在开始编码之前优先完成服务脚手架搭建与部署脚本编写确保后续迭代中能够快速编译、构建镜像与部署将开发精力集中在业务逻辑上。项目目录结构设计在以go-zero为框架的微服务体系中推荐将所有应用服务统一放在apps/下每个服务内部可进一步区分为api与rpc子服务。同时将部署相关的 Dockerfile、Makefile 与 Shell 脚本集中放置在deploy/中形成清晰的工程结构im-system/ ├── apps/ # 服务聚合根 │ └── user/ # 用户服务 │ ├── rpc/ # gRPC 服务 │ │ ├── internal/ │ │ │ ├── config/ │ │ │ ├── server/ │ │ │ ├── svc/ │ │ │ └── logic/ │ │ ├── user.proto │ │ └── user.go │ └── api/ # HTTP API 服务预留 ├── deploy/ # 部署相关 │ ├── dockerfile/ # 各服务 Dockerfile │ │ └── user-rpc/ │ ├── makefile/ # 各服务 Makefile │ │ └── user-rpc.mk │ └── scripts/ # 容器部署 Shell 脚本 │ ├── deploy_user_rpc_test.sh │ └── start_all.sh ├── common/ # 公共库、工具函数 ├── docker-compose.yml # 基础中间件编排 ├── Makefile # 总控入口 └── go.mod该结构将“服务代码”与“部署描述”解耦便于多服务扩展。用户服务 Proto 定义与代码生成首先在apps/user/rpc/下创建user.proto文件定义用户服务的 RPC 接口与消息体。核心方法包括Ping健康检查、Login、Register、GetUserInfo、FindUser。syntax proto3; package user; option go_package ./user; message PingRequest { string msg 1; } message PingResponse { string msg 1; } message LoginRequest { string username 1; string password 2; } message LoginResponse { int64 uid 1; string token 2; } message RegisterRequest { string username 1; string password 2; string phone 3; } message RegisterResponse { int64 uid 1; } message GetUserInfoRequest { int64 uid 1; } message GetUserInfoResponse { int64 uid 1; string username 2; string phone 3; } message FindUserRequest { string keyword 1; // 用户名或手机号搜索 } message FindUserResponse { repeated GetUserInfoResponse users 1; } service User { rpc Ping(PingRequest) returns (PingResponse); rpc Login(LoginRequest) returns (LoginResponse); rpc Register(RegisterRequest) returns (RegisterResponse); rpc GetUserInfo(GetUserInfoRequest) returns (GetUserInfoResponse); rpc FindUser(FindUserRequest) returns (FindUserResponse); }在项目根目录下执行代码生成命令使用go-zerolatest的goctl工具$ goctl rpc protoc apps/user/rpc/user.proto--go_outapps/user/rpc/ --go-grpc_outapps/user/rpc/--zrpc_outapps/user/rpc/该命令会生成internal/config、internal/server、internal/svc、internal/logic等脚手架代码并生成对应的user.go启动文件。随后进入apps/user/rpc目录执行go mod tidy即可完成依赖加载。为了提高后续开发效率建议将此类常用的生成命令统一记录在项目根目录的COMMANDS.md或某个备忘文件中。自动化构建脚本设计Dockerfile 参数化针对用户服务的 RPC 组件编写deploy/dockerfile/user-rpc/Dockerfile。为保证不同环境测试、生产可复用通过ARG与ENV定义服务名、服务类型等动态参数。# 基础镜像 FROM alpine:3.17 # 设置时区避免容器日志时间偏差 RUN apk add --no-cache tzdata \ cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ echo Asia/Shanghai /etc/timezone # 定义构建参数使用 ARG 仅在 image build 时生效 ARG SERVICE_NAMEuser ARG SERVICE_TYPErpc # 将参数转为环境变量容器运行时可用 ENV SERVICE_NAME${SERVICE_NAME} ENV SERVICE_TYPE${SERVICE_TYPE} # 创建工作目录等 RUN mkdir -p /app/${SERVICE_NAME}/${SERVICE_TYPE} WORKDIR /app/${SERVICE_NAME}/${SERVICE_TYPE} # 复制编译好的二进制文件和配置文件 COPY ./apps/${SERVICE_NAME}/${SERVICE_TYPE}/user /app/${SERVICE_NAME}/${SERVICE_TYPE}/ COPY ./apps/${SERVICE_NAME}/${SERVICE_TYPE}/etc /app/${SERVICE_NAME}/${SERVICE_TYPE}/etc # 设置启动命令 CMD [sh, -c, ./user -f etc/user.yaml]这样当服务名或类型变化时只需在构建时传入不同ARG无需修改 Dockerfile 内容。Makefile 编译与镜像推送在deploy/makefile/user-rpc.mk中定义编译、构建镜像、打标签、推送四个步骤并使用变量统一管理版本与仓库地址。# 变量定义 SERVICE_NAME user SERVICE_TYPE rpc VERSION latest DOCKER_REGISTRY registry.cn-hangzhou.aliyuncs.com/im-system IMAGE_NAME $(DOCKER_REGISTRY)/$(SERVICE_NAME)-$(SERVICE_TYPE):$(VERSION) # 编译输出二进制名 BINARY user # 测试环境使用的 Dockerfile 路径相对根目录 DOCKERFILE deploy/dockerfile/$(SERVICE_NAME)-$(SERVICE_TYPE)/Dockerfile .PHONY: all compile build push all: compile build push compile: echo Compiling $(SERVICE_NAME)-$(SERVICE_TYPE)... cd apps/$(SERVICE_NAME)/$(SERVICE_TYPE) go build -o $(BINARY) -ldflags-s -w . build: compile echo Building image $(IMAGE_NAME)... docker build \ --build-arg SERVICE_NAME$(SERVICE_NAME) \ --build-arg SERVICE_TYPE$(SERVICE_TYPE) \ -t $(IMAGE_NAME) \ -f $(DOCKERFILE) . push: build echo Pushing image $(IMAGE_NAME)... docker push $(IMAGE_NAME) # 一键执行测试环境完整流程 test: all echo Deploy test environment... bash deploy/scripts/deploy_user_rpc_test.sh项目根目录的Makefile作为总控入口只需通过include或直接调用子 Makefile.PHONY: user-rpc-test user-rpc-test: $(MAKE) -f deploy/makefile/user-rpc.mk test现在在根目录执行make user-rpc-test即可完成“编译 → 构建镜像 → 推送 → 部署测试”全流程大幅降低重复操作成本。部署 Shell 脚本在测试环境中不希望使用docker-compose up依赖本地已有镜像而是强制从私有仓库重新拉取最新镜像确保每次部署的都是最新构建版本。为此编写deploy/scripts/deploy_user_rpc_test.sh#!/bin/bashset-eCONTAINER_NAMEuser-rpcIMAGE_NAMEregistry.cn-hangzhou.aliyuncs.com/im-system/user-rpc:latestHOST_PORT10001CONTAINER_PORT10001# 停止并删除旧容器if[$(dockerps-aq-fname$CONTAINER_NAME)];thendockerstop$CONTAINER_NAME||truedockerrm$CONTAINER_NAME||truefi# 删除旧镜像避免缓存if[$(dockerimages-q$IMAGE_NAME)];thendockerrmi-f$IMAGE_NAME||truefi# 拉取最新镜像dockerpull$IMAGE_NAME# 启动容器注意挂载配置文件如有以及 etcd 地址dockerrun-d\--name$CONTAINER_NAME\--networkhost\-p$HOST_PORT:$CONTAINER_PORT\-eETCD_ENDPOINTS192.168.1.10:2379\$IMAGE_NAME后续其他服务API、社交等的部署脚本结构类似为了统一管理再编写一个总启动脚本start_all.sh遍历所有子脚本并执行#!/bin/bashSCRIPT_DIR$(cd$(dirname$0);pwd)services(deploy_user_rpc_test.sh# 其他服务脚本待补充)forsin${services[]};dochmodx$SCRIPT_DIR/$secho Execute$sbash$SCRIPT_DIR/$sdoneecho Running containers dockerpsecho Etcd registered keys # 简单验证通过 etcdctl 查看所有 key需安装 etcdctletcdctl--endpoints192.168.1.10:2379 get--prefixtrue --keys-only测试环境部署与验证基础中间件准备在部署用户服务之前需要先启动etcd、Redis、MySQL等基础组件。可使用docker-compose.yml编排并注意etcd镜像可使用官方或定制版本确保版本兼容性。数据持久化目录需具备适当权限否则etcd启动异常如权限拒绝。etcd的客户端访问地址必须使用宿主机 IP 或可跨容器访问的网络地址因为后续微服务注册发现依赖该地址。若所有服务同宿主机可使用内网 IP如192.168.1.10。示例docker-compose.yml片段version:3.7services:etcd:image:quay.io/coreos/etcd:v3.5.4container_name:etcdenvironment:-ETCD_LISTEN_CLIENT_URLShttp://0.0.0.0:2379-ETCD_ADVERTISE_CLIENT_URLShttp://192.168.1.10:2379volumes:-./data/etcd:/etcd-datacommand:etcd--data-dir/etcd-dataredis:image:redis:7-alpineports:-6379:6379mysql:image:mysql:8.0ports:-3306:3306environment:MYSQL_ROOT_PASSWORD:root123volumes:-./data/mysql:/var/lib/mysql启动后确认etcd可正常连接。部署与健康检查登录测试服务器如192.168.1.10拉取项目代码后执行$makeuser-rpc-test脚本将自动完成拉取镜像、启动容器。随后通过以下方式验证服务是否注册成功$ etcdctl--endpoints192.168.1.10:2379 get--prefixtrue --keys-only# 预期能看到类似 /user.rpc/ 的 key同时使用grpcurl或编写简单的 Go 客户端调用Ping方法确认 RPC 可达packagemainimport(contextfmtloggoogle.golang.org/grpcim-system/apps/user/rpc/user)funcmain(){conn,err:grpc.Dial(192.168.1.10:10001,grpc.WithInsecure())iferr!nil{log.Fatal(err)}deferconn.Close()client:user.NewUserClient(conn)resp,err:client.Ping(context.Background(),user.PingRequest{Msg:hello})iferr!nil{log.Fatal(err)}fmt.Println(Ping response:,resp.Msg)// 预期输出pong 或自定义信息}若输出预期信息则说明用户服务构建与部署流程完全正确。总结本节完成了以下事项确定了整个项目的标准目录结构为后续多服务开发奠定基础。编写用户服务的Proto文件使用goctl生成 gRPC 脚手架。设计参数化的Dockerfile使其可复用至其他服务与环境。编写Makefile实现编译、构建镜像、推送的一键自动化。编写部署 Shell 脚本配合Makefile实现从源代码到测试环境部署的全流程自动化。在测试服务器上实际部署并验证服务可用性确保etcd注册与 RPC 调用正常。通过这套标准化流水线后续只需复制上述模式并调整少量变量即可快速接入 IM 服务、社交服务的开发与部署极大提升团队协作效率。