Can a Dockerfile extend another one? - docker

I have a Dockerfile for PHP like this :
FROM php:7-fpm
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update && \
apt-get install -y git libicu-dev libmagickwand-dev libmcrypt-dev libcurl3-dev jpegoptim
RUN pecl install imagick && \
docker-php-ext-enable imagick
RUN docker-php-ext-install intl
RUN docker-php-ext-install pdo_mysql
RUN docker-php-ext-install opcache
RUN docker-php-ext-install mcrypt
RUN docker-php-ext-install curl
RUN docker-php-ext-install zip
And I'd like to create another Dockerfile, based on the first one, but with some PHP extensions added (for dev purpose) : Xdebug and other stuffs.
Can I create a "dev" Dockerfile that extends my main Dockerfile (without rewrite it) ?

Using multi-stage build is definitely one part of the answer here.
docker-compose v3.4 target being the second and last.
Here is a example to have 2 containers (1 normal & 1 w/ xdebug installed) living together :
Dockerfile
FROM php:7-fpm AS php_base
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update && \
apt-get install -y git libicu-dev libmagickwand-dev libmcrypt-dev libcurl3-dev jpegoptim
RUN pecl install imagick && \
docker-php-ext-enable imagick
RUN docker-php-ext-install intl
RUN docker-php-ext-install pdo_mysql
RUN docker-php-ext-install opcache
RUN docker-php-ext-install mcrypt
RUN docker-php-ext-install curl
RUN docker-php-ext-install zip
FROM php_base AS php_test
RUN pecl install xdebug
RUN docker-php-ext-enable xdebug
docker-compose.yml
version: '3.4'
services:
php:
build:
context: ./
target: php_base
php_test:
build:
context: ./
target: php_test
# ...

If you don't want to tag your first Dockerfile in order to use it in a FROM instruction in your next Dockerfile, and you are using Docker 20.10+, you can also do this:
# syntax = edrevo/dockerfile-plus
INCLUDE+ Dockerfile.base
RUN whatever
The INCLUDE+ instruction gets imported by the first line in the Dockerfile. You can read more about the dockerfile-plus at https://github.com/edrevo/dockerfile-plus

That is exactly what your FROM php:7-fpm is doing: extending the Dockerfile from the php image (with 7-fpm tag) with the contents of your Dockerfile.
So after building an image from your Dockerfile:
docker build -t my-php-base-image .
You can extend that by creating a new Dockerfile that starts with:
FROM my-php-base-image

Related

Docker- .sh file not found in path

In my new Symfony application, I am trying to run docker-compose build when I get an error:
In my root bin folder I have the file from the error message. I am starting to question if this is a path problem? Can someone please help? Maybe it is something wrong with volume definition in the docker file I posted below.
RUN /var/www/html/bin/app_build.sh:
#19 0.164 /bin/sh: 1: /var/www/html/bin/app_build.sh: not found
version: "3.9"
services:
app-www:
container_name: app-www
hostname: app-www
restart: unless-stopped
entrypoint: apache2-foreground
build:
context: .
args:
ENVIRONMENT: local
volumes:
- ./www:/var/www/html
- ./.docker/.ssh:/root/.ssh
- ./www/node_modules:/var/www/html/node_modules:rw,cached
- ./www/vendor:/var/www/html/vendor:rw,cached
ports:
- "8080:80"
- "8081:443"
depends_on:
- redis
redis:
image: redis:6.2-alpine
restart: always
ports:
- '6363:6379'
command: redis-server --save 20 1 --loglevel warning
volumes:
- cache:/data
volumes:
cache:
driver: local
and dockerfile
FROM php:7.4-apache
ENV TZ="Europe/Zurich"
ARG COMPOSER_TOKEN
ENV COMPOSER_TOKEN=${COMPOSER_TOKEN}
# Debian Packages
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get --yes --no-install-recommends install libxml2-dev libgmp-dev zip npm zlib1g-dev libpng-dev libonig-dev git unzip tzdata \
&& npm install --global yarn
# PHP Extensions
RUN docker-php-ext-install soap bcmath gmp pdo pdo_mysql intl opcache gd json mbstring gmp \
&& docker-php-ext-enable soap bcmath gmp pdo pdo_mysql intl opcache gd json mbstring gmp \
&& pecl install xdebug \
&& pecl install redis \
&& docker-php-ext-enable xdebug redis
# Install composer
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
RUN mkdir /root/.composer && echo "${COMPOSER_TOKEN}" > /root/.composer/auth.json
# Configure PHP
COPY ./config/docker/php/php.ini /usr/local/etc/php/php.ini
# Configure Apache
RUN a2enmod headers
RUN a2enmod rewrite
RUN a2enmod ssl
RUN rm -rf /etc/apache2/sites-enabled/* /etc/apache2/sites-available/
COPY ./config/docker/apache2/breitling.conf /etc/apache2/sites-enabled
COPY ./config/docker/apache2/ssl/ /etc/apache2/ssl/
# Deploy & Build app
COPY . /var/www/html/
RUN /var/www/html/bin/app_build.sh
# Fix permissions
RUN chmod -R 777 /var/www/html/var/
EXPOSE 80 443
ENTRYPOINT /var/www/html/bin/entrypoint.sh
I am not sure what is wrong as this is the main config for my project. And I am running it on MacOs.
After looking into these lines:
COPY . /var/www/html/
RUN /var/www/html/bin/app_build.sh
I would expect that inside path /var/www/html/ there is again www directory.
My guess is that you need only the contents of the www dir copied into the docker image. Then your copy command should look like this:
COPY ./www/ /var/www/html/
Give it a shot :-)

Dockerfile COPY command puts an empty file in its container when overwriting another file

When copying files from host machine to container where a file already exists at the destination path, the copied file is empty.
I've attempted to copy the same files to a path with a different name and this works fine.
The two lines from my dockerfile that this issue happens on are:
COPY conf/policy.xml /etc/ImageMagick-6/
COPY conf/000-default.conf /etc/apache2/sites-available/
Full dockerfile:
FROM php:7.3-apache
RUN docker-php-ext-install pdo_mysql && docker-php-ext-enable pdo_mysql
RUN docker-php-ext-install mysqli && docker-php-ext-enable mysqli
RUN apt-get update && apt-get install -y \
git libmagick++-dev \
--no-install-recommends && \
git clone https://github.com/mkoppanen/imagick.git && \
cd imagick && git checkout master && phpize && ./configure && \
make && make install && \
docker-php-ext-enable imagick && \
cd ../ && rm -rf imagick && \
apt-get install -y ghostscript && rm -r /var/lib/apt/lists/*
RUN pecl install xdebug
RUN docker-php-ext-enable xdebug
COPY conf/php.ini /etc/php/7.3/fpm/conf.d/40-custom.ini
COPY conf/policy.xml /etc/ImageMagick-6/
COPY www/ /var/www/html/
COPY conf/000-default.conf /etc/apache2/sites-available/
COPY scripts/generate-ssl.sh /generate-ssl.sh
RUN chmod +x /generate-ssl.sh
RUN /bin/bash /generate-ssl.sh
EXPOSE 80 443
Is this intended behavior ?
From Docker Documentation - Docerfile Copy:
COPY src dest: If src is any kind of file, it is copied individually along with its metadata. In this case, if ends with a trailing slash /, it will be considered a directory and the contents of will be written at /base().
For your case try and specifiy the dest file:
COPY conf/policy.xml /etc/ImageMagick-6/policy.xml
COPY conf/000-default.conf /etc/apache2/sites-available/000-default.conf
Otherwise i dont see anything wrong with your dockerfile

dockerfile not updating container

I'm working with an app using docker (i'm not super familiar) and I need to add 2 new PHP extensions. I have changed the Dockerfile on an existing image as follows:
FROM php:7.2-fpm
RUN apt-get update
RUN apt-get install -y git unzip
RUN php -r "readfile('http://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer
RUN apt-get install -y git libpng-dev \
&& docker-php-ext-install gd
RUN apt-get install -y mysql-client \
&& docker-php-ext-configure pdo_mysql --with-pdo-mysql=mysqlnd \
&& docker-php-ext-install pdo_mysql
RUN apt-get install -y libgmp-dev bcmath \
&& docker-php-ext-configure gmp \
&& docker-php-ext-install gmp \
&& docker-php-ext-install bcmath
RUN pecl install xdebug \
&& docker-php-ext-enable xdebug
ADD docker/templates/usr/local/etc/php/conf.d/uploads.ini /usr/local/etc/php/conf.d/uploads.ini
My new lines are:
RUN apt-get install -y libgmp-dev bcmath \
&& docker-php-ext-configure gmp \
&& docker-php-ext-install gmp \
&& docker-php-ext-install bcmath
I tried docker-compose restart, I tried docker-compose down followed by docker-compose up, I removed the container entirely and re-created with up. However hard I try, I always get this error when doing a composer require
the requested PHP extension bcmath is missing from your system.
I'm not sure why this is happening. Why won't the extension install, and how come if I completely delete the contents and write garbled text in the Dockerfile, it always runs successfully. Is it caching it?
Can somebody explain how I'd re-provision with the new changes I made?
Snippet of docker-compose.yml:
services:
web:
build:
context: ./
dockerfile: docker/web.docker
working_dir: /var/www
volumes:
- ./:/var/www
ports:
- 81:80
app:
build:
context: ./
dockerfile: docker/app.docker
working_dir: /var/www
volumes:
- ./:/var/www
environment:
- "LARAVEL_ENVIRONMENT=local"
You need to rebuild the image
docker-compose build
and next re-run containers
docker-compose up -d

Start Nginx from php fpm image automatically

I have the following Dockerfile
FROM php:7.2-fpm
LABEL maintainer="youri#smilinggents.nl"
RUN apt-get update && \
apt-get install -y nginx git zip
COPY default.conf /etc/nginx/conf.d/default.conf
RUN apt-get update && \
apt-get install -y libpng-dev libxml2-dev libcurl3-dev libcurl4-openssl-dev && \
docker-php-ext-install gd && \
docker-php-ext-install soap && \
docker-php-ext-install pdo_mysql && \
docker-php-ext-install intl && \
docker-php-ext-install zip
RUN curl -sS https://getcomposer.org/installer | php && mv composer.phar /usr/local/bin/composer
WORKDIR /var/www/pidz/
RUN mkdir ./var/
COPY ./app app
COPY ./bin bin
COPY ./src src
COPY ./web web
COPY ./composer.json composer.json
COPY ./composer.lock composer.lock
ARG SSH_PRIVATE_KEY
# some ssh stuff I perform
RUN export SYMFONY_ENV=staging && \
composer install
EXPOSE 80
When I build the Dockerfile
docker build . --build-arg SSH_PRIVATE_KEY="$(cat ~/.ssh/id_rsa)"
And run the image
docker run -p 80:80 <image>
Nginx is not running, but when I run nginx inside the container Nginx is started
How can I make Nginx starting automatically?
Because you don't start the nginx.
docker run -p 80:80 <image> -d nginx
or you can add CMD ["/usr/sbin/nginx", "-g", "daemon off;"] official Dockerfile end of the Dockerfile then when u run the image it will automatically will start

docker run vs. docker-compose up: same image, different outcome

TL;DR Using the same image, I get different results on running docker run and docker-compose up.
I am using the official php docker image and I want to install a set of extensions. Here is my Dockerfile:
FROM php:7.1.2-fpm
# Install software and dependencies (for extensions)
RUN apt-get update \
&& apt-get install -qy \
libcurl4-gnutls-dev \
libpng-dev \
libicu-dev \
mcrypt \
libmcrypt-dev \
libxml2-dev \
libfreetype6-dev \
libjpeg62-turbo-dev \
libpng12-dev \
git \
nodejs
# Install required PHP extensions
RUN 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-enable gd
# Install and setup composer
RUN curl -sS https://getcomposer.org/installer | php \
&& mv composer.phar /usr/local/bin/composer
# Cleanup tasks
RUN apt-get clean
As you see I am trying to install the gd library. This is actually taken from their example. On running docker build I see that it runs the configure and install steps (Step 3/5):
Step 1/5 : FROM php:7.1.2-fpm
---> 7191c638ed10
Step 2/5 : RUN apt-get update && apt-get install -qy libcurl4-gnutls-dev libpng-dev libicu-dev mcrypt libmcrypt-dev libxml2-dev libfreetype6-dev libjpeg62-turbo-dev libpng12-dev git nodejs
---> Using cache
---> 1f53f9211603
Step 3/5 : RUN 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-enable gd
---> Using cache
---> 4598a07d9fca
Step 4/5 : RUN curl -sS https://getcomposer.org/installer | php && mv composer.phar /usr/local/bin/composer
---> Running in 89c18c9ddf40
All settings correct for using Composer
Downloading...
Composer (version 1.4.0) successfully installed to: /var/www/html/composer.phar
Use it: php composer.phar
---> 059a1da3bb1a
Removing intermediate container 89c18c9ddf40
Step 5/5 : RUN apt-get clean
---> Running in 66c9cb68f684
---> f9543fa8b6e3
Removing intermediate container 66c9cb68f684
Successfully built f9543fa8b6e3
When I now do a plain docker run and ssh into the machine, the gd extension is available:
$ php -m
[PHP Modules]
Core
ctype
curl
date
dom
fileinfo
filter
ftp
gd
hash
iconv
json
libxml
mbstring
mysqlnd
openssl
pcre
PDO
pdo_sqlite
Phar
posix
readline
Reflection
session
SimpleXML
SPL
sqlite3
standard
tokenizer
xml
xmlreader
xmlwriter
zlib
[Zend Modules]
Now, here is the interesting part: When I build (docker build) the image and then run the container with docker-compose up, the extension is not installed.
I narrowed it down to docker-compose up being the problem, as I did a lot of diffent things:
docker-compose build {servicename} + docker run {image-ID} --> extension availabe
removed all running containers and images, removed all docker-compose images (docker-compose down)
tried it with remote registry, using dockerfile, even building the image and then entering the local image in the docker-compose.yml --> same result
UPDATE
My docker-compose.yml:
version: '2'
services:
php:
# this is the variant with the registry
image: registry.example.com/devops/php:base-php-fpm
volumes:
- './src:/code'
- './config/php:/usr/local/etc/php'
links:
- mysql
depends_on:
- mysql
nginx:
image: nginx:1.10
ports:
- "80:80"
volumes:
- './src:/code'
- './config/nginx:/etc/nginx'
depends_on:
- php
links:
- php
mysql:
image: mysql
ports:
- "3306:3306"
Turns out it is the volume mount of the config file into the config folder of php - can only be found in my compose file. It overwrites the auto-generated config of PHP.
One of these things that keep you busy the whole day without delivering the tiniest piece of functionality...
Thanks for your help, guys!

Resources