<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Focus on your mission, not your tech - Another Cup of Coffee (Posts about Docker)</title><link>https://anothercoffee.net/</link><description></description><atom:link href="https://anothercoffee.net/categories/docker.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Copyright © 2006 - 2026 &lt;a href="https://anothercoffee.net/" title="Another Cup of Coffee Limited"&gt;Another Cup of Coffee Limited&lt;/a&gt; </copyright><lastBuildDate>Wed, 18 Feb 2026 16:39:44 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>How To Set Up Drupal 7 Docker Containers for Migration Projects</title><link>https://anothercoffee.net/drupal-7-docker-containers-migration-projects/</link><dc:creator>Anthony Lopez-Vito</dc:creator><description>&lt;figure&gt;&lt;img src="https://anothercoffee.net/images/posts/Drupal-Docker-Containers-og-1200x630.jpg"&gt;&lt;/figure&gt; &lt;p&gt;&lt;strong&gt;Docker is a valuable tool for Drupal 7 end of life migrations. In this post, I'll give a step-by-step guide to setting up a Drupal 7 container for your migration project. Instructions for the migration itself are out of scope for this article but you will have a running Drupal installation that can be used with a migration tool of your choice.&lt;/strong&gt;&lt;/p&gt;
&lt;section&gt;
    &lt;div class="border bg-light p-4 rounded"&gt;
        &lt;h4 class="text-center"&gt;Table of Contents&lt;/h4&gt;
        &lt;ol class="list-group"&gt;
            &lt;li class="list-group-item d-flex justify-content-between align-items-center"&gt;
                &lt;a href="https://anothercoffee.net/drupal-7-docker-containers-migration-projects/#introduction" class="text-decoration-none"&gt;1. Introduction&lt;/a&gt;
            &lt;/li&gt;
            &lt;li class="list-group-item d-flex justify-content-between align-items-center"&gt;
                &lt;a href="https://anothercoffee.net/drupal-7-docker-containers-migration-projects/#upgrade-or-migrate" class="text-decoration-none"&gt;2. Upgrade Drupal 7 or Migrate?&lt;/a&gt;
            &lt;/li&gt;
            &lt;li class="list-group-item d-flex justify-content-between align-items-center"&gt;
                &lt;a href="https://anothercoffee.net/drupal-7-docker-containers-migration-projects/#setting-up" class="text-decoration-none"&gt;3. Hassles with Setting up the Migration Environment&lt;/a&gt;
            &lt;/li&gt;
            &lt;li class="list-group-item d-flex justify-content-between align-items-center"&gt;
                &lt;a href="https://anothercoffee.net/drupal-7-docker-containers-migration-projects/#introduction-to-docker" class="text-decoration-none"&gt;4. An Introduction to Docker&lt;/a&gt;
            &lt;/li&gt;
            &lt;li class="list-group-item d-flex justify-content-between align-items-center"&gt;
                &lt;a href="https://anothercoffee.net/drupal-7-docker-containers-migration-projects/#how-to-set-up-docker" class="text-decoration-none"&gt;5. How to Set Up Docker Containers for Drupal 7 Migrations&lt;/a&gt;
            &lt;/li&gt;
            &lt;li class="list-group-item d-flex justify-content-between align-items-center"&gt;
                &lt;a href="https://anothercoffee.net/drupal-7-docker-containers-migration-projects/#testing-workflow" class="text-decoration-none"&gt;6. Testing and Workflow&lt;/a&gt;
            &lt;/li&gt;
            &lt;li class="list-group-item d-flex justify-content-between align-items-center"&gt;
                &lt;a href="https://anothercoffee.net/drupal-7-docker-containers-migration-projects/#preparing-migration" class="text-decoration-none"&gt;7. Preparing for Your Drupal 7 Migration&lt;/a&gt;
            &lt;/li&gt;
            &lt;li class="list-group-item d-flex justify-content-between align-items-center"&gt;
                &lt;a href="https://anothercoffee.net/drupal-7-docker-containers-migration-projects/#conclusion" class="text-decoration-none"&gt;8. Conclusion&lt;/a&gt;
            &lt;/li&gt;
        &lt;/ol&gt;
    &lt;/div&gt;
&lt;/section&gt;

&lt;p&gt;&lt;span id="introduction"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="1-introduction"&gt;1. Introduction&lt;/h2&gt;
&lt;p&gt;After several deadline extensions, the Drupal Association &lt;a href="https://www.drupal.org/psa-2023-06-07" target="_blank" rel="noopener noreferrer"&gt;has confirmed&lt;/a&gt; that Drupal 7 will officially reach end of life (EOL) on 5 January 2025. For site owners, agencies, and freelancers who've postponed making a decision, the time has come to make a choice. Do you upgrade to a newer version of Drupal, or migrate to an entirely different platform? Neither option is straightforward.&lt;/p&gt;
&lt;p&gt;I sympathise with the &lt;em&gt;"if it ain't broken, don't fix it"&lt;/em&gt; approach to most things, especially for something like a business-critical website. It's hard to justify disrupting a system that's running without any apparent problems. However, a Drupal 7 site migration is now unavoidable. Drupal Core will no longer be supported after EOL and hiring developers to keep it maintained, while a possibility, will not be feasible in the long term.&lt;/p&gt;
&lt;p&gt;&lt;span id="upgrade-or-migrate"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="2-upgrade-drupal-7-or-migrate"&gt;2. Upgrade Drupal 7 or Migrate?&lt;/h2&gt;
&lt;p&gt;It's important to understand that &lt;a href="https://www.drupal.org/docs/upgrading-drupal/upgrading-from-drupal-6-or-drupal-7" target="_blank" rel="noopener noreferrer"&gt;moving from Drupal 7&lt;/a&gt; to a newer version of Drupal isn't a straightforward upgrade. Most Drupal developers already know this but it's worth pointing out early on. Unlike typical software updates, upgrading to Drupal 8 or higher involves a complete rebuild of the site.&lt;/p&gt;
&lt;p&gt;In other words, whether you plan to upgrade or migrate to a different content management platform like WordPress, the work involved is fundamentally going to be a migration project. For this reason, throughout this article, I'll use the terms 'migration' and 'upgrade' interchangeably. Both scenarios involve similar planning, testing, and execution requirements, as well as the need for a temporary development environment.&lt;/p&gt;
&lt;p&gt;&lt;span id="setting-up"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="3-hassles-with-setting-up-the-migration-environment"&gt;3. Hassles with Setting up the Migration Environment&lt;/h2&gt;
&lt;p&gt;Unfortunately, site migrations are notoriously intricate, requiring careful planning and execution. Even getting set up for a migration can feel like an uphill battle. In 2012, when we first started specialising in Drupal to WordPress migrations, local web development involved making sure the whole application stack was configured properly for each project. This meant setting up a virtual host on the development machine web server, as well as getting the database and PHP configurations right. Virtualisation tools like VirtualBox existed, but they often performed poorly, freezing frequently and proving unreliable for sustained work.&lt;/p&gt;
&lt;p&gt;The release of Docker in 2013 introduced a better way to manage development environments. As an open-source containerisation platform, it solved many of the problems developers faced when setting up for new migration projects. By isolating environments within lightweight containers, Docker streamlined workflows and eliminated many of the common compatibility headaches. By around 2018, it had become a standard tool for development teams worldwide, replacing clunky and expensive solutions like virtual machines.&lt;/p&gt;
&lt;p&gt;In this guide, we'll outline how to set up a Docker container tailored for Drupal 7 migrations. We'll also explain how Docker simplifies the migration process while providing the flexibility required for more complex scenarios.&lt;/p&gt;
&lt;p&gt;&lt;span id="introduction-to-docker"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="4-an-introduction-to-docker"&gt;4. An Introduction to Docker&lt;/h2&gt;
&lt;p&gt;I'll start off with some basics for readers who aren't familiar with Docker. Feel free to skip to the &lt;a href="https://anothercoffee.net/drupal-7-docker-containers-migration-projects/#how-to-set-up-docker"&gt;setup steps&lt;/a&gt; if you don't need the introduction.&lt;/p&gt;
&lt;h3 id="what-is-docker"&gt;What is Docker?&lt;/h3&gt;
&lt;p&gt;Here's a quick overview if you're unfamiliar with the technology. Docker is a containerisation platform that lets you bundle applications and their dependencies into isolated units called containers. You can think of a container as a self-contained environment where everything your project needs, such as applications, libraries, and other dependencies, are bundled together. This approach ensures that the software runs consistently, regardless of the underlying system.&lt;/p&gt;
&lt;p&gt;Unlike the old virtual machines, which emulate an entire operating system, Docker containers share the host system's kernel. This makes them lightweight, fast, and resource-efficient. Portability is central to Docker's appeal. A container built on a developer's laptop will work the same way on a production server. Combined with tools like Docker Compose, which orchestrates multi-container setups, you can recreate entire environments with just a few commands.&lt;/p&gt;
&lt;h3 id="why-use-docker-for-migrations"&gt;Why Use Docker for Migrations&lt;/h3&gt;
&lt;p&gt;Setting up a migration project used to require a huge amount of effort, especially for a Drupal 7 to WordPress conversion. It was a nightmare juggling multiple client projects on a single development machine. You would need to set up Apache virtual hosts for the new project sites and sometimes tweak system-wide PHP versions or database settings. If there was a risk of introducing a breaking change for another project, I would have to dig out and set up a spare physical machine.&lt;/p&gt;
&lt;p&gt;Docker helps streamline the project setup tasks by offering isolated containers for each client, reducing the time spent building the environment and troubleshooting compatibility issues. For example, a Drupal 7 site may need PHP 5.6, while a new WordPress installation might require PHP 8. With Docker, you can run both versions in separate containers, avoiding annoying conflicts.&lt;/p&gt;
&lt;p&gt;Docker volumes ensure data persistence for databases and installation files, even if a container is removed. Starting over from a botched migration simply means rebuilding the container from a pristine state—a process that usually takes minutes.&lt;/p&gt;
&lt;h3 id="key-advantages-and-limitations-of-docker"&gt;Key Advantages and Limitations of Docker&lt;/h3&gt;
&lt;p&gt;Docker is lightweight compared to traditional virtual machines. It shares the system kernel, allowing you to run multiple containers without overloading your system. This makes it particularly useful for testing different configurations or managing multiple projects.&lt;/p&gt;
&lt;p&gt;However, it's important to note some limitations. Building Docker images for the first time can be time-consuming, and unused containers or images can quickly consume disk space if not managed regularly. Also, keeping a clean and efficient environment requires periodic maintenance. This can be annoying when you're knee-deep in a complex migration and you find your development machine running out of disk space.&lt;/p&gt;
&lt;p&gt;Docker is not a complete solution for all problems, but thankfully, known issues like security concerns, networking challenges, and resource management apply to production sites rather than temporary migration environments.&lt;/p&gt;
&lt;h3 id="essential-docker-concepts"&gt;Essential Docker Concepts&lt;/h3&gt;
&lt;p&gt;I'll go over some important basics before delving into the steps for setting up Docker Containers for Drupal 7 Migration Projects. You might get a little lost without an understanding of these concepts so be sure to at least skim through them if you're new to Docker. You can find information over on the &lt;a href="https://docs.docker.com/" target="_blank" rel="noopener noreferrer"&gt;dockerdocs&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Containers:&lt;/strong&gt; Containers are lightweight, portable units that package your application and its dependencies. They run isolated from each other and the host system, ensuring consistency across development, staging, and production environments.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Images:&lt;/strong&gt; A Docker image is a pre-configured snapshot that defines what is inside a container. Images include your application, libraries, runtime, and any dependencies.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dockerfile:&lt;/strong&gt; A Dockerfile is a text file with instructions for creating a Docker image. It defines the base image, environment variables, software installations, and configuration commands.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Volumes:&lt;/strong&gt; Volumes are used to persist data generated by a container. They're essential for making sure changes to the Drupal database or files aren't lost when the container stops or is removed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Networks:&lt;/strong&gt; Docker's networking features allow containers to communicate with each other or with external services. For example, you could use the network to send data from Drupal container to a WordPress container, or a container that holds your migration utilities.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Docker Compose:&lt;/strong&gt; Docker Compose is a tool that allows you to define and run multi-container Docker applications using a &lt;code&gt;docker-compose.yml&lt;/code&gt; file. It simplifies the management of environments with multiple interconnected services (e.g., a Drupal site with a PHP container, a database container, and a reverse proxy).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Registry and Docker Hub:&lt;/strong&gt; Docker Hub is a public registry where developers can find and share Docker images. Knowing how to pull official images from trusted sources and push your custom images to private or public registries is an important skill.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Commands and CLI Basics:&lt;/strong&gt; Familiarity with Docker CLI commands like &lt;code&gt;docker build&lt;/code&gt;, &lt;code&gt;docker ps&lt;/code&gt;, and &lt;code&gt;docker compose up -d --build&lt;/code&gt; will allow you to manage and troubleshoot containers effectively. See the &lt;a href="https://docs.docker.com/reference/" target="_blank" rel="noopener noreferrer"&gt;command-line interfaces&lt;/a&gt; documentation for more about the commands.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt;&lt;span id="how-to-set-up-docker"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="5-how-to-set-up-docker-containers-for-drupal-7-migrations"&gt;5. How to Set Up Docker Containers for Drupal 7 Migrations&lt;/h2&gt;
&lt;p&gt;By now you should have a good understanding of what Docker is, how it can help with a migration project, and some basic concepts. Let's get on with actually setting it up. Here we'll create a container to install Drupal 7.103, released on 4 December 2024, with a full stack including web server, database and Drush.&lt;/p&gt;
&lt;h3 id="1-install-docker"&gt;1. Install Docker&lt;/h3&gt;
&lt;p&gt;First, ensure Docker is installed on your system. You can follow &lt;a href="https://docs.docker.com/get-docker/"&gt;Docker's official installation guide&lt;/a&gt; for your operating system. I find the most convenient method is to install Docker Desktop which includes all the Docker tools and is available for Linux, Mac and Windows.&lt;/p&gt;
&lt;h3 id="2-create-your-project-structure"&gt;2. Create Your Project Structure&lt;/h3&gt;
&lt;p&gt;Create a folder structure for your migration project. At Another Cup of Coffee, we use a variation of following project structure.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Secrets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;variables&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;backups&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;backups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yml&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;drupal&lt;/span&gt;&lt;span class="o"&gt;-[&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;]/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;└──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Dockerfile&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;└──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;phpmyadmin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="err"&gt;└──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Dockerfile&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logs&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Drupal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;installation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;
&lt;span class="err"&gt;└──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;utils&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;migration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;utilities&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="file-and-database-persistence"&gt;File and Database Persistence&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;File Changes: Drupal core/theme/module changes will persist on host through a mapping to the &lt;code&gt;./src&lt;/code&gt; directory.&lt;/li&gt;
&lt;li&gt;Database Changes: the database will be stored in a named volume managed by Docker. The data will persist across container restarts/rebuilds unless the volume is manually deleted.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-download-the-drupal-installation-files"&gt;3. Download the Drupal Installation Files&lt;/h3&gt;
&lt;p&gt;We will use Drupal 7.103 for our container. (Note: &lt;em&gt;This is the newest version, released on 4 December 2024, as of the last update for this article.&lt;/em&gt;) &lt;a href="https://www.drupal.org/project/drupal/releases/7.103" target="_blank" rel="noopener noreferrer"&gt;Download it from the Drupal website&lt;/a&gt; and extract the files into your &lt;code&gt;./src&lt;/code&gt; directory. &lt;/p&gt;
&lt;p&gt;The container will create a &lt;a href="https://docs.docker.com/engine/storage/bind-mounts/" target="_blank" rel="noopener noreferrer"&gt;bind mount&lt;/a&gt; to map the &lt;code&gt;./src&lt;/code&gt; directory on the host machine to &lt;code&gt;/var/www/html&lt;/code&gt; inside the container. This means that any changes made to the files in the container at &lt;code&gt;/var/www/html&lt;/code&gt; will be reflected in the &lt;code&gt;./src&lt;/code&gt; directory on the host machine, and vice versa.&lt;/p&gt;
&lt;h3 id="4-create-your-env-file"&gt;4. Create Your &lt;code&gt;.env&lt;/code&gt; File&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;.env&lt;/code&gt; file is a text file used by Docker Compose to define environment variables. These variables can be referenced in the &lt;code&gt;docker-compose.yml&lt;/code&gt; file to make your configurations more flexible and easier to manage. It's a good way of preventing sensitive information like passwords from being included in source control.&lt;/p&gt;
&lt;p&gt;It will look something like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;DRUPAL_DB_HOST=db
DRUPAL_DB_USER=dbuser
DRUPAL_DB_PASSWORD=dbpass
DRUPAL_DB_NAME=drupal_db

MYSQL_ROOT_PASSWORD=root
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ensure you adjust it to use your own variables.&lt;/p&gt;
&lt;h3 id="4-create-your-drupal-dockerfile"&gt;4. Create Your Drupal Dockerfile&lt;/h3&gt;
&lt;p&gt;The Dockerfile sets out the instructions for creating a Docker image, defining the base image, environment variables, software installations, and configuration commands.&lt;/p&gt;
&lt;p&gt;An image for Drupal 7.103 with Apache, Drush and PHP Composer might look like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;drupal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;7.103&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;apache&lt;/span&gt;

&lt;span class="c1"&gt;# Install required PHP extensions and tools&lt;/span&gt;
&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;unzip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;libicu&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;libzip&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;libxml2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;libonig&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;zlib1g&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pdo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pdo_mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;intl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;rf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lists&lt;/span&gt;&lt;span class="o"&gt;/*&lt;/span&gt;

&lt;span class="c1"&gt;# Configure PHP&lt;/span&gt;
&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"memory_limit = 256M"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ini&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"upload_max_filesize = 64M"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;upload&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ini&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"post_max_size = 64M"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;upload&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ini&lt;/span&gt;

&lt;span class="c1"&gt;# Install PHP extensions needed by Drupal&lt;/span&gt;
&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pdo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pdo_mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;intl&lt;/span&gt;

&lt;span class="c1"&gt;# Enable Apache mods commonly needed by Drupal&lt;/span&gt;
&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a2enmod&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rewrite&lt;/span&gt;

&lt;span class="c1"&gt;# Install Composer (from the Composer official image)&lt;/span&gt;
&lt;span class="n"&gt;COPY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;composer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;composer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;composer&lt;/span&gt;

&lt;span class="c1"&gt;# Install Drush globally via Composer&lt;/span&gt;
&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;composer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;global&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;drush&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;drush&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;8.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;

&lt;span class="c1"&gt;# Ensure Drush is on PATH&lt;/span&gt;
&lt;span class="n"&gt;ENV&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/root/.composer/vendor/bin:${PATH}"&lt;/span&gt;

&lt;span class="c1"&gt;# Set the container working directory&lt;/span&gt;
&lt;span class="n"&gt;WORKDIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;

&lt;span class="c1"&gt;# Ensure the Apache user (www-data) owns the web root&lt;/span&gt;
&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chown&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This grabs the offical Docker Hub repository image for Drupal 7.103 with the Apache web server. You'll notice the Drupal image doesn't include any specifications for a database. This will be handled by the &lt;code&gt;docker-compose.yml&lt;/code&gt; file later.&lt;/p&gt;
&lt;p&gt;If you followed my project structure above, place this Dockerfile in a &lt;code&gt;drupal-7.103&lt;/code&gt; folder inside the &lt;code&gt;docker&lt;/code&gt; subdirectory.&lt;/p&gt;
&lt;p&gt;Adjust the Dockerfile for your own needs but here are some notes to avoid headaches:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;default-mysql-client&lt;/code&gt;: If you're familiar with installing MySQL on a Linux system, you might be tempted to run &lt;code&gt;apt-get&lt;/code&gt; for &lt;code&gt;mysql-client&lt;/code&gt;. Don't do this. The Docker repository for &lt;code&gt;drupal:7.103-apache&lt;/code&gt; is based on Debian Bookworm (Debian 12). Debian has stopped packaging &lt;code&gt;mysql-client&lt;/code&gt; as of Debian 10 so you will encounter errors. Make sure you use the &lt;code&gt;default-mysql-client&lt;/code&gt; metapackage instead. This will install the MySQL compatible &lt;code&gt;mariadb-client&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;composer:2&lt;/code&gt;: Although Drupal 7 does not have native Composer support, we are using it to install Drush.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;drush:8&lt;/code&gt;: Install Drush 8, which is the latest compatible version Drupal 7 websites. A later version will install but you will encounter errors running some Drush commands.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="5-create-a-phpmyadmin-dockerfile-optional"&gt;5. Create a phpMyAdmin Dockerfile (optional)&lt;/h3&gt;
&lt;p&gt;This step is optional but it's useful to install phpMyAdmin so that you can do some basic database tasks. A phpMyAdmin Dockerfile that pulls the latest version of phpMyAdmin from the official Docker Hub repository would look like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;FROM phpmyadmin:latest

# Add ServerName configuration
RUN echo "ServerName localhost" &amp;gt;&amp;gt; /etc/apache2/apache2.conf
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Place this Dockerfile in a &lt;code&gt;phpmyadmin&lt;/code&gt; folder inside the &lt;code&gt;docker&lt;/code&gt; subdirectory.&lt;/p&gt;
&lt;h3 id="6-create-your-docker-composeyml-file"&gt;6. Create Your &lt;code&gt;docker-compose.yml&lt;/code&gt; File&lt;/h3&gt;
&lt;p&gt;Docker Compose will let you define and run all the necessary applications using a &lt;code&gt;docker-compose.yml&lt;/code&gt; file. The example below defines services for Drupal, MySQL and phpMyAdmin, and should be saved in the root of your project folder. Please read the &lt;a href="https://docs.docker.com/reference/compose-file/" target="_blank" rel="noopener noreferrer"&gt;Compose file reference&lt;/a&gt; for a detailed explanation of each section in order to customise it for your needs.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;drupal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;dockerfile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;drupal&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;7.103&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Dockerfile&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"8088:80"&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;# Ensure you copy your Drupal site here to avoid permission issues&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;# If you are starting with a fresh Drupal installation, download&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;# the correct Drupal version and extract it here.&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;# https://www.drupal.org/project/drupal/releases/7.103&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;cached&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;depends_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;service_healthy&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;env_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_HOST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_HOST&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_USER&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_NAME&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;PHP_FPM_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;PHP_FPM_GROUP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;5.7&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;env_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_NAME&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;MYSQL_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_USER&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3307:3306"&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;healthcheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"CMD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mysqladmin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ping"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-h"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"localhost"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-u"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"drupal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-pdrupal_pass"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;phpmyadmin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;dockerfile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;phpmyadmin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Dockerfile&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"8081:80"&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;env_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;PMA_HOST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_HOST&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;PMA_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_USER&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;PMA_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;PMA_ABSOLUTE_URI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8081&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;depends_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;

&lt;span class="n"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;db_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="the-mysql-image"&gt;The MySQL Image&lt;/h4&gt;
&lt;p&gt;You will see that I used MySQL 5.7 in this configuration to simulate an outdated environment. MySQL 5.7 reached its end of life in October 2023 but as of late-2024, we have clients who, for one reason or another, are still running MySQL 5.7. They are not alone. A September 2024 article from Percona, a database software and support company, has a FAQ section titled, "&lt;a href="https://www.percona.com/blog/mysql-8-0-vs-5-7-are-the-newer-versions-more-problematic/" target="_blank" rel="noopener noreferrer"&gt;Should I upgrade from MySQL 5.7 to 8.0?&lt;/a&gt;" Clearly, a large percentage of sites are still running legacy databases on their web stack.&lt;/p&gt;
&lt;p&gt;If you are using MySQL versions 8.x, visit Docker Hub's &lt;a href="https://hub.docker.com/_/mysql" target="_blank" rel="noopener noreferrer"&gt;MySQL repository&lt;/a&gt; to see the relevant image tags. You will need to update this section:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;    db:
        image: mysql:5.7
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Also, most development machines will already have a MySQL server running on the local port &lt;code&gt;3306&lt;/code&gt;. To avoid conflicts, this &lt;code&gt;docker-compose.yml&lt;/code&gt; maps the container's MySQL port to the local port &lt;code&gt;3307&lt;/code&gt;. Adjust this to suit your own setup.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;        ports:
            - "3307:3306"
&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="7-build-and-start-the-environment"&gt;7. Build and Start the Environment&lt;/h3&gt;
&lt;p&gt;Now you're ready to build and start your environment. Open up a terminal and run the following command:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;docker compose up -d --build
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will use Docker Compose to build the containers and run them in detached mode. It may take a few minutes to complete if you're running this command for the first time. Docker will need to download all the images from the Docker repository before building.&lt;/p&gt;
&lt;h3 id="8-access-your-local-drupal-setup"&gt;8. Access Your Local Drupal Setup&lt;/h3&gt;
&lt;p&gt;If all goes well you should have your environment ready to install Drupal 7. Visit &lt;code&gt;http://localhost:8080&lt;/code&gt; in your browser to access the Drupal 7 instance running in the Docker container.&lt;/p&gt;
&lt;p&gt;Follow the installation wizard and 
Use these database settings in your .env file.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;span id="testing-workflow"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="6-testing-and-workflow"&gt;6. Testing and Workflow&lt;/h2&gt;
&lt;p&gt;You can use these commands to test your installation. Check the documentation in the &lt;a href="https://anothercoffee.net/drupal-7-docker-containers-migration-projects/#additional-resources"&gt;Additional Resources&lt;/a&gt; section below for more commands.&lt;/p&gt;
&lt;h3 id="basic-testing"&gt;Basic Testing&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Container Status:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Check if all containers are running&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;ps
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Expected output: db, drupal and phpMyAdmin services should show "Up" status&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Drupal Installation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Access the Drupal site at http://localhost:8088&lt;/li&gt;
&lt;li&gt;You should see the Drupal installation page or site&lt;/li&gt;
&lt;li&gt;Check error logs if needed:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;logs&lt;span class="w"&gt; &lt;/span&gt;drupal
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Drush Functionality:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Test Drush status&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;drush&lt;span class="w"&gt; &lt;/span&gt;status

&lt;span class="c1"&gt;# Test Drush version&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;drush&lt;span class="w"&gt; &lt;/span&gt;--version

&lt;span class="c1"&gt;# Test site-specific Drush commands&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;drush&lt;span class="w"&gt; &lt;/span&gt;core-status
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Composer Functionality:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Test Composer version&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;composer&lt;span class="w"&gt; &lt;/span&gt;--version

&lt;span class="c1"&gt;# Test Composer diagnostics&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;composer&lt;span class="w"&gt; &lt;/span&gt;diagnose
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Database Connection:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Test database connection via Drush&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;drush&lt;span class="w"&gt; &lt;/span&gt;sql-connect

&lt;span class="c1"&gt;# Test phpMyAdmin access&lt;/span&gt;
&lt;span class="c1"&gt;# Visit http://localhost:8081&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="testing-your-migration-utilities-with-sample-content"&gt;Testing Your Migration Utilities With Sample Content&lt;/h3&gt;
&lt;p&gt;You can use Drush to generate sample content. This can be useful for testing your migration utilities.&lt;/p&gt;
&lt;h4 id="1-log-into-the-containers-terminal"&gt;1. Log Into the Container's Terminal&lt;/h4&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;bash
&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="2-install-helper-modules"&gt;2. Install Helper Modules&lt;/h4&gt;
&lt;p&gt;Install the &lt;code&gt;devel&lt;/code&gt;, &lt;code&gt;devel_generate&lt;/code&gt;, and &lt;code&gt;taxonomy_manager&lt;/code&gt; modules:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;drush&lt;span class="w"&gt; &lt;/span&gt;en&lt;span class="w"&gt; &lt;/span&gt;devel&lt;span class="w"&gt; &lt;/span&gt;-y
drush&lt;span class="w"&gt; &lt;/span&gt;en&lt;span class="w"&gt; &lt;/span&gt;devel_generate&lt;span class="w"&gt; &lt;/span&gt;-y
drush&lt;span class="w"&gt; &lt;/span&gt;en&lt;span class="w"&gt; &lt;/span&gt;taxonomy_manager&lt;span class="w"&gt; &lt;/span&gt;-y
&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Devel Module:&lt;/strong&gt; The Devel module is a comprehensive toolkit for Drupal developers that offers several submodules and features to aid in development and debugging.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Devel Generate Module:&lt;/strong&gt; The Devel Generate module is a submodule of the Devel module, specifically designed for generating dummy content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Taxonomy Manager Module:&lt;/strong&gt; Use the Taxonomy Manager module to mass insert taxonomy terms. &lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-generate-sample-content"&gt;3. Generate Sample Content&lt;/h4&gt;
&lt;p&gt;Now generate some sample content:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Generate nodes with randon content&lt;/span&gt;
drush&lt;span class="w"&gt; &lt;/span&gt;generate-content&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;500&lt;/span&gt;

&lt;span class="c1"&gt;# Generate users&lt;/span&gt;
drush&lt;span class="w"&gt; &lt;/span&gt;generate-users&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;25&lt;/span&gt;

&lt;span class="c1"&gt;# Generate taxonomy terms&lt;/span&gt;
drush&lt;span class="w"&gt; &lt;/span&gt;generate-terms&lt;span class="w"&gt; &lt;/span&gt;tags&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;

&lt;span class="c1"&gt;# Generate nodes for a specific content type&lt;/span&gt;
drush&lt;span class="w"&gt; &lt;/span&gt;generate-content&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--types&lt;span class="o"&gt;=&lt;/span&gt;article

&lt;span class="c1"&gt;# Generate comments on random nodes:&lt;/span&gt;
drush&lt;span class="w"&gt; &lt;/span&gt;generate-comments&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;250&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="development-workflow"&gt;Development Workflow&lt;/h3&gt;
&lt;p&gt;Here are some basic commands to support your development and migration workflow.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Starting/Stopping Environment:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Start containers&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;up&lt;span class="w"&gt; &lt;/span&gt;-d

&lt;span class="c1"&gt;# Stop containers&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;down

&lt;span class="c1"&gt;# View logs&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;logs&lt;span class="w"&gt; &lt;/span&gt;-f
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Using Drush:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Access Drush&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;drush

&lt;span class="c1"&gt;# Clear cache&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;drush&lt;span class="w"&gt; &lt;/span&gt;cc&lt;span class="w"&gt; &lt;/span&gt;all

&lt;span class="c1"&gt;# Update database&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;drush&lt;span class="w"&gt; &lt;/span&gt;updb
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Working with Composer:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Install dependencies&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;composer&lt;span class="w"&gt; &lt;/span&gt;install

&lt;span class="c1"&gt;# Add new package&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;composer&lt;span class="w"&gt; &lt;/span&gt;require&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;package-name&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Service Access:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Drupal: http://localhost:8088&lt;ul&gt;
&lt;li&gt;Username and password as set during the installation process.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;phpMyAdmin: http://localhost:8081&lt;ul&gt;
&lt;li&gt;Username: (from .env)&lt;/li&gt;
&lt;li&gt;Password: (from .env)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;MySQL: localhost:3307&lt;ul&gt;
&lt;li&gt;Username: (from .env)&lt;/li&gt;
&lt;li&gt;Password: (from .env)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Database Operations:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Export database&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;db&lt;span class="w"&gt; &lt;/span&gt;mysqldump&lt;span class="w"&gt; &lt;/span&gt;-u&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;user&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="o"&gt;[&lt;/span&gt;root-password&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;backup.sql

&lt;span class="c1"&gt;# Import database&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-T&lt;span class="w"&gt; &lt;/span&gt;db&lt;span class="w"&gt; &lt;/span&gt;mysql&lt;span class="w"&gt; &lt;/span&gt;-u&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;user&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="o"&gt;[&lt;/span&gt;root-password&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;backup.sql
&lt;/pre&gt;&lt;/div&gt;

&lt;hr&gt;
&lt;p&gt;&lt;span id="preparing-migration"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="7-preparing-for-your-drupal-7-migration"&gt;7. Preparing for Your Drupal 7 Migration&lt;/h2&gt;
&lt;p&gt;If you made it this far, you will have a fully working and tested Docker container with Drupal 7, access to the database, and some basic tools to support migration or upgrade tasks. This environment isolates your development work, ensuring that your live site remains unaffected throughout the process.&lt;/p&gt;
&lt;h3 id="importing-your-live-drupal-installation-into-the-container"&gt;Importing Your Live Drupal Installation into the Container&lt;/h3&gt;
&lt;p&gt;To get started with your migration project, you'll need to transfer your existing live Drupal installation into the container. The Drupal 7 documentation for &lt;a href="https://www.drupal.org/docs/7/backing-up-and-migrating-a-site/migrating-a-site" target="_blank" rel="noopener noreferrer"&gt;migrating a site between environments&lt;/a&gt; will give you an outline of the steps.&lt;/p&gt;
&lt;p&gt;As a summary, you begin by exporting the database and files from your live site. Once you have these, you can load the database into the container's MySQL instance and place the site's files in the &lt;code&gt;./src&lt;/code&gt; directory on your host filesystem. (Remember, we created a bind mount to map the &lt;code&gt;./src&lt;/code&gt; directory to the container's web directory at &lt;code&gt;/var/www/html&lt;/code&gt;.) This gives you a working copy of your live site, but in a safe, sandboxed environment. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important note:&lt;/strong&gt; &lt;em&gt;In this article we used Drupal 7.103 for our container. To avoid problems with version conflicts, you should update your live Drupal site to the same version before exporting.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="creating-a-pristine-snapshot"&gt;Creating a Pristine Snapshot&lt;/h3&gt;
&lt;p&gt;Before diving into migration tasks, it's a good idea to create a snapshot of the container in its pristine state. This serves as a clean starting point you can revert to if anything goes wrong during the migration process. A snapshot ensures you won't need to repeat the setup steps from scratch if you need to restart or experiment with different migration approaches.&lt;/p&gt;
&lt;p&gt;You create a snapshot by committing the current state of your container to a new Docker image. I'll cover this in a separate article but at this stage you will now be ready to use whatever tools you need to upgrade or migrate your Drupal 7 installation.&lt;/p&gt;
&lt;h3 id="migration-options"&gt;Migration Options&lt;/h3&gt;
&lt;p&gt;Instructions for the migration itself will need to be covered elsewhere as it's a very detailed process. However, you can check these resources for your migration options:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Upgrading to a newer version of Drupal&lt;/strong&gt;: You can use your container to trial-run the upgrade steps in the Drupal documentation, "&lt;a href="https://www.drupal.org/docs/upgrading-drupal/upgrading-from-drupal-6-or-drupal-7" target="_blank" rel="noopener noreferrer"&gt;Upgrading from Drupal 6 or Drupal 7&lt;/a&gt;."&lt;/li&gt;

    &lt;li&gt;&lt;strong&gt;Migrating to another platform:&lt;/strong&gt; If you plan to migrate to another platform such as WordPress, please see our &lt;a href="https://anothercoffee.net/drupal-to-wordpress-migration-guide/" title="Drupal to WordPress Migration Guide"&gt;Drupal to WordPress Migration Guide&lt;/a&gt;.&lt;/li&gt;

&lt;/ul&gt;

&lt;hr&gt;
&lt;p&gt;&lt;span id="conclusion"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="8-conclusion"&gt;8. Conclusion&lt;/h2&gt;
&lt;p&gt;Docker provides a very practical and reliable way to set up migration environments. While it requires an initial investment in learning, the long-term benefits include consistent workflows, reliable environments, and over-all, fewer frustrations when getting started with a migration project. Docker won't solve every migration challenge, but in my experience, it definitely simplifies many of the technical hurdles involved. &lt;/p&gt;
&lt;p&gt;If you're facing challenges with Drupal 7 migrations or need expert assistance, &lt;a href="https://anothercoffee.net/contact/"&gt;reach out to us&lt;/a&gt; at Another Cup of Coffee. We can help make your next project smooth, efficient, and future-proof.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;span id="additional-resources"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="additional-resources"&gt;Additional Resources&lt;/h2&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href="https://www.drupal.org/docs" target="_blank" rel="noopener noreferrer"&gt;Official Drupal Documentation&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://docs.docker.com/" target="_blank" rel="noopener noreferrer"&gt;Docker Documentation&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://www.drush.org/latest/" target="_blank" rel="noopener noreferrer"&gt;Drush Documentation&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://getcomposer.org/doc/%20target=" _blank" rel="noopener noreferrer"&gt;Composer Documentation&lt;/a&gt;&lt;/li&gt;            
&lt;/ul&gt;

&lt;hr&gt;

&lt;section class="mt-4 pt-4"&gt;
    &lt;h3&gt;You may also like&lt;/h3&gt;

    &lt;div class="row"&gt;

        &lt;div class="col-md-6 col-lg-4 mb-4"&gt;
            &lt;div class="card h-100"&gt;
                &lt;a href="https://anothercoffee.net/drupal-to-wordpress-migration-guide/"&gt;
                        &lt;img src="https://anothercoffee.net/images/drupal-to-wordpress-migration-utilities-featured.jpg" class="card-img-top" alt="Drupal to WordPress Migration Guide"&gt;&lt;/a&gt;
                &lt;div class="card-body d-flex flex-column"&gt;
                    &lt;h4 class="card-title"&gt;&lt;a href="https://anothercoffee.net/drupal-to-wordpress-migration-guide/" class="listtitle"&gt;Drupal to WordPress Migration Guide&lt;/a&gt;&lt;/h4&gt;
                    &lt;div class="mb-2"&gt;
                        &lt;span&gt;&lt;time class="listdate" datetime="2025-01-03T15:30:30Z" title="Updated for 2025"&gt;Updated for 2025&lt;/time&gt;&lt;/span&gt;
                    &lt;/div&gt;
                    &lt;p class="card-text flex-grow-1"&gt;In this guide, you'll find insights drawn from almost 15 years of specialising in complex Drupal to WordPress migration projects. I'll walk you through the entire migration process, from the initial evaluation to post-launch considerations.&lt;/p&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="col-md-6 col-lg-4 mb-4"&gt;
            &lt;div class="card h-100"&gt;
                &lt;a href="https://anothercoffee.net/drupal-7-end-of-life-why-wordpress-is-the-best-migration-option/"&gt;
                        &lt;img src="https://anothercoffee.net/images/posts/drupal-7-end-of-life-why-wordpress-is-the-best-migration-option-300x150.jpg" class="card-img-top" alt="Drupal 7 End of Life: Why WordPress is the Best Migration Option for Lower Maintenance Sites"&gt;&lt;/a&gt;
                &lt;div class="card-body d-flex flex-column"&gt;
                    &lt;h4 class="card-title"&gt;&lt;a href="https://anothercoffee.net/drupal-7-end-of-life-why-wordpress-is-the-best-migration-option/" class="listtitle"&gt;Drupal 7 End of Life: Why WordPress is the Best Migration Option for Lower Maintenance Sites&lt;/a&gt;&lt;/h4&gt;
                    &lt;div class="mb-2"&gt;
                        &lt;span&gt;&lt;time class="listdate" datetime="2024-12-17T14:25:15Z" title="17 December 2024"&gt;17 December 2024&lt;/time&gt;&lt;/span&gt;
                    &lt;/div&gt;

                        &lt;p class="card-text flex-grow-1"&gt;Drupal 7 support ends January 2025. Discover why WordPress is the cost-effective, user-friendly CMS for small agencies, freelancers, and businesses.&lt;/p&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;!--
      &lt;div class="col-md-6 col-lg-4 mb-4"&gt;
        &lt;div class="card h-100"&gt;
              &lt;a href="/still-alive-a-micro-agencys-20-year-journey/"&gt;
                      &lt;img src="/images/a-west-london-micro-agencys-journey-to-ai-featured.jpg" class="card-img-top" alt="Still Alive: A Micro Agency's 20 Year Journey"&gt;&lt;/a&gt;
              &lt;div class="card-body d-flex flex-column"&gt;
                  &lt;h3 class="card-title"&gt;&lt;a href="/still-alive-a-micro-agencys-20-year-journey/" class="listtitle"&gt;Still Alive: A Micro Agency's 20 Year Journey&lt;/a&gt;&lt;/h3&gt;
                  &lt;div class="mb-2"&gt;
                      &lt;span&gt;&lt;time class="listdate" datetime="2024-10-15T15:28:15Z" title="15 October 2024"&gt;15 October 2024&lt;/time&gt;&lt;/span&gt;
                  &lt;/div&gt;

                      &lt;p class="card-text flex-grow-1"&gt;This article will be the first in a series where I'll share how Artificial Intelligence has reshaped how we operate at Another Cup of Coffee.&lt;/p&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    --&gt;
            &lt;div class="col-md-6 col-lg-4 mb-4"&gt;
          &lt;div class="card h-100"&gt;
              &lt;a href="https://anothercoffee.net/secure-your-ai-workflow-using-local-tokenisation/"&gt;
                      &lt;img src="https://anothercoffee.net/images/Secure-your-AI-workflow-using-local-tokenisation-in-PaigeSafe-featured.jpg" class="card-img-top" alt="Secure Your AI Workflow Using Local Tokenisation"&gt;&lt;/a&gt;
              &lt;div class="card-body d-flex flex-column"&gt;
                  &lt;h4 class="card-title"&gt;&lt;a href="https://anothercoffee.net/secure-your-ai-workflow-using-local-tokenisation/" class="listtitle"&gt;Secure Your AI Workflow Using Local Tokenisation&lt;/a&gt;&lt;/h4&gt;
                  &lt;div class="mb-2"&gt;
                      &lt;span&gt;&lt;time class="listdate" datetime="2024-11-12T13:59:03Z" title="12 November 2024"&gt;12 November 2024&lt;/time&gt;&lt;/span&gt;
                  &lt;/div&gt;

                      &lt;p class="card-text flex-grow-1"&gt;Don't leak confidential client data when using cloud-based LLMs. Secure your AI workflow with local tokenisation using PaigeSafe.&lt;/p&gt;
              &lt;/div&gt;
          &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

&lt;/section&gt;</description><category>Docker</category><category>Drupal</category><category>End of Life</category><category>Migration</category><guid>https://anothercoffee.net/drupal-7-docker-containers-migration-projects/</guid><pubDate>Mon, 09 Sep 2024 13:25:15 GMT</pubDate></item></channel></rss>