# Docker 實戰 3 - Docker-compose
## 前言
前兩篇和大家介紹了什麼是Docker以及 Dockerfile的寫法
- [Docker 實戰 1 - 五分鐘了解 Docker](/lo88XIBlTiGJeiUDs8JmFw)
- [Docker 實戰 2 - 相關指令與Dockerfile](https://hackmd.io/@emmmmmma/ikFuYeHLRdeSM6p88_IhKA)
前面提到透過Dockerfile建立image並且用docker run的指令建立容器執行image,但如果同時有好幾的image要執行呢?例如寫後端的時候,除了建立後端的image之外,通常還會有資料庫的環境,換言之沒有compose的情況下就要執行兩次docker run,後續也會不好管理。這時候可以管理多個 Container 的工具 docker-compose就登場啦!
## Docker Compose
- 簡單來說Compose就是一個管理container的工具
- 檔名是.yml docker-compose.yml,只要把要執行的image寫進檔案裡面
## 常用指令
實作的部份主要就是要把 Docker-Compose 安裝起來,然後撰寫一個 docker-compose.yml,並且使用 docker-compose up,指令把所有的 Docker Container 啟動起來,步驟如下:
- 建立和刪除 container
docker-compose up
docker-compose down
> 在後面加上 -d ,就會在背景執行
- 起重和停止 container
docker-compose start
docker-compose stop
> docker-compose up與docker-compose start最大的差別在於,前者可以從0到有建立image和container但後者只能啟動已經建立的container而已
- 查看運行中的conatiner
docker-compose ps
> 和docker指令相似,用ps就可以列出所有資訊
## docker-compose.yml
### 基本語法
- version:使用哪個版本的語法,現在通常用3以上的版本
- services:設定容器的單位通稱為service,一個 service 設定可以用來啟動多個 container
- network : 沒有設定的話就代表services底下的container會被加入到一個預設的myapp_default網路中,
### 實作 Docker container
以下教大家幾個常用的docker-compose.yml寫法
#### 已經建立好image
1. 如果先前已經在前後端的資料夾中使用docker build建立個別的image,就可以建立一個docker-compose.yml檔案,並在裡面直接宣告image名稱
```dockerfile=
version: "3.9" #版本宣告
services:
frontend: # 宣告 service的名稱
image: frontend-image # 宣告要run起來的image名稱
ports:
- '3000:3000' # 設定port
restart: always # 如果server掛掉了會自動重啟
server:
image: backend-image # 宣告要run起來的image名稱
ports:
- '3311:3311'
restart: always
```
#### 執行的時候一起建立image
build會根據你設定的路徑去找該路徑底下的Dockerfile檔案去建立image
```dockerfile=
version: "3.9" #版本宣告
services:
frontend: # 宣告 service的名稱
build: ./frontend # 宣告建立image的路徑
ports:
- '3000:3000' # 設定port
restart: always # 如果server掛掉了會自動重啟
server:
build: ./backend # 宣告要run起來的image名稱
ports:
- '3311:3311'
restart: always
```
:::warning
:writing_hand: 宣告image和build的差別在於,如果是放在虛擬機上部署,前者只需要用docker load的方式把image抓下來就可以使用了,後者變成要把整份程式碼上傳才行,相對來說會不安全一點點。
:::
#### 加入資料庫
下方範例加入network的範例,當我們夠過docker部署,且外界要連上網址時,docker預設的網路模式bridge會出現一些問題(本篇不會詳細介紹),所以大家只先記得,透過設定network可以讓容器內外部的溝通更加方便!
```dockerfile=
version: "3.9"
networks:
shared:
services:
frontend:
image: analytic-frontend
ports:
- "3000:3000"
networks:
- shared
restart: always
server:
image: analytic-server
ports:
- '5006:5006'
depends_on:
- db
environment:
DB_HOST: db
DB_USER: docker
DB_PASSWORD: 1234
DATABASE_URL: "postgresql://docker:1234@db:5432/docker"
networks:
- shared
restart: always
db:
image: 'postgres'
ports:
- '5432:5432'
environment:
POSTGRES_DB: docker
POSTGRES_PASSWORD: 1234
POSTGRES_USER: docker
networks:
- shared
volumes:
- ./postgres:/var/lib/postgresql/data
nginx:
image: 'nginx'
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/conf.d
```
## 總結
恭喜大家看完Docker系列的教學啦,至於後面的兩個大坑暫時還不會教,因為我自己也還沒仔細研究XD
總之,只要能先把docker還有docker-compose學好,理論上可以解決80%的問題啦!

## 參考資料
- [Compose file version 3 reference](https://docs.docker.com/compose/compose-file/compose-file-v3/)
- [Networking in Compose](https://docs.docker.com/compose/networking/)
- [三周目 - Docker network](https://ithelp.ithome.com.tw/articles/10206725)