英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论