PHP extensions not installed / loaded / enabled, using the official PHP docker image - php

I've been trying all day long to install some PHP extensions into a custom made docker image (based on the official php:7.1.21-fpm-alpine3.8 image), but without success. I really don't know what I'm doing wrong as I was able to do the same thing in the past.
When I run docker-compose up, it seems that the images (php-fpm, nginx and mysql) are built correctly and that 3 docker containers are running.
However, when I check my phpinfo file, I can see that the extensions aren't loaded. (pdo_mysql, zip, imap and xdebug)
When I go into the php-fpm container and check the /usr/local/etc/php/conf.d directory I can see the ini files for all these extensions:
docker-php-ext-imap.ini
docker-php-ext-pdo_mysql.ini
docker-php-ext-xdebug.ini
docker-php-ext-zip.ini
my-firm.ini
The phpinfo also informs me that "Scan this dir for additional .ini files" is empty (no value)
app.dockerfile:
FROM php:7.1.21-fpm-alpine3.8
# Clean & update package manager
RUN rm -rf /var/cache/apk/* && \
rm -rf /tmp/*
RUN apk update
# Install tools
RUN apk add --no-cache ${PHPIZE_DEPS} \
imap-dev \
openssl-dev \
zlib-dev
# Install PHP extensions
RUN docker-php-ext-install pdo pdo_mysql zip
RUN docker-php-ext-configure imap --with-imap --with-imap-ssl \
&& docker-php-ext-install imap
RUN pecl install xdebug \
&& docker-php-ext-enable xdebug
# Copy configuration file(s)
COPY php-ini/my-firm.ini /usr/local/etc/php/conf.d/my-firm.ini
# Set workdir
WORKDIR /var/www
docker-compose.yml file:
version: '3'
services:
api-lumen-app:
build:
context: ./api-lumen
dockerfile: app.dockerfile
# name our image
image: my-firm/api-lumen-app-development
# set working dir
working_dir: /var/www
# bound volume for easy file sharing between host & docker container
volumes:
- ../api-lumen/:/var/www
env_file:
- .env
links:
- api-database
# can be used as DNS name to access another (external) service
container_name: api-lumen.app.my-firm.local
# environment variables
environment:
# Application
APP_ENV: ${APP_ENV}
APP_KEY: ${APP_KEY_LUMEN}
APP_DEBUG: ${APP_DEBUG}
APP_URL: ${APP_URL_LUMEN}
# Database
DB_HOST: ${DB_HOST}
DB_DATABASE: ${DB_DATABASE}
DB_USERNAME: ${DB_USERNAME}
DB_PASSWORD: ${DB_PASSWORD}
# Caching
CACHE_DRIVER: ${CACHE_DRIVER}
# Queue
QUEUE_DRIVER: ${QUEUE_DRIVER}
# Mail general
MAIL_DRIVER: ${MAIL_DRIVER}
MAIL_ENCRYPTION: ""
MAIL_FROM_ADDRESS: ""
MAIL_FROM_NAME: ""
MAIL_HOST: ""
MAIL_PORT: ""
MAIL_USERNAME: ""
MAIL_PASSWORD: ""
# Imap
IMAP_USERNAME: ${IMAP_USERNAME}
IMAP_PASSWORD: ${IMAP_PASSWORD}
IMAP_HOST: ${IMAP_HOST}
IMAP_PORT: ${IMAP_PORT}
IMAP_ENABLE_SSL: ${IMAP_ENABLE_SSL}
IMAP_VALIDATE_CERTIFICATE: ${IMAP_VALIDATE_CERTIFICATE}
IMAP_FOLDER: ${IMAP_FOLDER}
# Mail generator
MAILGENERATOR_BASE_URI: ${MAILGENERATOR_BASE_URI}
# Exact
EXACT_BASE_URI: ${EXACT_BASE_URI}
EXACT_DIVISION: ${EXACT_DIVISION}
EXACT_CLIENT_ID: ${EXACT_CLIENT_ID}
EXACT_CLIENT_SECRET: ${EXACT_CLIENT_SECRET}
# Google
GOOGLE_MAPS_BASE_URI: ${GOOGLE_MAPS_BASE_URI}
GOOGLE_MAPS_API_KEY: ${GOOGLE_MAPS_API_KEY}
GOOGLE_MAIL_BASE_URI: ${GOOGLE_MAIL_BASE_URI}
GOOGLE_MAIL_APPLICATION_NAME: ${GOOGLE_MAIL_APPLICATION_NAME}
GOOGLE_MAIL_AUTH_CONFIG: ${GOOGLE_MAIL_AUTH_CONFIG}
GOOGLE_MAIL_ACCESS_TYPE: ${GOOGLE_MAIL_ACCESS_TYPE}
GOOGLE_MAIL_PROMPT: ${GOOGLE_MAIL_PROMPT}
# The API (Lumen) Web Server
api-lumen-web:
build:
context: ./api-lumen
dockerfile: web.dockerfile
# name our image
image: my-firm/api-lumen-web-development
# set working dir
working_dir: /var/www
# bound volume for easy file sharing between host & docker container
volumes:
- ../api-lumen/:/var/www
ports:
- 8003:80
links:
- api-lumen-app
# can be used as DNS name to access another (external) service
container_name: api-lumen.web.my-firm.local
# The API Database
api-database:
# official (public) image
image: mysql:5.6.41
# named volume for persistent storage
volumes:
- dbdata:/var/lib/mysql
env_file:
- .env
ports:
- 3306:3306
# can be used as DNS name to access another (external) service
container_name: api.database.my-firm.local
# environment variables
environment:
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
# named volumes
volumes:
dbdata:
See my next post in this question for the docker-compose log, as body is limited to 30 000 chars
EDIT:
What makes it even stranger is that I've created an additional service in my docker-compose file with a dockerfile that looks more or less the same. When I check the phpinfo file for that new service, it does load the pdo_mysql?!
app.dockerfile (new service):
FROM php:7.1.21-fpm-alpine3.8
# Clean & update package manager
RUN rm -rf /var/cache/apk/* && \
rm -rf /tmp/*
RUN apk update
# Install tools
RUN apk add --no-cache ${PHPIZE_DEPS}
# Install PHP extensions
RUN docker-php-ext-install pdo pdo_mysql
RUN pecl install xdebug \
&& docker-php-ext-enable xdebug
# Copy configuration file(s)
COPY php-ini/my-firm.ini /usr/local/etc/php/conf.d/my-firm.ini
# Set workdir
WORKDIR /var/www

I've found the issue: I am loading an .env file in my docker-compose.yml file and the values in that .env file contained double-quotes. Removing the quotes fixed the issue.

Related

Dockerizing an already existing Symfony project

I am trying to automate the development of a project I am currently working on by creating a container on Docker that is composed of mysql, php and nginx to run a Symfony project. Here is my docker-compose.yml
services:
database:
container_name: database
image: mysql:8.0
command: --default-authentication-plugin=mysql_native_password
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: rapidhcm
MYSQL_USER: admin
MYSQL_PASSWORD: password
ports:
- '4306:3306'
volumes:
- ./docker/mysql:/var/lib/mysql
php:
container_name: php
build:
context: .
ports:
- '9000:9000'
volumes:
- ./rapid-backend:/var/www/public
depends_on:
- database
nginx:
container_name: nginx
image: nginx:stable-alpine
ports:
- '8080:80'
volumes:
- ./rapid-backend:/var/www/public
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
- database
And here is my Dockerfile:
FROM php:8.0-fpm
RUN apt update \
&& apt install -y zlib1g-dev g++ git libicu-dev zip libzip-dev zip \
&& docker-php-ext-install intl opcache pdo pdo_mysql \
&& pecl install apcu \
&& docker-php-ext-enable apcu \
&& docker-php-ext-configure zip \
&& docker-php-ext-install zip
WORKDIR /var/www/html
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
RUN curl -sS https://get.symfony.com/cli/installer | bash
RUN mv /root/.symfony5/bin/symfony /usr/local/bin/symfony
RUN git config --global user.email "email#email.com" \
&& git config --global user.name "Damian Kowalski"
The Dockerfile and docker-compose.yml files are in the root folder of the project, however the Symfony index.php file is situated in ./rapid-backend/public/index.php. How can I indicate that I want to serve that php file?
You would typically use only two containers: one for the database and one for the php-enabled web server.
You start from an php+apache image or an nginx image with php installed. Then you can bind-mount the web server's configuration files just as you did in your docker-compose.yaml for the nginx container.
You'd have something like this in your Dockerfile:
FROM php:8.2-apache AS production
ADD default.conf /etc/apache2/sites-available/default.conf
RUN # <...>
# Install tools and PHP dependencies
# apt-get update && \
# apt-get install -y <...> && \
# Configure docker php extensions, see image documenation on dockerhub
# docker-php-ext-configure <...> && \
# docker-php-ext-install <...> && \
# Maybe you want xdebug? In that case you'll also want to copy a .ini file
# pecl install xdebug && \
# Cleanup
# docker-php-source delete && \
# Install latest composer 2
# curl https://getcomposer.org/composer-2.phar > /usr/local/bin/composer && \
# chmod +x /usr/local/bin/composer && \
# Enable some apache mods if needed
# a2enmod rewrite headers expires xsend && \
# Some more cleanup if needed
# apt-get remove -y <...> && \
# apt-get clean
# If this image is to be used in a development environment, here you may want to create a user that you'll tell Apache to use with APACHE_RUN_USER, using the same UID as your own user on your host, so that you can bind-mount your sources in your docker-compose.yaml file without having permission issues.
# If however this is a deployment image, here you will probably want to "COPY" your source code in the image and to "RUN composer install".
with the appropriate apache configuration file default.conf that exposes your index.php (see the Symfony documentation at https://symfony.com/doc/current/setup/web_server_configuration.html for example configuration files).
Then your web server service in docker-compose.yaml could look like:
web-server:
build:
context: .
ports:
- '8080:80'
# If this is a dev environment, bind mount your source code, maybe also
# have a "user: ..." option here if you created one in the Dockerfile
volumes:
- ./rapid-backend:/var/www/public
It's a pretty open question but I hope this is a push in the right direction. Starting from here you can use docker-compose exec to run a bash shell inside your web server, and use composer to install Symfony and initialize your project.

Opening Docker container port on localhost in browser returns empty response

I'm trying to run a web project from a Docker container,
when I Dockerize the application on a macBook with an intel chip, everything runs fine and I can make a call to the Docker container. But when I run the same project, with the same setup on my M2 MacBook Air, the browser returns an empty response.
("this page isn't working" --> in Chrome)
This happens even though the containers appear to be running...
(Both containers are green lit up --> in Docker Desktop)
The container makes use of an Nginx service and a php service. The .yml file looks as below:
Docker-compose.yml
version: '3'
services:
#PHP Service
app:
build:
context: .
dockerfile: Dockerfile
image: php:8.0.6-fpm
container_name: Asset-Service
restart: unless-stopped
tty: true
environment:
SERVICE_NAME: Asset-Service
SERVICE_TAGS: dev
working_dir: /var/www
volumes:
- ./:/var/www
- ./php/local.ini:/usr/local/etc/php/conf.d/local.ini
networks:
- app-network
#Nginx Service
webserver:
image: nginx:stable
container_name: Asset-Web-Server
restart: unless-stopped
tty: true
ports:
- "8087:80"
- "4487:443"
volumes:
- ./:/var/www
- ./nginx/conf.d/:/etc/nginx/conf.d/
networks:
- app-network
#Docker Networks
networks:
app-network:
driver: bridge
#Volumes
volumes:
dbdata:
driver: local
My Dockerfile is the following, even though I don't think that this file causes the problem:
Dockerfile
FROM php:8.0.6-fpm
# Copy composer.lock and composer.json
COPY composer.lock composer.json /var/www/
# Set working directory
WORKDIR /var/www
# Install dependencies
USER root
RUN apt-get update && apt-get install -y \
mariadb-client-10.3 \
libcurl4-openssl-dev \
pkg-config \
libssl-dev \
libpng-dev \
libzip-dev \
libonig-dev \
libjpeg62-turbo-dev \
libfreetype6-dev \
locales \
zip \
jpegoptim optipng pngquant gifsicle \
vim \
unzip \
git \
curl \
nano
RUN pecl uninstall mongodb
RUN pecl install mongodb
RUN echo "extension=mongodb.so" >> /usr/local/etc/php/conf.d/mongodb.ini
# Clear cache
## RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# Install extensions
RUN docker-php-ext-install pdo_mysql mbstring zip exif pcntl
RUN docker-php-ext-configure gd --with-freetype=/usr/include/ --with-jpeg=/usr/include/
RUN docker-php-ext-install gd
#RUN docker-php-ext-enable mongodb
# Install composer
## RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Add user for laravel application
RUN groupadd -fg 1000 www
RUN id -u 1000 >/dev/null 2>&1 || useradd -u 1000 -ms /bin/bash -g www www
# Copy existing application directory contents
COPY . /var/www
# Copy existing application directory permissions
COPY --chown=www:www . /var/www
# Change current user to www
USER www
# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD ["php-fpm"]
The container logs look normal and the ports in the inspect tab show 0.0.0.0:8087 and 0.0.0.0:4487.
Is this a recurring issue with the apple silicon version of Docker,
and is there anything I can do about it?
I have already tried to replicate the issue on an Intel macBook, but got the desired result instead of the empty response.
On my M2 I tried reinstalling Docker and rebuilding the containers but this didn't seem to fix anything...
Nevermind this issue.
This problem occurred when trying to build the containers from the Desktop folder.

From which Dockerfile should composer install be called from

I need to call composer install and unsure from which Dockerfile to call it from - Dockerfile-apache or Dockerfile-php-fpm?
Should I install composer in Dockerfile-apache (and PHP CLI?) and run it from there?
Running composer install from Dockerfile-php-fpm gives me this: Composer could not find a composer.json file in /var/www/html
Docker-php-fpm
# Do we target a specific version? ie. 7.4.25?
FROM php:7.4-fpm
# Need to add zip and other extensions
RUN buildDeps=" \
libonig-dev \
libzip-dev \
libxml2-dev \
" \
&& apt-get -y update \
&& apt-get install -y $buildDeps zip libicu-dev \
&& docker-php-ext-configure intl \
&& docker-php-ext-install intl mbstring json mysqli opcache pdo pdo_mysql xml \
&& apt-get purge -y --auto-remove $buildDeps \
&& rm -r /var/lib/apt/lists/*
# Copying of base conf files
COPY docker/php-fpm/conf/php-fpm.conf /usr/local/etc
COPY docker/php-fpm/conf/php.ini-development /usr/local/etc/php/php.ini
COPY docker/php-fpm/conf/www.conf /usr/local/etc/php-fpm.d
# Install Composer.
RUN curl -sS https://getcomposer.org/installer | php \
&& mv composer.phar /usr/local/bin/ \
&& ln -s /usr/local/bin/composer.phar /usr/local/bin/composer
EXPOSE 9000
Docker-apache:
FROM httpd:2.4
# Copy config files
COPY docker/apache/conf/httpd.conf /usr/local/apache2/conf
COPY docker/apache/conf/httpd-vhosts.conf /usr/local/apache2/conf/extra
# Do something about log rotate?
# Create vhost directory
WORKDIR /var/www/html
#Set our application folder as an environment variable
ENV APP_HOME /var/www/html
#copy files
COPY bin ${APP_HOME}/bin
COPY config ${APP_HOME}/config
COPY plugins ${APP_HOME}/plugins
COPY src ${APP_HOME}/src
COPY webroot ${APP_HOME}/webroot
COPY .htaccess ${APP_HOME}
COPY index.php ${APP_HOME}
COPY composer.json ${APP_HOME}
COPY composer.lock ${APP_HOME}
Edit #1
docker-compose.yml
version: "3.2"
services:
php-fpm:
container_name: php-fpm
build:
context: .
dockerfile: Dockerfile-php-fpm
networks:
- backend
ports:
- "9000:9000"
apache:
container_name: httpd
build:
context: .
dockerfile: Dockerfile-apache
depends_on:
- php
networks:
- frontend
- backend
ports:
- "80:80"
- "443:443"
networks:
frontend:
backend:
Edit #2
This docker-compose file enables the communication via a common volume. I just need to compile, build and copy the files in Apache at this point.
version: "3.9"
services:
php-fpm:
container_name: php-fpm
build:
context: .
dockerfile: Dockerfile-php-fpm
volumes:
- mydata:/var/www/html:rw
networks:
- backend
ports:
- "9000:9000"
apache:
container_name: httpd
build:
context: .
dockerfile: Dockerfile-apache
depends_on:
- php
volumes:
- mydata:/var/www/html:rw
networks:
- frontend
- backend
ports:
- "80:80"
- "443:443"
networks:
frontend:
backend:
volumes:
mydata:
I would go with neither of the above; instead, run composer install locally and copy the resulting vendor directory as part of your application.
Fetching dependencies is fundamentally part of building an application, not part of running it, so Composer shouldn't even be installed on a production host or container. If you were writing a C application which needed to be compiled with gcc, you would run that as an earlier step, and then copy the binary into the container; composer install can be treated the same way.
So for instance, you might have a build script (to run manually, or in a CI server like Jenkins, Github Actions, Azure DevOps, etc) that went through the following steps:
Clone the repo from a git repository
Check out the latest tag
Run composer install
Run a script to minify the client-side JS
Run docker-composer, copying the source code, minified JS, and vendor directory
The software inside the Docker container therefore only needs to be able to run the application, not build it.

Why caddy + php-fpm configuration in docker-compose doesn't work?

I'm trying to set up a development environment on my local machine which consists of caddy + PHP.
docker-compose.yaml:
version: '3'
services:
app:
build:
context: .
container_name: app
restart: unless-stopped
tty: true
environment:
SERVICE_NAME: app
SERVICE_TAGS: dev
volumes:
- ./:/var/www
- ./docker/php/local.ini:/usr/local/etc/php/conf.d/local.ini
webserver:
image: caddy
container_name: webserver
restart: unless-stopped
tty: true
ports:
- "80:80"
- "443:443"
volumes:
- ./:/srv
- ./docker/caddy/Caddyfile/:/etc/caddy/Caddyfile
db:
image: mysql:8.0
container_name: db
restart: unless-stopped
tty: true
ports:
- "3306:3306"
environment:
MYSQL_USER: pingr
MYSQL_DB: pingr
MYSQL_PASSWORD: pingr
MYSQL_RANDOM_ROOT_PASSWORD: 'yes'
volumes:
- dbdata:/var/lib/mysql
volumes:
dbdata:
driver: local
Dockerfile for app service:
FROM php:7.4-fpm
# Copy composer.lock and composer.json
COPY composer.lock composer.json /var/www/
# Set working directory
WORKDIR /var/www
# Install dependencies
RUN apt-get update && apt-get install -y \
build-essential \
libpng-dev \
libjpeg62-turbo-dev \
libfreetype6-dev \
locales \
zip \
jpegoptim optipng pngquant gifsicle \
vim \
unzip \
git \
curl \
libzip-dev \
libicu-dev
# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# Install extensions
RUN docker-php-ext-install pdo_mysql zip exif pcntl intl
RUN docker-php-ext-configure gd --with-freetype --with-jpeg
RUN docker-php-ext-install gd
# Install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Add user for laravel application
RUN groupadd -g 1000 www
RUN useradd -u 1000 -ms /bin/bash -g www www
# Copy existing application directory contents
COPY . /var/www
# Copy existing application directory permissions
COPY --chown=www:www . /var/www
# Change current user to www
USER www
# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD ["php-fpm"]
Caddyfile:
:80 {
root * /srv/public
php_fastcgi app:9000
file_server /uploads/*
encode gzip zstd
}
This results in "File not found" when I open http://localhost.
I'm 100% sure that the problem is because root in caddyfile and volumes in app and webserver serivces are different.
When I make them the same, looks like it works. Moreover, it even doesn't matter which path I choose, I can have /var/bar for example.
But then I don't understand how it works.
In caddy image they say that the working directory is /srv. So as I get it, this is where site files should be placed.
In the Caddyfile I specify that Caddy should look at /srb/public (because I use Laravel)..
In the php-fpm image, they say that the working directory is /var/www. Which means that.. I'm not sure what does it mean. If I don't use Docker, then in my local machine I'd have caddy + php, only caddy "knows" where the source .php files are located. In case the requests asks for a .php file Caddy proxies it to php. Maybe I don't need a volume here at all?

How to enable LDAP on a dockerized Wordpress?

I have this container that I ran with a docker-compose.yml file.
version: '3'
services:
db:
<...>
wordpress:
depends_on:
- db
image: wordpress:latest
ports:
- "8000:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
I need to enable LDAP on PHP but I really can't find out how to complete the steps explained in the tutorial.
You will need to use the --with-ldap[=DIR] configuration option when
compiling PHP to enable LDAP support.
How am I supposed to do this on a running container ? Should this be done before running docker-compose up if so, which environment configuration am I supposed to use ?
You just have to use a different image as it's not easily configurable using the original image.
Have a look at dalareo/docker-wordpress-ldap-support on GitHub. You might use this Dockerfile by downloading it to the directory your project would be stored in and make a small change to your docker-compose.yml like here:
version: '3'
services:
db:
<...>
wordpress:
depends_on:
- db
# remove: image: wordpress:latest and put this instead:
build: .
# and place the rest of the definitions you normally have there
The Dockerfile copied from the repo:
FROM wordpress
RUN set -x \
&& apt-get update \
&& apt-get install -y libldap2-dev \
&& rm -rf /var/lib/apt/lists/* \
&& docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu/ \
&& docker-php-ext-install ldap \
&& apt-get purge -y --auto-remove libldap2-dev
edit
I've found a public registry image build from this Dockerfile
Now you don't actually have to make any changes to your original docker-compose.yml file except for changing the image your wordpress is expected to run from. From wordpress:latest to dalareo/wordpress-ldap

Categories