协作Dockerfile和Docker-Compose,搭建Go项目环境

427 阅读4分钟

当然,下面是优化后的项目文件夹结构,包含了配置文件夹、Go 项目文件夹、Redis 数据持久化以及独立的环境配置文件。

文件夹结构

myapp/
├── Dockerfile
├── docker-compose.yml
├── .env
├── redis/
│   └── redis.conf
├── mysql/
│   └── init.sql
└── src/
    └── main.go

1. Dockerfile

用于构建 Go 应用的 Docker 镜像。

FROM golang:1.19

WORKDIR /app

LABEL maintainer="cwx@email.com"

#这一步可以改成从仓库克隆代码
COPY ./src/ /app 

#  || true 的作用是确保即使 go mod init myapp 失败,Docker 构建过程也不会因为这一行而停止。
RUN go mod init myapp.com || true

RUN go mod tidy

RUN go build -o main .

EXPOSE 8080

CMD ["./main"]

注意📢:

  • docker build: 执行 Dockerfile 中的 FROM, WORKDIR, LABEL, COPY, RUN, 和 EXPOSE 等命令来构建镜像。
  • docker run: 执行 Dockerfile 中的 CMDENTRYPOINT 等命令来启动容器。

所以,如果是在主机改动了 Go 项目代码,就必须得重新 build 新的镜像,然后再执行。

所以,这里推荐使用通过 goland 进行远程连接到容器内,使用容器内的代码来改动调试,一并配置好远程 GO 调试和语法检测,那么本地就可以无任何编程环境的情况下,运行调试起来!

由于改的是容器内的代码,所以在容器内直接重新编译更新就好了!

2. docker-compose.yml

定义 Go 应用、MySQL 数据库和 Redis 缓存服务。

# docker-compose.yml

version: '3.8'

services:
  app:
    build: .
    container_name: go-app
    ports:
      - "8080:8080"
    env_file:
      - .env
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - mynetwork

  db:
    image: mysql:8.0
    container_name: mysql-db
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_USER: user
      MYSQL_PASSWORD: password
      MYSQL_DATABASE: mydatabase
    volumes:
      - dbdata:/var/lib/mysql
      - ./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql
    networks:
      - mynetwork
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-p${MYSQL_ROOT_PASSWORD}"]
      interval: 30s
      timeout: 10s
      retries: 3

  redis:
    image: redis:latest
    container_name: redis-cache
    volumes:
      - redisdata:/data
      - ./redis/redis.conf:/usr/local/etc/redis/redis.conf
    networks:
      - mynetwork
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  dbdata:
  redisdata:

networks:
  mynetwork:
    driver: bridge

3. Go 应用代码

src/main.go 包含连接 MySQL 和 Redis 的示例代码。

package main

import (
	"database/sql"
	"fmt"
	"log"
	"net/http"
	"os"

	redis "github.com/go-redis/redis/v8"
	_ "github.com/go-sql-driver/mysql"
	"golang.org/x/net/context"
)

var (
	db  *sql.DB
	rdb *redis.Client
	ctx = context.Background()
)

func main() {
	// 读取环境变量
	mysqlURL := os.Getenv("MYSQL_URL")
	redisURL := os.Getenv("REDIS_URL")

	// 初始化 MySQL 连接
	var err error
	db, err = sql.Open("mysql", mysqlURL)
	if err != nil {
		log.Fatalf("Error opening MySQL connection: %v", err)
	}
	defer db.Close()

	// 初始化 Redis 连接
	// 使用redis.ParseURL函数解析Redis URI
	opts, err := redis.ParseURL(redisURL)
	if err != nil {
		log.Fatalf("Error parsing Redis URL: %v", err)
	}

	// 创建Redis客户端
	rdb = redis.NewClient(opts)

	// 使用Redis客户端执行操作,例如Ping
	pong, err := rdb.Ping(ctx).Result()
	if err != nil {
		log.Fatalf("Error pinging Redis: %v", err)
	}
	log.Println("Redis ping response:", pong)

	// 设置 HTTP 处理器
	http.HandleFunc("/", handleRequest)

	// 启动 HTTP 服务器
	err = http.ListenAndServe(":8080", nil)
	if err != nil {
		log.Fatalf("Error starting HTTP server: %v", err)
	}
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
	// 从 Redis 读取数据
	redisValue, err := rdb.Get(ctx, "key").Result()
	if err != nil && err != redis.Nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// 从 MySQL 查询数据
	var now string
	err = db.QueryRow("SELECT NOW()").Scan(&now)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// 响应客户端
	fmt.Fprintf(w, "Current time from MySQL: %s\n", now)
	fmt.Fprintf(w, "Value from Redis: %s\n", redisValue)
}

4. 环境配置文件

.env 文件包含环境变量配置。

MYSQL_URL="user:password@tcp(db:3306)/mydatabase?charset=utf8mb4"
REDIS_URL=redis://123456@redis:6379

5. Redis 配置文件

redis/redis.conf 配置 Redis(可选)。

# redis.conf
# redis.conf

# Bind to all interfaces
bind 0.0.0.0

# Listening port
port 6379

# Require clients to authenticate with this password
requirepass 123456

# Directory for storing data
dir /data

# Dump file name
dbfilename dump.rdb

# Append only file configuration
appendonly yes

# Memory management
maxmemory 400mb
maxmemory-policy allkeys-lru

# 使用默认配置

6. MySQL 初始化脚本

mysql/init.sql 用于初始化 MySQL 数据库(可选)。

-- init.sql

CREATE TABLE IF NOT EXISTS test (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL
);

INSERT INTO test (name) VALUES ('initial data');

使用步骤

  1. 创建文件
    • 在项目目录中创建上述所有文件。
  1. 构建和启动服务
    • 在项目目录中运行 docker-compose 命令构建镜像并启动服务:
docker-compose up --build
  1. 访问 Go 应用
    • 打开浏览器,访问 http://localhost:8080,查看 Go 应用的输出。

优点

  • 清晰的组织结构:将不同类型的文件放在不同的文件夹中,方便管理和维护。
  • 持久化数据:Redis 和 MySQL 的数据都被持久化到 Docker 卷中,不会因容器重启而丢失。
  • 环境变量管理:使用 .env 文件管理环境变量,使得配置更为灵活和安全。

这个示例展示了如何使用 Docker 和 docker-compose 来创建一个包含 Go 应用、MySQL 和 Redis 的综合环境,并提供了改进后的文件结构和配置示例。

---

总结

通过以上步骤就可以搭建一个完成的 Go 项目开发环境了,可以把上述项目文件上传到公司的 Git 仓库,组内小伙伴克隆这个项目,然后 docker-compose up 就可以启动一个项目啦。

使用 Goland 或者 vsCode 进行远程连接,接入到 docker go 容器里面进行拉取代码修改(注意要改容器内的代码),再配置好远程 Go 编译和语法检测,那么本地就可以无任何开发环境的情况下,进行 Go 代码编写以及调试啦!

由于改的是容器内的代码,所以在容器内直接重新编译更新就好了!