1 場景描述
- 基於centos7的docker鏡像搭建golang開發環境
- 在docker容器內,使用golang實現一個Web服務器
- 啟動docker容器,並在容器內啟動Web服務器
我購買了一個最低配的阿里雲ECS服務器,並安裝好了git和docker,然后在本地實現Dockerfile和golang源代碼,並將源碼上傳到github,然后再到ECS服務器通過git下載代碼,並生成docker鏡像,最后啟動docker容器,場景圖示如下:
2 你可能會問
- 為什么不直接使用apache或其它http鏡像搭建Web服務器,而是自己實現Web服務?
因為我要自己使用golang實現一個Web服務器,搭建服務器不是目的,練習golang和docker才是目的。 - 為什么不直接使用golang鏡像,而是自己搭建golang開發環境 ?
因為我要部署自己的Web服務器,除了golang,我可能還需要其它操作系統服務,比如數據庫等。
總而言之,我要自己造一次輪子。
3 搭建過程
3.1 使用golang實現一個簡易Web服務器
golang的http包讓搭建Web服務器比寫一個hello world還簡單:
package main import ( "fmt" "net/http" ) func main() { http.HandleFunc("/", home) http.ListenAndServe(":80", nil) } func home(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "welcome to yanzi travel") }
除去包聲明、import語句以及函數頭,這個Web服務器的實現實際只有3行代碼。
3.1.1 注冊路由
http.HandleFunc("/", home)
這行語句的作用是將來自類似http://127.0.0.1:80/的請求路由到home函數。當然,你還可以注冊其它的路由,比如:
http.HandleFunc("/login", login)
將http://127.0.0.1:80/login的請求路由到login函數。home和login函數的原型是:
func(ResponseWriter, *Request)
第一個參數為Web服務器返回給客戶端的數據,第二個參數則是來自客戶端的請求數據。
3.1.2 實現handler
func home(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "welcome to yanzi travel") }
每次接收到http客戶端的請求后,該函數簡單地向客戶端返回一行語句就立即退出。
3.1.3 監聽80端口
http.ListenAndServe(":80", nil)
忽略地址意思是監聽所有地址上的80端口,第二個參數通常為nil,http包會給它指定默認值DefaultServeMux。經過以上三步處理,一個最簡單的Web服務器就搭建成功了,如果不需要在容器內運行,使用go build命令編譯得到可執行文件server.bin:
go build -o server.bin main.go
然后啟動server.bin,在瀏覽器內輸入http://127.0.0.1:80就可以得到服務器返回的結果:
但是,我們的目的是在docker容器內啟動這個Web服務器,那要怎么做?請繼續往下看。
3.2 編寫Dockerfile
實際上,如果只是為了單次部署,可以通過啟動並進入docker容器,然后搭建相應的服務,最后保存到自定義鏡像里即可。但是如此生成的鏡像不可重現,因為單從鏡像文件啟動的容器信息很難反推當初自己做過什么環境搭建和服務部署了。Dcokerfile的好處是讓這些過程變得透明,因為其中描述了鏡像生成的全過程,以及容器啟動的入口等。
3.2.1 指定基礎鏡像
FROM centos:7 MAINTAINER pirlo san <pirlo_san@163.com>
我們會基於官方的centos7鏡像搭建golang開發環境,然后使用golang實現一個Web服務器,並在容器內啟動該服務。
MAINTAINER語句是指定這個鏡像的作者。
3.2.2 安裝goalng開發環境
# install gcc # -y means saying yes to all questions RUN yum install -y gcc # install golang RUN yum install -y go
因為golang可能依賴於gcc,因此需要先安裝gcc
3.2.3 配置golang環境變量
# config GOROOT ENV GOROOT /usr/lib/golang ENV PATH=$PATH:/usr/lib/golang/bin # config GOPATH RUN mkdir -p /root/gopath RUN mkdir -p /root/gopath/src RUN mkdir -p /root/gopath/pkg RUN mkdir -p /root/gopath/bin ENV GOPATH /root/gopath
GOROOT是golang的安裝路徑,GOPATH則是golang的開發包路徑,其中包括src/pkg/bin三個子目錄,分別用於存儲golang源代碼、golang編譯生成的包,以及編譯生成的可執行文件。除了設置GOROOT和GOPATH之外,還需要在操作系統的PATH變量內加入$GOROOT/bin,以讓go工具可以被操作系統找到。
3.2.4 拷貝golang源代碼
# copy source files RUN mkdir -p /root/gopath/src/server COPY src/* /root/gopath/src/server/
在GOPATH的src目錄內創建server目錄,並將本地src目錄內的源文件全部拷貝進去。
3.2.5 編譯Web服務器
# build the server WORKDIR /root/gopath/src/server RUN go build -o server.bin main.go
WORKDIR將容器的工作目錄切換到server目錄,然后執行go build編譯得到可執行文件server.bin。
3.2.6 指定容器入口
# startup the server CMD /root/gopath/src/server/server.bin
CMD指定容器啟動后默認執行的程序,也就是我們剛剛生成的Web服務器。
3.3 生成鏡像
Dockerfile生成以后,就可以在Dockerfile所在目錄執行如下命令生成最終鏡像了,鏡像名稱為server,版本號為v0.1(注意最后的點哦):
docker build -t server:v0.1 .
3.4 啟動容器
終於到了啟動容器的時候了,還有點小激動呢。
docker run -d -p 80:80 server:v0.1
-p參數的意思是將容器的80端口映射到本機的80端口,啟動完成后使用docker ps可以看到我們的容器被啟動了:
[root@iZuf69cwe60vsy9pmo1e9iZ ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ae80a0b54134 server:v0.1 "/bin/sh -c /root/gop" About an hour ago Up About an hour 0.0.0.0:80->80/tcp compassionate_heisenberg
4 客戶端訪問
我的阿里雲ECS服務器公網地址是101.132.163.20,在瀏覽器地址輸入 http://101.132.163.20即可驗證我們的部署結果啦: