Wei's
Dev
Journal

Containerise with Docker Fundamental Part 02

article 08 cover

Image source: by Wei Chu

Table:

Docker Compose - Multiple Containers Configuration

Definition:

A docker-compose.yml file is used to define and manage multi-container Docker applications. It allows you to configure your application's services, networks, and volumes in a single file, making it easier to manage and deploy complex applications.

Exercise:

Step 1. Creating a Docker-compose.yml in the working directory.

The configuration primarily featuring 2 parts: version & services.

docker-compose.yml

  1. version: this specifies the version of the docker compose file format.
  2. services: this defines the container services that make up the application ( ex: web app, database, etc.)

Step 2. Using commands to run the docker-compose file

  1. Run the command $ docker-compose up -d to build the image. The flag -d means starting the services in detached mode, which sill means that the containers will run in the background, allowing you to continue using the terminal for other commands. The image is successfully built shown as below: docker terminal screenshot
  2. After the above process, using the command $ docker ps to call the list of existing images to check the newly created image. Shown as below: docker terminal screenshot
  3. Checking with the localhost network on a browser to test the web connection. It should be connected shown as below: browser view

Step 3. Bringing down the resources

  1. Using the command $ docker-compose down -v to remove the container built by the image specified in the dockerfile. The flag -v means the anonymous volumes will deleted as well. Using the flag to avoid redundant volumes build up.
  2. Using the command $ docker ps to double check if the resource has been removed. The result is shown as below: docker-compose terminal screenshot

Step 4. Bringing up the docker-compose file to see what happens

  1. This time, the container building process was way quicker than the beginning when the docker-compose file was run for the first time. This is because the process won't rebuild the image unless the dockerfile was modified before docker-compose file was run. Building the container this time was a static process.The result is shown as below: docker-compose terminal screenshot
  2. Forcing Rebuild - We can run the command $ docker-compose up -d --build to force docker rebuild the image if necessary.


Docker Compose & Development Staging

  • Using Docker Compose to build both development environment & production environment. It can be achieved by using 2 docker files, but Docker Compose creates a more integrated workflow.
  • The exercise here focuses on using Docker Compose configuration to dictate which running environment used rather than explicitly specify in the dockerfile.

Step 1. Stop explicitly indicating the running environment in the dockerfile

  1. Changing the default command executed when a container is started by the Docker Image.
  2. Stop explicitly indicating the running environment in the dockerfile by changing the command for running the app from CMD [“npm”, “run”, “dev”] to CMD [”node”, “index.js”] which is for generally bringing up the app. The running environment will be specified later by Docker Compose.

    Dockerfile

    github  commit change

Step 2. Start writing docker-compose configuration for both dev & prod environment

  1. Starting with the docker-compose.yml as the base file containing shared configuration variables.

    docker-compose.yml

  2. For Dev environment, creating another Docker Compose YAML file for dev environment called docker-compose.dev.yml.

    docker-compose.dev.yml

  3. run the following command to bring up the container wit docker compose files for development environment:

    bash

    The result: docker compose terminal screenshot
  4. The web page should be working in the browser. browser review
  5. Testing if the bind-mount has been successfully created as well.
    1. current preview content: browser review
    2. change the source code of the web page, replacing the “!!!” with a full stop “.”:

      index.js

      index.js code view
    3. The web preview has been updated as well once the update of the source code has been saved. browser review
  6. Bringing down the container with the following command:

    bash

    Result: docker compose terminal screenshot
  7. For PROD environment, creating another Docker Compose YAML file for prod environment called docker-compose.prod.yml:

    docker-compose.prod.yml

  8. Using the same command as the one for the DEV environment, but this time change the Docker Compose Environment file to docker-compose.prod.yml in the script:

    bash

    Result: docker compose terminal screenshot
  9. You will find that the review page in the browser is not reflecting the changes in the source code from the previous section when we were testing the bind mount of the dev environment: browser review That is because any update to the dockerfile and the source code, the image of the container needs to be rebuilt.
  10. Therefore we will need to bring down the container and run the -- build flag in our command to force the docker compose rebuild the image before bringing up the container:
    1. Run the following command to bring down and remove the containers:

      bash

    2. Run the following command to force docker compose rebuild the image before deploying the containers:

      bash

      Result: docker compose terminal screenshot
  11. We immediately can see that the web preview now has reflected the update of the web page source code done earlier: browser review
  12. Try to change the source code again to see if the preview page is still reflecting the update:

    index.js

    index.js code view It is not. That proves we have set up the dev and prod environment to pipeline our project development. It should not be bind-mount to the production, only when the docker image had been rebuilt to deploy new changes to the prod environment. browser review

Clean-up: Excluding docker-compose files and nodemon module for DEV from the PROD stage container

Step 1. Listing files-to-be-excluded in the .dockerignore

using .dockerignore to exclude any file related to Docker Compose from being parsed into the prod container.

  1. If we enter the PROD node and list out the files existed in the instance directory, we will find docker compose files are parsed into the instance, and we don't want that for security and best practice reason. docker compose terminal screenshot
  2. Exist the instance, and head to the .dockerignore file. Writing in docker-compose* in the list. * will help system to detect and ignore all the files containing phrase docker-compose in their filename.

    .dockerignore

    dockerignore screenshot

Step 2. If statement bash script in dockerfile for choosing installed modules

We can give bash script if statement in the dockerfile to make Docker Compose have the intelligence of choosing what NODE.js modules should be installed and what shouldn't.

  1. Firstly, we can see the npm dependency on nodemon is specified for DEV in the dependency configuration file package.json:

    package.json

    package.json file view
  2. However, we can also see the nodemon package in the PROD instance, which is not needed and taking up storage for nothing: PROD node instance installed modules list
  3. Therefore, we need to modify running script in the dockerfile with if statement shown as below:

    Dockerfile

    if statement in the docker file
  4. ARG in the previous script means it will pass the NODE_ENV argument into the process of running a container. Subsequently, The argument then will have to be specified in the Docker Compose DEV environment file:

    docker-compose.dev.yml

    docker-compose dev file
  5. After finishing the configuration change above, testing the workflow of bringing up and down of the app running in the DEV instance:
    1. bringing down the existing container and bringing up again with DEV docker-compose file. Including the flag --build to rebuild the image. docker-compose terminal view
    2. Check if bind-mount is working.

      index.js

      index.js code view browser review
  6. Now testing the PROD instance side:
    1. Bringing down the container file again and bring up with prod docker-compose file and the flag --build to rebuild the image.
    2. check if bind amount is working by changing the source code of the web app:

      index.js

      index.js code view
    3. The web page is not reflecting to the change in the source code. That is correct. browser review
  7. Check again if docker-compose files are excluded from the PROD instance. Enter the prod container instance to check: docker compose PROD instance terminal view
  8. If statement to make Docker Compose intelligently control dependency is now completed.