iT邦幫忙

2024 iThome 鐵人賽

DAY 30
0
Modern Web

Go 快 Go 高效: 從基礎語法到現代Web應用開發系列 第 30

【Day30】將服務推上 Docker Hub II | 打包 Docker image + 學習歷程感想

  • 分享至 

  • xImage
  •  

前言

昨天帶大家認識了什麼是 Docker?後,今天就來分享如何把我們寫過的專案推上 Docker Hub 為整個社群貢獻一份心力吧!

Docker 運作流程

這是一套把專案建置成容器的過程,但我們其實只需要轉成映像檔就能順利地推上 Docker Hub,但我還是會帶大家完整做一次,那我們就開始吧!/images/emoticon/emoticon42.gif

#
(圖片來源:https://medium.com/swlh/understand-dockerfile-dd11746ed183)

撰寫 Dockerfile ⭐️⭐️⭐️

首先我們需要在我們的專案下在額外創建一個Dockerfile的檔案(跟我們之前介紹到的 Makefile 是同一個意思)

https://ithelp.ithome.com.tw/upload/images/20241006/20161850w0sUT33FVA.png

如果是用 GoLand 開發的,可以很輕鬆的直接建立現成模板。

# 第 1 階段:建置階段
FROM --platform=$BUILDPLATFORM golang:1.23.2-alpine3.20 AS builder

# 設定工作目錄
WORKDIR /app

# 定義目標作業系統和架構的建置參數
ARG TARGETOS
ARG TARGETARCH

# 定義 Go 快取的建置參數
ARG GOCACHE=/app/.cache/go-build
ARG GOMODCACHE=/app/.go/pkg/mod

# 設定 Go 的環境變數
ENV GOCACHE=${GOCACHE} \
    GOPATH=/app/.go \
    GOMODCACHE=${GOMODCACHE}

# 複製 go.mod 和 go.sum 檔案
COPY go.mod go.sum ./

# 使用快取下載相依套件
RUN --mount=type=cache,target=${GOMODCACHE} \
    go mod download

# 複製專案的所有檔案
COPY . .

# 建立快取目錄
RUN mkdir -p ${GOCACHE} ${GOMODCACHE}

# 使用快取建置 Go 應用程式
RUN --mount=type=cache,target=${GOCACHE} \
    --mount=type=cache,target=${GOMODCACHE} \
    CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o my-first-go-service

# 第 2 階段:最終映像
FROM alpine:3.20

# 設定工作目錄
WORKDIR /root/

# 從建置階段複製編譯好的二進位檔
COPY --from=builder /app/my-first-go-service .

# 開放應用程式的埠號
EXPOSE 8080

# 定義預設的執行指令來啟動應用程式
CMD ["./my-first-go-service"]

(無關緊要的小提示:程式區段因為沒有 Dockerfile 的語法高亮格式,所以在尋找格式的途中,突然發現 swift 可以直接無縫銜接上,不愧是我大🍎,太神啦XD)
(無關緊要的小提示2:因為swift的註解是 // ,但是 Dockerfile 的註解是 # 所以如要直接使用上面內容,請手動修正註解~)

第一段的 From 我是從 (📎Golang 官方映像檔)中尋找的,如果版本過時了,請再從此連結中查看最新版的寫法。

關鍵字 描述
FROM 指定基礎映像檔,AS 用於命名階段,方便多階段建置中引用該階段。
WORKDIR 設定 Docker 容器中的工作目錄,後續指令會在該目錄下執行。
ARG 定義建置過程中的參數,這些參數可以在建置過程中設置特定值。
ENV 設定環境變數,這些變數在容器執行期間會被保留並使用。
COPY 將檔案或目錄從本地檔案系統複製到容器內指定的路徑。
RUN 執行指定的命令,例如安裝相依套件、建置程式等。在建置階段時運行,並將結果保存到映像檔中。
--mount=type=cache 用於快取目錄,減少重複下載或建置相依檔案的時間。
CGO_ENABLED 設定 Go 編譯選項,用來控制是否啟用 CGO(C 語言擴展)。
GOOS 設定要編譯的 Go 應用程式的目標作業系統(例如 Linux、Windows)。
GOARCH 設定要編譯的 Go 應用程式的目標架構(例如 amd64、arm64)。
EXPOSE 宣告容器中開放的埠號,這通常用來告訴其他開發者該應用程式會在哪個埠上運行。
CMD 指定容器啟動時要執行的命令。

參考資料:https://itnext.io/blazing-fast-golang-docker-builds-1e8829f743ca


構建 Docker 映像檔 ⭐️⭐️

從這裡開始,以下內容皆在專案下的 terminal 執行

  • 首先我們需要先檢查本地裝置的Go 緩存路徑在哪裡
go env GOCACHE GOMODCACHE
</* Output: */>
/Users/imac/Library/Caches/go-build
/Users/imac/go/pkg/mod
  • 設定環境變數
# 設置 GOCACHE 的路徑
export GOCACHE=<#LOCAL_GOCACHE#>

# 設置 GOMODCACHE 的路徑
export GOMODCACHE=<#LOCAL_GOMODCACHE#>
  • 建置 Docker 映像檔
docker build --no-cache --compress \
  --platform <#platform1#>,<#platform2#> \
  --build-arg GOCACHE=${GOCACHE} \
  --build-arg GOMODCACHE=${GOMODCACHE} \
  -t <#DOCKER_HUB_USERNAME#>/<#IMAGE_NAME#>:<#IMAGE_TAG#> .
# example
docker build  --no-cache --compress --platform linux/amd64,linux/arm64 --build-arg GOCACHE=${GOCACHE} --build-arg GOMODCACHE=${GOMODCACHE} -t mia1001/my-first-service:latest . 
  • --no-cache:強制不使用本地快取來進行映像的建構。雖然這會拖慢建置速度,但是這麼做可以減少外部因素導致建置映像檔失敗的問題。
  • --compress:這個選項可以減少建構的映像大小,透過壓縮圖層來優化映像
  • --platform linux/amd64,linux/arm64:platform 讓我們能建置多平台的映像檔(小提示:這裡的多平台指的是不同架構的CPU,我們的 OS 還是只能為同一個,因為我們在前面的 Dockerfile 開頭就是指定我們可以運行的 OS 類型了)
  • --build-arg:建置時參數。這些參數會被傳遞到 Dockerfile 中,可以用來設定一些環境變數,並且僅在映像檔建置過程中有效。
  • t:標記映像檔,格式為 username/repository:tag。latest 是標籤,可以根據需要更改。
  • 最後的.:表示 Dockerfile 位於當前目錄。

<#內容#>:這是在 Xcode 裡面可以去替換內容的寫法,以下都用這種方式來做替換說明。

注意事項

不同 Docker 平台架構(📎參考資料

Linux 架構

  • linux/arm64:
    • 說明:代表 64 位元的 ARM 架構。ARM 通常用於移動設備或低功耗伺服器上,這個架構被廣泛應用於像是 Raspberry Pi 或手機上,還有 Apple Silicon。
  • linux/amd64:
    • 說明:指的是 64 位元的 x86 架構,這是桌面電腦和伺服器最常用的架構之一,尤其是 Intel 和 AMD 的處理器,Apple Silicon 可以透過 Rosetta 2(用於模擬 x86 指令)/ qemu(模擬其他架構Ex:amd64/v2)來做使用。
  • linux/amd64/v2
    • 說明:表示 64 位元 x86 架構的第二版本,通常會包含更多現代處理器的指令集支持。(因為新的 CPU 有時候會更新架構,所以會有版本之分,通常是不能向下相容,除了無版本是屬於通用型的,如果不是很明白的話,希望這篇問題紀錄能幫助你更好理解。)
  • linux/riscv64:代表 64 位元的 RISC-V 架構,這是一個開放指令集架構,正在快速發展,尤其是在開源硬體和嵌入式系統中。
  • linux/ppc64le
    • 說明:代表 PowerPC 64 位元的「小端序」架構(LE,Little Endian),這種架構主要應用在 IBM Power 系列伺服器中。
  • linux/386
    • 說明:支援 32 位元的 x86 架構(IA-32),適用於較舊的硬體或特定的嵌入式設備。
  • linux/arm/v7
    • 說明:支援 32 位元的 ARMv7 架構,常見於 Raspberry Pi 3 及以下版本。
  • linux/s390x
    • 說明:支援 IBM Z 系列的大型機架構,適用於企業級應用。
  • linux/mips64le
    • 說明:MIPS 64 位元的小端序架構,這是一種常見於路由器或嵌入式系統的架構。

Windows 架構

  • windows/amd64
    • 說明:支援 64 位元的 Windows 作業系統,適用於大多數現代 Windows 伺服器和桌面環境。
  • windows/arm64
    • 說明:支援 64 位元的 Windows ARM 架構,適用於使用 ARM 處理器的 Windows 設備,如部分 Surface 系列。

簡化 platform 指令

因為我們的 platform 正常來說都會搭配 buildx 來做使用,但是你可以透過下列步驟來省去這個麻煩事項。

  • 首先確保更新到最新版的 Docker app,然後我們從右下方的通知中,來去找到 Multi-platform image 下的 Enable 選項來做開啟。

https://ithelp.ithome.com.tw/upload/images/20241007/20161850WoSefst0zu.png

  • 點擊 Enable and restart 就完成了!

https://ithelp.ithome.com.tw/upload/images/20241007/20161850JvmN65fTrN.png


測試 Docker 映像檔

在推送到 Docker Hub 之前,我們可以先在本地測試映像檔是否運行正常。

docker run -d \
  -p <#CONTAINER_PORT#>:<#LOCAL_PORT#> \
  --name <#CONTAINER_NAME#> \
  <#DOCKER_HUB_USERNAME#>/<#IMAGE_NAME#>:<#IMAGE_TAG#>
# example
docker run -d -p 8080:8080 --name my-go-app-container mia1001/my-first-go-service:latest
  • -d:以分離模式運行容器。
  • -p:將容器的 8080 端口映射到本地的 8080 端口(根據您的應用調整)。
  • --name:為容器命名。
  • mia1001/my-first-go-service:latest:指定要運行的映像檔。

可以通過訪問 http://localhost:8080 來檢查應用是否正常運行。

  • 停止並移除容器:

如果確認都正常的話,我們可以從 Docker app 來做這步驟,或是你想用下面指令也可以。

// 停止正在運行的容器
docker stop <#CONTAINER_NAME#>

// 移除容器
docker rm <#CONTAINER_NAME#>

登錄 Docker Hub

這不是確保我們能正常推送服務到我們自己的帳號下。

docker login

如有需要,系統將提示您輸入 Docker Hub 的使用者名稱和密碼。


推送 Docker 映像檔到 Docker Hub

docker push <#DOCKER_HUB_USERNAME#>/<#IMAGE_NAME#>:<#IMAGE_TAG#>
# example
docker push mia1001/my-first-go-service:latest

推送過程中,Docker 將上傳映像檔的各個層(layers)。根據映像檔的大小和網絡速度,這可能需要一些時間。


驗證映像檔在 Docker Hub 上(📎點擊此處並登入)

  • 如此圖,有出現就代表成功了
    https://ithelp.ithome.com.tw/upload/images/20241007/20161850hoGNSE9ZDF.png

  • 我們點進去後也可以看到我們當前服務支援的平台有哪些

小提示: IMAGE_TAG 的用處就在於,我們可以很清楚知道其他人的映像檔中,不同 TAG 所支援的平台有哪些。

https://ithelp.ithome.com.tw/upload/images/20241007/20161850Gk2GDgdjjU.png


從 Docker Hub 拉取並運行映像檔

docker pull <#DOCKER_HUB_USERNAME#>/<#IMAGE_NAME#>:<#IMAGE_TAG#>
docker run -d -p <#CONTAINER_PORT#>:<#LOCAL_PORT#> <#DOCKER_HUB_USERNAME#>/<#IMAGE_NAME#>:<#IMAGE_TAG#>
# example
docker pull mia1001/my-first-go-service:latest
docker run -d -p 8080:8080 mia1001/my-first-go-service:latest

恭喜你!完成這最後一步後,你就能算是另一種形式的開源家了~


30天心路歷程

(前提:我明明都是很認真在做分享,但大家好像對閒話比較感興趣,真是奇怪/images/emoticon/emoticon20.gif
今年會想挑戰寫Go是因為,我也是在今年寒假才開始接觸 Golang ,雖然學過幾個月的時間,可是沒有能用在開發的地方,而且當初在學習時還沒有養成寫筆記的習慣,於是就順道寫個鐵人賽當複習,還能順便研究一下沒碰觸過的領域好像也蠻不錯的(雖然每次好像都遊走在快斷賽的邊緣)?
在這30天之中,我感覺自己有比較會去撰寫一篇教學文(前面跟後面的風格差蠻多的,但我也懶得再去調整了XD),而且很高興的部分在於,自己能從那個每天看網路上各大文章的人,轉變成分享自己的學習與收穫,那感覺確實蠻不錯的,而且在寫分享文時,總會有一股動力推著自己去嘗試研究沒接觸過的方向(畢竟我研究不出來就真的要斷賽了/images/emoticon/emoticon06.gif)。
總結而言,如果看完後這30天的教學後,想在這條路上精進的,可以多加閱讀(不同版本更新的內容)(但我通常很懶,只想看別人介紹)如[這篇] / [另一篇],或是也可以參加一年一次的GopherDay,我也有參加今年的GopherDay,雖然我感覺自己好像聽的一知半解(可能跟我太菜有關),但我還是能被現場的熱情給吸引,而且他的紀念衣我也好喜歡穿著它,總感覺穿上後就莫名有熱誠開發了?
那我的建議大概就到這邊,感謝各位觀看這30天的歷程,有緣在跟大家相見。/images/emoticon/emoticon11.gif


上一篇
【Day29】將服務推上 Docker Hub I | Docker 介紹
系列文
Go 快 Go 高效: 從基礎語法到現代Web應用開發30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言