# Docker :::warning Q & A 什麼是 Docker? 什麼是 Container? ::: :::warning Q & A Container 有哪些特性? ::: :::info **[OCI (Open Container Initiative)](https://opencontainers.org)** 是一個由 Linux Foundation 支持的開放標準組織,成立於 2015 年,目標是: > 制定並維護容器映像檔 (Image) 與執行環境 (Runtime) 的標準規範,使不同平台之間能夠相容 **[runtime-spec](https://github.com/opencontainers/runtime-spec)** 訂定一個容器如何在作業系統上執行,只要遵循 OCI runtime-spec 的 runtime 都能執行相同的容器設定 **[image-spec](https://github.com/opencontainers/image-spec)** 訂定映像檔如何被封裝跟儲存,讓不同 runtime 都能用相同規格製作與解析映像檔 **[distribution-spec](https://github.com/opencontainers/distribution-spec)** 訂定映像檔在 registry (例如 Docker Hub、Harbor、GHCR) 之間如何被上傳、下載與管理的標準 ::: ## 基本操作 `docker <resource> [options] <action> <image:tag>` ```shell # 查看映像檔 docker image ls docker images # 查看執行中的容器 docker ps # 查看所有容器 (包括已停止的) docker ps -a # 停止容器 docker container stop <container_id> docker stop <container_id> # 啟動已停止的容器 docker container start <container_id> docker start <container_id> # 移除容器 docker container rm <container_id> docker rm <container_id> # 移除映像檔 docker image rm <image_id> docker rmi <image_id> # 查看容器 log docker container logs <container_id> docker logs <container_id> # 即時查看容器 log docker logs -f <container_id> # 進入執行中的容器 docker container exec -it <container_id> bash docker exec -it <container_id> bash # 查看容器資源使用情況 docker container stats docker stats # 清理未使用的資源 docker system prune ``` ## Volume :::info 將容器應用程式設計成 **無狀態 (stateless)** 是一種 best practice,這邊的狀態 (state) 指的是應用程式在某個時刻儲存的資料或上下文資訊,所有狀態資料要放在**外部**,需要時再注入容器當中,目的是讓系統能夠在任何時候開、關容器,而不影響整體服務 ::: 為了能夠讓無狀態的容器去方便取用這些有狀態的資料,要透過 volume 去實現 ### 建立 volume `docker volume create <volume_name>` `docker volume ls` ### 在 container 使用 volume 先使用 nginx 掛載資料夾,並檢查及修改內容 `docker run --rm --name web-server -d -p 8080:80 -v <volume_name>:/usr/share/nginx/html nginx` 然後再用 apache 掛載執行,看看結果是否一樣 `docker run --rm --name web-server -d -p 8080:80 -v <volume_name>:/usr/local/apache2/htdocs httpd` ## 如何建立 image? 在當前資料夾建立一 `index.html` ```html! <!DOCTYPE html> <html> <head> <title>Hello from Ubuntu + Nginx</title> </head> <body> <h1>Nginx running on Ubuntu!</h1> </body> </html> ``` 再建立一叫做 `Dockerfile` 的檔案 ```dockerfile FROM ubuntu:24.04 # 不讓 apt-get 要求互動輸入 ENV DEBIAN_FRONTEND=noninteractive # 更新套件清單並安裝 nginx RUN apt-get update && \ apt-get install -y --no-install-recommends nginx && \ rm -rf /var/lib/apt/lists/* # 刪除預設網頁,複製自己的 RUN rm -rf /var/www/html/* COPY index.html /var/www/html/ # 開放 80 port EXPOSE 80 # 啟動 Nginx (用 foreground 模式讓容器持續執行) CMD ["nginx", "-g", "daemon off;"] ``` 建立 image `docker build -t ubuntu-nginx .` 執行看看 `docker run -d -p 8080:80 ubuntu-nginx` :::info 為何 Dockerfile 安裝套件使用的是 `apt-get` 而不是 `apt`? `apt-get` 是早期 Debian/Ubuntu 系統中提供的套件管理指令,專門給 腳本與自動化工具使用,後來新增 `apt` 來提升使用者體驗。 而在 `docker build` 的過程中沒辦法做任何的互動式操作,且 `apt-get` 在版本更動的過程輸出格式沒有什麼變動,而 `apt` 為了更好的使用者體驗,輸出格式每次的改動都算滿大的,所以 `apt-get` 會更適合做自動化及分析 debug 而且最重要的 [Ubuntu 官方文件](https://manpages.ubuntu.com/manpages/noble/man8/apt.8.html)在 `SCRIPT USAGE AND DIFFERENCES FROM OTHER APT TOOLS` 有明確的建議 ::: # Docker Compose 使用 `yaml` 的格式定義多容器組成的應用程式的組合方式,有了這個檔案就能夠使用 `docker compose <action> [options]` 來建立或是管理應用程式 建立一 `compose.yaml` 檔案 ## Demo ```yaml name: dbms services: database: image: postgres environment: POSTGRES_PASSWORD: password ports: - 5432:5432 web-client: image: clidey/whodb ports: - 8080:8080 ``` 啟動應用程式 `docker compose up -d` 觀察應用程式的執行狀態 `docker compose ps` 觀察應用程式的 log `docker compose logs`