multiple command in postStart hook of a container - kubernetes

in a kubernetes Deployment yaml file is there a simple way to run multiple commands in the postStart hook of a container?
I'm trying to do something like this:
lifecycle:
postStart:
exec:
command: ["/bin/cp", "/webapps/myapp.war", "/apps/"]
command: ["/bin/mkdir", "-p", "/conf/myapp"]
command: ["touch", "/conf/myapp/ready.txt"]
But it doesn't work.
(looks like only the last command is executed)
I know I could embed a script in the container image and simply call it there... But I would like to be able to customize those commands in the yaml file without touching the container image.
thanks

Only one command allowed, but you can use sh -c like this
lifecycle:
postStart:
exec:
command:
- "sh"
- "-c"
- >
if [ -s /var/www/mybb/inc/config.php ]; then
rm -rf /var/www/mybb/install;
fi;
if [ ! -f /var/www/mybb/index.php ]; then
cp -rp /originroot/var/www/mybb/. /var/www/mybb/;
fi

You also can create a bash or make script to group all those commands.

Related

Kubernetes Container Command to start an bash that does not stop

I would like to start a container with bash only. In other words, a bash that does not stop, i guess an interactive bash or shell .
So far when i put sommething like ["bash"] or ["bin/bash"] or simply bash, the container run and stop. Is there a way to start a bash that run continuously ?
EDIT1
So far the only way that works for me is to write:
command:
- tail
- -f
- /dev/null
Edit2
My use case here is that i want to build a docker image simply to develop in it. So that image has all the tool i need to work.
Hence I wonder how such container should be start. I don't want to run any of the dev tool at start. I simply want the container to be available ready for someome to run the interactive shell at any time.
you can try the sleep command in while loop.
command: ["/bin/sh"]
args: ["-c", "while true; do sleep 10;done"]
You create a container with
command: ["cat"]
tty: true
stdin: true
That way it would consume less cpu and memory than bash

docker-compose entrypoint with mutiple commands

How to run docker-compose entrypoint configuration option with multiple bash commands
commands:
yarn install
yarn build
sleep infinity
In docker-compose.yml, for service gvhservice
gvhservice:
entrypoint:
- "/bin/sh"
- -ecx
- |
yarn install
yarn build
sleep infinity
OR
optionally, add all these commands to a file say - entrypoint.sh
and in docker-compose.yml,
gvhservice:
entrypoint: entrypoint.sh
OR,
Using the option of entrypoint.sh and command configuration option in docker-compose.yml (suitable for a variable number of commands to be passed during runtime)
entrypoint.sh
#!/bin/sh
set -ex
exec "$#"
docker-compose.yml
command:
- /bin/sh
- -ecx
- |
yarn install
yarn build
sleep infinity

Populating user home directory in JupyterHub

I'm trying to populate the home directory of the user on JupyterHub. I've followed the Zero to JupyterHub with Kubernetes guide and have a working cluster. I have the folders I want to copy in the container but I'm not sure how to copy them so that they're available to the user.
lifecycleHooks:
postStart:
exec:
command: ["cp", "-a", "mydir", "/home/jovyan/mydir"]
When I get a shell in my container the folders are there in /home/jovyan but when the exec hook runs these folders can't be found. I know I'm missing something simple here.
I found the best way is to copy the folders you need over to a directory other than /home/jovyan such as /tmp and then copy them from there.
I now have something like this in my config.yaml which allows running of multiple commands separated by a semi-colon
lifecycleHooks:
postStart:
exec:
command:
- "sh"
- "-c"
- >
cp -r /tmp/folder_a /home/jovyan;
cp -r /tmp/folder_b /home/jovyan

Send arguments to a Job

I have a docker Image that basically runs a one time script. That scripts takes 3 arguments. My docker file is
FROM <some image>
ARG URL
ARG USER
ARG PASSWORD
RUN apt update && apt install curl -y
COPY register.sh .
RUN chmod u+x register.sh
CMD ["sh", "-c", "./register.sh $URL $USER $PASSWORD"]
When I spin up the contianer using docker run -e URL=someUrl -e USER=someUser -e PASSWORD=somePassword -itd <IMAGE_ID> it works perfectly fine.
Now I want to deploy this as a job.
My basic Job looks like:
apiVersion: batch/v1
kind: Job
metadata:
name: register
spec:
template:
spec:
containers:
- name: register
image: registeration:1.0
args: ["someUrl", "someUser", "somePassword"]
restartPolicy: Never
backoffLimit: 4
But this the pod errors out on
Error: failed to start container "register": Error response from daemon: oci runtime error: container_linux.go:247: starting container process caused "exec: \"someUrl\": executable file not found in $PATH"
Looks like it is taking my args as commands and trying to execute them. Is that correct ? What can I do to fix this ?
In the Dockerfile as you've written it, two things happen:
The URL, username, and password are fixed in the image. Anyone who can get the image can run docker history and see them in plain text.
The container startup doesn't take any arguments; it just runs the single command with its fixed set of arguments.
Especially since you're planning to pass these arguments in at execution time, I wouldn't bother trying to include them in the image. I'd reduce the Dockerfile to:
FROM ubuntu:18.04
RUN apt update \
&& DEBIAN_FRONTEND=noninteractive \
apt install --assume-yes --no-install-recommends \
curl
COPY register.sh /usr/bin
RUN chmod u+x /usr/bin/register.sh
ENTRYPOINT ["register.sh"]
When you launch it, the Kubernetes args: get passed as command-line parameters to the entrypoint. (It is the same thing as the Docker Compose command: and the free-form command at the end of a plain docker run command.) Making the script be the container entrypoint will make your Kubernetes YAML work the way you expect.
In general I prefer using CMD to ENTRYPOINT. (Among other things, it makes it easier to docker run --rm -it ... /bin/sh to debug your image build.) If you do that, then the Kubernetes args: need to include the name of the script it's running:
args: ["./register.sh", "someUrl", "someUser", "somePassword"]
Use:
args: ["sh", "-c", "./register.sh someUrl someUser somePassword"]

Executing wait-for-it.sh in python Docker container

I have a Python docker container that needs to wait until another container (postgres server) finishes setup. I tried the standard wait-for-it.sh but several commands weren't included. I tried a basic sleep (again in an sh file) but now it's reporting exec: 300: not found when trying to finally execute the command I'm waiting on.
How do I get around this (preferably without changing the image, or having to extend an image.)
I know I could also just run a Python script, but ideally I'd like to use wait-for-it.sh to wait for the server to turn up rather than just sleep.
Dockerfile (for stuffer):
FROM python:2.7.13
ADD ./stuff/bin /usr/local/bin/
ADD ./stuff /usr/local/stuff
WORKDIR /usr/local/bin
COPY requirements.txt /opt/updater/requirements.txt
COPY internal_requirements.txt /opt/stuff/internal_requirements.txt
RUN pip install -r /opt/stuff/requirements.txt
RUN pip install -r /opt/stuff/other_requirements.txt
docker-compose.yml:
version: '3'
services:
local_db:
build: ./local_db
ports:
- "localhost:5432:5432"
stuffer:
build: ./
depends_on:
- local_db
command: ["./wait-for-postgres.sh", "-t", "300", "localhost:5432", "--", "python", "./stuffing.py", "--file", "./afile"]
Script I want to use (but can't because no psql or exec):
#!/bin/bash
# wait-for-postgres.sh
set -e
host="$1"
shift
cmd="$#"
until psql -h "$host" -U "postgres" -c '\l'; do >&2 echo "Postgres is unavailable - sleeping"
sleep 1
done
>&2 echo "Postgres is up - executing command"
exec $cmd
Sergey's comment. I had wrong argument order. This issue had nothing to do with docker and everything to do with my inability to read.
I made an example so you can see it working:
https://github.com/nitzap/wait-for-postgres
On the other hand also you can have errors inside the execution of the script to validate that the service is working. You should not refer as localhost .... because that is within the contexts of containers, if you want to point to another container has to be through the name of the service.