{"id":13617891,"url":"https://github.com/twtrubiks/docker-tutorial","last_synced_at":"2025-05-14T14:08:35.708Z","repository":{"id":43575901,"uuid":"106928246","full_name":"twtrubiks/docker-tutorial","owner":"twtrubiks","description":"Docker 基本教學 - 從無到有 Docker-Beginners-Guide   教你用 Docker 建立 Django + PostgreSQL 📝","archived":false,"fork":false,"pushed_at":"2025-05-10T01:45:10.000Z","size":179,"stargazers_count":1746,"open_issues_count":5,"forks_count":301,"subscribers_count":44,"default_branch":"master","last_synced_at":"2025-05-10T02:41:54.415Z","etag":null,"topics":["django","django-rest-framework","docker","postgresql","tutorial"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/twtrubiks.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-10-14T13:03:01.000Z","updated_at":"2025-05-10T01:45:14.000Z","dependencies_parsed_at":"2023-12-13T02:26:13.994Z","dependency_job_id":"f5a57b7f-4bf5-479d-bd5e-e62f46a8760c","html_url":"https://github.com/twtrubiks/docker-tutorial","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twtrubiks%2Fdocker-tutorial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twtrubiks%2Fdocker-tutorial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twtrubiks%2Fdocker-tutorial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twtrubiks%2Fdocker-tutorial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/twtrubiks","download_url":"https://codeload.github.com/twtrubiks/docker-tutorial/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254159843,"owners_count":22024564,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","django-rest-framework","docker","postgresql","tutorial"],"created_at":"2024-08-01T20:01:49.897Z","updated_at":"2025-05-14T14:08:35.695Z","avatar_url":"https://github.com/twtrubiks.png","language":"Python","readme":"# docker-tutorial\n\n Docker 基本教學 - 從無到有 Docker-Beginners-Guide\n\n 教你用 [Docker](https://www.docker.com/) 建立 [Django](https://github.com/django/django) + [PostgreSQL](https://www.postgresql.org/) 📝\n\n* [Youtube Tutorial PART 1 - Docker 基本教學 - 從無到有 Docker-Beginners-Guide](https://youtu.be/Wg5m0-Jyox8)\n* [目錄](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)\n* [目錄](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)\n* [目錄](https://github.com/twtrubiks/docker-tutorial#docker-registry) - [Youtube Tutorial PART 4 - Docker push image to Docker Hub 教學](https://youtu.be/dVBKwmqO5e4)\n\n其他說明\n\n* [Youtube Tutorial - Ubuntu(Linux) 如何安裝 docker](https://youtu.be/eS_HMBC_RaA)\n* [目錄](https://github.com/twtrubiks/docker-tutorial#docker-compose-networks) - [Youtube Tutorial - docker-compose networks 說明](https://youtu.be/wmV9WfkpyGk)\n* [目錄](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) - [Youtube Tutorial - Docker container 內如何連接到本機 localhost 服務](https://youtu.be/KbaHWdVej9U)\n* [目錄](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)\n* [目錄](https://github.com/twtrubiks/docker-tutorial/tree/master/docker-auto-run-linux) - [Youtube Tutorial - Linux 教學 - 開機自動啟動 docker / compose](https://youtu.be/c4YIQHCDLnQ)\n* [目錄](https://github.com/twtrubiks/docker-tutorial/tree/master/docker-env-tutorial) - [Youtube Tutorial - Docker 基本教學 - 在 docker compose 中善用 Environment variables](https://youtu.be/JwbI1aNKbtY)\n* [目錄](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)\n* [目錄](https://github.com/twtrubiks/docker-tutorial#json-file-logging-driver) - [Youtube Tutorial - Docker 中的 JSON File logging driver(container log)](https://youtu.be/wb9bONgnFn4)\n* [目錄](https://github.com/twtrubiks/docker-tutorial#health-check) - [Youtube Tutorial - docker 教學 Health Check](https://youtu.be/QffnQZgvmwE)\n* [目錄](https://github.com/twtrubiks/docker-tutorial/tree/master/docker-compose-override) - 介紹 docker-compose-override\n* [目錄](https://github.com/twtrubiks/docker-tutorial/tree/master/docker-compose-profiles) - 介紹 docker-compose-profiles\n* [目錄](https://github.com/twtrubiks/docker-tutorial/tree/master/docker-yaml-anchors) - 介紹 YAML Anchors\n* [目錄](https://github.com/twtrubiks/docker-tutorial/tree/master/cadvisor_tutorial) - 介紹 cadvisor - 可監控 docker 容器\n\n## 簡介\n\n[Docker](https://www.docker.com/)\n\n![](https://i.imgur.com/gDcSwcs.png)\n\n***Containers as a Service ( CaaS ) - 容器如同服務***\n\n算是近幾年才開始紅的技術，蠻多公司都有使用 Docker，而且真的很方便，值得大家去了解一下 :smile:\n\n如果你有環境上不統一的問題？ 請用 Docker :smile:\n\n如果你有每次建立環境都快抓狂的問題？ 請用 Docker :blush:\n\n如果你想要高效率、輕量、秒開的環境，請用 Docker :blush:\n\n如果你不想搞死自己，請用 Docker :smile:\n\n如果你想潮到出水，請一定要用 Docker :laughing:\n\n### 什麼是 Docker\n\n[Docker](https://www.docker.com/) 是一個開源專案，出現於 2013 年初，最初是 Dotcloud 公司內部的 Side-Project。\n\n它基於 Google 公司推出的 Go 語言實作。（ Dotcloud 公司後來改名為 Docker ）\n\n技術原理我們這邊就不提了，簡單提一下他的好處。\n\n我們先來看看官網的說明\n\nComparing Containers and Virtual Machines ( 傳統的虛擬化 )\n\n![](https://i.imgur.com/IqiGyoJ.png)\n\n從這張圖可以看出 Containers 並沒有 OS ，容量自然就小，而且啟動速度神快\n\n詳細可參考 [https://www.docker.com/what-container](https://www.docker.com/what-container)\n\nVirtual Machines 是什麼？\n\n類似 [https://www.virtualbox.org/](https://www.virtualbox.org/)，我們可能用它裝裝看其他作業系統，例如說\n\n我是 MAC，但我想玩 Windows，我就會在 MAC 中裝 VM 並且灌 Windows 系統。\n\n一個表格了解 Docker 有多棒 :+1:\n\nFeauture  | Containers                  |  Virtual Machines ( 傳統的虛擬化 )\n--      | ----------            | ----------\n 啟動   | 秒開 | 最快也要分鐘\n 容量 | MB        | GB\n 效能 | 快        | 慢\n 支援數量 | 非常多 Containers        | 10多個就很了不起了\n 複製相同環境 | 快        | 超慢\n\n不理解 :question: :question: :question:\n\n我們來看一張圖，包準你懂\n\n![](https://i.imgur.com/H8wmOUh.jpg)\n\n圖的來源\n[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/)\n\n### 為什麼要使用 Docker\n\n潮～ 不解釋 :satisfied:\n\n#### 更有效率的利用資源\n\n比起像是 [https://www.virtualbox.org/](https://www.virtualbox.org/)，Docker 的利用率更高，我們可以設定更多\n\n的 Containers, 而且啟動速度飛快！！ :flushed:\n\n#### 統一環境\n\n相信大家都有每次搞電腦的環境都搞的很煩的經驗 :angry:\n\n假設今天公司來了個新同事，就又要幫他建立一次環境 :expressionless:\n\n不然就是，我的電腦 run 起來正常阿～ 你的怎麼不行，是不是 xxx 版本的關係阿 :joy:\n\n相信大家多多少少都遇過上面這些事情，我們可以透過 Docker 來解決這些問題，\n\n保持大家環境一致，而且要建立的時候也很快 :smile:\n\n#### 對於 DevOps 的好處\n\n對於 [DevOps](https://zh.wikipedia.org/wiki/DevOps) 來說，最希望的就是可以設定一次，將來在其他地方都可以快速建立環境且正常執行。\n\n### Docker 概念\n\n建議大家先了解一下 Docker 中的幾個名詞，分別為\n\n***Image***\n\n映像檔，可以把它想成是以前我們在玩 VM 的 Guest OS（ 安裝在虛擬機上的作業系統 ）。\n\nImage 是唯讀（ R\\O ）\n\n***Container***\n\n容器，利用映像檔（ Image ）所創造出來的，一個 Image 可以創造出多個不同的 Container，\n\nContainer 也可以被啟動、開始、停止、刪除，並且互相分離。\n\nContainer 在啟動的時候會建立一層在最外（上）層並且是讀寫模式（ R\\W ）。\n\n這張圖解釋了 Image 是唯讀（ R\\O ）以及 Container 是讀寫模式（ R\\W ） 的關係\n\n![](https://i.imgur.com/wVvrWwJ.png)\n\n更多關係可參考 [https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/#images-and-layers](https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/#images-and-layers)\n\n***Registry***\n\n可以把它想成類似 [GitHub](https://github.com/)，裡面存放了非常多的 Image ，可在 [Docker Hub](https://hub.docker.com/) 中查看。\n\n更詳細的我這邊就不再解釋惹，留給大家做作功課 :stuck_out_tongue:\n\n## 安裝\n\nWindows\n\n請先到 Docker 官網\n\n[https://www.docker.com/docker-windows](https://www.docker.com/docker-windows)\n\n下載 stable 版本\n\n![](https://i.imgur.com/ryKtNXm.jpg)\n\n接下來就是無腦安裝，安裝完後他會叫你登出電腦，點下去後就會幫你登出電腦\n\n![](https://i.imgur.com/EE7XmYM.jpg)\n\n接著如果你的電腦沒有啟用 [Hyper-V](https://msdn.microsoft.com/zh-tw/library/hh831531(v=ws.11).aspx) ，他會叫你重啟電腦\n(一樣，點下去就對惹)\n\n( 更多可 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/) )\n\n![](https://i.imgur.com/YG79VE1.jpg)\n\n重新開機後，你就會發現可愛的 Docker 在右下角蹦出來惹\n\n![](https://i.imgur.com/zMgf36E.png)\n\n我們可以再用 cmd 確認一下是否有成功安裝\n\n```cmd\ndocker --version\ndocker-compose --version\n```\n\n![](https://i.imgur.com/k1o3GIz.png)\n\n記得再設定一個東西 Shared Drives\n\n![](https://i.imgur.com/a6dqWU8.jpg)\n\n裝完了之後，建議大家再多裝一個 [Kitematic](https://kitematic.com/)，他是 GUI 介面的，方便你使用 Docker，\n\n( 後面會再介紹一個更贊的 GUI 介面 [portainer](https://github.com/portainer/portainer)  :grin: )\n\n我知道打指令很潮，但還是建議裝一下。\n\n直接對著你的 Docker 圖示右鍵，就可以看到 [Kitematic](https://kitematic.com/)\n\n![](https://i.imgur.com/gdVFFMT.png)\n\n![](https://i.imgur.com/SRaHNCP.jpg)\n\n下載回來直接解壓縮雙點擊即可使用\n\n![](https://i.imgur.com/9zsU23B.png)\n\nMAC\n\nMAC 我本身也有，但因為更早之前就裝了，步驟就沒記錄了，基本上大同小異\n\n[https://www.docker.com/docker-mac](https://www.docker.com/docker-mac)\n\nLinux\n\n[Youtube Tutorial-Ubuntu(Linux) 如何安裝 docker](https://youtu.be/eS_HMBC_RaA)\n\n這裡使用 Ubuntu 當作範例,\n\n雖然在 ubuntu 中有 `snap` 可以非常快速的安裝 docker,\n\n但在這邊我們不使用 `snap` 的方法安裝 :smile:\n\n請參考官方文件步驟安裝,\n\nGet Docker Engine - Community for Ubuntu\n\n[Get Docker Engine - Community for Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu/)\n\n安裝後步驟 (optional :exclamation:), 但建議參考一下\n\n[Post-installation steps for Linux](https://docs.docker.com/install/linux/linux-postinstall/)\n\ndocker-compose 的安裝\n\n[docker-compose install](https://docs.docker.com/compose/install/)\n\n系統資源分配問題,\n\n假如你是使用 windows 或是 mac 的 docker,\n\n你會有一個界面可以設定你要分多少的 cpu 以及 ram 給你的 docker,\n\n通常會在 Preferences -\u003e Advanced, 有 GUI 界面,\n\n![](https://i.imgur.com/CWMQHxs.png)\n\n但如果是使用 linux, 就不會有這個界面, 因為在 Linux 中,\n\n會自動依照系統的資源進行分配.\n\n## 指令介紹\n\n接著介紹一些 Docker 的指令，\n\nDocker 的指令真的很多，這裡就介紹我比較常用的或是實用的指令\n\n查看目前 images\n\n```cmd\ndocker images\n```\n\n建立 image\n\n```cmd\ndocker create [OPTIONS] IMAGE [COMMAND] [ARG...]\n```\n\n詳細的參數可參考 [https://docs.docker.com/engine/reference/commandline/create/](https://docs.docker.com/engine/reference/commandline/create/)\n\n範例 ( 建立一個名稱為  busybox 的 image )\n\n```cmd\ndocker create -it --name busybox busybox\n```\n\n刪除 Image\n\n```cmd\ndocker rmi [OPTIONS] IMAGE [IMAGE...]\n```\n\n查看目前運行的 container\n\n```cmd\ndocker ps\n```\n\n查看目前全部的 container（ 包含停止狀態的 container ）\n\n```cmd\ndocker ps -a\n```\n\n新建並啟動 Container\n\n```cmd\ndocker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]\n```\n\n舉個例子\n\n```cmd\ndocker run -d -p 80:80 --name my_image nginx\n```\n\n`-d` 代表在 Detached（ 背景 ）執行，如不加 `-d`，預設會 foreground ( 前景 ) 執行\n\n`-p` 代表將本機的 80 port 的所有流量轉發到 container 中的 80 port\n\n`--name` 設定 container 的名稱\n\n在舉一個例子\n\n```cmd\n docker run -it --rm busybox\n```\n\n`--rm` 代表當 exit container 時，會自動移除 container。 ( incompatible with -d )\n\n更詳細的可參考 [https://docs.docker.com/engine/reference/run/](https://docs.docker.com/engine/reference/run/)\n\n啟動 Container\n\n```cmd\ndocker start [OPTIONS] CONTAINER [CONTAINER...]\n```\n\n如果想讓他在前景跑順便觀看輸出 , 可以使用以下指令\n\n```cmd\ndocker start -a [OPTIONS] CONTAINER [CONTAINER...]\n```\n\n`--attach` 或 `-a` 代表 Attach STDOUT/STDERR and forward signals.\n\n更詳細的可參考 [https://docs.docker.com/engine/reference/commandline/start/](https://docs.docker.com/engine/reference/commandline/start/)\n\n（ container ID 寫幾個就可以了，和 Git 的概念是一樣的 ，\n\n不了解 Git 可以參考 [Git-Tutorials GIT基本使用教學](https://github.com/twtrubiks/Git-Tutorials) ）\n\n停止 Container\n\n```cmd\ndocker stop [OPTIONS] CONTAINER [CONTAINER...]\n```\n\n重新啟動 Container\n\n```cmd\ndocker restart [OPTIONS] CONTAINER [CONTAINER...]\n```\n\n删除 Container\n\n```cmd\ndocker rm [OPTIONS] CONTAINER [CONTAINER...]\n```\n\n`--volumes , -v` 加上這個參數，會移除掉連接到這個 container 的 volume。\n\n可參考 [https://docs.docker.com/engine/reference/commandline/rm/](https://docs.docker.com/engine/reference/commandline/rm/)\n\n進入 Container\n\n```cmd\ndocker exec [OPTIONS] CONTAINER COMMAND [ARG...]\ndocker exec -it \u003cContainer ID\u003e bash\n```\n\n使用 root 使用者進入　\n\n```cmd\ndocker exec -u 0 -it \u003cContainer ID\u003e bash\ndocker exec -u root -it \u003cContainer ID\u003e bash\n```\n\n打指令比較潮，或是說你也可以透過 [Kitematic](https://kitematic.com/) 進入。\n\n[](https://i.imgur.com/Yui1UZb.png)\n\n當我們進入了 Container 之後，有時候想看一下裡面 Linux 的版本，\n\n這時候可以使用以下指令查看\n\n```cmd\ncat /etc/os-release\n```\n\n查看 Container 詳細資料\n\n```cmd\ndocker inspect [OPTIONS] NAME|ID [NAME|ID...]\n```\n\n查看 log\n\n```cmd\ndocker logs [OPTIONS] CONTAINER\n```\n\n`--follow` , `-f`  ,  Follow log output\n\n更詳細的可參考 [https://docs.docker.com/engine/reference/commandline/logs/](https://docs.docker.com/engine/reference/commandline/logs/)\n\n\n從最後 100 行開始追蹤,\n\n```cmd\ndocker logs -f --tail 100 CONTAINER\n```\n\n或是\n\n```cmd\ndocker logs -f -n 100 CONTAINER\n```\n\n可以透過 `--since` 從指定時間到現在的 log,\n\n例如,\n\n```cmd\ndocker logs --since 2023-04-13T09:20:00 \u003ccontainer_id\u003e\n```\n\n從 10 分鐘前到現在的 log\n\n```cmd\ndocker logs --since 10m CONTAINER\n```\n\n1 小時前到現在的 log\n\n```cmd\ndocker logs --since 1h CONTAINER\n```\n\n如果想指定時間, 查看特定區間的 logs,\n\n可以先使用 `-t` 找出 docker 的時間格式,\n\n```cmd\ndocker logs -t CONTAINER\n```\n\n接著就可以使用 `--since` 或 `--until` 指定時間段,\n\n一定要用 docker 的時間格式, 不然會無法生效.\n\n這邊來個組合, 找出 8:10 ~ 8:30 的全部 log\n\n```cmd\ndocker logs --since 2023-12-10T8:10:00.346748975Z  --until 2023-12-10T8:30:00.346748975Z  CONTAINER\n```\n\n也可以把 log 寫進去檔案中,\n\n```cmd\ndocker logs CONTAINER \u003e\u003e access.log\n```\n\n如果上述指令沒有生效, 請修改成以下\n\n```cmd\ndocker logs CONTAINER \u003e\u0026 access.log\n```\n\n也可以先過濾 log 再寫進檔案中,\n\n```cmd\ndocker logs CONTAINER | grep \"29/Mar/2022\" \u003e\u003e access_tmp.log\n```\n\n如果上述指令沒有生效, 請修改成以下\n\n```cmd\ndocker logs CONTAINER 2\u003e\u00261 | grep \"29/Mar/2022\" \u003e\u0026 access_tmp.log\n```\n\n顯示容器資源 ( CPU , I/O ...... )\n\n```cmd\ndocker stats [OPTIONS] [CONTAINER...]\n```\n\n也可以加上 `--no-stream`\n\n```cmd\ndocker stats --no-stream\n```\n\n`--no-stream` Disable streaming stats and only pull the first result.\n\n注意 :exclamation: :exclamation: 這邊得到的 memory usage 會比實際上的還要小,\n\n因為這邊的值是再減去 cache usage memory.\n\n相關 issues 可參考 [https://github.com/moby/moby/issues/32253](https://github.com/moby/moby/issues/32253)\n\n```txt\nOn Linux, the Docker CLI reports memory usage by subtracting cache usage from the total memory usage.\n```\n\n詳細說明可參考 [https://docs.docker.com/engine/reference/commandline/stats/](https://docs.docker.com/engine/reference/commandline/stats/)\n\n也可參考 [https://docs.docker.com/config/containers/runmetrics/](https://docs.docker.com/config/containers/runmetrics/)\n\n查看 container 中正在執行的 processes\n\n```CMD\ndocker top CONTAINER\n```\n\n停止指定的 CONTAINER 中全部的 **processes**\n\n```cmd\ndocker pause CONTAINER [CONTAINER...]\n```\n\n執行 `docker pause` 之後，可以試這用 `docker ps` 查看，會發現\n\n還是有在執行，這裡拿  `docker stop`  比較一下，差異如下。\n\n `docker stop` : process 級別。\n\n `docker pause`: container 級別。\n\n恢復指定暫停的 CONTAINER 中全部的 **processes**\n\n```cmd\ndocker unpause CONTAINER [CONTAINER...]\n```\n\ndocker tag\n\n```cmd\ndocker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]\n```\n\n範例\n\n```cmd\ndocker tag 0e5574283393 twtrubiks/nginx:version1.0\n```\n\n更多可參考 [https://docs.docker.com/engine/reference/commandline/tag/](https://docs.docker.com/engine/reference/commandline/tag/)\n\n儲存 (備份) image 成 tar 檔案\n\n```cmd\n\n[OPTIONS] IMAGE [IMAGE...]\n```\n\n範例\n\n```cmd\ndocker save busybox \u003e busybox.tar\n```\n\n或\n\n```cmd\ndocker save --output busybox.tar busybox\n```\n\n或 ( 也可以一次備份多個 )\n\n```cmd\ndocker save -o images.tar postgres:9.6 busybox\n```\n\n更多可參考 [https://docs.docker.com/engine/reference/commandline/save/](https://docs.docker.com/engine/reference/commandline/save/)\n\n載入 image\n\n```cmd\ndocker load [OPTIONS]\n```\n\n範例\n\n```cmd\ndocker load \u003c busybox.tar\n```\n\n或\n\n```cmd\ndocker load -i busybox.tar\n```\n\n更多可參考 [https://docs.docker.com/engine/reference/commandline/load/](https://docs.docker.com/engine/reference/commandline/load/)\n\n顯示 image 的 history，查詢 image 的每一層\n\n```cmd\ndocker history [OPTIONS] IMAGE\n```\n\n在 docker 中，一層一層的概念很重要。\n\n![](https://i.imgur.com/NmImVby.png)\n\n更多可參考 [https://docs.docker.com/engine/reference/commandline/history/](https://docs.docker.com/engine/reference/commandline/history/)\n\n剛剛有教大家如何儲存 (備份) images， 載入 images，\n\n還有另外一種是 export 和 import containers，\n\ndocker export container 請參考 [https://docs.docker.com/engine/reference/commandline/export/](https://docs.docker.com/engine/reference/commandline/export/)。\n\ndocker import container 請參考 [https://docs.docker.com/engine/reference/commandline/import/](https://docs.docker.com/engine/reference/commandline/import/)。\n\n其他指令\n\n刪除所有 dangling images\n\n```cmd\ndocker image prune\n```\n\n移除全部 unused images (不只 dangling images)\n\n```cmd\ndocker image prune -a\n```\n\n更多資訊可參考 [image_prune](https://docs.docker.com/engine/reference/commandline/image_prune/)\n\n停止所有正在運行的 Container\n\n```cmd\ndocker container stop $(docker ps -q)\n```\n\n更多資訊可參考 [container_stop](https://docs.docker.com/engine/reference/commandline/container_stop/)\n\n移除全部停止的 containers\n\n```cmd\ndocker container prune\n```\n\n更多資訊可參考 [container_prune](https://docs.docker.com/engine/reference/commandline/container_prune/)\n\n### ENTRYPOINT\n\n教學說明請點選 [entrypoint-tutorial](https://github.com/twtrubiks/docker-tutorial/tree/master/entrypoint-tutorial)\n\n### Volume\n\n接下來要介紹 Volume，Volume 是 Docker 最推薦存放 persisting data（ 數據 ）的機制，\n\n使用 Volume 有下列優點\n\n* Volumes are easier to back up or migrate than bind mounts.\n* You can manage volumes using Docker CLI commands or the Docker API.\n* Volumes work on both Linux and Windows containers.\n* Volumes can be more safely shared among multiple containers.\n* Volume drivers allow you to store volumes on remote hosts or cloud providers, to encrypt the contents of volumes, or to add other functionality.\n* A new volume's contents can be pre-populated by a container.\n\n在 container 的可寫層中，使用 volume 是一個比較好的選擇，因為他不會增加 container 的容量，\n\nvolume 的內容存在於 container 之外。\n\n也可參考下圖\n\n![](https://i.imgur.com/fiIt0kS.png)\n\n更詳細的可參考 [https://docs.docker.com/engine/admin/volumes/volumes/](https://docs.docker.com/engine/admin/volumes/volumes/)\n\n查看目前的 volume\n\n```cmd\ndocker volume ls [OPTIONS]\n```\n\n創造一個 volume\n\n```cmd\ndocker volume create [OPTIONS] [VOLUME]\n```\n\n刪除一個 volume\n\n```cmd\ndocker volume rm [OPTIONS] VOLUME [VOLUME...]\n```\n\n查看 volume 詳細資料\n\n```cmd\ndocker volume inspect [OPTIONS] VOLUME [VOLUME...]\n```\n\n移除全部未使用的 volume\n\n```cmd\ndocker volume prune [OPTIONS]\n```\n\n也可以建立 readonly 的 volumes (容器內 readonly)\n\n`docker-compose.yml` 方法如下,\n\n```yml\nversion: '3.5'\nservices:\n  nginx:\n    image: nginx\n    ports:\n      - \"80:80\"\n    volumes:\n      - \"nfs-data:/data:ro,z\"\n\nvolumes:\n    nfs-data:\n```\n\n如果要可讀寫, 就設定 `rw`.\n\nvolumes 在容器內的確不能寫 (只能讀)\n\n![alt tag](https://i.imgur.com/ve4572t.png)\n\n使用以下的指令查看 Mounts, 觀察它的 Mode\n\n```cmd\ndocker inspect \u003ccontainer ID\u003e\n```\n\n![alt tag](https://i.imgur.com/ex8A3Y5.png)\n\n也可以建立 NFS volumes,\n\n`docker-compose.yml` 方法如下,\n\n```yml\nversion: '3.5'\nservices:\n  nginx:\n    image: nginx\n    ports:\n      - \"80:80\"\n    volumes:\n      - \"nfs-data:/data\"\n\nvolumes:\n    nfs-data:\n      driver: local\n      driver_opts:\n        type: nfs\n        o: nfsvers=4,addr=ip,rw\n        device: \":/path/to/dir\"\n```\n\n可以用以下指令查看設定\n\n```cmd\ndocker volume ls\ndocker inspect \u003cvolume name\u003e\n```\n\n![alt tag](https://i.imgur.com/8mzUGsg.png)\n\nNFS 相關文章可參考 [linux-nfs-server - 如何在 ubuntu 啟用 NFS Server](https://github.com/twtrubiks/linux-note/tree/master/linux-nfs-server)\n\n### network\n\n建議大家花點時間研究 docker 中的 network，會蠻有幫助的 :smiley:\n\n查看目前 docker 的網路清單\n\n```cmd\ndocker network ls [OPTIONS]\n```\n\n詳細可參考 [https://docs.docker.com/engine/userguide/networking/](https://docs.docker.com/engine/userguide/networking/)\n\ndocker 中的網路主要有三種 Bridge、Host、None，預設皆為 Bridge 模式。\n\n指定 network 範例 ( 指定使用  `host` 網路 )\n\n```cmd\ndocker run -it --name busybox --rm --network=host busybox\n```\n\n建立 network\n\n```cmd\ndocker network create [OPTIONS] NETWORK\n```\n\n移除 network\n\n```cmd\ndocker network rm NETWORK [NETWORK...]\n```\n\n移除全部未使用的 network\n\n```cmd\ndocker network prune [OPTIONS]\n```\n\n查看 network 詳細資料\n\n```cmd\ndocker network inspect [OPTIONS] NETWORK [NETWORK...]\n```\n\n將 container 連接 network\n\n```cmd\ndocker network connect [OPTIONS] NETWORK CONTAINER\n```\n\n更多詳細資料可參考 [https://docs.docker.com/engine/reference/commandline/network_connect/](https://docs.docker.com/engine/reference/commandline/network_connect/)\n\nDisconnect container  network\n\n```cmd\ndocker network disconnect [OPTIONS] NETWORK CONTAINER\n```\n\n更多詳細資料可參考 [https://docs.docker.com/engine/reference/commandline/network_disconnect/](https://docs.docker.com/engine/reference/commandline/network_disconnect/)\n\n#### User-defined networks\n\n這個方法是官方推薦的 :thumbsup:\n\n透過內建的 DNS 伺服器，可以直接使用容器名稱，就可解析出 IP，不需要再使用 IP 讓容器互相\n\n溝通，我們只需要知道容器的名稱就可以連接到容器。\n\n更多詳細資料可參考 [https://docs.docker.com/engine/userguide/networking/#user-defined-networks](https://docs.docker.com/engine/userguide/networking/#user-defined-networks)\n\n## docker-compose\n\n再來要介紹 docker-compose，可參考官網 [https://docs.docker.com/compose/](https://docs.docker.com/compose/)\n\n![](https://i.imgur.com/YxrrO7t.png)\n\nCompose 是定義和執行多 Container 管理的工具，不懂我在說什麼 :question: :question: :question:\n\n試著想想看，通常一個 Web 都還會有 DB，甚至可能還有 [Redis](https://redis.io/) 或 [Celery](http://www.celeryproject.org/)，\n\n所以說我們需要有 Compose 來管理這些，透過 `docker-compose.yml` ( YML 格式 ) 文件。\n\n`docker-compose.yml` 的寫法可參考 [https://docs.docker.com/compose/compose-file/](https://docs.docker.com/compose/compose-file/)\n\n也可以直接參考官網範例 [https://docs.docker.com/compose/compose-file/#compose-file-structure-and-examples](https://docs.docker.com/compose/compose-file/#compose-file-structure-and-examples)\n\nCompose 的 Command-line 很多和 Docker 都是類似的，\n\n可參考 [https://docs.docker.com/glossary/?term=compose](https://docs.docker.com/glossary/?term=compose)\n\n查看目前 Container\n\n```cmd\ndocker-compose ps\n```\n\n加上 `-q` 的話，只顯示 id\n\n```cmd\ndocker-compose ps -q\n```\n\n啟動 Service 的 Container\n\n```cmd\ndocker-compose start  [SERVICE...]\n```\n\n停止 Service 的 Container ( 不會刪除 Container )\n\n```cmd\ndocker-compose stop [options] [SERVICE...]\n```\n\n重啟 Service 的 Container\n\n```cmd\ndocker-compose restart [options] [SERVICE...]\n```\n\nBuilds, (re)creates, starts, and attaches to containers for a service\n\n```cmd\ndocker-compose up [options] [--scale SERVICE=NUM...] [SERVICE...]\n```\n\n加個 `-d`，會在背景啟動，一般建議正式環境下使用。\n\n```cmd\ndocker-compose up -d\n```\n\n然後如果你有很多個 `docker-compose.yml` `docker-compose-dev.yml`,\n\n你可以透過 `-f` 決定你要執行哪一個, 範例如下,\n\n```cmd\ndocker-compose -f ./docker-compose-dev.yml up -d\n```\n\n`-f` `--file FILE` Specify an alternate compose file\n\n(default: `docker-compose.yml`)\n\n`up` 這個功能很強大，建議可以參考 [https://docs.docker.com/compose/reference/up/](https://docs.docker.com/compose/reference/up/)\n\n如果你希望每次都重新 build image，可以加上\n\n`--build` ( Build images before starting containers. )\n\n```cmd\ndocker-compose up -d --build\n```\n\ndocker-compose down\n\n```cmd\ndocker-compose down [options]\n```\n\n`down` 這個功能也建議可以參考 [https://docs.docker.com/compose/reference/down/](https://docs.docker.com/compose/reference/down/)\n\n舉個例子\n\n```cmd\ndocker-compose down -v\n```\n\n加個 `-v` 就會順便幫你把 volume 移除（ 移除你在 `docker-compose.yml` 裡面設定的 volume ）\n\n在指定的 Service 中執行一個指令\n\n```cmd\ndocker-compose run [options] [-v VOLUME...] [-p PORT...] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...]\n[ARGS...]\n```\n\n舉個例子\n\n```cmd\ndocker-compose run web bash\n```\n\n在 web Service 中執行 `bash` 指令\n\n可參考 [https://docs.docker.com/compose/reference/run/](https://docs.docker.com/compose/reference/run/)\n\n觀看 Service logs\n\n```cmd\ndocker-compose logs [options] [SERVICE...]\n```\n\n檢查 `docker-compose.yml` 格式是否正確\n\n```cmd\ndocker-compose config\n```\n\n如下指令，和 `docker exec` 一樣\n\n```cmd\ndocker-compose exec\n```\n\n範例 ( 進入 web 這個 service 的 bash )\n\n```cmd\ndocker-compose exec web bash\n```\n\n顯示被使用到的 container 中的 images 清單\n\n```cmd\ndocker-compose images\n```\n\n移除  service containers\n\n```cmd\ndocker-compose rm\n```\n\nPushes images 到 docker hub\n\n```cmd\ndocker-compose push\n```\n\n目前這個指令其實我也搞不太懂，可參考 [https://github.com/docker/compose/issues/4283](https://github.com/docker/compose/issues/4283)\n\n官網也解釋的沒有很清楚 [https://docs.docker.com/compose/reference/push/](https://docs.docker.com/compose/reference/push/)\n\n### docker-compose up/down 和 restart 的差異\n\n* [Youtube Tutorial - docker-compose up/down 和 restart 的差異](https://youtu.be/nX-sbLPz-MU)\n\n先來談 `docker-compose up/down`,\n\n假如今天你修改了 `docker-compose.yml` 又或是更新了 image,\n\n當你要重建 docker , 有幾種方法,\n\n方法一.\n\n先停止 container, 執行 `docker-compose down` 再執行 `docker-compose up`.\n\n方法二.\n\n不需要停止 container, 直接執行 `docker-compose up -d`.\n\n(他會自動幫你重建, 很方便, 不需要多一步先關閉 container )\n\n結論, 只要你的 `docker-compose.yml` 有任何變動, 一定要執行 `docker-compose up` 才會生效.\n\n再來談 `docker-compose restart`,\n\n請看官方文件 [docker-compose restart](https://docs.docker.com/compose/reference/restart/), 如果你對 `docker-compose.yml` 修改, 然後使用這個指令, 是**不會**生效的,\n\n但是, 如果你是改 code (可能是 python code), 那這個指令是有效的.\n\n### docker-compose networks\n\n* [Youtube Tutorial - docker-compose networks 說明](https://youtu.be/wmV9WfkpyGk)\n\n這邊多補充 docker-compose networks 的觀念，因為剛好最近有用到 :smile:\n\n```yml\nversion: '3.5'\nservices:\n\n    db:\n      container_name: 'postgres'\n      image: postgres\n      environment:\n        POSTGRES_PASSWORD: password123\n      ports:\n        - \"5432:5432\"\n        # (HOST:CONTAINER)\n      volumes:\n        - pgdata:/var/lib/postgresql/data/\n      networks:\n        - proxy\n\n    web:\n      build: ./api\n      command: python manage.py runserver 0.0.0.0:8000\n      restart: always\n      volumes:\n        - api_data:/docker_api\n        # (HOST:CONTAINER)\n      ports:\n        - \"8000:8000\"\n        # (HOST:CONTAINER)\n      depends_on:\n        - db\n      networks:\n        - proxy\n\nvolumes:\n    api_data:\n    pgdata:\n\nnetworks:\n    proxy:\n      # external:\n        name: my_network\n```\n\n先把 version 改成 3.5，因為這版本才開始有 networks name 的概念，在\n\ndb 以及 web 中都加了 networks ( 自己定義的 )，定義的地方在最後面，\n\nproxy 是名稱 ( 類似 volumes 的概念 )，`external` option 的意思代表\n\n是不是要參考外部別人已經定義好的 network ( 所以如果找不到就會報錯 )，\n\n但如果不加上 `external` option，也就代表是自己定義的，會幫你自動建立\n\n你所定義的 network，名稱為 my_network。\n\n如果你都完全沒有定義 networks，預設就是資料夾的名稱_default 。\n\n### docker-compose ports 和 expose 差異\n\n在 docker-compose 中有兩種方法可以暴露容器 ports，\n\n分別是 ports 和 expose，\n\n#### ports\n\n```yml\n...\nports:\n  - \"5000:5000\"  # 绑定 container 中的 5000 port 到 本機(HOST) 的 5000 port\n  # (HOST:CONTAINER)\n\n  - \"5001:5000\"  # 绑定 container 中的 5000 port 到 本機(HOST) 的 5001 port\n\n  - \"5000\"       # 绑定 container 中的 5000 port 到本機的任意 port (本機會隨機被分配到一個 port)\n...\n```\n\n隨機 port 範例，\n\n這邊使用 dpage/pgadmin4 這個 images 來示範，\n\n```cmd\ndocker run -p 80 \\\n    -e \"PGADMIN_DEFAULT_EMAIL=xxxrubiks@gmail.com\" \\\n    -e \"PGADMIN_DEFAULT_PASSWORD=SuperSecret\" \\\n    -d dpage/pgadmin4\n```\n\n如果我們執行兩次以上指令，你會發現本機被分配到兩個隨機的 ports (如下圖)，\n\n![alt tag](https://i.imgur.com/kkcnuJI.png)\n\n本機被隨機分配到 32768 以及 32769 port，\n\n這邊不管我們怎麼設定 ports，這些 ports 都會暴露給本機 (HOST) 以及其他 containers，這點很重要 :exclamation: :exclamation:\n\n也就是說，如果本機 5001 ports 被使用了，其他的 containers 就無法使用 5001 ports，\n\n可能要改成5002 ports 之類的。\n\n#### expoese\n\n```yml\n...\nexpose:\n  - \"4000\"\n  - \"6000\"\n...\n```\n\nexpose 是將 port 暴露給其他容器。\n\nexpose 和 ports 最大的差別就是在 expose 不會暴露 port 給本機(HOST)，\n\n所以 本機(HOST)絕對無法被訪問，但 containers 內可以被訪問，\n\n所以說如果今天你的容器想要在 本機(HOST) 被訪問，一定要使用 ports 方式。\n\n***ports 和 expose 差異***\n\n簡單說，就是 ports 可以被 本機(HOST) 和 containers 訪問 ; 而\n\nexpose 是本機(HOST) 無法被訪問，只有在 containers 中可以被訪問。\n\n## Docker container 內如何連接到本機 localhost 服務\n\n* [Youtube Tutorial - Docker container 內如何連接到本機 localhost 服務](https://youtu.be/KbaHWdVej9U)\n\n![alt tag](https://i.imgur.com/kQLcALp.png)\n\n假設今天在本機上有一個 A 服務, 他是使用 docker run 起來的,\n\n而本機上還有一個 B 服務, 是用 vscode run 起來的 (非 docker),\n\n這時候我有一個需求, 我想要將我的 A 服務連線到我的 B 服務,\n\n也就是從 docker 內的服務連接到本機 localhost.\n\n比較簡單的方法, 就是透過 docker 內的這個參數,\n\n`host.docker.internal:host-gateway`.\n\n在你的 yml 裡面加上,\n\n```yml\nversion: '3.5'\nservices:\n\n  web:\n    ......\n    extra_hosts:\n      - \"host.docker.internal:host-gateway\"\n......\n```\n\n這樣當你在容器內, 就可以順利訪問本機 :smile:\n\n```cmd\ncurl http://host.docker.internal:8069\n```\n\n也可以參考 [docker compose 安裝 pgadmin4](https://github.com/twtrubiks/docker-pgadmin4-tutorial#docker-compose-%E5%AE%89%E8%A3%9D-pgadmin4),\n\n假設今天不考慮使用網路的方法, 如果一個容器 db 是在 5432, 另一個容器是 pgadmin4,\n\n這樣要怎麼透過 pgadmin4 連接到我的本機的 5432 呢 😵‍💫\n\n答案就是使用 `host.docker.internal:host-gateway`.\n\n## Docker Registry\n\n![](https://i.imgur.com/uAXUtxT.png)\n\n可以把它想成是一個類似 github 的地方，只不過裡面變成是存 docker 的東西，當然，\n\n也可以自己架，但會有一些額外的成本，像是網路，維護等等，這部分就要自己衡量了 :grinning:\n\n接下來教大家如何將 image push 到 Docker Registry :smiley:\n\n* [Youtube Tutorial PART 4 - Docker push image to Docker Hub 教學](https://youtu.be/dVBKwmqO5e4)\n\n首先，先登入 [Docker Registry](https://hub.docker.com/)  ( 註冊流程很簡單，我就跳過了 )\n\n```cmd\ndocker login\n```\n\n![](https://i.imgur.com/lm9GWTj.png)\n\n舉個例子，先 run 一個 busybox 的容器\n\n```cmd\ndocker run -it busybox\n```\n\n接著在裡面新增一筆資料\n\n```cmd\n echo 'text' \u003e data.txt\n```\n\n![](https://i.imgur.com/KCeZGQh.png)\n\n然後打開另一個 terminal ，使用 `docker ps` 查看目前容器的 id\n\n![](https://i.imgur.com/mBIhGBW.png)\n\n再來使用像 git 一樣的方式 commit\n\ndocker commit\n\n```cmd\ndocker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]\n```\n\n可參考 [https://docs.docker.com/engine/reference/commandline/commit/](https://docs.docker.com/engine/reference/commandline/commit/)\n\n```cmd\ndocker commit -m \"test\" 4fb4ef51e917 twtrubiks/my_busybox\n```\n\n`-m` commit message ，和 git 一樣。\n\ntwtrubiks/my_busybox 則為我們定義的 REPOSITORY。\n\n如果需要 tag , 也可以增加\n\n```cmd\ndocker commit -m \"test\" 4fb4ef51e917 twtrubiks/my_busybox:v1\n```\n\n（ 如果沒定義 tag , 則會顯示 latest ）\n\n這時候可以用 `docker images` 查看\n\n![](https://i.imgur.com/R548ail.png)\n\n最後 push\n\n```cmd\ndocker push twtrubiks/my_busybox\n```\n\n![](https://i.imgur.com/2ExgYpB.png)\n\ndocker 是一層一層的概念，他只會 push 自己新增的幾層上去而已，\n\n所以不用擔心整個 image 很大，要上傳很久 :relaxed:\n\n最後可以到 [https://hub.docker.com/](https://hub.docker.com/) 確認是否有成功 :smile:\n\n![](https://i.imgur.com/W5P3YQL.png)\n\n## 用 Docker 實戰 Django 以及 Postgre\n\n* [Youtube Tutorial PART 2 - 用 Docker 實戰 Django 以及 Postgre](https://youtu.be/aZ6woJ7qekE)\n\n上面介紹了那麼多，來實戰一下是必須的 :satisfied:\n\n我們使用 [Django-REST-framework 基本教學 - 從無到有 DRF-Beginners-Guide](https://github.com/twtrubiks/django-rest-framework-tutorial) 來當範例\n\n有幾個地方必須修改一下，\n\n將 `settings.py`  裡面的 db 連線改成 [PostgreSQL](https://www.postgresql.org/)\n\n```pyhon\nDATABASES = {\n    'default': {\n        'ENGINE': 'django.db.backends.postgresql_psycopg2',\n        'NAME': 'postgres',\n        'USER': 'postgres',\n        'PASSWORD': 'password123',\n        'HOST': 'db',\n        'PORT': 5432,\n    }\n}\n```\n\n建議也將 `ALLOWED_HOSTS = []` 改為 `ALLOWED_HOSTS = ['*']`\n（ 這只是方便，實務上不會這樣使用 ）\n\n再來是兩個很重要的檔案，分別為 `Dockerfile` 和 `docker-compose.yml`\n\n`Dockerfile`\n\n```text\nFROM python:3.8.12\nLABEL maintainer twtrubiks\nENV PYTHONUNBUFFERED 1\nRUN mkdir /docker_api\nWORKDIR /docker_api\nCOPY . /docker_api/\nRUN pip install -r requirements.txt\n```\n\n詳細可參考 [https://docs.docker.com/engine/reference/builder/](https://docs.docker.com/engine/reference/builder/)\n\n`docker-compose.yml`\n\n```yml\nversion: '3'\nservices:\n\n    db:\n      container_name: 'postgres'\n      image: postgres\n      environment:\n        POSTGRES_PASSWORD: password123\n      ports:\n        - \"5432:5432\"\n        # (HOST:CONTAINER)\n      volumes:\n        - pgdata:/var/lib/postgresql/data/\n\n    web:\n      build: ./api\n      command: python manage.py runserver 0.0.0.0:8000\n      restart: always\n      volumes:\n        - api_data:/docker_api\n        # (HOST:CONTAINER)\n      ports:\n        - \"8000:8000\"\n        # (HOST:CONTAINER)\n      depends_on:\n        - db\n\nvolumes:\n    api_data:\n    pgdata:\n```\n\n詳細可參考 [https://docs.docker.com/compose/compose-file/#compose-file-structure-and-examples](https://docs.docker.com/compose/compose-file/#compose-file-structure-and-examples)\n\n溫馨小提醒 1  :heart:\n\n可能有人會問為什麼我是使用 `0.0.0.0`，而不是使用 `127.0.0.1` :question: :question:\n\n```cmd\npython manage.py runserver 0.0.0.0:8000\n```\n\n`127.0.0.1`，並不代表真正的 **本機**，我們經常認為他是本機是因為我們電腦的 `host` 預設都幫你設定好了 :smirk:\n\n詳細的 `host` 設定教學可參考 [hosts-設定檔 以及 查詢內網 ip](https://github.com/twtrubiks/docker-django-nginx-uswgi-postgres-tutorial#hosts-設定檔-以及-查詢內網-ip)，\n\n`0.0.0.0` 才是真正的代表，**當下 ( 本 ) 網路中的本機** :pencil2:\n\n如果大家想更深入的了解，可 google 再進一步的了解 `127.0.0.1` 以及 `0.0.0.0` 的差異 :smile:\n\n溫馨小提醒 2  :heart:\n\n這邊要特別提一下 `depends_on` 這個參數，\n\n詳細可參考 [https://docs.docker.com/compose/compose-file/#depends_on](https://docs.docker.com/compose/compose-file/#depends_on)，\n\n上面連結中有一段說明很值得看\n\n****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.****\n\n以我的 [docker-compose.yml](https://github.com/twtrubiks/docker-tutorial/blob/master/docker-compose.yml) 為例，啟動順序雖然為 db -\u003e web，**但他不會等待 db 啟動完成後才啟動 web**，\n\n也就是說，還是有可能 **web 比 db 先啟動完成**，這樣就需要重啟 web service，否則會無法連上 db :sob:\n\n如果真的要控制啟動順序，請參考 [Controlling startup order](https://docs.docker.com/compose/startup-order/)。\n\n溫馨小提醒 3  :heart:\n\n`docker-compose.yml` 其實使用 `docker run` 也是可以完成的，例如這個範例中，如果使用\n\n`docker run` 來寫，會變成這樣。\n\n首先，為了讓容器彼此可以溝通，我們先建立一個網路 ( User-defined networks )，\n\n```cmd\ndocker network create my_network\n```\n\ndb 容器\n\n```cmd\ndocker run --name db -v pgdata:/var/lib/postgresql/data/ -p 5432:5432 --network=my_network -e POSTGRES_PASSWORD=password123 postgres\n```\n\n接下來先去 api 資料夾中 build 出 image\n\n```cmd\ndocker build --tag web_image .\n```\n\n`--tag , -t` , tag 這個 image 名稱為 web_image\n\n也可以是\n\n```cmd\ndocker build -t user/repo:tag .\n```\n\nweb 容器\n\n```cmd\ndocker 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\n```\n\n以上這樣，和 `docker-compose.yml`  其實是一樣的 :open_mouth:\n\n設定完了之後，接下來我們就可以啟動他了\n\n```cmd\ndocker-compose up\n```\n\n接下來你會看到類似的畫面\n\n![](https://i.imgur.com/GJWIgEP.png)\n\n![](https://i.imgur.com/dVRRyrM.png)\n\n假如你出現了類似的畫面\n\n![](https://i.imgur.com/cCEmVBq.png)\n\n代表 database 還在建立的時候，你的 web ( Django ) 就去連接他，\n\n所以導致連接不上，這時候我們可以先終止他 ( 按 Ctrl+C )\n\n接著在重新 `docker-compose up`\n\n我們成功啟動了 ( db 連線也正常 )\n\n![](https://i.imgur.com/iuCxLMY.png)\n\n:exclamation: [commit](https://github.com/twtrubiks/docker-tutorial/commit/398cb2fc375af8926cfe1eeabda33da018437897) 已經更新為自動 migrate :exclamation:\n\n但你仔細看上圖，你會發現他說你還沒 migrate\n\n接下來我們開啟另一個 cmd 進入 web 的 service，\n\n透過剛剛介紹的指令進入 service\n\n```cmd\ndocker ps\ndocker exec -it \u003cContainer ID\u003e bash\n```\n\n或是說也可以從 [Kitematic](https://kitematic.com/) 進入，\n\n進入後我們可以開始 migrate\n\n```cmd\npython manage.py makemigrations musics\npython manage.py migrate\n```\n\n![](https://i.imgur.com/zMmZKuL.png)\n\n順便在建立一個 superuser\n\n```cmd\npython manage.py createsuperuser\n```\n\n:exclamation: [commit](https://github.com/twtrubiks/docker-tutorial/commit/398cb2fc375af8926cfe1eeabda33da018437897) 已經更新為自動建立 superuser :exclamation:\n\n請參考 [docker-compose.yml](https://github.com/twtrubiks/docker-tutorial/blob/master/docker-compose.yml) 中的 environment ( 如下 ),\n\n`DJANGO_SUPERUSER_USERNAME` `DJANGO_SUPERUSER_PASSWORD` `DJANGO_SUPERUSER_EMAIL`\n\n接著我們可以試著使用 GUI 介紹連接 db，\n\n因為我們是用 [PostgreSQL](https://www.postgresql.org/)  ，可以透過 [pgadmin](https://www.pgadmin.org/) 連線\n\n![](https://i.imgur.com/2Hdt7wU.png)\n\n我們剛剛 migrate 的東西確實有存在\n\n![](https://i.imgur.com/PEUfGRy.png)\n\n我們不需要再重新啟動\n\n直接可以開開心心的去瀏覽 [http://127.0.0.1:8000/api/music/](http://127.0.0.1:8000/api/music/)\n\n大家一定會看到很熟悉的畫面\n\n![](https://i.imgur.com/pzqZbdz.png)\n\n接著依照自己剛剛設定的帳密登入進去即可\n\n![](https://i.imgur.com/l6RZXsQ.png)\n\n![](https://i.imgur.com/xeJtRJc.png)\n\n以上整個環境，都是在 Docker 中 :open_mouth:\n\n如果我們再 Ctrl+C 退出，重新啟動一次  `docker-compose up`\n\n這次就不會再和你說你沒有 migrate 了\n\n![](https://i.imgur.com/zIBkL3t.png)\n\n## 其他管理 Docker GUI 的工具\n\n* [Youtube Tutorial PART 3 - Docker 基本教學 - 透過 portainer 管理  Docker](https://youtu.be/VZjHmBcEcew)\n\n除了 [Kitematic](https://kitematic.com/) 之外，還有其他不錯的推薦給大家，\n\n這次要介紹的就是 [portainer](https://github.com/portainer/portainer) 功能強大又好用 :fire:\n\n其實如果去看看 [Kitematic](https://github.com/docker/kitematic) 以及 [portainer](https://github.com/portainer/portainer) 的 github，\n\n你會發現 [portainer](https://github.com/portainer/portainer) 感覺比較有在 maintenance :smile:\n\n而且我使用了 [portainer](https://github.com/portainer/portainer) 之後，真心大推 :smiley:\n\n安裝方法可參考 [https://portainer.io/install.html](https://portainer.io/install.html)\n\n```cmd\ndocker volume create portainer_data\ndocker run --name=portainer -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer\n```\n\n`-d` `-p` 在前面的 `docker run` 有介紹過代表的含意，`--name` 只是命名而已。\n\n`Note 1`: The -v /var/run/docker.sock:/var/run/docker.sock option is available on Linux environments only.\n\n`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.\n\n（ 建立起來之後，就依照 container 的操作即可 ）\n\n之後查看 [http://localhost:9000/](http://localhost:9000/) 就會看到下圖\n\n然後設定帳號、密碼\n\n![](https://i.imgur.com/exdMf2p.png)\n\n選 Local or Remote\n\n![](https://i.imgur.com/3mkNMxF.png)\n\n畫面真的不錯看，而且資訊也很豐富 :heart_eyes:\n\n![](https://i.imgur.com/ynoqTZT.png)\n\n相信我，你使用完他之後，你會默默的邊緣化 [Kitematic](https://kitematic.com/) :smirk:\n\n## 查看 port 佔用狀況\n\n這個推薦給大家，有時候會遇到 port 被佔用，用指令查比較方便\n\nLinux\n\n安裝 net-tools\n\n```cmd\nsudo apt install net-tools\n```\n\n查看誰佔用 80 port\n\n```cmd\nsudo netstat -lnp | grep -w ':80'\n```\n\n`-l`, `--listening` display listening server sockets.\n\n`-n`, `--numeric` don't resolve names.\n\n`-p`, `--programs` display PID/Program name for sockets.\n\n也可以使用 `lsof`\n\n```cmd\nsudo lsof -i :80\n```\n\n`-i` select IPv[46] files.\n\nWindows\n\n查看所有 port 的佔用狀況\n\n```cmd\nnetstat -ano\n```\n\n查看指定 port 的佔用狀況，例如現在想要查看 port 5432 佔用的狀況\n\n```cmd\nnetstat -aon|findstr \"5432\"\n```\n\n查看 PID 對應的 process\n\n```cmd\ntasklist|findstr \"2016\"\n```\n\n停止 PID 為 6093 的 process\n\n```cmd\ntaskkill /f /PID 6093\n```\n\n停止 vscode.exe process\n\n```cmd\ntaskkill /f /t /im vscode.exe\n```\n\nMAC\n\n將 port 為 8000 的 process 全部停止\n\n```cmd\nsudo lsof -t -i tcp:8000 | xargs kill -9\n```\n\n查看指定 port 的佔用狀況，例如現在想要查看 port 5432 佔用的狀況\n\n```cmd\nlsof -i tcp:5432\n```\n\n## 在 Linux 中自動啟動 docker\n\n[在 Linux 中自動啟動 docker](https://github.com/twtrubiks/docker-tutorial/tree/master/docker-auto-run-linux)\n\n## 如何清除 Docker container log\n\n[Youtube Tutorial - 如何清除 Docker container log](https://youtu.be/SiG0tmwhqqg)\n\ndocker 的 container log 都會在 `/var/lib/docker/containers` 裡面\n\n( 前提是你使用官方的安裝方法, [Youtube Tutorial - Ubuntu(Linux) 如何安裝 docker](https://youtu.be/eS_HMBC_RaA))\n\n如果你是使用 `snap` 安裝 docker, 路徑則會在 `/var/snap/docker/common/var-lib-docker/containers`.\n\n![alt tag](https://i.imgur.com/sK5k4Iw.png)\n\nlog 是一個 json 的檔案\n\n![alt tag](https://i.imgur.com/feSGmcm.png)\n\n如果你一直不去管他, log 就會越來越大 :scream:\n\n以下狀況這個 log 會被清除, 就是修改了 `docker-compose.yml` 或是\n\n你執行了 `docker-compose down`, 這些 logs 都會被清除 (因為 containers 重新建立).\n\n(`docker-compose stop` 不受影響, 因為只是暫停而已)\n\n建立大家可參考 [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)\n\n那你可能會問我, 如果我很長一段時間都不會修改 `docker-compose.yml` 以及執行\n\n`docker-compose down` 該怎麼辦 :sob: (因為 log 可能會長很快)\n\n這邊提供大家一個方法, 使用 linux 中的 truncate 指令(可參考 [ Linux 指令教學 - truncate](https://github.com/twtrubiks/linux-note#truncate))\n\n刪除全部 container 的 logs\n\n```cmd\ntruncate -s 0 /var/lib/docker/containers/*/*-json.log\n```\n\n但是有時候只希望針對(清除)某個 container 的 logs, 這時候就可以使用以下的指令\n\n```cmd\ntruncate -s 0 $(docker inspect --format='{{.LogPath}}' \u003ccontainer_name_or_id\u003e)\n```\n\n(`container_name_or_id` 請換上自己 container 的 id 或 name)\n\n其中的 `docker inspect --format='{{.LogPath}}' \u003ccontainer_name_or_id\u003e` 只是顯示路徑而已.\n\n![alt tag](https://i.imgur.com/TKCCdio.png)\n\n但還有一個更好的方法, 直接透過 docker 內的 JSON File logging driver.\n\n## JSON File logging driver\n\n[Youtube Tutorial - Docker 中的 JSON File logging driver(container log)](https://youtu.be/wb9bONgnFn4)\n\n在 docker 中 json-file driver 是默認的 default logging driver, 詳細可參考 [json-file](https://docs.docker.com/config/containers/logging/json-file/)\n\n所以我們可以透過這個設定限制 log 的大小,\n\n```yaml\nlogging:\n  driver: \"json-file\"\n  options:\n    max-file: \"1\"    # default 是 1\n    max-size: \"200m\" # default 是 -1, 也就是沒有限制\n```\n\n設定完之後重新啟動 docker-compose, 可以使用以下的指令查看是否生效\n\n```cmd\ndocker inspect --format '{{.HostConfig.LogConfig}}' CONTAINER\n```\n\n![alt tag](https://i.imgur.com/L6Z7bYX.png)\n\n這樣設定完之後, 就不用再擔心 container log 吃掉大量的容量了 :smile:\n\n## Health Check\n\n* [Youtube Tutorial - docker 教學 Health Check](https://youtu.be/QffnQZgvmwE)\n\n直接來看一個範例 [docker-compose.yml](https://github.com/twtrubiks/odoo-docker-tutorial/blob/15.0/docker-compose.yml)\n\n```yml\nversion: '3.5'\nservices:\n  web:\n    image: odoo:17.0\n    depends_on:\n      db:\n        condition: service_healthy\n    ports:\n      - \"8069:8069\"\n    healthcheck:\n      test: curl -fs http://localhost:8069/web/database/selector || exit 1\n      interval: 10s\n      timeout: 5s\n      retries: 5\n    volumes:\n      - odoo-web-data:/var/lib/odoo\n      - ./config:/etc/odoo\n\n  db:\n    image: postgres:16\n    environment:\n      - POSTGRES_DB=postgres\n      - POSTGRES_USER=odoo\n      - POSTGRES_PASSWORD=odoo\n      - PGDATA=/var/lib/postgresql/data/pgdata\n    healthcheck:\n      test: [\"CMD-SHELL\", \"pg_isready -U odoo\"]\n      interval: 10s\n      timeout: 5s\n      retries: 5\n    volumes:\n      - odoo-db-data:/var/lib/postgresql/data/pgdata\n\nvolumes:\n    odoo-web-data:\n    odoo-db-data:\n\n```\n\n當執行時, 你會發現多了一個 `health: starting` 如下圖,\n\n![alt tag](https://i.imgur.com/j4TBQ7M.png)\n\n當(每)過了 10 秒 (`interval: 10s`) 之後, 如果順利啟動會變成 `(healthy)` 如下圖,\n\n![alt tag](https://i.imgur.com/g8ysqZ0.png)\n\n當(每)過了 10 秒之後, 如果連續失敗很多次 (`retries: 5`),\n\n則會顯示 `(unhealthy)` 如下圖,\n\n![alt tag](https://i.imgur.com/zJhJf6u.png)\n\ndocker 的 Health Check 會回傳你數字,\n\n0 代表成功，container is healthy\n\n1 代表失敗，假設失敗超過指定次數(`retries: 5`), container is unhealthy\n\n至於 depends_on 底下的 `condition: service_healthy` 代表必須檢查通過,\n\n才會啟動, 可參考 [Control startup](https://docs.docker.com/compose/startup-order/#control-startup), 有以下三種,\n\n`service_started` 如果沒有特別指定, 就是這一種.\n\n`service_healthy`\n\n`service_completed_successfully`\n\n## 後記：\n\nDocker 算是我最近才開始接觸的，所以也算是新手，如果我有任何講錯的，歡迎和我說，我會再修改  :grinning:\n\nDocker 可以玩的真的很多，延伸參考\n\n* [實戰 Docker + Jenkins + Django + Postgres 📝](https://github.com/twtrubiks/docker-jenkins-django-tutorial) - 結合 Jenkins\n\n* [Docker + Django + Nginx + uWSGI + Postgres 基本教學 - 從無到有](https://github.com/twtrubiks/docker-django-nginx-uwsgi-postgres-tutorial)\n\n* [實戰 Docker + Django + Nginx + uWSGI + Postgres - Load Balance 📝](https://github.com/twtrubiks/docker-django-nginx-uwsgi-postgres-load-balance-tutorial)\n\n也可以再玩玩 **Docker Swarm** ( 分散式系統 ) :satisfied:\n\n* [Docker Swarm 基本教學 - 從無到有 Docker-Swarm-Beginners-Guide📝](https://github.com/twtrubiks/docker-swarm-tutorial)\n\n最後，希望大家在學習 Docker 的過程中，遇到不懂的，可以去找資料並且了解他，\n順便補足一些之前不足的知識。\n\n## 執行環境\n\n* Mac\n* Python 3.8.12\n* windows 10\n\n## Reference\n\n* [https://docs.docker.com/](https://docs.docker.com/)\n* [portainer](https://github.com/portainer/portainer)\n\n## Donation\n\n文章都是我自己研究內化後原創，如果有幫助到您，也想鼓勵我的話，歡迎請我喝一杯咖啡 :laughing:\n\n綠界科技ECPAY ( 不需註冊會員 )\n\n![alt tag](https://payment.ecpay.com.tw/Upload/QRCode/201906/QRCode_672351b8-5ab3-42dd-9c7c-c24c3e6a10a0.png)\n\n[贊助者付款](http://bit.ly/2F7Jrha)\n\n歐付寶 ( 需註冊會員 )\n\n![alt tag](https://i.imgur.com/LRct9xa.png)\n\n[贊助者付款](https://payment.opay.tw/Broadcaster/Donate/9E47FDEF85ABE383A0F5FC6A218606F8)\n\n## 贊助名單\n\n[贊助名單](https://github.com/twtrubiks/Thank-you-for-donate)\n\n## License\n\nMIT license\n","funding_links":[],"categories":["內容大綱 Table of Contents","Python"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftwtrubiks%2Fdocker-tutorial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftwtrubiks%2Fdocker-tutorial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftwtrubiks%2Fdocker-tutorial/lists"}