Setting Up a PHP Development Environment with Podman

October 16, 2020

Recently I’ve been taking an online course through Coursera on PHP. In my early experiments with PHP I generally got along fine with php’s built in web server. This course however, uses a traditional LAMP (Linux, Apache, MySQL, PHP) stack for assignments. Now I could just install those things on my computer, but I like to keep my computer clean and cluttering it up with various config files and databases is not particularly appealing to me. I want a solution that I can easily setup/teardown and purge from my machine when done. Containers are perfectly suited to this.

I have used Docker in the past, but the experience with Docker on Fedora 32 is pretty bad. I thought this was a good opportunity to finally learn podman beyond just installing podman-docker and calling it a day.

Folder Setup

/src
/mysqldb
etc

Creating the PHP and MySQL Images

For this step, you’ll need both podman and buildah. On Fedora or CentOS 8 this is as easy as sudo dnf install podman buildah. Just like docker, podman supports the use of Dockerfiles via the podman build command. However, I have heard good things about buildah so I wanted to see the difference for myself. buildah allows you to build images from the command line, or using normal shell scripts. If you’re familiar with Dockerfiles, buildah is a pretty easy transition.

So lets get started by building the php apache image. Luckily there is a really nice image on DockerHub. Run:

$ id=$(buildah from --pull php:7.4.10-apache-buster

buildah from --pull will search various repositories, including DockerHub, for matching images and return a ID. We will store this ID in the variable id.

Next, since we will be connecting this to a MySQL instance we need to install the necessary php extensions to our image. Luckily, the php image from DockerHub has a handy built-in utility to install php extensions called docker-php-ext-install. We will need the pdo and pdo_mysql extensions.

$ buildah run $id docker-php-ext-install pdo pdo_mysql

This command will install pdo and pdo_mysql in the image. Now all that’s left is to commit the changes to save the image.

$ buildah commit $id php-apache

This will save the image with $id as php-apache. Now that we have the php image lets create our mysql image, this one is simple.

$ id=$(buildah from --pull mysql:8)
$ buildah commit $id php-mysql

Now if you run podman images you should see our two newly created images php-apache and php-mysql. At this point, we could run our new images as containers with podman run -p 8080:80 php-apache, but I’ve got something better in mind.

Group the Images in a Pod

Ideally we want both of these containers to run as a group. In the Docker world we would use something like docker-compose, but podman has a build in concept called pods which allows us to orchestrate many containers their own mini kubernetes cluster. All containers in a pod can be started, and stopped together with the podman pod start <pod-name> and podman pod stop <pod-name> commands respectively. Also, all containers in a pod share the same private network, so all containers in a pod can easily access each other without opening any ports outside the pod. There are several ways to add a new pod, but podman offers an easy way through podman run.

podman run \
    --detach \
    --pod new:php-lamp \
    --publish 127.0.0.1:8080:80 \
    --name php-dev \
    --security-opt label=disable \
    --volume ./src:/var/www/html \
    php-apache

Let’s break this command down:

Now you should be able to see a new pod called php-lamp when running podman pod ls. The container is also running so pointing your browser to localhost:8080 should bring up the phpinfo page. Now all we need to do is add the mysql container to the pod.

podman run \
    --detach \
    --pod php-lamp \
    --name mysql-dev \
    --env MYSQL_ROOT_PASSWORD=dev \
    --security-opt label=disable \
    --volume ./mysqldb:/var/lib/mysql \
    php-mysql

This will add a new container mysql-dev to the php-lamp pod. Now you can stop and start both containers together using podman pod stop php-lamp and podman pod start php-lamp.

Putting it all Together

The beauty of all these shell commands, is we can put them in a script like mklamp.sh

#!/bin/sh

echo -e "Building Apache PHP image"
id=$(buildah from --pull php:7.4.10-apache-buster)
buildah run $id docker-php-ext-install pdo pdo_mysql
buildah commit $id php-apache

echo -e "\nBuilding MySQL image"
id=$(buildah from --pull mysql:8)
buildah commit $id php-mysql

podman run \
    --detach \
    --pod new:php-lamp \
    --publish 127.0.0.1:8080:80 \
    --name php-dev \
    --security-opt label=disable \
    --volume ./src:/var/www/html \
    php-apache

podman run \
    --detach \
    --pod php-lamp \
    --name mysql-dev \
    --env MYSQL_ROOT_PASSWORD=dev \
    --security-opt label=disable \
    --volume ./mysqldb:/var/lib/mysql \
    php-mysql

Now simply running sh mklamp.sh will build an run a nice php dev environment. This is obviously very similar to building a docker-compose file, but and we get to reap the benefits of not having Docker daemon running in the background.