Docker

Introduction

三個概念:

  • Image
  • Container
  • Repository

Image

Image 包含了要執行的所有東西,例如完整的 ubuntu,或者 Python 以及需要的套件等等。

可以在 shell 下 dokcer images -a 來顯示當前系統有什麼 imageGot permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Delete "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/images/8329955d3214": dial unix /var/run/docker.sock: connect: permission denied

$ docker images -a

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

我們在建立 image 時,常常因為一些小錯誤會建立失敗(例如版本不合),這時候建立失敗的 image 使用 dokcer images -a 顯示出來的 TAG 都會是 none ,這種時候我們必須得移除這些 none,我們可以透過剛剛下的 dokcer images -a 來找到這些 none 的 image ID, 然後使用 docker rmi [OPTIONS] IMAGE [IMAGE...] 來移除。

$ docker rmi [OPTIONS] IMAGE [IMAGE...]

這些失敗的 image 是無法使用的,建立失敗後請記得隨手清掉,不然很佔空間的~~

這裡需要特別注意的是,如果 image 已經掛載在 container 上,則 image 會沒有辦法順利被刪除,必須先刪掉對應的 container 後才可以再刪除 image。

Repository

這個不用特別管,除非你想上傳自己的 image,多數時候我們都是從 Dokcer hub,把別人已經製作好的 image 給 pull 下來,類似 github 的 pull 機制,也可以透過 push 把自己的 image 上傳到倉庫中。

Dockerfile

Dockerfile 是一個可以自動幫我們把 image build 起來的檔案,通常我們都是以一個已經存在的 image 做為基底 (e.g. python/ ubuntu),然後下去做些許改動。

注意到,在 docker build 的時候,Docker 預設會尋找當前目錄底下的 Dockerfile檔案,所以通常約定俗成都會把這個文字檔命名為 Dockerfile

如下:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

通常我們都會拿別人寫好的 image 下去做魔改,以下是一個 Dockerfile 的範例:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

語法:

  • FROM
    • 必須以 FROM 開頭
    • FROM 指的是要從哪個基底 image 下去做修改
  • WORKDIR
    • 設置當前目錄,Docker 會將指定的目錄設定為當前的工作目錄,只後如果執行任何指令(e.g. RUN、CMD、ENTRYPOINT、COPY…) 都會在這個目錄下進行。
  • COPY
    • COPY [--chown=<user>:<group>] <source path>... <dist path>
    • 複製「來源文件\目錄」到的 Image 中的「文件\目錄」中。
    • 這裡的 COPY ./app . 的意思就是把 build 環境下的 /app 資料夾複製到 container 的 WORKDIR 路徑下
    • 注意到如果要包起來的東西不多的話,可以考慮直接下 COPY . .
  • RUN
    • 用來執行 Shell 指令,例如 apt-get install 之類的。

Dockerfile 寫完之後,執行 docker build -t [YOUR IMAGE NAME] . 就可以把 image 建起來了,-t 是幫你的 image 加一個標籤。

Container

Container 是把 Image 跑起來的 容器,它可以被啟動、開始、停止、刪除

每個容器都是相互隔離的、保證安全的平台。

可以透過下列指令,搭配已經存在的 image 來創立 container

$ docker create --name [conainer name] [iamge]

我們可以在創建 container 時給他一個名子,以後要啟動這個 container 可以透過這個名子跟他互動,沒有給的話 docker 會隨機給他一個名子

$ docker ps -a // 列出所有 container (包含停止的)
$ docker run [OPTIONS] IMAGE [COMMAND] [ARG...] // run container
$ docker stop [OPTIONS] CONTAINER [CONTAINER...] // stop container
$ docker kill [OPTIONS] CONTAINER [CONTAINER...] // kill container
$ docker restart [OPTIONS] CONTAINER [CONTAINER...] // restart container
$ docker rm [OPTIONS] CONTAINER [CONTAINER...] // rm container
$ docker logs [OPTIONS] CONTAINER // check containers log

stopkill 的差別在於: stop 屬於 graceful shutdown,而 kill 會直接停止

注意到移除 contaier 是使用 rm,而移除 image 是 rmi (i: image)

docker run [OPTION] IMAGE 可以加上很多選項,如下

  • -i : 保持 stdin 開啟
  • -t : 賦予終端介面
  • -v : volume
  • -p : port
  • -d : detach, 背景執行
  • -e : 設定環境變數
  • --name : 幫 container 取名字

Docker volume

如果我們把 container 刪掉的話,存放在該 container 的資料也會被刪除掉,那這時候我們可以透過把 container 跟實體路徑綁定起來,把不想要被刪除掉的資料存放在實體機器上,避免資料不見的問題。

有兩種方式:

  1. 執行 docker run 指令時加上 -v 參數,使得 Container 裡面的檔案路徑Mapping 到實體主機的檔案路徑。
  2. 在撰寫 Dockerfile 時,加入 VOLUME 指令,做到把資料存放在實體的主機上。使用這種方法需要搭配 docker inspect 指令,才能查詢到實體主機檔案的存放路徑在哪。

這邊我只會教使用 -v 的方式

在使用 docker run 指令時,指定 -v 參數,使得實體主機的資料夾路徑 Mapping 到 Container 的資料夾路徑,指令如下

$ docker run -it --name Computer_Organization -v $PWD/app:/app linux_latest
  • Container Volumes:
    • Volumes provide the ability to connect specific filesystem paths of the container back to the host machine.
    • -t: attach時Container的螢幕會接到原來的螢幕上
    • -i: Container stays interactive
    • -v: volume, absolute path which you want to mount local folder into container: container folder you want to mount with

也就是說 $PWD/app:/app 這邊

  • : 前面的是你想要 mount 的實體路徑,需要注意的是,我這邊用 $PWD 不是一個很好的方法,建議使用 absolute path。
  • : 後面的是 container 內的路徑

建議各位在包 docker 的時候,隨手寫一個 README,這樣以後要重啟重下指令都比較方便。