以 Docker for Mac 搭建開發環境
以前 Mac 上的 Docker
之前 Docker 就可以在 MAC 上面使用,但是實在太麻煩了,需要安裝 Boot2Docker, VirtualBox, Docker-Toolbox,實際上的體驗也遠不如 Linux 版本的。
如:每次重開機都需要執行以下命令,啟動也很花時間,在開發過程中,IP 需要透過 docker-machine
查詢,使用 Docker 開發失去了很多彈性:
docker-machine start default
eval $(docker-machine env default)
Vagrant 的虛擬網路
也因為如此,後來我改用了 Vagrant 作為開發環境。Vagrant 中的 private_network
可以讓 VM 中的網路環境與外部隔離,再也不需要預先決定好端口的映射關係,也不需要擔心端口被佔用的問題。
直到幾天前,遇到了一個問題:某部分的 API 在 VM 中雖然能正確取得回傳值,但總是會收到這個錯誤導致程式扔出異常而終止,即使把域名換成 IP 也是一樣的結果,在 Host 上執行同樣的命令沒有這個問題,測試過在 Guest VM 以及 Host 的出口 IP 都是相同的,無從得知對方的防火牆規則是什麼,因此無法進一步排查問題:
curl: (56) Recv failure: Connection reset by peer
回到 Docker 的懷抱
經過來回比對之後,幾乎可以明確定位是 VirtualBox 的問題,嘗試升級到最新版,還是沒有辦法解決,沒有很具體的重現步驟可以回報給社群解決,在這個問題消除之前只好暫時棄用 Vagrant 回歸 Docker 的懷抱。
在我電腦上的 Docker 還是舊版的,底層也是透過 VirtualBox 實作,問題依舊存在。這時想起了今年初發佈的 Docker for Mac Beta ,那時候都還是邀請制,一般人沒有辦法下載,這幾天上去看已經是 Stable 可以下載了。不過事情也沒有就這樣一帆風順...在 Container 中需要起 MySQL Server,啟動的時候總是報錯,稍微查了一下,似乎是 CentOS 的大坑,按照網路上的建議換上了 centos:latest
仍然有相同的問題:
Failed to get D-Bus connection: No connection to service manager
最後只好退回到 centos:6.8
的版本才解決了這個問題。
Native 的體驗
雖然號稱是 Native,實際上 Docker Engine 仍是運行在 xhyve VM 中的 Alpine 之上。
不過在使用上確實帶來了 Native 的體驗:
- 直接使用 Host IP,不需要再透過 docker-machine 查詢虛擬機中的 IP 來訪問容器中的機器
- 開機的時候自動啟動,不需要自行修改 .zshrc。啟動速度也比原先要快許多
- 在選單列中即可修改記憶體、CPU 核心數套用後快速重新啟動
- 安裝與其他的應用程式沒有差異,不需要額外設定也沒有相依套件需要安裝
美中不足的缺點
在短暫的使用過程中最惱人的就是磁碟空間無法動態伸縮這件事了,因為原本在 Virtualbox 中的 images/containers 就佔用了不少空間,遷移到 Docker for Mac 我只 pull 一個 image 就爆炸了,查了一下才知道因為底層依賴 QEMU,這部分目前還沒辦法跟 Docker.app 結合得很好,也就是說你在容器中 rm -rf /tmp
或是刪除任何檔案,你的磁碟空間一樣只增不降,嘗試過 qemu-img convert
,只能改 Virtual Disk Size。無奈之下還是忍痛重置 Docker for MAC,重置後有 60GB 的空間可以使用,應該可以撐到這個問題被解決吧(苦笑)?
docker rm $(docker ps -a -q)
docker rmi $(docker images -q)
docker volume rm $(docker volume ls |awk '{print $2}') rm -rf ~/Library/Containers/com.docker.docker/Data/*
利用 Docker 作為開發環境常用的小技巧
保存/載入 Docker 狀態有以下四個指令,是大家比較容易搞混的:
- docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
- Create a new image from a
container
's changes
- Create a new image from a
- docker save [OPTIONS] IMAGE [IMAGE...]
- Save one or more
images
to a tar archive (streamed to STDOUT by default)
- Save one or more
- docker export [OPTIONS] CONTAINER
- Export a
container's filesystem
as a tar archive
- Export a
- docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]
- Import the contents from a tarball to create a
filesystem image
- Import the contents from a tarball to create a
export/import
會將 images 合併成單一的 images。在一般情況,使用 commit/save
可以保留較高的彈性。
有興趣深入研究的可以參考這篇文章的介紹:
比較 save, export 對於映象檔操作差異
建立 Container 快照 (Snapshot)
我們在除錯的過程中可能會需要保存先前的狀態為新的 Image,在 Docker 我們可以利用 commit 指令來完成:
docker commit CONTAINER_HASH
儲存了快照後,停用運行中的容器,並 docker run
指定你要執行的快照。
docker run -it --name=foo CREATED_IMAGE_HASH bash
每層 image 都是增量式地向上疊加,所以在開發的過程中,大可盡量地 docker commit
保存環境的狀態。