DEV Community

Cover image for PHP + MySQL using Docker Compose
Aly Sivji
Aly Sivji

Posted on • Originally published at alysivji.github.io

PHP + MySQL using Docker Compose

This post was originally published on Siv Scripts

Being a Software Engineer isn't just about being effective in a specific programming language, it's about being able to solve any given problem using the tools at hand.

This week at work I have to extend the functionality of a WordPress plug-in so it can fit into our microservices-based backend architecture. This means learning enough PHP to write some production-grade code.

I don't want to install PHP on my local machine so this is the perfect use case for Docker! In this Quick Hit, I will describe how to create a containerized PHP + MySQL development environment using Docker Compose.

The LAMP Stack is back!


Instructions

  • We'll start by creating a folder for this project:

    mkdir lamp-stack && cd lamp-stack

  • Create another subdirectory, /php which contains the following index.php file:

<!-- ./php/index.php -->

<html>
    <head>
        <title>Hello World</title>
    </head>

    <body>
        <?php
            echo "Hello, World!";
        ?>
    </body>
</html>
Enter fullscreen mode Exit fullscreen mode
  • Populate docker-compose.yml with the following configuration:
# ./docker-compose.yml

version: '3'

services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: my_secret_pw_shh
      MYSQL_DATABASE: test_db
      MYSQL_USER: devuser
      MYSQL_PASSWORD: devpass
    ports:
      - "9906:3306"
  web:
    image: php:7.2.2-apache
    container_name: php_web
    depends_on:
      - db
    volumes:
      - ./php/:/var/www/html/
    ports:
      - "8100:80"
    stdin_open: true
    tty: true
Enter fullscreen mode Exit fullscreen mode
  • Our directory structure should look as follows:
$ tree
.
├── docker-compose.yml
└── php
    └── index.php
Enter fullscreen mode Exit fullscreen mode

Time to learn some PHP!

Notes
  • We use port-forwarding to connect to the inside of containers from our local machine.
    • webserver: http://localhost:8100
    • db: mysql://devuser:devpasslocalhost:9906/test_db
  • Our local directory, ./php, is mounted inside of the webserver container as /var/www/html/
    • The files within in our local folder will be served when we access the website inside of the container

Top comments (7)

Collapse
 
ripsup profile image
Richard Orelup • Edited

Thanks for the article. While trying to run through the above I ran into this error

ERROR: In file './docker-compose.yml', service must be a mapping, not a NoneType.

which I solved by updating docker-compose.yml to this

version: '3'

services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: my_secret_pw_shh
      MYSQL_DATABASE: test_db
      MYSQL_USER: devuser
      MYSQL_PASSWORD: devpass
    ports:
      - "9906:3306"
  web:
    image: php:7.2.2-apache
    container_name: php_web
    depends_on:
      - db
    volumes:
      - ./php/:/var/www/html/
    ports:
      - "8100:80"
    stdin_open: true
    tty: true
Enter fullscreen mode Exit fullscreen mode

The indentation matters and this finally got it working. Hope this helps anyone else trying to use this.

Collapse
 
alysivji profile image
Aly Sivji

Thanks for the heads up!

Didn't realize the indentation got messed up as I copied this over. It has been corrected.

Collapse
 
ripsup profile image
Richard Orelup

I'm just getting in to Docker so I'm actually glad it had that issue so I'm now aware that I have to get the indentation correct. :)

Collapse
 
vladimir_efremenko_af2271 profile image
Vladimir Efremenko

When working with the database from the application, I get the following:
Fatal error: Uncaught Error: Call to undefined function mysqli_connect() in /var/www/html/index.php:6 Stack trace: #0 {main} thrown in /var/www/html/index.php on line 6

Connection code:
<?php
$servername = "localhost:9906";
$username = "devuser";
$password = "devpass";
$dbname = "test_db";
$conn = mysqli_connect($servername, $username, $password, $dbname) or die("Fatal error: " . mysqli_connect_error());
if (mysqli_connect_errno()) {
printf("Fatal error: %s\n", mysqli_connect_error());
exit();
}
?>

With the help of mysqlworkbench i can connect and work with the database!
Tell me where I went wrong and why it doesn't work?

Collapse
 
valenzuelatalo profile image
Gonzalo Valenzuela

Thanks, Aly. I have a question: if the container is restarted, are the MySQL databases lost? In other words, is there persistence in the database?

Collapse
 
alysivji profile image
Aly Sivji • Edited

The setup I describe above stores data inside of the container. This data is lost when the container is deleted (docker-compose down)

You could mount a volume so the data is persisted on your local machine.

Looking at hub.docker.com/_/mysql/ (search for Where to Store Data), we can update the docker-compose.yml with another volume mount as follows:

# ./docker-compose.yml

version: '3'

services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: my_secret_pw_shh
      MYSQL_DATABASE: test_db
      MYSQL_USER: devuser
      MYSQL_PASSWORD: devpass
    volumes:
      - ./sql:/var/lib/mysql
    ports:
      - "9906:3306"
  web:
    image: php:7.2.2-apache
    container_name: php_web
    depends_on:
      - db
    volumes:
      - ./php/:/var/www/html/
    ports:
      - "8100:80"
    stdin_open: true
    tty: true

Now data will persist in the ./sql directory.

Collapse
 
valenzuelatalo profile image
Gonzalo Valenzuela

Thank you very much!