上一篇文章,我們在 MySQL 容器中放置 sql 檔,完成資料庫的初始化。而本文要介紹的,是將這種經過客製化的容器,轉換為映像檔,再上傳到 Docker Hub 共享。最後討論這道程序,能夠在多人開發上帶來什麼好處。
本文將以 MySQL 為練習對象,請執行下面的指令,取得映像檔。
docker image pull mysql:8.2.0
隨後再建立出容器,但不需要啟動。
docker container create -p 3306:3306 --name SchoolMySQL -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=school mysql:8.2.0
以上的 MYSQL_DATABASE
參數,會建立名為「school」的資料庫。
接著請讀者事先準備一份用「mysqldump」備份出來的「.sql」檔。或者將以下的 SQL 腳本存為 sql 檔。目的是透過它來建立資料表,並插入一些初始資料。
CREATE DATABASE IF NOT EXISTS `school`;
CREATE TABLE `school`.`student` (
`id` VARCHAR(20) NOT NULL,
`studentId` VARCHAR(20) NOT NULL,
`name` VARCHAR(20) NOT NULL,
`birthday` DATE NOT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO `school`.`student`
VALUES("1", "10346000", "Vincent", "1996-01-01");
最後將 sql 檔放置在主機的某資料夾,再複製到 MySQL 容器的 /docker-entrypoint-initdb.d
路徑下,讓 MySQL 在初次啟動時執行。
docker container cp . SchoolMySQL:"/docker-entrypoint-initdb.d"
這時讀者可以啟動容器,並確認 MySQL 真的如預期地完成資料庫的初始化。後續再從容器中刪除該 SQL 腳本,原因後面會說。
以上的準備完成後,讓我們進入正題,開始建立映像檔。
在主機與容器之間,可以做資料的移入和移出,或者軟體本身也可能自行產生資料,我們視為容器已經經過「客製化」了。例如在上一節進行了資料庫內容的初始化。
那麼「將容器打包為映像檔」,指的就是以容器目前的狀態為基礎,來建立出新的映像檔。之後透過這個新映像檔來建立容器,其檔案系統的狀況均會與先前的相同,都具有那些客製化的部份。
附帶一提,第一節將初始化腳本從容器中刪除的原因,是避免使用新映像檔建立容器時,會重複執行。
以容器建立映像檔的 Docker 指令寫法為 docker container commit {容器 id | 容器名稱} {映像檔名稱}
。範例指令如下:
docker container commit SchoolMySQL mysql-for-school-system
把容器打包成映像檔,能讓我們輕鬆建立出檔案系統處於相同狀態的容器,是個方便的功能。
如果映像檔沒有 tag,則預設為「latest」。為了區別映像檔的不同版本,可為其加上適當的 tag。
加 tag 的指令寫法為 docker image tag {映像檔 id | 映像檔名稱} {新映像檔名稱}:{tag}
。
這個指令除了給予 tag,同時也能重新命名映像檔。範例指令如下:
docker image tag mysql-for-school-system mysql-for-college-system:1.0.0
此處的 tag 名稱為「1.0.0」,可以自己取名。並且將映像檔改名為「mysql-for-college-system」。完成後,會看到新舊映像檔並存。
準備好客製化的映像檔後,本節讓我們上傳到 Docker Hub。首先要請讀者註冊該平台的帳號。
dockerhub-homepage-indicate-signup.png
註冊後,可透過指令在 command line 登入,指令寫法為 docker logn --username {帳號}
,隨後再輸入密碼即可。
要上傳的映像檔,其名稱必須包含帳號名稱。如果沒有,請重新命名。指令寫法為docker image tag {映像檔 id | 映像檔名稱} {帳號}/{新映像檔名稱}:{tag}
。
範例指令如下:
docker image tag mysql-for-college-system your_username/mysql-for-college-system:1.0.0
如果已知映像檔是會被上傳的,那麼在前面「以容器建立映像檔」或「加上映像檔 tag」的階段,就可以將帳號名稱加上去了:
docker container commit {容器 id | 容器名稱} {帳號}/{映像檔名稱}:{tag}
docker image tag {映像檔 id | 映像檔名稱} {帳號}/{新映像檔名稱}:{tag}
而上傳的指令寫法為 docker image push {帳號}/{映像檔名稱}:{tag}
。範例指令如下:
docker image push your_username/mysql-for-college-system:1.0.0
稍等一段時間,最後就可以在 Docker Hub 看到上傳完成的映像檔了。
dockerhub-repository-list.png
當別臺電腦想取得這個映像檔,只要下個指令即可。
docker image pull {上傳者帳號}/mysql-for-college-system:1.0.0
本文介紹如何上傳經過客製化後的映像檔,那麼這道程序在多人開發上有什麼幫助呢?本節將從不同面向來思考。
以本文將 MySQL 做為示範對象為例,我們可以在 DB 中預先插入大量測試資料,例如會員、產品、優惠券序號、訊息等。讓開發人員在本地就有資料可以運用。
如果後端或前端的程式沒有寫好,導致 DB 的資料「髒掉」了,那麼重新建立容器即可重回先前初始資料的狀態。
對比筆者前公司在開發階段可能會共用同一個 DB,上述將其做成映像檔共享,讓同事們各自獨立在本地運行容器,也不失為一種安全的做法。
假設我是負責後端的同事,當我在本地寫好程式,會想要有個 UI 畫面來操作,以便驗證結果。這時可以下載前端同事上傳的映像檔,啟動容器即可。不必從版本控制平台(如 Github)中下載前端的專案,也不用記得要如何在本地使用 Node.js 管理和運行前端程式。
假設我是前端的同事,則道理也相同。我不需要了解如何準備後端的程式與資料庫,只要透過後端同事所上傳的映像檔啟動容器就好。
雙方需要知道的,只剩下啟動容器的 Docker 指令和環境參數而已。這點可記在內部文件,或利用之後介紹的「Docker Compose」進一步簡化。
當產品的程式碼都完成了,接下來便會部署(deploy)到測試環境或生產環境。前端、後端與資料庫各自會有一套將成品打包成映像檔的方式,只是如何打包並非本文重點。
總之建立出映像檔並上傳後,需要部署的 server 只要執行 docker container run
指令,即可下載映像檔並啟動容器,相當簡便。而不必透過其他工具或技術(如 FileZilla),將程式的產出傳送到 server 上。
另外不論是前端或後端程式,難免會有一些用來存放連線設定的配置檔。不同的環境,要連線的地址也不同。經由給映像檔加上不同的 tag,能幫助區分這項產出,會部署在哪臺 server,以及對應的版本。
說到這裡,那要如何將自己寫好的程式產出,打包成映像檔呢?下一篇會介紹 Dockerfile,一步步撰寫製作的步驟。
今日文章到此結束!
最後推廣一下自己的部落格,我是「新手工程師的程式教室」的作者,請多指教
請問一下大大**docker image push {帳號}/{映像檔名稱}:{tag}中的{帳號}**是不是應該填入Repositories的名稱,因為一開始我輸入自己的帳號名稱系統會提示說找不到image,後來改成Repositories的名稱才會過,希望大大能幫忙解惑,謝謝大大
嗨嗨!
Repository 名稱正是由「帳號」和「映像檔名稱」組成,所以假設你在上傳 image 時,可能就會輸入如下的指令:
docker image push yanpu/mysql-demo:1.0.0
此時 Repository 名稱就是「yanpu/mysql-demo」了
感謝大大的回覆,後來上傳完有發現repository的組成是由帳號+映像檔名稱組成,想了一下我的問題應該是是否要再上傳前建立好repository才對XD