The image can be found here https://content.nanobox.io/content/images/2017/08/heroku-to-docker-banner.png

站在 Docker 的肩膀上,部署任何語言的 Web 應用到 Heroku

前言

前陣子去參加 IT 鐵人賽頒獎典禮,剛好有朋友問到說 Docker 到底能做什麼,雖然知道 Docker 很紅但不知道哪些地方會用到,所以身為 Docker 傳教士的我,決定寫一篇如何部署 Docker 應用到 Heroku 上,算是 Docker 最簡單的應用之一

這篇會從 Docker 是什麼開始講起,接著再把 Node.js 應用打包成 Docker Image,以及把 Image 部署到 Heroku 上,所以就算你完全沒碰過 Docker 跟 Heroku 也不用怕看不懂

先上 Demo

Docker 🐳

Docker 是一種輕量的虛擬化技術,Logo 是一隻可愛的小鯨魚,他可以把你的 應用程式連同環境 打包成一個 Docker Image,譬如說把你寫的 JS 程式碼跟裝有 Node 12 的環境 打包在一起,然後就可以在任何機器上用 Node 12 執行你的 JS code

因為是連同執行環境一起包起來,所以就不會發生「在我那邊明明就可以啊」這樣的問題,可以保證部署環境跟自己開發的環境一致,若有什麼 bug 也比較容易重現

Heroku

我猜聽過 Heroku 的人應該比較少一點,Heroku 是一個雲端應用平台,很適合用來部署 Web 應用,像是簡單的 API server、聊天機器人這種 需要 HTTP server 的應用 都很適合,而且每個月有一千個小時的免費額度,看到免費兩個字就一定要來用一下啊

支援的程式語言方面,因為 Heroku 支援用 Docker Image 進行部署,所以只要你把程式碼跟想要的環境打包成 Image,就可以把它部署到 Heroku 上。簡而言之 Heroku 能部署各種不同語言的應用程式,只要你有辦法把應用打包成 Docker Image

今日任務

今天會示範如何把一個很簡單 Node.js 寫的 Hello World 部署到 Heroku 上,程式碼少到不行只有四行,不嫌麻煩的話可以把 heroku-node-demo clone 下來跟著跑跑看

Step 0 — 事前準備

首先你需要到 Heroku 上申請帳號、裝好 DockerHeroku Cli,完成後下指令 heroku login 進行登入

接著在 Heroku 上新增一個 app(自己想名字)跟目前的專案連結起來

heroku create <YOUR_APP_NAME>
heroku git:remote --app <YOUR_APP_NAME>

成功後會看到這個畫面

Step 1 — 包裝成 Docker Image

下一步是 把應用跟環境包成 Docker Image,那究竟要怎麼包呢?首先在專案目錄下寫一個 Dockerfile

上圖的意思是說,在打包成 Docker image 時要執行這幾個步驟:

  1. 使用 node:12 作為 base image,這樣 image 內就有 Node 12 的環境
  2. 切換工作目錄到 /app,然後把 index.jspackage.json 複製進 image,之後會用到這兩個檔案
  3. 執行 npm installpackage.json 內的 dependencies 都裝好
  4. 設定 image 在 Heroku 上啟動時,自動執行 node index.js 把程式跑起來

寫完 Dockerfile 後執行 docker build -t api-server .,意思是根據目前的 Dockerfile 建出一個叫做 api-server 的 image

第一次 build 要花時間把 base image 下載下來,所以會比較久

完成後下 docker images 就可以看到 api-server,這個 image 包含完整的 Node 12 環境、npm dependencies、還有我寫的 index.js 程式碼,所以他非常肥總共有 916MB

Step 2 — 部署到 Heroku

上一步我們已經確定 Docker image 可以成功 build 出來,接著就是把這個 image 推到 Heroku 的伺服器,由 Heroku 負責把這個 image 跑起來

heroku container:login
heroku container:push web
heroku container:release web

第一次 push 要比較久,之後就都很快了,不用 push 相同的 Layer

部署後下 heroku open 就會自動打開 https://larry-heroku-node.herokuapp.com/,而且預設就有 HTTPS,超棒 der

日後如果要 release 一個新版本,只要再跑一次上面三個指令就可以了,他會自動 build 出一個新版本的 image 並 push 到 Heroku 上

延伸到其他語言

既然標題是叫做「部署任何語言的 Web 應用到 Heroku」,那只示範 Node.js 好像有點不夠意思,所以我也寫個一個 Go 的版本在 heroku-go-demo,程式碼長這樣

雖然換個語言聽起來很費功夫,但反正 Heroku 只認 Docker image,所以其實只要改一下 Dockerfile,把 base image 從 node 改成 golang:1.13npm install 改成 go build,就可以建出一個包含 Go 環境跟執行檔的 image,也就可以部署到 Heroku 上

其他語言如 Python ,就以 python:3 作為 base image,然後跑 pip install 就好。因為 Docker Hub 上面有各種語言的 base image 可以用,甚至連很小眾的 Hylang 也有,所以真的可以部署任何語言的應用到 Heroku 上

從 Heroku 的視角來看,他根本不需要知道 image 包含什麼語言的環境,也不用知道我們的應用是怎麼寫成的,只要負責把 image 跑起來就可以了,這樣子以 Docker image 作為雙方的共同語言對開發者跟 Heroku 來說都方便

結語

雖然這篇是以簡單的 Hello World 作為範例,但只要你知道怎麼寫 Dockerfile 把你的應用跟環境包成 image,就有辦法部署任何語言的應用到 Heroku ,這就是 Docker 厲害的地方,從此不用再擔心雲端平台提供的 Node 版本是多少、glibc 有沒有更到最新等等細節

另外,因為你的應用已經被包裝成 Docker image,即便你有一天不想再用 Heroku 了(Heroku 超過免費額度之後很貴),你也可以輕鬆部署到 Amazon ECS/EKS 或是 Google Kubernetes/App Engine 這種基於容器的雲端服務

日後若應用越做越大想導入 CI/CD 做自動化的測試、部署,也有 GitlabCI/CircleCI/DroneCI 等等免費、自架的 CI 服務可以用,所以完全不會被綁在 Heroku,反而因為用了 Docker 之後讓你的世界變得更寬廣

延伸閱讀

範例程式碼

--

--

一群技術人想要寫出一些好文章所建立的技術專欄。每週二一篇原創文章、一封電子報,歡迎大家訂閱!主網站: https://weekly.starbugs.dev/。

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Larry Lu

Larry Lu

我是 Larry 盧承億,傳說中的 0.1 倍工程師。我熱愛技術、喜歡與人分享,專長是 Javascript 跟 Go,平常會寫寫技術文章還有參加各種技術活動,歡迎大家來找我聊聊技術~