Docker 基本教學 - 從無到有 Docker-Beginners-Guide   教你用 Docker 建立 Django + PostgreSQL 📝
# docker-tutorial

 Docker 基本教學 - 從無到有 Docker-Beginners-Guide

 教你用 [Docker](https://www.docker.com/) 建立 [Django](https://github.com/django/django) + [PostgreSQL](https://www.postgresql.org/) 📝

* [Youtube Tutorial PART 1 - Docker 基本教學 - 從無到有 Docker-Beginners-Guide](https://youtu.be/Wg5m0-Jyox8)
* [目錄](https://github.com/twtrubiks/docker-tutorial#%E7%94%A8-docker-%E5%AF%A6%E6%88%B0-django-%E4%BB%A5%E5%8F%8A-postgre) - [Youtube Tutorial PART 2 - 用 Docker 實戰 Django 以及 Postgre](https://youtu.be/aZ6woJ7qekE)
* [目錄](https://github.com/twtrubiks/docker-tutorial#%E5%85%B6%E4%BB%96%E7%AE%A1%E7%90%86-docker-gui-%E7%9A%84%E5%B7%A5%E5%85%B7) - [Youtube Tutorial PART 3 - Docker 基本教學 - 透過 portainer 管理  Docker](https://youtu.be/VZjHmBcEcew)
* [目錄](https://github.com/twtrubiks/docker-tutorial#docker-registry) - [Youtube Tutorial PART 4 - Docker push image to Docker Hub 教學](https://youtu.be/dVBKwmqO5e4)

其他說明

* [Youtube Tutorial-Ubuntu(Linux) 如何安裝 docker](https://youtu.be/eS_HMBC_RaA)
* [目錄](https://github.com/twtrubiks/docker-tutorial#docker-compose-networks) - [Youtube Tutorial-docker-compose networks 說明](https://youtu.be/wmV9WfkpyGk)
* [目錄](https://github.com/twtrubiks/docker-tutorial#docker-container-%E5%85%A7%E5%A6%82%E4%BD%95%E9%80%A3%E6%8E%A5%E5%88%B0%E6%9C%AC%E6%A9%9F-localhost-%E6%9C%8D%E5%8B%99) - Docker container 內如何連接到本機 localhost 服務
* [目錄](https://github.com/twtrubiks/docker-tutorial#docker-compose-updown-%E5%92%8C-restart-%E7%9A%84%E5%B7%AE%E7%95%B0) - [Youtube Tutorial-docker-compose up/down 和 restart 的差異](https://youtu.be/nX-sbLPz-MU)
* [目錄](https://github.com/twtrubiks/docker-tutorial/tree/master/docker-auto-run-linux) - [Youtube Tutorial-Linux 教學-開機自動啟動 docker / compose](https://youtu.be/c4YIQHCDLnQ)
* [目錄](https://github.com/twtrubiks/docker-tutorial/tree/master/docker-env-tutorial) - [Youtube Tutorial - Docker 基本教學 - 在 docker compose 中善用 Environment variables](https://youtu.be/JwbI1aNKbtY)
* [目錄](https://github.com/twtrubiks/docker-tutorial#%E5%A6%82%E4%BD%95%E6%B8%85%E9%99%A4-docker-container-log) - [Youtube Tutorial - 如何清除 Docker container log](https://youtu.be/SiG0tmwhqqg)
* [目錄](https://github.com/twtrubiks/docker-tutorial#json-file-logging-driver) - [Youtube Tutorial - Docker 中的 JSON File logging driver(container log)](https://youtu.be/wb9bONgnFn4)

## 簡介

[Docker](https://www.docker.com/)

![](https://i.imgur.com/gDcSwcs.png)

***Containers as a Service ( CaaS ) - 容器如同服務***

算是近幾年才開始紅的技術，蠻多公司都有使用 Docker，而且真的很方便，值得大家去了解一下 :smile:

如果你有環境上不統一的問題？ 請用 Docker :smile:

如果你有每次建立環境都快抓狂的問題？ 請用 Docker :blush:

如果你想要高效率、輕量、秒開的環境，請用 Docker :blush:

如果你不想搞死自己，請用 Docker :smile:

如果你想潮到出水，請一定要用 Docker :laughing:

### 什麼是 Docker

[Docker](https://www.docker.com/) 是一個開源專案，出現於 2013 年初，最初是 Dotcloud 公司內部的 Side-Project。

它基於 Google 公司推出的 Go 語言實作。（ Dotcloud 公司後來改名為 Docker ）

技術原理我們這邊就不提了，簡單提一下他的好處。

我們先來看看官網的說明

Comparing Containers and Virtual Machines ( 傳統的虛擬化 )

![](https://i.imgur.com/IqiGyoJ.png)

從這張圖可以看出 Containers 並沒有 OS ，容量自然就小，而且啟動速度神快

詳細可參考 [https://www.docker.com/what-container](https://www.docker.com/what-container)

Virtual Machines 是什麼？

類似 [https://www.virtualbox.org/](https://www.virtualbox.org/)，我們可能用它裝裝看其他作業系統，例如說

我是 MAC，但我想玩 Windows，我就會在 MAC 中裝 VM 並且灌 Windows 系統。

一個表格了解 Docker 有多棒 :+1:

Feauture  | Containers                  |  Virtual Machines ( 傳統的虛擬化 )
--      | ----------            | ----------
 啟動   | 秒開 | 最快也要分鐘
 容量 | MB        | GB
 效能 | 快        | 慢
 支援數量 | 非常多 Containers        | 10多個就很了不起了
 複製相同環境 | 快        | 超慢

不理解:question::question::question:

我們來看一張圖，包準你懂

![](https://i.imgur.com/H8wmOUh.jpg)

圖的來源
[https://blog.jayway.com/2015/03/21/a-not-very-short-introduction-to-docker/](https://blog.jayway.com/2015/03/21/a-not-very-short-introduction-to-docker/)

### 為什麼要使用 Docker

潮～ 不解釋 :satisfied:

#### 更有效率的利用資源

比起像是 [https://www.virtualbox.org/](https://www.virtualbox.org/)，Docker 的利用率更高，我們可以設定更多

的 Containers ，而且啟動速度飛快！！:flushed:

#### 統一環境

相信大家都有每次搞電腦的環境都搞的很煩的經驗 :angry:

假設今天公司來了個新同事，就又要幫他建立一次環境 :expressionless:

不然就是，我的電腦 run 起來正常阿～ 你的怎麼不行，是不是 xxx 版本的關係阿 :joy:

相信大家多多少少都遇過上面這些事情，我們可以透過 Docker 來解決這些問題，

保持大家環境一致，而且要建立的時候也很快 :smile:

#### 對於 DevOps 的好處

對於 [DevOps](https://zh.wikipedia.org/wiki/DevOps) 來說，最希望的就是可以設定一次，將來在其他地方都可以快速建立環境且正常執行。

### Docker 概念

建議大家先了解一下 Docker 中的幾個名詞，分別為

***Image***

映像檔，可以把它想成是以前我們在玩 VM 的 Guest OS（ 安裝在虛擬機上的作業系統 ）。

Image 是唯讀（ R\O ）

***Container***

容器，利用映像檔（ Image ）所創造出來的，一個 Image 可以創造出多個不同的 Container，

Container 也可以被啟動、開始、停止、刪除，並且互相分離。

Container 在啟動的時候會建立一層在最外（上）層並且是讀寫模式（ R\W ）。

這張圖解釋了 Image 是唯讀（ R\O ）以及 Container 是讀寫模式（ R\W ） 的關係

![](https://i.imgur.com/wVvrWwJ.png)

更多關係可參考 [https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/#images-and-layers](https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/#images-and-layers)

***Registry***

可以把它想成類似 [GitHub](https://github.com/)，裡面存放了非常多的 Image ，可在 [Docker Hub](https://hub.docker.com/) 中查看。

更詳細的我這邊就不再解釋惹，留給大家做作功課:stuck_out_tongue:

## 安裝

Windows

請先到 Docker 官網

[https://www.docker.com/docker-windows](https://www.docker.com/docker-windows)

下載 stable 版本

![](https://i.imgur.com/ryKtNXm.jpg)

接下來就是無腦安裝，安裝完後他會叫你登出電腦，點下去後就會幫你登出電腦

![](https://i.imgur.com/EE7XmYM.jpg)

接著如果你的電腦沒有啟用 [Hyper-V](https://msdn.microsoft.com/zh-tw/library/hh831531(v=ws.11).aspx) ，他會叫你重啟電腦
(一樣，點下去就對惹)

( 更多可 Hyper-V 介紹請參考 [https://docs.microsoft.com/zh-tw/virtualization/hyper-v-on-windows/about/](https://docs.microsoft.com/zh-tw/virtualization/hyper-v-on-windows/about/) )

![](https://i.imgur.com/YG79VE1.jpg)

重新開機後，你就會發現可愛的 Docker 在右下角蹦出來惹

![](https://i.imgur.com/zMgf36E.png)

我們可以再用 cmd 確認一下是否有成功安裝

```cmd
docker --version
docker-compose --version
```

![](https://i.imgur.com/k1o3GIz.png)

記得再設定一個東西 Shared Drives

![](https://i.imgur.com/a6dqWU8.jpg)

裝完了之後，建議大家再多裝一個 [Kitematic](https://kitematic.com/)，他是 GUI 介面的，方便你使用 Docker，

( 後面會再介紹一個更贊的 GUI 介面 [portainer](https://github.com/portainer/portainer)  :grin: )

我知道打指令很潮，但還是建議裝一下。

直接對著你的 Docker 圖示右鍵，就可以看到 [Kitematic](https://kitematic.com/)

![](https://i.imgur.com/gdVFFMT.png)

![](https://i.imgur.com/SRaHNCP.jpg)

下載回來直接解壓縮雙點擊即可使用

![](https://i.imgur.com/9zsU23B.png)

MAC

MAC 我本身也有，但因為更早之前就裝了，步驟就沒記錄了，基本上大同小異

[https://www.docker.com/docker-mac](https://www.docker.com/docker-mac)

Linux

[Youtube Tutorial-Ubuntu(Linux) 如何安裝 docker](https://youtu.be/eS_HMBC_RaA)

這裡使用 Ubuntu 當作範例,

雖然在 ubuntu 中有 `snap` 可以非常快速的安裝 docker,

但在這邊我們不使用 `snap` 的方法安裝:smile:

請參考官方文件步驟安裝,

Get Docker Engine - Community for Ubuntu

[Get Docker Engine - Community for Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu/)

安裝後步驟 (optional:exclamation:), 但建議參考一下

[Post-installation steps for Linux](https://docs.docker.com/install/linux/linux-postinstall/)

docker-compose 的安裝

[docker-compose install](https://docs.docker.com/compose/install/)

系統資源分配問題,

假如你是使用 windows 或是 mac 的 docker,

你會有一個界面可以設定你要分多少的 cpu 以及 ram 給你的 docker,

通常會在 Preferences -> Advanced, 有 GUI 界面,

![](https://i.imgur.com/CWMQHxs.png)

但如果是使用 linux, 就不會有這個界面, 因為在 Linux 中,

會自動依照系統的資源進行分配.

## 指令介紹

接著介紹一些 Docker 的指令，

Docker 的指令真的很多，這裡就介紹我比較常用的或是實用的指令

查看目前 images

```cmd
docker images
```

建立 image

```cmd
docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
```

詳細的參數可參考 [https://docs.docker.com/engine/reference/commandline/create/](https://docs.docker.com/engine/reference/commandline/create/)

範例 ( 建立一個名稱為  busybox 的 image )

```cmd
docker create -it --name busybox busybox
```

刪除 Image

```cmd
docker rmi [OPTIONS] IMAGE [IMAGE...]
```

查看目前運行的 container

```cmd
docker ps
```

查看目前全部的 container（ 包含停止狀態的 container ）

```cmd
docker ps -a
```

新建並啟動 Container

```cmd
docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]
```

舉個例子

```cmd
docker run -d -p 80:80 --name my_image nginx
```

`-d` 代表在 Detached（ 背景 ）執行，如不加 `-d`，預設會 foreground ( 前景 ) 執行

`-p` 代表將本機的 80 port 的所有流量轉發到 container 中的 80 port

`--name` 設定 container 的名稱

在舉一個例子

```cmd
 docker run -it --rm busybox
```

`--rm` 代表當 exit container 時，會自動移除 container。 ( incompatible with -d )

更詳細的可參考 [https://docs.docker.com/engine/reference/run/](https://docs.docker.com/engine/reference/run/)

啟動 Container

```cmd
docker start [OPTIONS] CONTAINER [CONTAINER...]
```

如果想讓他在前景跑順便觀看輸出 , 可以使用以下指令

```cmd
docker start -a [OPTIONS] CONTAINER [CONTAINER...]
```

`--attach` 或 `-a` 代表 Attach STDOUT/STDERR and forward signals.

更詳細的可參考 [https://docs.docker.com/engine/reference/commandline/start/](https://docs.docker.com/engine/reference/commandline/start/)

（ container ID 寫幾個就可以了，和 Git 的概念是一樣的 ，

不了解 Git 可以參考 [Git-Tutorials GIT基本使用教學](https://github.com/twtrubiks/Git-Tutorials) ）

停止 Container

```cmd
docker stop [OPTIONS] CONTAINER [CONTAINER...]
```

重新啟動 Container

```cmd
docker restart [OPTIONS] CONTAINER [CONTAINER...]
```

删除 Container

```cmd
docker rm [OPTIONS] CONTAINER [CONTAINER...]
```

`--volumes , -v` 加上這個參數，會移除掉連接到這個 container 的 volume。

可參考 [https://docs.docker.com/engine/reference/commandline/rm/](https://docs.docker.com/engine/reference/commandline/rm/)

進入 Container

```cmd
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
docker exec -it <Container ID> bash
```

使用 root 使用者進入　

```cmd
docker exec -u 0 -it <Container ID> bash
docker exec -u root -it <Container ID> bash
```

打指令比較潮，或是說你也可以透過 [Kitematic](https://kitematic.com/) 進入。

[](https://i.imgur.com/Yui1UZb.png)

當我們進入了 Container 之後，有時候想看一下裡面 Linux 的版本，

這時候可以使用以下指令查看

```cmd
cat /etc/os-release
```

查看 Container 詳細資料

```cmd
docker inspect [OPTIONS] NAME|ID [NAME|ID...]
```

查看 log

```cmd
docker logs [OPTIONS] CONTAINER
```

`--follow` , `-f`  ,  Follow log output

更詳細的可參考 [https://docs.docker.com/engine/reference/commandline/logs/](https://docs.docker.com/engine/reference/commandline/logs/)


從最後 100 行開始追蹤,

```cmd
docker logs -f --tail 100 CONTAINER
```

也可以把 log 寫進去檔案中,

```cmd
docker logs CONTAINER >> access.log
```

也可以先過濾 log 再寫進檔案中,

```cmd
docker logs CONTAINER | grep "29/Mar/2022" >> access_tmp.log
```

顯示容器資源 ( CPU , I/O ...... )

```cmd
docker stats [OPTIONS] [CONTAINER...]
```

也可以加上 `--no-stream`

```cmd
docker stats --no-stream
```

`--no-stream` Disable streaming stats and only pull the first result.

注意:exclamation::exclamation:這邊得到的 memory usage 會比實際上的還要小,

因為這邊的值是再減去 cache usage memory.

相關 issues 可參考 [https://github.com/moby/moby/issues/32253](https://github.com/moby/moby/issues/32253)

```txt
On Linux, the Docker CLI reports memory usage by subtracting cache usage from the total memory usage.
```

詳細說明可參考 [https://docs.docker.com/engine/reference/commandline/stats/](https://docs.docker.com/engine/reference/commandline/stats/)

也可參考 [https://docs.docker.com/config/containers/runmetrics/](https://docs.docker.com/config/containers/runmetrics/)

查看 container 中正在執行的 processes

```CMD
docker top CONTAINER
```

停止指定的 CONTAINER 中全部的 **processes**

```cmd
docker pause CONTAINER [CONTAINER...]
```

執行 `docker pause` 之後，可以試這用 `docker ps` 查看，會發現

還是有在執行，這裡拿  `docker stop`  比較一下，差異如下。

 `docker stop` : process 級別。

 `docker pause`: container 級別。

恢復指定暫停的 CONTAINER 中全部的 **processes**

```cmd
docker unpause CONTAINER [CONTAINER...]
```

docker tag

```cmd
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
```

範例

```cmd
docker tag 0e5574283393 twtrubiks/nginx:version1.0
```

更多可參考 [https://docs.docker.com/engine/reference/commandline/tag/](https://docs.docker.com/engine/reference/commandline/tag/)

儲存 (備份) image 成 tar 檔案

```cmd

[OPTIONS] IMAGE [IMAGE...]
```

範例

```cmd
docker save busybox > busybox.tar
```

或

```cmd
docker save --output busybox.tar busybox
```

或 ( 也可以一次備份多個 )

```cmd
docker save -o images.tar postgres:9.6 busybox
```

更多可參考 [https://docs.docker.com/engine/reference/commandline/save/](https://docs.docker.com/engine/reference/commandline/save/)

載入 image

```cmd
docker load [OPTIONS]
```

範例

```cmd
docker load < busybox.tar
```

或

```cmd
docker load -i busybox.tar
```

更多可參考 [https://docs.docker.com/engine/reference/commandline/load/](https://docs.docker.com/engine/reference/commandline/load/)

顯示 image 的 history，查詢 image 的每一層

```cmd
docker history [OPTIONS] IMAGE
```

在 docker 中，一層一層的概念很重要。

![](https://i.imgur.com/NmImVby.png)

更多可參考 [https://docs.docker.com/engine/reference/commandline/history/](https://docs.docker.com/engine/reference/commandline/history/)

剛剛有教大家如何儲存 (備份) images， 載入 images，

還有另外一種是 export 和 import containers，

docker export container 請參考 [https://docs.docker.com/engine/reference/commandline/export/](https://docs.docker.com/engine/reference/commandline/export/)。

docker import container 請參考 [https://docs.docker.com/engine/reference/commandline/import/](https://docs.docker.com/engine/reference/commandline/import/)。

其他指令

刪除所有 dangling images

```cmd
docker image prune
```

移除全部 unused images (不只 dangling images)

```cmd
docker image prune -a
```

更多資訊可參考 [image_prune](https://docs.docker.com/engine/reference/commandline/image_prune/)

停止所有正在運行的 Container

```cmd
docker container stop $(docker ps -q)
```

更多資訊可參考 [container_stop](https://docs.docker.com/engine/reference/commandline/container_stop/)

移除全部停止的 containers

```cmd
docker container prune
```

更多資訊可參考 [container_prune](https://docs.docker.com/engine/reference/commandline/container_prune/)

### ENTRYPOINT

教學說明請點選 [entrypoint-tutorial](https://github.com/twtrubiks/docker-tutorial/tree/master/entrypoint-tutorial)

### Volume

接下來要介紹 Volume，Volume 是 Docker 最推薦存放 persisting data（ 數據 ）的機制，

使用 Volume 有下列優點

* Volumes are easier to back up or migrate than bind mounts.
* You can manage volumes using Docker CLI commands or the Docker API.
* Volumes work on both Linux and Windows containers.
* Volumes can be more safely shared among multiple containers.
* Volume drivers allow you to store volumes on remote hosts or cloud providers, to encrypt the contents of volumes, or to add other functionality.
* A new volume's contents can be pre-populated by a container.

在 container 的可寫層中，使用 volume 是一個比較好的選擇，因為他不會增加 container 的容量，

volume 的內容存在於 container 之外。

也可參考下圖

![](https://i.imgur.com/fiIt0kS.png)

更詳細的可參考 [https://docs.docker.com/engine/admin/volumes/volumes/](https://docs.docker.com/engine/admin/volumes/volumes/)

查看目前的 volume

```cmd
docker volume ls [OPTIONS]
```

創造一個 volume

```cmd
docker volume create [OPTIONS] [VOLUME]
```

刪除一個 volume

```cmd
docker volume rm [OPTIONS] VOLUME [VOLUME...]
```

查看 volume 詳細資料

```cmd
docker volume inspect [OPTIONS] VOLUME [VOLUME...]
```

移除全部未使用的 volume

```cmd
docker volume prune [OPTIONS]
```

也可以建立 readonly 的 volumes (容器內 readonly)

`docker-compose.yml` 方法如下,

```yml
version: '3.5'
services:
  nginx:
    image: nginx
    ports:
      - "80:80"
    volumes:
      - "nfs-data:/data:ro,z"

volumes:
    nfs-data:
```

如果要可讀寫, 就設定 `rw`.

volumes 在容器內的確不能寫 (只能讀)

![alt tag](https://i.imgur.com/ve4572t.png)

使用以下的指令查看 Mounts, 觀察它的 Mode

```cmd
docker inspect <container ID>
```

![alt tag](https://i.imgur.com/ex8A3Y5.png)

也可以建立 NFS volumes,

`docker-compose.yml` 方法如下,

```yml
version: '3.5'
services:
  nginx:
    image: nginx
    ports:
      - "80:80"
    volumes:
      - "nfs-data:/data"

volumes:
    nfs-data:
      driver: local
      driver_opts:
        type: nfs
        o: nfsvers=4,addr=ip,rw
        device: ":/path/to/dir"
```

可以用以下指令查看設定

```cmd
docker volume ls
docker inspect <volume name>
```

![alt tag](https://i.imgur.com/8mzUGsg.png)

NFS 相關文章可參考 [linux-nfs-server - 如何在 ubuntu 啟用 NFS Server](https://github.com/twtrubiks/linux-note/tree/master/linux-nfs-server)

### network

建議大家花點時間研究 docker 中的 network，會蠻有幫助的 :smiley:

查看目前 docker 的網路清單

```cmd
docker network ls [OPTIONS]
```

詳細可參考 [https://docs.docker.com/engine/userguide/networking/](https://docs.docker.com/engine/userguide/networking/)

docker 中的網路主要有三種 Bridge、Host、None，預設皆為 Bridge 模式。

指定 network 範例 ( 指定使用  `host` 網路 )

```cmd
docker run -it --name busybox --rm --network=host busybox
```

建立 network

```cmd
docker network create [OPTIONS] NETWORK
```

移除 network

```cmd
docker network rm NETWORK [NETWORK...]
```

移除全部未使用的 network

```cmd
docker network prune [OPTIONS]
```

查看 network 詳細資料

```cmd
docker network inspect [OPTIONS] NETWORK [NETWORK...]
```

將 container 連接 network

```cmd
docker network connect [OPTIONS] NETWORK CONTAINER
```

更多詳細資料可參考 [https://docs.docker.com/engine/reference/commandline/network_connect/](https://docs.docker.com/engine/reference/commandline/network_connect/)

Disconnect container  network

```cmd
docker network disconnect [OPTIONS] NETWORK CONTAINER
```

更多詳細資料可參考 [https://docs.docker.com/engine/reference/commandline/network_disconnect/](https://docs.docker.com/engine/reference/commandline/network_disconnect/)

#### User-defined networks

這個方法是官方推薦的 :thumbsup:

透過內建的 DNS 伺服器，可以直接使用容器名稱，就可解析出 IP，不需要再使用 IP 讓容器互相

溝通，我們只需要知道容器的名稱就可以連接到容器。

更多詳細資料可參考 [https://docs.docker.com/engine/userguide/networking/#user-defined-networks](https://docs.docker.com/engine/userguide/networking/#user-defined-networks)

## docker-compose

再來要介紹 docker-compose，可參考官網 [https://docs.docker.com/compose/](https://docs.docker.com/compose/)

![](https://i.imgur.com/YxrrO7t.png)

Compose 是定義和執行多 Container 管理的工具，不懂我在說什麼:question::question::question:

試著想想看，通常一個 Web 都還會有 DB，甚至可能還有 [Redis](https://redis.io/) 或 [Celery](http://www.celeryproject.org/)，

所以說我們需要有 Compose 來管理這些，透過 `docker-compose.yml` ( YML 格式 ) 文件。

`docker-compose.yml` 的寫法可參考 [https://docs.docker.com/compose/compose-file/](https://docs.docker.com/compose/compose-file/)

也可以直接參考官網範例 [https://docs.docker.com/compose/compose-file/#compose-file-structure-and-examples](https://docs.docker.com/compose/compose-file/#compose-file-structure-and-examples)

Compose 的 Command-line 很多和 Docker 都是類似的，

可參考 [https://docs.docker.com/glossary/?term=compose](https://docs.docker.com/glossary/?term=compose)

查看目前 Container

```cmd
docker-compose ps
```

加上 `-q` 的話，只顯示 id

```cmd
docker-compose ps -q
```

啟動 Service 的 Container

```cmd
docker-compose start  [SERVICE...]
```

停止 Service 的 Container ( 不會刪除 Container )

```cmd
docker-compose stop [options] [SERVICE...]
```

重啟 Service 的 Container

```cmd
docker-compose restart [options] [SERVICE...]
```

Builds, (re)creates, starts, and attaches to containers for a service

```cmd
docker-compose up [options] [--scale SERVICE=NUM...] [SERVICE...]
```

加個 `-d`，會在背景啟動，一般建議正式環境下使用。

```cmd
docker-compose up -d
```

然後如果你有很多個 `docker-compose.yml` `docker-compose-dev.yml`,

你可以透過 `-f` 決定你要執行哪一個, 範例如下,

```cmd
docker-compose -f ./docker-compose-dev.yml up -d
```

`-f` `--file FILE` Specify an alternate compose file

(default: `docker-compose.yml`)

`up` 這個功能很強大，建議可以參考 [https://docs.docker.com/compose/reference/up/](https://docs.docker.com/compose/reference/up/)

如果你希望每次都重新 build image，可以加上

`--build` ( Build images before starting containers. )

```cmd
docker-compose up -d --build
```

docker-compose down

```cmd
docker-compose down [options]
```

`down` 這個功能也建議可以參考 [https://docs.docker.com/compose/reference/down/](https://docs.docker.com/compose/reference/down/)

舉個例子

```cmd
docker-compose down -v
```

加個 `-v` 就會順便幫你把 volume 移除（ 移除你在 `docker-compose.yml` 裡面設定的 volume ）

在指定的 Service 中執行一個指令

```cmd
docker-compose run [options] [-v VOLUME...] [-p PORT...] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...]
[ARGS...]
```

舉個例子

```cmd
docker-compose run web bash
```

在 web Service 中執行 `bash` 指令

可參考 [https://docs.docker.com/compose/reference/run/](https://docs.docker.com/compose/reference/run/)

觀看 Service logs

```cmd
docker-compose logs [options] [SERVICE...]
```

檢查 `docker-compose.yml` 格式是否正確

```cmd
docker-compose config
```

如下指令，和 `docker exec` 一樣

```cmd
docker-compose exec
```

範例 ( 進入 web 這個 service 的 bash )

```cmd
docker-compose exec web bash
```

顯示被使用到的 container 中的 images 清單

```cmd
docker-compose images
```

移除  service containers

```cmd
docker-compose rm
```

Pushes images 到 docker hub

```cmd
docker-compose push
```

目前這個指令其實我也搞不太懂，可參考 [https://github.com/docker/compose/issues/4283](https://github.com/docker/compose/issues/4283)

官網也解釋的沒有很清楚 [https://docs.docker.com/compose/reference/push/](https://docs.docker.com/compose/reference/push/)

### docker-compose up/down 和 restart 的差異

* [Youtube Tutorial- docker-compose up/down 和 restart 的差異](https://youtu.be/nX-sbLPz-MU)

先來談 `docker-compose up/down`,

假如今天你修改了 `docker-compose.yml` 又或是更新了 image,

當你要重建 docker , 有幾種方法,

方法一.

先停止 container, 執行 `docker-compose down` 再執行 `docker-compose up`.

方法二.

不需要停止 container, 直接執行 `docker-compose up -d`.

(他會自動幫你重建, 很方便, 不需要多一步先關閉 container )

結論, 只要你的 `docker-compose.yml` 有任何變動, 一定要執行 `docker-compose up` 才會生效.

再來談 `docker-compose restart`,

請看官方文件 [docker-compose restart](https://docs.docker.com/compose/reference/restart/), 如果你對 `docker-compose.yml` 修改, 然後使用這個指令, 是**不會**生效的,

但是, 如果你是改 code (可能是 python code), 那這個指令是有效的.

### docker-compose networks

* [Youtube Tutorial - docker-compose networks 說明](https://youtu.be/wmV9WfkpyGk)

這邊多補充 docker-compose networks 的觀念，因為剛好最近有用到:smile:

```yml
version: '3.5'
services:

    db:
      container_name: 'postgres'
      image: postgres
      environment:
        POSTGRES_PASSWORD: password123
      ports:
        - "5432:5432"
        # (HOST:CONTAINER)
      volumes:
        - pgdata:/var/lib/postgresql/data/
      networks:
        - proxy

    web:
      build: ./api
      command: python manage.py runserver 0.0.0.0:8000
      restart: always
      volumes:
        - api_data:/docker_api
        # (HOST:CONTAINER)
      ports:
        - "8000:8000"
        # (HOST:CONTAINER)
      depends_on:
        - db
      networks:
        - proxy

volumes:
    api_data:
    pgdata:

networks:
    proxy:
      # external:
        name: my_network
```

先把 version 改成 3.5，因為這版本才開始有 networks name 的概念，在

db 以及 web 中都加了 networks ( 自己定義的 )，定義的地方在最後面，

proxy 是名稱 ( 類似 volumes 的概念 )，`external` option 的意思代表

是不是要參考外部別人已經定義好的 network ( 所以如果找不到就會報錯 )，

但如果不加上 `external` option，也就代表是自己定義的，會幫你自動建立

你所定義的 network，名稱為 my_network。

如果你都完全沒有定義 networks，預設就是資料夾的名稱_default 。

### docker-compose ports 和 expose 差異

在 docker-compose 中有兩種方法可以暴露容器 ports，

分別是 ports 和 expose，

#### ports

```yml
...
ports:
  - "5000:5000"  # 绑定 container 中的 5000 port 到 本機(HOST) 的 5000 port
  # (HOST:CONTAINER)

  - "5001:5000"  # 绑定 container 中的 5000 port 到 本機(HOST) 的 5001 port

  - "5000"       # 绑定 container 中的 5000 port 到本機的任意 port (本機會隨機被分配到一個 port)
...
```

隨機 port 範例，

這邊使用 dpage/pgadmin4 這個 images 來示範，

```cmd
docker run -p 80 \
    -e "PGADMIN_DEFAULT_EMAIL=xxxrubiks@gmail.com" \
    -e "PGADMIN_DEFAULT_PASSWORD=SuperSecret" \
    -d dpage/pgadmin4
```

如果我們執行兩次以上指令，你會發現本機被分配到兩個隨機的 ports (如下圖)，

![alt tag](https://i.imgur.com/kkcnuJI.png)

本機被隨機分配到 32768 以及 32769 port，

這邊不管我們怎麼設定 ports，這些 ports 都會暴露給本機 (HOST) 以及其他 containers，這點很重要:exclamation::exclamation:

也就是說，如果本機 5001 ports 被使用了，其他的 containers 就無法使用 5001 ports，

可能要改成5002 ports 之類的。

#### expoese

```yml
...
expose:
  - "4000"
  - "6000"
...
```

expose 是將 port 暴露給其他容器。

expose 和 ports 最大的差別就是在 expose 不會暴露 port 給本機(HOST)，

所以 本機(HOST)絕對無法被訪問，但 containers 內可以被訪問，

所以說如果今天你的容器想要在 本機(HOST) 被訪問，一定要使用 ports 方式。

***ports 和 expose 差異***

簡單說，就是 ports 可以被 本機(HOST) 和 containers 訪問 ; 而

expose 是本機(HOST) 無法被訪問，只有在 containers 中可以被訪問。

## Docker container 內如何連接到本機 localhost 服務

![alt tag](https://i.imgur.com/kQLcALp.png)

假設今天在本機上有一個 A 服務, 他是使用 docker run 起來的,

而本機上還有一個 B 服務, 是用 vscode run 起來的 (非 docker),

這時候我有一個需求, 我想要將我的 A 服務連線到我的 B 服務,

也就是從 docker 內的服務連接到本機 localhost.

比較簡單的方法, 就是透過 docker 內的這個參數,

`host.docker.internal:host-gateway`.

在你的 yml 裡面加上,

```yml
version: '3.5'
services:

  web:
    ......
    extra_hosts:
      - "host.docker.internal:host-gateway"
......
```

這樣當你在容器內, 就可以順利訪問本機:smile:

```cmd
curl http://host.docker.internal:8069
```

## Docker Registry

![](https://i.imgur.com/uAXUtxT.png)

可以把它想成是一個類似 github 的地方，只不過裡面變成是存 docker 的東西，當然，

也可以自己架，但會有一些額外的成本，像是網路，維護等等，這部分就要自己衡量了:grinning:

接下來教大家如何將 image push 到 Docker Registry :smiley:

* [Youtube Tutorial PART 4 - Docker push image to Docker Hub 教學](https://youtu.be/dVBKwmqO5e4)

首先，先登入 [Docker Registry](https://hub.docker.com/)  ( 註冊流程很簡單，我就跳過了 )

```cmd
docker login
```

![](https://i.imgur.com/lm9GWTj.png)

舉個例子，先 run 一個 busybox 的容器

```cmd
docker run -it busybox
```

接著在裡面新增一筆資料

```cmd
 echo 'text' > data.txt
```

![](https://i.imgur.com/KCeZGQh.png)

然後打開另一個 terminal ，使用 `docker ps` 查看目前容器的 id

![](https://i.imgur.com/mBIhGBW.png)

再來使用像 git 一樣的方式 commit

docker commit

```cmd
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
```

可參考 [https://docs.docker.com/engine/reference/commandline/commit/](https://docs.docker.com/engine/reference/commandline/commit/)

```cmd
docker commit -m "test" 4fb4ef51e917 twtrubiks/my_busybox
```

`-m` commit message ，和 git 一樣。

twtrubiks/my_busybox 則為我們定義的 REPOSITORY。

如果需要 tag , 也可以增加

```cmd
docker commit -m "test" 4fb4ef51e917 twtrubiks/my_busybox:v1
```

（ 如果沒定義 tag , 則會顯示 latest ）

這時候可以用 `docker images` 查看

![](https://i.imgur.com/R548ail.png)

最後 push

```cmd
docker push twtrubiks/my_busybox
```

![](https://i.imgur.com/2ExgYpB.png)

docker 是一層一層的概念，他只會 push 自己新增的幾層上去而已，

所以不用擔心整個 image 很大，要上傳很久 :relaxed:

最後可以到 [https://hub.docker.com/](https://hub.docker.com/) 確認是否有成功 :smile:

![](https://i.imgur.com/W5P3YQL.png)

## 用 Docker 實戰 Django 以及 Postgre

* [Youtube Tutorial PART 2 - 用 Docker 實戰 Django 以及 Postgre](https://youtu.be/aZ6woJ7qekE)

上面介紹了那麼多，來實戰一下是必須的 :satisfied:

我們使用 [Django-REST-framework 基本教學 - 從無到有 DRF-Beginners-Guide](https://github.com/twtrubiks/django-rest-framework-tutorial) 來當範例

有幾個地方必須修改一下，

將 `settings.py`  裡面的 db 連線改成 [PostgreSQL](https://www.postgresql.org/)

```pyhon
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'postgres',
        'USER': 'postgres',
        'PASSWORD': 'password123',
        'HOST': 'db',
        'PORT': 5432,
    }
}
```

建議也將 `ALLOWED_HOSTS = []` 改為 `ALLOWED_HOSTS = ['*']`
（ 這只是方便，實務上不會這樣使用 ）

再來是兩個很重要的檔案，分別為 `Dockerfile` 和 `docker-compose.yml`

`Dockerfile`

```text
FROM python:3.8.12
LABEL maintainer twtrubiks
ENV PYTHONUNBUFFERED 1
RUN mkdir /docker_api
WORKDIR /docker_api
COPY . /docker_api/
RUN pip install -r requirements.txt
```

詳細可參考 [https://docs.docker.com/engine/reference/builder/](https://docs.docker.com/engine/reference/builder/)

`docker-compose.yml`

```yml
version: '3'
services:

    db:
      container_name: 'postgres'
      image: postgres
      environment:
        POSTGRES_PASSWORD: password123
      ports:
        - "5432:5432"
        # (HOST:CONTAINER)
      volumes:
        - pgdata:/var/lib/postgresql/data/

    web:
      build: ./api
      command: python manage.py runserver 0.0.0.0:8000
      restart: always
      volumes:
        - api_data:/docker_api
        # (HOST:CONTAINER)
      ports:
        - "8000:8000"
        # (HOST:CONTAINER)
      depends_on:
        - db

volumes:
    api_data:
    pgdata:
```

詳細可參考 [https://docs.docker.com/compose/compose-file/#compose-file-structure-and-examples](https://docs.docker.com/compose/compose-file/#compose-file-structure-and-examples)

溫馨小提醒 1  :heart:

可能有人會問為什麼我是使用 `0.0.0.0`，而不是使用 `127.0.0.1`:question::question:

```cmd
python manage.py runserver 0.0.0.0:8000
```

`127.0.0.1`，並不代表真正的 **本機**，我們經常認為他是本機是因為我們電腦的 `host` 預設都幫你設定好了:smirk:

詳細的 `host` 設定教學可參考 [hosts-設定檔 以及 查詢內網 ip](https://github.com/twtrubiks/docker-django-nginx-uswgi-postgres-tutorial#hosts-設定檔-以及-查詢內網-ip)，

`0.0.0.0` 才是真正的代表，**當下 ( 本 ) 網路中的本機** :pencil2:

如果大家想更深入的了解，可 google 再進一步的了解 `127.0.0.1` 以及 `0.0.0.0` 的差異 :smile:

溫馨小提醒 2  :heart:

這邊要特別提一下 `depends_on` 這個參數，

詳細可參考 [https://docs.docker.com/compose/compose-file/#depends_on](https://docs.docker.com/compose/compose-file/#depends_on)，

上面連結中有一段說明很值得看

****depends_on does not wait for db and redis to be 「ready」 before starting web - only until they have been started. If you need to wait for a service to be ready, see Controlling startup order for more on this problem and strategies for solving it.****

以我的 [docker-compose.yml](https://github.com/twtrubiks/docker-tutorial/blob/master/docker-compose.yml) 為例，啟動順序雖然為 db -> web，**但他不會等待 db 啟動完成後才啟動 web**，

也就是說，還是有可能 **web 比 db 先啟動完成**，這樣就需要重啟 web service，否則會無法連上 db :sob:

如果真的要控制啟動順序，請參考 [Controlling startup order](https://docs.docker.com/compose/startup-order/)。

溫馨小提醒 3  :heart:

`docker-compose.yml` 其實使用 `docker run` 也是可以完成的，例如這個範例中，如果使用

`docker run` 來寫，會變成這樣。

首先，為了讓容器彼此可以溝通，我們先建立一個網路 ( User-defined networks )，

```cmd
docker network create my_network
```

db 容器

```cmd
docker run --name db -v pgdata:/var/lib/postgresql/data/ -p 5432:5432 --network=my_network -e POSTGRES_PASSWORD=password123 postgres
```

接下來先去 api 資料夾中 build 出 image

```cmd
docker build --tag web_image .
```

`--tag , -t` , tag 這個 image 名稱為 web_image

也可以是

```cmd
docker build -t user/repo:tag .
```

web 容器

```cmd
docker run --name web -v api_data:/docker_api -p 8000:8000 --network=my_network --restart always web_image python manage.py runserver 0.0.0.0:8000
```

以上這樣，和 `docker-compose.yml`  其實是一樣的:open_mouth:

設定完了之後，接下來我們就可以啟動他了

```cmd
docker-compose up
```

接下來你會看到類似的畫面

![](https://i.imgur.com/GJWIgEP.png)

![](https://i.imgur.com/dVRRyrM.png)

假如你出現了類似的畫面

![](https://i.imgur.com/cCEmVBq.png)

代表 database 還在建立的時候，你的 web ( Django ) 就去連接他，

所以導致連接不上，這時候我們可以先終止他 ( 按 Ctrl+C )

接著在重新 `docker-compose up`

我們成功啟動了 ( db 連線也正常 )

![](https://i.imgur.com/iuCxLMY.png)

:exclamation: [commit](https://github.com/twtrubiks/docker-tutorial/commit/398cb2fc375af8926cfe1eeabda33da018437897) 已經更新為自動 migrate:exclamation:

但你仔細看上圖，你會發現他說你還沒 migrate

接下來我們開啟另一個 cmd 進入 web 的 service，

透過剛剛介紹的指令進入 service

```cmd
docker ps
docker exec -it <Container ID> bash
```

或是說也可以從 [Kitematic](https://kitematic.com/) 進入，

進入後我們可以開始 migrate

```cmd
python manage.py makemigrations musics
python manage.py migrate
```

![](https://i.imgur.com/zMmZKuL.png)

順便在建立一個 superuser

```cmd
python manage.py createsuperuser
```

:exclamation: [commit](https://github.com/twtrubiks/docker-tutorial/commit/398cb2fc375af8926cfe1eeabda33da018437897) 已經更新為自動建立 superuser:exclamation:

請參考 [docker-compose.yml](https://github.com/twtrubiks/docker-tutorial/blob/master/docker-compose.yml) 中的 environment ( 如下 ),

`DJANGO_SUPERUSER_USERNAME` `DJANGO_SUPERUSER_PASSWORD` `DJANGO_SUPERUSER_EMAIL`

接著我們可以試著使用 GUI 介紹連接 db，

因為我們是用 [PostgreSQL](https://www.postgresql.org/)  ，可以透過 [pgadmin](https://www.pgadmin.org/) 連線

![](https://i.imgur.com/2Hdt7wU.png)

我們剛剛 migrate 的東西確實有存在

![](https://i.imgur.com/PEUfGRy.png)

我們不需要再重新啟動

直接可以開開心心的去瀏覽 [http://127.0.0.1:8000/api/music/](http://127.0.0.1:8000/api/music/)

大家一定會看到很熟悉的畫面

![](https://i.imgur.com/pzqZbdz.png)

接著依照自己剛剛設定的帳密登入進去即可

![](https://i.imgur.com/l6RZXsQ.png)

![](https://i.imgur.com/xeJtRJc.png)

以上整個環境，都是在 Docker 中 :open_mouth:

如果我們再 Ctrl+C 退出，重新啟動一次  `docker-compose up`

這次就不會再和你說你沒有 migrate 了

![](https://i.imgur.com/zIBkL3t.png)

## 其他管理 Docker GUI 的工具

* [Youtube Tutorial PART 3 - Docker 基本教學 - 透過 portainer 管理  Docker](https://youtu.be/VZjHmBcEcew)

除了 [Kitematic](https://kitematic.com/) 之外，還有其他不錯的推薦給大家，

這次要介紹的就是 [portainer](https://github.com/portainer/portainer) 功能強大又好用 :fire:

其實如果去看看 [Kitematic](https://github.com/docker/kitematic) 以及 [portainer](https://github.com/portainer/portainer) 的 github，

你會發現 [portainer](https://github.com/portainer/portainer) 感覺比較有在 maintenance :smile:

而且我使用了 [portainer](https://github.com/portainer/portainer) 之後，真心大推 :smiley:

安裝方法可參考 [https://portainer.io/install.html](https://portainer.io/install.html)

```cmd
docker volume create portainer_data
docker run --name=portainer -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
```

`-d` `-p` 在前面的 `docker run` 有介紹過代表的含意，`--name` 只是命名而已。

`Note 1`: The -v /var/run/docker.sock:/var/run/docker.sock option is available on Linux environments only.

`Note 2`: The -v portainer_data:/data portainer/portainer option will persist Portainer data in portainer_data on the host where Portainer is running. You can specify another location on your filesystem.

（ 建立起來之後，就依照 container 的操作即可 ）

之後查看 [http://localhost:9000/](http://localhost:9000/) 就會看到下圖

然後設定帳號、密碼

![](https://i.imgur.com/exdMf2p.png)

選 Local or Remote

![](https://i.imgur.com/3mkNMxF.png)

畫面真的不錯看，而且資訊也很豐富 :heart_eyes:

![](https://i.imgur.com/ynoqTZT.png)

相信我，你使用完他之後，你會默默的邊緣化 [Kitematic](https://kitematic.com/) :smirk:

## 查看 port 佔用狀況

這個推薦給大家，有時候會遇到 port 被佔用，用指令查比較方便

Linux

安裝 net-tools

```cmd
sudo apt install net-tools
```

查看誰佔用 80 port

```cmd
sudo netstat -lnp | grep -w ':80'
```

`-l`, `--listening` display listening server sockets.

`-n`, `--numeric` don't resolve names.

`-p`, `--programs` display PID/Program name for sockets.

也可以使用 `lsof`

```cmd
sudo lsof -i :80
```

`-i` select IPv[46] files.

Windows

查看所有 port 的佔用狀況

```cmd
netstat -ano
```

查看指定 port 的佔用狀況，例如現在想要查看 port 5432 佔用的狀況

```cmd
netstat -aon|findstr "5432"
```

查看 PID 對應的 process

```cmd
tasklist|findstr "2016"
```

停止 PID 為 6093 的 process

```cmd
taskkill /f /PID 6093
```

停止 vscode.exe process

```cmd
taskkill /f /t /im vscode.exe
```

MAC

將 port 為 8000 的 process 全部停止

```cmd
sudo lsof -t -i tcp:8000 | xargs kill -9
```

查看指定 port 的佔用狀況，例如現在想要查看 port 5432 佔用的狀況

```cmd
lsof -i tcp:5432
```

## 在 Linux 中自動啟動 docker

[在 Linux 中自動啟動 docker](https://github.com/twtrubiks/docker-tutorial/tree/master/docker-auto-run-linux)

## 如何清除 Docker container log

[Youtube Tutorial - 如何清除 Docker container log](https://youtu.be/SiG0tmwhqqg)

docker 的 container log 都會在 `/var/lib/docker/containers` 裡面

( 前提是你使用官方的安裝方法, [Youtube Tutorial-Ubuntu(Linux) 如何安裝 docker](https://youtu.be/eS_HMBC_RaA))

如果你是使用 `snap` 安裝 docker, 路徑則會在 `/var/snap/docker/common/var-lib-docker/containers`.

![alt tag](https://i.imgur.com/sK5k4Iw.png)

log 是一個 json 的檔案

![alt tag](https://i.imgur.com/feSGmcm.png)

如果你一直不去管他, log 就會越來越大:scream:

以下狀況這個 log 會被清除, 就是修改了 `docker-compose.yml` 或是

你執行了 `docker-compose down`, 這些 logs 都會被清除 (因為 containers 重新建立).

(`docker-compose stop` 不受影響, 因為只是暫停而已)

建立大家可參考 [docker-compose up/down 和 restart 的差異](https://github.com/twtrubiks/docker-tutorial#docker-compose-updown-%E5%92%8C-restart-%E7%9A%84%E5%B7%AE%E7%95%B0)

那你可能會問我, 如果我很長一段時間都不會修改 `docker-compose.yml` 以及執行

`docker-compose down` 該怎麼辦:sob: (因為 log 可能會長很快)

這邊提供大家一個方法, 使用 linux 中的 truncate 指令(可參考 [ Linux 指令教學 - truncate](https://github.com/twtrubiks/linux-note#truncate))

刪除全部 container 的 logs

```cmd
truncate -s 0 /var/lib/docker/containers/*/*-json.log
```

但是有時候只希望針對(清除)某個 container 的 logs, 這時候就可以使用以下的指令

```cmd
truncate -s 0 $(docker inspect --format='{{.LogPath}}' <container_name_or_id>)
```

(`container_name_or_id` 請換上自己 container 的 id 或 name)

其中的 `docker inspect --format='{{.LogPath}}' <container_name_or_id>` 只是顯示路徑而已.

![alt tag](https://i.imgur.com/TKCCdio.png)

但還有一個更好的方法, 直接透過 docker 內的 JSON File logging driver.

## JSON File logging driver

[Youtube Tutorial - Docker 中的 JSON File logging driver(container log)](https://youtu.be/wb9bONgnFn4)

在 docker 中 json-file driver 是默認的 default logging driver, 詳細可參考 [json-file](https://docs.docker.com/config/containers/logging/json-file/)

所以我們可以透過這個設定限制 log 的大小,

```yaml
logging:
  driver: "json-file"
  options:
    max-file: "1"    # default 是 1
    max-size: "200m" # default 是 -1, 也就是沒有限制
```

設定完之後重新啟動 docker-compose, 可以使用以下的指令查看是否生效

```cmd
docker inspect --format '{{.HostConfig.LogConfig}}' CONTAINER
```

![alt tag](https://i.imgur.com/L6Z7bYX.png)

這樣設定完之後, 就不用再擔心 container log 吃掉大量的容量了:smile:

## 後記：

Docker 算是我最近才開始接觸的，所以也算是新手，如果我有任何講錯的，歡迎和我說，我會再修改  :grinning:

Docker 可以玩的真的很多，延伸參考

* [實戰 Docker + Jenkins + Django + Postgres 📝](https://github.com/twtrubiks/docker-jenkins-django-tutorial) - 結合 Jenkins

* [Docker + Django + Nginx + uWSGI + Postgres 基本教學 - 從無到有](https://github.com/twtrubiks/docker-django-nginx-uwsgi-postgres-tutorial)

* [實戰 Docker + Django + Nginx + uWSGI + Postgres - Load Balance 📝](https://github.com/twtrubiks/docker-django-nginx-uwsgi-postgres-load-balance-tutorial)

也可以再玩玩 **Docker Swarm** ( 分散式系統 ) :satisfied:

* [Docker Swarm 基本教學 - 從無到有 Docker-Swarm-Beginners-Guide📝](https://github.com/twtrubiks/docker-swarm-tutorial)

最後，希望大家在學習 Docker 的過程中，遇到不懂的，可以去找資料並且了解他，
順便補足一些之前不足的知識。

## 執行環境

* Mac
* Python 3.8.12
* windows 10

## Reference

* [https://docs.docker.com/](https://docs.docker.com/)
* [portainer](https://github.com/portainer/portainer)

## Donation

文章都是我自己研究內化後原創，如果有幫助到您，也想鼓勵我的話，歡迎請我喝一杯咖啡:laughing:

綠界科技ECPAY ( 不需註冊會員 )

![alt tag](https://payment.ecpay.com.tw/Upload/QRCode/201906/QRCode_672351b8-5ab3-42dd-9c7c-c24c3e6a10a0.png)

[贊助者付款](http://bit.ly/2F7Jrha)

歐付寶 ( 需註冊會員 )

![alt tag](https://i.imgur.com/LRct9xa.png)

[贊助者付款](https://payment.opay.tw/Broadcaster/Donate/9E47FDEF85ABE383A0F5FC6A218606F8)

## 贊助名單

[贊助名單](https://github.com/twtrubiks/Thank-you-for-donate)

## License

MIT license
