Introduction

Setting up a development environment can be a daunting task, especially if you’re new to the world of programming. Even experienced developers can have trouble getting everything set up correctly. There are a few things you’ll need to do to set up your development environment in your local machine.

First, you’ll need to install a programming language and it’s dependencies. This is the language you’ll use to write your code. Next, you’ll need to install a development server and the server dependencies. This is the program that will run your code.

While setting up your development environment, you will make it sure it is also available to other developers. Because chances are, you’re not the only one who will develop the project. So, you start to think about cross machine compatibility. How will you make your project available to others without them the need to execute the same process you did on your local machine. So, what’s the solution?


What is the solution?

If you’re a developer, chances are you’ve heard of Docker. Docker is a tool that can help you package and ship your applications with all of their dependencies. This can be a great time saver, and it can also help you ensure that your applications will run the same on any environment.

How Docker Works?

When you setup your project with Docker, the first thing you need to do is to make an image through dockerfile , this file contain all the necessary code and configurations for an application. When you run a Docker container, it will use the image as a template to create a new isolated environment for the application to run in. This is our project output looks like.

project strucure with docker

In this article, we’ll walk you through the process of setting up a development environment with using Docker Engine. We will setup PHP, NGINX, PHP-FPM as example project. We’ll cover everything from choosing an operating system to installing the necessary tools and libraries. By the end, you’ll be ready to start developing your own applications, share it and deploy it in any environment. And so that, you will no longer have to say “But it works in my machine!!“.



Prerequisites

Setting up a development environment for PHP 8 with NGINX and PHP-FPM can be done with just a few simple steps using Docker. This guide will show you how to get everything up and running so that you can start coding with PHP. But first we need the prerequisites to start the project.

Docker Engine – Well, we already now what docker is, it is a tool that enables developers to create, deploy, and manage applications within software containers. Now we have to install it to our computer. You can find the installation guide in the link below for specific OS.

Docker installation guide for Windows
Docker installation guide for Ubuntu
Docker installation guide for Mac

Docker-composeDocker-compose is a tool for defining and running multi-container Docker applications. With docker compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration.

We need to install docker-compose extension for our docker so that we could setup, build, run and remove our multiple container services at once.

Docker-compose installation guide

Alpine Linux OS – We need an OS inside our docker. There are lots of option to choose from you can find it here. But I recommend Alpine OS due to it’s lightweight size.

NGINX – A web server which can also be used as a reverse proxy, load balancer, and HTTP cache. We need a server to run our script so that, it can be accessible to client. We can find the installation guide for alpine in nginx official site.

PHP-FPM – Nginx alone will not work with php, we need a PHP-FPM (FastCGI) to allow PHP script to run in nginx web server. We will configure php-fpm and nginx in our Dockerfile.

PHP – Of course, we need php language and php dependencies.


Structure of our project

This is our sample project looks like. You can clone the project repository in Github.

project strucure with docker

Creating a DockerFile

FROM – FROM is the first instruction in a Dockerfile. It specifies the base image that the Dockerfile will use to build a new image.

RUN – To execute a command during the build process.

COPY – Copies files or directories from a source on the host to a destination in the container.

EXPOSE – It exposes a port on the container

STOPSIGNAL SIGTERM – To specify that the container will be gracefully shut down when it receives a SIGTERM signal.

CMD – To specify the default command that will be executed when a container is run from an image.

Here is our dockerfile script looks.

# First, We need an Operating System for our docker. We choose alpine.
FROM alpine:3.16.2

# Next, Update Alpine OS
RUN apk update && apk upgrade

# Next, we need to install utilities inside alpine, we can achieve this by type RUN then, the alpine command.
# Install apline utilities and php depedencies
RUN apk add --no-cache \
    bash \
    php8 \ 
    php8-fpm \ 
    php8-opcache \
    php8-gd \
    php8-zlib \
    php8-curl \
    php8-bcmath \
    php8-ctype \
    php8-iconv \
    php8-intl \
    php8-json \
    php8-mbstring \
    php8-mysqlnd \
    php8-openssl \
    php8-pdo \
    php8-pdo_mysql \
    php8-pdo_pgsql \
    php8-pdo_sqlite \
    php8-phar \
    php8-posix \
    php8-session \
    php8-soap \
    php8-xml \
    php8-zip \
    libmcrypt-dev \
    libltdl 

# Next, Install nginx on alpine official guide in nginx official site. I just copied and paste what's on the site guide for installing nginx on alpine.
# https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-open-source/
RUN apk add openssl curl ca-certificates

# To set up the apk repository for stable nginx packages, run the command:
RUN printf "%s%s%s\n" \
"http://nginx.org/packages/alpine/v" \
`egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release` \
"/main" \
| tee -a /etc/apk/repositories

# Import an official nginx signing key so apk could verify the packages authenticity. Fetch the key:
RUN curl -o /tmp/nginx_signing.rsa.pub https://nginx.org/keys/nginx_signing.rsa.pub

# Verify that the downloaded file contains the proper key:
RUN openssl rsa -pubin -in /tmp/nginx_signing.rsa.pub -text -noout

# Move the key to apk trusted keys storage
RUN mv /tmp/nginx_signing.rsa.pub /etc/apk/keys/

# Now, install nginx
RUN apk add nginx

# Install PHP Composer, If you use composer, you can uncomment this one.
# RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# copy project file to nginx inside docker.
COPY ./src /usr/share/nginx/html/project

# Copy default config and paste it into nginx config path inside docker.
COPY ./nginx-configs/default.conf /etc/nginx/conf.d/default.conf

# Expose port to be visible outside the container.
EXPOSE 80
EXPOSE 443

STOPSIGNAL SIGTERM

# Execute startup command.
# Start php-fpm8 and nginx through bash terminal.
CMD ["/bin/bash", "-c", "php-fpm8 && chmod 755 /usr/share/nginx/html/* && nginx -g 'daemon off;'"]

Now that we’ve created our dockefile, we have to test our application. First, we need to build the image. The name of our image is backend.

Type the command below in your project terminal.

docker build -t backend .

After we build the image, we can now execute the backend image to create a container.

docker run -dp 8081:80 backend

To see if the container is running, you can check it by typing : docker ps in your project terminal. or testing the application via web browser: http://localhost:8081


What the heck is Docker Volume?

A Docker volume is a directory on the host filesystem that is mounted into the container. Volumes provide a way to persist data generated by and used by containers. Why is it so important?

When you don’t use docker volumes, you have to store all your data in the docker image. This can lead to a number of problems:

1) Your image can get very large, making it difficult to manage.

2) If you need to update your project code, you have to rebuild your image, which can be time-consuming.

3) If you accidentally delete your image, you lose all your data.

In our project, we want to persist whatever is in our src directory. Here is how we do it.

docker run -dp 8081:80 -v src:/usr/share/nginx/html/project backend

We can now change our project code in src directory without the need to rebuild the image and re-run the container.


Docker Compose to the rescue

When you ran the project through docker, you first built the image and then, started the container by typing docker run command and specify what ports, volumes and name of your image. We might wonder if there is a way to execute all these commands at once? Well yes, with the use of docker-compose. Why is it again so important?

If you don’t use docker-compose, you will have to manually build and run each container separately. This can be very time-consuming and difficult to manage, especially if you have a lot of containers.

Here is how you rewrite your docker command to docker-compose. Create a docker-compose.yml file inside the project. and paste the code below.

version: "1.0"

services:
  backend:
    # Specify Image name
    image: backend

    # Specify Container name
    container_name: backend

    # specify context and dockerfile to build
    build: 

      #Docker context is path where dockerfile is located.
      context: ./

      #specify Dockerfile to build.
      dockerfile: Dockerfile

    #expose ports
    ports:
      - "8081:80"
      - "443:43"

    #persistent volume
    volumes: 
      - ./src:/usr/share/nginx/html/project

Run the script in your project terminal.

docker-compose up -d

Now test your application via web browser: http://localhost:8081.


To remove a container:

docker-compose down

To build an image:

docker-compose build

Final Thought

Docker is a powerful tool that can help you develop and deploy applications with ease. It is important to learn how to use Docker in order to maximize its potential. With Docker, you can quickly and easily deploy your applications to any environment, whether it is development, production, or anywhere in between.

Disclosure: All opinions remain with the author's. Our articles may contain sponsorship, paid, or related references, but we believe in editorial integrity and honesty of opinion. We  recommend products and services  curated based on our research or  our own positive experience. See Copyright and Disclosure Policy for more information.