Running and configuring mqtt broker with docker composer - docker

In the documentation of docker composer version 3, from what I understood, to run some commands after a container has started I need to add the "command" tag as follows:
version: "3"
services:
broker:
image: "toke/mosquitto"
restart: always
ports:
- "1883:1883"
- "9001:9001"
command: ["cd /etc/mosquitto", "echo \"\" > mosquitto.pwd", "mosquitto_passwd -b /etc/mosquitto/mosquitto.pwd user pass", "echo \"password_file mosquitto.pwd\" >> mosquitto.conf", "echo \"allow_anonymous false\" >> mosquitto.conf"]
The log returns /usr/bin/docker-entrypoint.sh: 5: exec: cd /etc/mosquitto: not found
A workaround could be specify in the composer file what dockerfile to run and add the commands that should run there, so I created one dockerfile:
FROM toke/mosquitto
WORKDIR .
EXPOSE 1883:1883 9001:9001
ENTRYPOINT cd /etc/mosquitto
ENTRYPOINT echo "" > mosquitto.pwd
ENTRYPOINT mosquitto_passwd -b mosquitto.pwd usertest passwordtest
ENTRYPOINT echo "password_file mosquitto.pwd" >> mosquitto.conf
ENTRYPOINT echo "allow_anonymous false" >> mosquitto.conf
The container's keep restarting and the log doesn't return anything. I've also tried changing the "ENTRYPOINT" for "CMD" with no changing in the output.
As an addend specifying the docker composer file to use a specific dockerfile it fails to parse and says:
ERROR: The Compose file '.\docker-compose.yml' is invalid because:
Unsupported config option for services.broker: 'dockerfile'
As in it can't parse or doesn't understand "dockerfile" tag. Does anyone know how to configure a dockerfile or even docker-composer to run the commands intended in this post to configure a mqtt broker?

The command entry in the compose file is not a list of commands to run, it's a single command and it's arguments
e.g. to run mosquitto -c /etc/mosquitto/mosquitto.conf
command: ["mosquitto", "-c", "/etc/mosquitto/mosquitto.conf"]
As for the Dockerfile, There should only be one ENTRYPOINT or CMD. If you want to run multiple commands then you should create a shell script to do run them, add it to the container then use ENTRYPOINT or CMD to run the script.

Related

Docker container fails on Windows Powershell succeeds on WSL2 with identical Dockerfile and docker-compose

Problem Description
I have a docker image which I build and run using docker-compose. Normally I develop on WSL2, and when running docker-compose up --build the image builds and runs successfully. On another machine, using Windows powershell, with an identical clone of the code, executing the same command successfully builds the image, but gives an error when running.
Error
[+] Running 1/1
- Container fastapi-service Created 0.0s
Attaching to fastapi-service
fastapi-service | exec /start_reload.sh: no such file or directory
fastapi-service exited with code 1
I'm fairly experienced using Docker, but am a complete novice with PowerShell and developing on Windows more generally. Is there a difference in Dockerfile construction in this context, or a difference in the execution of COPY and RUN statements?
Code snippets
Included are all parts of the code required to replicate the error.
Dockerfile
FROM tiangolo/uvicorn-gunicorn:python3.7
COPY requirements.txt requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
COPY ./start.sh /start.sh
RUN chmod +x /start.sh
COPY ./start_reload.sh /start_reload.sh
RUN chmod +x /start_reload.sh
COPY ./data /data
COPY ./app /app
EXPOSE 8000
CMD ["/start.sh"]
docker-compose.yml
services:
web:
build: .
container_name: "fastapi-service"
ports:
- "8000:8000"
volumes:
- ./app:/app
command: /start_reload.sh
start-reload.sh
This is a small shell script which runs a prestart.sh if present, and then launches gunicorn/uvicorn in "reload mode":
#!/bin/sh
# If there's a prestart.sh script in the /app directory, run it before starting
PRE_START_PATH=/app/prestart.sh
HOST=${HOST:-0.0.0.0}
PORT=${PORT:-8000}
LOG_LEVEL=${LOG_LEVEL:-info}
echo "Checking for script in $PRE_START_PATH"
if [ -f $PRE_START_PATH ] ; then
echo "Running script $PRE_START_PATH"
. "$PRE_START_PATH"
else
echo "There is no script $PRE_START_PATH"
fi
# Start Uvicorn with live reload
exec uvicorn --host $HOST --port $PORT --log-level $LOG_LEVEL main:app --reload
The solution lies in a difference between UNIX and Windows systems, and the way they end lines. A discussion on the topic can be found [here].
(Difference between CR LF, LF and CR line break types?)
The presence/absence of these characters in the file, and configuration of the shell running the command leads to an error where the file being run is the Dockerfile start-reload.sh(CR-LF) but the file that exists is simply start-reload.sh, hence the no such file or directory error raised.

Unable to view the environment variable in the sh file when passing it through docker-compose file

I have a docker file
FROM tomcat:9.0.45-jdk8-adoptopenjdk-hotspot
RUN mkdir -p /opt/main
WORKDIR /opt/main
COPY run.sh test.sh runmain.sh /opt/main
RUN chmod +x /opt/main/run.sh && bash /opt/main/run.sh
ENTRYPOINT bash /usr/local/tomcat/bin/runmain.sh && /usr/local/tomcat/bin/catalina.sh run
An env file
ENV_MQ_DETAILS=tcp://10.222.12.12:61616
ENV_DB_HOST=10.222.12.12
runmain.sh file has the following code
#!/bin/bash
echo ${ENV_MQ_DETAILS}
echo ${ENV_DB_HOST}
when I run the docker run command
docker run --env-file .env bootstrap -d
The docker logs shows both env variable values printed.
when I use the docker-compose file
version: "3"
services:
bootstrap:
image: bootstrap
container_name: bootstrap
hostname: bootstrap
ports:
- 8080:8080
and run the command
docker-compose -f docker-compose-bootstrap.yaml --env-file .env bootstrap -d
I get two issues
While running the docker-compose-bootstrap.yaml the environment variables aren't shown in the logs hence can use them in the latest part of the code, why is it so and please help to resolve this (highest priority).
2 In both the cases (docker run and docker-compose run) , it keeps echoing the files in /opt/main/ folder
but nothing to bother though, but why ?
Please help in resolving the above issues.

docker-compose debugging service show `pwd` and `ls -l` at run?

I have a docker-compose file with a service called 'app'. When I try to run my docker file I don't see the service with docker ps but I do with docker ps -a.
I looked at the logs:
docker logs my_app_1
python: can't open file '//apps/index.py': [Errno 2] No such file or directory
In order to debug I wanted to be able to see the home directory and the files and dirs contained there when the app attempts to run.
Is there a command I can add to docker-compose that would show me the pwd and ls -l of the container when it attempts to run index.py?
My Dockerfile:
FROM python:3
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "apps/index.py"]
My docker-compose.yaml:
version: '3.1'
services:
app:
build:
context: ./app
dockerfile: ./Dockerfile
depends_on:
- db
ports:
- 8050:8050
My directory structure:
my_app:
* docker-compose.yaml
* app
* Dockerfile
* apps
* index.py
You can add a RUN statement in the application Dockerfile to run these commands.
Example:
FROM python:3
COPY . .
RUN pip install -r requirements.txt
# Run your commands
RUN pwd && ls -l
CMD ["python", "apps/index.py"]
Then you chan check the logs of the build process and view the results.
I hope this answer helps you.
If you're just trying to debug an image you've already built, you can docker-compose run an alternate command:
docker-compose run apps \
ls -l ./apps
You don't need to modify anything in your Dockerfile to be able to do this (assuming it uses CMD correctly; see below).
If you need to do more intensive debugging, you can docker-compose run apps sh (or, if your image has it, bash) to get an interactive shell. The container will include any mounted volumes and be on the same Docker network as the named container, but won't have published ports.
Note that the command here replaces the CMD in the Dockerfile. If your image uses ENTRYPOINT for its main command, or if it has a complete command split between ENTRYPOINT and CMD (especially, if you have ENTRYPOINT ["python"]), these need to be combined into a single CMD for this to work. If your ENTRYPOINT is a wrapper script that does some first-time setup and then runs the CMD, this approach will work fine; the debugging ls or sh will run after the first-time setup happens.

How to put command of build docker container to dockerfile?

I have script: docker run -it -p 4000:4000 bitgosdk/express:latest --disablessl -e test
how to put this command to dockerfile with arguments?
FROM bitgosdk/express:latest
EXPOSE 4000
???
Gone through your Dockerfile contents.
The command running inside container is:
/ # ps -ef | more
PID USER TIME COMMAND
1 root 0:00 /sbin/tini -- /usr/local/bin/node /var/bitgo-express/bin/bitgo-express --disablessl -e test
The command is so because the entrypoint set in the Dockerfile is ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/node", "/var/bitgo-express/bin/bitgo-express"] and the arguments --disablessl -e test are the one provided while running docker run command.
The --disablessl -e test arguments can be set inside your Dockerfile using CMD:
CMD ["--disablessl", "-e","test"]
New Dockerfile:
FROM bitgosdk/express:latest
EXPOSE 4000
CMD ["--disablessl", "-e","test"]
Refer this to know the difference between entrypoint and cmd.
You don't.
This is what docker-compose is used for.
i.e. create a docker-compose.yml with contents like this:
version: "3.8"
services:
test:
image: bitgodsdk/express:latest
command: --disablessl -e test
ports:
- "4000:4000"
and then execute the following in a terminal to access the interactive terminal for the service named test.
docker-compose run test
Even if #mchawre's answer seems to directly answer OP's question "syntactically speaking" (as a Dockerfile was asked), a docker-compose.yml is definitely the way to go to make a docker run command, as custom as it might be, reproducible in a declarative way (YAML file).
Just to complement #ChrisBecke's answer, note that the writing of this YAML file can be automated. See e.g., the FOSS (under MIT license) https://github.com/magicmark/composerize
FTR, the snippet below was automatically generated from the following docker run command, using the accompanying webapp https://composerize.com/:
docker run -it -p 4000:4000 bitgosdk/express:latest
version: '3.3'
services:
express:
ports:
- '4000:4000'
image: 'bitgosdk/express:latest'
I omitted the CMD arguments --disablessl -e test on-purpose, as composerize does not seem to support these extra arguments. This may sound like a bug (and FTR a related issue is opened), but meanwhile it might just be viewed as a feature, in line of #DavidMaze's comment…

Print status after docker-compose container starts

In a docker-compose file, is it possible to wait for a container to start and then print a status?
e.g. sleep 10 && echo started mysql on http://${HOST}:${PORT}
A Dockerfile has a run command, but there isn't such a thing in a compose file. How can I do this?
With docker-compose, just like with a regular docker run [...], you can specify entrypoint (cf. here) and command (cf. here).
In your case, however, what I would do is building an own Docker image based on your preferred MySQL image and COPY a simple entrypoint script into the image that does what you want, e.g.
#!/bin/sh
sleep 10
[command to run MySQL]
echo "Started MySQL on xyz"
Then specify this script as ENTRYPOINT in your Dockerfile.
The best way is just add this to the compose file:
print-status:
image: busybox
env_file: .env
command: "sh -c 'sleep 10 && echo \"http://localhost:${PORT}\"'"
depends_on:
- mysql

Resources