Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a feature to shtudown container after running init scripts #357

Closed
mjpowersjr opened this issue Dec 21, 2017 · 16 comments
Closed

Add a feature to shtudown container after running init scripts #357

mjpowersjr opened this issue Dec 21, 2017 · 16 comments
Labels
Request Request for image modification or feature

Comments

@mjpowersjr
Copy link

Sometimes I use a command like the following to initialize a mysql new database volume from a backup.

docker run --rm ... --volume /path/to/backup.sql:/docker-entrypoint-initdb.d/backup.sql mysql

It would be handy if I could (through a environment variable, alternative entrypoint, etc.) cause the docker container to stop running after the init process is complete, instead of listening for connections.

My current workaround (hack) is to build a new image based on the mysql image, that contains a shell script that waits for the init process to finish - and then kill the mysql service. This seems to work fine, but it would be nice if there was a baked in way to accomplish this behavior.

#!/bin/bash

set -e

# wait until init process is finished
until /docker-entrypoint.sh mysqld 2>&1 | \
    tee /dev/tty | \
    grep --silent --extended-regexp --max-count=1 "init process done|error";
do 
    sleep 1; 
done

# shutdown container
kill -s TERM $$
@yosifkit
Copy link
Member

Why not just make your script alphabetically after your backup file in docker-entrypoint-initdb.d and then you can do something like the following:

#!/bin/bash
set -e

# you should have access to any vars from the entrypoint since scripts are sourced
kill -s TERM "$pid"
wait "$pid"
# or
killall -s TERM mysqld
sleep 10

# prevent entrypoint from continuing
exit 1

@davidroeca
Copy link

The solution documented in this issue no longer works ($pid is no longer an accessible variable). The solution mentioned in #423 (comment) works but will have to be manually updated every time the implementation changes.

Are there plans to support this now that #471 is merged?

@tianon
Copy link
Member

tianon commented Jan 28, 2020

You should be able to invoke docker_temp_server_stop to stop the temporary server, followed by exit in order to stop the execution of any further instructions (as above).

@tianon
Copy link
Member

tianon commented Jan 28, 2020

Also, with #471 you could more easily write your own script which just does the initialization followed by exiting (and thus be much less error-prone).

@davidroeca
Copy link

A script that copies _main from docker-entrypoint.sh becomes error-prone the moment a name used within _main changes, or a new (and necessary) command is added. What I'd like to do is just run _main without the last line.

@davidroeca
Copy link

Maybe I'm confused and there's an easier way to go about this?

@mjpowersjr
Copy link
Author

I'm not sure if this works for everyone else interested - but I have since found a clean solution for my needs:

I simply append the SQL SHUTDOWN statement at the end of my bootstrap script!

https://dev.mysql.com/doc/refman/5.7/en/shutdown.html

As far as I'm concerned, this is a good solution. If there are no objections, I think it's safe to close this issue?

@davidroeca
Copy link

I try this one out today, thanks!

@davidroeca
Copy link

Works as intended for my use case; this should be the recommended solution

@marzigolbaz
Copy link

marzigolbaz commented Mar 18, 2020

This is the command I run at the end of my bootstrap script:

 mysql -u root -A -e "SHUTDOWN;"

But, the container does not shut down and I see this error in the logs:

mysql: [Warning] Using a password on the command line interface can be insecure.
2020-03-18T19:48:31.974925Z 10 [System] [MY-013172] [Server] Received SHUTDOWN from user root. Shutting down mysqld (Version: 8.0.19).

2020-03-18 19:48:31+00:00 [Note] [Entrypoint]: Stopping temporary server
mysqladmin: connect to server at 'localhost' failed
error: 'Lost connection to MySQL server at 'reading initial communication packet', system error: 104'
2020-03-18 19:48:32+00:00 [ERROR] [Entrypoint]: Unable to shut down server.

What am I doing wrong?

@yosifkit
Copy link
Member

@marzigolbaz, you probably just need an exit 0 on the next line. The error comes because the entrypoint continues its regular shutdown after your shutdown. Be warned that if you exit during initdb, then you will not get anything from _main that happens later (which right now is just expiring the root password if you set MYSQL_ONETIME_PASSWORD).

docker_process_init_files /docker-entrypoint-initdb.d/*
mysql_expire_root_user
mysql_note "Stopping temporary server"
docker_temp_server_stop
mysql_note "Temporary server stopped"
echo
mysql_note "MySQL init process done. Ready for start up."
echo

docker_temp_server_stop() {
if ! mysqladmin --defaults-extra-file=<( _mysql_passfile ) shutdown -uroot --socket="${SOCKET}"; then
mysql_error "Unable to shut down server."
fi
}

Since the init scripts are sourced:

*.sh) mysql_note "$0: running $f"; . "$f" ;;

You can just use the provided function to shut it down:

#!/bin/bash
# all your initialization steps...

docker_temp_server_stop
exit 0

@marzigolbaz
Copy link

@yosifkit thank you so much for your detailed clarification. Adding exit 0 fixed the issue. Thanks again.

@yosifkit
Copy link
Member

Closing old issue. Customization like this is supported by allowing users to source the entrypoint script (for example #423 (comment)).

@Arkemlar
Copy link

I wasted half of the day finding the proper way to achieve initialisation and exit.
I used that micro sh script injection proposed by @yosifkit and it works fine BUT

  1. This solution is hidden. I googled a lot and found only waiter solution, which is overkill for initialize-and-stop use case. After couple of hours I got idea to search in closed issues here, ffs...
  2. Using extra file injection is still not as tidy solution as it could be. More about this below.

I am really wondering why cant we move last line in _main func:

exec "$@"

to the last part of the file, like this:

if ! _is_sourced; then
	_main "$@"
	exec "$@"
fi

So then anyone can just run container with something like
docker compose run --rm --volume path_to_dump.sql:/docker-entrypoint-initdb.d/dump.sql database bash -c "source /entrypoint.sh; _main mysqld"

  • There would be no need to inject extra file anymore.
  • Also I would prefer to see nice "MySQL init process done. Ready for start up." message, which is not shown now since injected file exits before that.
  • Decoupling of init logics and mysqld call smells much better then coupling it together.

@Arkemlar
Copy link

Arkemlar commented Jul 27, 2022

For those who get in there, here is mine example of init scipt I am using, maybe it will be useful:

    cat > /tmp/exit.sh <<EOF
#!/bin/bash

mysql_note "Stopping temporary server"
docker_temp_server_stop
mysql_note "Temporary server stopped"

echo
mysql_note "MySQL init process done."
echo
exit 0
EOF

    docker compose run --rm --volume $(pwd)/dump.sql:/docker-entrypoint-initdb.d/00-dump.sql --volume /tmp/exit.sh:/docker-entrypoint-initdb.d/99-exit.sh --no-deps database

    rm /tmp/exit.sh

By the way, with my proposal above it must be as easy as

docker compose run --rm --volume $(pwd)/dump.sql:/docker-entrypoint-initdb.d/00-dump.sql --no-deps database bash -c "source /entrypoint.sh; _main mysqld"

@sneakyx
Copy link

sneakyx commented Jun 5, 2023

I just removed the line
exec "$@"
from file and injected the changed file into my docker container.
But in humble opinion this should be possible without injecting a file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Request Request for image modification or feature
Projects
None yet
Development

No branches or pull requests

8 participants