Launch service at container startup - mysql

I've already searched for ideas for my problem but I didn't found anything that I could use.
I have a dockerfile with MySql & Apache2 and I want them start when the container start too but I can't do it in the dockerfile with CMD or ENTRYPOINT because I want to put a tail to keep my container alive and I want to be able to go in bash mode directly with run -it container bash and if I put a tail in script or CMD/ENTRYPOINT it's impossible.
I tried to launch my services with update-rc.d but it doesn't work at all...
I tried to start MySql & Apache2 with a script with ENTRYPOINT and put the tail with CMD but I think it's impossible after a lot of try with differents dockerfile and script...
Here my dockerfile:
###
# Dockerfile db MySql
###
###
# Image
###
FROM debian:jessie
###
# Volume
###
VOLUME /usr/projet/volumes/volume_db
###
# Proxy & installations
###
RUN export http_proxy="myproxy:port" \
&& export https_proxy="myproxy:port" \
&& apt-get update \
&& apt-get install -y vim \
&& echo "mysql-server mysql-server/root_password select root" | debconf-set-selections \
&& echo "mysql-server mysql-server/root_password_again select root" | debconf-set-selections \
&& apt-get install -y mysql-server \
&& apt-get install -y mysql-client \
&& service mysql start \
#&& service mysql stop \
&& echo "phpmyadmin phpmyadmin/dbconfig-install boolean true" | debconf-set-selections \
&& echo "phpmyadmin phpmyadmin/app-password-confirm password root" | debconf-set-selections \
&& echo "phpmyadmin phpmyadmin/mysql/admin-user string root" | debconf-set-selections \
&& echo "phpmyadmin phpmyadmin/mysql/admin-pass password root" | debconf-set-selections \
&& echo "phpmyadmin phpmyadmin/mysql/app-pass password root" | debconf-set-selections \
&& echo "phpmyadmin phpmyadmin/reconfigure-webserver multiselect apache2" | debconf-set-selections \
&& apt-get install -y phpmyadmin\
&& apt-get autoremove --purge
###
# Script startup
###
#COPY script_start /etc/init.d/
RUN update-rc.d apache2 defaults \
&& update-rc.d mysql defaults
###
# Variable env
###
ENV MYSQL_ROOT_PASSWORD=root
###
###
# Port exposition & cmd
###
EXPOSE 3306 80
CMD tail -F -n0 /etc/hosts
And there my script:
#!/bin/bash
### BEGIN INIT INFO
# Provides: script_start
# Required-Start: $local_fs $syslog
# Required-Stop: $local_fs $syslog
# Default-Start: 2
# Default-Stop:
# Short-Description: Boot services mysql apache2
# Description: Boot services
### END INIT INFO
service mysql start \
&& service apache2 start

I've already searched for ideas for my problem but I didn't found anything that I could use.
In almost all cases, you should only run a single process in a single container. Decoupling applications into multiple containers makes it much easier to scale horizontally and reuse containers. If that service depends on another service, make use of container linking.
https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#/run-only-one-process-per-container

A few pointers that might help you in your path -
Using MySQL and Apache2 in the same container is against
container best practices. Consider dividing the two processes into
separate containers, and connecting them with docker-compose.
Using RUN to start a service will do you no good, since it will run at build time but won't persist when you actually run the container. You should ENTRYPOINT for that, making sure that the script runs on container startup.
If you want to allow yourself connection into the container, you should use docker exec (which executes a command over a running container) over docker run (which tries to launch a new container from the same image)

Thanks for your replies, I had in mind to be able to go in bash mode directly with run...
So you're saying that normally I have to use docker exec to be able to modify my container in contrary to run that should be use to only deploy container ?
I'm going to do it with your advices, thanks ! :D

Related

Docker mysql via MariaDB with Supervisor

Somewhat a year ago, I came up with the idea of extending my Docker knowledge to begin with creating a sort of multi-platform server image for development purposes, since then, I figured out how to get Nginx and PHP-fpm running in a stable environment. This all is based on a Debian image. Now since a couple one week ago, I wanted to add MySQL functionality to the image. At first, I tried the normal MySQL(-server) image and after trying to fix errors about why it couldn't run in my image, I switched to using MariaDB - I even had changed the Docker image of MySQL to fit to my needs (Replaced CMD ["mysqld"] for a supervisord.conf executable since my project is using several services of course). Now, I'm trying to figure it out for days but it is still not running. At the moment, I've chosen to use https://hub.docker.com/_/mariadb (second: 10.4.12-bionic, 10.4-bionic, 10-bionic, bionic, 10.4.12, 10.4, 10, latest) with my image.
I've just created a mariadb copy on time of writing, but replaced directly executing mysqld (working). When this topic is created, it didn't worked with a supervisord and that works as supposed to be now.
I have a docker-compose.yml where it will be started, here the code:
version: "3"
services:
db:
container_name: mariadb
image: mariadb
build: .
restart: on-failure
ports:
- 3306:3306
environment:
- MYSQL_ROOT_PASSWORD=test123
networks:
- local-network
networks:
local-network:
driver: bridge
Then, I will execute docker-compose up -d or with the (--build) parameter.
The Dockerfile behind that is:
FROM debian:buster-slim
ENV DEBIAN_FRONTEND noninteractive
ENV GOSU_VERSION 1.12
ENV MARIADB_VERSION 10.4
ENV GPG_KEYS \
199369E5404BD5FC7D2FE43BCBCB082A1BB943DB \
177F4010FE56CA3336300305F1656F24C74CD1D8
# add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added
RUN groupadd -r mysql && useradd -r -g mysql mysql
RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -q -y \
wget \
ca-certificates \
gnupg \
gnupg1 \
gnupg2 \
dirmngr \
pwgen \
tzdata \
xz-utils
# Get Gosu for easy stepdown from root (to avoid sudo/su miscommunications)
# https://github.com/tianon/gosu/releases
RUN set -eux; \
savedAptMark="$(apt-mark showmanual)"; \
dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \
wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \
wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \
export GNUPGHOME="$(mktemp -d)"; \
gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \
gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \
gpgconf --kill all; \
rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \
apt-mark auto '.*' > /dev/null; \
[ -z "$savedAptMark" ] || apt-mark manual $savedAptMark > /dev/null; \
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
chmod +x /usr/local/bin/gosu; \
gosu --version; \
gosu nobody true
RUN mkdir /docker-entrypoint-initdb.d
RUN set -ex; \
export GNUPGHOME="$(mktemp -d)"; \
for key in $GPG_KEYS; do \
gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \
done; \
gpg --batch --export $GPG_KEYS > /etc/apt/trusted.gpg.d/mariadb.gpg; \
command -v gpgconf > /dev/null && gpgconf --kill all || :; \
rm -r "$GNUPGHOME"; \
apt-key list
# Add MariaDB repo
RUN set -e;\
echo "deb http://downloads.mariadb.com/MariaDB/mariadb-$MARIADB_VERSION/repo/debian buster main" > /etc/apt/sources.list.d/mariadb.list; \
{ \
echo 'Package: *'; \
echo 'Pin: release o=MariaDB'; \
echo 'Pin-Priority: 999'; \
} > /etc/apt/preferences.d/mariadb
# Install MariaDB and set custom requirements
RUN set -ex; \
{ \
echo "mariadb-server" mysql-server/root_password password 'unused'; \
echo "mariadb-server" mysql-server/root_password_again password 'unused'; \
} | debconf-set-selections; \
apt-get update && apt-get install --no-install-recommends --no-install-suggests -y -q \
mariadb-server \
mariadb-backup \
socat; \
# comment out any "user" entires in the MySQL config ("docker-entrypoint.sh" or "--user" will handle user switching)
sed -ri 's/^user\s/#&/' /etc/mysql/my.cnf /etc/mysql/conf.d/*; \
# making sure that the correct permissions are set
mkdir -p /var/lib/mysql /var/run/mysqld; \
chown -R mysql:mysql /var/lib/mysql /var/run/mysqld; \
# comment out a few problematic configuration values
find /etc/mysql/ -name '*.cnf' -print0 \
| xargs -0 grep -lZE '^(bind-address|log)' \
| xargs -rt -0 sed -Ei 's/^(bind-address|log)/#&/'; \
# don't reverse lookup hostnames, they are usually another container
echo '[mysqld]\nskip-host-cache\nskip-name-resolve' > /etc/mysql/conf.d/docker.cnf
# Setup the Supervisor
RUN apt-get update && apt-get install supervisor -y \
&& mkdir -p /var/log/supervisor
COPY /supervisord.conf /etc/supervisor/conf.d/supervisord.conf
RUN chmod +x /etc/supervisor/conf.d/supervisord.conf
VOLUME /var/lib/mysql
COPY /docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh \
&& ln -s /usr/local/bin/docker-entrypoint.sh /
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 3306 33060
# call and execute the supervisor after build
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
After a couple days of working on fixing the image I thought that the supervisord was the issue, it couldn't run because of that or something. Well, here is the supervisord:
[supervisord]
logfile=/var/log/supervisord.log
nodaemon=true
user=root
[program:mysql]
command=/usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql
process_name=mysqld
priority=1
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stdout_events_enabled=true
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
stderr_events_enabled=true
autorestart=true
user=mysql
What happens next when the image has been build is that mysql will be executed by the supervisor. But, the problem is that I wanted to use the entrypoint from https://github.com/mariadb-corporation/mariadb-server-docker/tree/master/10.4 - I'm not very well known in Bash, so it will take some time to practice things there. Anyway, the docker-entrypoint has not been executed the first time, the database will not be initialized. What I can do, is creating an own shell script to initialize it. Tested that and it worked, but why can't I just use the default entrypoint as the first choise?
Is it going wrong at some point between Supervisord commands - docker-entrypoint with mysql connection points or something?
I really hope that someone can help me out.
Edit [04/26/2020]: Described the latest situation from now on, database not initializing, no message, notes or warnings from the entrypoint script.
Regards,
Colin
The MySQL service should run as root user, but later that's the mysql user whiche tries to access to the "socket". So, the socket directory should be accessible by mysql user but Superviser runs the mysql service as root user.
I fixed this issue by creating and gave right permission to the MySQL socket directory in my Dockerfile:
ARG MARIADB_MYSQL_SOCKET_DIRECTORY='/var/run/mysqld'
RUN mkdir -p $MARIADB_MYSQL_SOCKET_DIRECTORY && \
chown root:mysql $MARIADB_MYSQL_SOCKET_DIRECTORY && \
chmod 774 $MARIADB_MYSQL_SOCKET_DIRECTORY
then configured the Supervisor like this:
[program:mariadb]
command=/usr/sbin/mysqld
autorestart=true
user=root

Connecting to mysql in docker fails

I'm setting up a Dockerfile where I can run my automated tests, and I'm having troubles with connecting to mysql database.
The Dockerfile depends on a prevoously built image and looks like this:
# Stage 0, assign argument as multistage image alias
ARG PHP_IMAGE
FROM ${PHP_IMAGE} as image
# Stage 1, start tests
FROM php:7.2-fpm
RUN curl -sS https://getcomposer.org/installer | php \
&& chmod +x composer.phar && mv composer.phar /usr/local/bin/composer
RUN apt-get update && apt-get install -y gnupg
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - && \
apt-get install -yq nodejs build-essential \
git unzip \
libfreetype6-dev \
libjpeg62-turbo-dev \
libmcrypt-dev \
libpng-dev \
subversion \
&& curl -sL https://deb.nodesource.com/setup_8.x | bash - \
&& pecl install mcrypt-1.0.1 \
&& docker-php-ext-enable mcrypt \
&& docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
&& docker-php-ext-install -j$(nproc) gd \
&& docker-php-ext-install -j$(nproc) mysqli
RUN apt-get install -y mysql-server
RUN /etc/init.d/mysql start
RUN mysqladmin -u root -p status
RUN yes | pecl install xdebug \
&& echo "zend_extension=$(find /usr/local/lib/php/extensions/ -name xdebug.so)" > /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.remote_enable=on" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.remote_autostart=off" >> /usr/local/etc/php/conf.d/xdebug.ini
RUN npm install -g npm
COPY --from=image /var/www/html/ /var/www/html/
WORKDIR /var/www/html/
COPY scripts/develop.sh develop.sh
COPY scripts/docker-test.sh docker-test.sh
RUN ["/bin/bash", "-c", "bash develop.sh && bash docker-test.sh"]
I've added RUN mysqladmin -u root -p status to try to debug why connecting to mysql failed and I got
Enter password: mysqladmin: connect to server at 'localhost' failed
error: 'Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2 "No such file or directory")'
Check that mysqld is running and that the socket: '/var/run/mysqld/mysqld.sock' exists!
To run this I am running
docker build -t $TEST_DOCKER_NAME --build-arg PHP_IMAGE=$DOCKER_IMAGE_NAME_PHP -f Dockerfile.test .
The TEST_DOCKER_NAME and DOCKER_IMAGE_NAME_PHP are stored in an env file and read from there. The PHP image was built successfuly and I'm using it to copy the files from there to here so that I can run PHPUnit.
When I remove that RUN line my build fails when I'm trying to run a script that creates the database
mysqladmin: connect to server at 'localhost' failed
error: 'Can't connect to MySQL server on 'localhost' (99 "Cannot assign requested address")'
Check that mysqld is running on localhost and that the port is 3306.
You can check this by doing 'telnet localhost 3306'
What do I need to do in my Dockerfile to make it work?
Answer to your specific problem
This is a common mistake people make when using docker. When you use the RUN directive in docker you are running a command through to completion, capturing the filesystem changes and then exiting.
So when you have the lines
RUN /etc/init.d/mysql start
RUN mysqladmin -u root -p status
The first one is starting mysql. But then the changes are captured, the container is exited and then a new one is started to run the mysqladmin command. Therefore the mysql process is no longer running.
To avoid this you could combine them into a single line like
RUN /etc/init.d/mysql start && mysqladmin -u root -p status
However you will need to do this every time you want to use mysql. Such as in your develop.sh.
Wider answer
It is not recommended to run multiple processes within your container and it is also not recommended to use init.d or other system startup frameworks within your container.
You seem to be treating your container like a virtual machine and are having issues because containers are not VMs.
I recommend you explore running mysql in a separate container and then using a tool like docker-compose to start and and stop your containers.

Docker : Start mysql and apache from entrypoint or CMD

Building a docker image for development, I want to start automatically mysql and apache when I run the image.
If I log into the container and run "service apache2 start" and "service mysql start" it works. But if I put in entrypoint or CMD it fails.
I was able to start apache by putting ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]but I was not able to start mysql programmatically.
I tried many many things. Most of the time if fails silently in that the container is not running, other time I got : docker: Error response from daemon: oci runtime error: container_linux.go:247: starting container process caused "exec: \"/etc/init.d/mysql start\": stat /etc/init.d/mysql start: no such file or directory"
This is what I have so far :
FROM debian:wheezy
RUN apt-get update && \
apt-get install -y libmcrypt-dev \
subversion ssl-cert nano wget unzip && \
echo "deb http://packages.dotdeb.org wheezy-php56 all" >> /etc/apt/sources.list.d/dotdeb.list && \
echo "deb-src http://packages.dotdeb.org wheezy-php56 all" >> /etc/apt/sources.list.d/dotdeb.list && \
wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add - && \
echo mysql-server-5.5 mysql-server/root_password password yourpass | debconf-set-selections && \
echo mysql-server-5.5 mysql-server/root_password_again password yourpass | debconf-set-selections && \
apt-get update && \
apt-get install -y \
apache2 apache2-doc apache2-mpm-prefork apache2-utils apache2.2-bin apache2.2-common libapache2-mod-php5 \
openssl php-pear php5 php5-cli php5-common php5-curl php5-gd php5-mcrypt php5-mysql php5-memcache php5-readline \
subversion ssl-cert nano wget unzip \
mysql-server-5.5 mysql-client mysql-client-5.5 mysql-common && \
/etc/init.d/mysql start && \
mysql -u root -pyourpass -e "create database mydb;" && \
rm -rf /var/lib/apt/lists/* && \
rm /etc/apache2/sites-enabled/000-default && \
mkdir -p /var/www/html && \
chown www-data:www-data -R /var/www/html/
COPY conf/etc/ /etc/
COPY mydump.sql /var/www/html/mydump.sql
RUN /etc/init.d/mysql start && \
mysql -u root -pyourpass -h localhost mydb < /var/www/html/mydump.sql && \
rm /var/www/html/mydump.sql
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2", "/var/lib/mysql"]
EXPOSE 80 443 3306
Your way of starting either Apache or Mysql looks wrong to me
If I look at the most popular Apache on hub.docker.com the Dockerfile shows how to start Apache. The last line of the Dockerfile is
CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
For the reference Mysql, the last line of the Dockerfile is
CMD ["mysqld"]
So you can look at supervisor or any other similar tool like S6 or daemontools in order to start both Apache and Mysql in the Docker way.
A model often seen is to include a script (bash, shell, etc) in your Docker image, and then use that script as the entrypoint for your application. See that described in https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#entrypoint
So, put the things you're starting in a docker-entrypoint.sh script, COPY the script in, and reference it from the ENTRYPOINT.

Create database and schema for mySQL in docker

I am creating a docker image with tomcat and mySql. I have a .war file that I can push to the Tomcat and the docker image is working as expected.
But the application also need a database on mySQL in the same docker image (as I do not want to run multiple images as this is fairly small and is for a demonstration only).
I am using a tomcat image as base and install mySql on it. The base OS is Ubuntu.
Here is my dockerfile:
#Get the base
FROM davidcaste/debian-tomcat:tomcat8
#Add mySql
RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
RUN apt-get -y update
RUN apt-get -y install wget zip gcc
RUN { \
echo mysql-community-server mysql-community-server/data-dir select ''; \
echo mysql-community-server mysql-community-server/root-pass password ''; \
echo mysql-community-server mysql-community-server/re-root-pass password ''; \
echo mysql-community-server mysql-community-server/remove-test-db select false; \
} | debconf-set-selections \
&& apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y mysql-server
RUN /etc/init.d/mysql start
RUN wget http://github.com/xxxx/xxxx/blob/master/xxxx/src/main/resources/sql/create-schema.sql
RUN cp create-schema.sql /usr/
RUN wget http://github.com/xxxx/xxxx/blob/master/xxxx/src/main/resources/sql/metadata.sql
RUN cp metadata.sql /usr/
#RUN mysql -- this gives error
#RUN create database test; -- this gives error
#Get the Web Application from Nexus
RUN wget "http://mynexus:8081/nexus/service/local/artifact/maven/redirect?g=org.my&a=my-app&r=repo&e=war&v=LATEST" --content-disposition -O app.war
#Copy the war file
RUN cp app.war /opt/tomcat/webapps/
EXPOSE 8080
CMD ["catalina.sh", "run"]
Without the mySql related items (create database etc) the docker build works and it runs well. But I am not able to understand how to create the database using my schema and metadata sql files.
You can run the SQL commands after container start up but not during you build it. One option would be to override the entrypoint and do it there. Another option would be to have a docker-compose first bringing up the plain mysql container and after that create db and schema with an additional container that runs the bash script.
See i.e. here to get an idea about it. Another option is to pass the SQL related stuff as ENV setting as depicted in one of the answers in above link.

Why SSH connection to docker container is not working?

So i have this Dockerfile:
FROM debian:squeeze
MAINTAINER Name < email : >
# Update the repository sources list
RUN apt-get update
# Install apache, PHP, and supplimentary programs. curl and lynx-cur are for debugging the container.
RUN DEBIAN_FRONTEND=noninteractive apt-get -y install apache2 build-essential php5 mysql-server openssh-server libapache2-mod-php5 php5-mysql php5-gd php-pear php-apc php5-curl curl lynx-cur
# Enable apache mods.
RUN a2enmod php5
RUN a2enmod rewrite
# Manually set up the apache environment variables
ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /var/log/apache2
ENV APACHE_LOCK_DIR /var/lock/apache2
ENV APACHE_PID_FILE /var/run/apache2.pid
EXPOSE 80
# Copy site into place.
ADD www /var/www/site
# Update the default apache site with the config we created.
ADD apache-config.conf /etc/apache2/sites-enabled/000-default.conf
# start mysqld and apache
EXPOSE 3306
RUN mkdir /var/run/sshd
RUN echo 'root:123' | chpasswd
RUN sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config
EXPOSE 22
CMD bash -c ' (mysqld &); /usr/sbin/apache2ctl -D FOREGROUND;/usr/sbin/sshd -D'
it builds up, no problem,MySQL and Apache start and work fine but the ssh won't work and i don't know why. openssh-server is installed.
i tried starting it up like this:
#startup.sh file
#/bin/bash
sshd
+
ADD ./startup.sh /opt/startup.sh
ENTRYPOINT ["/opt/startup.sh"]
and many other,i'm stuck.
What am i doing wrong?
you are starting apache in the foreground, hence the apachectl process will never give back the hand to the shell that started it and thus the /usr/sbin/sshd -D will never be called (unless you kill apache).
The following instruction will start both mysql and apache in the background and then sshd in the foreground:
CMD bash -c ' (mysqld &); /usr/sbin/apache2ctl start;/usr/sbin/sshd -D'
While such a CMD statement is ok for tests I would advise using a different approach for running multiple processes in a single docker container:
supervisor
phusion/baseimage
Replace below lines of code in the docker file,
RUN mkdir /var/run/sshd
RUN echo 'root:123' | chpasswd
RUN sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config
Using these codes
RUN apt-get install -y openssh-server
RUN echo 'root:password' |chpasswd
RUN mkdir -p /var/run/sshd
this works for me.
Note: Use ssh only for debugging purpose, it is not a good practice at all.