如何使用容器來協助進行開發(下)
透過Docker將環境建置時間縮短100倍
問題情境
承接上一篇文章,目前已經可以透過單個容器來達成下面的成果。
- 啟動一個直接運行的專案或服務。
- 啟動一個擁有合適環境的容器,並且掛載要開法的專案進去,免除在本地安裝環境的麻煩。
那現在遇到新的問題了,如果我同時有多個專案要執行,每個專案需要的環境也不同,那我光是啟動容器的前置作業就得花很多時間。倒不如還一開始痛苦一點將所有環境建置完成。 要解決這個問題,就該 docker-compose 上場了。
docker-compose 是何方神聖,要怎麼使用?
docker-compose是一套工具,可以讓我們用一個簡單的配置文件來定義和管理多個容器。想像它是一套寫好的使用說明書,docker會按照說明書的內容啟動所有需要的容器,而這一切只需要一行指令就可以完成:
docker-compose up
那我們開始吧!
我們一樣透過專案來實作。在上一篇文章中,我們已經學會使用 Dockerfile 來建置屬於自己的鏡像,並且在該鏡像的基礎上啟動容器。我們的最終目標是能夠透過一行指令,就將專案中的前端畫面與後端伺服器同時啟動,並且會隨著我的專案內容調整而即時更新內容。 我們先將想要見到的成果描述一次。
「我希望可以啟動兩個容器,一個叫做 backend_dev,一個叫做 frontend_dev。這兩個容器分別是夠過我的 backend 以及 frontend 資料夾下的 Dockerfile-env 建置的鏡像啟動的。由於我想要夠執行開發,因此他需要掛載各自資料夾底下的所有檔案。在容器啟動後,我希望他自動執行專案的啟動指令,並且分別將我電腦上的port號 3001 以及 3002 對應到他們開放的 3000 端口上,好讓我可以透過網路與他們互動。喔對了,幫我將 backend_dev 設定一個環境變數 RAILS_ENV 為 development。」
上面描述資訊量有點多的內容,就是我們要寫給 docker 的說明書,也就是專案底下的 docker-compose.yml 檔案。
version: '3.8'
services:
backend:
build:
context: ./backend
dockerfile: Dockerfile-env
container_name: backend_dev
volumes:
- ./backend:/backend
ports:
- "3001:3000"
environment:
- RAILS_ENV=development
command: >
bash -c "bundle check || bundle install &&
rails server -b '0.0.0.0'"
frontend:
build:
context: ./frontend
dockerfile: Dockerfile-env
container_name: frontend_dev
volumes:
- ./frontend:/frontend
ports:
- "3002:3000"
command: >
bash -c "npm install &&
npm start"
我們一行一行來看裡面的內容,看他們如何分別與上面的指令對應,以及實際使用的方法。 首先要注意的是,docker-compose 是透過縮排來定義階層的,因此如果調整到縮排會讓腳本無法確定你想表達的內容。
- version: '3.8':指定docker-compose的版本,現階段可先不用調整它。
- services::定義服務,即我們要啟動的容器有哪些,我們這裡定義的是下面提到的 backend 和 frontend。
- backend 和 frontend::這是我們定義的兩個服務,每個服務都有自己的一組配置。
- build::指定鏡像的建置方式,包括context和dockerfile。
- context: ./backend:設置鏡像建置的上下文路徑。
- dockerfile: 指定用於建置鏡像的Dockerfile,這裡我們不使用上一篇文章使用的 Dockerfile,而是新的,被我們命名為 Dockerfile-env 的檔案。
- container_name::可以指定容器啟動後的名稱。
- volumes::定義掛載的資料夾,這裡將本地的backend和frontend資料夾掛載到容器中。
- ports::將主機的端口映射到容器的端口,這樣我們可以在主機上訪問容器內的服務,在 backend 中,我們主機如果呼叫3001 port號就會被轉到容器 backend 的 3000。
- environment::用來設置環境變數,這裡我們為backend容器設置了RAILS_ENV=development,假設 frontend 有設定一些環境變數的話,也可以設定在這裡,在專案中執行 process.env 就會看到我們設定的變數。
- command::指定容器啟動後要執行的命令,這樣啟動後就會自動啟動我們的專案。
在理解之後,我們只要實際上在終端機中在 docker-compose.yml 所在的路徑打下:
docker-compose up -d
其中-d
跟我們上一篇提到的一樣,是代表後台運行的意思,可以不用加。執行完後,就可以在 docker desktop 看到啟動後的容器。
為了體會他實際在執行中,我們可以在本地瀏覽器輸入localhost:3002
,會看到前端的畫面。
他實際上呼叫了後端一支寫好的 api,只要在輸入框中輸入任意文字。就可以看到後端回傳的哈囉訊息。
如果不相信,還可以自己在後端專案下
backend/app/controllers/hello_controller.rb
中,修改回傳的訊息,再次按下 submit 按鈕就會即時更新囉。
這樣,docker-compose會根據配置文件啟動並管理我們的兩個服務,節省了很多手動操作的時間和精力。
好耶,我會了,然後呢?
到這邊,我們只是很粗淺的學習 docker 在真正實務上的用法,沒有深挖底層的原理,但我們已經可以根據自己需求的環境建置客製化的鏡像。也可以透過 docker-compose 一次啟動多個容器。 希望可以用這些最核心的知識,減少大家在開發過程中環境建置的困擾。如果真的對容器很感興趣的話,可以在自己研究容器的內容,我後續也會再慢慢補上相關的筆記。