Learning Objectives
- 比較 Debian、Ubuntu、Fedora、openSUSE、Alpine 等基底映像檔的定位,挑選合適的作業系統映像檔
- 用 python 映像檔執行一行程式、進入 Python 互動環境,並用 --rm 讓容器用完自動刪除
- 用 -p 對應埠號啟動 Jupyter Notebook,從 logs 取得登入用的 token
- 用 -e 設定環境變數啟動 MySQL;容器啟動後馬上結束時,會用 ls -a 與 logs 找出原因
不用安裝,直接拿來用
上一課學會從 Docker Hub 搜尋與下載映像檔。這一課實際挑幾個常用的官方映像檔來用:
- 想試試另一套 Linux?跑一個那套系統的容器就好,不用重灌電腦
- 想用 Python 3.12,但電腦裝的是別的版本?用
python:3.12容器 - 想要 Jupyter Notebook 或 MySQL?一行指令就啟動,用完刪掉也不會在電腦留下一堆設定
挑映像檔的基本步驟:
- 先找官方映像檔(只有倉庫名稱的那種)
- 到 Docker Hub 網頁看說明:有哪些標籤、要設定哪些環境變數、資料放在哪裡
- 選一個明確的版本標籤,不要只用
latest
作業系統映像檔怎麼挑
投影片示範了好幾套 Linux 發行版的映像檔。它們的用法幾乎一樣(docker container run -it … /bin/bash),
差別在於定位與套件管理工具:
| 映像檔 | 背景與定位 | 套件管理 | 適合 |
|---|---|---|---|
debian |
社群維護、穩定保守;很多官方映像檔(例如 python)預設就建立在 Debian 上 |
apt |
一般用途的穩定基底 |
ubuntu |
以 Debian 為基礎;每年 4 月與 10 月各發行一版,每兩年 4 月推出 LTS 長期支援版(如 24.04) | apt |
初學者首選,教學與網路資源最多 |
fedora |
Red Hat 贊助的社群發行版,盡早採用新技術;每個版本支援期較短,大約一年多;Red Hat Enterprise Linux(RHEL)以它為開發基礎 | dnf |
想試新版工具 |
opensuse/leap |
SUSE 主導的社群發行版;Leap 是穩定版,另有持續更新的 Tumbleweed | zypper |
熟悉 SUSE 環境的人 |
alpine |
非常小(大約只有幾 MB),使用 musl libc 與 BusyBox | apk |
追求小體積;但有些需要編譯的套件會比較麻煩 |
CentOS 呢? 投影片用的 CentOS Linux 已經停止維護,不再有安全更新,本課程改用 Ubuntu 示範。 如果工作上需要與 RHEL 相容的環境,可以查看 Rocky Linux、AlmaLinux 等發行版的官方說明。
進到任何一個作業系統容器之後,可以用這些指令探索環境:
| 指令 | 看什麼 |
|---|---|
cat /etc/os-release |
發行版名稱與版本 |
hostname、cat /etc/hosts |
主機名稱(預設是容器 ID 的前 12 碼)與 IP 對照 |
uname -r |
核心版本:你會發現是主機的核心,因為容器共用主機核心(第 01 課) |
nproc、free -h、df -h / |
CPU 數、記憶體、磁碟空間 |
ps -elf |
執行中的程序:通常只有你的 bash,容器不是一整台開機的電腦 |
裝軟體時依發行版使用不同的工具,例如 Ubuntu 要先 apt update 再 apt install -y 套件,
Fedora 用 dnf install、openSUSE 用 zypper install、Alpine 用 apk add。
在容器裡裝的軟體只存在這個容器,刪掉容器就沒了;要固定下來,第 07 課會教你寫成 Dockerfile。
用 Python 映像檔
官方的 python 映像檔已經裝好 Python 與 pip,有三種常見用法:
1. 執行一行程式,跑完就刪掉容器
docker container run --rm python:3.12 python -c "print(6*7)"
--rm 表示容器結束後自動刪除,適合這種跑一次就好的工作,不會在 ls -a 留下一堆停止的容器。
2. 進入 Python 互動環境
docker container run -it --rm python:3.12
python 映像檔預設執行的程式就是 python3,所以加上 -it 會直接出現 >>> 提示字元,輸入 exit() 離開。
3. 進入 bash,再執行自己的程式
docker container run -it --name python3_env python:3.12 /bin/bash
docker container cp hello.py python3_env:/root/ # 在主機上執行:把檔案複製進容器
docker container cp 可以在主機與容器之間複製檔案(容器停止時也可以)。
標籤的變化:同一個版本通常有幾種基底可選,例如 python:3.12(Debian,最完整)、
python:3.12-slim(精簡版 Debian,比較小)、python:3.12-alpine(Alpine,最小)。不確定時先用沒有後綴的版本。
其他程式語言也有對應的官方映像檔,例如 node、golang;Java 可以用 eclipse-temurin
(舊投影片的 openjdk 映像檔已經停止更新)。
服務式容器:Jupyter Notebook
Jupyter 是一個網頁介面的服務:容器在背景執行,你用瀏覽器連進去。
docker container run -d --name notebook -p 8888:8888 quay.io/jupyter/base-notebook
| 部分 | 意思 |
|---|---|
-d |
在背景執行(服務式容器,第 03 課) |
-p 8888:8888 |
把主機的 8888 埠對應到容器的 8888 埠;寫法是 主機埠:容器埠(第 09 課會詳細說明) |
quay.io/jupyter/base-notebook |
Jupyter 官方團隊維護的映像檔,放在 Quay registry |
舊投影片用的
jupyter/datascience-notebook是 Docker Hub 上的名稱;Jupyter 團隊已改在quay.io/jupyter/…發布新版, Docker Hub 上的jupyter/…不再更新。除了base-notebook,還有scipy-notebook、datascience-notebook、pyspark-notebook等不同套件組合。
登入要 token:Jupyter 啟動時會產生一組 token,寫在容器的輸出裡。用 docker container logs notebook 找到
http://127.0.0.1:8888/lab?token=… 這一行,整串貼到瀏覽器就能進去。
- 主機的 8888 已經被別的程式占用時,改成
-p 9999:8888,瀏覽器改開http://127.0.0.1:9999 - 不加
-d在前景執行時,按Ctrl+C會結束 Jupyter,容器也跟著停止 - 之後可以
docker container stop notebook、docker container start notebook;重新啟動後,用logs再查一次網址 - 在容器裡存的筆記本,刪掉容器就不見了;第 06 課會教你把資料存到容器外面
環境變數:MySQL 為什麼一啟動就結束
很多映像檔需要你在啟動時提供設定,方法是用 -e 傳入環境變數:
docker container run -d --name db mysql:8.4 # 沒給密碼
docker container run -d --name db -e MYSQL_ROOT_PASSWORD=你的密碼 mysql:8.4 # 正確
第一行會印出容器 ID,看起來成功了,但 docker container ls 找不到它。這時的除錯步驟:
docker container ls -a:STATUS 是Exited (1),結束碼不是 0,代表程式出錯結束docker container logs db:看容器最後說了什麼
[ERROR] [Entrypoint]: Database is uninitialized and password option is not specified
You need to specify one of the following as an environment variable:
- MYSQL_ROOT_PASSWORD
- MYSQL_ALLOW_EMPTY_PASSWORD
- MYSQL_RANDOM_ROOT_PASSWORD
錯誤訊息直接告訴你缺什麼。先 docker container rm db 移除失敗的容器(名稱必須唯一),再加上 -e 重新啟動。
容器啟動後馬上結束,第一件事就是看 logs。 這個習慣對所有服務式容器都適用。
MySQL 映像檔常用的環境變數(完整清單在 Docker Hub 的 mysql 頁面):
| 環境變數 | 作用 |
|---|---|
MYSQL_ROOT_PASSWORD |
設定 root 密碼(三選一的必填) |
MYSQL_RANDOM_ROOT_PASSWORD |
隨機產生 root 密碼,印在 logs 裡 |
MYSQL_DATABASE |
啟動時順便建立一個資料庫 |
MYSQL_USER、MYSQL_PASSWORD |
建立一個一般使用者 |
資料庫啟動後,可以在容器裡直接開 mysql 用戶端連線:
docker container exec -it db mysql -uroot -p
MariaDB 是從 MySQL 分支出來、協定相容的資料庫,用法幾乎相同:docker container run -d --name mariadb_server -e MARIADB_ROOT_PASSWORD=你的密碼 mariadb。
密碼寫在指令裡,會留在終端機的歷史紀錄,在
docker container inspect裡也看得到。練習可以這樣做; 正式服務請改用設定檔或專門保管密碼的機制,而且不要用root、123456這種密碼。
在真的終端機跑 Python 與 Jupyter
在已經安裝 Docker 的電腦(第 02 課)打開終端機跟著做。第一次執行時會先下載映像檔,需要等一下。版本號碼與容器 ID 是示意,你看到的會不同。導覽中 root@…:/# 與 >>> 開頭的行是在容器裡輸入的。
-
1
用 python:3.12 執行一行程式
platform.system()印出Linux:即使你的電腦是 Windows 或 macOS,容器裡也是 Linux。加了--rm,所以接著用ls -a找不到這個容器。 -
2
進入 Python 互動環境
加上
-it、不指定要執行的程式,就會進入映像檔預設的python3。輸入exit()離開,容器結束並自動刪除。 -
3
進入 bash,把自己的程式複製進去執行
先在主機的目前資料夾建立
hello.py,內容是print("Hello from a container!")。建立名為python3_env的容器並進入 bash 看看環境,離開後用docker container cp把檔案複製進去,再用start -ai重新啟動並接回 bash 執行它。uname -r顯示的是主機的核心版本。 -
4
在背景啟動 Jupyter Notebook
映像檔比較大,第一次下載要等一陣子。
-d只會印出容器 ID,接著用ls確認它在執行,PORTS 欄位會顯示埠號對應。 -
5
從 logs 找到含 token 的網址
把
http://127.0.0.1:8888/lab?token=…整串複製到瀏覽器,就會進入 JupyterLab。token 每次啟動可能不同,忘記時再查一次 logs 就好。 -
6
停止與清理
用完先
stop;之後還要用就start,不需要了就rm。python3_env也一起移除。注意:移除 notebook 容器後,存在容器裡的筆記本也會一起消失(第 06 課會解決這個問題)。
想一想:挑映像檔與 Python 映像檔
只想用 Python 3.12 跑一次 print(6*7),又不想留下停止的容器,應該怎麼寫?
在 ubuntu:24.04 容器裡執行 uname -r,顯示的是誰的核心版本?
投影片用 CentOS 示範,本課程改用 Ubuntu 的原因是?
想一想:服務式容器的除錯
docker container run -d --name db mysql:8.4 印出了容器 ID,但 docker container ls 看不到 db。下一步最好做什麼?
啟動 Jupyter 時寫 -p 9999:8888,瀏覽器要開哪個網址?
-e MYSQL_ROOT_PASSWORD=… 的 -e 是做什麼用的?
重點精華回顧
- 挑映像檔:先找官方映像檔,看 Docker Hub 頁面的標籤與環境變數說明,選明確的版本標籤。
- 作業系統映像檔:Debian 穩定、Ubuntu 初學首選(LTS)、Fedora 新技術、openSUSE(zypper)、Alpine 最小;CentOS Linux 已停止維護。
- 容器裡的
uname -r是主機的核心;容器裡裝的軟體刪掉容器就沒了。 --rm讓一次性的容器用完自動刪除;python:3.12加-it進入 Python 互動環境;docker container cp在主機與容器間複製檔案。- Jupyter 用
-d -p 8888:8888在背景啟動,token 從docker container logs取得;埠號衝突就換主機埠。 - MySQL 要用
-e MYSQL_ROOT_PASSWORD=…設定密碼;容器一啟動就結束時,先ls -a看狀態、再看logs。