In this series, we have discussed about creating a basic Go based devcontainer and then we moved onto showcasing the life cycle events in devcontainers. Events like postCreateCommand and postStartCommand are good for smaller scripts execution during initialisation and running stage, but sometimes complex operations are needed to create an appropriate container such as installing major dependencies, initialisation of DB, etc. To facilitate this purpose, Dockerfile can be used create a devcontainer.

There is one more advantage of using Dockerfile as devcontainer which is portability. The Dockerfile used during the development can be directly used in deployment environments without worrying about breaking of code of missing or conflicting dependencies.

PHP devcontainer using Dockerfile

In this part of the series, we will extend our PHP devcontainer from the previous part to install some of the dependencies, run some Apache based settings and most importantly run our devcontainer as non-root user.

Dockerfile is used in this example, to achieve the same. The following is the Dockerfile used for the features mentioned above:

FROM php:8.2.20-apache
 
# Switching to root user for installation of dependencies
USER root
 
RUN a2enmod rewrite
 
RUN apt-get update && apt-get install -y git vim
 
WORKDIR /var/www/html
 
COPY . .
 
# Setting for running devcontainer as non-root user
RUN groupadd -g 1000 asura && useradd -r -u 1000 -g asura -m asura -c "Project Asuras" -s /bin/bash
 
RUN chown -R www-data:www-data /var/www/html
 
# Switching to apache2 default non-root user
USER www-data
 
EXPOSE 80
 
CMD [ "apache2-foreground" ]

Note

The Dockerfile should reside in the project root directory instead of .devcontainer with the current settings of devcontainer.json.

In the above Dockerfile we are switching to root user for installing the dependencies using apt repository and enabling rewrite plugin in apache.

Also, for our devcontainer we are creating a user and group named asura with UID of 1000 (as this is default uid used for devcontainer).

As Apache web server requires, owner of our /var/www/html directory to be www-data, we are executing chown command.

Once all the root operations are performed, we are switching to non-root www-data user. (such that during deployment, www-data is used instead of root user).

Our Dockerfile is ready, now let’s change our devcontainer.json file to:

{
    "name": "Test Application Dev Container",
    "build": {
        "dockerfile": "../Dockerfile",
        "context": ".."
    },
    "postStartCommand": "apache2ctl start",
    "appPort": ["8080:80"],
    "workspaceFolder": "/var/www/html",
    "mounts": [
        "source=${localWorkspaceFolder},target=/var/www/html,type=bind"
    ],
    // Setting for running devcontainer as non-root user asura
    "remoteUser": "asura",
    "customizations": {
        "vscode": {
            "extensions": [
                "bmewburn.vscode-intelephense-client",
                "esbenp.prettier-vscode",
                "xdebug.php-debug",
                "ms-azuretools.vscode-docker"
            ],
            "settings": {
                "php.validate.executablePath": "/usr/local/bin/php",
                "php.validate.run": "onType"
            }
        }
    }
}

The new parameters in the devcontainer.json which needs a bit of a understanding are as follows:

  • build: Build parameter is used for building a new container image (instead of pre-built container images) for devcontainer.
    • dockerfile: Path of the Dockerfile for building the image for devcontainer.
    • context: Build context directory (.. as our files are residing at the parent of .devcontainer directory). Alternatively, one can place Dockerfile inside .devcontainer directory and change the context to ., but it is always a good practice to keep your Dockerfile at project’s root directory.
    • Other keys which can be used are args, options and target during building of docker image:
      • args are list of arguments that should be passed during the building stage.
      • options are list of options that should be passed to docker during the building stage.
      • target specifies the build target.
  • remoteUser: Specify the user to be used while running the devcontainer, in our case, we have specially created a user named asura.

After running the devcontainer using Rebuild command, you will be able to access the index.php page as previously.

Note

You can also check full specifications at containers.dev.

In the next part, we will be looking at running multiple containers in devcontainer.