「Docker」カテゴリーアーカイブ

Istio使ってURLパス単位でリクエスト処理を分けてみる

Istioを使ってURLパス単位で、コンテナアプリケーションを割り振ってみます。

  • コンテナアプリケーションを作成する
    • ソースコードを作成する
    • helloaコンテナイメージを作成する
    • hellobコンテナイメージを作成する
  • コンテナアプリケーションを実行する
  • Istioの設定をする
    • Gatewayを作成する
    • VirtualServiceを作成する
  • 設定を確認する

コンテナアプリケーションを作成する


Istioの割り振り先コンテナアプリケーションを作成します。

今回作成するのは、httpリクエストをポート8080で受け付けると以下の振る舞いを行うアプリケーションです。

    • / ・・・”Hello A” or “Hello B”を表示する
    • /hello ・・・”Hello A” or “Hello B”を表示する

ソースコードを作成する


コンテナアプリケーションで使うソースコードをgolangで作成します。

main.goを以下に示します。マックスハンドラを使って、URL毎に使うhtmlファイルを分けています。

package main

import (
    "log"
    "net/http"
    "html/template"
    "fmt"
)

func main() {
    //index関数をルートディレクトリに指定
    http.HandleFunc("/", index)
    //hello関数をルートディレクトリに指定
    http.HandleFunc("/hello", hello)
    //サーバー起動
    if err := http.ListenAndServe(":8080", nil); err != nil {
        log.Fatal("ListenAndServe:", nil)
    }
}

func index(writer http.ResponseWriter, r *http.Request) {
  generateHTML(writer, "index")
}

func hello(writer http.ResponseWriter, r *http.Request) {
  generateHTML(writer, "hello")
}

func generateHTML(writer http.ResponseWriter, filenames ...string) {
    var files []string
    for _, file := range filenames {
        files = append(files, fmt.Sprintf("templates/%s.html", file))
    }

    templates := template.Must(template.ParseFiles(files...))
  templates.Execute(writer, nil)
}

main.goを実行するコンテナをビルドするためのDockerfileを以下に示します。

FROM golang:latest

# コンテナ作業ディレクトリの変更
WORKDIR /go/src/web
# ホストOSの ./src の中身を作業ディレクトリにコピー
COPY ./src .
RUN go build -o web
# ウェブアプリケーション実行コマンドの実行
CMD ["./web"]

ディレクトリ構造は以下の通りです。index.htmlとhello.htmlはhelloa, hellobアプリケーション毎に作成します。

$ tree .
.
├── Dockerfile
└── src
    ├── main.go
    └── templates
        ├── hello.html
        └── index.html

helloaコンテナイメージを作成する


httpリクエストを受け付けると”Hello A”を表示するhelloaコンテナイメージを作成します。

以下のコマンドを使って、”Hello A”を表示するindex.htmlとhello.htmlを作成します。

$ echo "Hello A" > index.html
$ echo "Hello A" > hello.html

以下のコマンドでコンテナイメージをビルドして、docker registryに登録します。このdocker registryはMicroK8s上にコンテナとして動いています。docker registryの起動方法は、MicroK8sでアプリケーションを動かすを参考にしてください。

$ docker build -t helloa:latest .
$ docker tag helloa 192.168.64.2:32147/helloa
$ docker push 192.168.64.2:32147/helloa

hellobコンテナイメージを作成する


httpリクエストを受け付けると”Hello B”を表示するhelloaコンテナイメージを作成します。

以下のコマンドを使って、”Hello B”を表示するindex.htmlとhello.htmlを作成します。

$ echo "Hello B" > templates/index.html 
$ echo "Hello B" > templates/hello.html

以下のコマンドでコンテナイメージをビルドして、docker registryに登録します。

$ docker build -t hellob:latest .
$ docker tag hellob 192.168.64.2:32147/hellob
$ docker push 192.168.64.2:32147/hellob

コンテナアプリケーションを実行する


作成したコンテナイメージからコンテナアプリケーションを実行します。

以下のコマンドを使って、Injection済みのnamespaceにhelloaとhellobを実行し、サービスを公開します。Injectionの方法は、Microk8sでIstioによるABテストを試してみる(1/2)を参照してください。

ubuntu@microk8s-vm:~$ microk8s.kubectl run helloa --image=localhost:32147/helloa:latest --port=8080 -n istio-app
pod/helloa created
ubuntu@microk8s-vm:~$ microk8s.kubectl run hellob --image=localhost:32147/hellob:latest --port=8080 -n istio-app
pod/hellob created
ubuntu@microk8s-vm:~$ microk8s.kubectl expose pod helloa --port=8080 -n istio-app
service/helloa exposed
ubuntu@microk8s-vm:~$ microk8s.kubectl expose pod hellob --port=8080 -n istio-app
service/hellob exposed

Istioの設定をする


Gatewayを作成する


全てのホスト名をポート80で受け付けるIstioのGatewayを作成します。

yamlファイルを以下に示します。

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: hello-gateway
spec:
  selector:
    istio: ingressgateway # use Istio default gateway implementation
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"

以下のコマンドでgatewayリソースを作成します。

ubuntu@microk8s-vm:~$ microk8s.kubectl apply -f gateway.yaml -n istio-app

VirtualServiceを作成する


/helloのリクエストはhellobに、それ以外はhelloaに割り振るVirtualServiceを作成します。

VirtualService全体のyamlファイルを以下に示します。match.uri.prefixを使うことでURL毎に割り振り先を変更できます。

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: hello-switch-url-route
spec:
  hosts:
  - "*"
  gateways:
  - hello-gateway
  http:
  - match:
    - uri:
        prefix: /hello
    route:
    - destination:
        host: hellob
        port:
          number: 8080
  - route:
    - destination:
        host: helloa
        port:
          number: 8080

設定を確認する


以下のcurlコマンドを利用して確認すると、正しくルーティングされていることがわかります。192.168.64.2:31380はIstio Ingressgatewayの公開Serviceで、[multipass-vmのIP]:[NodePort]です。IngressgatewayをNodePortにする方法は、MicroK8sでIstioによるABテストを試してみる(2/2)を参照してください。

$ curl -s http://192.168.64.2:31380/
Hello A
$ curl -s http://192.168.64.2:31380/hello
Hello B

 

以上です。ページなどモジュール単位で分けるようなシステムには使えそうですね!

Jeagerって何?

Jeagerの概要を調査したので、記事を描いてみました。

  • 分散トレーシング
    • 分散トレーシングとは
    • SpanとTraceの関係
    • Propagation
  •  Jeager
    • Jeagerとは 
    • Jeagerを操作してみる 

分散トレーシング


分散トレーシングとは


分散トレーシングとは、マイクロサービスのような分散されたシステムにおいて、障害の検知や原因特定を迅速化するために考えられた、サービス間通信の監視を行う概念です。

SpanとTraceの関係


分散トレーシングの基本概念であるSpanとTraceの関係について以下に示します。

  • Span・・・サービス単位の処理
  • Trace・・・任意のリクエストにおけるSpanの集合体

Propagation


分散トレーシングでは、Span同士でメタデータを伝播(Propagation)させています。以下のように、HttpヘッダーにSpanのメタデータを埋め込み、Spanの関係を把握しています。

参照元)https://github.com/openzipkin/b3-propagation#overall-process

Jeager


Jeagerとは


分散トレーシングを体現したツールは、Zipkin、Hawkularなど様々あります。Jeagerはその中の一つで、Uber社がGo言語で開発した分散トレーシングシステムです。

CNCFにホストされたのがきっかけで、分散トレーシングシステムの代表例でもあります。IstioをOperatorでインストールする場合は、Jeagerも一緒にインストールすることができ、Operatorによって構成されます。

アーキテクチャは以下の通りです。jeager-clientが取得したログをjeager-agentを経由してjeager-collectorが受け取り、DBにログを保管します。ユーザーはGUIを通して、このDBを参照することができます。

参照元)https://www.jaegertracing.io/docs/1.8/architecture/

Jeagerを操作してみる 


以下の記事で、MicroK8sにIstioをインストールした時に、一緒にインストールされていたJeagerを使って簡単に確認したいと思います。

MicroK8sでistioによるABテストを試してみる(1/2)
MicroK8sでistioによるABテストを試してみる(2/2)

アクセスするとこんな画面でした。キャラクターが可愛い件について。

適当に検索してみると、トレースログ毎に発生日時とレスポンスタイムのグラフに表示されていました。また、それぞれのトレースログの詳細が確認できますし、トレースログ同士を比較する機能までついていました。

トレースログをクリックすると、上で説明したようなTraceとSpanが確認できました。

Httpリクエストヘッダーも確認することができました。

右上の「Trace Timeline」を「Trace Graph」に変更すると、以下のように依存関係が確認できました。

以上です。本当に概要だけですが、参考になれば幸いです。

LinuxでDockerのネットワークサブネットを変更する

LinuxでDockerのネットワークサブネットを変更する方法について紹介します。

  • Dockerのネットワークサブネットを考慮する理由

  • Dockerのネットワークサブネットを変更する方法

Dockerのネットワークサブネットを考慮する理由


dockerサブネットを気にしたことはありますか?
仮想的にアサインされるので外の機器に影響を与えることはないのですが、外のサブネットと重複する場合は少し考慮が必要です。

企業のシステムだと、Proxyサーバーを経由してインターネットへアクセスすることがあります。その時、docker.ioなどインターネットからベースイメージを取得したい場合、dockerでもproxyを指定することになります。しかし、以下のようにdockerサブネットとProxyサーバーのIPアドレスが重複する場合、docker.ioへ到達することができません。ProxyサーバーのIPアドレスを変える訳にもいかないので、dockerのサブネットを変更しなければなりません。

Dockerのネットワークサブネットを変更する方法


ここからDockerのネットワークサブネットを変更する方法について紹介します。と言ってもすぐできます。

以下のコマンドで/lib/systemd/system/docker.serviceを開き、オプション--bip=XXX.XXX.XXX.XXX/XXを追記した後、dockerをリスタートします。

$ vi /lib/systemd/system/docker.service
→「--bip=XXX.XXX.XXX.XXX/XX」を追記
$ systemctl daemon-reload
$ systemctl restart docker

 

以上です!私が実際に仕事で経験した小ネタでした。皆さんもご注意ください。

GoとMongoDBのコンテナでフロントとバックエンドを分けてみる

GoとMongoDBを使って、DBのデータを表示する簡単なWebアプリケーションを作成します。本記事は、過去に投稿したコンテナでフロントとバックエンドを分けてみるで作成したWebアプリケーションのデータ格納先をMongoDBにしたものです。

以下の流れで紹介します。

  • dbコンテナを作成する
  • searcherコンテナを作成する
    • ソースコードを作成する
    • コンテナイメージを作成する
  • webコンテナを作成する
  • アプリケーションを起動する

dbコンテナを作成する


以下の記事で作成したMongoDBのコンテナを利用します。

mongodbコンテナの起動時に初期データを登録してみる

コンテナ起動時に、recommendデータベースcategoriesコレクションに以下のデータが保管されています。

[
  { "name": "スポーツ" },
  { "name": "文化" },
  { "name": "娯楽" },
  { "name": "食事" },
  { "name": "お酒" },
  { "name": "イベント" },
  { "name": "ドライブ" },
  { "name": "文化" }
]

searcherコンテナを作成する


dbコンテナからデータを取得し、json形式で出力するsearcherコンテナを作成します。

ソースコードを作成する


MongoDBからデータを取得し、json形式で出力するgolangを作成します。
MongoDBからデータを取得する方法は、mongodbからデータを抽出するgolangを書くで解説しています。

package main

import (
    "fmt"
    "log"
    "net/http"
    "encoding/json"
    "time"
    "context"
    "os"
    "github.com/gorilla/mux"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    "go.mongodb.org/mongo-driver/bson"
)

type category struct {
    Categories []struct{
      Name string `json:"name"`
    }`json:"categories"`
}

func main() {
    r := mux.NewRouter()
    // localhost:8082/publicでpublicハンドラーを実行
    r.Handle("/public", public)

    //サーバー起動
    if err := http.ListenAndServe(":8082", r); err != nil {
        log.Fatal("ListenAndServe:", nil)
    }
}

var public = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    //MongoDBの認証情報
    credential := options.Credential{
      Username: "root",
      Password: "password",
    }

    //MongoDBへの接続
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    connect, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://db:27017").SetAuth(credential))
    defer connect.Disconnect(ctx)

    //collectionの取得
    collection, err := connect.Database("recommend").Collection("categories").Find(context.Background(), bson.M{})
    if err != nil { log.Fatal(err) }
    var results []bson.M
    if err = collection.All(context.TODO(), &results); err != nil {
      log.Fatal(err)
    }

    //取得したコレクションの_idエントリを削除
    for _, entry_map := range results {
      delete(entry_map, "_id")
    }

    //bson.Mのデータをjson形式に変換
    json_result, err := json.Marshal(results)
    if err != nil {
        fmt.Println("JSON marshal error: ", err)
        return
    }

    //category構造体にJson形式の値を代入
    var output category
    if err := json.Unmarshal(json_result, &output.Categories); err != nil {
        log.Fatal(err)
        os.Exit(1)
    }

    //読み込んだJsonの表示
    json.NewEncoder(w).Encode(output)

})

コンテナイメージを作成する


Dockerfileを書いてコンテナイメージをビルドします。

ディレクトリ構造は以下の通りです。

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

Dockerfileは以下の通りです。

FROM golang:latest

# コンテナ作業ディレクトリの変更
WORKDIR /go/src/searcher
# ホストOSの ./src の中身を作業ディレクトリにコピー
COPY ./src .
RUN go get -u github.com/gorilla/mux
RUN go get -u "go.mongodb.org/mongo-driver/mongo"
RUN go build -o searcher
# ウェブアプリケーション実行コマンドの実行
CMD ["./searcher"]

以下のコマンドで作成します。

$ docker build -t searcher:latest .

webコンテナを作成する


webコンテナは以下の記事で作成したwebコンテナを流用します。以下の記事でフロントとバックエンドを分けていたので、修正する必要がありません。

goコンテナでフロントとバックエンドを分けてみる

アプリケーションを起動する


docker-composeを記述してコンテナアプリケーションを実行します。

docker-composeは以下の通りです。

version: '3'
services:
  db:
    container_name: db
    image: mongo-db:latest
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: password
    ports:
      - "27017:27017"
  searcher:
    container_name: searcher
    image: searcher:latest
    depends_on:
      - db
    links:
      - db
    ports:
      - "8082:8082"
  web:
    container_name: web
    image: web:latest
    depends_on:
      - searcher
    links:
      - searcher
    ports:
      - "8080:8080"

以下のコマンドを実行して起動します。

$ docker-compose up -d

localhost:8080にアクセスすると以下の結果が得られます。

以上です!

MongoDBコンテナの起動時に初期データを登録してみる

MongoDBをちょっと検証で利用するのに便利な方法をご紹介します。
通常DBコンテナには永続ボリュームをアタッチしますが、DBへの接続方法をクイックに確認したい時は、その処理が煩わしく感じます。そんな時私は、コンテナ起動時に簡単なデータを登録して検証しています。
今回はMongoDBを使って、初期データを投入する方法を紹介します。

  • jsonファイルを作成する
  • jsonファイルを登録するスクリプトを作成する
  • コンテナイメージを作成する
  • コンテナを実行する

jsonファイルを作成する


登録するデータを配列構造で記述したjsonファイル(categories.json)を作成します。

[
  { "name": "スポーツ" },
  { "name": "文化" },
  { "name": "娯楽" },
  { "name": "食事" },
  { "name": "お酒" },
  { "name": "イベント" },
  { "name": "ドライブ" },
  { "name": "文化" }
]

jsonファイルを登録するスクリプトを作成する


コンテナ起動時に、categories.jsonのデータをMongoDBに登録するスクリプト(init.sh)を作成します。
recommendDBのcategoriesコレクションに、/docker-entrypoint-initdb.d/categories.jsonの配列構造データを登録しています。

mongoimport --authenticationDatabase admin --username root --password password --db recommend --collection categories --drop --file /docker-entrypoint-initdb.d/categories.json --jsonArray

mongoimportコマンドのドキュメントは以下URLになります。
https://docs.mongodb.com/manual/reference/program/mongoimport/
--dropは、データ登録時にそのコレクションがあった場合、一度削除してからデータを登録します。
--jsonArrayは、配列構造を扱うためのオプションです。

コンテナイメージを作成する


MongoDBを起動するためのDockerfileを作成します。
ビルド用ディレクトリ構造は以下の通りです。

$ tree .
.
├── Dockerfile
├── categories.json
└── init.sh

Dockerfileは以下の通りです。
mongoベースイメージを取得して、/docker-entrypoint-initdb.dに上記で作成したcategories.jsonとinit.shをコピーしています。/docker-entrypoint-initdb.dにスクリプトを配置することで、コンテナ起動時に実行されます。

FROM mongo:latest
COPY categories.json /docker-entrypoint-initdb.d/
COPY init.sh /docker-entrypoint-initdb.d/

以下のコマンドでコンテナイメージを作成します。

$ docker build -t mongo-test .
Sending build context to Docker daemon  4.096kB
Step 1/3 : FROM mongo:latest
 ---> 3f3daf863757
Step 2/3 : COPY categories.json /docker-entrypoint-initdb.d/
 ---> Using cache
 ---> 209a1bede01c
Step 3/3 : COPY init.sh /docker-entrypoint-initdb.d/
 ---> Using cache
 ---> 68ffc7b95b98
Successfully built 68ffc7b95b98
Successfully tagged mongo-test:latest

コンテナを実行する


コンテナを実行します。今回はdocker-compose.yamlを作成しました。

version: '3'
services:
  db:
    container_name: db
    image: mongo-test:latest
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: password
    ports:
      - "27017:27017"

以下のコマンドで実行します。

$ docker-compose up -d
Creating network "wishy_default" with the default driver
Creating db ... done

以下のコマンドで確認してみましょう。データが登録されていることがわかります。

$ docker exec -it db /bin/bash
root@897eb9caf5c4:/# mongo -uroot -ppassword
> show dbs
admin      0.000GB
config     0.000GB
local      0.000GB
recommend  0.000GB
> use recommend
switched to db recommend
> db.categories.find()
{ "_id" : ObjectId("5ecbe8257399a6df837e7384"), "name" : "スポーツ" }
{ "_id" : ObjectId("5ecbe8257399a6df837e7385"), "name" : "娯楽" }
{ "_id" : ObjectId("5ecbe8257399a6df837e7386"), "name" : "食事" }
{ "_id" : ObjectId("5ecbe8257399a6df837e7387"), "name" : "お酒" }
{ "_id" : ObjectId("5ecbe8257399a6df837e7388"), "name" : "文化" }
{ "_id" : ObjectId("5ecbe8257399a6df837e7389"), "name" : "ドライブ" }
{ "_id" : ObjectId("5ecbe8257399a6df837e738a"), "name" : "文化" }
{ "_id" : ObjectId("5ecbe8257399a6df837e738b"), "name" : "イベント" }
> 

以上です!

Goコンテナでフロントとバックエンドを分けてみる

今日はGo言語で簡単なwebアプリケーションを作成します。webとdbにコンテナを分けて、webページにdbから取得したデータを表示したいと思います。以下のように、マイクロサービスを意識して、コンテナ間通信をhttpリクエストで行いたいと思います。

以下の流れで作成します。

  • dbを作成する
  • webを作成する
    • ソースコードを作成する
      • main.goを作成する
      • layout.htmlを作成する
      • index.htmlを作成する
    • Dockerfileを作成する
  • コンテナを実行する
    • コンテナイメージの作成
    • Docker Composeファイルを作成する
    • コンテナを実行する

dbを作成する

 dbコンテナは以下の記事で作成したものを利用します。ここで作成したのは、httpリクエストを行うとjsonファイルを読み込んで出力するコンテナです。本来であればデータベースも作成しますが、今回はhttpリクエストでやり取りするのをメインにしているので、データはファイルにします。データベースを使うのはまた記事書きたいと思います。

go言語でjsonファイルを読み込んで表示してみる

webを作成する

ソースコードを作成する

main.goを作成する

 ポート8080で受け付けると、dbコンテナから取得したjsonコードをhtml形式で表示するwebのソースコード(main.go)を以下に示します。

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "github.com/gorilla/mux"
    "io/ioutil"
    "os"
        "html/template"
)

type category struct {
    Categories []struct{
      Name string `json:"name"`
    }`json:"categories"`
}

func main() {
    r := mux.NewRouter()
    r.Handle("/", index)

    //サーバー起動
    if err := http.ListenAndServe(":8080", r); err != nil {
        log.Fatal("ListenAndServe:", nil)
    }
}

var index = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    url := "http://db:8082/public"
    req, _ := http.NewRequest("GET", url, nil)
    client := new(http.Client)
    resp, _ := client.Do(req)
    defer resp.Body.Close()
    byteArray, _ := ioutil.ReadAll(resp.Body)
    var categories category
    if err := json.Unmarshal(byteArray, &categories); err != nil {
            log.Fatal(err)
            os.Exit(1)
    }
    generateHTML(w, categories, "layout", "index")
})

func generateHTML(writer http.ResponseWriter, data interface{}, filenames ...string) {
    var files []string
    for _, file := range filenames {
        files = append(files, fmt.Sprintf("templates/%s.html", file))
    }

    templates := template.Must(template.ParseFiles(files...))
    templates.ExecuteTemplate(writer, "layout", data)
}

 index = http.HandlerFuncでは、dbコンテナから取得したjsonコードを構造体categoryの変数categoriesに代入し、generateHTML関数を呼び出します。generateHTMLは引数で与えられた名前のhtmlファイル、ここではlayout.htmlとindex.htmlを使ってページを生成します。

layout.htmlを作成する

 generateHTML関数は、layout.htmlとindex.htmlを使ってページを生成します。layout.htmlは以下の通り、body以外のheaderのみを記述しています。layoutを作成することで、それぞれのhtmlのheaderを統一し、ソースコードの重複を回避できます。

{{ define "layout" }}

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Test</title>
  </head>
  <body>
    {{ template "content" . }}
  </body>
</html>

{{ end }}

index.htmlを作成する

 このlayoutを使ったindex.htmlが以下になります。{{ define "content" }} と{{ end }}で囲んだhtml文がlayoutの{{ template "content" . }}、つまりはページの本文に記述されることになります。

{{ define "content" }}
  <center>
    {{ range .Categories }}
        {{ .Name }}<br>
    {{ end }}
  </center>
{{ end }}

Dockerfileを作成する

 コンテナイメージを作成するのに必要なDockerfileを作成します。ビルド用のディレクトリ構造は以下の通りです。

$ tree web
web
├── Dockerfile
└── src
    ├── main.go
    └── templates
        ├── index.html
        └── layout.html

 src配下に作成したソースコードを配置します。このディレクトリ構造に合わせて作成したDockerfileが以下になります。

FROM golang:latest

# コンテナ作業ディレクトリの変更
WORKDIR /go/src/web
# ホストOSの ./src の中身を作業ディレクトリにコピー
COPY ./src .
RUN go get -u github.com/gorilla/mux
RUN go build -o web
# ウェブアプリケーション実行コマンドの実行
CMD ["./web"]

コンテナを実行する

コンテナイメージを作成する

 上記で作成したwebとdbのコンテナイメージを以下のコマンドで作成します。

$ docker build -t web:latest web/
$ docker build -t db:latest db/

Docker Composeファイルを作成する

 webとdbのコンテナイメージからコンテナを実行しますが、webとdb間は通信できる必要があります。そこでdocker-compose.yamlファイルを作成します。以下にその内容を示します。

version: '3'
services:
  db:
    container_name: db
    image: db:latest
    ports:
      - "8082:8082"
  web:
    container_name: web
    image: web:latest
    depends_on:
      - db
    links:
      - db
    ports:
      - "8080:8080"

 docker-compose.yamlはservicesブロックの中に実行するコンテナ毎にブロックを作成します。今回はwebとdbコンテナだけなので、webブロックとdbブロックを作成しました。
 webのmain.goにurl := "http://db:8082/public"とurlを直接指定しました。従ってwebコンテナはホスト名dbをdbコンテナに名前解決できる必要があります。それを定義しているのがlinksです。

コンテナを実行する

 docker-compose.yamlファイルからコンテナを実行するにはdocker-composeコマンドを利用します。docker-compose.yamlを置いたディレクトリで以下のコマンドを実行します。

$ docker-compose up -d
Creating db ... done
Creating web ... done
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS                    NAMES
da224d318f33        web:latest          "./web"             About a minute ago   Up About a minute   0.0.0.0:8080->8080/tcp   web
b245c4eb8320        db:latest           "./searcher"        About a minute ago   Up About a minute   0.0.0.0:8082->8082/tcp   db

 docker-compose.yamlで定義した内容で実行されていることがわかります。ブラウザでhttp://localhost:8080/にアクセスしてみましょう。jsonの中身が表示されていることがわかります。

以上です!なんとなくGo言語がわかってきたようなきてないような。。ちゃんと仕組みから理解した方が良さそうなので、またそういう記事も書きたいと思います!ソースコードが汚いのは許してください。。。