211

I have a Dockerfile to install MySQL server in a container, which I then start like this:

sudo docker run -t -i 09d18b9a12be /bin/bash

But the MySQL service does not start automatically, I have to manually run (from within the container):

service mysql start

How do I automatically start the MySQL service when I run the docker container?

2
  • 16
    you might want to copy the dockerfile here instead of linking to a file that no longer exists
    – neo112
    Commented Apr 18, 2016 at 7:36
  • The docker article on supervisord is now here: docs.docker.com/config/containers/multi-service_container I used the && tail command to get my service to work - but needed to add "--cap-add SYS_PTRACE" to the docker run command.
    – Ted Cahall
    Commented Mar 10, 2018 at 0:18

16 Answers 16

271

First, there is a problem in your Dockerfile:

RUN service mysql restart && /tmp/setup.sh

Docker images do not save running processes. Therefore, your RUN command executes only during docker build phase and stops after the build is completed. Instead, you need to specify the command when the container is started using the CMD or ENTRYPOINT commands like below:

CMD mysql start

Secondly, the docker container needs a process (last command) to keep running, otherwise the container will exit/stop. Therefore, the normal service mysql start command cannot be used directly in the Dockerfile.

Solution

There are three typical ways to keep the process running:

  • Using service command and append non-end command after that like tail -F

    CMD service mysql start && tail -F /var/log/mysql/error.log
    

This is often preferred when you have a single service running as it makes the outputted log accessible to docker.

  • Or use foreground command to do this

    CMD /usr/bin/mysqld_safe
    

This works only if there is a script like mysqld_safe.

  • Or wrap your scripts into start.sh and put this in end

    CMD /start.sh
    

This is best if the command must perform a series of steps, again, /start.sh should stay running.

Note

For the beginner using supervisord is not recommended. Honestly, it is overkill. It is much better to use single service / single command for the container.

BTW: please check https://registry.hub.docker.com for existing mysql docker images for reference

8
  • How would you restart the service once started in the docker container?
    – basickarl
    Commented Nov 24, 2015 at 17:36
  • 4
    @KarlMorrison docker exec -it <CONTAINER NAME> mysql /etc/init.d/mysqld restart
    – kaiser
    Commented Mar 14, 2016 at 0:46
  • 1
    I would not recommend tail'ing MySQL's error log to determine if the database is running or not. In most mysqld setups, the server will recover from soe errors and in the process of doing this the error log will be closed and then reopened. I am also unsure that your tail -F will work out for you in all or even some cases.
    – Brian Aker
    Commented Jun 5, 2016 at 0:55
  • I am not sure why, but the first solution option works fine for service script. When you do not use tail, it will fail, even though service is started(at least for tomcat7 service). With tail it works. For both cases you need to use switch cap_add(--cap-add SYS_PTRACE for run) with at least SYS_PTRACE
    – zhrist
    Commented Nov 10, 2017 at 19:48
  • 1
    no, see more in stackoverflow.com/questions/46800594/…
    – Larry Cai
    Commented Mar 9, 2019 at 15:10
99

In your Dockerfile, add at the last line

ENTRYPOINT service ssh restart && bash

It works for me

And this is the result:

root@ubuntu:/home/vagrant/docker/add# docker run -i -t ubuntu
 * Restarting OpenBSD Secure Shell server sshd   [ OK ]                                                                      
root@dccc354e422e:~# service ssh status
 * sshd is running
6
  • 2
    this is nice but I think you can't have a detached container this way.
    – mdob
    Commented Sep 17, 2015 at 12:28
  • 1
    This worked great for me. I was having trouble getting Nginx 1.8 to auto start. You may find adding the following helpful: RUN echo "daemon off;" >> /etc/nginx/nginx.conf RUN ln -sf /dev/stdout /var/log/nginx/access.log RUN ln -sf /dev/stderr /var/log/nginx/error.log Commented Feb 5, 2016 at 17:53
  • 1
    Are there any drawbacks to this solution?
    – srph
    Commented May 2, 2016 at 5:05
  • 3
    Starting Bash finally is a bad idea when you want to stop your services gracefully, because in this way the docker contaienr cannot be stopped by docker stop or docker restart gracefully, just it can be killed. Commented Jan 21, 2017 at 18:06
  • I was working on packer to create docker images and this seems to fix my issue with the conaitner in the packer file. "changes": [ "ENTRYPOINT service nginx start && /bin/bash" ]
    – karthik101
    Commented Sep 4, 2017 at 11:13
19

Simple! Add at the end of dockerfile:

ENTRYPOINT service mysql start && /bin/bash
1
  • This is the best answer that solves my current Docker Container issue: Docker version 18.09.7, build 2d0083d, without && /bin/bash the service will stop immediately
    – Long
    Commented Aug 6, 2019 at 16:44
13

There's another way to do it that I've always found to be more readable.

Say that you want to start rabbitmq and mongodb when you run it then your CMD would look something like this:

CMD /etc/init.d/rabbitmq-server start && \
    /etc/init.d/mongod start

Since you can have only one CMD per Dockerfile the trick is to concatenate all instructions with && and then use \ for each command to start a new line.

If you end up adding to many of those I suggest you put all your commands in a script file and start it like @larry-cai suggested:

CMD /start.sh
0
7

This not works CMD service mysql start && /bin/bash

This not works CMD service mysql start ; /bin/bash ;

-- i guess interactive mode would not support foreground.

This works !! CMD service nginx start ; while true ; do sleep 100; done;

This works !! CMD service nginx start && tail -F /var/log/nginx/access.log

beware you should using docker run -p 80:80 nginx_bash without command parameter.

5

In my case, I have a PHP web application being served by Apache2 within the docker container that connects to a MYSQL backend database. Larry Cai's solution worked with minor modifications. I created a entrypoint.sh file within which I am managing my services. I think creating an entrypoint.sh when you have more than one command to execute when your container starts up is a cleaner way to bootstrap docker.

#!/bin/sh

set -e

echo "Starting the mysql daemon"
service mysql start

echo "navigating to volume /var/www"
cd /var/www
echo "Creating soft link"
ln -s /opt/mysite mysite

a2enmod headers
service apache2 restart

a2ensite mysite.conf
a2dissite 000-default.conf
service apache2 reload

if [ -z "$1" ]
then
    exec "/usr/sbin/apache2 -D -foreground"
else
    exec "$1"
fi
2
  • Just put it alongside your Dockerfile. Then in your Dockerfile you should have an instruction that copies this file to the desired location. Then you point the ENTRYPOINT ['your location'] instruction to the script file. Remember to set the execute permissions on your script though. COPY entrypoint.sh /entrypoint.sh RUN chmod 755 /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"]. In this example, i copied my entry point to root directory in the docker container. Commented Jan 13, 2018 at 14:19
  • where is Dockerfile? Commented May 21, 2018 at 11:22
5

I add the following code to /root/.bashrc to run the code only once,

Please commit the container to the image before run this script, otherwise the 'docker_services' file will be created in the images and no service will be run.

if [ ! -e /var/run/docker_services ]; then
    echo "Starting services"
    service mysql start
    service ssh start
    service nginx start
    touch /var/run/docker_services
fi
0
5

I have the same problem when I want to automatically start ssh service. I found that append

/etc/init.d/ssh start
to
~/.bashrc
can resolve it ,but only you open it with bash will do.

4

Here is how I automatically start the MySQL service whenever the docker container runs.

On my case, I need to run not just MySQL but also PHP, Nginx and Memcached

I have the following lines in Dockerfile

RUN echo "daemon off;" >> /etc/nginx/nginx.conf
EXPOSE 80
EXPOSE 3306
CMD service mysql start && service php-fpm start && nginx -g 'daemon off;' && service memcached start && bash

Adding && bash would keep Nginx, MySQL, PHP and Memcached running within the container.

2
ENTRYPOINT name-service

Inside your Dockerfile

Example:

ENTRYPOINT mysqld_explorer

/etc/systemd/system/mysqld_explorer.service

1
docker export -o <nameOfContainer>.tar <nameOfContainer>

Might need to prune the existing container using docker prune ...

Import with required modifications:

cat <nameOfContainer>.tar | docker import -c "ENTRYPOINT service mysql start && /bin/bash" - <nameOfContainer>

Run the container for example with always restart option to make sure it will auto resume after host/daemon recycle:

docker run -d -t -i --restart always --name <nameOfContainer> <nameOfContainer> /bin/bash

Side note: In my opinion reasonable is to start only cron service leaving container as clean as possible then just modify crontab or cron.hourly, .daily etc... with corresponding checkup/monitoring scripts. Reason is You rely only on one daemon and in case of changes it is easier with ansible or puppet to redistribute cron scripts instead of track services that start at boot.

0

The following documentation from the Docker website shows how to implement an SSH service in a docker container. It should be easily adaptable for your service:

A variation on this question has also been asked here:

2
0

if you can not change docker file /docker image. here is the workaround:

docker run imageid bash -c 'service mysql start ; while true ; do sleep 100; done; '

0

I am using docker-compose.yml (version: "3.9")

What I do is add a command like below in the service of docker-compose.yml to start a service and running a non-end process.

command: /bin/sh -c "service mysql start; while sleep 1000; do :; done"
0

I've just been I trying and searching for hours before I found this hint here. I have tweaked the above:

  • CMD: '/bin/sh' '-c' '/mypath/startup.sh; bash'
  • "mypath" is on a persistent volume, where I placed startup.sh

In Portainer (2.11.1) this is placed in "Command", "Entrypoint" is still empty.

0

Assuming you want to run your main process as pid 1 but you also let say want to have cron started or some other service you may add something like

#make sure some other service starts on container start, tested in Ubuntu 20.04 based container
RUN echo "cron" >> /etc/bash.bashrc

CMD ["myproc"] #should run as 1 to receive sigterm

Using that approach chances are high, but didn't test it you could do something like, to start a service besides main process

RUN echo "service mysql start" >> /etc/bash.bashrc

CMD ["myproc"] #should run as 1 to receive sigterm

So basically you add custom entry to /etc/bash.bashrc and this is executed on system (container) start. Again Ubuntu 20.04, on other version the system bashrc may be under different name

Not the answer you're looking for? Browse other questions tagged or ask your own question.