# 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
```
---