using a .sh script for docker healthchecks - bash

sitting on that problem for like 2 hours now and iam getting crazy
here is the example bash script:
#!/bin/bash
exit 0;
here is the dockerfile:
HEALTHCHECK --interval=2s CMD HealthCheckTest.sh || exit 1
I still get always unhealthy.
Want i want to do is have some logic inside my bash script to determine if the container is healthy or not.

You can also use Compose health check if you use Docker Compose:
https://docs.docker.com/compose/compose-file/compose-file-v2/#healthcheck
Also you can define your health checks in a bash script which can be called using ENTRYPOINT in Dockerfile, e.g.:
https://github.com/ledermann/docker-rails/blob/develop/docker/wait-for-services.sh

Related

How can I build a shell script to build a Docker-Compose Image and start up the Docker container if successful?

I'm trying to write a shell script that will attempt to build a Docker-Compose image, then if that's successful, start up the Docker container with it by doing a Docker-Compose up -d.
In the second step, I load some JSON files into Mongo, but then if there's a problem with that step, I want want to stop all Docker services and print out an error message saying "Could not start Docker service because there was a problem seeding the DB."
My problem is that I don't know how to check if the image was created successfully in the first step. (I want to stop and print out a message saying that there were errors in the build.)
I think I can figure out something that checks if both services are running at the end, but I'm wondering if there is a way to print out the name of the problematic JSON file that couldn't load.
Does anyone have a similar script that I can use or modify for my own use?
My understanding is you are trying to branch out the logic of the script based on whether the build command was a success. Here is what you can do:
cat create-image.sh
#!/bin/bash
docker build -q -t test-image .
if [ $? -eq 0 ]; then
echo OK, images created
else
echo FAIL, image not created
exit 1
fi
echo "...DOING OTHER THINGS... (like docker-compose up)"
Let me know if this is what you were looking for.
You don't need a script if you just want to build images before starting containers:
docker-compose --build up
If you must use a script, you can certain call the above command and check its exit code. There is no need to call docker build individually for every service in the docker-compose file.

Detect if docker ran successfully within the same script

My script.sh:
#/bin/sh
docker run --name foo
(Just assume that the docker command works and the container name is foo. Can't make the actual command public.)
I have a script that runs a docker container. I want to check that it ran successfully and echo the successful running status on the terminal.
How can I accomplish this using the container name? I know that I have to use something like docker inspect but when I try to add that command, it only gets executed after I ^C my script probably because docker has the execution.
In this answer, the docker is executed in some other script so it doesn't really work for my use case.
The linked answer from Jules Olléon works on permanently running services like webservers, application servers, database and similar software. In your example, it seems that you want to run a container on-demand, which is designed to do some work and then exit. Here, the status doesn't help.
When running the container in foreground mode as your example shows, it forwards the applications return code to the calling shell. Since you didn't post any code, I give you a simple example: We create a rc.sh script returning 1 as exit-code (which normally indicates some failure):
#!/bin/sh
echo "Testscript failed, returning exitcode 1"
exit 1
It got copied and executed in this Dockerfile:
FROM alpine:3.7
COPY rc.sh .
ENTRYPOINT [ "sh", "rc.sh" ]
Now we build this image using docker build -t rc-test . and execute a short living container:
$ docker run --rm rc-test
Testscript failed, returning exitcode 1
Bash give us the return code in $?:
$ echo $?
1
So we see that the container failed and could simply check them e.g. inside some bash script with an if-condition to perform some action when it fails:
#!/bin/bash
if ! docker run --rm rc-test; then
echo "Docker container failed with rc $?"
fi
After running your docker run command you can check this way if your docker container is still up and running:
s='^foo$'
status=$(docker ps -qf "name=$s" --format='{{.Status}}')
[[ -n $status ]] && echo "Running: $status" || echo "not running"
You just need to execute it with "-d" to execute the container in detached mode. With this, the solutions provided in the other post or the solution provided by #anubhava are both good solutions.
docker run -d -name some_name mycontainer
s='^some_name$'
status=$(docker ps -qf "name=$s" --format='{{.Status}}')
[[ -n $status ]] && echo "Running: $status" || echo "not running"

How to Synchronize the bash shell

I'm trying to make some code that start docker container automately.
So i already make shell script to run the container.
and now I'm making the script run the all script i made.
like this
IP=$1
WEBPORT=$2
STREAMPORT=$3
NAME=$4
ID=$5
PASSWARD=$6
RTSP=$7
#create Container
bash ./docker_script/create_container.sh $IP $WEBPORT $STREAMPORT $NAME
#start Container
bash ./docker_script/start_container.sh $IP $NAME
#setting for using kerberos
#1 Setup user and PASSWARD
bash ./kerberos_script/setup_account_script.sh $IP $WEBPORT $ID $PASSWARD
But for making container and run some time is take.
So i want to make to run each script to be run after the script befored was done.
Is there anyway to run the code synchronize?

Docker CMD evaluation with ENTRYPOINT

I have a Dockerfile that falls into the exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd category in the matrix found in Understand how CMD and ENTRYPOINT interact. The behavior is not what I'm expecting. I was expecting /bin/sh -c exec_cmd p1_cmd to evaluate first then get passed into exec_entry p1_entry. What I am observing is that /bin/sh -c exec_cmd p1_cmd literally gets passed into exec_entry p1_entry which I think is funny.
To provide more context, I am specifically deriving a new Dockerfile from an existing Dockerfile where the parent has:
ENTRYPOINT ["/bin/registrator"]
I want to pass in specific command-line parameters from my Dockerfile:
FROM gliderlabs/registrator:v7
CMD echo "-ip=$EXTERNAL_IP consul://$CONSUL_HOST"
When I run my Docker image in a container:
$ docker run --rm --name=test-registrator --volume=/var/run/docker.sock:/tmp/docker.sock -e "EXTERNAL_IP=<some-ip>" -e "CONSUL_HOST=<some-consul-hostname>:8500" my/registrator
I get the following error:
2016/12/28 19:20:46 Starting registrator v7 ...
Extra unparsed arguments:
-c echo "-ip=$EXTERNAL_IP consul://$CONSUL_HOST"
Options should come before the registry URI argument.
Usage of /bin/registrator:
/bin/registrator [options] <registry URI>
-cleanup=false: Remove dangling services
-deregister="always": Deregister exited services "always" or "on-success"
-internal=false: Use internal ports instead of published ones
-ip="": IP for ports mapped to the host
-resync=0: Frequency with which services are resynchronized
-retry-attempts=0: Max retry attempts to establish a connection with the backend. Use -1 for infinite retries
-retry-interval=2000: Interval (in millisecond) between retry-attempts.
-tags="": Append tags for all registered services
-ttl=0: TTL for services (default is no expiry)
-ttl-refresh=0: Frequency with which service TTLs are refreshed
This means that -c echo "-ip=$EXTERNAL_IP consul://$CONSUL_HOST" is literally getting passed into /bin/registrator as the parameter.
Am I doing something wrong or is this a limitation of the use case where /bin/sh -c exec_cmd p1_cmd does not get evaulated first before getting passed into the ENTRYPOINT? If the latter is true, then can you also explain the usefulness of this use case?
Yes. This is exactly how it is supposed to work.
The value of CMD is just passed as a parameter to the ENTRYPOINT.
Main difference between CMD and ENTRYPOINT is that CMD just provides default command argument to the ENTRYPOINT program and it's usually overridden by the arguments to run command. On the other hand you have to redefine ENTRYPOINT explicitly with --entrypoint option if you want different command to be executed.
Also, notice there is a difference how things are executed depending on the way ENTRYPOINT and CMD are defined in the Dockerfile. When they are defined as an array in the form of ['arg1', 'arg2'] this array is passed as is to the ENTRYPOINT command, with the first element of ENTRYPOINT being the program being executed. In the other case when they are defined as a simple string like arg1 arg2 this string is first passed is prepended by "/bin/sh -c" note that Docker does not execute /bin/sh and returns the result of evaluation back, that string itself is passed to the ENTRYPOINT program.
So in your case you have to use array method of passing the arguments:
CMD [-ip, $EXTERNAL_IP, consul://$CONSUL_HOST]

how do I get etcd values into my systemd service on coreOS?

I have two services A and B.
A sets a value in etcd as it's being started, say the public IP address which it gets from an environment file:
ExecStartPost=/usr/bin/etcdctl set /A_ADDR $COREOS_PUBLIC_IPV4
B needs that value as it starts up, as well as its own IP address. So something like this would be nice:
ExecStart=/usr/bin/docker run -e MY_ADDR=$COREOS_PUBLIC_IPV4 -e A_ADDR=$ETCD_A_ADDR mikedewar/B
but that's obviously not possible as etcd variables don't present as systemd environment variables like that. Instead I can do some sort of /usr/bin/bash -c 'run stuff' in my ExecStart but it's awkward especially as I need systemd to expand $COREOS_PUBLIC_IPV4 and my new bash shell to expand $(etcdctl get /A_ADDR). It also reeks of code smell and makes me think I'm missing something important.
Can someone tell me the "right" way of getting values from etcd into my ExecStart declaration?
-- update
So I'm up and running with
ExecStart=/usr/bin/bash -c 'source /etc/environment && /usr/bin/docker run -e A_ADDR=$(/usr/bin/etcdctl get /A_ADDR) -e MY_ADDR=$COREOS_PUBLIC_IPV4 mikedewar/B'
but it's pretty ugly. Still can't believe I'm not missing something..
I've was struggling with the same thing until recently. After reading much of the documentation of CoreOS and systemd, here is a slightly 'cleaner' version of what you're doing:
[Service]
EnvironmentFile=/etc/environment
ExecStart=/bin/sh -c '/usr/bin/docker run -e A_ADDR=$(/usr/bin/etcdctl get /A_ADDR) -e MY_ADDR=$COREOS_PUBLIC_IPV4 mikedewar/B'
Additionally, I have adopted a pattern where my services depend on a systemd 'oneshot' service that will compute some value and write it in to /etc/environment. This allows you to keep more complex shell scripting out of the main service unit and place it into it's own oneshot service unit.
Here are the docs for EnvironmentFile: http://www.freedesktop.org/software/systemd/man/systemd.exec.html#EnvironmentFile=
Finally, a quick gotchya: you must use a shell invocation if you use any variable in your ExecStart/Stop commands. systemd does no shell invocation when executing the command you provide, so variables will not be expanded.
I am currently using such a workaround:
I've created scripts which extracts data from particular etcd directory
#! /bin/sh
for entry in `etcdctl ls /my_dir --recursive` ; do
echo ' -e '`grep -o '[^/]*$' <<< ${entry}`=`etcdctl get ${entry}`
done
its output looks following:
-e DATABASE_URL=postgres://m:m#mi.cf.us-.rds.amazonaws.com:5432/m
-e WEB_CONCURRENCY=4
So then eventually I can in my init file place that in such way
/bin/sh -c '/usr/bin/docker run -p 9000:9000 $(/home/core/envs.sh) me/myapp -D FOREGROUND'
It's not the most elegant way, and I'd love to know how to improve it, but placing that for loop as a one-liner requires lots of escaping.
Can you container read directly from etcd as it starts, over the docker0 bridge IP, instead of passing in the values? This will also allow you to do more complex logic on the response, parse JSON if you are storing it as the etcd value, etc.

Resources