taisablog

taisa's engineer blog

Go

DockerでGoのWebサーバーを起動する

投稿日:


ミニマムにやっておかないと忘れがちなのでメモ

サンプル用Goサーバを作成する

package main

import (
	"encoding/json"
	"net/http"
)

type User struct {
	FirstName string `json:"firstName"`
	LastName  string `json:"lastName"`
}

func users(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	user := User{
		FirstName: "John",
		LastName: "Doe",
	}
	var users []User
	users = append(users, user)
	json.NewEncoder(w).Encode(users)
}

func main() {
	http.HandleFunc("/users", users)
	http.ListenAndServe(":8002", nil)
}

普通に起動して動作確認をします。

$ go run main.go

http://localhost:8002/usersにアクセスするとJSON結果が出力されます。

[
  {
    "firstName": "John",
    "lastName": "Doe"
  }
]

Dockerfile

Dockerfileを作成します。alpineをつけるとよりミニマムなイメージができます。参考(https://hub.docker.com/_/golang?tab=description

FROM golang:1.14
#FROM golang:1.14-alpine

# コンテナログイン時のディレクトリ指定
WORKDIR /opt/sandbox-docker-go

# ホストのファイルをコンテナの作業ディレクトリにコピー
COPY . .
# ADD . .

# ビルド
RUN go build -o app main.go

# 起動
CMD ["/opt/sandbox-docker-go/app"]

構成

$ tree
.
├── Dockerfile
└── main.go

ビルド

$ docker build -t sandbox-docker-go .
[+] Building 3.0s (9/9) FINISHED                                                                                                                                                                                                        
 => [internal] load build definition from Dockerfile                                                                                                                                                                               0.0s
 => => transferring dockerfile: 361B                                                                                                                                                                                               0.0s
 => [internal] load .dockerignore                                                                                                                                                                                                  0.0s
 => => transferring context: 2B                                                                                                                                                                                                    0.0s
 => [internal] load metadata for docker.io/library/golang:1.14                                                                                                                                                                     1.8s
 => [1/4] FROM docker.io/library/golang:1.14@sha256:d31a307a7e42116adb00d8d70971dbf228460904dd9b6217e911d088aa4b650c                                                                                                               0.0s
 => [internal] load build context                                                                                                                                                                                                  0.0s
 => => transferring context: 605B                                                                                                                                                                                                  0.0s
 => CACHED [2/4] WORKDIR /opt/sandbox-docker-go                                                                                                                                                                                    0.0s
 => [3/4] COPY . .                                                                                                                                                                                                                 0.0s
 => [4/4] RUN go build -o app main.go                                                                                                                                                                                              1.0s
 => exporting to image                                                                                                                                                                                                             0.1s
 => => exporting layers                                                                                                                                                                                                            0.1s
 => => writing image sha256:b59f0afdb5a50873182e88aa7e65836b15049b8a8e3d8a3644a856cc438e3610                                                                                                                                       0.0s
 => => naming to docker.io/library/sandbox-docker-go   

Dockerイメージが作成されました。

$ docker images
REPOSITORY                                   TAG                 IMAGE ID            CREATED             SIZE 
sandbox-docker-go                            latest              b59f0afdb5a5        30 seconds ago      817MB

コンテナ起動

$ docker run -p 8002:8002 -td --name sandbox-docker-go b59f0afdb5a5<br>8fe6ad253218c6c700eb91f458eed99cc8bfbd0ea03423d21a6a42d851268409

プロセスチェック

$ docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
8fe6ad253218        b59f0afdb5a5        "/opt/sandbox-docker…"   26 seconds ago      Up 26 seconds                           infallible_williams

http://localhost:8002/usersにアクセスして動作確認をします。

[
  {
    "firstName": "John",
    "lastName": "Doe"
  }
]

コンテナ再起動

$ docker restart cb8f814837cf

コンテナ停止

$ docker stop cb8f814837cf

コンテナ起動

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                       PORTS               NAMES
cb8f814837cf        b59f0afdb5a5        "/opt/sandbox-docker…"   3 minutes ago       Exited (2) 52 seconds ago                        reverent_snyder

$ docker start cb8f814837cf

コンテナプロセスkill

$ docker kill cb8f814837cf

コンテナ削除

$ docker rm cb8f814837cf

イメージ削除

$ docker images
REPOSITORY                                   TAG                 IMAGE ID            CREATED             SIZE
sandbox-docker-go                            latest              b59f0afdb5a5        13 minutes ago      817MB

$ docker rmi b59f0afdb5a5

-Go

執筆者:


  1. Hello to every body, it’s my first pay a visit of this web site; this weblog carries awesome and actually good material in support
    of readers.

  2. youtube.com says:

    Neat blog! Is your theme custom made or did you download it from somewhere?
    A theme like yours with a few simple adjustements would really make my blog stand out.
    Please let me know where you got your design. Thank you

  3. Thanks for the marvelous posting! I definitely enjoyed reading it, you’re a great author.I will always bookmark your blog and will eventually come back
    in the future. I want to encourage you to definitely continue your great job, have a nice
    afternoon!

  4. Thank you for the good writeup. It in fact was a amusement account it.
    Look advanced to more added agreeable from you! By the way, how could we communicate?

comment

Your email address will not be published.

関連記事

Go言語 GORM+GinでTODOリストのAPIを作ってみた

前回の「Go言語 GORM+GinでTODOリストを作ってみた」に続いて「GORM+Gin」でTODOリストのAPIを作ってみました。ソースコードは前回からの差分だけを記載しています。できたものは下記URLから確認できます。 http://sandbox.taisablog.com/api/v1/ GinのGithub 事前情報 Webフレームワーク:Gin (https://github.com/gin-gonic/gin) ORM:GORM (https://gorm.io/docs) DB:MySQL ルーティングは今回はAPIなので以下としました。モデルをtasksにすればよかったと思いましたが一旦このままにしておきます。 [GIN-debug] GET /todo –> main.main.func1 (3 handlers) // 一覧表示 [GIN-debug] POST /todo –> main.main.func2 (3 handlers) // 新規作成 [GIN-debug] GET /todo/:id –> main.main.func3 (3 handlers) // 編集画面表示 [GIN-debug] PUT /todo/:id –> main.main.func4 (3 handlers) // 編集 [GIN-debug] DELETE /todo/:id –> main.main.func5 (3 handlers) // 削除 ディレクトリ構成 . ├── api │   └── v1 │   └── todo.go ├── controllers │   └── todo.go ├── db │   └── db.go ├── main.go ├── models │   └── todo.go ├── router    └── router.go router.go router.goにr.Group(“/api/v1”)のAPI用のグループを追加してルーティングを追加しました。 package router import ( “github.com/gin-contrib/cors” “github.com/gin-gonic/gin” “github.com/jinzhu/gorm” v1 “github.com/taisa831/sandbox-gin/api/v1” “github.com/taisa831/sandbox-gin/controllers” …

no image

【3分で作れる】Goのコマンドラインツール by Cobra

同僚のおすすめでコマンドラインツール作成にCobraを使いました。ものすごく簡単につくれるのですが、それでも少しハマったところがあったので、コマンドラインツールを作るまでの流れを書いておきます。 前提 go version go1.14.2 darwin/amd64利用ライブラリ:https://github.com/spf13/cobra本記事のサンプルコード:https://github.com/taisa831/sandbox-cobra Index 雛形を作成するコマンドを追加するコンフィグを追加するサブコマンドを追加するまとめ 雛形を作成する 雛形作成にはgeneratorを使います。go getしてcobraコマンドを利用可能にします。 go get -u github.com/spf13/cobra/cobra cobraコマンドを実行すると以下のようなusageが表示されます。 $ cobra Cobra is a CLI library for Go that empowers applications. This application is a tool to generate the needed files to quickly create a Cobra application. Usage: cobra [command] Available Commands: add Add a command to a Cobra Application help Help about any command init Initialize a Cobra Application Flags: -a, –author string author name for copyright attribution (default “YOUR NAME”) –config string config file (default is $HOME/.cobra.yaml) -h, –help help for cobra -l, –license string name of license for the project …

GORMでよく使うSQLの書き方

GORMでよく使うSQLの書き方をメモとして残しておきます。詳細は記事最後の参考リンクの公式ドキュメントで確認できます。 CREATE insertするだけであれば create を利用します。 db.Create(&models.User{Name: “user”}) # 実行SQL INSERT INTO “users” (“created_at”,”updated_at”,”name”,”email”) VALUES (‘2020-04-25 11:22:00′,’2020-04-25 11:22:00′,’user’,0) UPDATE 特定のフィールドだけ更新したい場合、 Update と Updates を使います。 update 一つのフィールドだけアップデートします。 user := &models.User{Name: “user”} db.Create(user) db.Model(user).Update(“name”, “user2”) # 実行SQL INSERT INTO “users” (“created_at”,”updated_at”,”name”,”email”) VALUES (‘2020-04-25 11:34:39′,’2020-04-25 11:34:39′,’user’,”) UPDATE “users” SET “name” = ‘user2’, “updated_at” = ‘2020-04-25 11:34:39’ WHERE “users”.”id” = 5 updates updates は map を利用して複数のフィールドをアップデートします。 user := &models.User{Name: “user”} db.Create(user) db.Model(user).Updates(map[string]interface{}{“name”: “user3”, “email”: “g5.taisa831@gmail.com”}) # 実行SQL INSERT INTO “users” (“created_at”,”updated_at”,”name”,”email”) VALUES (‘2020-04-25 11:39:52′,’2020-04-25 11:39:52′,’user’,”) UPDATE “users” SET “email” = ‘g5.taisa831@gmail.com’, “name” = ‘user3’, “updated_at” = ‘2020-04-25 11:39:52’ WHERE “users”.”id” = 6 SAVE Save は SQL を実行する際にすべてのフィールドを含みます。フィールドを指定しなくても空にはなりません。 user := &models.User{Name: …

Golangを使ってJWTを15分で理解する

JWTとは JWT(ジョットと言うらしい)はJSON Web Tokenの略で、JSONをベースとしたアクセストークンのためのオープン標準 (RFC 7519) です。色々記事を見ましたが、最終的にWikipediaが分かりやすく一番参考にしました。https://ja.wikipedia.org/wiki/JSON_Web_Token JWTの構造 JWTは以下の3つの要素をピリオドで区切った文字列で構成されます。 ヘッダー 署名生成に使用するアルゴリズムを格納します。下記のHS256は、このトークンがHMAC-SHA256で署名されていることを示しています。署名アルゴリズムとしては、SHA-256を使用したHMAC (HS256) や、SHA-256を使用したRSA署名 (RS256) がよく用いられます。 { “alg” : “HS256”, “typ” : “JWT” } ペイロード 認証情報などのクレームを格納します。クレームとはペイロードに含める以下のような標準フィールド(クレーム)を指します。JWTの仕様では、トークンに一般的に含まれる7つの標準フィールドが定義されています。また用途に応じた独自のカスタムフィールドを含むこともできます。下記の例では、トークン発行日時を示す標準のクレーム (iat) と、カスタムクレーム (loggedInAs) を格納しています。 { “loggedInAs” : “admin”, “iat” : 1422779638 } 7つのペイロードの標準クレーム 署名 トークン検証用の署名です。署名はヘッダーとペイロードをBase64urlエンコーディングしてピリオドで結合したものから生成します。署名はヘッダーで指定された暗号化アルゴリズムにより生成されます。下記はHMAC-SHA256形式でのコード例です。 HMAC-SHA256(base64urlEncoding(header) + ‘.’ + base64urlEncoding(payload), ‘secret key’) JWTを使用するにあたって JWTはトークンが返され、それをローカルに保存して利用します(主にlocal storageやsession storageが用いられますが、セッションIDのようにCookieを用いる場合もあります。) 認証時にはAuthorizationヘッダーでBearerスキーマを利用します。またサーバー上に認証状態を保持しないステートレスな認証方式です。その為JWT単体ではトークンを無効にすることが出来ません。サーバーに状態を保持すれば可能ですが、その場合ステートレスの利点は失われることになります。さて、ここまではほぼ Wikipedia に書いてある内容そのままです。ここから実際にGo/GinのJWT Middlewareを使って実際の動作を確認してみます。 Go/GinのJWT Middlewareを使った動作確認 利用するJWT Middlewareについて ここでは、「https://github.com/gin-gonic/gin」 を使う前提で、次のMiddlewareを利用します。「https://github.com/appleboy/gin-jwt」。このMiddlewareは、auth_jwt.goの1ファイルでで構成されていて、「https://github.com/dgrijalva/jwt-go」 をGin用に薄くラップしたものです。jwt-goはトークンを作成したりパースしたり様々な機能が用意されています。 サンプルソース サンプルソースは、https://github.com/appleboy/gin-jwt/blob/master/README.md に載っているのでこれを元に確認します。処理は大きく「ログイン時にToken発行する」と「トークン認証&処理実行する」の2種類あります。 ログイン時にToken発行する ログイン時にTokenを発行する処理は、LoginHandlerです。Routerでは次のように定義しています。LoginHandlerではAuthenticatorとPayloadFuncが呼ばれる為、Middlewareにてこれらを実装する必要があります。 r.POST(“/login”, authMiddleware.LoginHandler) Authenticatorはログイン認証の為の関数です。例では固定値が設定されていますが、実際は主にDBから値を取得することになると思います。PayloadFuncはペイロードに含めるクレームを設定します。ペイロードには任意のクレームを追加可能なので、ログインIDとなるuserIDをセットしています。 // ログインに基づいたユーザの認証振る舞いをするコールバック Authenticator: func(c *gin.Context) (interface{}, error) { var loginVals login if err := c.ShouldBind(&loginVals); err != nil { return “”, jwt.ErrMissingLoginValues } userID := loginVals.Username password := loginVals.Password // …

[Golang] Goを始めたらまずはioパッケージを知るべし

Goを書いているとio.writerとio.readerを扱うケースが頻繁に出てきますが、これはioパッケージが多くの他のパッケージのインターフェースになっているからなのでioパッケージを知っておくことで開発が楽になります。 参考書籍 本書はGoのio.Writer、io.Readerからはじまりシステムの深いところまで丁寧に説明されているのでとてもおすすめです。ioパッケージから始まっているのも納得です。Webで無料で見れますし書籍版、PDF版で購入も可能です。 Web版 https://ascii.jp/elem/000/001/235/1235262/ 書籍版 Goならわかるシステムプログラミング ioパッケージのインターフェース一覧 ioパッケージのインターフェース一覧です。Goのインターフェースの実装は、明示的にインターフェースを明示的にimplementsせず、インターフェースを満たしていたらimplementsしていることになります。 Reader(インターフェース)Writer(インターフェース)Seeker(インターフェース)Closer(インターフェース)ReadWriter(複合インターフェース)ReadCloser(複合インターフェース)WriteCloser(複合インターフェース)ReadSeeker(複合インターフェース)WriteSeeker(複合インターフェース)ReadWriteCloser(複合インターフェース)ReadWriteSeeker(複合インターフェース)ReaderFrom(インターフェース)WriterTo(インターフェース)ReaderAt(インターフェース)WriterAt(インターフェース)ByteReader(インターフェース)ByteScanner(インターフェース)ByteWriter(インターフェース)RuneScanner(インターフェース)StringWriter(インターフェース) 複合インターフェース表 Goではインターフェースにインターフェースを食わせることができ、ioパッケージで作られている複合インターフェースは以下となります。 インターフェースio.Readerio.Writerio.Seekerio.Closerio.ReadWriter◯◯  io.ReadSeeker◯ ◯ io.ReadCloser◯  ◯io.WriteSeeker ◯◯ io.WriteCloser ◯ ◯io.ReadWriteSeeker◯◯◯ io.ReadWriteCloser◯◯ ◯ インターフェースを満たしている一覧を確認する方法 以下のコマンドを叩くと対象のインターフェースを満たしているものの一覧が確認できます。 $ GOPATH=/ godoc -http “:6060” -analysis type ## 実行後以下のURLにアクセスすると`io`パッケージが確認できる http://localhost:6060/pkg/io/ Readerのimplements一覧 テストも含んでいますが沢山あります pointer type *archive/tar.Reader implements Readerpointer type *archive/tar.regFileReader implements Readerpointer type *archive/tar.sparseFileReader implements Readerpointer type *archive/tar.testFile implements Readerpointer type *archive/zip.checksumReader implements Readerpointer type *archive/zip.pooledFlateReader implements Readerpointer type *bufio.Reader implements Readerpointer type *bufio_test.StringReader implements Readerpointer type *bufio_test.emptyThenNonEmptyReader implements Readerpointer type *bufio_test.errorThenGoodReader implements Readerpointer type *bufio_test.negativeReader implements Readerpointer type *bufio_test.rot13Reader implements Readerpointer type *bufio_test.scriptedReader implements Readerpointer type *bufio_test.slowReader implements Readerpointer type *bufio_test.testReader implements Readerpointer type *bytes.Buffer implements Readerpointer type *bytes.Reader implements Readerpointer type *bytes_test.negativeReader implements Readerpointer …