Docker container exited with code 0 after docker-compose up -d - docker

I know the question has been asked in various situations, but I'm still stucked despite everything I read on the Internet.
I want to have a script executed after the container "mywebsite" is built and I used ENTRYPOINT for that and I know that in normal use, after the ENTRYPOINT command is executed, the container "mywebsite" exit. I tried several tricks to avoid exit, unfortunately without success.
In my DOCKERFILE I have this :
FROM php:7.1.17-apache
[...]
WORKDIR /var/www
COPY docker-entrypoint.sh /var/www/docker-entrypoint.sh
ENTRYPOINT ["sh", "/var/www/docker-entrypoint.sh"]
Then in my docker-entrypoint.sh I have this :
#!/bin/bash
set -e
cd www
chown -R www-data:www-data sites modules themes
exec "$#"
And here is my docker-compose.yml :
version: '3.3'
services:
mywebsite:
build: .
extra_hosts:
- "mywebsite.local:127.0.0.1"
hostname: mywebsite
domainname: local
ports:
- 8088:80
volumes:
- ./www:/var/www/www
- ./vendor:/var/www/vendor
- ./scripts:/var/www/scripts
links:
- database:database
restart: always
tty: true
database:
image: mysql:5.5.49
container_name: mysql-container
ports:
- 3307:3306
volumes:
- ./www/dumps/mywebsite.sql:/docker-entrypoint-initdb.d/dump.sql
restart: always
command: --max_allowed_packet=32505856
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: mywebsite
When build, all steps are fine, and everything is set properly, but the container "mywebsite" keep exiting. (The "database" service is running fine)
I haded tty: true and exec "$#" but none of that works.

You can end with command like tail -f /dev/null
I often use this directly in my docker-compose.yml with command: tail -f /dev/null. And it is easy to see how I keep the container running.

I had the same problem when creating my own image from a postgis-image. The problem was that I added an entrypoint. When I removed the entrypoint, build the image again, docker-compose does start my container and postgis was accepting connections.
dockerfile
FROM postgis/postgis:12-master
COPY organisation.sql
#ENTRYPOINT ["docker-entrypoint.sh"] #This was the problem
In docker-compose I did not need command's or tty.
version: "3.7"
services:
mydb:
image: mydb:latest
container_name: mytest
ports:
- "5432:5432"
environment:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: secret

Related

When scaling, run some docker container startup commands only once

I have the following docker-compose.yml.
version: "3.1"
services:
db:
container_name: ${MYSQL_CONTAINER}
image: mysql:5.7.30
volumes:
- ${VOLUMES_DIR}/mysql_data:/var/lib/mysql
- ./slow_log.cnf:/etc/mysql/my.cnf
- ${VOLUMES_DIR}/mysql_logs:/var/log/mysql
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD}
- MYSQL_USER=${MYSQL_USER}
ports:
- ${MYSQL_PORT}:3306
entrypoint: ""
command: bash -c "chown -R mysql:mysql /var/log/mysql && exec /entrypoint.sh mysqld --default-authentication-plugin=mysql_native_password"
restart: on-failure
backend:
container_name: ${BACKEND_CONTAINER}
image: ${BACKEND_IMAGE}
depends_on:
- db
ports:
- ${BACKEND_PORT}
command: >
bash -c "command A
&& command B
&& ... "
restart: unless-stopped
I am scaling backend service so my startup command is sudo docker-compose -p ${COMPOSE_PROJECT_NAME} up -d --scale backend=10.
The problem I am facing is command A, command B in service backend was running for all 10 containers startup(means they were being run 10 times).
But I want command A to run only once for all the backend service-related containers but Command B should run for all containers.
Any suggestions in accomplishing this?
I'm not entirely sure that there would be an out-of-the-box solution for your requirement.
However, I can suggest you a workaround like this. You can duplicate your backend service in docker-compose and run one backend service with both Command A and Command B, while the other backend has only Command B.
Then when you want to scale, you scale the backend which has only Command B.
version: "3.1"
services:
db:
container_name: ${MYSQL_CONTAINER}
image: mysql:5.7.30
volumes:
- ${VOLUMES_DIR}/mysql_data:/var/lib/mysql
- ./slow_log.cnf:/etc/mysql/my.cnf
- ${VOLUMES_DIR}/mysql_logs:/var/log/mysql
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD}
- MYSQL_USER=${MYSQL_USER}
ports:
- ${MYSQL_PORT}:3306
entrypoint: ""
command: bash -c "chown -R mysql:mysql /var/log/mysql && exec /entrypoint.sh mysqld --default-authentication-plugin=mysql_native_password"
restart: on-failure
backend_default:
container_name: ${BACKEND_CONTAINER}
image: ${BACKEND_IMAGE}
depends_on:
- db
ports:
- ${BACKEND_PORT}
command: >
bash -c "command A
&& command B
&& ... "
restart: unless-stopped
backend:
container_name: ${BACKEND_CONTAINER}
image: ${BACKEND_IMAGE}
depends_on:
- db
ports:
- ${BACKEND_PORT}
command: >
bash -c "command B
&& ... "
restart: unless-stopped
Now you can use the scale option like below:
sudo docker-compose -p ${COMPOSE_PROJECT_NAME} up -d --scale backend=9
Now if there happens to be a scenario, where you need only 1 backend to be run, you can use profiles in docker-compose to only run backend when there is a specific profile is given with docker-compose command. That means only default_backend will run if that profile is not given and hence the scale is 1.
Hope this helps you. Cheers 🍻 !!!
If BACKEND_IMAGE is being built by you, you should do RUN command A in your Dockerfile. The RUN line will be executed only once during build time — so you will also need to make sure that this meshes with your needs — while the ENTRYPOINT and CMD lines will only be run upon execution of the container. The command in the docker-compose file overrides the CMD line.

docker-compose: wait for a container to be run before running another container

In this example, I want to run prisma container, only when mysql container is exposed on mysql:3036. I tried to use wait-for-it.sh but how can I use this inside prisma container?
https://github.com/vishnubob/wait-for-it
version: '3.7'
services:
prisma:
image: prismagraphql/prisma:1.34.8
restart: always
depends_on:
- mysql
ports:
- '4466:4466'
environment:
PRISMA_CONFIG: |
port: 4466
databases:
default:
connector: mysql
host: mysql
user: root
password: prisma
rawAccess: true
port: 3306
migrations: true
mysql:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: prisma
volumes:
- ./persistence/test/mysql:/var/lib/mysql
redis:
image: redis:5-alpine
command: redis-server
ports:
- 6379:6379
volumes:
- ./persistence/test/redis:/data
hostname: redis
restart: always
# env_file: ${ENV_FILE}
If you want to use the wait-for-it.sh to wait for the service mysql:3036 to become available, you will have to build your own image FROM prismagraphql/prisma:1.34.8 and COPY wait-for-it.sh to that image. After that you will have to create a custom startup script, which will call wait-for-fit.sh and then exec the main prisma process.
e.g. Dockerfile
FROM prismagraphql/prisma:1.34.8
COPY wait-for-it.sh /
COPY entrypoint.sh /
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
e.g. entrypoint.sh
#!/usr/bin/env bash
/wait-for-it.sh mysql:3036 #add timeout if you want `-t 10s`
exec /app/start.sh "$#"
The tricky part is finding out the starting script inside images. Sometimes you will find a public Dockerfile in the projects repo or you will have to inspect the image e.g. docker image inspect prismagraphql/prisma:1.34.8 --format '{{.ContainerConfig.Entrypoint}}'

Wait for a docker container to be ready with command in docker-compose.yml

I have a mysql-db and prisma image in my docker-compose.yml. I want prisma to wait for the db to be ready, cause otherwise prisma keeps restarting and it wont work at all. And I know from here, that I can use ./wait-for-it but I was not able to connect the pieces after searching for a while.
version: '3'
services:
prisma:
image: prismagraphql/prisma:1.25
restart: unless-stopped
ports:
- "4001:4466"
depends_on:
- db
# I added this command
command: ["./wait-for-it.sh", "db:33061", "--"]
environment:
PRISMA_CONFIG: |
managementApiSecret: server.secret.123
port: 4466
databases:
default:
connector: mysql
active: true
host: db
port: 3306
user: ***
password: ***
db:
image: mysql:5.7
restart: unless-stopped
command: --default-authentication-plugin=mysql_native_password
environment:
MYSQL_USER: ***
MYSQL_ROOT_PASSWORD: ***
ports:
- "33061:3306"
volumes:
- /docker/mysql:/var/lib/mysql
I added the command above but nothing changed, not even an error in the logs but as I understand, the command is run inside the container.
How do I get the ./wait-for-it.sh into the container?
And can this even work this way with the command or does this depend
on the prisma-image?
Otherwise, how would I achieve the waiting?
I just have the docker-compose file and want to do docker-compose up -d
Now I found out how to include wait-for-it.sh into the container.
I downloaded the wait-for-it.sh into the project folder and then I created a file called Dockerfile with the contents:
FROM prismagraphql/prisma:1.25
COPY ./wait-for-it.sh /app/wait-for-it.sh
RUN chmod +x /app/wait-for-it.sh
ENTRYPOINT ["/bin/sh","-c","/app/wait-for-it.sh db:3306 -t 30 -- /app/start.sh"]
In my docker-compose.yml I replaced
image: prismagraphql/prisma:1.25 with build: . which causes a new build from the Dockerfile in my project path.
Now the new image will be built from the prisma image and the wait-for-it.sh will be copied into the new image. Then the ENTRYPOINT is overridden and prisma will wait until the db is ready.
You are confusing internal and external ports. Database is visible on port 3306 inside your network, so you have to wait on db:3306 and not on 33061.
Port exposing has no effect inside user-defined bridge network, created by default by docker-compose. All ports are visible to containers inside network by default. When you expose port, you make it visible outside network.
Also, make sure what is ENTRYPOINT for image prismagraphql/prisma:1.25. If it is not /bin/sh -c or other type of shell, your command wont get executed.
UPD
If you get ENTRYPOINT in base image different from /bin/sh -c, you can override it. Supposing you have /bin/sh -c /app/start.sh, you could do following magic:
docker-compose.yml
...
services:
prisma:
entrypoint: ["/bin/sh", "-c", "'./wait-for-it.sh db:3306 && /app/start.sh'"]

docker-compose keep container running after run entrypoint

My docker-compose.yml
version: '3.1'
services:
redis:
container_name: redis
image: redis:3.0
app_prod:
container_name: app_prod
build:
dockerfile: .docker/app/prod.Dockerfile
context: ./../
ports:
- "8080:80"
links:
- mysql:mysql
- redis:redis
depends_on:
- mysql
- redis
environment:
PRODUCTION_MODE: 'true'
entrypoint: .docker/app/sh/entry-point.sh
mysql:
image: mysql
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: 'my-db'
build:
context: ./mysql # path to folder containing Dockerfile
My .docker/app/sh/entry-point.sh
#!/usr/bin/env bash
set -e # exit script if any command fails (non-zero value)
echo Waiting for redis service start...;
while ! nc -z redis 6379;
do
sleep 1;
done;
echo Waiting for mysql service start...;
while ! nc -z mysql 3306;
do
sleep 1;
done;
echo Connected!;
php www/index.php orm:schema-tool:update --force
exec "$#"
I am building by command:
docker-compose -f .docker/docker-compose-prod.yml up -d --build
All containers are built successfully but at the end is running entrypoint script of container app_prod (.docker/app/sh/entry-point.sh). Entry point script was processed successfully too but after execute entrypoint script is app_prod container stopped.
It is some way to keep container running?
Thanks
Definitionally, no: once the entrypoint exits the container exits.
Your entrypoint is a shell script ending in exec "$#" (good!) which means that, after it successfully waits for its databases to be up, it will run whatever is passed in the docker-compose.yml as command:. (Note that if you declare entrypoint: in docker-compose.yml, it ignores a CMD in the Dockerfile.) So you just need a command: that starts your service and you should be set
entrypoint: .docker/app/sh/entry-point.sh
command: php-fpm

golang program running fine outside of docker, but exiting with 0 when dockerized

I have the following docker-compose.yml file:
version: "3.3"
services:
api:
build: ./api
expose:
- '8080'
container_name: 'api'
ports:
- "8080:8080"
depends_on:
- db
stdin_open: true
tty: true
networks:
- api-net
db:
build: ./db
expose:
- '27017'
container_name: 'mongo'
ports:
- "27017:27017"
networks:
- api-net
networks:
api-net:
driver: bridge
and the Dockerfile for the api container is as follows:
FROM iron/go:dev
RUN mkdir /app
COPY src/main/main.go /app/
ENV SRC_DIR=/app
ADD . $SRC_DIR
RUN go get goji.io
RUN go get gopkg.in/mgo.v2
# RUN cd $SRC_DIR; go build -o main
CMD ["go", "run", "/app/main.go"]
If I run the code for main.go outside of a container it runs as expected, however if I try to run the container as part of docker-compose I get an exit 0. I have seen other threads on stackoverflow that have suggested using stdin_open and tty, but these have not helped. I have also tried creating an .env file in the same directory I issue docker-compose up from with COMPOSE_HTTP_TIMEOUT=8000 in it and this has not worked either. I am looking for helped and suggestions as to what I need to do in order for my api container to stay up.
I know that --verbose can be issued with docker-compose, however I'm not sure what I should be looking for in the output that this produces.
I finally managed to get to the bottom of this, in my code which worked outside of a container I had:
http.ListenAndServe("localhost:8080", mux)
the fix was to simply remove localhost such that I now have:
http.ListenAndServe(":8080", mux)

Resources