Getting exit code out of docker-compose up - docker

I have an issue getting an exit code out of docker-compose up.
I have the simplest container that runs a script that always exits with 1:
#!/usr/bin/env sh
exit 1
My Dockerfile:
FROM mhart/alpine-node:6
RUN mkdir /app
WORKDIR /app
And my docker-compose.yml:
version: '2'
services:
test_container:
container_name: test_container
build: .
volumes:
- ${PWD}/run.sh:/app/run.sh
entrypoint: ["/app/run.sh"]
When I run it with:
docker-compose -f docker-compose.yml up --force-recreate test_container
I can see in logs:
Recreating test_container ...
Recreating test_container ... done
Attaching to test_container
test_container exited with code 1
But when I echo $?, I get 0.
Docker version 17.09.0-ce, build afdb6d4. Running on OSX 10.12.6.
Am I doing something wrong? Is that a known issue (I couldn't find anything out there)?

An option --exit-code-from SERVICE can be used with docker-compose up :)
From the documentation:
docker compose up
Options:
--exit-code-from SERVICE Return the exit code of the selected service container.
Implies --abort-on-container-exit.
--abort-on-container-exit Stops all containers if any container was stopped.
Incompatible with -d.
-d Detached mode: Run containers in the background,
print new container names.
Incompatible with --abort-on-container-exit.

Related

Start a container in interactive shell in docker compose [duplicate]

Is there any way to start an interactive shell in a container using Docker Compose only? I've tried something like this, in my docker-compose.yml:
myapp:
image: alpine:latest
entrypoint: /bin/sh
When I start this container using docker-compose up it's exited immediately. Are there any flags I can add to the entrypoint command, or as an additional option to myapp, to start an interactive shell?
I know there are native docker command options to achieve this, just curious if it's possible using only Docker Compose, too.
You need to include the following lines in your docker-compose.yml:
version: "3"
services:
app:
image: app:1.2.3
stdin_open: true # docker run -i
tty: true # docker run -t
The first corresponds to -i in docker run and the second to -t.
The canonical way to get an interactive shell with docker-compose is to use:
docker-compose run --rm myapp
(With the service name myapp taken from your example. More general: it must be an existing service name in your docker-compose file, myapp is not just a command of your choice. Example: bash instead of myapp would not work here.)
You can set stdin_open: true, tty: true, however that won't actually give you a proper shell with up, because logs are being streamed from all the containers.
You can also use
docker exec -ti <container name> /bin/bash
to get a shell on a running container.
The official getting started example (https://docs.docker.com/compose/gettingstarted/) uses the following docker-compose.yml:
version: "3.9"
services:
web:
build: .
ports:
- "8000:5000"
redis:
image: "redis:alpine"
After you start this with docker-compose up, you can shell into either your redis container or your web container with:
docker-compose exec redis sh
docker-compose exec web sh
docker-compose run myapp sh should do the deal.
There is some confusion with up/run, but docker-compose run docs have great explanation: https://docs.docker.com/compose/reference/run
If anyone from the future also wanders up here:
docker-compose exec service_name sh
or
docker-compose exec service_name bash
or you can run single lines like
docker-compose exec service_name php -v
That is after you already have your containers up and running.
The service_name is defined in your docker-compose.yml file
Using docker-compose, I found the easiest way to do this is to do a docker ps -a (after starting my containers with docker-compose up) and get the ID of the container I want to have an interactive shell in (let's call it xyz123).
Then it's a simple matter to execute
docker exec -ti xyz123 /bin/bash
and voila, an interactive shell.
This question is very interesting for me because I have problems, when I run container after execution finishes immediately exit and I fixed with -it:
docker run -it -p 3000:3000 -v /app/node_modules -v $(pwd):/app <your_container_id>
And when I must automate it with docker compose:
version: '3'
services:
frontend:
stdin_open: true
tty: true
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "3000:3000"
volumes:
- /app/node_modules
- .:/app
This makes the trick: stdin_open: true, tty: true
This is a project generated with create-react-app
Dockerfile.dev it looks this that:
FROM node:alpine
WORKDIR '/app'
COPY package.json .
RUN npm install
COPY . .
CMD ["npm", "run", "start"]
Hope this example will help other to run a frontend(react in example) into docker container.
I prefer
docker-compose exec my_container_name bash
If the yml is called docker-compose.yml it can be launched with a simple $ docker-compose up. The corresponding attachment of a terminal can be simply (consider that the yml has specified a service called myservice):
$ docker-compose exec myservice sh
However, if you are using a different yml file name, such as docker-compose-mycompose.yml, it should be launched using $ docker-compose -f docker-compose-mycompose.yml up. To attach an interactive terminal you have to specify the yml file too, just like:
$ docker-compose -f docker-compose-mycompose.yml exec myservice sh
A addition to this old question, as I only had the case last time. The difference between sh and bash. So it can happen that for some bash doesn't work and only sh does.
So you can:
docker-compose exec CONTAINER_NAME sh
and in most cases: docker-compose exec CONTAINER_NAME bash
use.
If you have time. The difference between sh and bash is well explained here:
https://www.baeldung.com/linux/sh-vs-bash
You can do docker-compose exec SERVICE_NAME sh on the command line. The SERVICE_NAME is defined in your docker-compose.yml. For example,
services:
zookeeper:
image: wurstmeister/zookeeper
ports:
- "2181:2181"
The SERVICE_NAME would be "zookeeper".
According to documentation -> https://docs.docker.com/compose/reference/run/
You can use this docker-compose run --rm app bash
[app] is the name of your service in docker-compose.yml

docker-compose command not running on `up`, but on entering container command runs

I have a docker-compose.yml file as such:
version: '3'
services:
my_service:
...
command: /bin/bash my_script.sh
...
and a script that launches some rq workers in the background:
# my_script.sh
rq worker worker_1 &
rq worker worker_2 &
When I run docker-compose up --build -d, the my_service image is built and creates a container, but my_script.sh does not run.
If instead I change the docker-compose.yml file to:
...
command: tail -f /dev/null
...
run docker-compose up --build -d again, enter the container with:
# host
$ docker exec -it my_service_1 /bin/bash
and run the same command from within the container
# my_service_1 container
$ /bin/bash my_script.sh
then my_script.sh runs successfully. I have checked file paths are fine, and there is no ENTRYPOINT associated with the Dockerfile for my_service. I have also checked the container logs with docker logs my_service_1, but this does not return any output.
Has anyone encountered anything similar before? Why am I unable to run command: /bin/bash my_script.sh directly from the up command?
Kindly let me know if there is anything I should clarify in more detail, or avenues for debugging this. Thank you.

How can I run two instances of a command in a container?

I am trying to write a docker-compose file that references a Dockerfile in the same directory. The purpose of this docker-compose file is to run the command htop when I build my Dockerfile image it runs htop perfectly fine and I can pass arguments to an entry point. Whenever I go to try to run docker-compose up it starts the htop instances but then exits immediately. Is there anyway I can open two terminals or two containers and each container be running an htop instance?
Dockerfile:
FROM alpine:latest
MAINTAINER anon
RUN apk --no-cache add \
htop
ENTRYPOINT ["htop"]
docker-compose.yml
version: '3'
services:
htop_one:
build: .
environment:
TERM: "linux"
htop_two:
build: .
environment:
TERM: "linux"
Any help would be greatly appreciated!
The immediate problem is a terminal incompatibility. You run this from a terminal that is unknown to the software in the docker image.
The second problem, of the containers exiting immediately, could be fixed by using a proper init like tini:
Dockerfile:
FROM alpine:latest
MAINTAINER anon
RUN apk --no-cache add \
htop\
tini
ENTRYPOINT ["/sbin/tini", "--"]
docker-compose.yaml:
version: '3'
services:
htop_one:
build: .
environment:
TERM: "linux"
command: ["top"]
htop_two:
build: .
environment:
TERM: "linux"
command: ["top"]
To run the two services in parallel, as they each need a controlling terminal, you would run, from two different terminals:
docker-compose up htop_one
and
docker-compose up htop_two
respectively.
Note this is creating two containers from the same image. Each docker-compose service is, of course, run in a separate container.
If you'd like to run commands in the same container, you could start a service like
docker-compose up myservice
and run commands in it:
docker exec -it <container_name> htop
from different terminals, as many times as you'd like.
Not also that you can determine container_name via docker container ls and you can also set the container name from the docker-compose file,
On the issue of your htop command exiting, thus causing your docker container to exit.
This is normal behavior for docker containers. The htop is most likely exiting because it can't figure out the terminal when in a docker image, as #petre mentioned. When you run your docker image, be sure to use the -i option for an interactive session.
docker run -it MYIMAGE htop
To change the docker auto-exit behavior, do something like this in your Dockerfile:
CMD exec /bin/sh -c "trap : TERM INT; (while true; do MYCOMMAND; sleep 1000; done) & wait"
This runs your MYCOMMAND command over and over again, but allows the container to be stopped when you want. You can run a docker exec -it MYCONTAINER sh when you want to do other things in that same container.
Also, if you happen to be running docker in Windows, then prefix a winpty to the docker command like: winpty docker ... so it can get the terminal correct.

Docker container's status started by docker-compose is always exited

Here is my docker-compose.yml:
version: "3"
services:
test123:
build: .
container_name: "test123"
My Dockerfile:
FROM alpine:3.9
CMD ["/bin/sh"]
When I run:
docker run -it alpine:3.9
It works fine. But when I run from docker-compose:
docker-compose up -d
The container's status is always: Exited (0)
Any idea?
Your container starts and exits immediately because /bin/sh stops. This is how containers work. When their PID 1 stops, they exit. So, in order to prevent sh from exiting, you have to use:
tty: true
stdin_open: true
These options are the equivalent -it that you already use in your docker run ... command.
from the docs:
--tty , -t Allocate a pseudo-TTY
--interactive , -i Keep STDIN open even if not attached
Updated docker-compose.yml file:
version: "3"
services:
test123:
build: .
container_name: "test123"
tty: true
stdin_open: true
No wonder your container exits (with status 0, which means success).
The container must keep running in order to stay alive, so the command that is run must never end. Here would be a workaround:
Dockerfile:
FROM alpine:3.9
CMD ["tail", "-f", "/dev/null"]
That way the container will always remain busy, until you stop it.

Launching docker command from docker-compose v.3 file

I'm learning about Docker and I'm at first steps.
I've to 'refresh' postgres image from compose file to initialize db scripts as YOSIFKIT here do through shell (https://github.com/docker-library/postgres/issues/193).
here is my Docker file:
FROM postgres:9.6.7
COPY docker-postgresql-9.6.7/prova.sql /docker-entrypoint-initdb.d/
and here is my compose file:
version: '3'
services:
postgresql_rdbms:
restart: always
image: postgres-prova
build:
context: ../
dockerfile: docker-postgresql-9.6.7/Dockerfile
command: bash -c "docker run -it --rm postgres-prova ls -ln /docker-entrypoint-initdb.d && docker run -it --rm postgres-prova && postgres"
environment:
PG_PASSWORD: postgres
ports:
- "5432:5432"
volumes:
- /srv/docker/postgresql:/var/lib/postgresql
HOW can I insert a command in a compose-file to do "docker run -it --rm imageToReload" ???
Because I've seen that "command:" in compose file works inside the container, but I want operate ON the container, on a upper level (=manage the container from the compose file, after the container creation)
Thank you very much
From what I understand you want docker-compose to delete/remove the container after every run so that the build is run each time and a fresh prova.sql file can be copied into the image each time the service is brought up. The --force-recreate flag is probably what you need.
The command directive within the yaml file provides the command that is run inside the container.

Resources