Search code examples
dockerfigdocker-compose

Difference between docker-compose and manual commands


What I'm trying to do

I want to run a yesod web application in one docker container, linked to a postgres database in another docker container.

What I've tried

I have the following file hierarchy:

/
    api/
        Dockerfile
    database/
        Dockerfile
    docker-compose.yml

The docker-compose.yml looks like this:

database:
    build: database
api:
    build: api
    command: .cabal/bin/yesod devel # dev setting
    environment:
        - HOST=0.0.0.0
        - PGHOST=database
        - PGPORT=5432
        - PGUSER=postgres
        - PGPASS
        - PGDATABASE=postgres
    links:
        - database
    volumes:
        - api:/home/haskell/
    ports:
        - "3000:3000"

Running sudo docker-compose up fails either to start the api container at all or, just as often, with the following error:

api_1      | Yesod devel server. Press ENTER to quit
api_1      | yesod: <stdin>: hGetLine: end of file
personal_api_1 exited with code 1

If, however, I run sudo docker-compose database up & then start up the api container without using compose but instead using

sudo docker run -p 3000:3000 -itv /home/me/projects/personal/api/:/home/haskell --link personal_database_1:database personal_api /bin/bash

I can export the environment variables being set up in the docker-compose.yml file then manually run yesod devel and visit my site successfully on localhost.

Finally, I obtain a third different behaviour if I run sudo docker-compose run api on its own. This seems to start successfully but I can't access the page in my browser. By running sudo docker-compose run api /bin/bash I've been able to explore this container and I can confirm the environment variables being set in docker-compose.yml are all set correctly.

Desired behaviour

I would like to get the result I achieve from running the database in the background then manually setting the environment in the api container's shell simply by running sudo docker-compose up.

Question

Clearly the three different approaches I'm trying do slightly different things. But from my understanding of docker and docker-compose I would expect them to be essentially equivalent. Please could someone explain how and why they differ and, if possible, how I might achieve my desired result?


Solution

  • The error-message suggests the API container is expecting input from the command-line, which expects a TTY to be present in your container.

    In your "manual" start, you tell docker to create a TTY in the container via the -t flag (-itv is shorthand for -i -t -v), so the API container runs successfully.

    To achieve the same in docker-compose, you'll have to add a tty key to the API service in your docker-compose.yml and set it to true;

    database:
        build: database
    api:
        build: api
        tty: true # <--- enable TTY for this service
        command: .cabal/bin/yesod devel # dev setting