# Docker 筆記
docker的介紹及簡單操作,歡迎留言指證錯誤或直接修改
TODO :
- [ ] 介紹 -> Network -> MACVLAN 待測試
- [ ] 操作 -> Docker Swarm 使用 待新增
---
# 介紹
## 簡介
Docker為一個開源軟體專案,輕量化的虛擬技術,
在原本的OS上增加一層虛擬化容器,是以應用為其核心
不同於虛擬機以OS為核心需包含自己的OS,
Docker是與host共用kernel,
在部屬時間及空間的節省上都更優於虛擬機

除了OS的有無以外,VM即使在沒有應用運行的時候也會保持開啟,
而 docker container 在應用結束後便會自動停止
### 優點
- 低成本(時間、空間、效能)
- 開發者: 環境架設方便,統一開發環境
- 正式部屬: 避免因不同執行環境造成的問題
### 缺點
- 仍然存在安全上的隱患
- 共用kernel所以並不是實質意義上的隔絕
- 缺乏像vm disk的儲存空間(解法: 詳見[Volume](#Volume))
- 並不是所有應用都適合被包裝
---
## Image & Container
### Image
- 可重複產生container的模板
- 分層式架構
- 唯讀性質
- 從DockerHub上pull image
- 使用DockerFile自訂(詳見[DockerFile](#DockerFile))
### Container
- 基於image啟動的實體
- container間被隔離且不互相衝突
- 在image上外加一層可寫層
### 分層式架構

從圖可看出image是由base image不斷疊加資料層而來,
container則是在最上層的可寫層做操作
### 查看 image layer
以mysql image為例

tag一般用來標註版本,
點擊Tags可看到各種版本的mysql image
再來點擊tag就可看到image的layer

從layer就能夠大致推測dockerfile是如何撰寫

---
## Volume
- container不像vm有自己的disk,一旦消失資料也會隨之不見
- volume為docker提供的一種資料保留方法
- 將container內指定路徑mapping到host的指定路徑上
- 可用docker指令創建由docker管理的volume(可用指令刪除、列出、詳細資訊),或自行指定host路徑(自行管理)
---
## Network
使container對container或container對host能互相溝通
### Bridge
- 預設網路介面
- 使container可與host或其他container連線
- 創建時使用
`docker run -p hostPort:targetPort`
連接host及container的port
- 使用
`docker network create -d bridge`
自訂義bridge

### Host
- 與host共用網路
- 取消了container在網路上的隔絕性質
- 只能在linux系統使用
### MACVLAN(待測試)
- 使用前須先將網卡開啟混雜模式(promiscuous mode)
- 在實體網卡上設定多個 mac address 或 ip 分配給 container
- 讓只能使用實體網卡的應用能正常運作

---
### Overlay
- 使不同host間的container能互相溝通
- Docker Swarm

---
## Docker Swarm
- 管理在多個host上的container
- 自動擴展或縮減container數量
- 分散流量
swarm 將每個 host 都視為一個 node , node 又分為以下兩種
- manager : 控制worker、訊息同步、分派任務
manager 中有一個 leader 負責執行上述工作,一旦 leader 失效,其餘 manager 就會使用 [Raft Consensus Algorithm](http://thesecretlivesofdata.com/raft/) 推選出新的 leader 維持運作,manager的容忍失效數為 (n-1)/2 ,所以官方建議 manager 數量為奇數
- worker : 執行service

---
# 操作
## Image常用指令
- `docker image ls` : 列出所有 image
- `docker pull IMAGE` : 從 dockerhub 下載 image
- `docker push IMAGE` : 上傳 image
- `docker rmi IMAGE` : 刪除 image
- 建立 image 詳見 [DockerFile](#DockerFile)
---
## Container常用指令
- `docker ps -a` : 列出 container 包含停止的,-a 意為 all ,選用
- `docker create CONTAINER` : 創造 container
- `docker start CONTAINER` : 啟動 container
- `docker stop CONTAINER` : 停止 container
- `docker rm CONTAINER` : 刪除 container
- `docker exec CONTAINER COMMAND` : 令container執行指令,若要執行 /bin/bash 等等終端介面需在 exec 後加 -it
- `docker cp FILE CONTAINER:PATH` : 從host複製檔案進 container ,也可反向操作,用法類似 scp
- `docker run [OPTION] IMAGE`: 創造並運行 container,option如下
`-i` : 保持stdin開啟
`-t` : 賦予終端介面
`-v` : volume,寫法為,`VOLUME:targetPATH`、`hostPATH:targetPATH`
`-p` : port forwarding,寫法為,`hostPORT:targetPORT`
`-d` : detach,背景執行
`-e` : 設定環境變數
`--rm` : container 停止時自動刪除
`--name` : 命名 container (建議要用)
---
## Volume常用指令
- `docker volume ls` : 列出所有 volume
- `docker volume create VOLUME` : 創造 volume
- `docker volume rm VOLUME` : 刪除 volume
---
## Network常用指令
- `docker network ls` : 列出所有 network
- `docker network create NETWORK` : 創造 network
- `docker network rm NETWORK` : 刪除 network
- `docker network connect NETWORK CONTAINER` : 將 container 連接 network
---
## 其他
- `docker login` : push image 前需先登入,相對也有 logout
- `docker inspect OBJECT` : 顯示 docker 物件的詳細資訊
- `docker --version` : 查看版本
---
## DockerFile
### 關鍵字說明(可新增)
- FROM 設定 base image ( dockerfile 的開頭 )
- RUN 執行指令
- WORKDIR 設定工作目錄
- COPY/ADD 將檔案複製進image
- ENV 設定環境變數
- EXPOSE 對其他container開啟port
- CMD/ENTRYPOINT 開啟container時執行
### 簡單範例
下面兩個範例為 web server 及資料庫 mysql 的 image,串接起來即為一個小網站
- django web server image
```dockerfile=
FROM python:3.8
RUN apt-get update
WORKDIR /usr/src/app
COPY /DataBaseProject/ .
RUN pip install -r requirements.txt
CMD python manage.py runserver 0.0.0.0:8000
```
line 1 : 此 server 是用 python 套件 django 所建,所以用 python 為 base image
line 3 : 更新以免發生問題
line 5 : 設定我的工作路徑
line 7、8 : 從 host 複製專案(包含前端及後端)及安裝所需套件
line 10 : 讓我的 container 開啟時自動啟動 server
- mysql server image
```dockerfile=
FROM mysql
ENV MYSQL_ROOT_PASSWORD=0000 \
MYSQL_DATABASE=DBproject
ADD /DataBaseDDL/* /docker-entrypoint-initdb.d
EXPOSE 3306
```
line 1 : base image 為 mysql
line 3、4 : 設定環境變數,資料庫密碼及要預建的資料庫名稱
line 6 : 複製資料庫設定檔到指定初始路徑
line 8 : 對其他 container 開放 port 3306 ( mysql 預設 port ),應該可省略,因為 mysql image 預設就有開放 port
### build指令
```
docker build -t IMAGE -f FILE PATH
```
- -t : 定義 image 名稱
- -f : dockerfile 名稱(Dockerfile為預設名稱,若為預設名稱不用特別註明)
---
## Docker Compose
撰寫YAML檔來定義多個容器,可使用一行指令啟動或刪除所有容器,不必逐一執行
### 關鍵字說明(可新增)
- version : 不同版本的 docker 支援的 compose 版本也不同,需查[對應表](https://docs.docker.com/compose/compose-file/)
- service : 設定 service name
- network : 設定使用的 network 名稱
- volume : 設定 volume ,寫法如下 `hostPath:targetPath` 或 `volumeName:targetPath`
- port : port forwarding,寫法為 `hostPort:targetPort` 或 `targetPort` (不指名 hostPort 會隨機分配)
- healthcheck : 確認container是否活著,內容詳見[官方說明](https://docs.docker.com/compose/compose-file/compose-file-v3/#healthcheck)
- restart : 何種條件可重啟,四種選項, "no" 、 always 、 on-failure 、 unless-stopped , 詳見[官方說明](https://docs.docker.com/compose/compose-file/compose-file-v3/#restart)
- depends_on : 設定啟動順序,會在 depend on 的service啟動後啟動
### 特殊說明(可新增)
- 在非 swarm mode 時 service 等同於 container ( swarm mode 下 service 可能會有多個 container )
- 在檔案最後要特別統整使用的 network 及 volume , 這時可設置 network driver , 沒設置則是預設使用 bridge
### 簡單範例
以下範例使用到前一節所示範的 dockerfile ,建立起一個簡易的網站
```yaml=
version: "3.9"
services:
db:
image: barry0310/my_mysql
networks:
- backend
volumes:
- db_vol:/var/lib/mysql
healthcheck:
test: mysqladmin ping -h localhost -p0000
interval: 10s
timeout: 5s
retries: 3
restart: on-failure
web:
image: barry0310/my_django
networks:
- backend
ports:
- "80:8000"
depends_on:
db:
condition: service_healthy
healthcheck:
test: curl -f localhost:8000
interval: 5m
timeout: 5s
retries: 3
restart: on-failure
volumes:
db_vol:
networks:
backend:
```
line 1 : 3.9版本的 docker compose
line 4~15 : 創建 database container
line 17~31 : 創建 web server container
line 33~36 : 列出使用的 volume 及 network
### 相關指令
- 啟動: `docker-compose -p NAME up -d `
- 移除: `docker-compose -p NAME down`
註 : -p 意為 project name 、 -d 為 detach , 不然預設會跑出執行log
---
## Docker Machine
有預裝 docker 的虛擬機,為快速創立 swarm 的 node
### 安裝
在 windows 環境下的安裝
使用 Git bash 執行
```bash=
if [[ ! -d "$HOME/bin" ]]; then mkdir -p "$HOME/bin"; fi && \
curl -L https://github.com/docker/machine/releases/download/v0.13.0/docker-machine-Windows-x86_64.exe > "$HOME/bin/docker-machine.exe" && \
chmod +x "$HOME/bin/docker-machine.exe"
```
輸入`docker-machine version`以確認安裝成功
### 額外設定
因為是使用 windows hyperv 的關係需要做額外的設定
搜尋

進來後右邊選虛擬交換器管理員

新增外部交換器

名稱隨意

### 指令
- `docker-machine create -d hyperv --hyperv-virtual-switch "SWITCH" NAME` : 創建 vm
`-d` : driver , `--driver` 也可
`--hyperv-virtual-switch` : SWITCH 替換成前面額外設定的 switch 名稱
- `docker-machine start NAME` : 啟動 vm
- `docker-machine stop NAME` : 停止 vm
- `docker-machine rm NAME` : 刪除 vm
- `docker-machine ssh NAME` : 進入 vm
- `docker-machine ls` : 所有 vm
---
## Docker Swarm 使用(待新增)
---
# 參考資源
https://github.com/twtrubiks/docker-tutorial
https://github.com/twtrubiks/docker-swarm-tutorial
https://ithelp.ithome.com.tw/articles/10242460
https://docs.docker.com/compose/compose-file/compose-file-v3/
###### tags: `Docker`