如何使用 go with docker 等待 postgres 数据库?

How to wait postgres db using go with docker?

我通过 docker-compose 使用 postgres 部署了一个 go with gorm 应用程序。

我通过另一个容器服务进行了数据库创建和数据迁移。这里只列出了应用和数据库容器问题。

docker-compose.yml

  app:
    build: ./app
    command: ["/bin/wait-for-it.sh", "db:5432", "--", "/bin/main"]
    volumes:
      - ./app/:/app/
    ports:
      - 8080:8080
    environment:
      - DB_USER=postgres
      - DB_NAME=mydb
      - DB_PASS=password
    depends_on:
      - db
    links:
      - db

  db:
    image: postgres:13-alpine
    environment:
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=mydb

Docker 文件

FROM golang:1.16.3-alpine3.13 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o main

FROM alpine:3.13
RUN apk update && apk --no-cache add bash
COPY --from=builder /app /bin/.
RUN ["chmod", "+x", "/bin/wait-for-it.sh"]

db/db.go

package db

import (
    "fmt"
    "os"

    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

var (
    db *gorm.DB
)

func Init() {
    conn := fmt.Sprintf("host=db port=5432 user=%s password=%s dbname=%s sslmode=disable", os.Getenv("DB_USER"), os.Getenv("DB_PASS"), os.Getenv("DB_NAME"))

    _, err := gorm.Open(postgres.Open(conn), &gorm.Config{})
    if err != nil {
        panic(err)
    }
}

func GetDB() *gorm.DB {
    return db
}

models/post.go

package models

type Post struct {
    ID    int    `json:"id" gorm:"primary_key"`
    Title string `json:"title"`
    Body  string `json:"body"`
}

main.go

   1   │ package main
   2   │
   3   │ import (
   4   │     "app/db"
   5   │     "app/models"
   6   │     "fmt"
   7   │ )
   8   │
   9   │ func main() {
  10   │     db.Init()
  11   │
  12   │     db := db.GetDB()
  13   │
  14   │     var posts []models.Post
  15   │     db.Find(&posts)
  16   │     fmt.Println(posts)
  17   │ }

当开始构建docker-compose 时,它​​首先尝试连接数据库,但似乎数据库还无法访问。即使添加 wait-for-it 也不起作用。

app_1   | wait-for-it.sh: waiting 15 seconds for db:5432
db_1    |
db_1    | PostgreSQL Database directory appears to contain a database; Skipping initialization
db_1    |
app_1   | wait-for-it.sh: db:5432 is available after 0 seconds
db_1    | 2021-06-02 03:53:03.731 UTC [1] LOG:  starting PostgreSQL 13.2 on x86_64-pc-linux-musl, compiled by gcc (Alpine 10.2.1_pre1) 10.2.1 20201203, 64-bit
db_1    | 2021-06-02 03:53:03.731 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
app_1   | panic: runtime error: invalid memory address or nil pointer dereference
app_1   | [signal SIGSEGV: segmentation violation code=0x1 addr=0x28 pc=0x59c446]
app_1   |
app_1   | goroutine 1 [running]:
app_1   | gorm.io/gorm.(*DB).getInstance(0x0, 0xc000026038)
app_1   |   /go/pkg/mod/gorm.io/gorm@v1.21.10/gorm.go:355 +0x26
app_1   | gorm.io/gorm.(*DB).Find(0x0, 0x868220, 0xc00000c018, 0x0, 0x0, 0x0, 0xc000094058)
app_1   |   /go/pkg/mod/gorm.io/gorm@v1.21.10/finisher_api.go:159 +0x2f
app_1   | main.main()
app_1   |   /app/main.go:15 +0x7f
db_1    | 2021-06-02 03:53:03.731 UTC [1] LOG:  listening on IPv6 address "::", port 5432
db_1    | 2021-06-02 03:53:03.734 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
db_1    | 2021-06-02 03:53:03.741 UTC [22] LOG:  database system was shut down at 2021-06-02 03:52:34 UTC
db_1    | 2021-06-02 03:53:03.747 UTC [1] LOG:  database system is ready to accept connections
myapp_app_1 exited with code 2

如何正确设置?

/app/main.go:15有什么不对的吗?它应该可以正常工作并获取数据。

您需要在命令中添加等待时间:

command: ["/bin/wait-for-it.sh", "db:5432", "-t", "600000000", "--", "/bin/main"]

这里是最长等待时间,应用程序 /bin/main 将在数据库启动和 运行ning 后立即执行。

当你 运行 没有 -t 时默认为 15 秒

更多信息Here