Ruddra.com

Why Use Docker Compose, Build Argument and Environment Variable

Why Use Docker Compose, Build Argument and Environment Variable

Imagine, you have some microservices and you want to use API from one service to another, how can you do that if all of them are running in different docker container? Docker Compose has a solution for you.

Suppose you want to deploy a project in test, stage and production environment with same Dockerfile for all of them through a single Dockerfile. You can do that through Build Argument and Environment Variable.

Supercharge your containers using docker-compose

docker-compose is a great tool for orchestrating multiple docker instances. But it is not like kubernetes or docker swarm. Rather, its a simple application which allows you to communicate between docker containers, allow you to easily configure things, even help you generate service, route, build config etc for kubernetes if you use kompose.

Example

Here is an example of docker-compose.yml:

version: 3
services:
  web:
    build: .
    container_name: dz01
  db:
    image: postgres:alpine
    container_name: pz01

Use multiple compose file in same project

If you want to have different compose files for building the same project(like one for test server, another for production server), then just write two or more .yml files and when building one of them or run them just use -f argument. Like this:

docker-compose -f your_file_name.yml build

Share services from one container to another

Let us say you have a database in one container and a server in another container, how can you use that database from that server? Rather than doing the communication manually, I would recommend using docker compose. For example:

version: "2"
services:
  web:
    build: .
    container_name: dz01
    depends_on:
      - db
    volumes:
      - ./src:/src
    expose:
      - "8000"
  db:
    image: postgres:alpine
    container_name: pz01
    port:
      - "5432:5432"

In here, database service is defined as db. From web container, you can simply access the database using:

psql -h db -p 5432

Even wget db:5432 will work, because the word db will be resolved automatically through docker compose.

Docker compose shell and logs

Access docker compose shell by:

docker exec -ti container_name /bin/sh

Access docker compose log by:

docker-compose logs service_name

Build arguments or ARG

Build arguments or ARG is value which is available during build. It is useful for many cases:

. Set value of environment variable during build.

. Use same Dockerfile in multiple projects. For example, you have a django Docker Image, and you can use it in similar projects. Just you need to know project root and where the requirements file is. Example code:

ARG PROJECT_ROOT
ARG REQUIREMENTS_DIR
ENV SRC_DIR PROJECT_ROOT # Setting the environment variable from Build Argument

ADD SRC_DIR /app
WORKDIR /app
RUN pip install -r "${REQUIREMENTS_DIR}"  # Installing Requirements from ARGS
CMD ["python", "manage.py", "runserver"]

Basic usages of ARG

Pass build arguments when building the image like this:

docker build --build-arg PROJECT_ROOT=./src REQUIREMENTS_DIR=./requirements/local.txt

Or if you use docker-compose.yml then update file like this:

version: "3"

services:
  django:
    build:
      context: ./app
      dockerfile: Dockerfile
      args:
        PROJECT_ROOT: ./src
        REQUIREMENTS_DIR: ./requirements/local.pip

Envionment variable or ENV

Using ENV will create environment variables inside Docker container. You can also send them from outside when building the Dockerfile(through Build Arguments) or running the image.

Basic usages of ENV

If you are running the Image using docker command in terminal or command line, then use argument -e.

docker run -e "SRC_DIR=./src" django

Or you can declare them in docker-compose.yml file:

version: "3"

services:
  django:
    environment:
      - "SRC_DIR=./src"

Set default value for environment variables

You can simply do that by:

# With default value
ENV ABC ./src
# Without Default value
ENV XYZ

And you can override the value of ABC here by passing the environment from outside of container, ie docker run -e ABC=./abc ....

Loading environment variables from file

You can store your environment variables in a file and load them in docker-compose.yml via env_file:

django:
  env_file:
    - web-variables.env

Which is similar to what you can use docker run --env-file=FILE ... for load the environment file when running a docker image.

Using .env in docker compose

You can put environment variables inside .env file and it will be picked up automatically from docker compose. This pretty cool feature as there are some interesting usages within the docker compose file itself.

$ cat .env
PORT=8088

$ cat docker-compose.yml
version: '3'
services:
  django:
    build:
      context: .
      dockerfile: ./compose/django/Dockerfile
    image: django
    ports:
      - "${PORT}:8000"

So when you run docker-compose up then the variable ${PORT} will be replaced by 8088.

Use host machine environment variables

It will work almost same as above example. Just define the value of PORT in your host machine, then it will automatically be picked up when you run docker-compose up

$ export PORT=8088
$ cat docker-compose.yml
version: '3'
services:
  django:
    build:
      context: .
      dockerfile: ./compose/django/Dockerfile
    image: django
    ports:
      - "${PORT}:8000"

ARG vs ENV

As explained above, ARG is only build time variables. Means it will be available when you are building the Image from a Dockerfile. On the other hand, ENV can be accessed when you are running the Image. But you can still use the environment variable when building the Image. Then you have to use either ARG to update the ENV value or use a default value.

In conclusion

In this post, I tried to explain usages of docker compose, build arguments and environment variables in as detail as possible. But its better to use them in your own project to understand these better. Also checkout the reference links given below which has more detailed explanation.

Relevent posts

References

Last updated: Apr 05, 2024


← Previous
How to Write Dockerfile to Reduce Size and Build Time of Docker Images

For the past couple of years, I have been creating Dockerfile for different projects. based on those …

Next →
How to Use Volume, EntryPoint and Ignore Files in Docker

Have you worked with Docker before? Do you think you have trouble with it, like when you are …

Share Your Thoughts
M↓ Markdown