docker

標籤:docker

Docker打包 App還是打包底層程式作為Image ?

潮流特區
MacauYeah ・2023-07-28

雖然筆者對於Docker Swarm Mode的資歷尚淺,但由於後期更動的難點越來越多,筆者很想早一點討論其中不同操作的差異 Docker Swarm Docker Swarm Mode其實是Docker提供的一個Cluster(群集)環境。在其中運行的Image,都可以比較方便地隨時分身到不同的node(節點)上,對於提高負載或可用性,都是一個不錯的解決。 只要該Image跑起的Container是Stateless(前後兩次執行的結果互不相干涉),或者是把Stateful的部份(有干涉的部份)外包到第三方(例如儲存空間使用NFS,或記憶體暫存改為Key-Value Database),就可以方便地運作在Docker Swarm mode上。 部署Docker Swarm的選項 Docker Swarm可以把Image變成分身Container,但並不沒有硬性改變傳統App操作方式。大部份App在執行時,都需要另一個底層程式的支緩。例如 Php Web App,需要底層php fpm + nginx或apache Java Web App,就需要java + Tomcat 所以在發佈App時,可以選擇把 App直接打包成Image 只把底層程式打包在Image中(例如Tomcat),再在跑起Container時再動態接起App。 兩者有何差別? 就信心層面上,一定是把App直接打包成Image實際一點。因為這樣可以極大地減少測試環境和正式環境的差異而出現的問題。筆者一開始也不完全讚成,但也越來越傾向這種做法。 在解釋筆者為何有這個結論前,先條列式地對比一下兩種差別。 事項打包App成為Image打包底層程式成為Image 打包複雜度 需要把App用到的一些環境變數引入設定Image的entrypoint中,方便配合不同的環境可以改變App的行為。打包次數根據App數量有關。比較靈活,但比較需要學習和試錯。 底層程式統一設定環境變數,其中所有App都會使用類似或相同的設定,設定方式跟傳統方式無異。打包次數根據底層程式數量有關。比較死版,但要試錯的成本較低 發佈流程 打包App成Image。再靠Docker Swarm設定Image有多少分身,每個分身不需要特別再設定。 原來的底層程式已存在於Docker Swarm中,只需把新建或更新了的App放入不同分身的儲存空間,讓底層程式動態跑起App。 管理複雜度 每個App都是獨立的,代表有任何更新也是獨立更新。在微服務的協作環境中,需要管理員從Image層面為每個App設定網絡(network)或開放端口(Port)。但每個App可以設定不同的分身數量,靈活性一定比只打包底層程式要高。 使用同一個底層程式Image的App都會使用同一個網路和端口設定。在微服務的協作環境中,管理員要應付的設定數量一定比打包App要少。但由於是Conatiner分身是針對底層程式,所以若然某個App有不同需求,就要重新設定另一套底層程式。 上述幾個點,最後其實都是複雜度和靈活度的取捨。雖然打包App的工序更多,但提供的靈活性也更多。如果考慮要從傳統模式中過渡,方便與完成不懂Docker的同事協作,就首選打包底層程式。如果考慮可重複性和信心保證,還是打抱App比較直接,要複制一個環境到另一個環境,也比較易測試。

自己架設Docker的共享儲存空間

潮流特區
MacauYeah ・2023-07-21

Docker很好用,在單機環境下真的很好用。Docker原本的設計,是為了快速迭代而設計成Image的。在一般設定下,每次新建或重建container,都會根據Image重設一下各方面的環境,包括儲存空間。重設CPU,Memory,大家都很易理解,但重設儲存空間,真的不是每一個使用情況都可以這樣。 又或者說,未必所有使用情況都會有一個第三方的儲存空間可以用。所以良心的Docker在單機環境下也有提供bind mount或是docker named volume,作為可以長期保存,不受container生死的影響,以達到長期存在Data的存在。 單機-儲存空間 單機情況下很簡單,就用一個docker compose做例子 其中html就是一個bind mount,而nginxlogs就是一個docker named volume,兩者都可以長期保存data,除非各位自己手動刪除,否則不會因為container的興亡而不見了。 但有兩個很重要的分別 bind mount,直接跟host os連接,實際上是每次folder有更新,docker都要同步host和container之間的資料。 bind mount在linux下很暢順,因為大部份docker image/container原本就是linux engine,所以folder mount真的可以互通。 bind mount在windows / mac下,就會不斷抄資料。面對大量檔案,例如node_module,就會有速度上的問題 docker named volume,就是docker 分離一些獨立空間,然後再綁到container上 相對bind mount,即使在windows / mac下,都沒有那個速度上的問題。筆者猜測,即使是獨立空間,其實本身都已經限定在linux enginx下,所以沒有需要抄資料。 但在windows / mac下,因應docker 底層建立Linux VM的技術不同,你可能沒法在windows / mac預設環境下直接讀取docker named volume。 若要讀取docker named volume,最好的做法,還是連上docker container,然後用docker cp 來抄回資料。一但抄資料,其實都會有速度上問題,不過docker cp是手動決定何時做的,不做docker cp,其實container也是可以用。 Cluster-儲存空間 雖然良心的bind mount和named volume解決了單機上的儲存問題,但到了cluster環境,就沒有可以跨機同步儲存空間的做法,要做就自己建立。 筆者也稍為研究了一下同步的問題,不過對技術真的很有要求。所以退而求其次,筆者還是選擇簡單的第三方儲存空間。就是做一個可以分享存取的NAS。 建立nfs linux下要安裝nfs其實很簡單,不過要注意資料夾和防火牆權限,以下安裝教學以ubunut 22.04為例,記得把下面的YOUR_DOCKER_NODE_ADDRESS_RANGE轉為你的真實IP段落 修改docker compose 最後,你在原來的docker-compose的docker volume上加driver_opts就大功告成。 記得把下面的YOUR_NFS_IP轉為你的真實IP

使用 Multipass 建立Docker Cluster

潮流特區
MacauYeah ・2023-06-02

以下流程,假設各位已經 在Ubuntu Server中開設了virtual bridge 供Multipass設定Static IP,並且network interface定為 localbr 使用Packer template制成docker.img , 並存放於當前資料夾內 使用docker.img 起三個node,並使用network interface localbr,各有一個指定的mac address multipass launch file://$PWD/docker.img --name node21 --network name=localbr,mode=manual,mac="52:54:00:4b:ab:21" multipass launch file://$PWD/docker.img --name node22 --network name=localbr,mode=manual,mac="52:54:00:4b:ab:22" multipass launch file://$PWD/docker.img --name node23 --network name=localbr,mode=manual,mac="52:54:00:4b:ab:23" 對運行中的三個node,為它們設定static ip multipass exec -n node21 -- sudo bash -c 'cat /etc/netplan/10-custom.yaml network: version: 2 ethernets: extra0: dhcp4: no match: macaddress: "52:54:00:4b:ab:21" addresses: [10.13.31.21/24] EOF' multipass exec -n node22 -- sudo bash -c 'cat /etc/netplan/10-custom.yaml network: version: 2 ethernets: extra0: dhcp4: no match: macaddress: "52:54:00:4b:ab:22" addresses: [10.13.31.22/24] EOF' multipass exec -n node23 -- sudo bash -c 'cat /etc/netplan/10-custom.yaml network: version: 2 ethernets: extra0: dhcp4: no match: macaddress: "52:54:00:4b:ab:23" addresses: [10.13.31.23/24] EOF' multipass exec -n node21 -- sudo netplan apply multipass exec -n node22 -- sudo netplan apply multipass exec -n node23 -- sudo netplan apply 使用node21作為Leader (Manager),與其他兩個node一起組成Cluster multipass exec -n node21 -- sudo docker swarm init --advertise-addr 10.13.31.21 multipass exec -n node21 -- sudo docker swarm join-token manager managerToken=$(multipass exec -n node21 -- sudo docker swarm join-token manager -q) multipass exec -n node22 -- sudo docker swarm join --token $managerToken 10.13.31.21:2377 multipass exec -n node23 -- sudo docker swarm join --token $managerToken 10.13.31.21:2377 Cluster就建立完成。 若想刪掉重來 multipass delete node21 multipass delete node22 multipass delete node23 multipass purge 備註 在直正使用時,大部份時間還需要做port forwarding。multipass沒有自己的port forward,可以用ssh tunnel來模擬。 例如把Ubuntu Server的8080指向node21的8080,可以這樣 sudo ssh -i /var/snap/multipass/common/data/multipassd/ssh-keys/id_rsa -L 0.0.0.0:8080:10.13.31.21:8080 ubuntu@10.13.31.21 完整的script可以參考initDockerCluster.sh。 沒有Bare Metal Ubuntu或者沒有static ip也可以參考initDockerClusterWithoutStaticIp.sh。只是因為network brandwidth問題,我就不會在每次更新時都測試。