-[![hackmd-github-sync-badge](https://hackmd.io/pJNDY4QbQH-6qwIrI-jXwg/badge)](https://hackmd.io/pJNDY4QbQH-6qwIrI-jXwg) ###### tags: `教學` `Docker` `學習筆記` # Docker and Container 003 - image 映像檔 [TOC] --- ## 0. Docker Image - 映像檔的概念(裡面放什麼) > 映像檔是 Docker 的三大組件之一。(image, container, registry)。 Docker 在執行容器前需要本地端存在對應的映像檔,如果映像檔不存在本地端,Docker 會從映像檔倉庫下載(預設是 Docker Hub 公共註冊伺服器中的倉庫)。 - Docker如何使用映像檔 >- dockerfile → image → container >- image ←→ registry - 一種簡易的成品,可食用,但通常可擴充/客製 - 一鍋醃肉,但一頓飯不會只吃醃肉 - 一鍋咖哩,比醃肉更完整些,但也可擴充 --- 以下就常用功能一一做介紹: --- ## 1. PULL 取用映像檔 - 從docker hub拉取:`$ docker pull nginx:latest` - latest是tag/標籤,一般來說可當作版本來理解。 - 沒有指定版本的話,預設都為最新版(latest) - 從docker hub 尋找(search):`$ docker search nginx` - 說明找到的結果,官方認證、星星數 - 查看映像檔資料:把image放在容器執行起來,查看裡面的內容:`$ docker run -it --name [container] [image] /bin/sh` - --name [container]:替容器取名 - [image]:容器基底的映像檔 --- ## 2. PUSH 推送映像檔 > 把映像檔 Push到公開網路的 Docker Hub 上,所有的人都可以把這個映像檔 Pull 下來使用 1. 註冊 [Docker Hub](https://hub.docker.com/) 帳號 2. 把 Docker Image Push 到 Docker Hub 上 ```linux= 1. 查看現在有什麼映像檔 $ docker images 2. 選擇一個叫alpine,放在test_alpine專案裡 $ docker tag alpine kihifung/test_alpine 3. 推到遠端(hub) $ docker push kihifung/test_alpine 沒登入,所以失敗 Using default tag: latest The push refers to repository [docker.io/kihifung/test_alpine] bc276c40b172: Preparing denied: requested access to the resource is denied 4. 登入registry $ docker login Username: kihifung Password: Login Succeeded 5. 重新推一次(成功的訊息如下) $ docker push kihifung/test_alpine Using default tag: latest The push refers to repository [docker.io/kihifung/test_alpine] bc276c40b172: Mounted from library/alpine latest: digest: sha256:be9bdc0ef8e96dbc428dc189b31e2e3b05523d96d12ed627c37aa2936653258c size: 528 ``` - 實例圖如下: ![](https://i.imgur.com/yzdwsQz.jpg) ![](https://i.imgur.com/HbQl9ilm.jpg) 3. 測試是否成功的把 Docker Image Push 到 Docker Hub 上 ```linux= 1. 查看現有的映像檔,選擇刪除kihifung/test_alpine $ docker images $ docker rmi kihifung/test_alpine Untagged: kihifung/test_alpine:latest Untagged: kihifung/test_alpine@sha256:be9bdc0ef8e96dbc428dc189b31e2e3b05523d96d12ed627c37aa2936653258c 2. 確認已刪除後,將hub上的拉下來, $ docker images $ docker pull kihifung/test_alpine:latest latest: Pulling from kihifung/test_alpine Digest: sha256:be9bdc0ef8e96dbc428dc189b31e2e3b05523d96d12ed627c37aa2936653258c Status: Downloaded newer image for kihifung/test_alpine:latest docker.io/kihifung/test_alpine:latest 3. 確認有拉下來 $ docker images ``` - 實例圖如下: ![](https://i.imgur.com/ZPmej6p.jpg) ![](https://i.imgur.com/2OWNRim.jpg) --- ## 3. SAVE 儲存/匯出 > 原本用來存成串流,寫入指定的檔案,常用來存成壓縮檔 * `$ docker images`,查看有什麼映像檔 * `$ docker save alpine:latest > alpine.tar`,選擇alpine:latest這個映像檔存成壓縮檔(或是`$ docker save -o mytomcat.tar mytomcat`,先寫結果名稱,再來原始image,-o: 輸出檔案) * `$ ls`,查看這個資料夾有什麼檔案,確認alpine.tar有沒有產生 --- ## 4. LOAD 加載 * 接續前面的範例 * `$ docker images` * `$ docker rmi alpine:latest` * `$ docker load -i [路徑]/ai-engine.tar` * 過程中可仔細觀看log ### 實例(小i) * `$ docker load -i /xiaoi_app/ai-engine/images/ai-engine.tar`, 將/xiaoi_app/ai-engine/images這個資料夾裡面的ai-engine.tar這個檔案,加載上去。 --- ## 5. Build 建構 - [Image-building best practices](https://docs.docker.com/get-started/09_image_best/) --- ## 6. Commit > 將conatainer重新包成image ### [修改已有映像檔](https://philipzheng.gitbook.io/docker_practice/image/create#xiu-gai-yi-you-ying-xiang-dang) * 先使用下載的映像檔啟動容器。 ``` $ sudo docker run -t -i training/sinatra /bin/bash root@0b2616b0e5a8:/# ``` * 注意:記住容器的 ID,稍後還會用到。 * 在容器中加入 json 的 gem 套件。 root@0b2616b0e5a8:/# gem install json * 當結束後,我們使用 exit 來退出,現在我們的容器已經被改變了,使用 docker commit 命令來提交更新後的副本。 ``` $ sudo docker commit -m "Added json gem" -a "Docker Newbee" 0b2616b0e5a8 ouruser/sinatra:v2 4f177bd27a9ff0f6dc2a830403925b5360bfe0b93d476f7fc3231110e7f71b1c ``` * 其中,-m 指定提交的說明信息,跟我們使用的版本控制工具一樣;-a 可以指定更新的使用者信息;之後是用來建立映像檔的容器的 ID;最後指定新映像檔的名稱和 tag 。建立成功後會印出新映像檔的 ID。 #### 常見docker image * `alpine`:輕量化的Linux作業系統 * `nginx`:輕量的網站伺服器 * `apache`:重量的網站伺服器 --- ## 7. 刪除image ### 1. 還有容器在使用 - `$ docker rmi AAA`,砍掉AAA這個image - 常見錯誤訊息:這個image還放在container中運行 ![](https://i.imgur.com/x2fIQTm.jpg) ![](https://i.imgur.com/L51dPba.jpg) * `$ docker rm 4caa6d8ca27c`,刪除container * `docker rmi kihifung/course-image-build`,刪除特定image * `docker rmi -f kihifung/course-image-build`,強制刪除特定image ![](https://i.imgur.com/lVT9GjC.jpg) ::: info 刪除image指令 ```linux= 兩種皆可 $ docker rmi [image_name] $ docker rmi [image_id] ``` ::: #### 刪不掉? - 因為已經有容器在使用,要先把容器停止 - [指令連結](https://hackmd.io/CHWfratfRWGz0Ykb1ShC6A?both#%E5%8 8%AA%E9%99%A4) ### 2. 與多個專案連結 :::warning root@docker_machine docker]# docker rmi b1d9e36f9546 Error response from daemon: conflict: unable to delete b1d9e36f9546 (must be forced) - **image is referenced in multiple repositories** ::: - b1d9e36f9546 這個映像檔被兩個專案給使用:kihifung/t0802_2、kihifung/test0802 - 刪除時可以用repository和tag的方式來刪除: - `$ docker rmi kihifung/t0802_2:latest `和 - `$ docker rmi kihifung/test0802:1.0 ` ![](https://i.imgur.com/jDLwbYr.jpg) ### 3. 孤兒 dangling=true :::warning [root@docker_machine docker]# docker rmi 021b3423115f Error response from daemon: conflict: unable to delete 021b3423115f (cannot be forced) - image has dependent child images ::: 解法: 1. 先刪掉孤懸的映像檔 * `$ docker rmi $(docker images --filter "dangling=true" -q )` 2. 再刪除欲刪除的映像檔 `$ docker rmi 021b3423115f` - 這個主要是拿來清理一些,同一個 tag 但已經被覆蓋過的 image。有些 tag 被 build 了兩次,那第一次的 build 所建立出來的非共用部份的 image 就等於是孤兒了,用這個指令可以清除。 :::info **dangling** 是表示那些沒有 TAG (標記)的 Image,常發生於自行建立的 Image 上,若是從 Docker Hub 或其他地方 pull 下來的幾乎都不會有這問題。 **系統判定這些未被 TAG 的 Image,不被用於任何 Images Layer 中,同時也占用了磁碟空間**,因此註記為 dangling,提醒開發人員此 Image 的狀況。 開發人員可以做的動作是將其 TAG、保持不變或刪除。 --- - [參考資料](https://hackmd.io/@KaiChen/Skt8SLZV8#%E6%9F%A5%E8%A9%A2%E9%80%8F%E9%81%8E-Filter-%E7%AF%A9%E9%81%B8) ::: - 相關指令 * `$ docker image prune`,移除沒有標籤並且沒有被容器引用的映象,這種映象稱為 **dangling(搖晃的)** 映象 ##### 延伸閱讀 - [DOCKER 移除 CONTAINERS、IMAGES、VOLUMES 與 NETWORKS 的方法](https://blog.clarence.tw/2019/09/10/docker-removing-containers-images-volumes-and-networks/) - [docker 移除,裁剪,刪除(prune)不使用的映象、容器、卷、網路](https://iter01.com/572355.html) - [解決刪除映象時 image is referenced in multiple repositories](https://www.itread01.com/content/1545240006.html) --- ## 8. Tag 更名 - (範例圖,顯示映像檔名稱與image id) - image的名稱其實只是一個貼紙,本體是以image id來編號,在顯示上會顯示為分配到哪一個專案(repository) - 所以第一行表示:xxxx(image id)現在被OOOO(repository)使用,有著QQQ(tag)的標籤 - 因此,有些複製或刪除的指令看起來就像是貼上貼紙或撕掉貼紙(可在log裡看到tagged/untagged)。同一個image也可以有多個貼紙(被多個repo同時使用) - `$ docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]` --- ## 9. 其他 ### docker image放在哪? - `$ docker info`,查看docker相關資訊,其中`Docker Root Dir: /var/lib/docker`顯示出docker image的存放路徑 - ref:[修改 Docker image 預設存放位置](https://marcus116.blogspot.com/2019/03/change-download-docker-image-path.html) ### 其他不使用docker的方法 - [Kaniko — Image Builder 試玩](https://www.geminiopencloud.com/zh-tw/blog/kaniko/) ### 其他指令 * `$ docker images --no-trunc` 列出 Images 完整資訊 * `$ docker inspect --format='{{.Id}} {{.Parent}}' $(docker images --filter since=<image_id> -q)`,列出與<特定映像檔>有關的內容 ![](https://i.imgur.com/arX8BDO.jpg) ##### 建構docker應用程式的小技巧 1. (不包含函式庫和相依套件的話)image盡量小,這樣啟動快載入也快 2. 如應用程式需要擴展,應考慮使用dockerswarn、kubernetes等工具 3. 為了最大效率,請將Docker與CI/CD結合,可以從雲端自動建立映像檔,並推送到docker倉庫。 - 資料來源:[quicks tips for building applications with Docker](https://medium.com/hackernoon/docker-commands-the-ultimate-cheat-sheet-994ac78e2888) --- --- ## 回顧 ### Image * [ ] 什麼是image * [ ] image可以幹嘛 * [ ] 這麼多不同的指令代表image的什麼用途 --- - [回到目錄](https://hackmd.io/@Hualiteq/r1lye3M3d)