docker

標籤:docker

Docker Tag 命名

潮流特區
MacauYeah ・2024-10-24

一般來講,同一個docker image會提供多個不同的版本,每個版本會附予不同的tag,以作標識。但以docker image的維護者來講,它的tag通常代表的是自己程式的版本號。不過這個版本號卻存在很多變數,就讓筆者好好地逐一說明。 程式的版本號 在沒有Docker的年代,其實所有軟件在發佈時,都會標示版本號,方便使用方明確追蹤問題,自行選擇升級、降級以解決相容性問題。大家要重現問題,也能清清楚地重現。所以docker image的tag,在某程度,都是代表發佈自己的程式版本號。但以前的年代,軟件底層的依賴,例如OS層面的共享程式庫,則不在發佈的管控中,所以過去的程式,在跨電腦安裝時,都會出現缺少某些共享庫的問題。而使用了Docker後,image以內的共享庫的都會在打包的那一刻固定和發佈,就不會有漏的問題。 庫更新,怎麼辦 上面說到image可以打包共享庫,但問題是共享庫也會有安全性更新問題,那麼對docker image的維護者來講,它自己的tag又該如何命名? 因為庫的量可大可少,所以一般來說,都不可能完全把各個庫的版本號寫在自己的tag上。退而求其次,就是用quot;版本號日期quot;,庫的細版本號,就存在原始碼當中。Ubuntu 就是這樣的例子。 不過quot;版本號日期quot;的命名方式真的方便嗎?每次下遊用戶想更新去最近版本,都要自己找一次最近的日期。這樣對很多用戶來講都不夠方便。所以docker又提供了一個重tag的功能。例如ubuntunoble,在早些時候指著noble20240904.1,然後過幾天,又指向更新的noble20241009。更常見的是latest,每次image都預設會存在,docker也希望大家會定期更新這個tag,讓大家可以更易地找到最新版本。 註 這跟git tag有所不同,git tag並不預期會變的。當協作者收到tag後,那怕上遊刻意更新tag指針,協作者沒有刪除原tag之前,都不會知道tag更新去了哪裏。 我們該如何選 在發佈方和引用方來講,引用時可以明確使用唯一的quot;版本號日期quot;,對穩定性來講是有意義的。不過多多少少,會產生額外的時間成本。發佈方來說,就是多用了一些儲存空間,方便引用方可以隨時找到舊庫版本。而引用方,就要手動修改引用號,作為驗收依據,自動更新的難度比較大。 但對於自動更新要求比較大的情況下,可能就是使用latest或者會隨時更新的share tag共用tag比較實際。但我們也依然要定一些方式去版本更新記錄,例如:同時使用 beta latest archive 每日自動更新beta,只有所有測試都通過時,才把archive指向現在的latest,再把latest指向現在的beta。這樣做的好處是,核心的docker stack檔案改變的機會較少,也可以免除docker swarm做太細緻的權限管理。

Swarm mode 上線 4 | IP 設定

潮流特區
MacauYeah ・2024-07-23

單機模式 IP設定 平常我們自己做測試,網絡功能通常用預設的就好。但當我們的Docker Container需要存取在區域網內的其他資源,避晚IP網段相衝是必需要的事。 大部份情況下,單機Docker使用的預設IP段會是 172.17.0.016 172.18.0.016 ... 若然現在區域網中,有一段172.18.0.024,大家不想Docker踩到其中,可以修改設定檔,加入預設的defaultaddresspools,以後它就只會從指定的區段使用。 # vim etcdockerdaemon.json quot;defaultaddresspoolsquot; quot;basequot; quot;172.17.0.016quot;, quot;sizequot; 24 , quot;basequot; quot;172.19.0.016quot;, quot;sizequot; 24 , quot;basequot; quot;172.20.0.016quot;, quot;sizequot; 24 其中base,是docker可以操作的總區域,size指的是Docker要自行分段的話,每段的大小是多少,上述的例子,就代表未來可能有以下Docker 網段。 172.17.0.024 172.17.1.024 ... 172.17.255.024 172.19.0.024 172.19.1.024 ... 172.19.255.024 172.20.0.024 172.20.1.024 ... 172.20.255.024 修改完設定後,重啟Docker就會生效。當然,重啟前,先刪除所有不在預設範圍的所有Container。 Swarm模式 IP設定 Swarm模式,與單機差不多,它需要在初始化Swarm就要定義,而且它不能與單機的網段有重疊。單機會預設使用Private IPv4 Class B,Swarm則是預設使用Private IPv4 Class A段,所以我們若就更改,就使用10.x.x.x吧。 docker swarm init defaultaddrpool 10.1.0.016 defaultaddrpoolmasklength 24 經上述例子初始化的 ingress 網段,將會是 10.1.0.024,隨後每個stack 則會是 10.1.1.024 10.1.2.024 10.1.3.024 重置Swarm 跟單機的情況類似,如果已建立Swarm後才修改網段,還是要整個刪掉重來。 每個節點都要執行以下指令。 docker swarm leave force 實測swarm leave這個指令也會把所有運行中的stack刪掉。 各節點重新建立swarm # in node 1, init new swarm with new ip docker swarm init defaultaddrpool 10.1.0.016 defaultaddrpoolmasklength 24 # in node 1, get new manager token docker swarm jointoken manager # in node 2 and node 3, join node 1 with new token docker swarm join token XXXXX YOUR_NEW_NODE1_IP2377 雙管齊下 如果大家同想要修定單機及Swarm的網段,還要留意有一個特別的網段docker_gwbridge。它雖然是Swarm的附帶產物,但它則是受單機的網段控制。也就是,如果大家有需要同時修改單機及Swarm的網段,則需要手動刪除Swarm及docker_gwbridge 在每個節點先刪掉舊有的Swarm及docker_gwbridge,並關掉docker docker swarm leave force docker network rm docker_gwbridge 在每個節點為docker_gwbridge修改設定,然後重起docker # vim etcdockerdaemon.json quot;defaultaddresspoolsquot; quot;basequot; quot;172.17.0.016quot;, quot;sizequot; 24 然後像前述一樣,重起Swarm。

Docker Image打包建議

潮流特區
MacauYeah ・2024-07-10

之前筆者有分享過兩個不同的Docker Image打包方式 App直接打包成Image 只把底層程式打包在Image中例如Tomcat,再用Docker Volume的方式讓Container可以起動App。 筆者就兩種方式做了一個條列式的對比。詳見連結 httpsmacauyeah.github.ioAProgrammerPreparesVMDockerNotesDeployDockerClusterCN.html 因為兩種方式筆者都有實作過,也算用了很段時間,所以也有一些實際經驗可以分享。 如果大家上正式的Docker課程,Docker導師通常會推薦為每個App打包成獨立Image,因為底層程式的Overhead通常不大,例如底層程式是Tomcat、Apache、Nignx這類網頁伺服器,重量級的開銷並不是因為多幾個Web Engine的分身造成,通常都是因為業務本身。但如果你講的底層程式是資料庫等的大型程式,才可能會有明顯的差異。 但實務上的建議,就是必需考慮自身的經驗,到底那個方案自己比較有把握。獨立打包App,在正式環境也需要考慮跟蹤問題的情況,多個不同App要溝通,也是了解Container網絡。如果打包底層程式,所有App都可以當成是本機下運行,更有信心追蹤問題,也是一個很好的出發點,到了有需要彈性改變不同App的需要,才轉向獨立打包的做法。 筆者最初也是走這個打包底層程式的方向,到了自己有信心試用Docker Swarm,才走向獨立打包的做法。筆者親身經驗,因為到了Docker Swarm,網段會變得暴增,這跟公司現有的內部網絡相衝的機會就會變多。在Swarm起立初時,筆者並沒有意識到這件事,所以當初排查問題,也花了一些時間才知道要向網段衝突上著手。 另一個出自Docker導師實務上的建議,就是正式環境中不要做用Docker compose,應該使用Docker Swarm。那怕Swarm只有一個節點,也應該用Swarm,導師的主要理據是Swarm有Rolling Update (滾動更新)的機制。同一個node也可以有多個分身,每個分身輪流更新,就不會出現大中斷的情況。筆者就自身經驗,Tomcat可以同時容納一個App的多個版本,Nginx也有Failover(故障轉移)等,如果你很熟這些功能,不一定要需要靠Swarm去提供。可以按自己步調去慢慢適應。

何謂 Infrastructure as code - IaC

潮流特區
MacauYeah ・2024-06-07

在雲端服務出現後,好多新的名字,或許大家都聽過,筆者也稍為再簡介一下。 Software as a Service Saas。就像我們的Web App,不用下載體件,可以直接經雲進行業務操作。 Platform as a service Paas。這個概念可能最含糊,筆者理解就是,雲端供應商提供一些底層的軟件,供IT人使用。像是資料庫,Web Engine。 Infrastructure as a Service Iaas。這個更底層,雲端供應商給出CPU, IP, Memory, Storage等,頂多就再多個預安裝OS的選項。IT人自己去配搭使用。 多得這些彈性服務,雲端應用才真的跟過去租用實體伺服器有所差異。 但對於IT人來講,要使用這麼多不同的服務,實在也不簡單。對於IT消費方,用錢換來實體硬件的靈活性,但因為硬件沒有邊界之後,軟件的量就暴增。管理也不能說是很方便。 在Docker, Kubernetes等Container容器出現後,又為這些管理問題帶來另一種希望,就是Infrastructure as code IaC。它的目標是,管理基礎設施,要像管理原始碼一樣,checkout 就可以回覆到指定狀態。 初聽之下,大家可能覺得好玄,但其實這個概念,在之前筆者的Docker 教學中,已經有出現過。Docker compose 、Docker stack 指令,它們都是基於yaml檔的IaC。 當筆者更新了yaml 檔,執行一次stack deploy ,docker 就會對比之前狀態,如果replica分身不夠多,就自動增加所欠數量,如果image 也更新了,就排隊輪流重起換image 。最重要的是,當我們checkout 舊的yaml 檔,回到過去某個狀況,只要還是執行同一句stack deploy ,系統就自然減少所需的replica數量,下戴過去的image。這就代表,我們對於container 構建而成的環境,都可以放入Git等版本控制中,整個管理模式,就像管理程式碼一樣GitOps。 對於更進階的Kubernetes更是如些,除了container外,多種不同的network,storage配置,都通過yaml檔進行控制。這樣,架構即使複雜,但只少可以測試、重現和管理。還有一個,它比Docker stack要強的是,它某程度上支緩刪除的概念。雖然不完全,但總比完全沒有方便。 這個IoC的概念,可能還未達到一定廣泛地應用的階段,但它的核心在於,基建項目有檢測試差異的功能,自動去因為這個差異去加或減資源。用Programmer的講法,就是系統有Diff的功能,自動多除少補。

Docker環境參數化 - Arg VS Env

潮流特區
MacauYeah ・2024-03-26

Docker Variable control 我們在Docker Image的打包時,最簡單當然就是每個步驟都使用最新版本。例如Docker Base Image,大家可能選用latest tag,安裝linux package (Linux包),也可能就apt install yum 安裝最新的穩定版本。但如果我們想要更好地做測試,就要使用指定版本,方便追蹤問題。而Docker在打包和運行時,都有不同的方式讓大家定義或覆寫指定參數。 Docker build arg 我們先從打包Image開始。 例如我們需要使用一個Base image為 ubuntu,版本預設為22.04,但有需要時可以經build指令覆寫,可以這樣寫 ARG ubuntu_version=22.04 FROM ubuntu$ubuntu_version # default ubuntu_version=22.04 docker image build t test2204 . # or overwrite by buildarg docker image build t test2404 buildarg=quot;ubuntu_version=24.04quot; 雖然Dockerfile的RUN指令都是使用linux shell,但在Dockerfile中想表達條件控制(if else statment)就不太易看。在外部加入script做控制,是另一個可行的後備選擇,它更可以連image名字也進行參數化。 # in bash script, you also can if $beta == true then ubuntu_version=24.04 else ubuntu_version=22.04 fi docker image build t test$ubuntu_version buildarg ubuntu_version=$ubuntu_version Docker Container Run and Docker Compose 一般來講,Linux Container 在執行時,就等於進入Linux Shell。也就是,我們可以使用Shell中的環境變數。 我們在打包Image前,已經可以在Dockerfile中定義自己的ENV數參(也就是環境變數)。與前面的Build Arg有所不同的是,ENV是定義在Dockerfile中,在Container運行時以環境變數的形式存在,它也可以在運行中被改變。而Arg,則只在打包Image時存在,運行期間就不存在了。(當然,你在打包時,用Arg傳入Env,以運到這個目的。) 另一個更特別的性質是,那怕ENV沒有定義在Dockerfile中,我們運行時也可以加入更多的環境變數,大家就當成是一般Linux操作,隨時在自己的shell中加入變數。 # e, env for inline variable # envfile for file docker container run e MYVAR1 env MYVAR2=foo envfile .env.list ubuntu bash 同樣地Docker compose,也支援環境變數。筆者建議environment可以使用Array格式,日後可以更方便地直接改為env_file。 # dockercompose.yaml services ubuntu image ubuntu22.04 environment RACK_ENV=development SHOW=true USER_INPUT 上述的寫法沒有任何問題,不過如果你的dockercompose.yaml是放在git等版本控制中,你更新環境變數就有可能會影響到其他人,這時你就會想轉成env_file。 dockercompose.yaml預設就會讀當前資料夾的.env,就算不存在,也可以正常運行。(當然,大家的ImageContainer應該要有預設值) # dockercompose.yaml services ubuntu image ubuntu22.04 # if env_file is not defined, it will load .env. # or you can load the specific file. # env_file # .a.env env_file內,每一行就是一個變數 # .env or a.env RACK_ENV=development SHOW=true USER_INPUT 使用預設的.env還有一個好處,就是我們可以把dockercompose.yaml也變成受環境變數控制。 # dockercompose.yaml with variable control, only works in default .env services ubuntu image ubuntu$ubuntu_version # .env ubuntu_version=22.04

龐大的Docker Logs該如何處理? | 傳統的syslog幫到你

潮流特區
MacauYeah ・2024-02-02

平常大家在做單機app時,寫log有很多選擇,最簡單就是寫在檔案中。但在docker container裏面,寫檔案時要注意怎樣保留log檔,避免因為重建container時不見了。 docker 大部份官方預設image,都把log導向至stdout和stderr。這是方便docker做管理,也方便大家使用統一的docker logs指令來查看,即使到了Swarm mode底下,docker service logs也是同樣原理,使用差異不大,頂多就是不保證log的實時性。 如果網路延遲不計較的話,最大問題也是logs怎樣保存的做法。預設就是container刪走的時候,logs也會一借走。單機模式下,沿用最普遍的方法寫log的做法不是不可行,只是考慮到在極端情況下,同一個node節點中,有可能同時運作同一個service服務的多個分身replica,這裏它們寫檔案時就有機會互相搶佔。 筆者認為,比較合理的是外部提供的服務,例如syslog,把寫檔的操作交給節點的Host OS處理。然後就保證好每筆log都會是一條完整的記錄。 以下就以linux Host裏面的syslog,為大家簡介一下設定的步驟。 設定docker 導向 syslog 把該主機的docker daemon etcdockerdaemon.json,設定使用syslog driver,並以特定的方式編寫syslog tag。 quot;logdriverquot; quot;syslogquot;, quot;logoptsquot; quot;tagquot; quot;dockercontainer.ImageName.Name.IDquot; 無腦設定已完成,重啟docker就可以了。 但為了日後管理方便,能把docker log放進獨立的一個檔案中,會更易找問題。所以我們可以進一步設定syslog。我們以Ubuntu 22.04為例,可以在etcrsyslog.d下增加一個設定檔etcrsyslog.d.conf,指定看到syslog tag以dockercontainer為首的記錄,都要獨立抽出來。 # file etcrsyslog.d51docker.conf syslogtag,startswith,quot;dockercontainerquot; varlogdockercontainer.log 為免有檔案權限問題,手動指定檔案的所有權後,才正式重啟syslog。然後所有相關記錄都會寫在varlogdockercontainer.log 滾滾滾滾滾動的log檔 檔案一天一天地長大,如果可以,還是自動清掉太舊的記錄為妙。Linux Syslog,通常也會配著logrotate使用。 筆者亦以Ubuntu 22.04為例子,做了個最簡單的自動滾Log功能。目標就是當log檔案大於1M後,就要重開log檔。舊的log檔最多保留7份,多了就刪掉最舊的。 # file etclogrotate.drsyslogdockercontainer varlogdockercontainer.log rotate 7 size 1M missingok notifempty compress delaycompress sharedscripts postrotate usrlibrsyslogrsyslogrotate endscript 加了設定後,什麼都不用重啟,因為它是Ubuntu 的排程動作,到執行時就會以最新的設定檔執行,詳見etccron.dailylogrotate. 有需要手動測試的話,需要手動呼叫usrsbinlogrotate。加入d參數後,會被視為debug mode,這是官方的說法,但因為debug mode沒有執行效果,更加像是linux中常見的dry run mode。

Oracle Database in Docker

潮流特區
MacauYeah ・2023-09-22

雖然筆者之前有提過,Docker並不是萬能,Docker在管理有狀態應用Stateful Application的情況下,只能走單機路線。但因為Docker實在很方便,所以連Oracle Database這類強狀態應用也有出Docker版本。當然,它在預設的情況下,只能在單機下操作。 不過即使在單機操作下,還是有一些跟其他Docker Image有差異的地方,需要特別拿出來聊聊。 假設根據官方的教學,跑起了一個oracle19c的Docker Container。再查看當中的Process,你會發現有一個內部PID為1的runOracle.sh 在Docker中這個PID為1的Process是很重要的,它是判斷整個Container有沒有運行的依據。它就是當初在Docker Image中Entrypoint或CMD指定的那個指令生起的Process。Docker daemon要進行停止指令,要停止container時,也是對著PID為1的那個process來處理。 一般的情況下,如果PID為1的那個process可以無腦地停了、重開,那一切都好辦。但在Oracle Database的情況下,就不適合。因為Database始乎都是有交易概念的Transaction,它的停止並不是殺了process就了事,它還要考慮HDD操作中,有那些可以被考慮為完成,有那些下次要還原undo、重做redo。如果殺了process就等於Oracle 的Shutdown Abort,有機會下次開機會,就會有交易異常而且無法決定該如何操作。 大家需要先進入Docker container,經sqlplus進行必要的關閉Database指令。但此時,PID為1的那個process,其實還在進行中,在Docker 層面,它就像是Docker Container還在正常運行中,只是Database離線了。又因為sqlplus關閉Database並不是馬上有結果的,所以在整體關閉時可能需要串連command。就像

Docker Swarm mode 指令教學 | docker service

潮流特區
MacauYeah ・2023-08-22

之前一直都討論Image 的打包形式,現在聊聊部署上線時的一些指令。 Docker Service swarm mode 主要通過quot;docker servicequot; 指令去產生一堆可以在不同節點上運行的container。為了更加形象地講,我把container稱為Image的分身。 docker service create跟docker container run的感覺很像,兩者都可以指定image # swarm mode $ docker swarm init $ docker service create name nginx_s nginx # container mode $ docker container run d name nginx_c nginx 兩者的差別在於docker service 可以指定多少個分身,可以隨時加減數目,而且如果你有多過一台機器,分身就會在不同的機器上遊走。而docker container就是只對本機有操作,也不會散播到其他機器。 # swarm mode $ docker service create replicas=2 name nginx_s nginx $ docker service ls ID NAME MODE REPLICAS IMAGE PORTS uro4rwy6nelh nginx_s replicated 22 nginxlatest $ docker service update replicas=5 nginx_s $ docker service ls ID NAME MODE REPLICAS IMAGE PORTS uro4rwy6nelh nginx_s replicated 55 nginxlatest # container mode $ docker container run d name nginx_c1 nginx $ docker container run d name nginx_c2 nginx $ docker container run d name nginx_c3 nginx $ docker container run d name nginx_c4 nginx $ docker container run d name nginx_c5 nginx $ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c45771f06612 nginx quot;dockerentrypoint.hellip;quot; 7 seconds ago Up 6 seconds 80tcp nginx_c5 a587a718da3a nginx quot;dockerentrypoint.hellip;quot; 9 seconds ago Up 9 seconds 80tcp nginx_c4 079f206f8645 nginx quot;dockerentrypoint.hellip;quot; 9 seconds ago Up 9 seconds 80tcp nginx_c3 e10dc525fd22 nginx quot;dockerentrypoint.hellip;quot; 10 seconds ago Up 9 seconds 80tcp nginx_c2 dcaa2b4bb3de nginx quot;dockerentrypoint.hellip;quot; 10 seconds ago Up 9 seconds 80tcp nginx_c1 在建立網段時也差不多,service需要的是overlay network,而container用一般network就可以。 # swarm mode $ docker network create driver overlay nginx_s_gateway $ docker service update networkadd name=nginx_s_gateway,alias=gateway nginx_s $ docker service ps nginx_s ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS fxqtheyvr914 nginx_s.1 nginxlatest dockertest Running Running 33 seconds ago u0pvj1leoizw _ nginx_s.1 nginxlatest dockertest Shutdown Shutdown 33 seconds ago q7arumjlxduv nginx_s.2 nginxlatest dockertest Running Running 36 seconds ago kurlwqfmopbg _ nginx_s.2 nginxlatest dockertest Shutdown Shutdown 37 seconds ago zd0zlkhxafv0 nginx_s.3 nginxlatest dockertest Running Running 40 seconds ago 3kapr00fs6pt _ nginx_s.3 nginxlatest dockertest Shutdown Shutdown 40 seconds ago 5o4afd3whygo nginx_s.4 nginxlatest dockertest Running Running 35 seconds ago oxocropolbo8 _ nginx_s.4 nginxlatest dockertest Shutdown Shutdown 35 seconds ago x5y94jf3ok51 nginx_s.5 nginxlatest dockertest Running Running 38 seconds ago cgld3au0w1i9 _ nginx_s.5 nginxlatest dockertest Shutdown Shutdown 39 seconds ago # container mode $ docker network create nginx_c_gateway $ docker network connect alias gateway nginx_c_gateway nginx_c1 $ docker network connect alias gateway nginx_c_gateway nginx_c2 $ docker network connect alias gateway nginx_c_gateway nginx_c3 $ docker network connect alias gateway nginx_c_gateway nginx_c4 $ docker network connect alias gateway nginx_c_gateway nginx_c5 不過比較大的差異是service會停了原有的分身,重開新的分身去加入網段。所以上面的docker service ps nginx_s執行結果,就有一半是停掉的。 類似地,docker service也不能單獨地停掉分身,頂多只能調整replicas=NUMBER,來控制分身數量。而單機則可以經過docker container stop來暫停分身。

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

潮流特區
MacauYeah ・2023-07-28

雖然筆者對於Docker Swarm Mode的資歷尚淺,但由於後期更動的難點越來越多,筆者很想早一點討論其中不同操作的差異 Docker Swarm Docker Swarm Mode其實是Docker提供的一個Cluster群集環境。在其中運行的Image,都可以比較方便地隨時分身到不同的node節點上,對於提高負載或可用性,都是一個不錯的解決。 只要該Image跑起的Container是Stateless前後兩次執行的結果互不相干涉,或者是把Stateful的部份有干涉的部份外包到第三方例如儲存空間使用NFS,或記憶體暫存改為KeyValue 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 imagecontainer原本就是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 最後,你在原來的dockercompose的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$PWDdocker.img name node21 network name=localbr,mode=manual,mac=quot;5254004bab21quot; multipass launch file$PWDdocker.img name node22 network name=localbr,mode=manual,mac=quot;5254004bab22quot; multipass launch file$PWDdocker.img name node23 network name=localbr,mode=manual,mac=quot;5254004bab23quot; 對運行中的三個node,為它們設定static ip multipass exec n node21 sudo bash c 'cat etcnetplan10custom.yaml network version 2 ethernets extra0 dhcp4 no match macaddress quot;5254004bab21quot; addresses 10.13.31.2124 EOF' multipass exec n node22 sudo bash c 'cat etcnetplan10custom.yaml network version 2 ethernets extra0 dhcp4 no match macaddress quot;5254004bab22quot; addresses 10.13.31.2224 EOF' multipass exec n node23 sudo bash c 'cat etcnetplan10custom.yaml network version 2 ethernets extra0 dhcp4 no match macaddress quot;5254004bab23quot; addresses 10.13.31.2324 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 advertiseaddr 10.13.31.21 multipass exec n node21 sudo docker swarm jointoken manager managerToken=$multipass exec n node21 sudo docker swarm jointoken manager q multipass exec n node22 sudo docker swarm join token $managerToken 10.13.31.212377 multipass exec n node23 sudo docker swarm join token $managerToken 10.13.31.212377 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 varsnapmultipasscommondatamultipassdsshkeysid_rsa L 0.0.0.0808010.13.31.218080 ubuntu@10.13.31.21 完整的script可以參考initDockerCluster.sh。 沒有Bare Metal Ubuntu或者沒有static ip也可以參考initDockerClusterWithoutStaticIp.sh。只是因為network brandwidth問題,我就不會在每次更新時都測試。