DockerコンテナへのGoアプリケーションのデプロイ

イントロ

Dockerについて聞いたことがないが、それが起こりそうにない場合、最初に知っておくべきことは、Dockerを使用すると、アプリケーションを分離して、関心の分離を大幅に分離して実行できると同時に、アプリケーションが外部と通信および対話できることです。

そして、誰もがそれを使用していることを知っておく必要があります。すべての主要なクラウドプロバイダーには、コンテナーの実行専用のソリューションがあるので、それを学ぶ必要があります。

インストール

システムによってインストールが変わるので、確認してくださいhttps://www.docker.com/get-docker

すでにDockerをインストールしていて、dockerシェルで使用可能なコマンド。

囲碁公式画像

Dockerは多くの異なる言語の公式イメージのリストを維持しており、Goも例外ではなく、オリジナルの一部です。公式画像発売 back in 2014.

公式の画像リポジトリは次の場所にあります。https://hub.docker.com/_/golang/。 Goのバージョンとフェッチするオペレーティングシステムの両方を識別するタグはたくさんあります。

サンプルアプリ

例として、Dockerコンテナーに小さなGoアプリをデプロイします。ポート8000でリッスンし、Webページを次のように取得します。qパラメータをクエリし、それをフェッチして、見つかったリンクを出力します。

findlinks.go

package main

import ( “fmt” “log” “net/http”

<span style="color:#e6db74">"golang.org/x/net/html"</span>

)

func main() { http.HandleFunc("/", handler) log.Fatal(http.ListenAndServe(“0.0.0.0:8000”, nil)) }

func handler(w http.ResponseWriter, r *http.Request) { url := r.URL.Query().Get(“q”) fmt.Fprintf(w, “Page = %q\n”, url) if len(url) == 0 { return } page, err := parse(“https://” + url) if err != nil { fmt.Printf(“Error getting page %s %s\n”, url, err) return } links := pageLinks(nil, page) for _, link := range links { fmt.Fprintf(w, “Link = %q\n”, link) } }

func parse(url string) (*html.Node, error) { fmt.Println(url) r, err := http.Get(url) if err != nil { return nil, fmt.Errorf(“Cannot get page”) } b, err := html.Parse(r.Body) if err != nil { return nil, fmt.Errorf(“Cannot parse page”) } return b, err }

func pageLinks(links []string, n *html.Node) []string { if n.Type == html.ElementNode && n.Data == “a” { for _, a := range n.Attr { if a.Key == “href” { links = append(links, a.Val) } } } for c := n.FirstChild; c != nil; c = c.NextSibling { links = pageLinks(links, c) } return links }

使用例:

アプリをDockerに移動する

私はアプリを置きますhttps://github.com/flaviocopes/findlinks

使用するgo getを使用して簡単にダウンロードしてインストールできますgo get github.com/flaviocopes/findlinks

ランニング

docker run golang go get -v github.com/flaviocopes/findlinks

最初にダウンロードしますgolangDockerイメージ(まだ持っていない場合)は、リポジトリをフェッチし、標準ライブラリに含まれていない追加の依存関係をスキャンします。この場合、golang.org/x/net/html

$ docker run golang go get -v github.com/flaviocopes/findlinks
github.com/flaviocopes/findlinks (download)
Fetching https://golang.org/x/net/html?go-get=1
Parsing meta tags from https://golang.org/x/net/html?go-get=1 (status code 200)
get "golang.org/x/net/html": found meta tag main.metaImport{Prefix:"golang.org/x/net", VCS:"git", RepoRoot:"https://go.googlesource.com/net"} at https://golang.org/x/net/html?go-get=1
get "golang.org/x/net/html": verifying non-authoritative meta tag
Fetching https://golang.org/x/net?go-get=1
Parsing meta tags from https://golang.org/x/net?go-get=1 (status code 200)
golang.org/x/net (download)
golang.org/x/net/html/atom
golang.org/x/net/html
github.com/flaviocopes/findlinks

このコマンドは、コンテナーを作成して実行します。を使用して検査できますdocker ps -l-lオプションは、実行された最新のコンテナーをリストするようにDockerに指示します):

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS               NAMES
343d96441f16        golang              "go get -v github...."   3 minutes ago       Exited (0) 2 minutes ago                       mystifying_swanson

コンテナは、go getコマンドが完了しました。

Dockerはオンデマンドイメージを構築して実行しました。再度実行するには、プロセスを繰り返す必要がありますが、画像が役立ちます。このコンテナから画像を作成して、後で実行できるようにします。

docker commit $(docker ps -lq) findlinks

上記のコマンドは、を使用して最後のコンテナIDを取得しますdocker ps -lq、およびイメージをコミットします。を使用して確認できるように、イメージがインストールされましたdocker images findlinks

$ docker images findlinks
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
findlinks           latest              4e7ebb87d02e        11 seconds ago      720MB

実行できますfindlinks私たちのコマンドfindlinksとの画像

docker run -p 8000:8000 findlinks findlinks

それでおしまい!私たちのアプリは今応答しますhttp://192.168.99.100:8000/、 どこ192.168.99.100DockerコンテナのIPアドレスです。

通話をテストできますhttp://192.168.99.100:8000/?q=flaviocopes.com、アプリをローカルで実行したときと同じ出力を出力します。

Page = "flaviocopes.com"
Link = "https://flaviocopes.com/index.xml"
Link = "https://twitter.com/flaviocopes"
Link = "https://github.com/flaviocopes"
Link = "https://stackoverflow.com/users/205039/flaviocopes"
Link = "https://linkedin.com/in/flaviocopes/"
Link = "mailto:[email protected]"
Link = "/"
Link = "/page/contact/"
Link = "/page/about/"
Link = "https://flaviocopes.com/golang-tutorial-rest-api/"
Link = "https://flaviocopes.com/golang-environment-variables/"
Link = "https://flaviocopes.com/golang-sql-database/"
Link = "https://flaviocopes.com/golang-is-go-object-oriented/"
Link = "https://flaviocopes.com/golang-comparing-values/"
Link = "https://flaviocopes.com/golang-data-structures/"
Link = "https://flaviocopes.com/golang-data-structure-binary-search-tree/"
Link = "https://flaviocopes.com/golang-data-structure-graph/"
Link = "https://flaviocopes.com/golang-data-structure-linked-list/"
Link = "https://flaviocopes.com/golang-data-structure-queue/"
Link = "https://flaviocopes.com/golang-data-structure-stack/"
Link = "https://flaviocopes.com/golang-event-listeners/"

Dockerイメージをトリミングします

この戦略は現在非推奨であり、多段階ビルド

上記の結果の問題は、画像は巨大です:この単純なプログラムの720MBは実際には受け入れられません。これは、非常に単純なシナリオであることに注意してください。アプリケーションの何千ものインスタンスをデプロイしたい場合がありますが、このサイズは機能しません。

なぜ画像がこんなに大きいのですか?何が起こるかというと、Goアプリはコンテナー内でコンパイルされるからです。したがって、イメージにはGoコンパイラがインストールされている必要があります。そしてもちろん、コンパイラ、GCC、そしてLinuxディストリビューション全体(Debian Jessie)に必要なすべてのもの。 Goをダウンロードしてインストールし、アプリをコンパイルして実行します。

それは私たちが気付かないほど速いです。しかし、私たちはもっとうまくやることができます。どうやって?学んだことを応用するGoアプリケーション用の最小限のDockerコンテナの構築沿ってニック・ゴーティエ

Dockerに実行するように指示しますgolang:1.8.3画像と静的にコンパイル私たちのアプリケーションは、CGOを無効にします。つまり、イメージは、動的にリンクされたときに通常アクセスする必要のあるCライブラリを必要としません。

docker run --rm -it -v "$GOPATH":/gopath -v "$(pwd)":/app -e "GOPATH=/gopath" -w /app golang:1.8.3 sh -c 'CGO_ENABLED=0 go build -a --installsuffix cgo --ldflags="-s" -o findlinks'

私たちは今持っていますfindlinksフォルダ内のバイナリ:

$ ll
.rw-r--r--   77 flavio 17 Aug 18:57 Dockerfile
.rwxr-xr-x 4.2M flavio 17 Aug 19:13 findlinks
.rw-r--r-- 1.1k flavio 12 Aug 18:10 findlinks.go

$ file findlinks findlinks: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped

もちろん、これは私が取得した場合と同じファイルではないことに注意してくださいgo buildOSXでは、Linux対応のバイナリです。

$ file findlinks
findlinks: Mach-O 64-bit executable x86_64

次に、Dockerfileを作成し、Dockerに使用するように指示します。鉄/ベース、非常に明るい画像:

FROM iron/base
WORKDIR /app
COPY findlinks /app/
ENTRYPOINT ["./findlinks"]

これで、画像を作成してタグを付けることができますflaviocopes/golang-docker-example-findlinks

docker build -t flaviocopes/golang-docker-example-findlinks .

そしてそれを実行します:

docker run --rm -it -p 8000:8000 flaviocopes/golang-docker-example-findlinks

出力は以前と同じですが、今回の画像は720MBではなく、11.1MBです。

REPOSITORY                                    TAG                 IMAGE ID            CREATED             SIZE
flaviocopes/golang-docker-example-findlinks   latest              f32d2fd74638        14 minutes ago      11.1MB
findlinks                                     latest              c60f6792b9f3        20 minutes ago      720MB

マルチステージビルド

このセクションは、Redditのコメントがマルチステージビルドを示しているおかげで追加されました。Docker 17.05

マルチステージビルドバイナリをコンパイルして個別に実行しなくても、非常に簡単に軽量のイメージを作成できます。これは、アプリに配置するDockerfileです。

FROM golang:1.8.3 as builder
WORKDIR /go/src/github.com/flaviocopes/findlinks
RUN go get -d -v golang.org/x/net/html
COPY findlinks.go  .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o findlinks .

FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /root/ COPY --from=builder /go/src/github.com/flaviocopes/findlinks/findlinks . CMD ["./findlinks"]

実行

$ docker build -t flaviocopes/golang-docker-example-findlinks .

軽量(10.8MB)のイメージを構築します:

$ docker images
REPOSITORY                                    TAG                 IMAGE ID            CREATED             SIZE
flaviocopes/golang-docker-example-findlinks   latest              aa2081ca7016        12 seconds ago      10.8MB

Run the image with

$ docker run --rm -it -p 8000:8000 flaviocopes/golang-docker-example-findlinks  

More go tutorials: