在介紹完 Linux 後,今天我們要來介紹 Container 技術,但是在開始之前,我們先來打包之前製作的 Spring Boot 專案,並設置一台 Ubuntu Server,然後把 Jar 部署到上面,運行我們的後端程式。
如果你是 Java 的開發人員,那有很高的可能你的書架上會有一本 Java 的書,叫做 Java SE XX版 技術手冊 -By 林信良,其中在第一章的 Java 平台概論就提到:
JVM 是 Java 程式唯一認識的作業系統,其可執行檔為 .class 檔案
也就是說,一台裝有 JRE (Java Runtime Environment) 的作業系統,便可以執行由 Java 撰寫並編譯後的檔案,達到跨平台的功效。
當然開發完成後,我們並不會將 .class 檔一個一個交出去,而是會將他們封裝為 Jar 檔案。在建立 Spring Boot 專案的時候,Spring Boot 的框架預設就提供了一套打包的機制,會自動引入 spring-boot-maven-plugin,來實現將 Spring Boot 專案打包成可執行的 jar 檔。
在開發完成後,我們僅需右鍵點選專案,點選 Run As => Maven install,即可在專案的 target 目錄下找到生成的 Jar 檔。不過這個流程其實牽扯到 Maven 的生命週期,等於在這過程中一路從 clean、compile 一路到 jar 的打包。
另外,也能夠再傳案點選右鍵 Show in Local Termainal,以 Common Line 的形式輸入 maven 的指令。
mvn package
如果你在公司看到 Pipeline 內出現 -DskipTests ,那 你最好快跑 表示在打包的過程中略過單元測試。
本次我們將安裝 Ubuntu Server 20.04 LST,昨天我們提到 Ubuntu 是 Linux 的一個發行版本,終歸要運行在一台機器上,我們可以選用虛擬機 (Virtual Machine) 或是實體機,今天,我就以實體機作範例,我出我家封藏已久的 Aspere one 小筆電安裝 Ubuntu Server 20.04 LST 版本 (後來不堪負荷改成 dell 小電腦)。
關於安裝的步驟就不多做講解,大致上與灌電腦系統一致,將硬碟清空,並把安裝的 iso 檔案設定在 USB 上,並連接電腦啟動安裝 Linux。
在我們安裝好 Ubuntu 後,就要來完成兩個主要的任務:
為了完成第一步,我們可以用 SFTP 的方式連線到伺服器上,並將檔案放置到伺服器的資料夾中,等等我們使用 WinSCP 進行操作。
首先要做的兩件事情便是確認 IP 地址與更新,在伺服器上輸入:
#更新
sudo apt update && sudo apt upgrade -y
#安裝 net-tools
sudo apt install net-tools
ifconfig
這時,在 enp0 上,便可觀察到伺服器目前的 IP 地址,若你是使用實體機操作,並用網路線與家裡的數據機直接連線,則 ip 地址會由數據機隨機發配給你,在電腦重開機時會重新發配 IP 地址,引此還需要額外設定固定 IP。
這時,我的伺服器 IP 地址為 192.168.1.188。再來為了使 Java 程式能夠運作,我們需要在電腦上安裝 openJDK11 (JDK 內包含了 JVM 和 JRE,所以若伺服器只是想運行 Java 程式而沒有開發的需求,僅安裝 JRE 即可)
#安裝 openJDK11
sudo apt install openjdk-11-jdk -y
java -version
WinSCP 是使用 SSH 的圖形化 SFTP 用戶端軟體,主要的功能是安全的在電腦間傳輸檔案。
我們先在官方網站下載並安裝,完成後開啟 WinSCP,在主機名稱輸入 IP 地址,port 預設 22,並且輸入安裝時設定的使用者與密碼,連線後會看到左側是本機,而右側則是伺服器的地址,預設位置是 /home/userName,這時我們就可以直接將 Jar 檔拖移到伺服器中,並關閉 WinScp。
接著我們要到遠端的伺服器內將 Jar 檔啟動,若你是使用實體機的話,可以直接打開電腦操作,或是使用遠端的工具如 Putty 連線進去。這時我們會在預設的 /home/userName 的路徑下,這時 Ubuntu 內的防火牆並未開啟 8081 port,因此我們需要開啟 8081 port 讓外部的人可以訪問。
#檢視資料夾下的檔案,應該能夠看到 color-code-tag-back-0.0.1-SNAPSHOT.jar
ls -l
#開放 8081 port
sudo ufw allow 8081
#執行 jar 檔
java -jar color-code-tag-back-0.0.1-SNAPSHOT.jar
完成後可以看到 jar 檔被啟動,console 會跑出 Spring Boot 的資訊。接著可以重啟 postman,並將 url 的 localhost 更改成 192.168.1.188,並且重新發送請求,即可獲得回應。這時,我們便是由自己的電腦傳送照片到伺服器上解析,並回傳色碼。
到這裡,我們已經成功地完成 Java 後端的部署,並且開放了服務給外部人使用,而這一種部署 Java 程式的方法事實上也是很多現有服務採用的方式,由於運行會仰賴伺服器的 JDK 版本,當程式的 Java 版本升級時,伺服器的 JDK 也需要隨之升級。另一方面,當我們有了微服務的需求,需要再一台伺服器上啟動不同 Java 版本的程式,則會需要額外的去安裝新的 JDK 版本並指定不同的 Java Home 路徑。
可見這種部署方式會增加程式與環境的耦合度,那既然這樣,我是否將環境獨立開來就好了? 事實上也是如此,藉由建立一個獨立的環境(如再伺服器上建立多個虛擬機),將應用程式所需要的環境打包起來,來解決環境的問題。但隨之而來也是多個虛擬機器的維護、以及消耗記憶體資源 (就是花錢啦) 的問題,同時 Dev 和 Ops 之間的溝通問題也會隨之產生(安裝手冊等文件的維護)。而 Container 便再這個需求之下誕生了。
Container (容器) 是一個以應用程式為核心的打包技術,而 Docker 則是一種容器化的實踐技術。
在上一篇有提到,Container 的目的是為了改善虛擬機器帶來的問題,由於容器是在作業系統之上再虛擬化,並利用 Container Manager (如 Docker),去分配作業系統上的資源。也因此,透過容器,應用程式便不需要再另外安裝作業系統。
(取自 AWS 官網)
因為不需要另外安裝作業系統,建立容器所需要的硬碟容量可以大幅降低,且啟動速度可以更快,不需要等待 Guest OS 的開機時間。,這裡舉幾個 Container 與 VM 的最大差異:
今天我們打包 Jar 檔並執行後端程式,並介紹了容器與 Docker,明天,我們將介紹幾個基本的 Docker 指令,並將前後端的程式打包成 Images,並在伺服器上部署與執行。