I am trying to connect to postgres running in a docker container from another container using gorm but I am getting
panic: failed to connect to host=postgres user=postgres database=test: dial error (dial tcp 192.168.176.5:6543: connect: connection refused)
My docker-compose:
version: '3'
services:
patients-service:
build:
context: ./../patients-service
dockerfile: ./../patients-service/patients-service.dockerfile
restart: always
deploy:
mode: replicated
replicas: 1
postgres:
image: 'postgres:14.2'
ports:
- "6543:5432"
restart: always
deploy:
mode: replicated
replicas: 1
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: test
volumes:
- ./db-data/postgres/:/var/lib/postgresql/data/
Here is my go file:
package database
import (
"gorm.io/driver/postgres"
"gorm.io/gorm"
"log"
)
var DB *gorm.DB
var err error
func Open() error {
dsn := "host=postgres port=6543 user=postgres password=password dbname=test sslmode=disable timezone=UTC connect_timeout=5"
DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
return err
}
return nil
}
The weird thing is if I use port 5432 instead of 6543 in my code and change port mapping in docker-compose to - "5432:5432" it will connect just fine but I have postgres running locally and I don't want the two to interfere with each other since I am planning to connect to the one running in docker in DBeaver and localhost:5432 obviously connects to the local one.
Related
I have tried whatever solutions were provided but nothing works
I don't have any host port like this 127.0.0.11:53: to connect to the database, I am using docker-compose for the database.
I am not sure why I am getting this error
SQL database: "database/sql"
driver: "github.com/lib/pq"
docker-compose file
services:
db:
hostname: db
image: postgres:10.7
restart: always
ports:
- 54321:5432
environment:
POSTGRES_USER: dbuser
POSTGRES_PASSWORD: password
POSTGRES_DB: postgres
volumes:
- db-data1:/var/lib/postgresql/data
networks:
- my_network
I try to initialize a database with Go.
I use port 5433 at postgres:alpine because 5432 is already taken by another microservice app.
func Init() {
DB, err = gorm.Open(postgres.New(postgres.Config{
DSN: "host=url_db user=gorm password=gorm dbname=gorm port=5433 sslmode=disable TimeZone=Asia/Tokyo",
}), &gorm.Config{})
if err != nil {
panic(err)
}
autoMigration()
}
url_db:
build:
context: ./api/services/url/db
dockerfile: Dockerfile
container_name: "url_db"
environment:
POSTGRES_USER: gorm
POSTGRES_PASSWORD: gorm
POSTGRES_DB: gorm
POSTGRES_HOST: url_db
ports:
- 5433:5433
You can confirm that only 5432 is exposed here.
I tried to expose 5433 by creating a new Dockerfile like this.
FROM postgres:alpine
EXPOSE 5433
But I got this error.
failed to initialize database, got error failed to connect to `host=url_db user=gorm database=gorm`: dial error (dial tcp 172.19.0.3:5433: connect: connection refused)
This comment:
Simply exposing the port on the docker image won't do anything unless postgres is actually configured to listen on that port. – super 5 mins ago
that teaches me the title(How can I expose a new port(not 5432) at postgres:alpine image?) is not the point, so I updated the title.
How to make postgres listen on the container's new exposed port (not 5432)?
You have multiple options:
Option 1: Define own postgresql.conf
url_db:
build:
context: ./api/services/url/db
dockerfile: Dockerfile
container_name: "url_db"
command: postgres -c "config_file=/etc/postgresql/postgresql.conf"
environment:
POSTGRES_USER: gorm
POSTGRES_PASSWORD: gorm
POSTGRES_DB: gorm
POSTGRES_HOST: url_db
ports:
- 5433:5433
volumes:
- /path/to/config:/etc/postgresql/postgresql.conf
Postgres has an example config at /usr/share/postgresql/postgresql.conf.sample within the container.
To get the config run:
docker run -i --rm postgres cat /usr/share/postgresql/postgresql.conf.sample > my-postgres.conf
Option 1: Overwrite the RUN command
url_db:
build:
context: ./api/services/url/db
dockerfile: Dockerfile
container_name: "url_db"
command: postgres -c port=5433
environment:
POSTGRES_USER: gorm
POSTGRES_PASSWORD: gorm
POSTGRES_DB: gorm
POSTGRES_HOST: url_db
ports:
- 5433:5433
You can have multiple containers that are internally listening on the same port, so long as they're mapped to different ports on the host (if they're published at all). In your example, you can set
url_db:
image: postgres:latest
environment:
POSTGRES_USER: gorm
et: cetera
ports:
- 5433:5432
Connections from outside Docker reach the remapped port, on <host ip>:5433. Connections between Docker containers use the standard service port, on url_db:5432. These connections ignore (and don't require) ports:.
"Expose" in modern Docker means almost nothing; it is most valuable as documentation in an image showing what port(s) the service normally uses. You can in theory ask Compose to expose: additional ports without modifying the image, but there's no practical effect from doing so.
For Docker Compose assuming we want to change port to 5433
An alternative to doing this is to do the following in your docker-compose.yml file
you can mount the postgres data into a volume in your directory in this case ./db
postgres:
image: postgres:10.14-alpine
environment:
POSTGRES_DB: iam
ports:
- 5433:5433
volumes:
- ./db:/var/lib/postgresql/data
Find the postgresql.conf file, then search the port
change the port to
port = 5433 # (change requires restart)
I have the following error message from a Go app in Docker:
panic: failed to connect to `host=localhost user=postgres-dev database=dev`: dial error (dial tcp [::1]:5432: connect: cannot assign requested address)
which appear in the environment of the next Dockerfile and docker-compose.yml file:
FROM golang:latest
WORKDIR /WD
COPY go.mod go.sum ./
RUN go mod download
COPY . .
the docker-compose.yml file:
version: '3'
services:
db:
image: postgres:latest
environment:
POSTGRES_DB: dev
POSTGRES_USER: postgres-dev
POSTGRES_PASSWORD: [~secret~]
ports: 5432:5432
app:
build: .
command: ["./wait-for-it.sh", "db:5432", "--", "go", "run", "main.go"]
volumes:
- .:/WD
ports:
- "8000:8000"
depends_on:
- db
links:
- db
here the main.go file:
package main
import (
"context"
"fmt"
"log"
"net/http"
api "github.com/[placeholder]/[placeholder]/api"
db "github.com/[placeholder]/[placeholder]/db"
pgx "github.com/jackc/pgx/v4"
)
func main() {
fmt.Println("Init")
r := api.InitRoutes()
conn, err := pgx.Connect(context.Background(), "postgresql://postgres-dev:[~secret~]#localhost:5432/dev")
if err != nil {
panic(err) // the error appears from this line.
}
dbInstance := &db.DbService{Conn: conn}
dbInstance.Conn.Ping(context.Background())
dbInstance.Migrate("/db/db.sql")
http.ListenAndServe(":8000", r)
}
May this be helpful?
in console logs I found the next lines, which I think related to the problem:
db_1 | 2019-12-07 08:08:59.350 UTC [1] LOG: starting PostgreSQL 12.1 (Debian 12.1-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
db_1 | 2019-12-07 08:08:59.351 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432
# read the next line:
db_1 | 2019-12-07 08:08:59.351 UTC [1] LOG: listening on IPv6 address "::", port 5432
the address of the database is :: with port 5432 and while the program try to connect to ::1 with port 5432, could this be the cause of the problem?
Within a container attatched to a bridge network (the default) localhost (127.0.0.1) is the container itself. So your app container is trying to access the database at port 5432 on itself (not on the host or on the db container). The easiest fix is to change the connection string from:
postgresql://postgres-dev:[~secret~]#localhost:5432/dev
to
postgresql://postgres-dev:[~secret~]#db:5432/dev
Note: I think you have a typo in your docker-compose.yml - ports: 5432:5432 is setting an environmental variable rather than mapping a port (note that this is not actually needed for app to talk to db if they are both on the same bridged network as is the case by default).
Note2: You should not need to use links in this case (this is a legacy feature).
I trying connection to my postgresql database with Docker:
package main
import (
"fmt"
"log"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/postgres"
)
type Product struct {
gorm.Model
Code string
Price uint
}
var db *gorm.DB
func init() {
connection := fmt.Sprintf("host=db sslmode=disable user=dnz-dev password=dnz-dev")
db, err := gorm.Open("postgres", connection)
if err != nil {
log.Fatalln(err)
}
defer db.Close()
}
func main() {
// Migrate the schema
db.AutoMigrate(&Product{})
}
and docker-compose
version: "3.3"
services:
db:
build: ./dnz-db
container_name: dnz-database
ports:
- "6000:5432"
volumes:
- ./dnz-db/data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=dnz-dev
- POSTGRES_PASSWORD=dnz-dev
api:
build: ./dnz-api
container_name: dnz-api
volumes:
- ./dnz-api:/go/src/app
ports:
- "5000:3000"
depends_on:
- db
I run docker-compose up --build and I get this error:
Attaching to dnz-database, dnz-api dnz-api | 2017/11/05 10:23:46 dial
tcp 172.21.0.2:5432: getsockopt: connection refused dnz-api | exit
status 1 dnz-api exited with code 1
What I doing wrong?
You are unable to connect to your psql container because you haven't linked it. Take a look at Docker-Compose documentation on links.
Also, I'm assuming you aren't scheduling your container startup order. Psql container must start before golang's one. Take a look at Docker Compose documentation on startup order. You can use wait-for-it to achieve such objective ast stated in the docs. Just wget it and save it in your project.
I don't know the contents of your Dockerfile but I'll assume it's something like:
FROM golang:1.9
RUN mkdir -p /go/src/github.com/pavel/gorm-psql
WORKDIR /go/src/github.com/pavel/gorm-psql
ADD . /go/src/github.com/pavel/gorm-psql
RUN go get -v
So, your docker-compose.yml should be edited to first run wait-for-it.sh and link psql container to your app with something like:
version: '3.3'
services:
db:
image: postgres
environment:
POSTGRES_DB: dnz-dev
POSTGRES_USER: dnz-dev
POSTGRES_PASSWORD: dnz-dev
ports:
- 6000:5432
api:
build: .
command: ["./wait-for-it.sh", "db:6000", "--", "go", "run", "main.go"]
volumes:
- .:/go/src/github.com/pavel/gorm-psql
ports:
- "5000:3080"
depends_on:
- db
links:
- db
If your main has another name just change it. Edit your volumes to point whatever path you need. I've set a standard one with /go/src/github.com/pavel/gorm-psql. I'm assuming you created a db named dnz-dev, if the name is different just edit it.
$ go env:
. . .
GOPATH="/home/pavel/go"
GOROOT="/usr/lib/go"
. . .
Just run docker-compose up and it should work just fine. I'm relying on postgresql and golang latest images.
I've already seen this topic : https://stackoverflow.com/a/26599273/2323245
But I have the following problem :
postgres_1 | FATAL: role "docker" does not exist
app_1 | Error: Could not establish a connection with the database
This is my docker-compose.yml file
version: "2"
services:
app:
build:
context: .
dockerfile: Dockerfiles/app.dockerfile
links:
- postgres
depends_on:
- postgres
ports:
- "8080:8080"
environment:
PORT: 8080
networks:
- neo_dev
restart: always
postgres:
build:
context: .
dockerfile: Dockerfiles/postgres.dockerfile
networks:
- neo_dev
volumes:
- postgresql:/var/lib/postgresql
# This needs explicit mapping due to https://github.com/docker-library/postgres/blob/4e48e3228a30763913ece952c611e5e9b95c8759/Dockerfile.template#L52
- postgresql_data:/var/lib/postgresql/data
ports:
- "5430:5432" #in case you already have postgres running in your host machine
networks:
neo_dev:
driver: bridge
volumes:
postgresql:
postgresql_data:
My postgres.dockerfile is
FROM library/postgres
MAINTAINER Samir Bouaked "sbouaked#neocasesoftware.com"
ADD Dockerfiles/init.sql /docker-entrypoint-initdb.d/
And this is my init.sql file
CREATE USER docker with password 'docker';
CREATE DATABASE docker;
GRANT ALL PRIVILEGES ON DATABASE docker TO docker;
In my golang app, i'm trying to reach the database with
router.GET("/db", func(c *gin.Context) {
db, err := sql.Open("postgres", "host=postgres port=5432 user=docker dbname=docker password=docker sslmode=disable")
if err != nil {
log.Fatal("Error: The data source arguments are not valid - " + err.Error())
}
err = db.Ping()
if err != nil {
log.Println("Error: Could not establish a connection with the database")
c.String(http.StatusOK, "hotstName : %s\nDbStatus : %s", os.Getenv("HOSTNAME"), err)
} else {
c.String(http.StatusOK, "\nhotstName : %s\nDbStatus : connection ok !\n", os.Getenv("HOSTNAME"))
}
defer db.Close()
})
I tried different solutions like passing directly in the dockerfile env variables like that
ENV POSTGRES_USER docker
ENV POSTGRES_PASSWORD docker
ENV POSTGRES_DB docker
But have always the same result...
For more information you can check this repo https://github.com/neocase/docker-go-starter-kit
I don't understand the problem
It was a problem of docker volume.
I have to docker volume rm postgresvolume and do again a docker-compose up --build
It wasn't a problem of environment variables, but juste the fact that the init.sql was in cash and not run at the begining. It's due to some test I make a the start of the project
If you want to create the DB by passing ENV variables using docker-compose you can specify something like
postgres:
container_name: postgres
image: library/postgres
ports:
- "5432:5432"
environment:
- POSTGRES_DATABASE=docker
- POSTGRES_USER=docker
- POSTGRES_PASSWORD=docker
- POSTGRES_ADMIN_PASSWORD=docker
in your compose YML file.
This should create you a postgres container with an DB docker with user/pwd docker, no need for your own dockerfile anymore (so you can use any postgres image that supports this behavior)
After running compose (and if it doesn't work as you expect) you should have a look at the logs if your postgres container is working at all, or if there is an issue with your app.