Did you recently learn about the docker compose command and need help breaking it down? This command is used to manage multiple Docker containers using a YAML file.
How to Start Multiple Docker Containers without Docker Compose
As I said in my introduction, the purpose of this section is to show you how to manage multiple Docker containers manually – without using docker compose and a YAML file.
Specifically, I will start a MySQL Docker container first. After that, I will start a container for the GUI tool – phpmyadmin – required to manage MySQL.
I have talked about starting the two containers and this is all well and good but there is one problem. To manage the MySQL container instance from the phpmyadmin GUI, the two containers need to communicate!
How do we achieve this?
By creating a Docker network.
So, before we start both containers, we must create a Docker network first. Then, when we start each container, we connect them to the Docker network to allow communication.
This is one of the major problems that orchestrating multiple containers with Docker Compose resolves.
As we will see in the next section – when we start multiple containers via a YAML file using Docker Compose – the process creates a Docker Network automatically and connects the containers to the network.
Before then, follow the steps in these subsections to create a Docker network, then start the two containers. In the final subsection, we will open phpmyadmin via a browser and manage MySQL.
Step 1: Create a Docker Network to Link MySQL and phpmyadmin Containers
Creating a docker network requires a single, simple command. The command below creates a bridge Docker Network called “mysql-phpmyadmin-network.”
sudo docker network create mysql-phpmyadmin-network
The command creates the network and displays its ID.
To view all Docker networks, including the one you just created, run the “sudo docker network” command with the “ls” switch
sudo docker network ls
Step 2: Start MySQL Container Using Docker Run
To start a MySQL container, run the command below. See my explanations of each section of the command below.
sudo docker run -p 3306:3306 \ --name mysql \ --network mysql-phpmyadmin-network \ -e MYSQL_ROOT_PASSWORD=Password \ -e MYSQL_DATABASE=test-mysql-db \ -e MYSQL_USER=admin \ -e MYSQL_PASSWORD=adminpass \ -d mysql
a) docker run -p 3306:3306: the “docker run” command starts a mysql Docker container. Then, using the “-p” switch maps a port on the host (the first 3306) to the container’s port (the second 3306).
b) –network mysql-phpmyadmin-network: this specifiies the Docker network the container connects to. “mysql-phpmyadmin-network” is the Docker network we created in step 1 of this section.
c) –name mysql: specified the name of the Docker Container. You can call this whatever you want. However, using “mysql” makes it easy to identify the container when you run the “docker ps” command.
d) -e MYSQL_ROOT_PASSWORD=Password: The “-e” swicth of the “D”docker run” command is used to configure variables. The MYSQL_ROOT_PASSWORD variable is mandatory and specifies the password that will be set for the MySQL root superuser account. In my comand, I set this password to P@ssWord!!1.
e) -e MYSQL_DATABASE=test-mysql-db: The MYSQL_DATABASE is an optional variable for starting mySQL container. Use this to specify the name of a database to be created on the mySQL database. I called mine test-mysql-db.
f) -e MYSQL_USER=admin and -e MYSQL_PASSWORD=adminpass: these two variabbles are optional.However, if you specify the MYSQL_USER, you MUST also include the MYSQL_PASSWORD. The two variables create a create a new user and to set that user’s password. This user will be granted superuser permissions.
g) -d mysql: starts the mysql container in a detached mode, meaning that the container starts and runs on the background. Specifying mysql instructs Docker run to pull the latest mysql Docker image from the Docker Hub.
After executing both commands, to confirm that the mysql container is running, run the “docker ps” comand
sudo docker ps
The command confirms that a mysql container is running.
Before we move on, let’s confirm that the container is connected to the “mysql-phpmyadmin-network” Docker network by running the command below:
sudo docker network inspect mysql-phpmyadmin-network
If you scroll down to the “Containers” section of the output of the command, you can see the mysql container listed.
Step 3: Start the phpmyadmin Container (Mysql GUI Tool)
Now that we have successfully stared the mysql container, we can start the phpmyadmin container using the command below:
sudo docker run -p 8081:80 \ --network mysql-phpmyadmin-network \ --name phpmyadmin \ --link mysql:db \ -d phpmyadmin
a) docker run -p 8081:80: starts the container and maps its port 81 to the host’s port 8081. When we access phpmyadmin via the browser, we would use port 8081.
b) –network mysql-phpmyadmin-network: connects the container to our Docker network
c) –name phpmyadmin: gives the container a name – phpmyadmin, in this example.
d) –link mysql:db: links phpmyadmin container to the mysql container and connects to its db instance. This allows us to manage mysql from phpmyadmin .
e) -d phpmyadmin: starts the container in detached mode. Specifying phpmyadmin without an image tag, pulls the latest version of phpmyadmin from Docker Hub.
Step 4: Login to phpmyadmin to Manage Mysql Server
- Open a browser and enter the IP address of the server you started the containers, followed by a colon and the phpmyadmin container port number, 8081. Here is mine for your reference>
192.168.0.22:8081
You will receive a prompt to sign in to phpmyadmin.
2. Login to phpmyadmin with the username and password you specified in the MYSQL_USER and MYSQL_PASSWORD variables when you started the mysql container
I have highlighted the name of the database created when we started the mysql container.
How to Start Multiple Docker Containers with Docker Compose and YAML File
In this section, we will repeat the tasks we performed in the last section. However, this time, we’ll add the container configurations to a YAML file.
After that we will experience the power of Docker Compose! Before you begin, ensure to stop and delete the containers created in the last section.
This is important as we’re using the same names and ports in this secion. Use the commands below to stop and delete the containers;
sudo docker ps #displays the running containers. Note their IDs sudo docker stop container_ID #stops the containers - run twice, using the container IDs sudo docker container rm container_ID #deletes the containers - run twice, using the container IDs
Let’s dive in!
Step 1: Create a YAML File for Use with Docker Compose
I have provided the complete YAML file required to manage MySQL and phpmyadmin. It may not look like it, but the entries in this file represent the commands we ran in the previous section.
I will map the commands to the entries in the YAML file below. But, before that, I want to explain the structure of a Docker Compose YAML file.
version: '3' services: mysql: image: mysql container_name: mysql restart: always environment: - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} - MYSQL_DATABASE=${DB_NAME} - MYSQL_USER=${DB_USER} - MYSQL_PASSWORD=${DB_PWD} volumes: - mysql-data:/var/lib/mysql ports: - 3306:3306 phpmyadmin: image: phpmyadmin container_name: phpmyadmin restart: always depends_on: - mysql environment: - PMA_HOST=${PMA_HOST} ports: - 8081:80 volumes: mysql-data: driver: local
Here are a few facts about the above Docker Compose YAML file:
- The file shows structure by indenting the entries with spaces, not tabs. So, if you look from top to bottom of the file you will notice that version: ‘3’, services:, and volumes: are top-level keys that do not have any indentation spaces before them.
- The next level beneath services: (usually has two spaces from left to right) defines the container entries in the YAML file.
Specifically, the next level beneath services: are mysql: and phpmyadmin: – these tell Docker Compose that anything beneath these levels defines the container information.
By the way, you can call these anything. For example, you could decide to call them mysql-container: and phpmyadmin-container: - Earlier, I mentioned that the volumes: entry is on the top level with version: ‘3’, services: but what does volumes: mean?
This creates a Docker Volume to persist the SQL data. This volume can then be used by any of the containers that require it. For example, the mysql container entry has a volumes: definition – more on this later. - Finally, a YAML file is saved with the .yaml or .yml file extensions.
Now, let’s dive deep into the container entries in the YAML file, starting with the mysql container entries:
- image: mysql – does the same thing as the “-d mysql” in the Docker Run command in the last section. image: mysql tells Docker Compose to pull the latest version of mysql image from the Docker Hub.
If you want to use a different image other than the latest version or tag, you will specify mysql:tag-name for example, mysql:oraclelinux8 would have pulled the “oraclelinux8” version.
- container_name: mysql – defines the name of the container. This entry does the same job as “–name mysql” in the Docker Run command. Once again, you can specify any name but best practice is to use a name that easily identifies the container.
- restart: always – this is an optional but necessary entry that ensures the container restarts if it fails. As you will see later, this is more applicable to the phpmyadmin container.
I have provided the YAML file entries again below for easy reference.
version: '3' services: mysql: image: mysql container_name: mysql restart: always environment: - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} - MYSQL_DATABASE=${DB_NAME} - MYSQL_USER=${DB_USER} - MYSQL_PASSWORD=${DB_PWD} volumes: - mysql-data:/var/lib/mysql ports: - 3306:3306 phpmyadmin: image: phpmyadmin container_name: phpmyadmin restart: always depends_on: - mysql environment: - PMA_HOST=${PMA_HOST} ports: - 8081:80 volumes: mysql-data: driver: local
- environment: – defines the various environment variables required by the container. This is the same as specifying environment variables with the “-e” statement in Docker Run.
The only difference is that we specify the environment: statement once and then on that level we enter the various environment variables.
Another important point to mention here is that I used variable definitions – for example, ${MYSQL_ROOT_PASSWORD} instead of specifying the actual variable values, for example the password.
This is best practice as a YAML file is not encrypted so, entering passwords directly on the file is a security risk.
By specifying variables we can add values for the variables on the terminal before we start the containers with the “Docker Compose” command.
We will see this in action shortly. - volumes: – I did mention that the top-level volumes: statement creates a Docker Volume that is then used by the containers. The volumes: statement in the mysql container section creates a named Docker volume and defines the path to the data in the container.
In my example, mysql-data is the named Docker Volume. On the other hand, “/var/lib/mysql” is the path in the container that we want to save on the Docker Volume created on the host.
The benefit of doing this?
Since containers do not save (or persist) data, whenever you stop or restart it, it loses all data. By saving the data in a volume on the host, when you restart the container, it syncs the data from the volume on the host.
This way, your container persists its data!
- ports: – specifies the container ports. It is similar to the “-p” parameter in Docker Run. 3306:3306 maps the container port (3306 for mysql after the “:”) to the host port (3306 before “:”).
Moving on to the phpmyadmin container entries, I have already explained the “image,” “container_name,” “restart,” “environment,” and “port” entries.
Earlier, I promised to provide more details about the restart entry. When you run the Docker Compose command to start the containers with the definitions in the YAML file, the containers start in order.
However, there is a chance that the mysql container (which the phpmyadmin container depends on) may not have fully started. If this happens, the phpmyadmin container will fail to start.
But, because we included the “restart: always” in the YAML file, the container will attempt to restart and at some point in the multiple retries, the mysql container would have been ready for connection.
This leads us to the “depends_on” entry in the phpmyadmin container section. This tells Docker Compose that the phpmyadmin container connects to the mysql container.
Step 2: Copy the YAML File to the Ubuntu Server and Execute Docker Compose
Now that we understand the entries in the YAML file, it is time to create an actual YAML file.
Talking about creating a YAML file, it is better to use an IDE like Visual Studio Code. To do this, I created a file called mysql-phpmyadmin.yml.
Here is the file in VS Code. Can you see the levels of the indentation?
This is the benefit of using an IDE as it highlights problems (if any) with the file’s indentation.
Now that we have the file, it is time to copy it to the Ubuntu box and run “Docker Compose.” I have broken down the steps below:
- Create a directory on the Ubuntu server to copy the file into. This is optional. I created a directory called “Docker” in my home folder.
- The next step is to copy my mysql-phpmyadmin.yml file using the Secure Copy (SCP) command. To make it easy, I change the directory to the location of the file.
- After that run the command below to copy the file across.
scp mysql-phpmyadmin.yml victoradmin@IPMvUL01:/home/Docker
If the file copied successfully, your terminal will display the information about the file.
Complete the following steps in the Ubuntu box where you want to use Docker Compose to start the containers with the YAML file.
- Check that the YAML file is available using the “ls” command.
- Next, let’s set all the environment variables we need to start the containers. To do this, run the following commands (copy all, pasted and press enter):
export DB_USER="admin" \ export DB_PWD="adminpass" \ export DB_SERVER="mysql" \ export DB_NAME="test-mysql-db" \ export MYSQL_ROOT_PASSWORD="Password" \ export PMA_HOST="mysql"
- Finally, start the mysql and phpmyadmin containers with the “Docker Compose” command.
sudo -E docker compose -f mysql-phpmyadmin.yml up
Docker Compose will take a while to start the containers. When the containers are fully created and started, open another terminal and execute the “docker ps” command.
The command shows that the two containers are running and the ports are mapped as specified.
Earlier, I mentioned that Docker Compose creates a Docker Network automatically and attaches all containers to the network.
If you scroll up to the terminal where you ran the Docker Compose command, the log shows that the two containers were created but it did not show that the network was created.
But, it was actually created. Let’s see the Docker Networks by running this command.
sudo docker network ls
The command returns available Docker networks. The one created by compose is called “docker_default.”
Now, let’s confirm that the two containers are connected to this network by running…
sudo docker network inspect docker_default
If you scroll down to the “Containers” section, of the result of the command, it confirms that the phpmyadmin and mysql containers are attached to this network.
Finally, let’s access phpmyadmin from a browser.
The 192.168.0.22 is the IP address of my Ubuntu host where I started the containers. Similarly, 8081 is the phpmyadmin container port mapped on the container host (the Ubuntu server).
To login to phpmyadmin, use the username and password specified in the DB_USER and DB_PWD variables.
I have highlighted the database we created in the mysql container in the screenshot.
By the way, to stop all the running containers started via the YAML file and Docker Compse, you can use the command below:
sudo -E docker compose -f mysql-phpmyadmin.yml down
The command stops and deletes all the containers. Additionally, it deletes the Docker Network created by “Docker Compose up” command.
Alternatively, if you just want to stop the containers and not delete them, use the “stop” directive as shown below:
sudo -E docker compose -f mysql-phpmyadmin.yml stop
Instead of removing the containers, the Compose command stopped them.
So, to restart the containera, use the start directive.
sudo -E docker compose -f mysql-phpmyadmin.yml start
The contaiers are started and as shown by the result of “docker ps”, they’re running!
Frequently Asked Questions
The first step to using docker compose is to create a YAML file that defines the parameters of the containers you want to manage. After that run the – docker compose -f yaml_file up – command
Docker Compose reads one file – a YAML file specified with the -f argument
The YAML configuration file is used to define the configurations of the Docker containers managed with Docker Compose.
Not necessarily. The Dockerfile is used to create a Docker image of an application. The concept of Dockerfile is different from Docker Compose which uses a YAML file for multi-container deployment.
Using Docker Run is convenient for managing single containers. However, if you need to manage multiple containers, you need to define the container configurations in a YAML file. Then, use Docker Compose to start, stop, or remove them.
Conclusion
If you’re starting one container you may not need a YAML file or Docker Compose.
However, if you need to manage multiple Docker containers that need to talk to each other, managing them with a YAML file and Docker Compose is strongly recommended.
I hope that by demonstrating how to manage multiple containers with Docker run and then with Docker Compose, I have been able to show the benefit of Docker compse.
Before you go, remember that you can share your thoughts about this article or ask a question using the comment form at the end of this page.
Alternatively, you can respond to the “Was this page helpful?” question below.