熟悉Docker如何提升你在構(gòu)建、測試并部署Go Web應(yīng)用程序的方式,并且理解如何使用Semaphore來持續(xù)部署。
簡介
大多數(shù)情況下Go應(yīng)用程序被編譯成單個二進(jìn)制文件,web應(yīng)用程序則會包括模版和配置文件。而當(dāng)一個項(xiàng)目中有很多文件的時候,由于很多文件沒有同步就會導(dǎo)致錯誤的發(fā)生并且產(chǎn)生很多的問題。
在本教程中,你將學(xué)習(xí)如何使用Docker部署一個Go web應(yīng)用程序,并且認(rèn)識到Docker將如何改進(jìn)你的開發(fā)工作流及部署流程。各種規(guī)模的團(tuán)隊(duì)都會從這里所介紹的設(shè)置中受益。
目標(biāo)
在本文結(jié)束后,你將:
。對Docker有基本的了解,
。發(fā)現(xiàn)在Docker將如何幫助你開發(fā)Go應(yīng)用程序
。學(xué)習(xí)如何為一個生產(chǎn)環(huán)境中的Go應(yīng)用程序創(chuàng)建Docker容器
。知道如何使用Semaphore持續(xù)地在你的服務(wù)器上部署Docker容器
先決條件
為了學(xué)習(xí)本教程,你講需要:
。在你的主機(jī)或者服務(wù)器上安裝Docker
。具有一臺能夠使用SSH密鑰對SSH請求進(jìn)行認(rèn)證的服務(wù)器
理解Docker
Docker幫助你為應(yīng)用程序創(chuàng)建一個單獨(dú)的可部署單元。這個單元,也被稱為容器,包含該應(yīng)用程序需要的所有東西。它包括代碼(或者二進(jìn)制文件)、runtime(運(yùn)行環(huán)境)、系統(tǒng)工具盒系統(tǒng)庫。將所有必需的資源打包成一個單元將確保無論應(yīng)用程序部署到哪里都有完全相同的環(huán)境。這也有助于維護(hù)一個完全相同的開發(fā)和生產(chǎn)配置,這在以前是很難追蹤的。
一旦開始,容器的創(chuàng)建和部署將自動完成。它消除了一大類問題。這些問題主要是由于文件沒有同步或者開發(fā)和生產(chǎn)環(huán)境之間的差異導(dǎo)致的。Docker幫助解決了這些問題。
相比于虛擬機(jī)的優(yōu)勢
容器提供了與虛擬機(jī)相似的資源分配和隔離優(yōu)勢。然而,相同之處僅此而已。
一個虛擬機(jī)需要它自己的客戶操作系統(tǒng)而容器共享主機(jī)操作系統(tǒng)的內(nèi)核。這意味著容器更加輕量而且需要更少的資源。從本質(zhì)上講,一個虛擬機(jī)是操作系統(tǒng)中的一個操作系統(tǒng)。而另一方面的容器則更像是操作系統(tǒng)中的其它應(yīng)用程序?;旧希萜餍枰馁Y源(內(nèi)存、磁盤空間等等)比虛擬機(jī)少很多,并且具有比虛擬機(jī)快很多的啟動時間。
Docker在開發(fā)階段的優(yōu)勢
在開發(fā)中使用Docker的優(yōu)勢包括:
。一個用于所有團(tuán)隊(duì)成員的標(biāo)準(zhǔn)開發(fā)環(huán)境
。更新的依賴性集中化以及在任何地方都能使用相同的容器
。在開發(fā)和生產(chǎn)中完全相同的環(huán)境
。修復(fù)了可能只會出現(xiàn)在生產(chǎn)環(huán)境中的潛在問題
為什么使用Docker運(yùn)行一個Go Web應(yīng)用程序?
多數(shù)Go應(yīng)用程序時簡單的二進(jìn)制文件。這就引發(fā)一個問題 - 為什么使用Docker運(yùn)行一個Go應(yīng)用程序?一些使用Docker運(yùn)行Go的理由包括:
。Web應(yīng)用程序通常都有模版和配置文件。Docker有助于保持這些文件與二進(jìn)制文件的同步
。Docker確保了在開發(fā)或生產(chǎn)中完全相同的配置。很多時候當(dāng)應(yīng)用程序可以在開發(fā)環(huán)境中正常工作時,在生產(chǎn)環(huán)境去無法正常工作。使用DOcker則把你從對這些問題的擔(dān)心中解放了出來。
。在一個大型的團(tuán)隊(duì)中主機(jī)、操作系統(tǒng)及所安裝的軟件可能存在很大的不同。Docker提供了一種機(jī)制來確保一致的開發(fā)環(huán)境配置。這將提升團(tuán)隊(duì)的生產(chǎn)力并且在開發(fā)階段減少沖突和可避免問題的發(fā)生。
創(chuàng)建一個簡單的Go Web應(yīng)用程序
在本文中味了演示,我們會用Go創(chuàng)建一個簡單的Web應(yīng)用程序。這個我們稱之為MathApp的應(yīng)用程序?qū)ⅲ?/p>
。探索不同數(shù)學(xué)運(yùn)算的路徑
。在視圖中使用HTML模版
。使用一個可配置的文件來定制化該應(yīng)用程序
。包含所選功能的測試
訪問 /sum/3/6 將顯示一個包含3與6相加后結(jié)果的頁面。同樣的,訪問 /product/3/6 將顯示一個3和6乘積的頁面。
在本文中我們使用 Beego 框架。請注意你可以為你的應(yīng)用亨旭使用任何框架(或者什么也不用)。
最終的目錄結(jié)構(gòu)
完成之后,MathApp的目錄結(jié)構(gòu)應(yīng)該看起來如下:
?
?
MathApp ├── conf │ └── app.conf ├── main.go ├── main_test.go └── views ├── invalid-route.html └── result.html
?
?
我們假設(shè) MathApp 目錄位于 /app 目錄之中。
應(yīng)用程序的主文件時 main.go ,為主應(yīng)用程序的根目錄中。這個文件包含該應(yīng)用的所有功能。一些 main.go 中的功能是使用 main_test.go 來測試的。
views文件夾中包含視圖文件 invald-route.html 和 result.html 。配置文件 app.conf 位于 conf 文件夾中。 Beego 使用該文件來定制化應(yīng)用程序。
應(yīng)用程序文件的內(nèi)容
應(yīng)用程序主文件(main.go)包含所有的應(yīng)用程序邏輯。該文件的內(nèi)容如下:
?
?
*// main.go* **package** main **import** ( "strconv" "github.com/astaxie/beego" ) *// The main function defines a single route, its handler* *// and starts listening on port 8080 (default port for Beego)* **func** main() { */* This would match routes like the following:* */sum/3/5* */product/6/23* *...* **/* beego.Router("/:operation/int/int", &mainController{}) beego.Run() } *// This is the controller that this application uses* **type** mainController **struct** { beego.Controller } *// Get() handles all requests to the route defined above* **func** (c *mainController) Get() { *//Obtain the values of the route parameters defined in the route above* operation := c.Ctx.Input.Param(":operation") num1, _ := strconv.Atoi(c.Ctx.Input.Param(":num1")) num2, _ := strconv.Atoi(c.Ctx.Input.Param(":num2")) *//Set the values for use in the template* c.Data["operation"] = operation c.Data["num1"] = num1 c.Data["num2"] = num2 c.TplName = "result.html" *// Perform the calculation depending on the 'operation' route parameter* **switch** operation { **case** "sum": c.Data["result"] = add(num1, num2) **case** "product": c.Data["result"] = multiply(num1, num2) **default**: c.TplName = "invalid-route.html" } } **func** add(n1, n2 int) int { **return** n1 + n2 } **func** multiply(n1, n2 int) int { **return** n1 * n2 }
?
?
在你的應(yīng)用程序中,它可能被分割到多個文件中。然而,針對本教程的目的,我們希望事情簡單化。
測試文件的內(nèi)容
main.go文件有一些需要測試的功能。對于這些功能的測試可以在main_test.go中找到。該文件的內(nèi)容如下:
?
?
// main_test.go package main import "testing" func TestSum(t *testing.T) { if add(2, 5) != 7 { t.Fail() } if add(2, 100) != 102 { t.Fail() } if add(222, 100) != 322 { t.Fail() } } func TestProduct(t *testing.T) { if multiply(2, 5) != 10 { t.Fail() } if multiply(2, 100) != 200 { t.Fail() } if multiply(222, 3) != 666 { t.Fail() }
?
?
}
如果你想進(jìn)行持續(xù)的部署,那么對你的應(yīng)用程序進(jìn)行測試是特別有用的。如果你有了足夠的測試,那么你可以持續(xù)地部署而不必?fù)?dān)心在你的應(yīng)用程序中出現(xiàn)錯誤。
視圖文件內(nèi)容
視圖文件時HTML模版。應(yīng)用程序使用它們來顯示對請求的應(yīng)答。result.html的內(nèi)容如下:
?
?
MathApp - {{.operation}} The {{.operation}} of {{.num1}} and {{.num2}} is {{.result}} invalid-route.html的內(nèi)容如下:MathApp Invalid operation
?
?
配置文件的內(nèi)容
app.conf是Beego用于配置應(yīng)用程序的文件。它的內(nèi)容如下:
?
?
; app.conf appname = MathApp httpport = 8080 runmode = dev
?
?
在這個文件中:
。appname是應(yīng)用程序?qū)⒁\(yùn)行的進(jìn)程的名字
。httpport是應(yīng)用程序?qū)⒁O(jiān)聽的的端口
。runmode聲明了應(yīng)用程序?qū)⒁\(yùn)行的模式。有效的指包括dev用于開發(fā)而prod用于生產(chǎn)。
在開發(fā)中使用Docker
本節(jié)將介紹在開發(fā)過程中使用Docker的好處,并且向你展示在開發(fā)中使用Docker的必須步驟。
配置Docker用于開發(fā)
我們將使用dockerfile來配置Docker以便用于開發(fā)。針對開發(fā)環(huán)境,對其的配置應(yīng)該滿足以下的要求:
。我們將使用上一節(jié)所提及的應(yīng)用程序
。這些文件無論從容器的內(nèi)部還是外部都可以訪問
。我們將使用beego自帶的bee工具。它用于在開發(fā)過程中在線地重新加載應(yīng)用程序(在Docker容器的內(nèi)部)
。Docker將為應(yīng)用程序開放8080端口
。在我們的主機(jī)上,應(yīng)用程序保存在/app/MathApp中
。在Docker容器中,應(yīng)用程序保存在/go/src/MathApp中
。我們將為開發(fā)所創(chuàng)建的Docker image的名字是ma-image
。我們將要運(yùn)行的Docker容器的名字是ma-instance
步驟一 - 創(chuàng)建Dockerfile
如下的Dockerfile可以滿足以上的要求:
?
?
**FROM** golang:1.6 *# Install beego and the bee dev tool* **RUN** go get github.com/astaxie/beego && go get github.com/beego/bee *# Expose the application on port 8080* **EXPOSE** 8080 *# Set the entry point of the container to the bee command that runs the* *# application and watches for changes* **CMD** ["bee", "run"]
?
?
第一行,
?
?
FROM golang:1.6
?
?
將Go的官方映像文件作為基礎(chǔ)映像。該映像文件預(yù)安裝了 Go 1.6 . 該映像已經(jīng)把 $GOPATH 的值設(shè)置到了 /go 。所有安裝在 /go/src 中的包將能夠被go命令訪問。
第二行,
?
?
RUN go get github.com/astaxie/beego && go get github.com/beego/bee
?
?
安裝 beego 包和 bee 工具。 beego 包將在應(yīng)用程序中使用。 bee 工具用語在開發(fā)中再現(xiàn)地重新加載我們的代碼。
第三行,
?
?
EXPOSE 8080
?
?
在開發(fā)主機(jī)上利用容器為應(yīng)用程序開放8080端口。
最后一行,
?
?
CMD ["bee", "run"]
?
?
使用bee命令啟動應(yīng)用程序的在線重新加載。
步驟二 - 構(gòu)建image
一旦創(chuàng)建了Docker file,運(yùn)行如下的命令來創(chuàng)建image:
?
?
docker build -t ma-image .
?
?
執(zhí)行以上的命令將創(chuàng)建名為ma-image的image。該image現(xiàn)在可以用于使用該應(yīng)用程序的任何人。這將確保這個團(tuán)隊(duì)能夠使用一個統(tǒng)一的開發(fā)環(huán)境。
為了查看你的系統(tǒng)上的image列表,運(yùn)行如下的命令:
?
?
docker images
?
?
這行該命令將輸出與以下類似的內(nèi)容:
?
?
REPOSITORY TAG IMAGE ID CREATED SIZE ma-image latest 8d53aa0dd0cb 31 seconds ago 784.7 MB golang 1.6 22a6ecf1f7cc 5 days ago 743.9 MB
?
?
注意image的確切名字和編號可能不同,但是,你應(yīng)該至少看到列表中有 golang 和 ma-image image。
步驟三 - 運(yùn)行容器
一旦 ma-image 已經(jīng)完成,你可以使用以下的命令啟動一個容器:
?
?
docker run -it --rm --name ma-instance -p 8080:8080 -v /app/MathApp:/go/src/MathApp -w /go/src/MathApp ma-image
?
?
讓我們分析一下上面的命令來看看它做了什么。
。docker run命令用于從一個image上啟動一個容器
。-it 標(biāo)簽以交互的方式啟動容器
。--rm 標(biāo)簽在容器關(guān)閉后將會將其清除
。--name ma-instance 將容器命名為ma-instance
。-p 8080:8080 標(biāo)簽允許通過8080端口訪問該容器
。-v /app/MathApp:/go/src/MathApp更復(fù)雜一些。它將主機(jī)的/app/MathApp映射到容器中的/go/src/MathApp。這將使得開發(fā)文件在容器的內(nèi)部和外部都可以訪問。
。ma-image 部分聲明了用于容器的image。
執(zhí)行以上的命令將啟動Docker容器。該容器為你的應(yīng)用程序開發(fā)了8080端口。無論何時你做了變更,它都將自動地重構(gòu)你的應(yīng)用程序。你將在console(控制臺)上看到以下的輸出:
?
?
bee :1.4.1 beego :1.6.1 Go :go version go1.6 linux/amd64 2016/04/10 1315 [INFO] Uses 'MathApp' as 'appname' 2016/04/10 1315 [INFO] Initializing watcher... 2016/04/10 1315 [TRAC] Directory(/go/src/MathApp) 2016/04/10 1315 [INFO] Start building... 2016/04/10 1318 [SUCC] Build was successful 2016/04/10 1318 [INFO] Restarting MathApp ... 2016/04/10 1318 [INFO] ./MathApp is running... 2016/04/10 1318 [asm_amd64.s:1998][I] http server Running on :8080
?
?
為了檢查相關(guān)的設(shè)置,可以在瀏覽器中訪問 http://localhost:8080/sum/4/5 。你講看到與下面類似的東西:
注意:這里假定你是在使用本地主機(jī)
步驟四 - 開發(fā)應(yīng)用程序
現(xiàn)在,讓我們看看這將如何在開發(fā)階段提供幫助。在完成以下的操作時請確保容器在運(yùn)行。在## main.go ##文件中,將第34行:
?
?
c.Data["operation"] = operation
?
?
改成:
?
?
c.Data["operation"] = "real " + operation
?
?
在你保存修改的一刻,你講看到類似以下的輸出:
?
?
2016/04/10 1351 [EVEN] "/go/src/MathApp/main.go": MODIFY 2016/04/10 1351 [SKIP] "/go/src/MathApp/main.go": MODIFY 2016/04/10 1352 [INFO] Start building... 2016/04/10 1356 [SUCC] Build was successful 2016/04/10 1356 [INFO] Restarting MathApp ... 2016/04/10 1356 [INFO] ./MathApp is running... 2016/04/10 1356 [asm_amd64.s:1998][I] http server Running on :8080
?
?
為了檢查該變更,在你的瀏覽器中訪問 http://localhost:8080/sum/4/5 。你將看到類似下面的輸出:
如你所見,你的應(yīng)用程序在保存了修改之后自動地編譯并提供了服務(wù)。
在生產(chǎn)中使用Docker
本節(jié)將講解如何在一個Docker容器中部署Go應(yīng)用程序。我們將使用Semaphore來完成以下的工作:
。當(dāng)一個變更被推送到git資料庫后自動地進(jìn)行編譯
。自動地運(yùn)行測試
。如果編譯成功并且通過測試就創(chuàng)建一個Docker映像
。將Docker映像文件推送入Docker Hub
。更新服務(wù)器以便使用最新的Docker映像
創(chuàng)建一個生產(chǎn)用的Dockerfile
在開發(fā)過程中,我們的目錄有如下的結(jié)構(gòu):
?
?
MathApp ├── conf │ └── app.conf ├── main.go ├── main_test.go └── views ├── invalid-route.html └── result.html
?
?
由于我們想要從項(xiàng)目中構(gòu)建Docker映像,我們需要創(chuàng)建一個將用于生產(chǎn)環(huán)境的Dockerfile。在項(xiàng)目的根目錄中創(chuàng)建一個Dockerfile。新的目錄結(jié)構(gòu)如下所示:
?
?
MathApp ├── conf │ └── app.conf ├── Dockerfile ├── main.go ├── main_test.go └── views ├── invalid-route.html └── result.html
?
?
在Dockerfile文件中輸入以下的內(nèi)容:
?
?
FROM golang:1.6
?
?
Create the directory where the application will reside
RUN?mkdir?/app
Copy the application files (needed for production)
ADD?MathApp?/app/MathApp
ADD?views?/app/views
ADD?conf?/app/conf
Set the working directory to the app directory
WORKDIR?/app
Expose the application on port 8080.
This should be the same as in the app.conf file
EXPOSE?8080
Set the entry point of the container to the application executable
ENTRYPOINT?/app/MathApp
讓我們具體看一下這些命令都做了什么。第一個命令,
?
?
FROM golang:1.6
?
?
表明將基于我們在開發(fā)中使用的golang:1.6映像構(gòu)建新的映像文件。第二個命令:
?
?
RUN mkdir /app
?
?
在容器的根里創(chuàng)建一個名為app的目錄,我們用其來保存項(xiàng)目文件。第三個命令集:
?
?
ADD MathApp /app/MathApp ADD views /app/views ADD conf /app/conf
?
?
從主機(jī)中拷貝二進(jìn)制、視圖文件夾及配置文件夾到映像文件中的應(yīng)用程序目錄。第四個命令:
?
?
WORKDIR /app
?
?
在映像文件中把/app設(shè)置為工作目錄。第五個命令:
?
?
EXPOSE 8080
?
?
在容器中開放8080端口。該端口應(yīng)該與應(yīng)用程序的 app.conf 文件中聲明的端口一致。最后的命令:
?
?
ENTRYPOINT /app/MathApp
?
?
將映像文件的入口設(shè)置為應(yīng)用程序的二進(jìn)制文件。這將啟動二進(jìn)制文件的執(zhí)行并監(jiān)聽8080端口。
自動地編譯及測試
一旦你把代碼上傳到你的資料庫中Semaphore將自動地對代碼進(jìn)行編譯和測試,一切都變得簡單了。點(diǎn)擊這里了解如何添加你的 Github 或 Bitbucket 項(xiàng)目并且在Semaphore上設(shè)置Golang項(xiàng)目。
一個Go項(xiàng)目的缺省配置文件關(guān)注以下幾點(diǎn):
。獲取相關(guān)文件
。編譯項(xiàng)目
。運(yùn)行測試
一旦你完成這個過程,就可以在Semaphore儀表盤上看到最近的編譯和測試狀態(tài)。如果編譯或測試失敗,該過程會終止而且也不會部署任何內(nèi)容。
在Semaphore上創(chuàng)建Initial Setup來實(shí)現(xiàn)自動部署
一旦你配置好了編譯過程,下一步就是配置部署過程。為了部署應(yīng)用程序,你需要:
1. 創(chuàng)建Docker image
2. 將Docker image推送入Docker Hub
3. 拉取新的image來更新服務(wù)器并基于該image啟動一個新的Docker容器
作為開始,我們需要在semaphore上配置項(xiàng)目實(shí)現(xiàn)持續(xù)部署。
前三個步驟相對簡單:
。選擇部署模式
。選擇部署策略
。選擇在部署過程中使用的資料庫分支
第四步(設(shè)置部署命令),我們將使用下一節(jié)中的命令。當(dāng)前暫且空著并轉(zhuǎn)到下一步。
在第五步中,輸入你的服務(wù)器中用戶的SSH私鑰。這將使得一些部署命令可以在你的服務(wù)器上安全執(zhí)行而不需要輸入口令。
在第六部中,你可以命名你的服務(wù)器。如果你做的話,Semaphore會給該服務(wù)器指定一個類似server-1234這樣的隨機(jī)名字。
在服務(wù)器上設(shè)置更新腳本
之后,我們將配置部署過程,Semaphore將創(chuàng)建新的image冰將其上傳到Docker Hub中。一旦完成,一個Semaphore的命令將執(zhí)行你的服務(wù)器上的腳本來初始化更新過程。
為了完成這個工作,我們需要將名為 update.sh 的文件放置到你的服務(wù)器中。
?
?
#!/bin/bash docker pull $1/ma-prod:latest if docker stop ma-app; then docker rm ma-app; fi docker run -d -p 8080:8080 --name ma-app $1/ma-prod if docker rmi $(docker images --filter "dangling=true" -q --no-trunc); then :; fi
?
?
使用如下的命令給該文件賦予執(zhí)行權(quán)限:
?
?
chmod +x update.sh
?
?
讓我們來看一下該文件是如何使用的。這個腳本接收一個參數(shù)并且在命令中使用該參數(shù)。這個參數(shù)應(yīng)該是你在Docker Hub上的用戶名。下面是使用該命令的例子:
?
?
./update.sh docker_hub_username
?
?
現(xiàn)在讓我們看一下這個文件中的每一個命令來理解他們要做什么。
第一個命令,
?
?
docker pull $1/ma-prod:latest
?
?
從Docker Hub上拉取最新的image到服務(wù)器中。如果你在Docker Hub上的用戶名是 demo_user ,該命令將拉取Docker Hub上標(biāo)記為 latest 、名為 demo_user/ma-prod 的image。
第二個命令:
?
?
if docker stop ma-app; then docker rm ma-app; fi
?
?
停止并刪除之前任何以 ma-app 為名字而啟動的容器。
第三個命令:
?
?
docker run -d -p 8080:8080 --name ma-app $1/ma-prod
?
?
使用在最近一次編譯中包涵變更的最新image來啟動一個新的容器。
最后的命令:
?
?
docker rmi $(docker images --filter "dangling=true" -q --no-trunc)
?
?
從服務(wù)器上刪除任何沒有用的image。這種清理將保持服務(wù)器整潔并降低磁盤空間的占用。
注意:這個文件必須存放在用戶主目錄中,而該用戶就是之前的步驟中所用到的SSH密鑰的所有者。如果文件的位置發(fā)生了變化,則需要在后面的章節(jié)中相應(yīng)地更新部署命令。
配置項(xiàng)目使其能夠支持Docker
缺省情況下,Semaphore上的新項(xiàng)目使用 Ubuntu 14.04 LTS v1603 平臺。該平臺并不支持Docker。由于我們希望使用Docker,我們需要修改Semaphore的配置來使用 Ubuntu 14.04 LTS v1603(beta with Docker support) 平臺。
設(shè)置環(huán)境變量
為了在部署過程中安全使用Docker Hub,我們需要把我們的證書保存在Semaphore自動初始化的環(huán)境變量中。
我們將保存以下的變量:
。DH_USERNAME - Docker Hub用戶名
。DH_PASSWORD - Docker Hub口令
。DH_EMAIL - Docker Hub email地址
這里是如何以安全的方式設(shè)置環(huán)境變量。
設(shè)置部署命令
雖然我們完成了初始配置,但是實(shí)際上什么也不會部署。原因是我們在命令環(huán)節(jié)中都還是空白。
在第一步,我們將輸入用于完成部署過程的命令。為了完成這一步,請進(jìn)入Semaphore中你的項(xiàng)目主頁。
在這一頁上,點(diǎn)擊 Server 欄中服務(wù)器的名字。這將帶你進(jìn)入:
點(diǎn)擊位于頁頭下方頁面右側(cè)的 Edit server 按鈕。
在隨后的一頁中,我們需要關(guān)注標(biāo)題為 Deploy commands 的最后一欄。點(diǎn)擊 Change deploy commands 鏈接來開啟命令編輯。
在編輯框中,輸入如下的命令并點(diǎn)擊 Save Deploy Commands 按鈕:
?
?
go get -v -d ./ go build -v -o MathApp docker login -u $DH_USERNAME -p $DH_PASSWORD -e $DH_EMAIL docker build -t ma-prod . docker tag ma-prod:latest $DH_USERNAME/ma-prod:latest docker push $DH_USERNAME/ma-prod:latest ssh -oStrictHostKeyChecking=no your_server_username@your_ip_address "~/update.sh $DH_USERNAME"
?
?
注意:請確定用正確的值替換 your_server_username@your_ip_address 。
讓我們具體看一下每個命令。
前兩個命令 go get和go build是Go的標(biāo)準(zhǔn)命令用于獲取相關(guān)文件并相應(yīng)地編譯項(xiàng)目。注意go build命令說聲明的二進(jìn)制文件名應(yīng)該是MathApp。這個名字應(yīng)該與Dockerfile中使用的名字相同。
第三個命令,
?
?
docker login -u $DH_USERNAME -p $DH_PASSWORD -e $DH_EMAIL
?
?
使用環(huán)境變量實(shí)現(xiàn)在Docker Hub上的認(rèn)證,從而使得我們能夠推送最新的Image。第四個命令,
?
?
docker build -t ma-prod .
?
?
基于最新的代碼庫萊創(chuàng)建Docker image。第五個命令,
?
?
docker tag ma-prod:latest $DH_USERNAME/ma-prod:latest
?
?
將新生成的image標(biāo)記為 your_docker_hub_username/ma-prod:latest 。完成這一步后,我們就可以把image推送到Docker Hub上相應(yīng)的資料庫中。第六個命令,
?
?
docker push $DH_USERNAME/ma-prod:latest
?
?
將該image推送到Docker Hub中。最后一個命令,
?
?
ssh -oStrictHostKeyChecking=no your_server_username@your_ip_address "~/update.sh $DH_USERNAME"
?
?
使用ssh命令登陸到你的服務(wù)器上并執(zhí)行我們之前創(chuàng)建的 update.sh 腳本。這個腳本從Docker Hub上獲取最新的image并在其上啟動一個新的容器。
部署應(yīng)用程序
由于我們目前還沒有真正地在我們的服務(wù)器上部署應(yīng)用程序,那么我們就手工操作一遍。注意你大可不必這么做。以后你提交任何變更到你的資料庫后,如果編譯和測試都成功的話Semaphore會自動部署你的應(yīng)用程序。我們現(xiàn)在手工部署它知識測試是否一切都能工作正常。
你可以在semaphore 文檔的編譯頁中找到如何手工地部署一個應(yīng)用程序。
一旦你已經(jīng)部署了應(yīng)用程序,就可以訪問:
?
?
http://your_ip_address:8080/sum/4/5
?
?
這將顯示與以下類似的結(jié)果:
這與我們在開發(fā)過程中看到的應(yīng)該是一致的。唯一的不同在于localhost被替換掉,在URL中你應(yīng)使用服務(wù)器的IP地址。
對配置進(jìn)行測試
現(xiàn)在我們已經(jīng)擁有了自動編譯和部署路程配置,我們將看到它是如何簡化工作流的。讓我們做一個小修改然后看看服務(wù)器上的應(yīng)用程序如何自動地響應(yīng)。
讓我們嘗試吧文本的顏色從黑色改為紅色。為了這個結(jié)果,在 views/result.html 文件中把第8行從
?
?
?
?
改成
?
?
?
?
現(xiàn)在,保存文件。在你的應(yīng)用程序目錄中,使用如下的命令提交變更:
?
?
git add views/result.html git commit -m 'Change the color of text from black (default) to red'
?
?
使用如下的命令將變更推送到你的資料庫中:
?
?
git push origin master
?
?
一旦git push命令完成,Semaphore將監(jiān)測到你的資料庫中的變化并且自動地啟動編譯過程。只要編譯過程(包括測試)成功完成,Semaphore將啟動部署過程。Semaphore的儀表盤上會實(shí)時地顯示編譯和部署的過程。
一旦Semaphore的儀表盤上顯示編譯和部署過程都以完成,刷新頁面:
?
?
http://your_ip_address:8080/sum/4/5
?
?
你現(xiàn)在應(yīng)該看到類似以下的內(nèi)容:
總結(jié)
在本教程中,我們學(xué)習(xí)了如何為一個Go應(yīng)用程序創(chuàng)建Docker容器并且使用Semaphore將容器部署到服務(wù)器上。
你現(xiàn)在應(yīng)該能夠使用Docker來簡化以后的Go應(yīng)用程序的部署任務(wù)。
審核編輯:黃飛
?
評論