I was adapting the Docker Compose example from Elasticsearch to set up a default cluster and have stumbled over this health check config which I don't understand:
healthcheck:
test: ["CMD-SHELL", "[ -f config/certs/es01/es01.crt ]"]
interval: 1s
timeout: 5s
retries: 120
I can guess that this command checks for the existence of the file at config/certs/es01/es01.crt. But how does it do so with the script
[ -f config/certs/es01/es01.crt ]
?
More specifically: is some unix command inferred before the -f option? And what are the square brackets for?
[ is a shell command; it is the same as test(1). Checking on a MacOS and Ubuntu system, in both cases there is a /bin/[ with an ordinary executable of that name in a normal search-path directory.
In your example, [ -f filename ] is the same as test -f filename, which returns true (exit code 0) if the file exists.
In a broader Bourne shell context, if [ -f filename ]; then ...; fi isn't special syntax. It runs [, and if that command returns true (exit code 0) then it runs the then block. You can put any command in the if statement and not just [.
Related
I am not particularly fluent with linux, so would appreciate some help.
My system is running with an external drive mounted at /mnt/SSD_240GB and contains two directories that I am trying to monitor the size of, with Telegraf and InfluxDB. These directories are:
/mnt/SSD_240GB/docker_data/InfluxDB/data
and
/mnt/SSD_240GB/docker_data/InfluxDB/wal
Telegraf and InfluxDB are both running in seperate docker containers.
Following this answer, I have made a shell script which contains the following code, which just uses du to get the sizes of any directories that you pass in as arguments:
#!/bin/bash
echo "["
du -s -B1 "$#" | awk '{if (NR!=1) {printf ",\n"};printf " { \"dir_size_bytes\": "$1", \"path\": \""$2"\" }";}'
echo
echo "]"
Running this script directly inside the Telegraf container works as expected, giving the correct file sizes :
Now I try to get Telegraf to automatically run this script at regular intervals by using the exec plugin, by adding the following code to my telegraf.conf file:
[[inputs.exec]]
commands = [ "/etc/telegraf/scripts/get_disk_usage.sh /mnt/SSD_240GB/docker_data/InfluxDB/wal /mnt/SSD_240GB/docker_data/InfluxDB/data" ]
timeout = "1m"
name_override = "du"
name_suffix = ""
data_format = "json"
tag_keys = [ "path" ]
The problem is that now the data which arrives in InfluxDB does not match this. In fact the file sizes returned are always the same (20480 bytes and 4096 bytes, respectively):
Does anyone know how to resolve this? Thanks!
Here is the telegraf section of the docker-compose.yaml file:
telegraf:
image: telegraf
container_name: telegraf_container
restart: always
ports:
- 8125:8125
networks:
- docker_monitoring_network
volumes:
- /mnt/SSD_240GB/docker_config_files/Telegraf/telegraf.conf:/etc/telegraf/telegraf.conf
- /mnt/SSD_240GB/docker_config_files/Telegraf/scripts:/etc/telegraf/scripts
- /mnt/SSD_240GB:/mnt/SSD_240GB:ro
Recently, we had an outage due to Redis being unable to write to a file system (not sure why it's Amazon EFS) anyway I noted that there was no actual HEALTHCHECK set up for the Docker service to make sure it is running correctly, Redis is up so I can't simply use nc -z to check if the port is open.
Is there a command I can execute in the redis:6-alpine (or non-alpine) image that I can put in the healthcheck block of the docker-compose.yml file.
Note I am looking for command that is available internally in the image. Not an external healthcheck.
If I remember correctly that image includes redis-cli so, maybe, something along these lines:
...
healthcheck:
test: ["CMD", "redis-cli","ping"]
Although the ping operation from #nitrin0 answer generally works. It does not handle the case where the write operation will actually fail. So instead I perform a change that will just increment a value to a key I don't plan to use.
image: redis:6
healthcheck:
test: [ "CMD", "redis-cli", "--raw", "incr", "ping" ]
I've just noticed that there is a phase in which redis is still starting up and loading data. In this phase, redis-cli ping shows the error
LOADING Redis is loading the dataset in memory
but stills returns the exit code 0, which would make redis already report has healthy.
Also redis-cli --raw incr ping returns 0 in this phase without actually incrementing this key successfully.
As a workaround, I'm checking whether the redis-cli ping actually prints a PONG, which it only does after the LOADING has been finished.
services:
redis:
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
interval: 1s
timeout: 3s
retries: 5
This works because grep returns only 0 when the string ("PONG") is found.
You can also add it inside the Dockerfile if your using a Redis image that contains the redis-cli:
Linux Docker
HEALTHCHECK CMD redis-cli ping || exit 1
Windows Docker
HEALTHCHECK CMD pwsh.exe -command \
try { \
$response = ./redis-cli ping; \
if ($response -eq 'PONG') { return 0} else {return 1}; \
} catch { return 1 }
I have a customized rabbitmq image that I am using with docker-compose (3.7) to launch a docker cluster. This is necessary because of some peculiar issues when trying to deploy a cluster in docker swarm. The image has a shell script which runs on the primary and secondary nodes and makes the modifications needed to run a cluster. This involves stopping rabbitmq and running rabbitmqctl commands to create the cluster between the two nodes. This configuiration works flawlessly until I try to add in a healthcheck. I have tried adding it in to the image and adding it into the compose file. Both cause the image to crash and constantly restart. I have the following shell script which gets copied into the image:
#!/bin/bash
set -eo pipefail
# A RabbitMQ node is considered healthy if all the below are true:
# * the rabbit app finished booting & it's running
# * there are no alarms
# * there is at least 1 active listener
rabbitmqctl eval '
{ true, rabbit_app_booted_and_running } = { rabbit:is_booted(node()), rabbit_app_booted_and_running },
{ [], no_alarms } = { rabbit:alarms(), no_alarms },
[] /= rabbit_networking:active_listeners(),
rabbitmq_node_is_healthy.
' || exit 1
On an already running image this works and produces the correct result.
I tried the flowing in the compose file:
healthcheck:
interval: 60s
timeout: 60s
retries: 10
start_period: 600s
test: ["CMD", "docker-healthcheck"]
It seems that the start_period is completely ignored. I can see the health status with an error right away. I have also tried the following native rabbitmq diagnostics command:
rabbitmq-diagnostics -q check_running && rabbitmq-diagnostics -q check_local_alarms
This oddly fails with an "unable to find rabbitmq-diagnostics" error, despite the fact the program is definitely in the path. I can execute the command successfully in an already running container.
If I create the container without the healthcheck and then add it in after the fact from the command line with:
docker service update --health-cmd docker-healthcheck --health-interval 60s --health-timeout 60s --health-retries 10 [container id]
it marks the container healthy. So it works but just not in a start up configuration. It seems like to me that the healthcheck should not begin until 10 minutes have passed. It doesn't seem to matter how long I wait for everything to startup using the start_period parameter it still causes the container to fail.
Is this a bug or is there something mysterious about the way start_period works?
Anyone else every have this problem?
I want to print environment variable defined in docker-compose file.
Here is my docker-compose-1.yml:
version: '3.6'
services:
busybox:
image: busybox
command: 'echo $DEBUG'
environment:
- DEBUG='123456'
And, try to print the DEBUG environment variable in docker container:
☁ environment-variables-in-compose [master] ⚡ docker-compose -f docker-compose-1.yml up
WARNING: The DEBUG variable is not set. Defaulting to a blank string.
Creating network "environmentvariablesincompose_default" with the default driver
Creating environmentvariablesincompose_busybox_1 ... done
Attaching to environmentvariablesincompose_busybox_1
busybox_1 |
environmentvariablesincompose_busybox_1 exited with code 0
As you can see, got WARNING: The DEBUG variable is not set. Defaulting to a blank string.
Am I wrong?
update 1:
docker-compose-1.yml:
version: '3.6'
services:
busybox:
image: busybox
command: 'echo $$DEBUG'
environment:
DEBUG: 123456
I change command using double $ sign, but the result is still not what I want.
☁ environment-variables-in-compose [master] ⚡ docker-compose -f docker-compose-1.yml up
Creating network "environmentvariablesincompose_default" with the default driver
Creating environmentvariablesincompose_busybox_1 ... done
Attaching to environmentvariablesincompose_busybox_1
busybox_1 | $DEBUG
environmentvariablesincompose_busybox_1 exited with code 0
As you can see, the environment variable is printed as $DEBUG, not expected value 123456
Compose will expand variables from the environment where you are running compose. To expand the variable inside your container, escape the $ using $$:
command: '/bin/sh -c "echo $$DEBUG"'
For more details, see: https://docs.docker.com/compose/compose-file/#variable-substitution
Edit: I've also added a shell inside the container to expand the variable.
I run many services in my docker-compse.yml. I'd like to display a message to let user know when docker-compose up is done?
I tried to echo message with command but my container exited with code 0
command: bash -c "echo Congratulation! You can use your containers now"
Is there anyway to let user know when docker-compose up is done?
Many thanks!
Anything you do in CMD will only be visible in the logs, and only per service, so you may as well just watch the logs which I assume is what you're trying to avoid. If you want it to work from the local command line you're going to need to wrap the docker-compose up command.
THE following is NOT fully tested. This is for guidance only. I use the getContainerHealth and waitContainer scripts myself, so can vouch for them. I'm fairly sure I found them on this site, but can't remember where.
Assuming you're waiting for your services to be in a usable state, you could use something similar to this compose file:
docker-compose.yml
services:
serviceOne:
// ... the usual stuff
container_name: serviceOne
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 10s
timeout: 10s
retries: 3
start_period: 1s
serviceTwo:
// ... the usual stuff
container_name: serviceTwo
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 10s
start_period: 1s
The commands in the test are the commands you use to define the service is up and running. More info here: https://docs.docker.com/compose/compose-file/#healthcheck
You will probably want different health checks (or at least intervals, timeouts, start_periods, etc) for production and development.
then some bash script that you use instead of docker-compose up:
getContainerHealth () {
docker inspect --format "{{json .State.Health.Status }}" $1
}
waitContainer () {
while STATUS=$(getContainerHealth $1); [ $STATUS != "\"healthy\"" ]; do
if [ $STATUS = "\"unhealthy\"" ]; then
echo "Failed!"
exit -1
fi
printf .
lf=$'\n'
sleep 1
done
printf "$lf"
}
waitContainers () {
waitContainer serviceOne
waitContainer serviceTwo
// ... for all services
}
docker-compose up
echo "In progress. Please wait"
waitContainers
echo "Done. Ready to roll."
create a shell file echo.sh that contains
echo "Your message"
In Docker file add
CMD ["/dockerRepo/echo.sh"]
Have you tried running something like the following directly in the Dockerfile itself ?
RUN echo -e "Your message"