---
# System prepended metadata

title: Docker compose

---

# Docker compose
### YAML
![](https://hackmd.io/_uploads/HJQ6_Gshn.png)

在介紹Docker  compose前，必定要先提到**YAML**全名 "YAML Ain't a Markup Language" YAML不是標記語言，是一個可讀性高，用來表達資料序列化的格式。YAML參考了其他多種語言，包括：C語言、Python、Perl。
## 為甚麼要用YAML
### JSON
JSON的語法是YAML1.2版的子集,，同時非常接近 YAML1.0與1.1版的子集，因此大部分的JSON檔案都可以被YAML的剖析器剖析。這是因為JSON的語法結構和YAML的內建格式相同。雖然大範圍的分層也可以使用類似JSON的內建格式，不過YAML標準並不建議這樣使用，除非這樣編寫能讓檔案可讀性增加。YAML的許多擴展在JSON是找不到的，如：進階資料形態、關係錨點、字串不需要雙引號、對映資料形態會儲存鍵值的順序。



### 非階層式的資料模型
跟SDL、JSON等，每個子結點只能有單一一個父節點的階層式模型不同，YAML提供了一個簡單的關係體制，可以從樹狀結構的其他地方，重複相同的資料，而不必顯示那些冗餘的結構，會自動將那些參考資料的結構展開，所以程式在使用時並不會查覺到哪些資料是解碼自這種結構。XML則不會將這種結構展開。這種表示法可以增加程式的可讀性，並且，在那種『大部分參數維持和上次相同，只有少數改變』的設定檔及通訊協定中，可以減少資料輸入錯誤。一個例子是：『送貨地點』和『購買地點』在發票的紀錄中幾乎都是相同的資料。


### 課程開始
不知道各位有沒有感覺到一件事，那就是如果要同時開多個服務，需要一個一個開起來，相當的麻煩。且在微服務的概念中，正常會需要多個小的服務共同組成一個大的服務，因此同時開啟多個小服務是正常情況，那有沒有一個方式能夠快速開啟需要的服務呢？

當然有， Docker 也幫你想好了，那就是 Docker-Compose 。

Docker-Compose 可以用一個指令一次啟動多個 Container ，並且可以讓它們之間互相構通。

首先就稍微改一下之前的 Demo ，假設我們需要一個 Flask 的後端、一個 Redis 的快取。

那麼這時候你就需要先寫一個 docker-compose.yml 的檔案。


```  cmd=
test-project
├── app.py
├── docker-compose.yml
├── Dockerfile
└── requirements.txt
```
```app.py```

``` python= 
import os

from flask import Flask
from flask_redis import FlaskRedis


app = Flask(__name__)
app.config['REDIS_URL'] = os.environ['REDIS_URL']

r = FlaskRedis(app)


@app.route('/')
def index():
    if not r.exists("count"):
        r.set("count", 0)
    r.incr("count")
    return r.get("count")


if __name__ == "__main__":
    app.run(host="0.0.0.0")
```
```docker-compose.yml```
``` YAML=
version: '3.8'

services:
  backend:
    build: .
    container_name: backend_flask
    networks:
      - net
    ports:
      - 5000:5000
    environment:
      - REDIS_URL=redis://cache:6379/0
    volumes:
      - .:/project:ro
    command: "python3 app.py"
  cache:
    image: redis
    container_name: database_redis
    networks:
      - net
    ports:
      - 6379:6379

networks:
  net:
    name: frnet
    driver: bridge

```

首先第一部分 version: '3.8' 是什麼意思呢？這個意思是這個文件的版本，主要是告訴 Docker 引擎該用哪個。不過也不用了解得太詳細，因為這個標籤官方說已經棄用了。詳細的部分請參考一下連結：https://docs.docker.com/compose/compose-file/#compose-file

接著先跳到第三部分 networks ，這部分就是跟前天的內容，不過是用 Docker-Compose 重現出來。用 Docker-Compose 的方式可以同時啟動多個服務，並且指定它們連結到某個 Network ，用這個方式就可以偷懶，不用一個一個指定連接到某個 Network 了。 net 是在 Docker-Compose 中使用的名稱； name 是這個 Network 實際的名稱； driver 是 Network 的類型。

接著是第二部分 services 的區塊，看名稱應該很容易理解吧，就是想要開啟的服務。
內部又分兩個小區塊 backend 跟 cache ， backend 的部分主要有 7 個小項，build 就是指定 Dockerfile 的路徑； container_name 就是 run 起來之後 Container 的名稱； network 就是要連接的 Network ； ports 是要開啟的 port ，前面是 host 後面是 container ；environment 是設定環境變數，需要注意的是，這邊如果有環境變數是有連結是連到其他 Container 的，需要將名稱設定為 Docker-Compose 中的服務名稱，在這邊就是 redis://cache:6379/0 中的 cache ； volumes 還是跟前面 Day 07 的 Valume 一樣；最後的 command 就是 Container 啟動時的指令，需要注意的是 Docker-Compose 會覆蓋掉 Dockerfile 中的 COMMAND 。cache 的部分中只有一個需要特別說明，那就是 image ，主要是直接使用已經打包好的 Image 。
當你寫好了 docker-compose.yml 之後，接著就可以下指令讓所有服務一起執行起來了。
``` python= 
$ docker-compose up
```
接著就可以看到兩個服務一起執行起來了。

如果需要將所有服務一起停下，也可以透過指令一起停下。
``` python= 
$ docker-compose down
```