Docker containers - LAMP stack to host a site with SQL and PHP
Introduction
Example of a LAMP stack to host a website
Introduction
Docker is set of technogies that allows us to run applications. It uses images that are built according to docker-compose.yml
. These images are deployed to containers, each including the software needed to run a web server, database, etc..
Dockerfile → (Build) → Image → (Run) → Container.
-
Dockerfile: contains a set of Docker instructions that installs and configures the software you specify.
-
Image: compiled Dockerfile. It saves you time from rebuilding the Dockerfile every time you need to run a container. The Docker registry has official images that you can use to build your own images. You can use many images to build your own.
-
Container: an image that is instantiated, a running environment, similar to an application that is executed (Notepad, for example).
It can have one of the states:created
,restarting
,running
,removing
,paused
,exited
, ordead
.
You canssh
into it and run commands, as if it were a real environment. You can run multiple containers from the same image.
You can install it for linux as per this link.
Basics
To specify docker commands, we use the command docker
with a verb.
After installing docker, we can check it with docker version
:
$ docker version
Client: Docker Engine - Community
Version: 27.5.1
API version: 1.47
Go version: go1.22.11
Git commit: 9f9e405
Built: Wed Jan 22 13:41:17 2025
OS/Arch: linux/amd64
Context: default
To see a list of running containers for example, we use docker ps
:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
85c98fc70491 my_project-nginx "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:80->80/tcp, :::80->80/tcp learn-ngnix
38507900c54c my_project-phpmyadmin "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:81->80/tcp, [::]:81->80/tcp learn-phpmyadmin
01a2a2c56113 my_project-php "docker-php-entrypoi…" 2 hours ago Up 2 hours 9000/tcp learn-php
26884c23deeb my_project-mariadb "docker-entrypoint.s…" 2 hours ago Up 2 hours 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp learn-mariadb
If there are no containers currently running, the list will be empty:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
We can list all containers by using:
docker ps -a
We can get more information on a docker command by adding the --help
parameter:
$ docker ps --help
Usage: docker ps [OPTIONS]
List containers
Aliases:
docker container ls, docker container list, docker container ps, docker ps
Options:
-a, --all Show all containers (default shows just running)
-f, --filter filter Filter output based on conditions provided
If we have built docker images, we can list them with docker image ls
:
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
my_project-nginx latest 5ee111c65203 4 hours ago 267MB
my_project-phpmyadmin latest 4463e2b475b7 4 hours ago 589MB
my_project-php latest 54e3df9f5159 4 hours ago 522MB
my_project-mariadb latest 6a08ad620c9c 4 hours ago 402MB
Example of a LAMP stack to host a website
Files need are here
Below we will set up multiple containers, each hosting its own software (web server, SQL server, PHP web scripting language, phpmyadmin
to manage SQL databases and run queries).
We will have a main compose.yml
file, in which we will specify four services, one for each piece of software specified above.
It is used to define services, networks, and volumes for a Docker application.
Each service will include its own dockerfile
, for installing the software; it will keep the main compose.yml
less cluttered.
The docker-compose.yml
or compose.yml
file is used to define and run multi-container Docker applications.
Let’s list the files we will be using. Create a folder, for example my_project
. In it should be the files:
compose.yml
config.inc.php
Dockerfile.mariadb
Dockerfile.nginx
Dockerfile.php
Dockerfile.phpmyadmin
Create a subfolder in the my_project
folder, name it html
. In it we will be adding the web server config file, and some php
files to test the server’s functionality.
index.php
mariadb.php
nginx.conf
test.php
Let’s analyse a section of compose.yml
.
services:
nginx:
container_name: learn-ngnix
build:
context: .
dockerfile: Dockerfile.nginx
hostname: nginx-host
ports:
- "80:80" # host port:container port
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
- mariadb
- phpmyadmin
This section defines the service nginx
. We:
- define the container name with
container_name
- include the
dockerfile
located in thecontext
folder (.
means current folder); for addional software and configuration - give a name to the host in the running container via
hostname
- map container ports to ports on the host (host - the machine on which you installed docker; your laptop, for example).
- define a volume in the
volume
section; a volume is a persistent data store for containers - add the
depends_on
section; thenginx
service starts only after first starting the services it depends on (php
,mariadb
,phpmyadmin
)
The next section in compose.yml
is for the php
web scripting language.
We add a volume
section, meaning that the subfolder html
will be mapped to the /var/www/html
folder, where the web server expects by default the home page and other pages.
php:
container_name: learn-php
build:
context: .
dockerfile: Dockerfile.php
hostname: php-host
volumes:
- ./html:/var/www/html
The Dockerfile.nginx
file installs the lastest nginx
web server from the Docker registry (notice the FROM
section).
In the RUN
section it installs telnet
and ping
to test network connectivity from the container.
# Dockerfile.nginx
FROM nginx:latest
RUN apt-get update && \
apt-get install -y iputils-ping telnet mc && \
rm -rf /var/lib/apt/lists/*
For the SQL server we map its database folder /var/lib/mysql
to a volume named db_data
.
We also can add passwords in the environment
section for SQL:
mariadb:
container_name: learn-mariadb
build:
context: .
dockerfile: Dockerfile.mariadb
hostname: mariadb-host
ports:
- "3306:3306" # Expose MariaDB port
environment:
MYSQL_ROOT_PASSWORD: root_password
MYSQL_DATABASE: my_database
MYSQL_USER: user
MYSQL_PASSWORD: user_password
volumes:
- db_data:/var/lib/mysql
The Dockerfile.mariadb
gets the latest SQL server from the Docker registry; it also installs the same software as for the nginx
file:
# Dockerfile.mariadb
FROM mariadb:latest
RUN apt-get update && \
apt-get install -y iputils-ping telnet mc && \
rm -rf /var/lib/apt/lists/*
To build and run the images as containers, use the command below, -d
parameter will return to the terminal.
docker compose up --build -d
To run the images, use docker compose up -d
.
You can specify the -f
parameter with the yaml
file to instantiate containers from a different file.
Docker will look for files namedcompose.yml/.yaml
, docker-compose.yml/.yaml
by default.
$ docker compose -f compose.yml up -d
[+] Running 4/4
✔ Container learn-mariadb Started 0.4s
✔ Container learn-php Started 0.4s
✔ Container learn-phpmyadmin Started 0.6s
✔ Container learn-ngnix Started
To stop the containers, use:
docker compose down
To list the running containers:
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bfe463eae3cd my_project-nginx "/docker-entrypoint.…" 57 minutes ago Up 57 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp learn-ngnix
b88806ecfd10 my_project-phpmyadmin "/docker-entrypoint.…" 57 minutes ago Up 57 minutes 0.0.0.0:81->80/tcp, [::]:81->80/tcp learn-phpmyadmin
30c10b0239f1 my_project-mariadb "docker-entrypoint.s…" 57 minutes ago Up 57 minutes 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp learn-mariadb
4dc9e61ede95 my_project-php "docker-php-entrypoi…" 57 minutes ago Up 57 minutes 9000/tcp learn-php
We can customise the columns:
$ docker container ls --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
NAMES STATUS PORTS
learn-ngnix Up About an hour 0.0.0.0:80->80/tcp, :::80->80/tcp
learn-phpmyadmin Up About an hour 0.0.0.0:81->80/tcp, [::]:81->80/tcp
learn-mariadb Up About an hour 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp
learn-php Up About an hour 9000/tcp
To connect to a container, use docker exec
, the -it
parameter runs an interactive session, bash
shell is executed:
$ docker exec -it learn-mariadb bash
root@mariadb-host:/# ls
bin boot docker-entrypoint-initdb.d home lib.usr-is-merged media opt root sbin srv tmp var
bin.usr-is-merged dev etc lib lib64 mnt proc run sbin.usr-is-merged sys usr
To see logs for a container, use docker logs
:
$ docker logs learn-mariadb
2025-02-17 20:28:16+00:00 [Note] [Entrypoint]: Entrypoint script for MariaDB Server 1:11.7.2+maria~ubu2404 started.
2025-02-17 20:28:17+00:00 [Warn] [Entrypoint]: /sys/fs/cgroup/et_cls:/
0:://memory.pressure not writable, functionality unavailable to MariaDB
2025-02-17 20:28:17+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2025-02-17 20:28:17+00:00 [Note] [Entrypoint]: Entrypoint script for MariaDB Server 1:11.7.2+maria~ubu2404 started.
ls -las $(docker volume inspect my_project_db_data | grep Mountpoint | cut -d\" -f 4)