---
# System prepended metadata

title: Docker - Compose
tags: [Docker, Compose]

---

# Docker - Compose

###### tags: `Docker` `Compose`

# Reference:

* [veggiemonk/awesome-docker](https://github.com/veggiemonk/awesome-docker)
---
* [Part 9. Docker, Docker Compose, Complete Intro](https://losikov.medium.com/part-9-docker-docker-compose-complete-intro-2cfcc510bd8e)
* [Using Docker Compose to Run Your Applications](https://medium.com/rate-engineering/using-docker-containers-to-run-a-distributed-application-locally-eeabd360bca3)
---
* [docker / rabbitmq](https://hub.docker.com/_/rabbitmq/)

* [Docker-Compose made Easy with Elasticsearch and Kibana](https://levelup.gitconnected.com/docker-compose-made-easy-with-elasticsearch-and-kibana-4cb4110a80dd)

---

# [Install Docker Compose](https://docs.docker.com/compose/install/)

## Prerequisites

Docker Compose relies on Docker Engine for any meaningful work, 
so make sure you __have Docker Engine installed either locally or remote__, 
depending on your setup.

* On desktop systems like Docker Desktop for Mac and Windows, 
Docker Compose is included as part of those desktop installs.
Mac/ Windows 版有包含 Compose

* On Linux systems, first install the Docker Engine for your OS 
as described on the Get Docker page, then come back here 
for instructions on installing Compose on Linux systems.

To run Compose as a non-root user, see Manage Docker as a non-root user.

## Install Compose

Follow the instructions below to install Compose on Mac, 
Windows, Windows Server 2016, or Linux systems, or 
find out about alternatives like using the ``pip`` Python package manager 
or installing Compose as a container.

## Install a different version

The instructions below outline installation of the current stable release (v1.28.2) of Compose. 
To install a different version of Compose, 
replace the given release number with the one that you want. 
Compose releases are also listed and available for direct download 
on the Compose repository release page on GitHub. 
To install a pre-release of Compose, refer to the install pre-release builds section.


### Linux - ubuntu 安裝
1. 從 Github 下載 binary file: https://github.com/docker/compose/releases

*version 1.28.2
``docker-compose-Linux-x86_64`` 

2. clone 一份並改名為 ``docker-compose``

3. Apply __executable permissions__ to the binary:

```
sudo cp docker-compose /usr/local/bin/
sudo chmod +x /usr/local/bin/docker-compose
```

---

# [“What, Why, How” Docker Compose?](https://medium.com/faun/what-why-how-docker-compose-482e8aa021b)

## What is docker Compose? Why docker Compose?

Docker compose is a simple yet powerful tool that 
is used to __run multiple containers as a single service__. 
For example, suppose you have an application which 
requires __Nginx as a web server__ and __PostgreSQL as a database service__. 
In this case by docker-compose, you can create one single file (``docker-compose.yml``) 
which will __create both the containers as a single service without starting each separately__

同時執行多個 containers 來組合成一個 service

## How Docker Compose Works?

1. use ``yaml`` files to configure application services (``docker-compose.yaml``)
2. can __start__ all the services with a single command ( ``docker-compose up`` )
3. can __stop__ all the service with a single command ( ``docker-compose down`` )
3. able to __scale up__ the specific services when required.
works in all environments: production, staging, development, testing, as well as CI workflows


### Step 1. Install Docker Compose

Run below command from your Linux terminal to install ``docker-compose``:

```
$ pip install -U docker-compose
# check version:
$ docker-compose -v
Note: docker-compose mostly comes along while installing docker in both Mac and windows.
```


### Step 2. Create Docker Compose file

Now, create a docker compose file at any location on your system named 
``docker-compose.yml`` and add below content to that yaml file.

* Base format:
```
version: "3.7"
services:
...
volumes:
...
networks:
...
```

* Example:
```
services:

  web:
    image: nginx         # webserver for our web application
  database:
    image: postgres     # postgresql is used as database 
```

you can select more from https://hub.docker.com/search?q=&type=image

### Step 3. Check the validity of file by command

check the validity of the ``yaml`` file by running:

```
docker-compose config

output: ERROR: The Compose file './docker-compose.yml' is invalid because:Unsupported config option for services: 'web'result:
```

```
docker-compose -f elite_lin_1_docker-compose.yaml config
```

To resolve the error you must add a version on top of the file 
matched with your docker-compose version. 
check all version compatibility here: 
https://docs.docker.com/compose/compose-file/

so our updated file will look like:
```
version: "3"
services:

  web:
    image: nginx
  database:
    image: postgres
```

#### [version](https://docs.docker.com/compose/compose-file/compose-file-v3/)

Compose file format | Docker Engine release
-- | --
3.8 | Docker Engine 19.03.0 +
3.7 | Docker Engine 18.06.0 +



### Step 4. Run ``docker-compose.yml`` file

Now, run following command to run your ``docker-compose`` file:

```
docker-compose up -d

docker-compose -f elite_lin_1_docker-compose.yaml up -d
```

#### ``-d`` or ``--detach`` means detached mode
__detached mode (-d, --detach)__: 
Detached mode shown by ``-d`` or ``- detach`` means 
a docker container is running in the background of your terminal. 
It doesn’t receive ``input`` or display any ``output``.

When the process will be done you will see something like this 
at the very end of your terminal:

```
Creating dockercomposefile_web_1      ... done
Creating dockercomposefile_database_1 ... done
```

### Step 5. Verify running containers

Now verify whether your containers are running or not by:
```
docker ps
```

or you can run 
```
docker-compose ps
```

### Step 6. expose ``nginx`` in a specific port

In our yaml file we’ve just used minimum code to run the service. 
Now if we want to add more, like we want to 
__expose nginx in a specific port__ we can do it by adding below content to the yaml file:

```
ports:
  - "6080:80"
```

It means expose the port 80 (default port of nginx) of the web server 
and expose it to the 6080 port of host machine.

Now our file will look like:

```
version: "3"
services:

  web:
    image: nginx
    ports:
      - "6080:80"      
  database:
    image: postgres
```

Run ``docker ps`` again and see the changes!

Now go to http://localhost:6080/ of your host machine, you will see nginx is running!

## Step 7. Bring down the application

To stop the running containers run below command:

```
$ docker-compose down      
```

--> all containers will be stopped 

verify whether the containers are stopped or not
```
docker ps
```

---

## My case: 


``elite_lin_1_docker-compose.yml``:
```
version: "3.7"
services:
  web:
    image: nginx        # webserver for our web application
    ports:
      - "6080:80"
  db:
    image: postgres:13  # postgresql is used as database 
    restart: always
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: aA1234567
```


```
docker-compose -f elite_lin_1_docker-compose.yml config
services:
  db:
    environment:
      POSTGRES_PASSWORD: aA1234567
      POSTGRES_USER: postgres
    image: postgres:13
    restart: always
  web:
    image: nginx
    ports:
    - published: 6080
      target: 80
version: '3.7'
```


```
docker-compose -f elite_lin_1_docker-compose.yml up -d
Building with native build. Learn about native build in Compose here: https://docs.docker.com/go/compose-native-build/
Creating network "yaml_defs_default" with the default driver
Creating yaml_defs_web_1 ... done
Creating yaml_defs_db_1  ... done
```

```
docker-compose -f elite_lin_1_docker-compose.yml ps
     Name                    Command               State          Ports        
-------------------------------------------------------------------------------
yaml_defs_db_1    docker-entrypoint.sh postgres    Up      5432/tcp            
yaml_defs_web_1   /docker-entrypoint.sh ngin ...   Up      0.0.0.0:6080->80/tcp
```


---

# [Learn Docker in 5 days (Day 5 — Docker compose)](https://medium.com/faun/learn-docker-in-5-days-day-5-docker-compose-11af7b9298db)

Welcome to the last chapter of my series: Learn Docker in 5 days. We have come across a long way! And hopefully, by now you have been able to learn some of the most fundamental concepts and utilities of Containers with Docker. If you haven’t read my past four articles yet. I invite you to do so here:
1. [General Concepts](https://medium.com/devopslinks/learn-docker-in-5-days-day-1-general-concepts-fcac5a4cf0a6)
2. [Basic Commands](https://medium.com/@andrewdavisescalona/learn-docker-in-5-days-day-2-basic-commands-f1dad39925c6)
3. [Storage and Networks](https://medium.com/@andrewdavisescalona/learn-docker-in-5-days-day-3-storage-and-networks-6c11f645017d)
4. [Dockerfiles](https://medium.com/@andrewdavisescalona/learn-docker-in-5-days-day-4-dockerfiles-a39935f53e6b)

Now we are about to learn about “Docker Compose”, which is a useful tool
when it comes to Docker local development. As usual, 
I have to remind you to have Docker installed in your local machine, 
or use [Play with Docker](https://labs.play-with-docker.com/) — 
whichever option suits you the best. Bear in mind that 
you might have Docker installed without the compose utility enabled. 
So make sure to have it before continuing.

## Our Mission

So far, we have learned how to start multiple containers 
using the commands ``build`` and ``run``. 
We have also learned how to __connect those containers using Networks 
and assign them custom volumes created by us. 
The problem with this approach is how tedious it is! 
Just think of all the steps you have to take to get your application stack running. 
There must be a better way, and there is.
With “Docker Compose” we can forget of using all the 
``build``, ``run`` and ``create volume`` instructions and 
centralize those steps within a file called ``docker-compose.yml``, 
which is pretty much a recipe for our application.

For our example, we are going to set up an application that uses 
``Nginx``, ``NodeJS``, and ``Mongo``. The diagram goes like this:

---

# [Introduction to Docker Compose](https://medium.com/@devops_83824/introduction-to-docker-compose-934238b14c13)


When using Docker extensively, 
__the management of several different containers quickly becomes cumbersome__. 
Docker Compose is a tool that helps us __overcome this problem and 
easily handle multiple containers at once__. 
In this tutorial, we’ll have a look at its main features and powerful mechanisms.

## Wondering what Docker Compose is?

Docker is the most popular containerization tool in the __DevOps__ world. 
But, What is Docker Compose? 
Docker Compose is used to __run applications which have multiple containers using a YAML file__. 
There can be several cases where the docker application 
must run multiple containers for different technology stack. 
__Now building, running, connecting separate dockerfiles 
for each container can be a difficult task__; 
this is where docker-compose helps you out. 
Using a single and straightforward ``docker-compose.yml`` file, 
you can build, connect, and launch all the containers by running a single command. 
This is very useful for enterprise applications in production, 
where several applications run inside containers. 
It saves a lot of time by running 100s of application inside docker containers with ease.
 
building, running, connecting dockerfiles ``*.yml`` file

## The Docker Compose File

Docker Compose works by applying many rules declared 
within a single ``docker-compose.yml`` configuration file. 
These YAML rules, both human-readable and machine-optimized, 
provide us an effective way to snapshot the whole project 
from ten-thousand feet in a few lines. 
Almost every rule replaces a specific Docker command so that in the end we just need to run :

```
docker-compose up
```

We can get dozens of configurations applied by Compose under the hood. This will save us the hassle of scripting them with Bash or something else.
In this file, we need to specify the version of the Compose file format, at least one service, and optionally volumes and networks:

基本語法

```
version: "3.7"
services:
...
volumes:
...
networks:
...
```

Let’s see what these elements actually are.

## 1. Services

First of all, ``services`` refer to __containers’ configuration__.
For example, let’s take a dockerized web application consisting of 
a front end, a back end, and a database: 
We’d likely split those components into three images and 
define them as three different services in the configuration:

```
services:
  frontend:
    image: my-vue-app
    ...
  backend:
    image: my-springboot-app
    ...
  db:
    image: postgres
    ...
```

There are multiple settings that we can apply to services.

### 1.1. Pulling an Image:

Sometimes, the image we need for our service has already been published 
(by us or by others) in Docker Hub, or another Docker Registry. 
If that’s the case, then we refer to it with the image attribute, 
by specifying the ``image`` ``name`` and ``tag``:

取得 ``Image`` - 指定 name/ tag
 ``image`` 是 keyword

```
services:
  my-service:
    image: ubuntu:latest
    ...
```

### 1.2. Building an Image:

Instead, we might need to [``build``](https://docs.docker.com/compose/compose-file/#build) an image from the source code 
by reading its _Dockerfile_. This time, we’ll use the ``build`` keyword, 
passing the __path to the Dockerfile__ as the value:

```
services:
  my-custom-app:
    build: /path/to/dockerfile/
    ...
```

### 1.3. Configuring the Networking:

Docker containers communicate between themselves in networks created, 
implicitly or through configuration, by Docker Compose. 
A service can communicate with another service on the same network 
by simply referencing it by container name and port 
(for example ``network-example-service:80``), 
provided that we’ve made the port accessible through the ``expose`` keyword:
```
services:
  network-example-service:
    image: karthequian/helloworld:latest
    expose:
      - "80"
```

https://github.com/karthequian/docker-helloworld
A simple helloworld nginx container to get you started with docker. 
how to use it?

### 1.4. Setting Up the Volumes :

There are __three types of volumes__: 
[``anonymous``, ``named``, and ``host``](https://success.docker.com/article/different-types-of-volumes) ones. 
Docker manages both anonymous and named volumes, 
automatically mounting them in self-generated directories in the host. 
While __anonymous volumes were useful with older versions of Docker__, 
__named ones are the suggested way to go nowadays__. 
__Host volumes also allow us to specify an existing folder in the host__. 
We can configure host volumes at the service level and 
named volumes in the outer level of the configuration, 
in order to make the latter visible to other containers 
and not only to the one they belong:

```
services:
  volumes-example-service:
    image: alpine:latest
    volumes:
      - my-named-global-volume:/my-volumes/named-global-volume
      - /tmp:/my-volumes/host-volume
      - /home:/my-volumes/readonly-host-volume:ro
    ...
  another-volumes-example-service:
    image: alpine:latest
    volumes:
      - my-named-global-volume:/another-path/the-same-named-volume
    ...
volumes:
  my-named-global-volume:
```

Here, both containers will have __read/write access__ to the ``my-named-global-volume`` shared folder, 
no matter the different paths they’ve mapped it to. 
The two __host volumes__, instead, will be available only to ``volumes-example-service``. 
The ``/tmp`` folder of the host’s file system is mapped to 
the ``/my-volumes/host-volume`` folder of the container. 
This portion of the file system is writeable, which means that 
__the container can not only read but also write (and delete) files in the host machine__.

2個 host volume
container 可以存取 host machine

看了那麼多 terms 和範例, 但還是不確定如何用與它代表的意義!
又對我而言, 只要使用哪些就能達成我要的? 
只能自己 try and error?

### Declaring the Dependencies :
Often, we need to create a __dependency chain__ between our services, 
so that some services get loaded before (and unloaded after) other ones. 
We can achieve this result through the depends_on keyword:

```
services:
  kafka:
    image: wurstmeister/kafka:2.11-0.11.0.3
    depends_on:
      - zookeeper
    ...
  zookeeper:
    image: wurstmeister/zookeeper
    ...

```

``wurstmeister/kafka`` 需要用到 ``wurstmeister/zookeeper``
https://kafka.js.org/docs/running-kafka-in-development


We should be aware, however, that __Compose will not wait for the ``zookeeper`` service 
to finish loading before starting the ``kafka`` service: 
it will simply wait for it to start. 
If we need a service to be fully loaded before starting another service, 
we need to get deeper control of startup and shutdown order in Compose.

Dependencies 不代表相依的 service 會先讀取完成!
若要 service 先載入完成，才啟動其它 service, 要自行控制 startup / shutdown

2. Volumes & Networks

``Volumes``, on the other hand, are physical areas of disk space 
shared between the host and a container, or even between containers. 
In other words, a volume is a shared directory in the host, 
visible from some or all containers. Similarly, 
networks define the communication rules between containers, 
and between a container and the host. 
Common network zones will make containers’ services discoverable by each other, 
while private zones will segregate them in virtual sandboxes.

``Volumes`` 代表實體磁碟空間, 一個 host 中共享的資料夾
可以被某些 containers 存取!

``Network`` 定義 containers 之間的溝通規則 與 container / host 之間的溝通規則
分 common/ private zone

## 3. Managing Environment Variables:

Working with environment variables is easy in Compose. 
We can define static environment variables, 
and also define dynamic variables with the ``${}`` notation:


## Lifecycle Management

Let’s finally take a closer look at the syntax of Docker Compose:

```
docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]
```

While there are [many options and commands available](https://docs.docker.com/compose/reference/overview/), 
we need at least to know the ones to activate and deactivate the whole system correctly.

* To start Docker Compose :
```
docker-compose up
```

After the first time, however, we can simply use start to start the services:

```
docker-compose start
```

In case __our file has a different name__ than the default one (``docker-compose.yml``), 
we can exploit the ``-f`` and ``— file`` flags to specify an alternate file name:

```
docker-compose -f custom-compose-file.yml start
```

Compose can also run __in the background as a daemon__ when launched with the ``-d`` option:
```
docker-compose up -d
```

To safely stop the active services, we can use stop, 
which will __preserve containers, volumes, and networks, 
along with every modification made to them__:

```
docker-compose stop
```

會保留設定

To reset the status of our project, instead, we simply run ``down``, 
which will __destroy everything__ with only the exception of external volumes:
```
docker-compose down
```

---

## 檢查執行 Logs

You can check the logs with the command:

```
docker-compose logs -f
```

my case:

```
$ docker-compose -f elite_lin_postgresql2_docker-compose.yml logs -f
Attaching to yaml_defs_database_1
database_1  | 
database_1  | PostgreSQL Database directory appears to contain a database; Skipping initialization
database_1  | 
database_1  | 2021-02-08 09:33:01.310 UTC [1] LOG:  starting PostgreSQL 13.1 (Debian 13.1-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
database_1  | 2021-02-08 09:33:01.310 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
database_1  | 2021-02-08 09:33:01.310 UTC [1] LOG:  listening on IPv6 address "::", port 5432
database_1  | 2021-02-08 09:33:01.317 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
database_1  | 2021-02-08 09:33:01.324 UTC [28] LOG:  database system was shut down at 2021-02-08 09:32:31 UTC
database_1  | 2021-02-08 09:33:01.388 UTC [1] LOG:  database system is ready to accept connections

```

---

# [Use volumes](https://docs.docker.com/storage/volumes/)

## Create and manage volumes

Unlike a bind mount, you can __create and manage volumes outside the scope of any container__.

#### Create a volume:

```
docker volume create my-vol
```

#### List volumes:

```
docker volume ls
```

#### Inspect a volume:

```
docker volume inspect my-vol
```

#### Remove a volume:

```
docker volume rm my-vol
```



## Use a volume with docker-compose

A single docker compose service with a volume looks like this:

```
version: "3.9"
services:
  frontend:
    image: node:lts
    volumes:
      - myapp:/home/node/app
volumes:
  myapp:
```  

On the first invocation of ``docker-compose up`` the volume will be created. 
The same volume will be reused on following invocations.

A volume may be created directly outside of compose with docker volume create and then referenced inside ``docker-compose.yml`` as follows:

```
version: "3.9"
services:
  frontend:
    image: node:lts
    volumes:
      - myapp:/home/node/app
volumes:
  myapp:
    external: true
```

---

## Docker volume

* [docker volume create](https://docs.docker.com/engine/reference/commandline/volume_create/)
* [How to deal with persistent storage (e.g. databases) in Docker](https://stackoverflow.com/questions/18496940/how-to-deal-with-persistent-storage-e-g-databases-in-docker)


format:

```
docker volume create [volume_name]
```

my case:
```
$ docker volume create postgres_data
postgres_data

$ docker volume inspect postgres_data
[
    {
        "CreatedAt": "2021-02-08T16:26:19+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/postgres_data/_data",
        "Name": "postgres_data",
        "Options": {},
        "Scope": "local"
    }
]

$ docker volume ls
DRIVER    VOLUME NAME
local     18a7f00fb351c7a03ebf3037eca9ab103758be25ead197f966a5c455b19ca5ae
local     752d515d2e88f701cff4ae462870d1f90bf76dd1239f590916a3909cfadea0e4
local     d4fcc6819b2feaa9e3ed861d18c2956e3ed5b6b1f15d16689f176aa305cb1561
local     e5b8905f1d45d5093c98cf592086464ca84afa32d34898abc994ff9cb0149c06
local     fbcc62a084c92f9872eea850e77575b3848822553bf434be9f72259a3824eb27
local     postgres_data
local     yaml_defs_database-data
```

---

