Docker container does not run with a non-root user - docker

FROM ubuntu:18.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -yq --no-install-recommends \
apt-utils \
curl \
# Install git
git \
# Install apache
apache2 \
# Install php 7.2
libapache2-mod-php7.2 \
php7.2-cli \
php7.2-json \
php7.2-curl \
php7.2-fpm \
php7.2-gd \
php7.2-ldap \
php7.2-mbstring \
php7.2-mysql \
php7.2-soap \
php7.2-sqlite3 \
php7.2-xml \
php7.2-zip \
php7.2-intl \
php-imagick \
# Install tools
openssl \
nano \
graphicsmagick \
imagemagick \
ghostscript \
mysql-client \
iputils-ping \
locales \
sqlite3 \
ca-certificates \
&& apt-get clean && rm -f /var/www/html/index.html && rm -rf /var/lib/apt/lists/**
ENV LANG en_US.utf8
RUN groupadd --gid 5000 newuser \
&& useradd --home-dir /home/newuser --create-home --uid 5000 \
--gid 5000 --shell /bin/sh --skel /dev/null newuser
WORKDIR /var/www/html
COPY index.php /var/www/html
EXPOSE 80
HEALTHCHECK --interval=5s --timeout=3s --retries=3 CMD curl -f http://localhost || exit 1
CMD ["apachectl", "-D", "FOREGROUND"]
USER newuser
The error I get:
(13)Permission denied: AH00072: make_sock: could not bind to address 0.0.0.0:80 no listening sockets available, shutting down AH00015: Unable to open logs Action '-D FOREGROUND' failed. The Apache error log may have more information.

As #Henry wrote:
A non root user cannot bind to ports below 1024. Use a port that is higher e.g. 8080.
I suggest you change apache port and, if you need to access apache from the host, map the port 8080 to 80 in docker.
e.g.
docker build -t myapacheimg .
docker run -it --rm -p 8080:80 myapacheimg
In order to have this stuff working you need to perform the following operations:
change the ports in the /etc/apache2/ports.conf
change the virtualhost in the /etc/apache2/sites-enabled/000-default.conf
change the ownership of the /var/log/apache2 and /var/run/apache2 folders
In other words, here's an excerpt of the Dockerfile:
...
&& apt-get clean && rm -f /var/www/html/index.html && rm -rf /var/lib/apt/lists/**
COPY ./ports.conf /etc/apache2/ports.conf
COPY ./000-default.conf /etc/apache2/sites-enabled/000-default.conf
ENV LANG en_US.utf8
RUN groupadd --gid 5000 newuser \
&& useradd --home-dir /home/newuser --create-home --uid 5000 \
--gid 5000 --shell /bin/sh --skel /dev/null newuser
RUN chown -R newuser /var/log/apache2 /var/run/apache2
...
ports.conf
Listen 8080
000-default.conf:
<VirtualHost *:8080>
ServerAdmin webmaster#localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
IMHO this is an ugly solution. I'd use the docker image php:7.2-apache and avoid all these problems.

A non root user cannot bind to ports below 1024. Use a port that is higher e.g. 8080.

It can be done without changing the port also, using the setcap command to modify the linux capability.
For example, If you wish to use the default port 80 for apache2 then your Dockerfile will look something like this:
[...]
RUN apt-get update \
&& apt-get install -y libcap2-bin \
&& setcap 'cap_net_bind_service=+ep' /usr/sbin/apache2 \
&& chown www-data:www-data /var/log/apache2
USER www-data
[...]

Related

Starting supervisor with Docker and seeing its logs in docker logs, but not finding the service with service supervisor status in the container

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.

Create unix socket inside of Alpine container to connect Gunicorn with Nginx

I'm moving my Django application (same as described here) from local machine to Docker container.
I'm redirecting users that come to port 80 from Nginx to Gunicorn via unix:run/gunicorn.sock It works on my local machine, but I7m not sure how to describe this action in Dockerfile.
Right now I'm doing it this way, but it won't works...
FROM python:3.7.4-alpine3.10
ADD mediadbin/requirements.txt /app/requirements.txt
RUN set -ex \
&& apk add --no-cache --virtual .build-deps postgresql-dev build-base python3-dev gcc jpeg-dev nginx zlib-dev\
&& python -m venv /env \
&& /env/bin/pip install --upgrade pip \
&& /env/bin/pip install --no-cache-dir -r /app/requirements.txt \
&& runDeps="$(scanelf --needed --nobanner --recursive /env \
| awk '{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \
| sort -u \
| xargs -r apk info --installed \
| sort -u)" \
&& apk add --virtual rundeps $runDeps \
&& mkdir run/gunicorn.sock \
&& mkdir /etc/nginx/sites-enabled \
&& apk del .build-deps
COPY ./config/mediadbin /etc/nginx/sites-enabled/mediadbin
ADD mediadbin /app
WORKDIR /app
ENV VIRTUAL_ENV /env
ENV PATH /env/bin:$PATH
EXPOSE 5432
EXPOSE 8000
EXPOSE 80
CMD ["gunicorn", "--bind", "unix:run/gunicorn.sock", "--workers", "3", "mediadbin.wsgi:application", "--name", "mediadbin"]
Also it won't throw an Error or somthing like that, so I'm not sure what is wrong...
I'm able to run Gunicorn without Nginx via port 8000 in my container when I edit a little bit the script above

Docker permission denied via build image for container

I tried to build image from Dockerfile.
For this purposes I used this dockerhub image: https://hub.docker.com/r/openshift/origin-haproxy-router
My Dockerfile:
FROM openshift/origin-haproxy-router
RUN INSTALL_PKGS="haproxy18 rsyslog" && \
yum install -y $INSTALL_PKGS && \
yum clean all && \
rpm -V $INSTALL_PKGS && \
mkdir -p /var/lib/haproxy/router/{certs,cacerts,whitelists} && \
mkdir -p /var/lib/haproxy/{conf/.tmp,run,bin,log} && \
touch /var/lib/haproxy/conf/{{os_http_be,os_edge_reencrypt_be,os_tcp_be,os_sni_passthrough,os_route_http_redirect,cert_config,os_wildcard_domain}.map,haproxy.config} && \
setcap 'cap_net_bind_service=ep' /usr/sbin/haproxy && \
chown -R :0 /var/lib/haproxy && \
chmod -R g+w /var/lib/haproxy
COPY images/router/haproxy/* /var/lib/haproxy/
LABEL io.k8s.display-name="OpenShift HAProxy Router" \
io.k8s.description="This component offers ingress to an OpenShift cluster via Ingress and Route rules." \
io.openshift.tags="openshift,router,haproxy"
USER root
EXPOSE 80 443
WORKDIR /var/lib/haproxy/conf
ENV TEMPLATE_FILE=/var/lib/haproxy/conf/haproxy-config.template \
RELOAD_SCRIPT=/var/lib/haproxy/reload-haproxy
ENTRYPOINT ["/usr/bin/openshift-router"]
After I tried to run command inside folder with dockerfile:
sudo docker build -t os-router .
I got next result:
ovl: Error while doing RPMdb copy-up:
[Errno 13] Permission denied: '/var/lib/rpm/Conflictname'
You need to be root to perform this command.
How can I solve this error?
put USER root in your dockerfile

Docker Entrypoint script cannot get $DB_PORT_3306_TCP_ADDR environment variable

I have the following Dockerfile:
FROM php:5.6-apache
MAINTAINER pc_magas#openmailbox.org
EXPOSE 80
RUN apt-get update && apt-get install -y \
libjpeg-dev \
libfreetype6-dev \
libgeoip-dev \
libpng12-dev \
libldap2-dev \
zip \
mysql-client \
&& rm -rf /var/lib/apt/lists/*
RUN docker-php-ext-configure gd --with-freetype-dir=/usr --with-png-dir=/usr --with-jpeg-dir=/usr \
&& docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu/ \
&& docker-php-ext-install -j$(nproc) gd mbstring mysql pdo_mysql zip ldap opcache
RUN pecl install APCu geoip
ENV PIWIK_VERSION 3.0.1
RUN curl -fsSL -o piwik.tar.gz \
"https://builds.piwik.org/piwik-${PIWIK_VERSION}.tar.gz" \
&& curl -fsSL -o piwik.tar.gz.asc \
"https://builds.piwik.org/piwik-${PIWIK_VERSION}.tar.gz.asc" \
&& export GNUPGHOME="$(mktemp -d)" \
&& gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 814E346FA01A20DBB04B6807B5DBD5925590A237 \
&& gpg --batch --verify piwik.tar.gz.asc piwik.tar.gz \
&& rm -r "$GNUPGHOME" piwik.tar.gz.asc \
&& tar -xzf piwik.tar.gz -C /usr/src/ \
&& rm piwik.tar.gz
COPY php.ini /usr/local/etc/php/php.ini
RUN curl -fsSL -o /usr/src/piwik/misc/GeoIPCity.dat.gz http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz \
&& gunzip /usr/src/piwik/misc/GeoIPCity.dat.gz
COPY docker-entrypoint.sh /entrypoint.sh
# WORKDIR is /var/www/html (inherited via "FROM php")
# "/entrypoint.sh" will populate it at container startup from /usr/src/piwik
VOLUME /var/www/html
ENV PIWIK_DB_HOST ""
ENV PIWIK_DB_PORT ""
ENV PIWIK_DB_USER ""
ENV PIWIK_DB_PASSWORD ""
ENV PIWIK_DB_NAME ""
#Create backup and restore foolders
RUN mkdir /var/backup && \
chmod 665 /var/backup && \
mkdir /var/restore && \
chmod 665 /var/restore
#Export Backup Folder
VOLUME /var/backup
#Export restore foolder
VOLUME /var/restore
COPY backup.php /tmp/backup.php
RUN cp /tmp/backup.php /usr/local/bin/piwik_backup && \
chown root:root /usr/local/bin/piwik_backup && \
chmod 733 /usr/local/bin/piwik_backup && \
rm -rf /tmp/backup
ENTRYPOINT ["/entrypoint.sh"]
CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
That uses the following script as entrypoint:
#!/bin/bash
if [ ! -e piwik.php ]; then
cp -R /usr/src/piwik/* /var/www/html
chown -R www-data:www-data .
fi
: ${PIWIK_DB_HOST:=$DB_PORT_3306_TCP_ADDR}
echo "Mariadb Addr:"$DB_PORT_3306_TCP_ADDR
: ${PIWIK_DB_PORT:=${DB_PORT_3306_TCP_PORT}}
COUNTER=0
echo "Waiting for mysql to start at ${PIWIK_DB_HOST} using port ${PIWIK_DB_PORT}..."
while ! mysqladmin ping -h"$PIWIK_DB_HOST" -P $PIWIK_DB_PORT --silent; do
if [ $COUNTER -gt 10 ] ; then
exit 1
fi
echo "Connecting to ${PIWIK_DB_HOST} Failed"
COUNTER=$[COUNTER+1]
sleep 1
done
echo "Setting up the database connection info"
: ${PIWIK_DB_USER:=${DB_ENV_MYSQL_USER:-root}}
: ${PIWIK_DB_NAME:=${DB_ENV_MYSQL_DATABASE:-'piwik'}}
if [ "$PIWIK_DB_USER" = 'root' ]; then
: ${PIWIK_DB_PASSWORD:=$DB_ENV_MYSQL_ROOT_PASSWORD}
else
: ${PIWIK_DB_PASSWORD:=$DB_ENV_MYSQL_PASSWORD}
fi
if ! mysql -h"$PIWIK_DB_HOST" -P $PIWIK_DB_PORT -u ${PIWIK_DB_USER} -p${PIWIK_DB_PASSWORD} -e ";" ; then
echo "The user does not exist to the mysql server: ${PIWIK_DB_HOST}"
exit 1
fi
php console config:set --section="database" --key="host" --value=${PIWIK_DB_HOST}
php console config:set --section="database" --key="port" --value=${PIWIK_DB_PORT}
php console config:set --section="database" --key="username" --value=${PIWIK_DB_USER}
php console config:set --section="database" --key="password" --value=${PIWIK_DB_PASSWORD}
php console config:set --section="database" --key="tables_prefix" --value="piwik_"
php index.php
exec "$#"
But for some reason The entrypoint script cannot find the enviromental variables provided by mariadb container such as the DB_PORT_3306_TCP_ADDR providing the connection to the mariadb server.
I use the following commands in order to run the images into the containers containers:
docker run --name piwikdb --volume $(pwd)/volumes/db:/var/lib/db \
-e MYSQL_ROOT_PASSWORD=123 -d mariadb
docker run --volume $(pwd)/volumes/piwik:/var/www/data --link piwikdb:mysql \
-p 8081:80 -t ^hash of the fresly build image^
I tried to troubleshoot it, but I cannot figure out why that happens.
This is not how you want to do linking.
The correct, supported, way, is one of the following.
Use docker-compose
If you use docker-compose, you would name your database service (say, db), and then your other containers can be told to connect to db as if it were a hostname.
You can use env_file in docker-compose.yml to specify a file with parameters such as database name, mariadb port, authentication info, and so on. Each container can load the same env_file.
Use a docker network
If you prefer to run containers without using compose, just make sure they are on the same network, like this:
docker network create myapp
docker run --name piwikdb --volume $(pwd)/volumes/db:/var/lib/db \
-e MYSQL_ROOT_PASSWORD=123 -d --network myapp mariadb
docker run --volume $(pwd)/volumes/piwik:/var/www/data \
--network myapp -p 8081:80 -t ^hash of the fresly build image^
If all containers are on the same network, then as with docker-compose, you can just tell your piwik container to use "piwikdb" as the server (i.e. the container name of your other container).

How to convert a systemctl command to supervisord command

I have found the following Dockerfile
FROM centos
# following http://www.pacb.com/wp-content/uploads/2015/09/SMRT-Analysis-Software-Installation-v2.3.0.pdf
MAINTAINER harekrishna#gmail.com
ENV SMRT_ROOT=/opt/smrtanalysis/
ENV SMRT_USER=smrtanalysis
ENV SMRT_GROUP=smrtanalysis
RUN yum groupinstall -y "Development Tools"
RUN yum install -y redhat-lsb net-tools
RUN groupadd $SMRT_GROUP
RUN adduser \
--gid $SMRT_GROUP \
--home-dir $SMRT_ROOT \
--create-home \
--shell /bin/bash \
$SMRT_USER
USER $SMRT_USER
WORKDIR $SMRT_ROOT
RUN curl -LO -# \
http://files.pacb.com/software/smrtanalysis/2.3.0/smrtanalysis_2.3.0.140936.run
RUN curl -LO -# \
https://s3.amazonaws.com/files.pacb.com/software/smrtanalysis/2.3.0/smrtanalysis-patch_2.3.0.140936.p5.run
RUN bash \
smrtanalysis_2.3.0.140936.run \
-p smrtanalysis-patch_2.3.0.140936.p5.run \
--rootdir $SMRT_ROOT \
--batch \
--ignore-syscheck \
--jmstype NONE
ADD ./run /usr/local/bin
#RUN chmod 755 ./run
EXPOSE 8080
CMD ["/usr/local/bin/run"]
Startup scripts:
$SMRT_ROOT/admin/bin/smrtportald-initd start
$SMRT_ROOT/admin/bin/kodosd start
How is it possible to covnert the two above commands to supervised commands?
Thank you in advance.
Mic

Resources