Nightspell
Nightspell

Reputation: 31

Can't setup and execute golang migration using docker compose

I can't get my Go app running. My goal is to run some migrations and then run the api server using a docker compose yaml file, so I'm using a db container for postgresql and a "back" container for the go service and the migration command so I can get everything up more simply. Here are the files:

Docker-compose.yaml:

services:
  db:
    image: postgres:9
    ports: 
      - 4321:5432
    environment:
      - POSTGRES_DB=vet-app
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=admin
  back:
    build: ./vet-app-back
    ports:
      - 8080:4000
    depends_on:
      db:
        condition: service_started
  

Dockerfile on /vet-app-back

FROM golang:1.19
WORKDIR /app
ENV VET_DB_DSN=postgres://postgres:admin@db:5432/vet-app?sslmode=disable
COPY go.mod go.sum ./
RUN go mod download
COPY . ./
RUN curl -L https://github.com/golang-migrate/migrate/releases/download/v4.14.1/migrate.linux-amd64.tar.gz | tar xvz &&\ 
  mv migrate.linux-amd64 $GOPATH/bin/migrate 
RUN migrate -path=./migrations -database=$VET_DB_DSN up
CMD ["go run ./cmd/api"]

Results im getting on console after docker compose up:

 => ERROR [7/7] RUN migrate -path=./migrations -database=postgres://postgres:admin@db:5432/vet-app?sslmode=disable up                                     10.4s
------
 > [7/7] RUN migrate -path=./migrations -database=postgres://postgres:admin@db:5432/vet-app?sslmode=disable up:
#0 10.35 error: dial tcp: lookup db on 192.168.65.7:53: read udp 172.17.0.2:56570->192.168.65.7:53: i/o timeout
------
failed to solve: executor failed running [/bin/sh -c migrate -path=./migrations -database=$VET_DB_DSN up]: exit code: 1

It seems like it can't resolve "db". But I'm using "depends_on" correctly, in order to run Postgres first, so now I'm really stuck.

Upvotes: 1

Views: 755

Answers (1)

David Maze
David Maze

Reputation: 159810

A Dockerfile can never connect to another container. You can never run migrations as part of your image build process, whether in Go or another language.

One good approach to this is to write a wrapper shell script that runs the migrations and does other first-time setup, and then runs a command it's given as arguments. You can then make this script be your image's ENTRYPOINT. For example:

#!/bin/sh
# docker-entrypoint

# run migrations as required
migrate -path=./migrations -database="$VET_DB_DSN" up

# run the command passed as arguments
exec "$@"

In your Dockerfile, make this script be your ENTRYPOINT; it must use JSON-array syntax. There is also a syntax error in your CMD, which you're not seeing yet: the three words in the command need to be three separate JSON-array elements.

ENTRYPOINT ["./docker-entrypoint"]
CMD ["go", "run", "./cmd/api"]

(I'd probably also move the ENV setting from the Dockerfile out to the Compose file, since the specific host name and credentials are specific to this Compose deployment; if you ran the image with a remote hosted database you'd need different settings. Also consider using a multi-stage build to be able to run the program without needing the Go toolchain. In this case you'd need to make sure the migrate tool and ./migrate source directory are present in the final image.)

Upvotes: 0

Related Questions