如何使用Go和Docker等待PostgreSQL数据库?

huangapple go评论91阅读模式
英文:

How to wait postgres db using go with docker?

问题

我使用docker-compose部署了一个使用gorm和postgres的Go应用程序。

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

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

Dockerfile

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有什么问题吗?它应该正常工作并获取数据。

英文:

I deployed a go with gorm app using postgres by docker-compose.

I did db creation and data migration by an another container service. Here only listed the app and db container issues.

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

Dockerfile

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   │ }

When start to build docker-compose, it tried to connect db first, but it seems that db didn't become reachable yet. Even added wait-for-it doesn't work.

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

How to set it correctly?

Does /app/main.go:15 anything incorrect? It should work and get data normally.

答案1

得分: 1

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

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

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

当你不使用-t参数运行时,默认等待时间为15秒。

更多信息请参考这里

英文:

you need to add the Time for waiting in your command:

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

the time is here the maximun time for waiting, the app /bin/main will be excuted as soon the DB is up and running.

when you run without -t the default is 15 seconds

more info Here

huangapple
  • 本文由 发表于 2021年6月2日 13:44:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/67799504.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定