Starting multiple services using shell script in Dockerfile - shell

I am creating a Dockerfile to install and start the WebLogic 12c services using startup scripts at "docker run" command. I am passing the shell script in the CMD instruction which executes the startWeblogic.sh and startNodeManager.sh script. But when I logged in to the container, it has started only the first script startWeblogic.sh and not even started the second script which is obvious from the docker logs.
The same script executed inside the container manually and it is starting both the services. What is the right instruction for running the script to start multiple processes in a container and not to exit the container?
What am I missing in this script and in the dockerfile? I know that container can run only one process, but in a dirty way, how to start multiple services for an application like WebLogic which has a nameserver, node manager, managed server and creating managed domains and machines. The managed server can only be started when WebLogic nameserver is running.
Script: startscript.sh
#!/bin/bash
# Start the first process
/u01/app/oracle/product/wls122100/domains/verdomain/bin/startWebLogic.sh -D
status=$?
if [ $status -ne 0 ]; then
echo "Failed to start my_first_process: $status"
exit $status
fi
# Start the second process
/u01/app/oracle/product/wls122100/domains/verdomain/bin/startNodeManager.sh -D
status=$?
if [ $status -ne 0 ]; then
echo "Failed to start my_second_process: $status"
exit $status
fi
while sleep 60; do
ps aux |grep "Name=adminserver" |grep -q -v grep
PROCESS_1_STATUS=$?
ps aux |grep node |grep -q -v grep
PROCESS_2_STATUS=$?
# If the greps above find anything, they exit with 0 status
# If they are not both 0, then something is wrong
if [ $PROCESS_1_STATUS -ne 0 -o $PROCESS_2_STATUS -ne 0 ]; then
echo "One of the processes has already exited."
exit 1
fi
done
Truncated the dockerfile.
RUN unzip $WLS_PKG
RUN $JAVA_HOME/bin/java -Xmx1024m -jar /u01/app/oracle/$WLS_JAR -silent -responseFile /u01/app/oracle/wls.rsp -invPtrLoc /u01/app/oracle/oraInst.loc > install.log
RUN rm -f $WLS_PKG
RUN . $WLS_HOME/server/bin/setWLSEnv.sh && java weblogic.version
RUN java weblogic.WLST -skipWLSModuleScanning create_basedomain.py
WORKDIR /u01/app/oracle
CMD ./startscript.sh
docker build and run commands:
docker build -f Dockerfile-weblogic --tag="weblogic12c:startweb" /var/dprojects
docker rund -d -it weblogic12c:startweb
docker exec -it 6313c4caccd3 bash

Please use supervisord for running multiple services in a docker container. It will make the whole process more robust and reliable.
Run supervisord -n as your CMD command and configure all your services in /etc/supervisord.conf.
Sample conf would look like:
[program:WebLogic]
command=/u01/app/oracle/product/wls122100/domains/verdomain/bin/startWebLogic.sh -D
stderr_logfile = /var/log/supervisord/WebLogic-stderr.log
stdout_logfile = /var/log/supervisord/WebLogic-stdout.log
autorestart=unexpected
[program:NodeManager]
command=/u01/app/oracle/product/wls122100/domains/verdomain/bin/startNodeManager.sh -D
stderr_logfile = /var/log/supervisord/NodeManager-stderr.log
stdout_logfile = /var/log/supervisord/NodeManager-stdout.log
autorestart=unexpected
It will handle all the things you are trying to do with a shell script.
Hope it helps!

Related

How to run shell script via kubectl without interactive shell

I am trying to export a configuration from a service called keycloak by using shell script. To do that, export.sh will be run from the pipeline.
the script connects to k8s cluster and run the command in there.
So far, everything goes okay the export work perfectly.
But when I try to exit from the k8s cluster with exit and directly end the shell script. therefore it will move back to the pipeline host without staying in the remote machine.
Running the command from the pipeline
ssh -t ubuntu#example1.com 'bash' < export.sh
export.sh
#!/bin/bash
set -x
set -e
rm -rf /tmp/realm-export
if [ $(ps -ef | grep "keycloak.migration.action=export" | grep -v grep | wc -l) != 0 ]; then
echo "Another export is currently running"
exit 1
fi
kubectl -n keycloak exec -it keycloak-0 bash
mkdir /tmp/export
/opt/jboss/keycloak/bin/standalone.sh -Dkeycloak.migration.action=export -Dkeycloak.migration.provider=dir -Dkeycloak.migration.dir=/tmp/export -Dkeycloak.migration.usersExportStrategy=DIFFERENT_FILES -Djboss.socket.binding.port-offset=100
rm /tmp/export/master-*
exit
kubectl -n keycloak cp keycloak-0:/tmp/export /tmp/realm-export
exit
exit
scp ubuntu#example1.com:/tmp/realm-export/* ./configuration2/realms/
After the first exit the whole shell script stopped, the left commands doesn't work. it won't stay on ubuntu#example1.com.
Is there any solutions?
Run the commands inside without interactive shell using HEREDOC(EOF).
It's not EOF. It's 'EOF'. this prevents a variable expansion in the current shell.
But in the other script's /tmp/export/master-* will expand as you expect.
kubectl -n keycloak exec -it keycloak-0 bash <<'EOF'
<put your codes here, which you type interactively>
EOF
export.sh
#!/bin/bash
set -x
set -e
rm -rf /tmp/realm-export
if [ $(ps -ef | grep "keycloak.migration.action=export" | grep -v grep | wc -l) != 0 ]; then
echo "Another export is currently running"
exit 1
fi
# the suggested code.
kubectl -n keycloak exec -it keycloak-0 bash <<'EOF'
<put your codes here, which you type interactively>
EOF
mkdir /tmp/export
/opt/jboss/keycloak/bin/standalone.sh -Dkeycloak.migration.action=export -Dkeycloak.migration.provider=dir -Dkeycloak.migration.dir=/tmp/export -Dkeycloak.migration.usersExportStrategy=DIFFERENT_FILES -Djboss.socket.binding.port-offset=100
rm /tmp/export/master-*
kubectl -n keycloak cp keycloak-0:/tmp/export /tmp/realm-export
scp ubuntu#example1.com:/tmp/realm-export/* ./configuration2/realms/
Even if scp runs successfully or not, this code will exit.

Get exit code from docker entrypoint command

I have a docker container that runs a script via the entrypoint directive. The container closes after the entrypoint script is finished. I need to get the exit code from the script in order to do some logging if the script fails. Right now I'm thinking of something like this
docker run container/myContainer:latest
if [ $? != 0 ];
then
do some stuff
fi
Is this proper way to achieve this? Specifically, will this be the exit code of docker run or of my entrypoint script?
Yes, the docker container run exit code is the exit code from your entrypoint/cmd:
$ docker container run busybox /bin/sh -c "exit 5"
$ echo $?
5
You may also inspect the state of an exited container:
$ docker container inspect --format '{{.State.ExitCode}}' \
$(docker container ls -lq)
5
Checking the value of $? is not needed if you just want to act upon the exit status of the previous command.
if docker run container/myContainer:latest; then
do_stuff
fi
The above example will run/execute do_stuff if the exit status of docker run is zero which is a success.
You can add an else and elif clause in that
Or if you want to negate the exit status of the command.
if ! docker run container/myContainer:latest; then
do_stuff
fi
The above example will run do_stuff if the exit status of docker run is anything but zero, e.g. 1 and going up, since the ! negates.
If the command has some output and if does not have a silent/quite flag/option you can redirect it to /dev/null
if docker run container/myContainer:latest >/dev/null; then
do_stuff
fi
Should not output anything to stdout
see help test | grep -- '^[[:blank:]]*!'
In some cases if some output is still showing then that might be stderr which you can silent with >/dev/null 2>&1 instead of just >/dev/null

How to run command conditionally in docker compose

I want to run command conditionally in docker-compose
because when someone run this application at first time,
They would have to run migrate command so that they can run django application properly
But If their docker have run migrate, there is no need to run migrate again
So this is the command to check that their docker have run migrate.
if [[ -z $(python3 zeus/manage.py showmigrations | grep '\[ \]')]]; then
echo 'no need to migrate'
else
echo 'need to migate'
fi
This is my docker-compose.
version: '3'
services:
db:
image: postgres
web:
command: >
bash -c "if [[ -z $(python3 zeus/manage.py showmigrations | grep '\[ \]')]]; then
echo 'no need to migrate'
else
echo 'need to migate'
fi && python3 zeus/manage.py runserver 0.0.0.0:8000
"
But Error occurs like this
ERROR: Invalid interpolation format for "build" option in service
"web": "bash -c "if [[ -z $(python3 zeus/manage.py showmigrations | grep '\[ \]')]]; then
echo 'no need to migrate' else echo 'need to migate' fi
&& python3 zeus/manage.py runserver 0.0.0.0:8000""
Any idea?
Edit
This is fine when I run the script of checking migration in normal bash
I think docker-compose can't parse $(python3 manage.py .....) part.
try this :
version: '3'
services:
db:
image: postgres
web:
command: bash -c "if [[ -z $$(python3 zeus/manage.py showmigrations | grep '\\[ \\]') ]]; then
echo 'no need to migrate';
else
echo 'need to migate';
fi && python3 zeus/manage.py runserver 0.0.0.0:8000"
three problems were there , you need to escap the escape charachter \ and add more $ to escape the replacment in compose and one more space before the last ]]
Try to avoid writing complicated scripts in docker-compose.yml, especially if they're for normal parts of your application setup.
A typical pattern is to put this sort of setup in an entrypoint script. That script ends with the shell command exec "$#". In a Docker context, that tells it to replace itself with the command (from a Dockerfile CMD statement or Docker Compose command:). For your example this could look like
#!/bin/sh
if [ -z $(python3 zeus/manage.py showmigrations | grep '\[ \]')]; then
echo 'no need to migrate'
else
echo 'need to migate'
fi
exec "$#"
Then in your Dockerfile, copy this file in and specify it as the ENTRYPOINT; leave your CMD that runs your application unmodified.
COPY entrypoint.sh /app
RUN chmod +x entrypoint.sh
ENTRYPOINT ["/app/entrypoint.sh"]
CMD python3 zeus/manage.py run --host=0.0.0.0:8000
The ENTRYPOINT statement must be the JSON-array form and must not have an explicit sh -c wrapper in it.
If you want to verify that things have gotten set up correctly, you can run
docker-compose run web sh
and you will get a shell at the point that exec "$#" is: after your migrations and other setup have run, but instead of your main server process.

Docker Check if DB is Running

entrypoint.sh contains various cqlsh commands that require Cassandra. Without something like script.sh, cqlsh commands fail because Cassandra doesn't have enough time to start. When I execute the following locally, everything appears to work properly. However, when I run via Docker, script.sh never finishes. In other words, $status never changes from 1 to 0.
Dockerfile
FROM cassandra
RUN apt-get update && apt-get install -y netcat
RUN mkdir /dir
ADD ./scripts /dir/scripts
RUN /bin/bash -c 'service cassandra start'
RUN /bin/bash -c '/dir/scripts/script.sh'
RUN /bin/bash -c '/dir/scripts/entrypoint.sh'
script.sh
#!/bin/bash
set -e
cmd="$#"
status=$(nc -z localhost 9042; echo $?)
echo $status
while [ $status != 0 ]
do
sleep 3s
status=$(nc -z localhost 9042; echo $?)
echo $status
done
exec $cmd
Alternatively, I could do something like until cqlsh -e 'some code'; do .., as noted here for psql, but that doesn't appear to work for me. Wondering how best to approach the problem.
You're misusing the RUN command in your Dockerfile. It's not for starting services, it's for making filesystem changes in your image. The reason $status doesn't update is because you can't start Cassandra via a RUN command.
You should add service cassandra start and /dir/scripts/entrypoint.sh to your script.sh file, and make that the CMD that's executed by default:
Dockerfile
CMD ['/bin/bash', '-c', '/dir/scripts/script.sh']
script.sh
#!/bin/bash
set -e
# NOTE: I removed your `cmd` processing in favor of invoking entrypoint.sh
# directly.
# Start Cassandra before waiting for it to boot.
service cassandra start
status=$(nc -z localhost 9042; echo $?)
echo $status
while [ $status != 0 ]
do
sleep 3s
status=$(nc -z localhost 9042; echo $?)
echo $status
done
exec /bin/bash -c /dir/scripts/entrypoint.sh

Couldn't connect to Docker daemon on Mac OS X

I would like to run multi-container application using docker-compose on Mac OS X El Capitan (v10.11.2).
However, the command $ docker-compose up command complains that it can't connect to the Docker daemon.
ERROR: Couldn't connect to Docker daemon - you might need to run docker-machine start default.
Only after executing $ eval "$(docker-machine env default)" I do have access to the docker-compose command.
Why is this and how can I overcome this extra step?
Update for Docker versions that come with Docker.app
The Docker experience on macOS has improved since this answer was posted:
The only prerequisite is now for Docker.app to be running. Note that starting it on demand takes a while, because the underlying Linux VM must be started.
Any shell then has access to Docker functionality.
By default, Docker.app is launched at login time (you can change that via its preferences).
If you instead prefer starting and stopping Docker on demand from the command line, here are bash scripts that do that, docker-start and docker-stop; place them anywhere in your $PATH.
When docker-start launches Docker.app, it waits until Docker has finished starting up and is ready.
docker-start:
#!/usr/bin/env bash
case $1 in
-h|--help)
echo $'usage: docker-start\n\nStarts Docker (Docker.app) on macOS and waits until the Docker environment is initialized.'
exit 0
;;
esac
(( $# )) && { echo "ARGUMENT ERROR: Unexpected argument(s) specified. Use -h for help." >&2; exit 2; }
[[ $(uname) == 'Darwin' ]] || { echo "This function only runs on macOS." >&2; exit 2; }
echo "-- Starting Docker.app, if necessary..."
open -g -a Docker.app || exit
# Wait for the server to start up, if applicable.
i=0
while ! docker system info &>/dev/null; do
(( i++ == 0 )) && printf %s '-- Waiting for Docker to finish starting up...' || printf '.'
sleep 1
done
(( i )) && printf '\n'
echo "-- Docker is ready."
docker-stop:
#!/usr/bin/env bash
case $1 in
-h|--help)
echo $'usage: docker-stop\n\nStops Docker (Docker.app) on macOS.'
exit 0
;;
esac
(( $# )) && { echo "ARGUMENT ERROR: Unexpected argument(s) specified. Use -h for help." >&2; exit 2; }
[[ $(uname) == 'Darwin' ]] || { echo "This function only runs on macOS." >&2; exit 2; }
echo "-- Quitting Docker.app, if running..."
osascript - <<'EOF' || exit
tell application "Docker"
if it is running then quit it
end tell
EOF
echo "-- Docker is stopped."
echo "Caveat: Restarting it too quickly can cause errors."
Original, obsolete answer:
Kevan Ahlquist's helpful answer shows what commands to add to your Bash profile (~/.bash_profile) to automatically initialize Docker on opening an interactive shell.
Note that you can always initialize Docker in a new shell tab/window by opening application /Applications/Docker/Docker Quickstart Terminal.app (e.g., via Spotlight).
From an existing shell, you can invoke it as open -a 'Docker Quickstart Terminal.app' (which also opens a new shell tab).
What this answer offers is a convenient way to start Docker in the current shell.
Adding the Bash shell functions below - docker-start and docker-stop - improves on Kevan's approach in the following respects:
You can run docker-start on demand, without the overhead of starting the VM on opening the shell (once the Docker VM is running, initialization is much faster, but still takes a noticeable amount of time).
(Of course, you can still opt to invoke docker-start right from your profile.)
docker-stop allows stopping Docker and cleaning up the environment variables on demand.
The functions ensure that Docker's error messages are not suppressed, and they pass Docker error exit codes through.
Additional status information is provided.
You may pass a VM name as a parameter; default is default.
Example:
$ docker-start
-- Starting Docker VM 'default' (`docker-machine start default`; this will take a while)...
Starting "default"...
(default) Check network to re-create if needed...
(default) Waiting for an IP...
Machine "default" was started.
Waiting for SSH to be available...
Detecting the provisioner...
Started machines may have new IP addresses. You may need to re-run the `docker-machine env` command.
-- Setting DOCKER_* environment variables (`eval "$(docker-machine env default)"`)...
DOCKER_CERT_PATH="/Users/jdoe/.docker/machine/machines/default"
DOCKER_HOST="tcp://192.168.99.100:2376"
DOCKER_MACHINE_NAME="default"
DOCKER_TLS_VERIFY="1"
-- Docker VM 'default' is running.
$ docker-stop
-- Stopping Docker VM 'default' (`docker-machine stop default`)...
Stopping "default"...
Machine "default" was stopped.
-- Unsetting DOCKER_* environment variables (DOCKER_CERT_PATH, DOCKER_HOST, DOCKER_MACHINE_NAME, DOCKER_TLS_VERIFY)...
-- Docker VM 'default' is stopped.
Shell functions for on-demand starting and stopping of Docker (place them in, e.g., ~/.bash_profile for global availability in your interactive shells).
Note: The functions work in bash, ksh, and zsh, but in ksh you have to rename them so as not to include a '-' in the function names.
function docker-start {
typeset vm=${1:-default} sts
case $vm in
-h|--help)
echo $'usage: docker-start [<vm>]\n\nEnsures that the specified/default Docker VM is started\nand the environment is initialized.'
return 0
;;
esac
sts=$(docker-machine status "$vm") || return
[[ $sts == 'Running' ]] && echo "(Docker VM '$vm' is already running.)" || {
echo "-- Starting Docker VM '$vm' (\`docker-machine start "$vm"\`; this will take a while)...";
docker-machine start "$vm" || return
}
echo "-- Setting DOCKER_* environment variables (\`eval \"\$(docker-machine env "$vm")\"\`)..."
# Note: If the machine hasn't fully finished starting up yet from a
# previously launched-but-not-waited-for-completion `docker-machine status`,
# the following may output error messages; alas, without signaling failure
# via the exit code. Simply rerun this function to retry.
eval "$(docker-machine env "$vm")" || return
export | grep -o 'DOCKER_.*'
echo "-- Docker VM '$vm' is running."
}
function docker-stop {
typeset vm=${1:-default} sts envVarNames fndx
case $vm in
-h|--help)
echo $'usage: docker-stop [<vm>]\n\nEnsures that the specified/default Docker VM is stopped\nand the environment is cleaned up.'
return 0
;;
esac
sts=$(docker-machine status "$vm") || return
[[ $sts == 'Running' ]] && {
echo "-- Stopping Docker VM '$vm' (\`docker-machine stop "$vm"\`)...";
docker-machine stop "$vm" || return
} || echo "(Docker VM '$vm' is not running.)"
[[ -n $BASH_VERSION ]] && fndx=3 || fndx=1 # Bash prefixes defs. wit 'declare -x '
envVarNames=( $(export | awk -v fndx="$fndx" '$fndx ~ /^DOCKER_/ { sub(/=.*/,"", $fndx); print $fndx }') )
if [[ -n $envVarNames ]]; then
echo "-- Unsetting DOCKER_* environment variables ($(echo "${envVarNames[#]}" | sed 's/ /, /g'))..."
unset "${envVarNames[#]}"
else
echo "(No DOCKER_* environment variables to unset.)"
fi
echo "-- Docker VM '$vm' is stopped."
}
I have the following in my ~/.bash_profile so I don't have to run the env command every time:
docker-machine start default 2>/dev/null # Hide output if machine is already running
eval `docker-machine env default`
In the Quickstart Terminal, I restarted the "default" machine solved my problem
docker-machine restart default
eval $(docker-machine env default)
Then I was able to start composing my container with docker-compose up -d --build
I my case helped: stop + remove all docker containers (Docker version 1.13.0-rc4)
docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)
After this "docker-compose up" run without Error "ERROR: Couldn't connect to Docker daemon. You might need to start Docker for Mac."
Perhaps in some cases this Error-message is only caused by another errors, i.e. memory space problems.
I've written a Homebrew tap, here: https://github.com/nejckorasa/mac-docker-go
It includes a script to start/restart Docker daemon.
Usage: dckr [options]
Options:
-k | --kill Kill Docker daemon
-s | --start Start Docker daemon
-r | --restart Restart Docker daemon
-ka | --killall Kill all running Docker containers
-h Display help
Defaults to restart if no options are present

Resources