iT邦幫忙

5

[不做怎麼知道系列之Android開發者的30天後端養成故事 Day12] - 容器vs.鴨子vs.搬運工 #Docker #什麼是容器? #可轉移的執行環境

https://ithelp.ithome.com.tw/upload/images/20200218/20124548BQkQfQJ7sO.png

哈囉,我們又見面了,今天要來看看什麼是 Docker,以及 Docker 能替我們做些什麼 ? 構構~

先來個開門見山法,為什麼會從昨天的 Testing 到今天的 Docker 呢 ? 那是因為測試,不一定是跑在本地端,也不一定是跑在你熟悉的作業系統上,也不一定是跑在你熟悉的套件版本上,所以呢,我們需要 統一 這一些的「環境」,而 Docker 就是在做這件事。

什麼是 Docker ?

先來個說文解字,Dock 是 碼頭 的意思,而 Docker 是 碼頭的搬運工 的意思,在唸 Docker 的時候不要唸成鴨子 (Duck) 囉 XD,那麼你可以怎麼理解 搬運工 這個詞呢 ?

想像一下你在自己的電腦開發 Django 後端,是不是需要先安裝 Python、安裝 IDE、安裝 Django,還有各式各樣的依賴套件,那麼你要換另一台電腦來開發的時候,就需要參考你之前安裝的版本,照著在另一台電腦也安裝一模一樣的套件,這是不是有點像 搬運工 的感覺,你把 A 電腦的環境 搬到 B 電腦,這是一件費時又費力的事情,所以,Docker 就出現來拯救大家了。

Docker 能替我們做些什麼 ?

簡單來說,你可以把你的執行環境隨時帶著走,再配合 Github,可以連同專案也一起帶著走。

那麼跟虛擬機 (Virtual Machine, VM) 有什麼不同呢?

先上個圖比較好理解,從左右圖比較可以看得出來,每一個 VM 都比 Container 多了 Guest OS,也就是說,我在我的電腦(假設是 Win10)上開 VirtualBox,可以開好幾台虛擬機,可能是 Ubuntu,可能是 Mac,可能是 Win7 等等的虛擬機,優點是它就像是一台新電腦的感覺,想要在虛擬機裡面做什麼事都可以,非常彈性,壞處就是一個虛擬機的檔案很大,大約是好幾 Gigabyte、到幾十 G,都是正常的,想像你要把這個虛擬機搬到別台電腦,是不是就要考慮一下你身邊隨身碟能不能裝得下,還有一點是很吃效能,處理器跟記憶體不夠的話跑起來就很卡,還有就是每次啟動虛擬機要等蠻久的,相當於你重開機的時間,但現在大家都是 SSD,這樣的開機時間就還能接受,可是如果要同時開好幾個虛擬機,就算電腦跑得動,想想還是會覺得很麻煩。

https://ithelp.ithome.com.tw/upload/images/20200218/20124548gaHRuEYxR2.png

左右這兩張圖來自 inwinSTACK,其餘是我加工上去的

這時候再來看看 Docker 贏在哪裡、輸在哪裡,Docker 不需要把作業系統也包進去,所以每個 Container 也就很瘦,大約是,啟動時間就不需要像虛擬機開機一樣那麼久,是秒級的啟動速度,缺點就是不像虛擬機這麼彈性,總體來講還是優大於缺,也依照使用情境不一樣來選擇 DockerVM

所以該怎麼入門 Docker 呢?

其實,RS 在入門 Docker 的時候,覺得非常難懂,在使用上不像是 VM 那麼友善,想當初使用 VirtualBox 時候,只要抓個映像檔,就能跑了,而且一進去是就像是一台真正的電腦,但是 Docker 不是,大部分需要 Command Line 指令來執行,但有壞就有好,透過指令來執行的好處是,懂指令的就可以玩得很猛,不懂的人根本就吃便便,就算下了指令也不知道自己在做什麼。

你可以把 Docker 想成,組樂高,需要自己把一塊一塊的樂高組起來;那麼 VM 就是給你一個玩具,看你要怎麼玩這個玩具都可以。如果你亂玩 Docker,就很像你不會玩樂高,隨便拿幾個積木組一組,看起來就不像是一個完整的東西,是有個入門門檻的,像我這個初新者傻傻的以為很容易入門 QQ,到現在都還在努力地理解 Docker,如果我有哪邊講錯,再麻煩大家給我一點指教,感謝。

講到組樂高,可以參考下面這張圖,可以把你的專案環境,拆成一層一層的,像積木一樣,需要用到的時候,再把它們組起來,舉例來說,我可以讓 django 是一個積木,MySQL 是一個積木,MongoDB 是一個積木,nginx 是一個積木,然後今天需要一個 MySQL 作為資料庫的 Django Server 時,那我就先不要放 MongoDB 的積木,達到重複使用的效果。

https://s4.itho.me/sites/default/files/styles/picture_size_large/public/field/image/683-%E5%B0%81%E9%9D%A2%E6%95%85%E4%BA%8B-P34-%28960%29.png?itok=WnTImP5j

引用自 Docker社群達人教你快速踏出Docker的第一步 | iThome

所以入門 Docker 的第一步,就是先搞懂幾個 Docker 的名詞:

  • Dockerfile
  • Image (映像檔)
  • Container (容器)
  • Registry (倉庫)

Dockerfile

我從網路上找的 Docker 教學,通常不會把 Dockerfile 放在名詞解釋一起講,但我覺得這是很重要的一個檔案,可以把 Dockerfile 想成是一個「建立環境」的檔案,可以透過 Dockerfile 來建立 image(映像檔),指令是 $ docker build -t tagnameofimage .,這個指令是參考用的,實際上的意思是把當前目錄下的 Dockerfile 建立出一個名為 tagnameofimage 的映像檔,以下是一個我用來把當前的 django 專案包在 python base image 的 Dockerfile:

# 告訴 Docker,我的 base image 要用 python 3 的版本
FROM python:3

# 環境變數 (這行是告訴 python,有 log 就往外吐)
# 可參考 Is PYTHONUNBUFFERED=TRUE a good idea?
# (https://github.com/awslabs/amazon-sagemaker-examples/issues/319)
ENV PYTHONUNBUFFERED 1

# 執行 shell script (這行是建立一個新資料夾 叫做 code)
RUN mkdir /code

# 切換目錄 到 /code 資料夾底下
WORKDIR /code

# 新增本地端的 requirement.txt 到 docker 的 code/ 資料夾底下
ADD requirements.txt /code/

# 執行 shell script
# (這行是根據 requirements.txt 
# 來安裝我需要的 python 套件)
RUN pip install -r requirements.txt

# 新增本地端的所有檔案(django專案) 到 docker 的 code/ 資料夾底下
ADD . /code/

# 告訴 docker container 跑起來之後,要執行的指令們
# (這邊是先執行 init.sh 的 shell script
# 並且 執行 django server 在 8000 port
# (0.0.0.0 很重要,不一定能用 127.0.0.1 取代)
# 可參考 What's the difference between 127.0.0.1 and 0.0.0.0?
# (https://superuser.com/questions/949428/
# whats-the-difference-between-127-0-0-1-and-0-0-0-0)
CMD sh init.sh && python3 manage.py runserver 0.0.0.0:8000

先不要怕 image、container 的名詞,我們等等解釋完名詞後,你再回來看這段,會比較有感覺。

Image (映像檔)

簡單來說,可以把它想成是環境的安裝檔,可以透過 $ docker build -t my_image . 這樣子的指令,把我依照當前目錄的 Dockerfile 檔案,來建立一個映像檔,並且這個映像檔透過 -t 的參數,給這個映像檔一個標籤 (tag),就是幫它取個名字的意思拉。

這個安裝檔,就是 讓你到處移動你的環境,但很難理解的一件事,就是你以為這是一個看得見的檔案,嘿嘿,事實上它偏不,你看不到這個檔案,你只能透過 $ docker images 的指令來檢視你現在有的映像檔有哪些,光是 看不到 的這一點,就已經很難理解了,但先別放棄 !! 讓我們繼續看下去。

不是說我可以把環境搬來搬去嗎,如果看不到,那麼要怎麼移動環境 !?

沒錯,你不能用複製貼上大法來移動環境,可是這就跟 git 很像,可以用 $ git checkout xxx-branch,可是你看不到 branch 的檔案 ! 你只能用 $ git branch 來檢視有哪些分支。

那麼回到怎麼移動這個環境的問題,在 git 有 push 的指令,可以讓你把更改的檔案上傳到 Github 上,在 docker 也有差不多的概念,你可以透過 $ docker push username/imagename 的指令,將你的映像檔上傳到 Docker Hub 上面,也就是說,你不需要用隨身碟把你的執行環境裝進去了,你只要在另一台電腦有網路、登入你的 Docker Hub 帳號,就可以用 $ docker pull username/imagename,把一模模一樣樣的環境給抓下來,是不是很酷。

所以你瞭解了映像檔就是你的執行環境,再來看下去。

Container (容器)

Container 也是你的執行環境,我這麼說不是要故意混淆你們,是真的 ContainerImage 都是執行環境,他們的差異就只有差在 Container 是跑起來之後的 Image,而 Image 是還沒跑起來的 Container,這兩個名詞之前的差異,就很像 Program 跑起來變 ProcessProcess 還沒跑起來就是 Program,你可以感受一下。

Registry (倉庫)

你可以把 Registry 當成是 Github 的感覺,Github 是用來存專案的地方,而存映像檔的地方就叫做 Docker Hub,是一個遠端的倉庫,除了 Docker Hub 之外,也有其他放映像檔的倉庫,這很像是你可以不要把專案都放在 Github 上,我想要放到 Gitlab 上,舉一反三,有 遠端的倉庫 也就是說有 本地端的倉庫,至於這個我們目前還不需要,先放在 Docker Hub 上面就好了。

講那麼多觀念,實際操作看看就有點感覺了

就我目前的理解,有兩種建立映像檔的方式

第一種,直接從 Docker Hub

這種最簡單,可以到 Docker Hub 找你需要的環境,像我這邊可以打關鍵字 python,就可以找到有 pythondjango 的兩種映像檔。

https://ithelp.ithome.com.tw/upload/images/20200218/2012454853wn6fC1CA.png

我點進去 python,就可以在 cmd 使用 $ docker pull python 指令,把 python 的映像檔抓下來,如果你想挑選特定 python 版本,那就在 Tags 裡面搜尋你想要的版本,照著右邊的指令就可以抓到特定版本的 python 映像檔了。

https://ithelp.ithome.com.tw/upload/images/20200218/20124548J8V60DefXY.png

我是指定了 python 版本了,那我如果還想要指定我的作業系統呢 ?!

假設我想要 Python,可是我又想要作業系統是 Ubuntu 18.04 版本,那就 base image 抓 ubuntu 18.04 映像檔,執行為 container,再進去裡面安裝你想要的 python 版本,大致上的指令流程如下,指令會依照不同情況有所不同,流程只是參考。

打開一個終端機

  • $ docker images (找出你的 image hash)
  • $ docker run -it yourimagehash bash (輸入完這行,就會進入到映像檔的終端機)

已進到映像檔的終端機

開啟另一個 cmd or terminal 視窗

  • $ docker container ls (找出你的 container hash)
  • $ docker container commit yourcontainerhash yourusername/yourimagename (將目前在 container 裡面做的改變儲存下來,產生另一個映像檔)
  • $ docker push yourusername/yourimagename (將目前的映像檔上傳到 Docker Hub 上)

第二種,從 Dockerfile 建立

這邊就以一個簡單到爆炸的 Dockerfile 來做範例,希望建立一個 python 3 為 base image 的映像檔。

Dockerfile

我把這個 Dockerfile 檔,存在 Downloads 底下

# 告訴 Docker,我的 base image 要用 python 3 的版本
FROM python:3

# 會在 docker build 的階段就執行
RUN echo hello

# 在執行容器之後會執行的指令
# 這行就是代表,希望它能在執行這個容器的時候
# 告訴我,它所安裝的 python 版本
# 然後就結束掉這個容器
CMD python --version

透過 $ docker build -t docker_hello_world .,利用當前目錄的 Dockerfile 來建立出一個叫做 docker_hello_world 的映像檔。

https://ithelp.ithome.com.tw/upload/images/20200218/201245489SI24ALeN2.png

再用 $ docker images 檢查一下有沒有建立映像檔成功

https://ithelp.ithome.com.tw/upload/images/20200218/20124548lcZ7cPx7JA.png

$ docker run -it docker_hello_world 跑跑看

https://ithelp.ithome.com.tw/upload/images/20200218/20124548WNjHk10UwG.png

所以它就回傳給我 Python 3.8.1,然後容器就結束。

那如果我想進去容器裡面玩玩看呢 ?

就可以利用 $ docker run -it docker_hello_world bash 的指令,進去容器的終端機裡面玩玩,這時候裡面就是一個簡易 linux 並且事先有安裝 python 的一個環境,所以這個映像檔才肥到 933MB。

https://ithelp.ithome.com.tw/upload/images/20200218/20124548gsVO95XBVY.png

單日心得總結

我覺得我已經盡力把我理解的 docker 解釋清楚了,再不懂的話可以參考其他網路資源,各種交互對照一下,每個人的理解方式不太一樣,多參考幾份講解、解說影片,然後再自己輸入指令玩玩看,驗證一下結果是不是真的像我們所理解的一樣,然後再不懂就去騷擾身邊的前輩們 XD,至少這是我學 docker 的方法哈哈,希望這篇對大家有點幫助。

為了這篇文章,我焦慮了好久 QQ,因為它對我來講,實在是太難理解了,每看一篇教學、每看一部教學影片、每輸入一次指令,都一直在顛覆我對 docker 的理解,反反覆覆、到目前花了整整四天的時間,都還對 docker 很沒有把握,在寫這篇文章的時候,我還一直在嘗試我的邏輯到底是不是對的,真的花了很多時間跟心力,如果有講錯、寫錯,希望大家鞭小力點,也希望能不吝給我一點指教,讓我能夠更理解 docker 這個好用的工具。

經歷了這幾天,反反覆覆地研究 DockerCI/CD,讓我對於「架 server」這件事,完全是有個顛覆性的思維升級,認真覺得後端人員 和 網管真的是挺辛苦的 ...。

我是 RS,這是我的 不做怎麼知道系列 文章,我們 明天見。



2 則留言

0
Robin
iT邦新手 5 級 ‧ 2020-02-20 14:16:12

懂指令的就可以玩得很猛,不懂的人根本就吃便便

我一直在吃便便QQ (努力學習中/images/emoticon/emoticon16.gif

我是已經習慣吃便便了 XD

0
paul12999
iT邦新手 5 級 ‧ 2020-05-06 18:03:22

安安好久不見,我熊阿,太神啦寫的很棒

題外話,之前幫朋友架環境,加上工作有用到docker
只覺得很像vm,但不知道在幹嘛xdd
看完文章後才知道確切用途

總之覺得django比較有趣,來像RS大大拜師了
p.s.工作真他貓的無聊= =

是你! 好久不見啊~

總之覺得django比較有趣

所以你最近也在玩 django 嗎~

p.s.工作真他貓的無聊= =

找一個好玩的工作啊 XD

paul12999 iT邦新手 5 級 ‧ 2020-05-07 14:07:19 檢舉

剛才安裝 努力摸所中
上班偷完喝

我要留言

立即登入留言