This post is using the default docker files that have already been pre-defined, the second post will use an alpine mini root file system as a base and then add on the additional packages for each part of this setup.
Folder listings
My folder listing for the below.
./nginx:
conf.d Dockerfile nginx.conf sites
./nginx/conf.d:
default.conf
./nginx/sites:
default.conf
./php-fpm:
Dockerfile xdebug.ini
(extras are for the logs / postgres volumne mounted data)
./logs
./posgtres-data
Enviornment file
To start with, I like to create a env(ironment) file that will denote internal settings used within the docker file builds. This file below will denote the php version that I wish to use and also since we are using php-fpm in this development environment, then might as well enable xdebug as well.
Below is the local.env — please save as that as well, shall include a git repo below.
PHP_VERSION=8.0
POSTGRES_PASSWORD= example
POSTGRES_USER= postgres
PGADMIN_DEFAULT_PASSWORD= example
PGADMIN_DEFAULT_EMAIL=ian@codingfriends.com
XDEBUG_PORT=9000
This starts of with the PHP version, follows onto the postgres default details with also the PGADMIN default login details with the tail of the environment details having the xdebug_port defined.
Docker-composer file
The next part is the docker-composer file, this describes how the containers will either rely on each other (depends_on within the docker composer file) networks to use and also the ports to expose. As a side thing, I always found the ports to be funny way around so it is <outside of the container>:<internal to the container> so port 8080:80 will expose the interal port 80 (websites that aren’t using SSL run on this port for example) to the outside world on port 8080 e.g. to host you can do http://localhost:8080 to view the containers port 80 service.
Also, if you are not altering the base docker files that are being pulled down from the docker repo (shall do another post about altering this to a local repo or AWS ECS) then there is no build descriptions akin to the db container description below, but for php-fpm / nginx there are some extra build steps required for this demo hence the Dockerfile(s) in those areas.
# Use postgres/example user/password credentials
version: '3.1'
services:
db:
image: postgres
restart: always
hostname: postgresDB
container_name: postgresDB
environment:
POSTGRES_PASSWORD: $POSTGRES_PASSWORD
POSTGRES_USER: $POSTGRES_USER
volumes:
- ./postgres-data:/var/lib/postgresql/data
ports:
- 5432:5432
networks:
- iKnowNW
pgdamin4:
image: dpage/pgadmin4
hostname: pgadmin4
container_name: pgadmin4
depends_on:
- db
restart: always
environment:
PGADMIN_DEFAULT_PASSWORD: $PGADMIN_DEFAULT_PASSWORD
PGADMIN_DEFAULT_EMAIL: $PGADMIN_DEFAULT_EMAIL
ports:
- 8080:80
networks:
- iKnowNW
php-fpm:
build:
context: ./php-fpm
args:
- PHP_VERSION=${PHP_VERSION}
- XDEBUG_PORT=${XDEBUG_PORT}
depends_on:
- db
environment:
- XDEBUG_CONFIG=client_port=${XDEBUG_PORT}
volumes:
- ../src:/var/www
- ./logs:/var/logs
- ./php-fpm/xdebug.ini:/usr/local/etc/php/conf.d/xdebug.ini
networks:
- iKnowNW
nginx:
build:
context: ./nginx
volumes:
- ../src:/var/www
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/conf.d/:/etc/nginx/conf.d
- ./nginx/sites/:/etc/nginx/sites-available
- ./logs:/var/log
depends_on:
- php-fpm
ports:
- 8081:80
networks:
- iKnowNW
networks:
iKnowNW:
driver: bridge
PHP-FPM
So the main things are within the php-fpm confirguration above
args:
– PHP_VERSION=${PHP_VERSION})
environment:
– XDEBUG_CONFIG=client_port=${XDEBUG_PORT}
Both of these are import, because they will pass details (arguments / enviornment variables) to the php-fpm DockerFile build process, so lets start with that — below is the php-fpm Dockerfile
ARG PHP_VERSION
ARG XDEBUG_PORT
FROM php:${PHP_VERSION}-fpm-alpine
RUN apk --update --no-cache add git postgresql-dev
RUN apk add --no-cache $PHPIZE_DEPS
RUN pecl install xdebug
RUN docker-php-ext-install pdo pdo_pgsql
RUN docker-php-ext-enable xdebug
WORKDIR /var/www
EXPOSE ${XDEBUG_PORT}
So the ARG variable is what was passed in from the docker-composer file within this instance it would be 8.0 denoting the php version to use. Also with exposing the xdebug port to the outside world of the container.
Additional xdebug settings are included in the xdebug.ini file below, this will be “copied” into the container during the build process.
xdebug.start_with_request=yes
xdebug.mode=debug
xdebug.log=/var/logs/xdebug/xdebug.log
xdebug.discover_client_host=1
Nginx
This one is the biggest folder, as the following steps will take place
- Insert the nginx.conf file — this is the service configuration — into the container
- Insert the default site configuration that uses the php-fpm container using the fast cgi protocol.
- Insert the configuration of the php-upstream of the php-fpm container
Lets start with the nginx.conf file, it just describes the nginx service with connections / logs and where the http configurations are placed etc.
user nginx;
worker_processes 4;
daemon off;
error_log /var/log/nginx/error.log debug;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
sendfile on;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-available/*.conf;
}
The default.conf is the default site, as from above it is placed into the /etc/nginx/sites-available folder.
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name localhost;
root /var/www/public;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
try_files $uri /index.php =404;
fastcgi_pass php-upstream;
fastcgi_index index.php;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_read_timeout 600;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}
The most important part here is the “root” key value pair above, this is where the local php folder needs to be mounted for the site to work.
The last part is php-fpm upstream service (conf.d/default.conf)
upstream php-upstream {
server php-fpm:9000;
}
Literally, the php-fpm value above matches the container name from the docker-compose file above.
And then the actually Dockerfile is very small!!
FROM nginx:alpine
WORKDIR /var/www
CMD ["nginx"]
EXPOSE 80
Literally describing where to get the nginx base container from e.g. nginx repository with the tag of alpine. Then define the WORKDIR (working directory) for where a container is “cd” into for the command (CMD) to be executed.
Final part!
Create the subdirectories
- logs
- postgres-data
To store the containers data that isn’t lost after the container has been stopped / killed (containers are in theory ephemeral — short existence)
Last step is to run the build process and then view your code that you have within your ../src directory (this is where the PHP hosting code will be — I am using the a sub folder within there called public e.g. ../src/public/ will be where the website viewable code controllers etc after a symfony creation script)
To view the PGADMIN page — just goto http://localhost:8080/
To view the PHP hosting code — just goto http://localhost:8081/
Have fun — if there are any issues, please contact me!! but here is my start.sh script to either build /run the container setup above.
#/bin/bash
## place your local enviornment file name here
ENV=local.env
case "$1" in
start)
echo "STARTING"
docker-compose --env-file=$ENV -f docker-compose.yml up
;;
stop)
echo "STOPPING"
docker-compose --env-file=$ENV -f docker-compose.yml down
;;
restart)
$0 stop
$0 start
;;
rebuild)
echo "REBUILD"
docker-compose --env-file=$ENV -f docker-compose.yml up --build
;;
upgarde)
echo "UPGRADING CONTAINERS"
docker-compose pull
;;
*)
echo "Usage: $0 {start|stop|rebulid|upgrade}"
esac
exit 0