Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run golang-migrate with docker-compose?

In golang-migrate's documentation, it is stated that you can run this command to run all the migrations in one folder.

docker run -v {{ migration dir }}:/migrations --network host migrate/migrate
    -path=/migrations/ -database postgres://localhost:5432/database up 2

How would you do this to fit the syntax of the new docker-compose, which discourages the use of --network?

And more importantly: How would you connect to a database in another container instead to one running in your localhost?

like image 316
Federico Avatar asked Apr 21 '19 04:04

Federico


3 Answers

Adding this to your docker-compose.yml will do the trick:

    db:
        image: postgres
        networks:
            new:
                aliases:
                    - database
        environment:
            POSTGRES_DB: mydbname
            POSTGRES_USER: mydbuser
            POSTGRES_PASSWORD: mydbpwd
        ports:
            - "5432"
    migrate:
        image: migrate/migrate
        networks:
            - new
        volumes:
            - .:/migrations
        command: ["-path", "/migrations", "-database",  "postgres://mydbuser:mydbpwd@database:5432/mydbname?sslmode=disable", "up", "3"]
        links: 
            - db
networks:
      new:

Instead of using the --network host option of docker run you set up a network called new. All the services inside that network gain access to each other through a defined alias (in the above example, you can access the db service through the database alias). Then, you can use that alias just like you would use localhost, that is, in place of an IP address. That explains this connection string:

"postgres://mydbuser:mydbpwd@database:5432/mydbname?sslmode=disable"
like image 59
Federico Avatar answered Sep 18 '22 19:09

Federico


As of Compose file formats version 2 you do not have to setup a network.

As stated in the docker networking documentation By default Compose sets up a single network for your app. Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by them at a hostname identical to the container name.

So in you case you could do something like:

version: '3.8'
services:
   #note this databaseservice name is what we will use instead
   #of localhost when using migrate as compose assigns
   #the service name as host
   #for example if we had another container in the same compose
   #that wnated to access this service port 2000 we would have written
   # databaseservicename:2000
  databaseservicename:
    image: postgres:13.3-alpine

    restart: always

    ports:
      - "5432"

    environment:
      POSTGRES_PASSWORD: password
      POSTGRES_USER: username
      POSTGRES_DB: database

    volumes:
      - pgdata:/var/lib/postgresql/data

    #if we had another container that wanted to access migrate container at let say
    #port 1000
    #and it's in the same compose file  we would have written migrate:1000
  migrate:
    image: migrate/migrate

    depends_on:
      - databaseservicename

    volumes:
      - path/to/you/migration/folder/in/local/computer:/database
    # here instead of localhost as the host we use databaseservicename as that is the name we gave to the postgres service
    command:
      [ "-path", "/database", "-database",  "postgres://databaseusername:databasepassword@databaseservicename:5432/database?sslmode=disable", "up" ]
volumes:
  pgdata:

like image 40
itachi sasuke Avatar answered Sep 20 '22 19:09

itachi sasuke


The answer provided by @Federico work for me at the beginning, nevertheless, I realised that I've been gotten a connect: connection refused the first time the docker-compose was run in brand new environment, but not the second one. This means that the migrate container runs before the Database is ready to process operations. Since, migrate/migrate from docker-hub runs the "migration" command whenever is ran, it's not possible to add a wait_for_it.sh script to wait for the db to be ready. So we have to add depends_on and a healthcheck tags to manage the order execution. So this is my docker file:

version: '3.3'
services:
  db:
    image: postgres
    networks:
      new:
        aliases:
          - database
    environment:
      POSTGRES_DB: mydbname
      POSTGRES_USER: mydbuser
      POSTGRES_PASSWORD: mydbpwd
    ports:
      - "5432"
    healthcheck:
      test: pg_isready -U mydbuser -d mydbname
      interval: 10s
      timeout: 3s
      retries: 5

  migrate:
    image: migrate/migrate
    networks:
      - new
    volumes:
      - .:/migrations
    command: ["-path", "/migrations", "-database",  "postgres://mydbuser:mydbpwd@database:5432/mydbname?sslmode=disable", "up", "3"]
    links: 
      - db
    depends_on:
      - db
networks:
      new:
like image 36
tul1 Avatar answered Sep 19 '22 19:09

tul1