Update WordPress Container for Docker – Data Persistence

Until now, we have been trying to keep up-to-date by using the apt update command in our containers. Such knowledge is very useful not only for updating Docker containers, but also for migration, scaling, backup strategies, and many other scenarios. However, methods such as the apt update command, shown below, are not recommended: while it is technically possible to perform apt update and package installation within the Docker container, it is not recommended as a Docker best practice. The reasons for this include

Violation of the principle of immutability

There is a principle that Docker containers should be immutable. That is, a container should not change throughout its lifecycle and should start in the same state each time it is re-created. Performing apt update or package installations within a container can change the state of the container, compromising reproducibility and predictability.

Security Risks

Updating or installing packages directly within a container may introduce security risks. In particular, there is a risk of introducing unexpected vulnerabilities or malware when installing packages from untrusted sources.

Size and Performance Impact

Installing packages within a container can increase the size of the image and increase the time it takes to distribute and boot. It may also increase security vulnerabilities due to the accumulation of unnecessary packages and dependencies.

Recommended approach

  • Use Dockerfile: Define required packages and dependencies in the Dockerfile and install them when building the custom image. This ensures that containers are immutable and have the same environment no matter where they are run.
  • Take advantage of multi-stage builds: By separating the build and execution environments, you can keep the image size small and include only the packages you need.

For example, if a certain package is needed, it can be described in the Dockerfile as follows

Example Dockerfile
FROM ubuntu:latest
RUN apt-get update && apt-get install -y \
[required package] \
&& rm -rf /var/lib/apt/lists/*

This approach allows you to build the environment you need while ensuring container reproducibility, security, and performance.

The location of the PHP configuration file php.ini in the container will vary depending on the version of PHP in particular and the base image being used, but a general guideline is as follows

/usr/local/etc/php/ directory

  • This directory is used to store PHP’s main configuration file , php.ini; the settings that are initially loaded when PHP is started are located here.
  • If you want to completely replace the default php.ini, or if you want to define PHP’s overall configuration from scratch, it is appropriate to place the files in this directory.

/usr/local/etc/php/conf.d/ directory

  • This directory is for placing additional configuration files; PHP will also automatically read the files in this directory and add them to the php.ini configuration.
  • It is convenient to place .ini files in the conf.d/ directory if you want to customize only certain settings, or if you want to make it easier to manage several different configuration files. So you do not have to modify the original php.ini file, and it is easier to add or update settings.

Which should I choose?

  • If you want to customize the overall PHP settings or completely replace the default php.ini, place the php.ini in /usr/local/etc/php/.
  • If you only want to change certain settings, or if you want more flexibility in managing your settings, you can place a customized .ini file (e.g., custom.ini ) in the /usr/local/etc/php/conf.d/ directory.

In fact, in many cases, the conf.d/ directory is easier to manage, and it is easier to add or change settings. That said, you can keep the default PHP settings and apply only the necessary changes.

What if I don’t have a backup on my host?
We suggest the following method Copy the necessary files from the container to the host. Using the docker cp command is a direct and easy way to copy files and directories from the container to the host. This command can be used to copy files and directories in a particular container to the host system.

Example usage

docker cp [container name or ID]: [destination path on host]

For an example in my environment, the usage example is as follows

docker cp wp:/var/www/html . /wp/html
docker cp wp:/usr/local/etc/php . /wp/php

This command copies the /var/www/html directory in the wordpress container (where the WordPress files are stored) to ./wp/html copy the PHP related files as well to save you the trouble of reconfiguring them. This will back up the files in /var/www/html to the host.

When copying files or directories from the container to the host using the docker cp command, if the destination directory does not exist, it will be created automatically. However, this is only the case if the destination path is specified as a directory.

For example, to copy the /var/www/html directory in a container to a new directory ./wp/html, the ./wp/html directory does not exist, the docker cp command will create this directory and then copy the files. In the above operation, ./wp/html is automatically created and the contents of /var/www/html are copied there. However, if you are copying files as a single file path (e.g., copying a single file in a container to a new file path on the host), the parent directory of that path is not automatically created.

However, the following error may occur

invalid output path: directory “/home/mamu/wp” does not exist

The docker cp command does not automatically create the final directory to which files and directories are copied. That is, the last segment of the destination path (in this case html ) may be created automatically, but its parent directory (in this case /home/mamu/wp ) must exist beforehand. It’s tricky, but I figured it out by actually trying it myself.

Solution.

To solve this problem, the destination directory (or at least its parent directory) must be created manually. Use the following command to create the necessary directories

mkdir -p /home/mamu/wp

Notes.

  • Note that if the destination directory already exists and contains files, this operation may overwrite its contents.
  • When making backups, dynamic data, especially databases, should also be considered; in the case of WordPress, not only the contents of the wp-content/uploads directory, but also the database export is important. It is also easier later if you copy any PHP-related customized configuration files.

After copying a file or directory from a container to a host with the docker cp command, it is common that the owner (owner) or group of the file or directory is set to the user who performed the copy operation (often root or the current user). In particular, some applications, such as web servers, require that the owner or group of a particular file or directory be set to a particular user or group (e.g., www-data ).

For example, if you are using the WordPress container, your web server (e.g. Apache or Nginx) will typically run as the www-data user. Therefore, the wp-content directory and any other directories that need to be accessed by the web server must be owned by the www-data user and group. To ensure this, you will need to change the owner of the copied files and directories.

Changing Ownership

To change the owner of a file or directory to www-data, use the chown command. For example, to change the owner of the ./wp/html directory and all files in it to the www-data user and group, execute the following command

sudo chown -R www-data:www-data ./wp/html

This command works as follows

  • chown: Command to change the owner of a file or directory.
  • R: Recursive operation on all files and subdirectories in a directory.
  • www-data:www-data: Specifies the new owner and group. In this case, both user and group are www-data.
  • ./wp/html: The path to the file or directory whose owner is to be changed.

Note: sudo is used because this operation may require superuser privileges. The directory creation command did not use superuser privileges. If the user has write permission to the directory, the mkdir command can create the directory without using sudo. For example, if it is the user’s home directory or a subdirectory thereof, the directory can usually be created without sudo. On the other hand, if you want to operate on a directory that affects the entire system (e.g., /usr/local ) or a directory owned by another user, you must use sudo and execute the command with superuser privileges. It is easy to forget to do this, so we have decided to describe it here.

This procedure will ensure that the web server can access files and directories properly and that your WordPress site will function properly. The change of ownership is important for security reasons, and it is recommended that only certain users (in this case, the web server) have access to important files and directories.

What if the OS system is different between the host and the container?
For example, if the host is CentOS-like and the container is Debian-like, it is important to ensure that the User ID (UID) and Group ID (GID) match and are properly configured. This is because the default user and group UID/GID differ between Linux distributions. For example, the UID for the www-data user is often 33 in Debian, but may be different on CentOS. These differences can cause authorization problems. We have experienced this many times and describe how to deal with it.

Specific steps

  1. Verify UID/GID: Check the UID/GID.
    • Run the id www-data command in the container to check the UID and GID of the www-data user and group.
    • Check for the existence of similar users on the host system and check their UID/GID as well.
  2. Create a user on the host: 1.
    • If the www-data user does not exist on the host system, or if the UID/GID is different, create a www-data user on the host with the same UID/GID as the container.

    sudo groupadd -g [GID] www-data
    sudo useradd -u [UID] -g www-data -M -N -s /sbin/nologin www-data

    where [UID] and [GID] are the values of www-data as confirmed in the container.
  3. File and directory permission settings:.
    • Set the appropriate owner (www-data) for the files and directories copied from the container to the host.

    sudo chown -R www-data:www-data /path/to/directory
  4. Security checks: Check the security of the
    • When adding new users or groups to the system, reassess the security risks and take additional security measures as necessary.

Points to note

  • Security and compatibility: When using different Linux distributions for hosts and containers, be aware of differences in security policies and file systems. In particular, if you are using a security-enhanced Linux (SELinux), additional configuration may be required.

What about PHP related files?
Use the docker cp command to copy the contents of wp:/usr/local/etc/php to . After copying to ./wp/php, it is common for the ownership of PHP configuration files to be set to the current user or root; for PHP configuration files, it is not necessarily necessary to change the ownership of these files.

Although PHP configuration files (e.g. php.ini ) contain configuration information that is read by the server, these files are not written by the server process (e.g. the www-data user). Therefore, read access permissions are sufficient for ownership of these files. In practice, PHP configuration files are only read at server startup and are rarely modified at runtime.

However, the following points should be noted

  • Permissions: In order for the PHP configuration file to be read by the server process, appropriate read permissions must be set. Usually, this is not a problem as long as read permissions are granted to the owner of the file, a group, or another user.
  • Security: PHP configuration files may contain critical settings that affect the server’s operation. Therefore, it is recommended that these files be secured and that unnecessary write permissions be removed.

If the PHP configuration files are working correctly after copying and the server starts without problems, no ownership changes will be necessary. However, if you experience problems reading the configuration file when the server starts, recheck the file’s permissions and adjust as necessary.

We have actually prepared the following docker-compose.yml. start the update process in Oracle Cloud. based on the contents of docker-compose.yml, create this file under the wp directory directly under your home directory. (For clarity and control) However, you will need to adjust the volume mount path appropriately in that case.

If you place the docker-compose.yml file under the wp directory, Docker Compose will resolve relative paths based on the directory where the docker-compose.yml file resides. So, if the docker-compose.yml file is located in the wp directory, use the prefix ./wp as a prefix is not necessary.

For example, consider the following directory structure

wp/ 
├── docker-compose.yml
├── html/
│ └─ (WordPress files...)
└── php/
└── php.ini

In this case, docker-compose.yml will look like this

version: "3.8"
services:
wordpress:
container_name: wp
image: wordpress:latest
ports:
- "8080:80"
environment:
- TZ=Asia/Tokyo
restart: always
volumes:
- /etc/localtime:/etc/localtime:ro
- ./html:/var/www/html # Specify relative paths from `wp` directory base.
- ./php/php.ini:/usr/local/etc/php/php.ini

Here, ./html and ./php/php.ini paths are based on the wp directory where the docker-compose.yml file resides. Therefore, if you create the docker-compose.yml file under the wp directory, the ./wp prefix is not necessary and a direct relative path is used.

By adjusting the path in this way, you can place the docker-compose.yml file under the wp directory and mount the files and directories in the appropriate locations in the container.

The reason there is no database information is because the database is on another server. The same may be true if you already have a customized wp-config.php. If wp-config.php already contains the proper database connection information and you have it mounted as a volume, then setting environment variables in the docker-compose.yml file There is no need to do this. wp-config.php is the core file for managing WordPress configuration and holds many site-specific settings, including database connection information. This configuration mounts the entire WordPress html directory, which means that wp-config.php, customized php.ini files, and other necessary files and directories (e.g., wp-content ) are also contained within the container The container will now contain the database connection information and other configuration settings. Database connection information and other settings will now be automatically applied when the container is started.

Also, if you want to set the container’s time zone to Japan Standard Time (JST), it is more efficient to put the settings in the docker-compose.yml file instead of setting them manually each time the container is launched. This way, the timezone is automatically applied each time the container is launched, ensuring consistency.

How to set the time zone in docker-compose.yml

To set the time zone, add an environment variable in the environment section that specifies the time zone. It is also common to mount the host’s /etc/localtime to the container so that the container can use the host’s time zone settings.

In the absence of a Dockerfile, using the official wordpress:latest image directly is the appropriate method.

https://hub.docker.com/_/wordpress

Update with the following steps, where wp is the currently running WordPress container.

  1. Stop the container: Run the following command
    docker stop wp
  2. Delete the container: docker rm wp
    docker rm wp
  3. Fetch the latest WordPress image: docker pull wordpress:latest
    docker pull wordpress:latest
  4. Start the service using docker-compose.yml:
    docker compose up -d
    This command starts the WordPress service in the background based on the docker-compose.yml file. The container will be created according to the settings specified in this file (port, volume, container name, etc.).

When running a WordPress container, files and directories that need to be mounted other than the PHP configuration, wp-config.php, and wp-content directories are usually based on specific customization and operational requirements. Here are a few additional elements worth considering

1. .htaccess files

  • If you are using Apache, you can easily manage server configuration, redirection rules, etc. by mounting .htaccess files. This is often placed in the root of var/www/html, but depending on the site configuration, it may be placed in a subdirectory. In the case of this container, it resided in the root of var/www/html. Note that this is a hidden file. 2.

2. SSL Certificate

  • If you want to run your site using HTTPS, you will need to securely mount your SSL certificate and private key in the container. However, it is more common to configure these on a reverse proxy or load balancer than on the WordPress container itself.

If you have a database on an external server, this is not a problem.

The docker-compose.yml above does not specifically describe networking. In that case, when you use Docker Compose to start the service, it will create its own network by default. On the same host, services (containers) can refer to each other by name in this network and can communicate inside the network. However, default communication between different Docker Compose projects (or with containers launched independently) is restricted. That is, they cannot communicate with the database because it is a separate network from the database.

The following is a record of a network created by the network on its own.

mamu@g570:~/wp$ docker compose up -d
WARN[0000] /home/mamu/wp/docker-compose.yml: version is obsolete
[+] Running 1/2
⠋ Network wp_default Created 3.0s
✔ Container wp Started

The recommended way to allow WordPress and existing database containers to communicate is to create a user-defined network and connect both containers to that network. To create a user-defined network, follow these steps It may not be recommended to match the database network. A solution will appear later.

Creating a user-defined network
docker network create my-custom-network
Using a user-defined network in docker-compose.yml
version: "3.8"
services:
wordpress:
container_name: wp
image: wordpress:latest
ports:
- "8080:80"
restart: always
volumes:
- ./html:/var/www/html
- ./php/php.ini:/usr/local/etc/php/php.ini
networks:
- my-custom-network

networks:
my-custom-network:
external: true

This configuration uses a user-defined network named my-custom-network. This network must also be applied to the database container.

3. Connecting database containers

If the database container is already running, you can connect to the user-defined network with the following command

docker network connect my-custom-network name or ID of the database container

This step will allow the WordPress container and the database container to communicate within the same user-defined network. You can then check the IP address of the container and put it in wp-config.php. docker inspect command can be used to find out the IP address of a particular container. This is especially useful if you want to know which network the container is connected to and its IP address within that network.

For example, if you know the name or ID of a container (e.g. wordpress_container ), you can run the following command to get more information about the container and find its IP address

docker inspect wordpress_container

The output is in JSON format and contains a lot of information, but the IP address is under the "NetworkSettings" key. Because of the length of the output, you can filter only specific information by using the grep command (available on Linux and Mac terminals) or the --format option built into the docker inspect command.

As an example, to get the IP address of a specific container, use the following

docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' wordpress_container

This command prints out the IP address of the specified container (in this example, wordpress_container ).-The -f or --format option is used to format the output. In this case, only the IP address of the container is extracted using Go’s template language.

*Note
When a container is connected to an existing user-defined network using the docker network connect command, the container will belong to multiple networks. The container will be able to communicate via all networks to which it is connected.

For example, if the database container is already connected to the default bridge network and you then run docker network connect my-custom-network database_container, the database_container will be connected to the bridge network and my-custom-network.

This is especially useful in complex environments where certain applications need to access services on different networks. However, for security reasons, connections to non-essential networks should be avoided. Connections to unnecessary networks increase security risks because they may provide an opportunity for an attacker to traverse the network and probe for vulnerabilities.

To see which networks your containers are connected to, you can use the docker inspect command mentioned earlier. Network connection information can be found in the "Networks" section under "NetworkSettings".

If you need to disconnect a container from a particular network, you can use the docker network disconnect command. For example, to disconnect database_container from the default-network, run: default-network was actually named bridge.

docker network disconnect default-network database_container

This will disconnect database_container from the default-network, leaving only the other network connections. In this way, you can take advantage of Docker’s networking capabilities to flexibly manage communication between containers.

And let’s not forget. The IP address has changed because we have made the database container belong to a custom Docker network. Put this IP address in wp-config.php. The IP address can be checked with the docker inspect command described earlier. When you write both WordPress and database settings in docker-compose.yml as follows, just write db for the host in wp-config.php. With this configuration, the Docker network is managed within Docker Compose, and the alias db allows other services (in this case wordpress ) to access the MariaDB server under the name db.

If both WordPress and the database are on the same server, the following is done. The reason I am describing the port number of the database is because I want to connect to it from the outside. For example, Workbench or python scripts.

version: "3.8"
services:
  db:
    container_name: maria
    image: mariadb:latest
    ports:
      - "3306:3306"
    volumes:
      - db_data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=examplepass
      - MYSQL_DATABASE=wordpress
      - MYSQL_USER=wordpress
      - MYSQL_PASSWORD=wordpress
    restart: always

  wordpress:
    container_name: wp
    depends_on:
      - db
    image: wordpress:latest
    ports:
      - "8080:80"
    environment:
      - WORDPRESS_DB_HOST=db
      - WORDPRESS_DB_USER=wordpress
      - WORDPRESS_DB_PASSWORD=wordpress
      - TZ=Asia/Tokyo
    restart: always
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ./html:/var/www/html
      - ./php/php.ini:/usr/local/etc/php/php.ini

volumes:
  db_data:

To keep your Docker images up-to-date, you will need to update your images periodically. This docker-compose.yml uses existing images but not the latest ones. docker pull command downloads the latest version of a given image from Docker Hub or another registry. This allows you to get the latest changes, including security patches and feature updates.

How to get the latest WordPress images

Using the latest images is very important from a security perspective, especially for WordPress. You can use the following command to pull the latest WordPress images

docker pull wordpress:latest

This command will download the latest WordPress image with the latest tag.

Usage considerations

  1. Specify the version: If you are using
    • Although using the latest tag will automatically fetch the latest version, it is sometimes recommended to specify a specific version for production environments. This improves predictability and repeatability of the environment. For example, you can specify a specific version such as wordpress:5.7.
  2. Updating the image and restarting the container:.
    • After acquiring a new image, you will need to recreate the container in order to update an existing container to use that image. This usually involves the process of stopping the container, deleting it, and restarting it with the new image.
  3. Data Persistence:.
    • WordPress requires proper volume setup to hold critical data, such as wp-content directories and databases. This ensures that the container’s data is retained even if the image is updated.
  4. Automation considerations:.
    • For more efficient management, you may want to consider automatic image updates. For example, a CI/CD pipeline can be set up to automatically deploy new images as they become available.

By using the latest images, you can enjoy both functional improvements and enhanced security. Keeping the environment up-to-date also makes future maintenance and troubleshooting easier. docker-compose pull command is another good practice. This command is used to update the images of all services defined in the docker-compose.yml file. In other words, this command will automatically update all the specified images to the latest version.

Finally, the
With the docker-compose.yml file and the files properly backed up (or mounted) on the host, you can update your services (e.g., WordPress) to the latest version at any time. It can also be restored to a previous state if necessary. This process increases deployment flexibility and facilitates version control.

Update Process

  1. Image update: To update the image specified in docker-compose.yml (e.g. wordpress:latest ) to the latest version, run the following command
    docker-compose pull
    All images described in docker-compose.yml will be updated to the latest version.
  2. Restart the container: Restart the container with the latest images.
    docker-compose up -d
    This command will stop and remove containers as needed, then recreate and start them using the latest images.

Data Persistence

  • Use of volumes: You can mount important data and settings, such as /var/www/html, which contains WordPress core files, plugins, themes, etc., WordPress configuration files wp-config.php, PHP configuration files, etc., on the host’s file system or on a volume to mount the container so that the data will be retained even if the container is deleted.
  • Backups: Make regular backups of your database and important files to ensure that your data is safe to restore in case something goes wrong.

Just in case.
The docker commit command can be used to save a new image of the currently running container state. This allows you to create a snapshot of the container at the moment and later launch a new container using that image. This is useful if you want to keep a particular working environment or configuration in case of “just in case” situations.

How to use docker commit

Here are the basic instructions for using the docker commit command

docker commit [options] container_id new_image_name

For example, if your container ID is c3f279d17e0a and you want to save its state as an image myapp:snapshot, you can execute the following

docker commit c3f279d17e0a myapp:snapshot

This command saves the current state of the running container as a new image named myapp:snapshot. This image can be used to recreate the container later. It will revert back to the original as soon as it fails.

Usage scenarios for docker commit

  • Save your development state: This is useful if you are debugging a particular issue during development and want to save the state of your application.
  • Backing up configuration and data: Keep a container containing your application configuration and specific data so that you can quickly restore your environment when needed.
  • Replicating a test environment: If you want to share a particular test environment with other team members, you can create an image of that environment for easy distribution.

Notes

  • Image size: The image created by docker commit can be larger than the original base image because it contains all of the container’s changes. Proper management and cleanup is required.
  • State persistence: committing saves changes to the container file system, but any data stored in external storage, such as databases or files, must be backed up to that storage itself.
  • Deprecated usage: some users use docker commit frequently to “version control” their Docker images, but it is originally recommended that Dockerfile be used to build images. This makes the environment more transparent and reproducible.

While docker commit is a very useful tool in certain circumstances, in normal operation, building and versioning images using Dockerfile should be the basis.

Please share if you like it!
TOC