docker-tutorial
Docker 基本教學 - 從無到有 Docker-Beginners-Guide
教你用 Docker 建立 Django + PostgreSQL
- Youtube Tutorial PART 1 - Docker 基本教學 - 從無到有 Docker-Beginners-Guide
- 目錄 - Youtube Tutorial PART 2 - 用 Docker 實戰 Django 以及 Postgre
- 目錄 - Youtube Tutorial PART 3 - Docker 基本教學 - 透過 portainer 管理 Docker
- 目錄 - Youtube Tutorial PART 4 - Docker push image to Docker Hub 教學
其他說明
- Youtube Tutorial-Ubuntu(Linux) 如何安裝 docker
- 目錄 - Youtube Tutorial-docker-compose networks 說明
- 目錄 - Youtube Tutorial-docker-compose up/down 和 restart 的差異
- 目錄 - Youtube Tutorial-Linux 教學-開機自動啟動 docker / compose
- 目錄 - Youtube Tutorial - Docker 基本教學 - 在 docker compose 中善用 Environment variables
- 目錄 - Youtube Tutorial - 如何清除 Docker container log
- 目錄 - Youtube Tutorial - Docker 中的 JSON File logging driver(container log)
簡介
Containers as a Service ( CaaS ) - 容器如同服務
算是近幾年才開始紅的技術,蠻多公司都有使用 Docker,而且真的很方便,值得大家去了解一下 😄
如果你有環境上不統一的問題? 請用 Docker
如果你有每次建立環境都快抓狂的問題? 請用 Docker
如果你想要高效率、輕量、秒開的環境,請用 Docker
如果你不想搞死自己,請用 Docker 😄
如果你想潮到出水,請一定要用 Docker
什麼是 Docker
Docker 是一個開源專案,出現於 2013 年初,最初是 Dotcloud 公司內部的 Side-Project。
它基於 Google 公司推出的 Go 語言實作。( Dotcloud 公司後來改名為 Docker )
技術原理我們這邊就不提了,簡單提一下他的好處。
我們先來看看官網的說明
Comparing Containers and Virtual Machines ( 傳統的虛擬化 )
從這張圖可以看出 Containers 並沒有 OS ,容量自然就小,而且啟動速度神快
詳細可參考 https://www.docker.com/what-container
Virtual Machines 是什麼?
類似 https://www.virtualbox.org/,我們可能用它裝裝看其他作業系統,例如說
我是 MAC,但我想玩 Windows,我就會在 MAC 中裝 VM 並且灌 Windows 系統。
一個表格了解 Docker 有多棒
Feauture | Containers | Virtual Machines ( 傳統的虛擬化 ) |
---|---|---|
啟動 | 秒開 | 最快也要分鐘 |
容量 | MB | GB |
效能 | 快 | 慢 |
支援數量 | 非常多 Containers | 10多個就很了不起了 |
複製相同環境 | 快 | 超慢 |
不理解
我們來看一張圖,包準你懂
圖的來源 https://blog.jayway.com/2015/03/21/a-not-very-short-introduction-to-docker/
為什麼要使用 Docker
潮~ 不解釋
更有效率的利用資源
比起像是 https://www.virtualbox.org/,Docker 的利用率更高,我們可以設定更多
的 Containers ,而且啟動速度飛快!!😳
統一環境
相信大家都有每次搞電腦的環境都搞的很煩的經驗
假設今天公司來了個新同事,就又要幫他建立一次環境
不然就是,我的電腦 run 起來正常阿~ 你的怎麼不行,是不是 xxx 版本的關係阿
相信大家多多少少都遇過上面這些事情,我們可以透過 Docker 來解決這些問題,
保持大家環境一致,而且要建立的時候也很快
對於 DevOps 的好處
對於 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://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/#images-and-layers
Registry
可以把它想成類似 GitHub,裡面存放了非常多的 Image ,可在 Docker Hub 中查看。
更詳細的我這邊就不再解釋惹,留給大家做作功課😛
安裝
Windows
請先到 Docker 官網
https://www.docker.com/docker-windows
下載 stable 版本
接下來就是無腦安裝,安裝完後他會叫你登出電腦,點下去後就會幫你登出電腦
接著如果你的電腦沒有啟用 Hyper-V ,他會叫你重啟電腦 (一樣,點下去就對惹)
( 更多可 Hyper-V 介紹請參考 https://docs.microsoft.com/zh-tw/virtualization/hyper-v-on-windows/about/ )
重新開機後,你就會發現可愛的 Docker 在右下角蹦出來惹
我們可以再用 cmd 確認一下是否有成功安裝
docker --version
docker-compose --version
記得再設定一個東西 Shared Drives
裝完了之後,建議大家再多裝一個 Kitematic,他是 GUI 介面的,方便你使用 Docker,
( 後面會再介紹一個更贊的 GUI 介面 portainer
我知道打指令很潮,但還是建議裝一下。
直接對著你的 Docker 圖示右鍵,就可以看到 Kitematic
下載回來直接解壓縮雙點擊即可使用
MAC
MAC 我本身也有,但因為更早之前就裝了,步驟就沒記錄了,基本上大同小異
https://www.docker.com/docker-mac
Linux
Youtube Tutorial-Ubuntu(Linux) 如何安裝 docker
這裡使用 Ubuntu 當作範例,
雖然在 ubuntu 中有 snap
可以非常快速的安裝 docker,
但在這邊我們不使用 snap
的方法安裝
請參考官方文件步驟安裝,
Get Docker Engine - Community for Ubuntu
Get Docker Engine - Community for Ubuntu
安裝後步驟 (optional
Post-installation steps for Linux
docker-compose 的安裝
系統資源分配問題,
假如你是使用 windows 或是 mac 的 docker,
你會有一個界面可以設定你要分多少的 cpu 以及 ram 給你的 docker,
通常會在 Preferences -> Advanced, 有 GUI 界面,
但如果是使用 linux, 就不會有這個界面, 因為在 Linux 中,
會自動依照系統的資源進行分配.
指令介紹
接著介紹一些 Docker 的指令,
Docker 的指令真的很多,這裡就介紹我比較常用的或是實用的指令
查看目前 images
docker images
建立 image
docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
詳細的參數可參考 https://docs.docker.com/engine/reference/commandline/create/
範例 ( 建立一個名稱為 busybox 的 image )
docker create -it --name busybox busybox
刪除 Image
docker rmi [OPTIONS] IMAGE [IMAGE...]
查看目前運行的 container
docker ps
查看目前全部的 container( 包含停止狀態的 container )
docker ps -a
新建並啟動 Container
docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]
舉個例子
docker run -d -p 80:80 --name my_image nginx
-d
代表在 Detached( 背景 )執行,如不加 -d
,預設會 foreground ( 前景 ) 執行
-p
代表將本機的 80 port 的所有流量轉發到 container 中的 80 port
--name
設定 container 的名稱
在舉一個例子
docker run -it --rm busybox
--rm
代表當 exit container 時,會自動移除 container。 ( incompatible with -d )
更詳細的可參考 https://docs.docker.com/engine/reference/run/
啟動 Container
docker start [OPTIONS] CONTAINER [CONTAINER...]
如果想讓他在前景跑順便觀看輸出 , 可以使用以下指令
docker start -a [OPTIONS] CONTAINER [CONTAINER...]
--attach
或 -a
代表 Attach STDOUT/STDERR and forward signals.
更詳細的可參考 https://docs.docker.com/engine/reference/commandline/start/
( container ID 寫幾個就可以了,和 Git 的概念是一樣的 ,
不了解 Git 可以參考 Git-Tutorials GIT基本使用教學 )
停止 Container
docker stop [OPTIONS] CONTAINER [CONTAINER...]
重新啟動 Container
docker restart [OPTIONS] CONTAINER [CONTAINER...]
删除 Container
docker rm [OPTIONS] CONTAINER [CONTAINER...]
--volumes , -v
加上這個參數,會移除掉連接到這個 container 的 volume。
可參考 https://docs.docker.com/engine/reference/commandline/rm/
進入 Container
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
docker exec -it <Container ID> bash
使用 root 使用者進入
docker exec -u 0 -it <Container ID> bash
docker exec -u root -it <Container ID> bash
打指令比較潮,或是說你也可以透過 Kitematic 進入。
當我們進入了 Container 之後,有時候想看一下裡面 Linux 的版本,
這時候可以使用以下指令查看
cat /etc/os-release
查看 Container 詳細資料
docker inspect [OPTIONS] NAME|ID [NAME|ID...]
查看 log
docker logs [OPTIONS] CONTAINER
--follow
, -f
, Follow log output
更詳細的可參考 https://docs.docker.com/engine/reference/commandline/logs/
從最後 100 行開始追蹤,
docker logs -f --tail 100 CONTAINER
顯示容器資源 ( CPU , I/O ...... )
docker stats [OPTIONS] [CONTAINER...]
停止指定的 CONTAINER 中全部的 processes
docker pause CONTAINER [CONTAINER...]
執行 docker pause
之後,可以試這用 docker ps
查看,會發現
還是有在執行,這裡拿 docker stop
比較一下,差異如下。
docker stop
: process 級別。
docker pause
: container 級別。
恢復指定暫停的 CONTAINER 中全部的 processes
docker unpause CONTAINER [CONTAINER...]
docker tag
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
範例
docker tag 0e5574283393 twtrubiks/nginx:version1.0
更多可參考 https://docs.docker.com/engine/reference/commandline/tag/
儲存 (備份) image 成 tar 檔案
[OPTIONS] IMAGE [IMAGE...]
範例
docker save busybox > busybox.tar
或
docker save --output busybox.tar busybox
或 ( 也可以一次備份多個 )
docker save -o images.tar postgres:9.6 busybox
更多可參考 https://docs.docker.com/engine/reference/commandline/save/
載入 image
docker load [OPTIONS]
範例
docker load < busybox.tar
或
docker load -i busybox.tar
更多可參考 https://docs.docker.com/engine/reference/commandline/load/
顯示 image 的 history,查詢 image 的每一層
docker history [OPTIONS] IMAGE
在 docker 中,一層一層的概念很重要。
更多可參考 https://docs.docker.com/engine/reference/commandline/history/
剛剛有教大家如何儲存 (備份) images, 載入 images,
還有另外一種是 export 和 import containers,
docker export container 請參考 https://docs.docker.com/engine/reference/commandline/export/。
docker import container 請參考 https://docs.docker.com/engine/reference/commandline/import/。
其他指令
刪除所有 dangling images
docker image prune
移除全部 unused images (不只 dangling images)
docker image prune -a
更多資訊可參考 image_prune
停止所有正在運行的 Container
docker container stop $(docker ps -q)
更多資訊可參考 container_stop
移除全部停止的 containers
docker container prune
更多資訊可參考 container_prune
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://docs.docker.com/engine/admin/volumes/volumes/
查看目前的 volume
docker volume ls [OPTIONS]
創造一個 volume
docker volume create [OPTIONS] [VOLUME]
刪除一個 volume
docker volume rm [OPTIONS] VOLUME [VOLUME...]
查看 volume 詳細資料
docker volume inspect [OPTIONS] VOLUME [VOLUME...]
移除全部未使用的 volume
docker volume prune [OPTIONS]
也可以建立 readonly 的 volumes (容器內 readonly)
docker-compose.yml
方法如下,
version: '3.5'
services:
nginx:
image: nginx
ports:
- "80:80"
volumes:
- "nfs-data:/data:ro,z"
volumes:
nfs-data:
如果要可讀寫, 就設定 rw
.
volumes 在容器內的確不能寫 (只能讀)
使用以下的指令查看 Mounts, 觀察它的 Mode
docker inspect <container ID>
也可以建立 NFS volumes,
docker-compose.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"
可以用以下指令查看設定
docker volume ls
docker inspect <volume name>
NFS 相關文章可參考 linux-nfs-server - 如何在 ubuntu 啟用 NFS Server
network
建議大家花點時間研究 docker 中的 network,會蠻有幫助的
查看目前 docker 的網路清單
docker network ls [OPTIONS]
詳細可參考 https://docs.docker.com/engine/userguide/networking/
docker 中的網路主要有三種 Bridge、Host、None,預設皆為 Bridge 模式。
指定 network 範例 ( 指定使用 host
網路 )
docker run -it --name busybox --rm --network=host busybox
建立 network
docker network create [OPTIONS] NETWORK
移除 network
docker network rm NETWORK [NETWORK...]
移除全部未使用的 network
docker network prune [OPTIONS]
查看 network 詳細資料
docker network inspect [OPTIONS] NETWORK [NETWORK...]
將 container 連接 network
docker network connect [OPTIONS] NETWORK CONTAINER
更多詳細資料可參考 https://docs.docker.com/engine/reference/commandline/network_connect/
Disconnect container network
docker network disconnect [OPTIONS] NETWORK CONTAINER
更多詳細資料可參考 https://docs.docker.com/engine/reference/commandline/network_disconnect/
User-defined networks
這個方法是官方推薦的
透過內建的 DNS 伺服器,可以直接使用容器名稱,就可解析出 IP,不需要再使用 IP 讓容器互相
溝通,我們只需要知道容器的名稱就可以連接到容器。
更多詳細資料可參考 https://docs.docker.com/engine/userguide/networking/#user-defined-networks
docker-compose
再來要介紹 docker-compose,可參考官網 https://docs.docker.com/compose/
Compose 是定義和執行多 Container 管理的工具,不懂我在說什麼
試著想想看,通常一個 Web 都還會有 DB,甚至可能還有 Redis 或 Celery,
所以說我們需要有 Compose 來管理這些,透過 docker-compose.yml
( YML 格式 ) 文件。
docker-compose.yml
的寫法可參考 https://docs.docker.com/compose/compose-file/
也可以直接參考官網範例 https://docs.docker.com/compose/compose-file/#compose-file-structure-and-examples
Compose 的 Command-line 很多和 Docker 都是類似的,
可參考 https://docs.docker.com/glossary/?term=compose
查看目前 Container
docker-compose ps
加上 -q
的話,只顯示 id
docker-compose ps -q
啟動 Service 的 Container
docker-compose start [SERVICE...]
停止 Service 的 Container ( 不會刪除 Container )
docker-compose stop [options] [SERVICE...]
重啟 Service 的 Container
docker-compose restart [options] [SERVICE...]
Builds, (re)creates, starts, and attaches to containers for a service
docker-compose up [options] [--scale SERVICE=NUM...] [SERVICE...]
加個 -d
,會在背景啟動,一般建議正式環境下使用。
docker-compose up -d
up
這個功能很強大,建議可以參考 https://docs.docker.com/compose/reference/up/
如果你希望每次都重新 build image,可以加上
--build
( Build images before starting containers. )
docker-compose up -d --build
docker-compose down
docker-compose down [options]
down
這個功能也建議可以參考 https://docs.docker.com/compose/reference/down/
舉個例子
docker-compose down -v
加個 -v
就會順便幫你把 volume 移除( 移除你在 docker-compose.yml
裡面設定的 volume )
在指定的 Service 中執行一個指令
docker-compose run [options] [-v VOLUME...] [-p PORT...] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...]
[ARGS...]
舉個例子
docker-compose run web bash
在 web Service 中執行 bash
指令
可參考 https://docs.docker.com/compose/reference/run/
觀看 Service logs
docker-compose logs [options] [SERVICE...]
檢查 docker-compose.yml
格式是否正確
docker-compose config
如下指令,和 docker exec
一樣
docker-compose exec
範例 ( 進入 web 這個 service 的 bash )
docker-compose exec web bash
顯示被使用到的 container 中的 images 清單
docker-compose images
移除 service containers
docker-compose rm
Pushes images 到 docker hub
docker-compose push
目前這個指令其實我也搞不太懂,可參考 docker/compose#4283
官網也解釋的沒有很清楚 https://docs.docker.com/compose/reference/push/
docker-compose up/down 和 restart 的差異
先來談 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, 如果你對 docker-compose.yml
修改, 然後使用這個指令, 是不會生效的,
但是, 如果你是改 code (可能是 python code), 那這個指令是有效的.
docker-compose networks
這邊多補充 docker-compose networks 的觀念,因為剛好最近有用到
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
...
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 來示範,
docker run -p 80 \
-e "[email protected]" \
-e "PGADMIN_DEFAULT_PASSWORD=SuperSecret" \
-d dpage/pgadmin4
如果我們執行兩次以上指令,你會發現本機被分配到兩個隨機的 ports (如下圖),
本機被隨機分配到 32768 以及 32769 port,
這邊不管我們怎麼設定 ports,這些 ports 都會暴露給本機 (HOST) 以及其他 containers,這點很重要❗❗
也就是說,如果本機 5001 ports 被使用了,其他的 containers 就無法使用 5001 ports,
可能要改成5002 ports 之類的。
expoese
...
expose:
- "4000"
- "6000"
...
expose 是將 port 暴露給其他容器。
expose 和 ports 最大的差別就是在 expose 不會暴露 port 給本機(HOST),
所以 本機(HOST)絕對無法被訪問,但 containers 內可以被訪問,
所以說如果今天你的容器想要在 本機(HOST) 被訪問,一定要使用 ports 方式。
ports 和 expose 差異
簡單說,就是 ports 可以被 本機(HOST) 和 containers 訪問 ; 而
expose 是本機(HOST) 無法被訪問,只有在 containers 中可以被訪問。
Docker Registry
可以把它想成是一個類似 github 的地方,只不過裡面變成是存 docker 的東西,當然,
也可以自己架,但會有一些額外的成本,像是網路,維護等等,這部分就要自己衡量了
接下來教大家如何將 image push 到 Docker Registry 😃
首先,先登入 Docker Registry ( 註冊流程很簡單,我就跳過了 )
docker login
舉個例子,先 run 一個 busybox 的容器
docker run -it busybox
接著在裡面新增一筆資料
echo 'text' > data.txt
然後打開另一個 terminal ,使用 docker ps
查看目前容器的 id
再來使用像 git 一樣的方式 commit
docker commit
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
可參考 https://docs.docker.com/engine/reference/commandline/commit/
docker commit -m "test" 4fb4ef51e917 twtrubiks/my_busybox
-m
commit message ,和 git 一樣。
twtrubiks/my_busybox 則為我們定義的 REPOSITORY。
如果需要 tag , 也可以增加
docker commit -m "test" 4fb4ef51e917 twtrubiks/my_busybox:v1
( 如果沒定義 tag , 則會顯示 latest )
這時候可以用 docker images
查看
最後 push
docker push twtrubiks/my_busybox
docker 是一層一層的概念,他只會 push 自己新增的幾層上去而已,
所以不用擔心整個 image 很大,要上傳很久
最後可以到 https://hub.docker.com/ 確認是否有成功
用 Docker 實戰 Django 以及 Postgre
上面介紹了那麼多,來實戰一下是必須的
我們使用 Django-REST-framework 基本教學 - 從無到有 DRF-Beginners-Guide 來當範例
有幾個地方必須修改一下,
將 settings.py
裡面的 db 連線改成 PostgreSQL
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
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/
docker-compose.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
溫馨小提醒 1
可能有人會問為什麼我是使用 0.0.0.0
,而不是使用 127.0.0.1
python manage.py runserver 0.0.0.0:8000
127.0.0.1
,並不代表真正的 本機,我們經常認為他是本機是因為我們電腦的 host
預設都幫你設定好了😏
詳細的 host
設定教學可參考 hosts-設定檔 以及 查詢內網 ip,
0.0.0.0
才是真正的代表,當下 ( 本 ) 網路中的本機 ✏️
如果大家想更深入的了解,可 google 再進一步的了解 127.0.0.1
以及 0.0.0.0
的差異
溫馨小提醒 2
這邊要特別提一下 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 為例,啟動順序雖然為 db -> web,但他不會等待 db 啟動完成後才啟動 web,
也就是說,還是有可能 web 比 db 先啟動完成,這樣就需要重啟 web service,否則會無法連上 db
如果真的要控制啟動順序,請參考 Controlling startup order。
溫馨小提醒 3
docker-compose.yml
其實使用 docker run
也是可以完成的,例如這個範例中,如果使用
docker run
來寫,會變成這樣。
首先,為了讓容器彼此可以溝通,我們先建立一個網路 ( User-defined networks ),
docker network create my_network
db 容器
docker run --name db -v pgdata:/var/lib/postgresql/data/ -p 5432:5432 --network=my_network -e POSTGRES_PASSWORD=password123 postgres
接下來先去 api 資料夾中 build 出 image
docker build --tag web_image .
--tag , -t
, tag 這個 image 名稱為 web_image
也可以是
docker build -t user/repo:tag .
web 容器
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
其實是一樣的😮
設定完了之後,接下來我們就可以啟動他了
docker-compose up
接下來你會看到類似的畫面
假如你出現了類似的畫面
代表 database 還在建立的時候,你的 web ( Django ) 就去連接他,
所以導致連接不上,這時候我們可以先終止他 ( 按 Ctrl+C )
接著在重新 docker-compose up
我們成功啟動了 ( db 連線也正常 )
但你仔細看上圖,你會發現他說你還沒 migrate
接下來我們開啟另一個 cmd 進入 web 的 service,
透過剛剛介紹的指令進入 service
docker ps
docker exec -it <Container ID> bash
或是說也可以從 Kitematic 進入,
進入後我們可以開始 migrate
python manage.py makemigrations musics
python manage.py migrate
順便在建立一個 superuser
python manage.py createsuperuser
接著我們可以試著使用 GUI 介紹連接 db,
因為我們是用 PostgreSQL ,可以透過 pgadmin 連線
我們剛剛 migrate 的東西確實有存在
我們不需要再重新啟動
直接可以開開心心的去瀏覽 http://127.0.0.1:8000/api/music/
大家一定會看到很熟悉的畫面
接著依照自己剛剛設定的帳密登入進去即可
以上整個環境,都是在 Docker 中 😮
如果我們再 Ctrl+C 退出,重新啟動一次 docker-compose up
這次就不會再和你說你沒有 migrate 了
其他管理 Docker GUI 的工具
除了 Kitematic 之外,還有其他不錯的推薦給大家,
這次要介紹的就是 portainer 功能強大又好用
其實如果去看看 Kitematic 以及 portainer 的 github,
你會發現 portainer 感覺比較有在 maintenance
而且我使用了 portainer 之後,真心大推
安裝方法可參考 https://portainer.io/install.html
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/ 就會看到下圖
然後設定帳號、密碼
選 Local or Remote
畫面真的不錯看,而且資訊也很豐富
相信我,你使用完他之後,你會默默的邊緣化 Kitematic
查看 port 佔用狀況
這個推薦給大家,有時候會遇到 port 被佔用,用指令查比較方便
Windows
查看所有 port 的佔用狀況
netstat -ano
查看指定 port 的佔用狀況,例如現在想要查看 port 5432 佔用的狀況
netstat -aon|findstr "5432"
查看 PID 對應的 process
tasklist|findstr "2016"
停止 PID 為 6093 的 process
taskkill /f /PID 6093
停止 vscode.exe process
taskkill /f /t /im vscode.exe
MAC
將 port 為 8000 的 process 全部停止
sudo lsof -t -i tcp:8000 | xargs kill -9
查看指定 port 的佔用狀況,例如現在想要查看 port 5432 佔用的狀況
lsof -i tcp:5432
在 Linux 中自動啟動 docker
如何清除 Docker container log
Youtube Tutorial - 如何清除 Docker container log
docker 的 container log 都會在 /var/lib/docker/containers
裡面
( 前提是你使用官方的安裝方法, Youtube Tutorial-Ubuntu(Linux) 如何安裝 docker)
如果你是使用 snap
安裝 docker, 路徑則會在 /var/snap/docker/common/var-lib-docker/containers
.
log 是一個 json 的檔案
如果你一直不去管他, log 就會越來越大
以下狀況這個 log 會被清除, 就是修改了 docker-compose.yml
或是
你執行了 docker-compose down
, 這些 logs 都會被清除 (因為 containers 重新建立).
(docker-compose stop
不受影響, 因為只是暫停而已)
建立大家可參考 docker-compose up/down 和 restart 的差異
那你可能會問我, 如果我很長一段時間都不會修改 docker-compose.yml
以及執行
docker-compose down
該怎麼辦😭 (因為 log 可能會長很快)
這邊提供大家一個方法, 使用 linux 中的 truncate 指令(可參考 Linux 指令教學 - truncate)
刪除全部 container 的 logs
truncate -s 0 /var/lib/docker/containers/*/*-json.log
但是有時候只希望針對(清除)某個 container 的 logs, 這時候就可以使用以下的指令
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>
只是顯示路徑而已.
但還有一個更好的方法, 直接透過 docker 內的 JSON File logging driver.
JSON File logging driver
Youtube Tutorial - Docker 中的 JSON File logging driver(container log)
在 docker 中 json-file driver 是默認的 default logging driver, 詳細可參考 json-file
所以我們可以透過這個設定限制 log 的大小,
logging:
driver: "json-file"
options:
max-file: "1" # default 是 1
max-size: "200m" # default 是 -1, 也就是沒有限制
設定完之後重新啟動 docker-compose, 可以使用以下的指令查看是否生效
docker inspect --format '{{.HostConfig.LogConfig}}' CONTAINER
這樣設定完之後, 就不用再擔心 container log 吃掉大量的容量了
後記:
Docker 算是我最近才開始接觸的,所以也算是新手,如果我有任何講錯的,歡迎和我說,我會再修改
Docker 可以玩的真的很多,延伸參考
-
實戰 Docker + Jenkins + Django + Postgres
📝 - 結合 Jenkins -
實戰 Docker + Django + Nginx + uWSGI + Postgres - Load Balance
📝
也可以再玩玩 Docker Swarm ( 分散式系統 )
最後,希望大家在學習 Docker 的過程中,遇到不懂的,可以去找資料並且了解他, 順便補足一些之前不足的知識。
執行環境
- Mac
- Python 3.8.12
- windows 10
Reference
Donation
文章都是我自己研究內化後原創,如果有幫助到您,也想鼓勵我的話,歡迎請我喝一杯咖啡
綠界科技ECPAY ( 不需註冊會員 )
歐付寶 ( 需註冊會員 )
贊助名單
License
MIT license