SpringBoot微服務編寫Dockerfile流程及問題匯總

背景

跟 Docker 磕了兩天,將一個包含 N 個微服務的應用部署包改造,使其能夠生成 Docker 鏡像,并在 Docker 容器中運行。幾年前玩過 Docker,隱約記得幾個命令「Dockerfile 命令:黑卡飲料、山楂果費、哦SUV,機器學習」,項目中用不到,早忘光了。

開著 metaso,一路追問了兩天,終于搞定了這個應用的 Dockerfile 編寫,卡住的點:

  1. 多層級命令結構下,啟動腳本中的 . 的相對路徑問題,它相對的是 WORKDIR 而不是當前執行腳本路徑。
  2. 如何查看容器中運行程序的 logs 日志?非 Docker 命令輸出到控制臺的日志,而是 SpringBoot 應用通過 logback 組件寫入到文件系統的日志。
  3. SpringBoot 應用配置文件中的變量,如何通過 Docker 運行命令傳遞并接收?基于 Nacos Config 的應用,容器運行時需要傳遞 Nacos 的信息。
  4. 外部宿主機怎么訪問容器中的 Web 應用?
  5. 包含驗證碼的應用使用了 sun.awt.X11FontManager 繪圖異常,怎么調整 JDK鏡像?
  6. 一個容器中啟動 N 個微服務 VS 每個容器啟動一個微服務?
  7. 保證容器運行時不出現 Exited 狀態的關鍵語句 tail -f /dev/null

需求描述

我有一個應用目錄 myApp,下面有一個 appA,包含 bin/start.sh bin/stop.sh,Dockerfile。appA 需要引用到 myApp 目錄的文件,現在需要對這個目錄打鏡像包含父級目錄,而Dockerfile 位于子目錄 appA中,怎么實現呢?

向秘搜AI輸入上面的提問,它梳理出應用的目錄結構如下:

	myApp/├── commonJar├── bin/│   ├── startAll.sh│   └── stopAll.sh		├── appA/│   ├── bin/│   │   ├── start.sh│   │   └── stop.sh│   └── Dockerfile│   └── bootstrap.yml		│   └── appA.jar	├── appB/│   ├── bin/│   │   ├── start.sh│   │   └── stop.sh│   └── Dockerfile│   └── appB.jar├── appC/│   ├── bin/│   │   ├── start.sh│   │   └── stop.sh│   └── Dockerfile│   └── appC.jar		└── Dockerfile

要實現將 myApp 目錄及其子目錄 appA 打包成 Docker 鏡像,并且 appA 中的 Dockerfile 需要引用 myApp 目錄下的文件,可以按照以下步驟進行操作:

  1. 構建上下文:Docker 構建時需要一個構建上下文(context),這個上下文是一個目錄,Dockerfile 中的所有 COPY 和 ADD 指令都會相對于這個目錄來查找文件。因此,我們需要將 myApp 目錄作為構建上下文。
  2. 指定 Dockerfile 路徑:由于 Dockerfile 位于 appA 子目錄中,我們需要使用 -f 參數來指定 Dockerfile 的路徑。
  3. 編寫 Dockerfile:在 Dockerfile 中,使用相對路徑來引用 myApp 目錄下的文件。

編寫Dockerfile

單獨為每個模塊編寫 Dockerfile,以模塊 appA 為例,編寫如下內容:

#use jdk
FROM eclipse-temurin:8-jre-alpine#work dir in docker.
RUN mkdir /opt/myApp
WORKDIR /opt#copy all content in myApp/* to /apps.
COPY . myApp#grant start.sh and stop.sh
RUN chmod +x /opt/myApp/appA/bin/start.sh#expose all ports for appA
EXPOSE 8080ENTRYPOINT ["/opt/myApp/appA/bin/start.sh"]
CMD ["in"]

調整 appA/bin/start.sh 啟動腳本,之前定位 appA.jar 是通過相對路徑,直接在 Linux 運行正常,使用 Docker 容器運行時,由于工作目錄設置的是父級 myApp ,相對路徑也是相對工作目錄的,所以直接啟動會出現 appA.jar 文件不存在。

此外,啟動時由于服務內部使用日志框架將日志輸出到 appA/logs 目錄了,所以忽略了控制臺日志,要想保證容器不退出,必須讓啟動腳本處于掛起狀態,通過一個啟動參數控制。

調整啟動腳本如下:

#!/bin/sh
basePath=$(cd `dirname $0`; pwd)
echo "basepath is $basePath"#change dir to appA ,which is .. of start.sh path
cd $basePath/..# start appA.jar use nohup & and ignore console log
loadPath=../commonJar
nohup java -Xmx512m -Dloader.path=$loadPath -jar -Dlogging.config=./logback-spring.xml  appA.jar >/dev/null 2>&1 &#hold on if has parameter 
if [ -n "$1" ]; thenecho '$1 is not empty, holding on for container'tail -f /dev/null
fi

此外,應用的 Nacos 參數需要容器通過設置環境變量的方式接收,因此修改應用的配置文件 bootstrap.yml ,使用環境變量接收:

spring:cloud:nacos:# nacos 服務器地址server-addr: ${address}# nacos 配置中心config:enabled: trueusername: ${username}password: ${password}# 引用的配置文件所屬的命名空間,public時必須注掉,非public可以放開并修改為目標名稱namespace: ${namespace}

這就編寫好了模塊 appA 的 Dockerfile 文件了,進入根目錄 myApp 下依次創建鏡像、運行容器、停止容器、刪除容器、刪除鏡像。啟動 DockerDesktop,

第一步,進入應用根目錄 cd /xxx/myApp

第二步,運行構建命令:docker build -t appa -f appA/Dockerfile . 。構建完成后,執行 docker images 查看鏡像:
在這里插入圖片描述
第三步,執行容器啟動:docker run -d -e address=IP:port -e username=xxx -e password=xxx -e namespace=nonPublic -p 8080:8080 -v /Applications/dockerlogs:/opt/myApp/appA/logs --name appa appa
等待容器啟動后,使用 docker ps -a 查看容器狀態,正常是 Up :
在這里插入圖片描述
第四步,停止容器:docker stop d8ec9fbf8f49
在這里插入圖片描述

第五步,刪除容器:docker rm d8ec9fbf8f49,只能針對 Exited 狀態的容器進行刪除。

第六步,刪除鏡像:docker rmi 616b785f371e,只能針對沒有容器運行的鏡像進行刪除。

Docker 操作匯總

針對每個應用提供一個 docker 操作腳本,方便操作,匯總 docker 腳本如下

  1. 根目錄下創建鏡像:docker build -t myapp .,針對當前文件目錄下的 Dockerfile進行編譯,且鏡像名稱必須小寫
  2. 在父級別目錄中對子模塊構建:docker build -t appa -f appA/Dockerfile .
  3. 后臺進程方式運行容器:docker run -d -e address=IP:port -e username=xxx -e password=xxx -e namespace=nonPublic -p 8080:8080 -v /Applications/dockerlogs:/opt/myApp/appA/logs --name appa appa ,容器環境變量、掛載日志文件,開放宿主機端口和容器端口一致。
  4. 查看容器:docker ps -a
  5. 刪除容器:docker rm containId
  6. 刪除鏡像:docker rmi imageId
  7. 查看鏡像:docker images
  8. 查看日志:docker logs appa【容器名稱】僅shell 執行時的控制臺日志
  9. 針對運行狀態的容器,可以打印容器中日志目錄下的文件:docker exec -it containId /opt/myApp/appA/logs/a.log
  10. 存儲鏡像: docker save -o appA.tar appA:latest

啟示錄

第一點,糾結一個問題 「一個容器中啟動 N 個微服務 VS 每個容器啟動一個微服務?」根據 Docker容器的設計思想:

  1. 一次構建,到處運行"的可移植性
  2. 輕量高效的資源利用
  3. 微服務友好的架構哲學,單一職責原則:每個Container僅運行一個主進程(如Nginx/MySQL),通過組合多個Container完成復雜應用,天然契合微服務拆分。
  4. 開發即生產的生命周期管理
  5. 開放生態的擴展性

比較好的實踐方式是一個微服務一個鏡像,獨立容器啟動。那么之前的部署方式一臺服務器上三個服務運行的方式就不可行了。但是如果硬是這么實踐,也是沒問題的吧,畢竟通過瘦身包方式部署的,微服務共用了通用 jar 包。

一個容器里面運行 N 個微服務的 Dockerfile 文件就編寫在根目錄 myApp 中,然后逐次調用子模塊的 start.sh 腳本進行啟動,只用對根目錄的應用打一個鏡像就可以了。小公司的單體多模塊的應用,就沒必要打 N 個鏡像了。

但是需要注意在一個容器中同時啟動的微服務的個數,如果過多的話,可能 Docker 容器運行有資源約束,可能有些服務啟動會失敗。

第二點,JDK 選擇上面,本來所有模塊統一用輕量級 eclipse-temurin:8-jre-alpine 可以的,單有一個包含驗證碼的模塊,這個精簡鏡像存在字體缺失問題,所以對該模塊使用 openjdk:17-jdk 鏡像。

最后一點,docker run 命令的參數 -v 必須在 --name 之前。用了 Docker 容器管理后,程序就不需要提供 stop 腳本了,直接通過容器的 stop 命令就可以停止應用。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/906528.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/906528.shtml
英文地址,請注明出處:http://en.pswp.cn/news/906528.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

pytorch語法學習

啟動 python main.py --config llve.yml --path_y test -i output

基于LiveData和ViewModel的路線管理實現(帶PopupWindow刪除功能)

包含RecyclerView綁定、PopupWindow刪除功能和SharedPreferences持久化存儲。 1. RouteInfo類(實現Parcelable接口) java 復制 下載 import android.os.Parcel; import android.os.Parcelable;public class RouteInfo implements Parcelable {private Integer routeID;p…

jvm安全點(二)openjdk17 c++源碼垃圾回收安全點信號函數處理線程阻塞

1. 信號處理與樁代碼(Stub)?? 當線程訪問安全點輪詢頁(Polling Page)時: ??觸發 SIGSEGV 信號??:訪問只讀的輪詢頁會引發 SIGSEGV 異常。??信號處理函數??:pd_hotspot_signal_handl…

如何用數據可視化提升你的決策力?

在數字化浪潮席卷全球的當下,數據已然成為企業和組織發展的核心資產。然而,單純的數據堆積猶如未經雕琢的璞玉,難以直接為決策提供清晰有力的支持。數據可視化作為一種強大的工具,能夠將海量、復雜的數據轉化為直觀、易懂的圖形、…

VoiceFixer語音修復介紹與使用

一.簡介 VoiceFixer 是一款基于深度學習的通用語音修復工具,主要用于恢復嚴重退化的語音信號,支持降噪、消除回聲、提升音質等功能。 二.核心功能 1.語音修復與增強 VoiceFixer 采用端到端的神經網絡模型,能夠處理多種語音退化問題&#x…

Vue百日學習計劃Day19-20天詳細計劃-Gemini版

重要提示: 番茄時鐘: 每個番茄鐘為25分鐘學習,之后休息5分鐘。每完成4個番茄鐘,進行一次15-30分鐘的長休息。動手實踐: DevTools 的使用和 Git 命令的掌握都需要大量的實際操作。請務必邊學邊練。環境準備&#xff1a…

Qt初識.

認識 QLabel 類,能夠在界面上顯示字符串. 通過 setText 來設置的。參數 QString (Qt 中把 C 里的很多容器類,進行了重新封裝。歷史原因) 內存泄露 / 文件資源泄露對象樹. Qt 中通過對象樹,來統一的釋放界面的控件對象. Qt 還是推薦使用 new 的…

WebGPU 圖形計算

以下是關于 WebGPU 圖形計算的基本知識點總結: 一、WebGPU 核心定位與優勢 1. 與傳統技術對比 維度WebGLWebGPU架構設計OpenGL ES 封裝現代圖形API抽象(Vulkan/Metal/D3D12)多線程支持單線程渲染多線程并行計算計算能力有限通用計算完整計算管線支持資源控制隱式狀態管理顯…

視覺基礎模型

2.1 視覺的“大模型”時代:ViT的誕生與革新 在計算機視覺領域,卷積神經網絡(CNN)曾是當之無愧的霸主。從LeNet到ResNet,CNN在圖像分類、目標檢測等任務上取得了巨大成功。然而,隨著Transformer模型在自然語…

【React Native】快速入門

對于移動端應用來說,開發 Android 應用使用的語言有 java 和 kotlin,開發 ios 應用使用的語言有 obj-c 和 Swift 。因此,我們使用 react-native 編寫一套代碼進行跨端開發。 構建項目: npx create-expo-applatest安裝 nativewin…

AR 開啟昆蟲學習新視界,解鎖奇妙微觀宇宙

在傳統昆蟲學習中,課堂教學是主要方式,老師通過板書、PPT 傳授知識,但學生被動接受,書本靜態圖片無法展現昆蟲真實比例、立體形態,學生難以直觀感受復雜身體結構。博物館的昆蟲標本也是學習途徑,不過標本放…

BI 大屏是什么意思?具體應用在哪些方面?

目錄 一、BI 大屏的定義與內涵 1. 基本概念 2. 核心要素 3. 特點優勢 二、如何搭建高效的 BI 大屏 1. 明確需求與目標 2. 選擇合適的 BI大屏工具 3. 數據整合與清洗 4. 設計可視化界面 5. 持續優化與更新 三、BI 大屏在企業運營管理中的應用 1. 銷售與營銷領域 2.…

Kafka Go客戶端--Sarama

Kafka Go客戶端 在Go中里面有三個比較有名氣的Go客戶端。 Sarama:用戶數量最多,早期這個項目是在Shopify下面,現在挪到了IBM下。segmentio/kafka-go:沒啥大的缺點。confluent-kafka-go:需要啟用cgo,跨平臺問題比較多,交叉編譯也…

Axure全鏈路交互設計:快速提升實現能力(基礎交互+高級交互)

想讓你的設計稿像真實App一樣絲滑?本專欄帶你玩轉Axure交互,從選中高亮到動態面板騷操作,再到中繼器表單花式交互,全程動圖教學,一看就會! 本專欄系統講解多個核心交互效果,是你的Axure交互急救…

自動化測試腳本點擊運行后,打開Chrome很久??

親愛的小伙伴們大家好。 小編最近剛換了電腦,這幾天做自動化測試發現打開Chrome瀏覽器需要等待好長時間,起初還以為代碼有問題,或者Chromedriver與Chrome不匹配造成的,但排查后發現并不是!! 在driver.py中…

現代人工智能系統的實用設計模式

關鍵要點 AI設計模式是為現代AI驅動的軟件中常見問題提供的可復用解決方案,幫助團隊避免重復造輪子。我們將其分為五類:提示與上下文(Prompting & Context)、負責任的AI(Responsible AI)、用戶體驗&…

經典面試題:TCP 三次握手、四次揮手詳解

在網絡通信的復雜架構里,“三次握手”與“四次揮手”仿若一座無形的橋梁,它們是連接客戶端與服務器的關鍵紐帶。這座“橋梁”不僅確保了連接的穩固建立,還保障了連接的有序結束,使得網絡世界中的信息能夠順暢、準確地流動。 在面…

食品飲料行業AI轉型趨勢分析與智能化解決方案探索?

一、行業洞察:AI驅動食品飲料行業價值重構? 當前,食品飲料行業正面臨消費分級顯性化、需求多元化與技術范式革新的三重挑戰。根據《2024食品飲料行業全營銷白皮書》,高收入群體傾向于高端化、個性化產品,而下沉市場更關注性價比…

Electron使用WebAssembly實現CRC-8 ITU校驗

Electron使用WebAssembly實現CRC-8 ITU校驗 將C/C語言代碼,經由WebAssembly編譯為庫函數,可以在JS語言環境進行調用。這里介紹在Electron工具環境使用WebAssembly調用CRC-8 ITU格式校驗的方式。 CRC-8 ITU校驗函數WebAssembly源文件 C語言實現CRC-8 I…

python如何遍歷postgresql所有的用戶表

要遍歷PostgreSQL數據庫中的所有用戶表,可以按照以下步驟操作: 安裝必要依賴庫 pip install psycopg2-binary使用標準SQL查詢方案(推薦) import psycopg2def list_user_tables():try:conn psycopg2.connect(host"your_ho…