項目地址:https://github.com/EDDYCJY/go... (快上車,支持一波)
原文地址:將Golang應用部署到Dockerhtml
注:mysql
docker
,配好鏡像源f-20180324-docker
分支上go-gin-example
爲基準(請配合本身本地項目靈活變更)在這裏簡單介紹下Docker,建議深刻學習linux
Docker 是一個開源的輕量級容器技術,讓開發者能夠打包他們的應用以及應用運行的上下文環境到一個可移植的鏡像中,而後發佈到任何支持Docker的系統上運行。 經過容器技術,在幾乎沒有性能開銷的狀況下,Docker 爲應用提供了一個隔離運行環境git
接下來咱們正式開始對項目進行 docker
的所需處理和編寫,每個大標題爲步驟大綱github
在 go-gin-example
項目根目錄建立 Dockerfile 文件,寫入內容golang
FROM golang:latest WORKDIR $GOPATH/src/github.com/EDDYCJY/go-gin-example COPY . $GOPATH/src/github.com/EDDYCJY/go-gin-example RUN go build . EXPOSE 8000 ENTRYPOINT ["./go-gin-example"]
golang:latest
鏡像爲基礎鏡像,將工做目錄設置爲 $GOPATH/src/go-gin-example
,並將當前上下文目錄的內容複製到 $GOPATH/src/go-gin-example
中sql
在進行 go build
編譯完畢後,將容器啓動程序設置爲 ./go-gin-example
,也就是咱們所編譯的可執行文件 docker
注意 go-gin-example
在 docker
容器裏編譯,並無在宿主機現場編譯shell
Dockerfile 文件是用於定義 Docker 鏡像生成流程的配置文件,文件內容是一條條指令,每一條指令構建一層,所以每一條指令的內容,就是描述該層應當如何構建;這些指令應用於基礎鏡像並最終建立一個新的鏡像數據庫
你能夠認爲用於快速建立自定義的 Docker 鏡像
一、 FROM
指定基礎鏡像(必須有的指令,而且必須是第一條指令)
二、 WORKDIR
格式爲 WORKDIR
<工做目錄路徑>
使用 WORKDIR
指令能夠來指定工做目錄(或者稱爲當前目錄),之後各層的當前目錄就被改成指定的目錄,若是目錄不存在,WORKDIR
會幫你創建目錄
三、COPY
格式:
COPY <源路徑>... <目標路徑> COPY ["<源路徑1>",... "<目標路徑>"]
COPY
指令將從構建上下文目錄中 <源路徑> 的文件/目錄複製到新的一層的鏡像內的 <目標路徑> 位置
四、RUN
用於執行命令行命令
格式:RUN
<命令>
五、EXPOSE
格式爲 EXPOSE
<端口1> [<端口2>...]
EXPOSE
指令是聲明運行時容器提供服務端口,這只是一個聲明,在運行時並不會由於這個聲明應用就會開啓這個端口的服務
在 Dockerfile 中寫入這樣的聲明有兩個好處
docker run -P
時,會自動隨機映射 EXPOSE
的端口六、ENTRYPOINT
ENTRYPOINT
的格式和 RUN
指令格式同樣,分爲兩種格式
exec
格式:<ENTRYPOINT> "<CMD>"
shell
格式:ENTRYPOINT [ "curl", "-s", "http://ip.cn" ]
ENTRYPOINT
指令是指定容器啓動程序及參數
go-gin-example
的項目根目錄下執行 docker build -t gin-blog-docker .
該命令做用是建立/構建鏡像,-t
指定名稱爲 gin-blog-docker
,.
構建內容爲當前上下文目錄
$ docker build -t gin-blog-docker . Sending build context to Docker daemon 96.39 MB Step 1/6 : FROM golang:latest ---> d632bbfe5767 Step 2/6 : WORKDIR $GOPATH/src/github.com/EDDYCJY/go-gin-example ---> 56294f978c5d Removing intermediate container e112997b995d Step 3/6 : COPY . $GOPATH/src/github.com/EDDYCJY/go-gin-example ---> 3b60960120cf Removing intermediate container 63e310b3f60c Step 4/6 : RUN go build . ---> Running in 52648a431450 ---> 7bfbeb301fea Removing intermediate container 52648a431450 Step 5/6 : EXPOSE 8000 ---> Running in 98f5b387d1bb ---> b65bd4076c65 Removing intermediate container 98f5b387d1bb Step 6/6 : ENTRYPOINT ./go-gin-example ---> Running in c4f6cdeb667b ---> d8a109c7697c Removing intermediate container c4f6cdeb667b Successfully built d8a109c7697c
查看全部的鏡像,肯定剛剛構建的 gin-blog-docker
鏡像是否存在
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE gin-blog-docker latest d8a109c7697c About a minute ago 946 MB docker.io/golang latest d632bbfe5767 8 days ago 779 MB ...
執行命令 docker run -p 8000:8000 gin-blog-docker
$ docker run -p 8000:8000 gin-blog-docker dial tcp 127.0.0.1:3306: connect: connection refused [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode) ... Actual pid is 1
運行成功,你覺得大功告成了嗎?
你想太多了,仔細看看控制檯的輸出了一條錯誤 dial tcp 127.0.0.1:3306: connect: connection refused
咱們研判一下,發現是 Mysql
的問題,接下來第二項咱們將解決這個問題
從 Docker
的公共倉庫 Dockerhub
下載 MySQL
鏡像(國內建議配個鏡像)
$ docker pull mysql
運行 Mysql
容器,並設置執行成功後返回容器ID
$ docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=rootroot -d mysql 8c86ac986da4922492934b6fe074254c9165b8ee3e184d29865921b0fef29e64
初始化的 Mysql
應該如圖
因爲本來的鏡像存在問題,咱們須要刪除它,此處有幾種作法
name
、tag
的新鏡像刪除本來的有問題的鏡像,-f
是強制刪除及其關聯狀態
若不執行 -f
,你須要執行 docker ps -a
查到所關聯的容器,將其 rm
解除二者依賴關係
$ docker rmi -f gin-blog-docker Untagged: gin-blog-docker:latest Deleted: sha256:d8a109c7697c3c2d9b4de7dbb49669d10106902122817b6467a031706bc52ab4 Deleted: sha256:b65bd4076c65a3c24029ca4def3b3f37001ff7c9eca09e2590c4d29e1e23dce5 Deleted: sha256:7bfbeb301fea9d8912a4b7c43e4bb8b69bdc57f0b416b372bfb6510e476a7dee Deleted: sha256:3b60960120cf619181c1762cdc1b8ce318b8c815e056659809252dd321bcb642 Deleted: sha256:56294f978c5dfcfa4afa8ad033fd76b755b7ecb5237c6829550741a4d2ce10bc
將項目的配置文件 conf/app.ini
,內容修改成
#debug or release RUN_MODE = debug [app] PAGE_SIZE = 10 JWT_SECRET = 233 [server] HTTP_PORT = 8000 READ_TIMEOUT = 60 WRITE_TIMEOUT = 60 [database] TYPE = mysql USER = root PASSWORD = rootroot HOST = mysql:3306 NAME = blog TABLE_PREFIX = blog_
重複先前的步驟,回到 gin-blog
的項目根目錄下執行 docker build -t gin-blog-docker .
Q:咱們須要將 Golang
容器和 Mysql
容器關聯起來,那麼咱們須要怎麼作呢?
A:增長命令 --link mysql:mysql
讓 Golang
容器與 Mysql
容器互聯;經過 --link
,能夠在容器內直接使用其關聯的容器別名進行訪問,而不經過IP,可是--link
只能解決單機容器間的關聯,在分佈式多機的狀況下,須要經過別的方式進行鏈接
執行命令 docker run --link mysql:mysql -p 8000:8000 gin-blog-docker
$ docker run --link mysql:mysql -p 8000:8000 gin-blog-docker [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode) ... Actual pid is 1
檢查啓動輸出、接口測試、數據庫內數據,均正常;咱們的 Golang
容器和 Mysql
容器成功關聯運行,大功告成 :)
雖然應用已經可以跑起來了
但若是對 Golang
和 Docker
有必定的瞭解,我但願你可以想到至少2個問題
gin-blog-docker
佔用空間這麼大?(可用 docker ps -as | grep gin-blog-docker
查看)Mysql
容器直接這麼使用,數據存儲到哪裏去了?Q:第一個問題,爲何這麼鏡像體積這麼大?
A:FROM golang:latest
拉取的是官方 golang
鏡像,包含Golang的編譯和運行環境,外加一堆GCC、build工具,至關齊全
這是有問題的,咱們能夠不在Golang容器中現場編譯的,壓根用不到那些東西,咱們只須要一個可以運行可執行文件的環境便可
Scratch鏡像,簡潔、小巧,基本是個空鏡像
FROM scratch WORKDIR $GOPATH/src/github.com/EDDYCJY/go-gin-example COPY . $GOPATH/src/github.com/EDDYCJY/go-gin-example EXPOSE 8000 CMD ["./go-gin-example"]
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o go-gin-example .
編譯所生成的可執行文件會依賴一些庫,而且是動態連接。在這裏由於使用的是 scratch
鏡像,它是空鏡像,所以咱們須要將生成的可執行文件靜態連接所依賴的庫
$ docker build -t gin-blog-docker-scratch . Sending build context to Docker daemon 133.1 MB Step 1/5 : FROM scratch ---> Step 2/5 : WORKDIR $GOPATH/src/github.com/EDDYCJY/go-gin-example ---> Using cache ---> ee07e166a638 Step 3/5 : COPY . $GOPATH/src/github.com/EDDYCJY/go-gin-example ---> 1489a0693d51 Removing intermediate container e3e9efc0fe4d Step 4/5 : EXPOSE 8000 ---> Running in b5630de5544a ---> 6993e9f8c944 Removing intermediate container b5630de5544a Step 5/5 : CMD ./go-gin-example ---> Running in eebc0d8628ae ---> 5310bebeb86a Removing intermediate container eebc0d8628ae Successfully built 5310bebeb86a
注意,假設你的Golang應用沒有依賴任何的配置等文件,是能夠直接把可執行文件給拷貝進去便可,其餘都沒必要關心
這裏能夠有好幾種解決方案
...
所以這裏若是解決了文件依賴的問題後,就不須要把目錄給 COPY
進去了
$ docker run --link mysql:mysql -p 8000:8000 gin-blog-docker-scratch [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode) [GIN-debug] GET /auth --> github.com/EDDYCJY/go-gin-example/routers/api.GetAuth (3 handlers) ...
成功運行,程序也正常接收請求
接下來咱們再看看佔用大小,執行 docker ps -as
命令
$ docker ps -as CONTAINER ID IMAGE COMMAND ... SIZE 9ebdba5a8445 gin-blog-docker-scratch "./go-gin-example" ... 0 B (virtual 132 MB) 427ee79e6857 gin-blog-docker "./go-gin-example" ... 0 B (virtual 946 MB)
從結果而言,佔用大小以Scratch
鏡像爲基礎的容器完勝,完成目標
假若不作任何干涉,在每次啓動一個 Mysql
容器時,數據庫都是空的。另外容器刪除以後,數據就丟失了(還有各種意外狀況),很是糟糕!
數據卷 是被設計用來持久化數據的,它的生命週期獨立於容器,Docker 不會在容器被刪除後自動刪除 數據卷,而且也不存在垃圾回收這樣的機制來處理沒有任何容器引用的 數據卷。若是須要在刪除容器的同時移除數據卷。能夠在刪除容器的時候使用 docker rm -v
這個命令
數據卷 是一個可供一個或多個容器使用的特殊目錄,它繞過 UFS,能夠提供不少有用的特性:
注意:數據卷 的使用,相似於 Linux 下對目錄或文件進行 mount,鏡像中的被指定爲掛載點的目錄中的文件會隱藏掉,能顯示看的是掛載的 數據卷。
首先建立一個目錄用於存放數據卷;示例目錄 /data/docker-mysql
,注意 --name
本來名稱爲 mysql
的容器,須要將其刪除 docker rm
$ docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=rootroot -v /data/docker-mysql:/var/lib/mysql -d mysql 54611dbcd62eca33fb320f3f624c7941f15697d998f40b24ee535a1acf93ae72
建立成功,檢查目錄 /data/docker-mysql
,下面多了很多數據庫文件
接下來交由你進行驗證,目標是建立一些測試表和數據,而後刪除當前容器,從新建立的容器,數據庫數據也依然存在(固然了數據卷指向要一致)
我已驗證完畢,你呢?