如何在Docker中设置环境变量实现Web容器与MySQL容器通信
解决Docker容器中Web应用与MySQL的连接及启动依赖问题
一、用Docker自定义网络替代容器IP(规避IP变化问题)
容器IP会随重启/重建变化,直接用容器名作为DNS地址更可靠——Docker自定义网络会自动完成域名解析,无需手动跟踪IP。
创建自定义Docker网络:
docker network create app-network启动MySQL容器时加入该网络,设置必要环境变量并指定容器名:
docker run -d \ --name mysqldb \ --network app-network \ -e MYSQL_ROOT_PASSWORD=你的根密码 \ -e MYSQL_DATABASE=你的数据库名 \ mysql:latest这里容器名
mysqldb就是Web应用要访问的地址,Docker会自动解析到对应容器IP。
二、修改Go应用代码:读取环境变量并验证数据库连接
你的Go应用需要读取环境变量获取MySQL地址,并且在启动前验证数据库是否就绪,避免Web应用启动时MySQL还未完成初始化。
1. 代码修改示例
import ( "database/sql" "fmt" "log" "net/http" "os" "time" "flag" "net" _ "github.com/go-sql-driver/mysql" ) var linkList map[string]string var db *sql.DB func main() { // 读取环境变量,未设置时使用默认值 mysqlHost := os.Getenv("mysqldb") if mysqlHost == "" { mysqlHost = "mysqldb" // fallback到MySQL容器名 } mysqlPort := os.Getenv("MYSQL_PORT") if mysqlPort == "" { mysqlPort = "3306" } mysqlUser := os.Getenv("MYSQL_USER") if mysqlUser == "" { mysqlUser = "root" } mysqlPassword := os.Getenv("MYSQL_PASSWORD") if mysqlPassword == "" { log.Fatal("MYSQL_PASSWORD环境变量未设置") } mysqlDB := os.Getenv("MYSQL_DATABASE") if mysqlDB == "" { log.Fatal("MYSQL_DATABASE环境变量未设置") } // 构建MySQL连接DSN dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=true", mysqlUser, mysqlPassword, mysqlHost, mysqlPort, mysqlDB) // 循环重试连接,等待MySQL就绪 var err error for i := 0; i < 10; i++ { db, err = sql.Open("mysql", dsn) if err == nil { err = db.Ping() // 实际验证连接 if err == nil { break } } log.Printf("等待MySQL就绪,第%d次重试...", i+1) time.Sleep(2 * time.Second) } if err != nil { log.Fatalf("无法连接到MySQL: %v", err) } defer db.Close() log.Println("成功连接到MySQL数据库") // 原有HTTP服务逻辑 linkList = map[string]string{} http.HandleFunc("/link", addLink) http.HandleFunc("/hpe/", getLink) http.HandleFunc("/", Home) ip := flag.String("i", "0.0.0.0", "") port := flag.String("p", "8080", "") flag.Parse() fmt.Printf("Listening on %s \n", net.JoinHostPort(*ip, *port)) log.Fatal(http.ListenAndServe(net.JoinHostPort(*ip, *port), nil)) }
2. 前置准备
确保你的Go项目已引入MySQL驱动:
go get github.com/go-sql-driver/mysql
三、更新Dockerfile与容器启动命令
1. 优化Dockerfile
添加健康检查,验证Web服务是否正常运行:
FROM golang:1.19-bullseye AS build WORKDIR /app COPY ./ ./ RUN go mod download # 下载项目依赖 RUN go build -o main ./ FROM debian:bullseye COPY --from=build /app/main /usr/local/bin/main # 安装curl用于健康检查 RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* # 健康检查配置 HEALTHCHECK --interval=30s --timeout=3s \ CMD curl -f http://localhost:8080/ || exit 1 CMD ["/usr/local/bin/main"]
2. 构建并启动Web应用容器
启动时加入同一Docker网络,传递必要环境变量:
# 构建镜像 docker build -t tiny . # 启动容器 docker run -d \ --name web-app \ --network app-network \ -p 9008:8080 \ -e mysqldb=mysqldb \ -e MYSQL_PASSWORD=你的根密码 \ -e MYSQL_DATABASE=你的数据库名 \ tiny
四、更高效的方案:用Docker Compose管理容器
Docker Compose可以一键启动所有服务,自动处理网络、环境变量和启动顺序,避免手动敲命令的繁琐。
创建docker-compose.yml:
version: '3.8' services: mysqldb: image: mysql:latest environment: MYSQL_ROOT_PASSWORD: 你的根密码 MYSQL_DATABASE: 你的数据库名 networks: - app-network healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] timeout: 20s retries: 10 web-app: build: . ports: - "9008:8080" environment: mysqldb: mysqldb MYSQL_PASSWORD: 你的根密码 MYSQL_DATABASE: 你的数据库名 networks: - app-network depends_on: mysqldb: condition: service_healthy # 等待MySQL健康检查通过后再启动 healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/"] timeout: 3s retries: 3 networks: app-network: driver: bridge
启动/停止服务:
# 启动所有服务(后台运行) docker-compose up -d # 停止并删除容器 docker-compose down
五、优化Makefile(可选)
添加Docker Compose相关命令,统一管理操作:
build: go build -o bin/main main.go run: go run main.go # 构建Docker镜像 docker-build: docker build -t tiny . # 用Docker Compose启动容器 runcontainer: docker-compose up -d # 停止容器 stopcontainer: docker-compose down compile: echo "Compiling for every OS and Platform" GOOS=linux GOARCH=arm go build -o bin/main-linux-arm main.go GOOS=linux GOARCH=arm64 go build -o bin/main-linux-arm64 main.go GOOS=freebsd GOARCH=386 go build -o bin/main-freebsd-386 main.go
内容的提问来源于stack exchange,提问作者user19880359
相关产品推荐
相关产品推荐

