Permission in docker Container just partly working with chown - docker

I have a problem with access rights in a Docker Container. I am copiyng a folder from the host to the docker image into the folder /var/www/html. This folder has a deeper folder structure. Then, I want www-data which is executing apache to have access to the complete /var/www/html folder. I create the container with the following dockerfile.
#start with base Image from php
FROM php:7.3-apache
#install system dependencies and enable PHP modules
RUN apt-get update && apt-get install -y \
libicu-dev \
libpq-dev \
libmcrypt-dev \
mysql-client \
git \
zip \
unzip \
&& rm -r /var/lib/apt/lists/* \
&& docker-php-ext-configure pdo_mysql --with-pdo-mysql=mysqlnd \
&& docker-php-ext-install \
intl \
mbstring \
pcntl \
pdo_mysql \
pdo_pgsql \
pgsql \
opcache
# zip \
# mcrypt \
#configure imap for mails
RUN apt-get update && \
apt-get install -y \
libc-client-dev libkrb5-dev && \
rm -r /var/lib/apt/lists/*
RUN docker-php-ext-configure imap --with-kerberos --with-imap-ssl && \
docker-php-ext-install -j$(nproc) imap
#install mcrypt
RUN apt-get update \
&& apt-get install -y libmcrypt-dev \
&& rm -rf /var/lib/apt/lists/* \
&& pecl install mcrypt-1.0.2 \
&& docker-php-ext-enable mcrypt
#install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin/ --filename=composer
#set our application folder as an environment variable
ENV APP_HOME /var/www/html
#change uid and gid of apache to docker user uid/gid
RUN usermod -u 1000 www-data && groupmod -g 1000 www-data
# enable apache module rewrite
RUN a2enmod rewrite
#COPY Data to html
COPY --chown=www-data:www-data AppBare/ /var/www/html
#change ownership of our applications
RUN chown -R www-data:www-data /var/www/html
#Copy file to start schema update on startup
ENTRYPOINT [ "sh", "-c", "/var/www/html/app/Console/cake schema update -y && /var/www/html/app/Console/cake migration && /usr/sbin/apachectl -D FOREGROUND"]
EXPOSE 80
After I create and start the container, I get the following error message accessing a website of the serving webserver. However it is also loading the website with images that were copied, so basically, the user has access to e.g. images, css and so on.
SplFileInfo::openFile(/var/www/html/app/tmp/cache/models/demo_backend_cake_model_default_backend_dockertest_list):
failed to open stream: Permission denied
When I go into the console of the container and reset the permissions with the chown command, the problem disappears. So the command itself must be right. Also when I create a volume and mount the folder from the host to /var/www/html, everything is working fine.
How can I give the user the full access to the folder? I also tried out to switch give the access before I copy the data, but that's not working also.

About your last comment
The two files are created by the Entrypoint of the code /var/www/html/app/Console/cake schema update -y. So this is executed by the root user. Is it possible to say to execute this as www-data not as root?
The answer is yes. You have to add the following line before your entrypoint :
USER www-data
This way, everything run after this line will be with this user.

Related

How to run docker container from non-root user?

How do I make a docker container run as non-root user and have working directory (and its files) owned by a non-root user. Variants I could find in various online tutorials didn't work for some reason, files in /var/www would still be owned by root root.
Below is my Dockerfile, I use docker-compose to build and run containers. Host system is Windows 10.
FROM php:7.4-fpm
ARG user
ARG uid
RUN apt-get update && apt-get install -y \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
WORKDIR /var/www
USER $user
You can try this docker file
FROM php:7.4-fpm
ARG user
ARG uid
RUN apt-get update && apt-get install -y \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip
RUN addgroup -g $uid $user && \
adduser -S -G $user -u $uid -h $user
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
RUN chown $user:$user -R /var/www
WORKDIR /var/www
USER $user
This change is needed to make sure that the user is created in the docker image
RUN addgroup -g $uid $user && \
adduser -S -G $user -u $uid -h $user
This is needed to change the ownership of the files to the new user
RUN chown $user:$user -R /var/www
Simply add
RUN chown $user:$user -R /var/www
before your WORKDIR instruction. Similarly you can change ownership for other locations as needed.

How to Add user when creating docker image from alpine base image

I want to add user www-data as my default user when I run my container in bash mode.
Currently, when I type WHOAMI then it's showing root as user, but I need www-data as user, how to do this in docker.
This is my docker file:
FROM php:7.2-fpm-alpine
LABEL maintainer="y.ghorecha#abc.de" \
muz.customer="xxx" \
muz.product="WIDC" \
container.mode="production"
#https://pkgs.alpinelinux.org/packages
RUN apk add --no-cache --virtual .deps autoconf tzdata build-base libzip-dev mysql-dev gmp-dev \
libxml2-dev libpng-dev zlib-dev freetype-dev jpeg-dev icu-dev openldap-dev libxslt-dev &&\
docker-php-ext-install zip xml mbstring json intl gd pdo pdo_mysql iconv soap \
dom gmp fileinfo sockets bcmath mysqli ldap xsl &&\
echo 'date.timezone="Europe/Berlin"' >> "${PHP_INI_DIR}"/php.ini &&\
cp /usr/share/zoneinfo/Europe/Berlin /etc/localtime &&\
echo 'Europe/Berlin' > /etc/timezone &&\
apk del .deps &&\
apk add --no-cache libzip mysql libxml2 libpng zlib freetype jpeg icu gmp git subversion libxslt openldap \
apache2 apache2-ldap apache2-proxy libreoffice openjdk11-jre ghostscript msttcorefonts-installer \
terminus-font ghostscript-fonts &&\
ln -s /usr/lib/apache2 /usr/lib/apache2/modules &&\
ln -s /usr/sbin/httpd /etc/init.d/httpd &&\
update-ms-fonts
# imap setup
RUN apk --update --virtual build-deps add imap-dev
RUN apk add imap
RUN docker-php-ext-install imap
# copy all codebase
COPY ./ /var/www
# SSH setup
RUN apk update && \
apk add --no-cache \
openssh-keygen \
openssh
# copy Azure specific files
COPY backend/build/azure/backend/ /var/www/backend/
# User owner setup
RUN chown -R www-data:www-data /var/www/
# Work directory setup
WORKDIR /var/www
# copy apache httpd.conf file
COPY httpd.conf /etc/apache2/httpd.conf
# copy crontabs for root user
COPY backend/data/CRONTAB/production/crontab.txt /etc/crontabs/www-data
# SSH Key setup
RUN mkdir -p /home/www-data/.ssh
RUN chown -R www-data:www-data /home/www-data/
#https://github.com/docker-library/httpd/blob/3ebff8dadf1e38dbe694ea0b8f379f6b8bcd993e/2.4/alpine/httpd-foreground
#https://github.com/docker-library/php/blob/master/7.2/alpine3.10/fpm/Dockerfile
CMD ["/bin/sh", "-c", "rm -f /usr/local/apache2/logs/httpd.pid && /usr/sbin/crond start && httpd -DBACKGROUND && php-fpm"]
Please advice on above.
I'd start with first checking if the www-data user even exits in the image. Execute in the running container something like:
sudo cat /etc/passwd | grep www-data
If the user does exist then add the USER www-data directive to the Dockerfile after all commands that do installs, create directories, change permissions, etc. It would be required to also add USER 0 at the beginning to switch to the root user for those commands if the base image doesn't run as root. Looking at the Dockerfile I'd suggest to add USER www-data before the CMD directive.
If the www-data user doesn't exist then it has to be added first. The commands for Alpine Linux are addgroup and adduser. Something like these if the user id for www-data is to be 33 and the group it belongs to is also named www-data and has id of 33:
RUN addgroup -S -g 33 www-data \
&& adduser -S -D -u 33 -s /sbin/nologin -h /var/www -G www-data www-data
Add the above just before RUN chown -R www-data:www-data /var/www/, or make it a single RUN directive:
RUN addgroup -S -g 33 www-data \
&& adduser -S -D -u 33 -s /sbin/nologin -h /var/www -G www-data www-data \
&& chown -R www-data:www-data /var/www/
You can add this line to you dockerfile in order to become the www-data user
USER www-data
This can be either added
in the end of your file (if you want at to become that user before the script exits), or
in the beginning if you want to perform your actions within the docker file as this user.

Split up Dockerfile in two Images

I have a Dockerfile including e.g. apache, further installations and my code that is copied to /var/www/html to create a project. After I created the image locally, I export it as a .tar file and upload the image to portainer. Portainer is my productive environment. However, everytime when I want to update the Version and the services that are using my software, I have to update the whole new image which has a size of 800MB. Portainer has furthermore multiple managers, which causes that I have to upload it to each manager.
Because everything keeps the same, except my code that is inserted by the copy part COPY HRmAppBare/ /var/www/html, I thought about the idea, If it is possible to create two images. One Image for the whole Installations (let us say: 1.0-BaseInstall) and a second Image (let us say: 1.9-backend) that only stores my code. Then, for each Version update, I only have to upload the image with the new code and can maybe somehow refere to the 1.0-BaseInstall like e.g. From 1.0-BaseInstall. If the BaseInstall changes (which is really rarely), I could just create a new image for that.
Because I could not find anything about that, I want to know, if this approach is applicable and if yes, how I have to build this?
#start with base Image from php
FROM php:7.3-apache
#install system dependencies and enable PHP modules
RUN apt-get update && apt-get install -y \
libicu-dev \
vim \
cron \
libpq-dev \
libmcrypt-dev \
default-mysql-client \
zip \
unzip \
libzip-dev \
&& docker-php-ext-configure zip --with-libzip \
&& docker-php-ext-install zip \
&& rm -r /var/lib/apt/lists/* \
&& docker-php-ext-configure pdo_mysql --with-pdo-mysql=mysqlnd \
&& docker-php-ext-install \
intl \
mbstring \
pcntl \
pdo_mysql \
opcache \
gettext \
&& pecl install mcrypt-1.0.2 \
&& docker-php-ext-enable mcrypt \
&& rm -rf /var/lib/apt/lists/*
#configure imap for mails
RUN apt-get update && \
apt-get install -y \
libc-client-dev libkrb5-dev && \
rm -r /var/lib/apt/lists/*
RUN docker-php-ext-configure imap --with-kerberos --with-imap-ssl && \
docker-php-ext-install -j$(nproc) imap
#install composer
#RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin/ --filename=composer
#change uid and gid of apache to docker user uid/gid, enable apache module rewrite
RUN usermod -u 1000 www-data && groupmod -g 1000 www-data && a2enmod rewrite
#copy the source code (Can this be in a 2nd image?)
COPY HRmAppBare/ /var/www/html
#Update apache2.conf
RUN echo 'Alias ${COOKIE_PATH} "/var/www/html"' >> /etc/apache2/apache2.conf
RUN echo 'Alias ${COOKIE_PATH}/ "/var/www/html/"' >> /etc/apache2/apache2.conf
#change ownership of our applications
RUN chown -R www-data:www-data /var/www/html/
ENTRYPOINT [ "sh", "-c", "rm /var/www/html/app/tmp/cache/models/* && rm /var/www/html/app/tmp/cache/persistent/* && /var/www/html/app/Console/cake schema update -y && apache2-foreground"]
EXPOSE 80
You can break this into multiple docker files and it would be viable.
If you have no other consumers of the base image it may create confusion and just add more overhead to have to manage versions for your base image and your application but it is certainly viable.
It may be worth it to look into multi-stage builds.
https://github.com/docker/docker.github.io/blob/master/develop/develop-images/multistage-build.md
If the objects on the file system that Docker is about to produce are unchanged between builds, reusing a cache of a previous build on the host is a great time-saver. It makes building a new container really, really fast.
https://thenewstack.io/understanding-the-docker-cache-for-faster-builds/
I'm unsure when you say
Then, for each Version update, I only have to upload the code
I may be misunderstanding the phrase but instead I would suggest having all of the builds done on your build box and have the versioned image pushed to a docker repo for your production box to pull from when you're ready to grab the next version. You shouldn't need to upload your code anywhere. Just the built image to whatever docker repo you store your images on.
Edit: Add in link for creating your own docker repo
https://docs.docker.com/registry/deploying/
Edit 2: To better answer your question
FROM php:7.3-apache AS base
//...rest of your dockerfile until copy
FROM base
#copy the source code (Can this be in a 2nd image?)
COPY HRmAppBare/ /var/www/html
#Update apache2.conf
RUN echo 'Alias ${COOKIE_PATH} "/var/www/html"' >> /etc/apache2/apache2.conf
RUN echo 'Alias ${COOKIE_PATH}/ "/var/www/html/"' >> /etc/apache2/apache2.conf
#change ownership of our applications
RUN chown -R www-data:www-data /var/www/html/
ENTRYPOINT [ "sh", "-c", "rm /var/www/html/app/tmp/cache/models/* && rm /var/www/html/app/tmp/cache/persistent/* && /var/www/html/app/Console/cake schema update -y && apache2-foreground"]
EXPOSE

Entrypoint at portainer.io is not working like in Docker image

I have a docker Image with the following Entrypoint.
ENTRYPOINT [ "sh", "-c", "/var/www/html/app/Console/cake schema update -y && /var/www/html/app/Console/cake migration && apache2-foreground"]
Now I want to use portainer.io to manage docker swarm. I created a new service to where I want to set the entrypoint (instead of in the Image). So I deleted the entrypoint In the dockerfile, and added it into "Image" > "Entrypoint". I added:
sh -c /var/www/html/app/Console/cake schema update -y && /var/www/html/app/Console/cake migration && apache2-foreground
However, the containers of the service are failing to start. Without the entrypoint, the containers are starting. Here is an example of the Dockerfile, where the Entrypoint is set.
#start with base Image from php
FROM php:7.3-apache
#install system dependencies and enable PHP modules
RUN apt-get update && apt-get install -y \
libicu-dev \
libpq-dev \
libmcrypt-dev \
mysql-client \
git \
zip \
unzip \
libzip-dev \
&& docker-php-ext-configure zip --with-libzip \
&& docker-php-ext-install zip \
&& rm -r /var/lib/apt/lists/* \
&& docker-php-ext-configure pdo_mysql --with-pdo-mysql=mysqlnd \
&& docker-php-ext-install \
intl \
mbstring \
pcntl \
pdo_mysql \
pdo_pgsql \
pgsql \
opcache \
gettext
# zip \
# mcrypt \
#configure imap for mails
RUN apt-get update && \
apt-get install -y \
libc-client-dev libkrb5-dev && \
rm -r /var/lib/apt/lists/*
RUN docker-php-ext-configure imap --with-kerberos --with-imap-ssl && \
docker-php-ext-install -j$(nproc) imap
#install mcrypt
RUN apt-get update \
&& apt-get install -y libmcrypt-dev \
&& rm -rf /var/lib/apt/lists/* \
&& pecl install mcrypt-1.0.2 \
&& docker-php-ext-enable mcrypt
#install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin/ --filename=composer
#change uid and gid of apache to docker user uid/gid
RUN usermod -u 1000 www-data && groupmod -g 1000 www-data
# enable apache module rewrite
RUN a2enmod rewrite
#change ownership of our applications
RUN chown -R www-data:www-data /var/www/html
#Copy file to start schema update on startup
ENTRYPOINT [ "sh", "-c", "/var/www/html/app/Console/cake schema update -y && /var/www/html/app/Console/cake migration && apache2-foreground"]
EXPOSE 80
How do I have to set the Entrypoint? When I set it a portainer, it is later shown under the section CDM.

Dockerfile drupal console access denied mkdir

I'm trying to install drupal console in docker (under Linux Antergos). I've the following error :
Warning: mkdir(): Permission denied in phar:///usr/local/bin/drupal/vendor/drupal/console-core/src/Utils/ConfigurationManager.php on line 49
Here is my PHP dockerfile :
FROM php:7.0-fpm
RUN usermod -u 1000 www-data
# Set timezone
RUN rm /etc/localtime
RUN ln -s /usr/share/zoneinfo/Europe/Bruxelles /etc/localtime
RUN "date"
RUN apt-get update && apt-get install -y \
git \
unzip \
libfreetype6-dev \
libjpeg62-turbo-dev \
libmcrypt-dev \
libpng12-dev \
mysql-client \
&& docker-php-ext-install -j$(nproc) iconv 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 mysqli pdo pdo_mysql mcrypt zip mbstring opcache json
# Install Xdebug / Redis
RUN pecl install redis \
&& pecl install xdebug \
&& docker-php-ext-enable redis xdebug
# Set the Drush version.
ENV DRUSH_VERSION 8.1.2
# Install Drush 8 with the phar file.
RUN curl -fsSL -o /usr/local/bin/drush "https://github.com/drush-ops/drush/releases/download/$DRUSH_VERSION/drush.phar" && \
chmod +x /usr/local/bin/drush
# Download console.
RUN curl https://drupalconsole.com/installer -L -o drupal.phar
# Install console.
RUN mv drupal.phar /usr/local/bin/drupal && \
chmod +x /usr/local/bin/drupal && \
drupal init --override
# Create drush-backups dir
RUN mkdir /var/www/drush-backups/
USER 1000
WORKDIR /var/www/html
To solve the problem I had to install Drupal Console by composer. There is certainly another solution, but it's work with it.

Resources