帶你十天輕鬆搞定 Go 微服務系列(一)

kevwan 發表於 2022-01-18
微服務 Go

本文開始,我們會出一個系列文章跟大家詳細展示一個 go-zero 微服務示例,整個系列分十篇文章,目錄結構如下:

  1. 環境搭建(本文)
  2. 服務拆分
  3. 使用者服務
  4. 產品服務
  5. 訂單服務
  6. 支付服務
  7. RPC 服務 Auth 驗證
  8. 服務監控
  9. 鏈路追蹤
  10. 分散式事務

期望通過本系列帶你在本機利用 Docker 環境利用 go-zero 快速開發一個商城系統,讓你快速上手微服務。

完整示例程式碼:github.com/nivin-studio/go-zero-ma...

1 環境要求

  • Golang 1.15+
  • Etcd
  • Redis
  • Mysql
  • Prometheus
  • Grafana
  • Jaeger
  • DTM

2 Docker 本地開發環境搭建

為了方便開發除錯,我們使用 Docker 構建本地開發環境。WindowsmacOS 系統可下載 Docker Desktop 安裝使用,具體下載安裝方法可自行搜尋相關教程。

這裡我們使用 Docker Compose 來編排管理我們的容器,建立如下目錄:

gonivinck
├── dtm                   # DTM 分散式事務管理器
│   ├── config.yml        # DTM 配置檔案
│   └── Dockerfile
├── etcd                  # Etcd 服務註冊發現
│   └── Dockerfile
├── golang                # Golang 執行環境
│   └── Dockerfile
├── grafana               # Grafana 視覺化資料監控
│   └── Dockerfile
├── jaeger                # Jaeger 鏈路追蹤
│   └── Dockerfile
├── mysql                 # Mysql 服務
│   └── Dockerfile
├── mysql-manage          # Mysql 視覺化管理
│   └── Dockerfile
├── prometheus            # Prometheus 服務監控
│   ├── Dockerfile
│   └── prometheus.yml    # Prometheus 配置檔案
├── redis                 # Redis 服務
│   └── Dockerfile
├── redis-manage          # Redis 視覺化管理
│   └── Dockerfile
├── .env                  # env 配置
└── docker-compose.yml

2.1 編寫 Dockerfile

go-zero 的微服務中採用 grpc 進行服務間的通訊,而 grpc 的編寫就需要用到 protoc 和翻譯成 go 語言 rpc stub 程式碼的外掛 protoc-gen-go

為了提高開發效率,減少程式碼的出錯率,縮短業務開發的工作量,go-zero 還提供了 goctl 程式碼生成工具。

因此,我們需要將 protoc, protoc-gen-go, goctl, 給提前安裝到 golang 的容器中,以便後續使用。

所以 golang 容器的 Dockerfile 程式碼如下:

FROM golang:1.17

LABEL maintainer="Ving <[email protected]>"

ENV GOPROXY https://goproxy.cn,direct

# 安裝必要的軟體包和依賴包
USER root
RUN sed -i 's/deb.debian.org/mirrors.tuna.tsinghua.edu.cn/' /etc/apt/sources.list && \
    sed -i 's/security.debian.org/mirrors.tuna.tsinghua.edu.cn/' /etc/apt/sources.list && \
    sed -i 's/security-cdn.debian.org/mirrors.tuna.tsinghua.edu.cn/' /etc/apt/sources.list && \
    apt-get update && \
    apt-get upgrade -y && \
    apt-get install -y --no-install-recommends \
    curl \
    zip \
    unzip \
    git \
    vim 

# 安裝 goctl
USER root
RUN GOPROXY=https://goproxy.cn/,direct go install github.com/tal-tech/go-zero/tools/[email protected]

# 安裝 protoc
USER root
RUN curl -L -o /tmp/protoc.zip https://github.com/protocolbuffers/protobuf/releases/download/v3.19.1/protoc-3.19.1-linux-x86_64.zip && \
    unzip -d /tmp/protoc /tmp/protoc.zip && \
    mv /tmp/protoc/bin/protoc $GOPATH/bin

# 安裝 protoc-gen-go
USER root
RUN go get -u github.com/golang/protobuf/protoc-gen-[email protected].4.0

# $GOPATH/bin新增到環境變數中
ENV PATH $GOPATH/bin:$PATH

# 清理垃圾
USER root
RUN apt-get clean && \
    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
    rm /var/log/lastlog /var/log/faillog

# 設定工作目錄
WORKDIR /usr/src/code

EXPOSE 8000
EXPOSE 8001
EXPOSE 8002
EXPOSE 8003
EXPOSE 9000
EXPOSE 9001
EXPOSE 9002
EXPOSE 9003

其他服務容器 Dockerfile 無需特殊處理,只要基於現有的映象即可。

服務 基於的映象
DTM yedf/dtm
Etcd bitnami/etcd
Mysql mysql:5.7
Redis redis:5.0
Mysql Manage phpmyadmin/phpmyadmin
Redis Manage erikdubbelboer/phpredisadmin
Prometheus bitnami/prometheus
Grafana grafana/grafana
Jaeger jaegertracing/all-in-one:1.28

2.2 編寫 .env 配置檔案

# 設定時區
TZ=Asia/Shanghai
# 設定網路模式
NETWORKS_DRIVER=bridge


# PATHS ##########################################
# 宿主機上程式碼存放的目錄路徑
CODE_PATH_HOST=./code
# 宿主機上Mysql Reids資料存放的目錄路徑
DATA_PATH_HOST=./data


# MYSQL ##########################################
# Mysql 服務對映宿主機埠號,可在宿主機127.0.0.1:3306訪問
MYSQL_PORT=3306
MYSQL_USERNAME=admin
MYSQL_PASSWORD=123456
MYSQL_ROOT_PASSWORD=123456

# Mysql 視覺化管理使用者名稱稱,同 MYSQL_USERNAME
MYSQL_MANAGE_USERNAME=admin
# Mysql 視覺化管理使用者密碼,同 MYSQL_PASSWORD
MYSQL_MANAGE_PASSWORD=123456
# Mysql 視覺化管理ROOT使用者密碼,同 MYSQL_ROOT_PASSWORD
MYSQL_MANAGE_ROOT_PASSWORD=123456
# Mysql 服務地址
MYSQL_MANAGE_CONNECT_HOST=mysql
# Mysql 服務埠號
MYSQL_MANAGE_CONNECT_PORT=3306
# Mysql 視覺化管理對映宿主機埠號,可在宿主機127.0.0.1:1000訪問
MYSQL_MANAGE_PORT=1000


# REDIS ##########################################
# Redis 服務對映宿主機埠號,可在宿主機127.0.0.1:6379訪問
REDIS_PORT=6379

# Redis 視覺化管理使用者名稱稱
REDIS_MANAGE_USERNAME=admin
# Redis 視覺化管理使用者密碼
REDIS_MANAGE_PASSWORD=123456
# Redis 服務地址
REDIS_MANAGE_CONNECT_HOST=redis
# Redis 服務埠號
REDIS_MANAGE_CONNECT_PORT=6379
# Redis 視覺化管理對映宿主機埠號,可在宿主機127.0.0.1:2000訪問
REDIS_MANAGE_PORT=2000


# ETCD ###########################################
# Etcd 服務對映宿主機埠號,可在宿主機127.0.0.1:2379訪問
ETCD_PORT=2379


# PROMETHEUS #####################################
# Prometheus 服務對映宿主機埠號,可在宿主機127.0.0.1:3000訪問
PROMETHEUS_PORT=3000


# GRAFANA ########################################
# Grafana 服務對映宿主機埠號,可在宿主機127.0.0.1:4000訪問
GRAFANA_PORT=4000


# JAEGER #########################################
# Jaeger 服務對映宿主機埠號,可在宿主機127.0.0.1:5000訪問
JAEGER_PORT=5000


# DTM #########################################
# DTM HTTP 協議埠號
DTM_HTTP_PORT=36789
# DTM gRPC 協議埠號
DTM_GRPC_PORT=36790

2.3 編寫 docker-compose.yml 配置檔案

version: '3.5'
# 網路配置
networks:
  backend:
    driver: ${NETWORKS_DRIVER}

# 服務容器配置
services:
  golang:                                # 自定義容器名稱
    build:
      context: ./golang                  # 指定構建使用的 Dockerfile 檔案
    environment:                         # 設定環境變數
      - TZ=${TZ}
    volumes:                             # 設定掛載目錄
      - ${CODE_PATH_HOST}:/usr/src/code  # 引用 .env 配置中 CODE_PATH_HOST 變數,將宿主機上程式碼存放的目錄掛載到容器中 /usr/src/code 目錄
    ports:                               # 設定埠對映
      - "8000:8000"
      - "8001:8001"
      - "8002:8002"
      - "8003:8003"
      - "9000:9000"
      - "9001:9001"
      - "9002:9002"
      - "9003:9003"
    stdin_open: true                     # 開啟標準輸入,可以接受外部輸入
    tty: true
    networks:
      - backend
    restart: always                      # 指定容器退出後的重啟策略為始終重啟

  etcd:                                  # 自定義容器名稱
    build:
      context: ./etcd                    # 指定構建使用的 Dockerfile 檔案
    environment:
      - TZ=${TZ}
      - ALLOW_NONE_AUTHENTICATION=yes
    ports:                               # 設定埠對映
      - "${ETCD_PORT}:2379"
    networks:
      - backend
    restart: always

  mysql:
    build:
      context: ./mysql
    environment:
      - TZ=${TZ}
      - MYSQL_USER=${MYSQL_USERNAME}                  # 設定 Mysql 使用者名稱稱
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}              # 設定 Mysql 使用者密碼
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}    # 設定 Mysql root 使用者密碼
    volumes:
      - ${DATA_PATH_HOST}/mysql:/var/lib/mysql        # 引用 .env 配置中 DATA_PATH_HOST 變數,將宿主機上存放 Mysql 資料的目錄掛載到容器中 /var/lib/mysql 目錄
    ports:
      - "${MYSQL_PORT}:3306"                          # 設定容器3306埠對映指定宿主機埠
    networks:
      - backend
    restart: always

  redis:
    build:
      context: ./redis
    environment:
      - TZ=${TZ}
    volumes:
      - ${DATA_PATH_HOST}/redis:/data                 # 引用 .env 配置中 DATA_PATH_HOST 變數,將宿主機上存放 Redis 資料的目錄掛載到容器中 /data 目錄
    ports:
      - "${REDIS_PORT}:6379"                          # 設定容器6379埠對映指定宿主機埠
    networks:
      - backend
    restart: always

  mysql-manage:
    build:
      context: ./mysql-manage
    environment:
      - TZ=${TZ}
      - PMA_ARBITRARY=1
      - MYSQL_USER=${MYSQL_MANAGE_USERNAME}               # 設定連線的 Mysql 服務使用者名稱稱
      - MYSQL_PASSWORD=${MYSQL_MANAGE_PASSWORD}           # 設定連線的 Mysql 服務使用者密碼
      - MYSQL_ROOT_PASSWORD=${MYSQL_MANAGE_ROOT_PASSWORD} # 設定連線的 Mysql 服務 root 使用者密碼
      - PMA_HOST=${MYSQL_MANAGE_CONNECT_HOST}             # 設定連線的 Mysql 服務 host,可以是 Mysql 服務容器的名稱,也可以是 Mysql 服務容器的 ip 地址
      - PMA_PORT=${MYSQL_MANAGE_CONNECT_PORT}             # 設定連線的 Mysql 服務埠號
    ports:
      - "${MYSQL_MANAGE_PORT}:80"                         # 設定容器80埠對映指定宿主機埠,用於宿主機訪問視覺化web
    depends_on:                                           # 依賴容器
      - mysql                                             # 在 Mysql 服務容器啟動後啟動
    networks:
      - backend
    restart: always

  redis-manage:
    build:
      context: ./redis-manage
    environment:
      - TZ=${TZ}
      - ADMIN_USER=${REDIS_MANAGE_USERNAME}           # 設定 Redis 視覺化管理的使用者名稱稱
      - ADMIN_PASS=${REDIS_MANAGE_PASSWORD}           # 設定 Redis 視覺化管理的使用者密碼
      - REDIS_1_HOST=${REDIS_MANAGE_CONNECT_HOST}     # 設定連線的 Redis 服務 host,可以是 Redis 服務容器的名稱,也可以是 Redis 服務容器的 ip 地址
      - REDIS_1_PORT=${REDIS_MANAGE_CONNECT_PORT}     # 設定連線的 Redis 服務埠號
    ports:
      - "${REDIS_MANAGE_PORT}:80"                     # 設定容器80埠對映指定宿主機埠,用於宿主機訪問視覺化web
    depends_on:                                       # 依賴容器
      - redis                                         # 在 Redis 服務容器啟動後啟動
    networks:
      - backend
    restart: always

  prometheus:
    build:
      context: ./prometheus
    environment:
      - TZ=${TZ}
    volumes:
      - ./prometheus/prometheus.yml:/opt/bitnami/prometheus/conf/prometheus.yml  # 將 prometheus 配置檔案掛載到容器裡
    ports:
      - "${PROMETHEUS_PORT}:9090"                     # 設定容器9090埠對映指定宿主機埠,用於宿主機訪問視覺化web
    networks:
      - backend
    restart: always

  grafana:
    build:
      context: ./grafana
    environment:
      - TZ=${TZ}
    ports:
      - "${GRAFANA_PORT}:3000"                        # 設定容器3000埠對映指定宿主機埠,用於宿主機訪問視覺化web
    networks:
      - backend
    restart: always

  jaeger:
    build:
      context: ./jaeger
    environment:
      - TZ=${TZ}
    ports:
      - "${JAEGER_PORT}:16686"                        # 設定容器16686埠對映指定宿主機埠,用於宿主機訪問視覺化web
    networks:
      - backend
    restart: always

  dtm:
    build:
      context: ./dtm
    environment:
      - TZ=${TZ}
    entrypoint:
      - "/app/dtm/dtm"
      - "-c=/app/dtm/configs/config.yaml"
    volumes:
      - ./dtm/config.yml:/app/dtm/configs/config.yaml # 將 dtm 配置檔案掛載到容器裡
    ports:
      - "${DTM_HTTP_PORT}:36789"
      - "${DTM_GRPC_PORT}:36790"
    networks:
      - backend
    restart: always

2.4 構建與執行

  • 使用 docker-compose 命令來構建和啟動執行我們的服務容器,在根目錄執行如下命令:
$ docker-compose up -d
  • 容器構建中
    帶你十天輕鬆搞定 Go 微服務系列(一)

  • Windows 系統容器構建中出現如下圖所示,請選擇 Share it 這將允許 Windows 的檔案目錄掛載到容器目錄中。
    帶你十天輕鬆搞定 Go 微服務系列(一)

  • 容器已啟動執行
    帶你十天輕鬆搞定 Go 微服務系列(一)

    帶你十天輕鬆搞定 Go 微服務系列(一)

2.5 容器說明

容器名稱 暴露埠 host地址 說明
golang 8000:8000
8001:8001
8002:8002
8003:8003
9000:9000
9001:9001
9002:9002
9003:9003
golang 在生產環境中微服務一般都是叢集部署,可能一個微服務一臺伺服器,也可能一個微服務一個容器。為了方便開發除錯,我們將在 golang 容器中啟動所有微服務,併為它們分配監聽不同的埠號以示區分。
80:開頭的埠號我們將用於 api 服務
90:開頭的埠號我們將用於 rpc 服務
dtm 36789:36789
36790:36790
dtm dtmhttp 協議和 grpc 協議服務埠號,供客戶端互動使用。
此專案中我們只在 Docker 內部容器之間訪問使用,所以也可以不暴露埠號給宿主機
etcd 2379:2379 etcd Etcd http api 服務埠號,供客戶端互動使用。
此專案中我們只在 Docker 內部容器之間訪問使用,所以也可以不暴露埠號給宿主機
mysql 3306:3306 mysql Mysql 服務預設埠號,宿主機可通過 127.0.0.1:3306 進行資料庫的連線
redis 6379:6379 redis Redis 服務預設埠號,宿主機可通過 127.0.0.1:6379 進行資料庫的連線
mysql-manage 1000:80 mysql-manage phpMyAdmin web 服務埠號,可以在宿主機 127.0.0.1:1000 訪問
redis-manage 2000:80 redis-manage phpRedisAdmin web 服務埠號,可以在宿主機 127.0.0.1:2000 訪問
prometheus 3000:9090 prometheus Prometheus web 服務埠號,可以在宿主機 127.0.0.1:3000 訪問
grafana 4000:3000 grafana Grafana web 服務埠號,可以在宿主機 127.0.0.1:4000 訪問
jaeger 5000:16686 jaeger Jaeger web 服務埠號,可以在宿主機 127.0.0.1:5000 訪問

2.6 訪問驗證

  • Mysql 訪問驗證
    帶你十天輕鬆搞定 Go 微服務系列(一)

  • Redis 訪問驗證
    帶你十天輕鬆搞定 Go 微服務系列(一)

  • Prometheus 訪問驗證
    帶你十天輕鬆搞定 Go 微服務系列(一)

  • Grafana 訪問驗證
    帶你十天輕鬆搞定 Go 微服務系列(一)

  • Jaeger 訪問驗證
    帶你十天輕鬆搞定 Go 微服務系列(一)

專案地址

github.com/zeromicro/go-zero

歡迎使用 go-zerostar 支援我們!

微信交流群

關注『微服務實踐』公眾號並點選 交流群 獲取社群群二維碼。

本作品採用《CC 協議》,轉載必須註明作者和本文連結