微服务架构中的Docker Compose与Golang实践
微服务架构中的Docker Compose与Golang实践 关于微服务及其管理的主题。 由于缺乏好的资料,我在此寻求帮助。
我正在基于微服务架构构建一个应用程序,并且为了开发,我决定使用 docker compose 功能。我们目前有使用 Java Spring 编写的服务,但未来也会使用其他语言。
每个服务都位于不同的代码仓库中。 每个服务都有自己的 Dockerfile 和 docker-compose.yaml 文件。
当我开发某个特定服务时,我希望在 docker 环境 中运行其他服务,并通过 Kafka 或 gRPC 与它们通信。
我遇到了许多与环境变量以及网络/DNS 服务发现相关的问题。
- 我应该在
.env文件中包含什么内容? - 与特定服务相关的环境文件应该放在哪里(放在其代码仓库中,还是放在我启动它的代码仓库中?)
- 如何在 docker compose 中管理 DNS?当然,我可以提供服务的名称,它会被解析,但是如何为运行在 docker swarm 中的服务提供我正在开发的服务的 IP 和端口?
问题可能表述得不够清晰,我只是想听听关于设计/文件夹/项目结构的建议,以实现管理此类应用程序的便利性和灵活性。
假设我们在 产品服务仓库 中,我们有一个 docker-compose.yaml 文件来运行其他服务,例如 购物车服务:
cart-service:
build:
context: ../cart-service
dockerfile: Dockerfile
container_name: cart-service
ports:
- "${CART_SERVICE_PORT:?error}:8080"
env_file:
-
path: ../cart-service/docker/app-env.txt
required: false
depends_on:
cart-service-db:
restart: true
condition: service_healthy
kafka:
condition: service_healthy
#
这是一个好的方法吗?需要改变什么?
更多关于微服务架构中的Docker Compose与Golang实践的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于微服务架构中的Docker Compose与Golang实践的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
针对你的微服务开发环境配置,以下是一些具体的实践方案:
1. 环境变量管理
.env 文件内容示例
# 全局环境变量
COMPOSE_PROJECT_NAME=product-service-dev
NETWORK_NAME=ms-network
# 服务端口
PRODUCT_SERVICE_PORT=8080
CART_SERVICE_PORT=8081
USER_SERVICE_PORT=8082
# Kafka配置
KAFKA_BOOTSTRAP_SERVERS=kafka:9092
KAFKA_GROUP_ID=product-service-group
# 数据库配置
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
环境文件位置建议
# 项目结构示例
product-service/
├── .env # 开发环境变量
├── docker-compose.yml
├── config/
│ ├── dev.env # 开发专用配置
│ └── test.env # 测试环境配置
├── internal/
│ └── config/
│ └── config.go # Go配置结构
└── cmd/
└── main.go
2. Go服务配置示例
// internal/config/config.go
package config
import (
"os"
"strconv"
)
type Config struct {
ServiceName string
Port int
Kafka KafkaConfig
Database DatabaseConfig
}
type KafkaConfig struct {
BootstrapServers string
GroupID string
Topics []string
}
type DatabaseConfig struct {
Host string
Port int
Username string
Password string
Database string
}
func LoadConfig() *Config {
port, _ := strconv.Atoi(getEnv("PORT", "8080"))
return &Config{
ServiceName: getEnv("SERVICE_NAME", "product-service"),
Port: port,
Kafka: KafkaConfig{
BootstrapServers: getEnv("KAFKA_BOOTSTRAP_SERVERS", "localhost:9092"),
GroupID: getEnv("KAFKA_GROUP_ID", "default-group"),
Topics: []string{"products", "orders"},
},
Database: DatabaseConfig{
Host: getEnv("DB_HOST", "localhost"),
Port: 5432,
Username: getEnv("DB_USER", "postgres"),
Password: getEnv("DB_PASSWORD", ""),
Database: getEnv("DB_NAME", "products"),
},
}
}
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}
3. Docker Compose网络配置
# docker-compose.yml
version: '3.8'
networks:
ms-network:
driver: bridge
name: ${NETWORK_NAME:-ms-network}
services:
product-service:
build:
context: .
dockerfile: Dockerfile
container_name: ${COMPOSE_PROJECT_NAME:-product-service}
ports:
- "${PRODUCT_SERVICE_PORT:-8080}:8080"
environment:
- SERVICE_NAME=product-service
- PORT=8080
- KAFKA_BOOTSTRAP_SERVERS=kafka:9092
- CART_SERVICE_URL=http://cart-service:8081
- USER_SERVICE_URL=http://user-service:8082
env_file:
- .env
- ./config/dev.env
networks:
- ms-network
depends_on:
kafka:
condition: service_healthy
postgres:
condition: service_healthy
cart-service:
image: cart-service:latest # 或使用build指向本地
container_name: cart-service
ports:
- "${CART_SERVICE_PORT:-8081}:8081"
environment:
- SERVICE_NAME=cart-service
- PORT=8081
- KAFKA_BOOTSTRAP_SERVERS=kafka:9092
networks:
- ms-network
kafka:
image: confluentinc/cp-kafka:latest
container_name: kafka
ports:
- "9092:9092"
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
networks:
- ms-network
healthcheck:
test: ["CMD", "kafka-topics", "--list", "--bootstrap-server", "localhost:9092"]
interval: 30s
timeout: 10s
retries: 3
4. Go服务发现示例
// internal/client/service_discovery.go
package client
import (
"context"
"fmt"
"net/http"
"time"
)
type ServiceClient struct {
baseURL string
httpClient *http.Client
}
func NewServiceClient(serviceName string, port string) *ServiceClient {
// Docker Compose中直接使用服务名作为主机名
baseURL := fmt.Sprintf("http://%s:%s", serviceName, port)
return &ServiceClient{
baseURL: baseURL,
httpClient: &http.Client{
Timeout: 30 * time.Second,
},
}
}
func (c *ServiceClient) GetCart(ctx context.Context, cartID string) ([]byte, error) {
url := fmt.Sprintf("%s/api/carts/%s", c.baseURL, cartID)
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return nil, err
}
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
// 处理响应...
return nil, nil
}
5. 多仓库开发配置
# 开发环境docker-compose.override.yml
version: '3.8'
services:
product-service:
build:
context: .
dockerfile: Dockerfile.dev # 开发专用Dockerfile
volumes:
- .:/app
- /app/vendor
command: air # 使用air实现热重载
cart-service:
build:
context: ../cart-service # 指向其他仓库
dockerfile: Dockerfile.dev
volumes:
- ../cart-service:/app
environment:
- DEBUG=true
6. 健康检查与依赖管理
// cmd/healthcheck/main.go
package main
import (
"context"
"fmt"
"net/http"
"os"
"time"
)
func main() {
services := map[string]string{
"cart-service": "http://cart-service:8081/health",
"user-service": "http://user-service:8082/health",
"kafka": "http://kafka:9092",
}
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
for name, url := range services {
if err := checkService(ctx, name, url); err != nil {
fmt.Printf("Service %s not ready: %v\n", name, err)
os.Exit(1)
}
}
fmt.Println("All services are ready")
}
func checkService(ctx context.Context, name, url string) error {
client := &http.Client{Timeout: 5 * time.Second}
for {
select {
case <-ctx.Done():
return fmt.Errorf("timeout waiting for %s", name)
default:
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return err
}
resp, err := client.Do(req)
if err == nil && resp.StatusCode == http.StatusOK {
resp.Body.Close()
return nil
}
time.Sleep(2 * time.Second)
}
}
}
这个配置方案确保了在Docker Compose环境中,各服务可以通过服务名直接通信,环境变量分层管理,并且支持多仓库开发。

