Skip to content
This repository has been archived by the owner on Nov 14, 2020. It is now read-only.

can't run postgresql with docker #28

Closed
sugizo opened this issue Feb 9, 2018 · 5 comments
Closed

can't run postgresql with docker #28

sugizo opened this issue Feb 9, 2018 · 5 comments

Comments

@sugizo
Copy link

sugizo commented Feb 9, 2018

Terraform Version

./terraform -v
Terraform v0.11.3
+ provider.docker v0.1.1
+ provider.postgresql v0.1.1

Terraform Configuration Files

variable "name" {
  default = {
    postgres = "postgres"
  }
}
provider "docker" {
  host = "unix:///var/run/docker.sock"
}
provider "postgresql" {
  alias           = "pg1"
#  host            = "localhost" # * provider.postgresql.pg1: Error initializing PostgreSQL client: error detecting capabilities:error PostgreSQL version: dial tcp 127.0.0.1:5432: getsockopt: connection refused
  host            = "\${docker_container.postgres.name}" # * provider.postgresql.pg1: Error initializing PostgreSQL client: error detecting capabilities:error PostgreSQL version: dial tcp: lookup postgres on 127.0.0.11:53: no such host
  port            = 5432
  username        = "postgres"
  password        = ""
  sslmode         = "disable"
  connect_timeout = 15
}
resource "docker_image" "postgres" {
  name = "postgres:latest"
}
resource "docker_container" "postgres" {
  image = "\${docker_image.postgres.latest}"
  name = "\${var.name["postgres"] }"
  restart = "always"
  hostname = "\${var.name["postgres"] }"
}
resource "postgresql_database" "mutualfunds" {
  provider = "postgresql.pg1"
  name     = "testnewdb"
}

Expected Behavior

postgresql can run alongside with docker and create new database name testnewdb

Actual Behavior

docker with postgresql image is not downloaded or running and receive an error during
./terraform plan
using configuration
host = "localhost"
error

  • provider.postgresql.pg1: Error initializing PostgreSQL client: error detecting capabilities:error PostgreSQL version: dial tcp 127.0.0.1:5432: getsockopt: connection refused

using configuration
host = "${docker_container.postgres.name}"
error

  • provider.postgresql.pg1: Error initializing PostgreSQL client: error detecting capabilities:error PostgreSQL version: dial tcp: lookup postgres on 127.0.0.11:53: no such host

Steps to Reproduce

cat << EOF > main.tf
variable "name" {
  default = {
    postgres = "postgres"
  }
}
provider "docker" {
  host = "unix:///var/run/docker.sock"
}
provider "postgresql" {
  alias           = "pg1"
#  host            = "localhost" # * provider.postgresql.pg1: Error initializing PostgreSQL client: error detecting capabilities:error PostgreSQL version: dial tcp 127.0.0.1:5432: getsockopt: connection refused
  host            = "\${docker_container.postgres.name}" # * provider.postgresql.pg1: Error initializing PostgreSQL client: error detecting capabilities:error PostgreSQL version: dial tcp: lookup postgres on 127.0.0.11:53: no such host
  port            = 5432
  username        = "postgres"
  password        = ""
  sslmode         = "disable"
  connect_timeout = 15
}
resource "docker_image" "postgres" {
  name = "postgres:latest"
}
resource "docker_container" "postgres" {
  image = "\${docker_image.postgres.latest}"
  name = "\${var.name["postgres"] }"
  restart = "always"
  hostname = "\${var.name["postgres"] }"
}
resource "postgresql_database" "mutualfunds" {
  provider = "postgresql.pg1"
  name     = "mutualfunds"
}
EOF
cat main.tf
./terraform init
./terraform plan
@wolf31o2
Copy link

wolf31o2 commented May 8, 2019

This is essentially the same issue as #2 which boils down to an upstream issue.

@mavogel
Copy link
Contributor

mavogel commented May 8, 2019

@wolf31o2 there are several reasons why this main.tf does not work. Let me give you an explanation first then a solution to make it work. Yes it boils down to #2 but I don't know if we will go back to the logic of v0.1.0 because all providers fail fast. Let's see until then the solution mentioned below works.

explanation

Mixing providers in one tf file causes problems by design if they depend on each other. In your case the postgres provider depends on the docker provider, meaning the database can only be created if the docker container is spun up. But on init of the postgres provider there need to already a connection to the postgres host be possible. That's why you first have to spin up the container and then create the database.

Things I noticed:

  • provider.docker is at v1.1.1. please update :)
  • You did not expose any port of the docker container, so your postgres provider would have never accomplished to connect ;)
  • The connection the goes to localhost and not to the hostname postgres because this one is only available within the docker DNS, meaning if you'd like to access the postgres container from another container within the same docker network.

solution

terraform cannot solve that kind of dependencies between modules, like https://github.com/milosgajdos83 already proposes. See hashicorp/terraform#1178 for a more in-depth explanation. Hence, you need to split the 2 providers in 2 modules and call them after each other in the right order. Maybe it will be fixed in 0.12 as Radek mentions #2 (comment)

 tree                                                                                                                                         ✔  1757 
.
├── mod_docker
│   └── main.tf
├── mod_postgres
│   └── main.tf
├── root.tf

With the following contents:

  • root.tf:
module "docker" {
  source = "mod_docker"
  name   = "postgres"
}

module "postgres" {
  source = "mod_postgres"
  name   = "postgres"
}
  • mod_docker/main.tf
variable "name" {
  default = "postgres"
}

provider "docker" {
  host = "unix:///var/run/docker.sock"
}

resource "docker_image" "postgres" {
  name = "postgres:latest"
}

resource "docker_container" "postgres" {
  image    = "${docker_image.postgres.latest}"
  name     = "${var.name}"
  restart  = "always"
  hostname = "${var.name}"
  ports = {
    internal = "5432"
    external = "5432"
  }
}
  • mod_postgres/main.tf
variable "name" {
  default = "postgres"
}

provider "postgresql" {
  alias           = "pg1"
  # host            = "${var.name}" // will not work because 'postgres' is only resolved within the docker dns
  host            = "localhost"
  port            = 5432
  username        = "postgres"
  password        = ""
  sslmode         = "disable"
  connect_timeout = 15
}

resource "postgresql_database" "mutualfunds" {
  provider = "postgresql.pg1"
  name     = "mutualfunds"
}

Then call the modules in the right order from the root folder

terraform init
terraform apply -target=module.docker
terraform apply -target=module.postgres

Eh voilà, there is your setup:

psql -h localhost -p5432 -U postgres

postgres=# \l
                                  List of databases
    Name     |  Owner   | Encoding |  Collate   |   Ctype    |   Access privileges   
-------------+----------+----------+------------+------------+-----------------------
 mutualfunds | postgres | UTF8     | C          | C          | 
 postgres    | postgres | UTF8     | en_US.utf8 | en_US.utf8 | 
 template0   | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
             |          |          |            |            | postgres=CTc/postgres
 template1   | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
             |          |          |            |            | postgres=CTc/postgres
(4 rows)

HTH
Best Manu

@wolf31o2
Copy link

wolf31o2 commented May 8, 2019

I'm not the OP. 🙂

@mavogel
Copy link
Contributor

mavogel commented May 8, 2019

I'm not the OP

True :) My bad => //ping @sugizo

@mavogel
Copy link
Contributor

mavogel commented Oct 12, 2019

As mentioned: duplicate of #2 and closing due to inactivity.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants