I am new to Docker and trying to adapt a setup from Symfony Docker to another app that uses a different Dockerfile.
I use a docker-entrypoint to run database migrations which, of course, require the database to be up.
My Dockerfile calls docker-entrypoint but somehow in enters into a loop, running it - the entrypoint code - repeatedly.
This is the Dockerfile at /docker/php:
FROM php:8.1-apache AS symfony_php
RUN a2enmod rewrite
RUN apt-get update \
&& apt-get install -y libpq-dev libzip-dev git libxml2-dev nano wget --no-install-recommends \
&& docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql \
&& docker-php-ext-install pdo pdo_pgsql pgsql zip \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN wget https://getcomposer.org/download/2.3.5/composer.phar \
&& mv composer.phar /usr/bin/composer && chmod +x /usr/bin/composer
COPY docker/php/apache.conf /etc/apache2/sites-enabled/000-default.conf
COPY docker/php/php.ini /usr/local/etc/php/conf.d/app.ini
COPY docker/php/docker-entrypoint.sh /usr/local/bin/docker-entrypoint
RUN chmod +x /usr/local/bin/docker-entrypoint
ENV SYMFONY_PHPUNIT_VERSION=9
COPY . /var/www
WORKDIR /var/www
RUN mkdir -p var/cache var/log
RUN chmod -R 777 ./var/cache && chmod -R 777 ./var/log
RUN composer install --prefer-dist --no-progress --no-interaction
ENTRYPOINT ["docker-entrypoint"]
The entrypoint also at /docker/php
set -e
if grep -q DATABASE_URL= .env; then
echo "Waiting for database to be ready..."
ATTEMPTS_LEFT_TO_REACH_DATABASE=60
until [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ] || DATABASE_ERROR=$(php bin/console dbal:run-sql -q "SELECT 1" 2>&1); do
if [ $? -eq 255 ]; then
# If the Doctrine command exits with 255, an unrecoverable error occurred
ATTEMPTS_LEFT_TO_REACH_DATABASE=0
break
fi
sleep 1
ATTEMPTS_LEFT_TO_REACH_DATABASE=$((ATTEMPTS_LEFT_TO_REACH_DATABASE - 1))
echo "Still waiting for database to be ready... Or maybe the database is not reachable. $ATTEMPTS_LEFT_TO_REACH_DATABASE attempts left."
done
if [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ]; then
echo "The database is not up or not reachable:"
echo "$DATABASE_ERROR"
exit 1
else
echo "The database is now ready and reachable"
fi
if ls -A migrations/*.php >/dev/null 2>&1; then
php bin/console doctrine:migrations:migrate --no-interaction
fi
fi
exec docker-php-entrypoint "$#"
The resulting loop:
Adding this to my entrypoint solved the issue:
/usr/sbin/apache2ctl -D FOREGROUND
It seems that the entrypoint interrupts the server process and placing the above snippet forces the server back up.
EDIT:
Even better:
Change Dockerfile as below:
ENTRYPOINT ["docker-entrypoint"]
CMD ["apachectl", "-D", "FOREGROUND"]
And on entrypoint.sh keep as per the original post:
exec docker-php-entrypoint "$#"
Related
I want to run supervisor to have multiple processes in the same container, as I can't use docker-compose in our current hosting environment. Things seems to work when I look in the docker logs, but I can't see the supervisor service inside the linux system when I've attached my terminal to the container.
When I check the logs for the container I get:
Starting supervisord.... (entrypoint.sh)
2021-12-22 08:38:50,871 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message.
2021-12-22 08:38:50,877 INFO RPC interface 'supervisor' initialized
2021-12-22 08:38:50,877 CRIT Server 'inet_http_server' running without any HTTP authentication checking
2021-12-22 08:38:50,878 INFO supervisord started with pid 1
However, if I attach my shell to the container and run "service supervisor status" I get:
supervisord is not running.
And I don't get why the system don't seem to recognise that the service is running. Can anyone help me figuring this out, because if I can't access the service from the terminal I can't really manage it in any way.
This is my Dockerfile
FROM python:3.8
ENV PYTHONUNBUFFERED 1
RUN apt-get update
RUN apt-get install -y pgbouncer
RUN apt-get update && apt-get install -y supervisor
# install nginx
ENV NGINX_VERSION 1.15.12-1~stretch
ENV NJS_VERSION 1.15.12.0.3.1-1~stretch
RUN set -x \
&& \
NGINX_GPGKEY=573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62; \
found=''; \
for server in \
hkp://keyserver.ubuntu.com:80 \
hkp://p80.pool.sks-keyservers.net:80 \
pgp.mit.edu \
; do \
echo "Fetching GPG key $NGINX_GPGKEY from $server"; \
apt-key adv --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$NGINX_GPGKEY" && found=yes && break; \
done; \
test -z "$found" && echo >&2 "error: failed to fetch GPG key $NGINX_GPGKEY" && exit 1; \
apt-get remove --purge --auto-remove -y gnupg1 && rm -rf /var/lib/apt/lists/* \
&& dpkgArch="$(dpkg --print-architecture)" \
&& nginxPackages=" \
nginx=${NGINX_VERSION} \
nginx-module-xslt=${NGINX_VERSION} \
nginx-module-geoip=${NGINX_VERSION} \
nginx-module-image-filter=${NGINX_VERSION} \
nginx-module-njs=${NJS_VERSION} \
" \
&& echo "deb https://nginx.org/packages/mainline/debian/ stretch nginx" >> /etc/apt/sources.list.d/nginx.list \
&& apt-get update \
&& apt-get install --no-install-recommends --no-install-suggests -y \
$nginxPackages \
gettext-base \
&& rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx.list
# install app
RUN mkdir /var/app && chown www-data:www-data /var/app
WORKDIR /var/app
COPY ./requirements.txt /var/app/
RUN pip install -r requirements.txt
COPY . /var/app/
COPY ./conf/nginx/staging.conf /etc/nginx/conf.d/default.conf
COPY ./conf/pgbouncer/pgbouncer.ini /etc/pgbouncer/pgbouncer.ini
COPY ./supervisord.conf /etc/supervisor/conf.d/supervisord.conf
VOLUME /var/logs
# Expose ports (Added from previous dockerfile)
EXPOSE 80 2222
# Added for setting right permissions to entrypoint script
RUN ["chmod", "+x", "./entrypoint.sh"]
RUN ["chmod", "+x", "/var/app/bin/staging/django-q.sh"]
ENTRYPOINT ["./entrypoint.sh"]
This is my entrypoint.sh - I first set-up some settings for pg-bouncer, and then start supervisor
#!/bin/bash
set -e
# SET UP PG BOUNCER
PG_CONFIG_DIR=/etc/pgbouncer
invoke_main(){
check_variables
create_config
}
check_variables(){
...
}
error(){
...
}
create_databases_config(){
...
}
create_config(){
...
}
[databases]
$(create_databases_config)
[pgbouncer]
...
invoke_main
# INVOKE SUPERVISORD
echo " Starting supervisord.... (entrypoint.sh)"
exec supervisord -n -c /etc/supervisor/conf.d/supervisord.conf
#exec supervisord -n -c /etc/supervisor/conf.d/supervisord.conf
This is my supervisord.conf
[supervisord]
logfile=/var/logs/supervisord.log ; main log file; default $CWD/supervisord.log
logfile_maxbytes=50MB ; max main logfile bytes b4 rotation; default 50MB
logfile_backups=10 ; # of main logfile backups; 0 means none, default 10
loglevel=info ; log level; default info; others: debug,warn,trace
pidfile=/var/logs/supervisord.pid
nodaemon=true ; Run interactivelly instead of deamonizing
# user=www-data
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[inet_http_server]
port = 127.0.0.1:9001
[supervisorctl]
serverurl = http://127.0.0.1:9001
You are starting supervisord manually. service command won't report its status correctly.
I have created a docker image, and I have problem to start automatically or even start mysql.
The problem is echo "$#" in entrypoint.sh, I expect to run mysqld_safe, but It doesn't. If a change the line echo "$#" to mysqld_safe --user=mysql it starts successfully. I don't know what is the correct form for run automatically as mysql_safe --user=mysql. What should to write in dockerfile CMD[] to run entrypoint.sh correctly.
My code is next:
-----------
Dockerfile:
-----------
## OS part
## -------
FROM debian:buster-slim
# 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 -y --no-install-recommends gnupg dirmngr && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y --no-install-recommends gnupg dirmngr
# Add packages for testing
RUN apt-get install iproute2 iputils-ping net-tools vim traceroute less -y
## MYSQL part
##-----------
ENV PATH /usr/local/mysql/bin:$PATH
#ENV MYSQLDATA /usr/local/mysql/data
VOLUME /usr/local/mysql/
ADD mysql-standard-4.0.27-pc-linux-gnu-i686 /usr/local/mysql
ADD my.cnf /etc/
#RUN chown -R mysql /usr/local/mysql/ && chgrp -R mysql /usr/local/mysql/
COPY entrypoint.sh /usr/local/bin/
#RUN chmod +x /entrypoint.sh
EXPOSE 3306
ENTRYPOINT ["entrypoint.sh"]
CMD ["mysqld_safe"]
---------------
Entrypoint.sh:
---------------
#!/bin/bash
set -e
# global variable
setup_env() {
MYSQLDATA="/usr/local/mysql/data"
MYSQLBASE="/usr/local/mysql"
MYSQL_ROOT_PASSWORD="password"
}
# init database
init__database_dir() {
echo "Change rights ..."
ls -la "$MYSQLDATA"
chown -R mysql "$MYSQLDATA"
chgrp -R mysql "$MYSQLDATA"
echo "Initializing database..."
cd $MYSQLBASE
scripts/mysql_install_db --user=mysql
}
temp_server_start() {
mysqld_safe --user=mysql &
}
temp_server_stop() {
mysqladmin shutdown -uroot
sleep 30
}
setup_db() {
sleep 20
echo "start password setting"
mysql -e "GRANT ALL PRIVILEGES ON *.* TO 'root'#'%' IDENTIFIED BY '$MYSQL_ROOT_PASSWORD' WITH GRANT OPTION"
echo "password ready"
}
# start mysql if it is exist.
main() {
setup_env
if [ -z "$(ls -A "$MYSQLDATA/mysql/")" ]; then
init__database_dir
temp_server_start
setup_db
temp_server_stop
fi
echo "start mysqld_safe"
echo "$#"
}
main
I think you forgot to pass the parameters in your entrypoint.sh. The last line should be
main "$#"
When the chromium succeed to launch, its Debugging WebSocket URL should be like ws://127.0.0.1:9222/devtools/browser/ec261e61-0e52-4016-a5d7-d541e82ecb0a.
127.0.0.1:9222 should be able to browse by Chrome to inspect the headless Chromium. However, I cannot access the remote debugger URL by Chrome after I dockerize my application.
launchOption for launching chromium by Puppeteer:
{
"args": [
"--remote-debugging-port=9222",
"--window-size=1920,1080",
"--mute-audio",
"--disable-notifications",
"--force-device-scale-factor=0.8",
"--no-sandbox",
"--disable-setuid-sandbox"
],
"defaultViewport": {
"height": 1080,
"width": 1920
},
"headless": true
}
Dockerfile:
FROM node:10.16.3-slim
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
&& apt-get update \
&& apt-get install -y google-chrome-unstable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf \
--no-install-recommends \
&& rm -rf /var/lib/apt/lists/* \
&& wget --quiet https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh -O /usr/sbin/wait-for-it.sh \
&& chmod +x /usr/sbin/wait-for-it.sh
WORKDIR /usr/app
COPY ./ ./
VOLUME ["......." ]
RUN groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \
&& mkdir -p /home/pptruser/Downloads \
&& chown -R pptruser:pptruser /home/pptruser \
&& chown -R pptruser:pptruser /usr/app \
&& npm install
USER pptruser
CMD npm run start
EXPOSE 3000 9222
Run the new container by :
docker run \
-p 3000:3000 \
-p 9222:9222 \
pptr
Port 9222 should be accessible in my host machine. But Chrome shows the error ERR_EMPTY_RESPONSE when I browse 127.0.0.1:9222 and DOCKER-INTERNAL-IP:9222 will timeout.
I managed to make this work with puppeteer using the following Dockerfile, docker run and puppeteer config:
FROM ubuntu:18.04
RUN apt update \
&& apt install -y \
curl \
wget \
gnupg \
gcc \
g++ \
make \
&& curl -sL https://deb.nodesource.com/setup_10.x | bash - \
&& apt install -y nodejs \
&& rm -rf /var/lib/apt/lists/*
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
&& apt-get update \
&& apt-get install -y google-chrome-unstable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf \
--no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
RUN groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \
&& mkdir -p /home/pptruser/Downloads \
&& chown -R pptruser:pptruser /home/pptruser
ADD . /app
WORKDIR /app
RUN chown -R pptruser:pptruser /app
RUN rm -rf node_modules
RUN rm -rf build/*
USER pptruser
RUN npm install --dev
RUN chmod +x /app/entrypoint.sh
ENTRYPOINT /app/entrypoint.sh
Docker run:
docker run -p 9223:9222 -it myimage
Puppeteer launch:
this.browser = await puppeteer.launch(
{
headless: true,
args: [
'--remote-debugging-port=9222',
'--remote-debugging-address=0.0.0.0',
'--no-sandbox'
]
}
);
The entrypoint just launches the platform like: node build/main.js
After that I just had to connect to localhost:9223 on Chrome to see the browser. Hope it helps!
I know there is already an accepted answer, but let me add onto this in hopes to greatly reduce your image size. One shouldn't add too many extras into the Dockerfile if one can help it. But ultimately, adding --remote-debugging-port=9222 and --remote-debugging-address=0.0.0.0 will allow you to access it.
Dockerfile
FROM ubuntu:latest
LABEL Full Name <email#email.com> https://yourwebsite.com
WORKDIR /home/
COPY wrapper-script.sh wrapper-script.sh
# install chromium-browser and cleanup.
RUN apt update && apt install chromium-browser --no-install-recommends -y && apt autoremove && apt clean && apt autoclean && rm -rf /var/lib/apt/lists/*
# Run your commands and add environment variables from your compose file.
CMD ["sh", "wrapper-script.sh"]
I use a wrapper script so that I can include environment variables here. You can see URL and USERNAME set so that I can configure them from the compose file. Of course, i'm sure there is a better way to do this, but I do this so that I can scale my containers horizontally with ease.
wrapper-script.sh
#!/bin/bash
# Start the process
chromium-browser --headless --disable-gpu --no-sandbox --remote-debugging-port=9222 --remote-debugging-address=0.0.0.0 ${URL}${USERNAME}
status=$?
if [ $status -ne 0 ]; then
echo "Failed to start chromium-browser: $status"
exit $status
fi
# Naive check runs checks once a minute to see if either of the processes exited.
# This illustrates part of the heavy lifting you need to do if you want to run
# more than one service in a container. The container exits with an error
# if it detects that either of the processes has exited.
# Otherwise it loops forever, waking up every 60 seconds
while sleep 60; do
ps aux |grep chromium-browser | grep -q -v grep
PROCESS_1_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 ]; then
echo "One of the processes has already exited."
exit 1
fi
done
Lastly, I have the docker-compose file. This is where I define all my settings so that I can configure my wrapper-script.sh with what I need and scale horizontally. Notice the environment section of the docker-compose file. USERNAME and URL are environment variables, and they can be called from the wrapper script.
docker-compose.yml
version: '3.7'
services:
chrome:
command: [ 'sh', 'wrapper-script.sh' ]
image: headless-chrome
build:
context: .
dockerfile: Dockerfile
environment:
- USERNAME=eaglejs
- URL=https://teamtreehouse.com/
ports:
- 9222:9222
If you are wondering what my folder structure looks like. all three files are at the root of the folder. For example:
My_Docker_Repo:
Dockerfile
docker-compose.yml
wrapper-script.sh
After that is all said and done, I simply run docker-compose up and I have one container running. Right now, using the ports section, you'll have to do something to scale that as well. if you were to run docker-compose up --scale chrome=5 your ports will clash, but let me know if you want to try that and i'll see what I can do for scaling, but other than that, if it is for testing, this should work well the way it is. :) Happy coding!
eaglejs
I am unable to switch user to a non-root user from the entry point script. The User directive to change the user in Dockerfile works, but I am not able to change permissions using chmod. To overcome this issue I created entrypoint.sh script to change the folder permissions but when I try to switch user using su command, it apparently doesn't work, the container is still running as root.
The Dockerfile
FROM php:7.2-fpm
# Installing dependencies
RUN apt-get update && apt-get install -y \
build-essential \
mysql-client \
libpng-dev \
libjpeg62-turbo-dev \
libfreetype6-dev \
locales \
zip \
jpegoptim optipng pngquant gifsicle \
vim \
unzip \
git \
curl
# Installing composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
ENV USER_ID=1000
ENV GROUP_ID=1000
ENV USER_NAME=www
ENV GROUP_NAME=www
RUN groupadd -g $GROUP_ID $GROUP_NAME
RUN useradd -u $USER_ID -ms /bin/bash -g $GROUP_NAME $USER_NAME
RUN mkdir /app
WORKDIR /app
EXPOSE 9000
COPY ./entrypoint.sh /
RUN ["chmod", "+x", "/entrypoint.sh"]
ENTRYPOINT ["/entrypoint.sh"]
Entrypoint.sh file
#!/bin/bash
if [ -n "$USER_ID" -a -n "$GROUP_ID" ]; then
chown -R $USER_NAME:$GROUP_NAME .
su $USER_NAME
fi
php-fpm
exec "$#"
whatever I do I am not able to switch user from the entrypoint.sh script.
My case is to run the container as non-root user.
I think that your su command should be something like
su $USERNAME --command "/doit.sh"
b/c your entrpoiny script is switching user, doing nothing, and then switching back to root.
To solve this you need to change your dockerfile and add:
RUN echo "root ALL = NOPASSWD: /bin/su ALL" >> /etc/sudoers
Or use gosu what is better:
# install gosu
# seealso:
# https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
# https://github.com/tianon/gosu/blob/master/INSTALL.md
# https://github.com/tianon/gosu
RUN set -eux; \
apt-get update; \
apt-get install -y gosu; \
rm -rf /var/lib/apt/lists/*; \
# verify that the binary works
gosu nobody true
Then inside entrypoint.sh:
gosu root yourservice &
#ie: gosu root /usr/sbin/sshd -D &
exec gosu no-root-user yourservice2
# ie: exec gosu no-root-user tail -f /dev/null
I built a simple dockerfile using php5.6-fpm image. This file should run my site php code and install all required dependencies. The problem is that php is working, but dependencies like
composer install --working-dir=/var/www/html $COMPOSER_ARGS
and
cp /var/www/html/config.inc.php.dist /var/www/html/config.inc.php
are not installed.
Dockerfile:
FROM php:5.6-fpm
LABEL maintainer "karolis#pretendentas.lt"
WORKDIR /var/www/html
VOLUME /var/www/html
EXPOSE 9000
COPY docker-entrypoint.sh /docker-entrypoint.sh
RUN set -ex \
&& apt-get update && apt-get install -y \
zip \
git \
libxml2-dev \
libjpeg-dev \
libpng12-dev \
&& docker-php-ext-configure gd --with-png-dir=/usr/ --with-jpeg-dir=/usr/ \
&& docker-php-ext-install -j$(nproc) bcmath gd mysqli opcache soap
RUN mkdir -p /var/lib/php/session \
&& mkdir -p /var/lib/php/wsdlcache \
&& chown -R www-data:www-data /var/lib/php/session \
&& chown -R www-data:www-data /var/lib/php/wsdlcache \
&& chmod +x /docker-entrypoint.sh
ENV GITHUB_TOKEN ********************
RUN set -ex \
&& curl -sS https://getcomposer.org/installer | php -- \
--install-dir=/usr/bin \
--filename=composer \
&& composer config -g github-oauth.github.com $GITHUB_TOKEN
ENTRYPOINT ["/docker-entrypoint.sh"]
docker-entrypoint.sh:
#!/bin/bash
set -e
if [ -f var/www/html/docker/init.sh ]; then
sleep 5 && echo "[info] Running /var/www/html/init.sh script" && sh /var/www/html/init.sh &
fi
docker-php-entrypoint php-fpm
init.sh:
#!/bin/bash
if [ -f /var/www/html/composer.json ] && [ ! -d /var/www/html/vendor ]; then
echo "[info] Composer install"
composer install --working-dir=/var/www/html $COMPOSER_ARGS
fi
if [ ! -f /var/www/html/config.inc.php ]; then
echo "[info] Copy default config"
cp /var/www/html/config.inc.php.dist /var/www/html/config.inc.php
fi
this is php image snippet from docker-compose file:
php:
image: pretendentas/php5.6-test
ports:
- "9000:9000"
volumes:
- .:/var/www/html
- ./docker/php/php.ini:/usr/local/etc/php/php.ini:ro
working_dir: /var/www/html
restart: always
depends_on:
- db
I think you ask into wrong path to execute the file.
dockerfile
COPY init.sh /var/www/html/init.sh
entrypoint.sh
if [ -f var/wwww/html/docker/init.sh ];
Fix the typos here:
if [ -f var/wwww/html/docker/init.sh ];
To:
if [ -f /var/www/html/docker/init.sh ];
However, take into account that the COPY of init.sh is being overrided by the volume. So in the entrypoint.sh refer to the correct path of init.sh. I assume that init.sh is in the project root dir, so it is located at the root of the volume: /var/www/html
if [ -f /var/www/html/init.sh ]; then
sleep 5 && echo "[info] Running /var/www/html/init.sh script " && sh /var/www/html/init.sh &
fi