docker + go + gin で connect() failed (111: Connection refused) while connecting to upstream が出た時の対応

docker にて go 製フレームワーク gin を使って hello world を出そうとしていて、
少しハマったのでメモ。

nginx の設定がうまくいかず、
下記のエラーが出ていた。

$ docker-compose up --build
connect() failed (111: Connection refused) while connecting to upstream, client: 172.27.0.1, server: localhost, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:8080", host: "localhost:8080"

以下解決したサンプルコード。
今回エラーが出た問題箇所だけ抜粋。

構造

app/
  ├ .realize.yaml
  ├ bin/
  │   └ dev
  ├ go.mod
  ├ go.sum
  └ main.go
docker-compose.yaml
go/
  └ Dockerfile
nginx/
  └ default.conf

サンプルコード

docker-compose.yaml

depends_on: - go しておけば networks で繋ぐ必要はない?

version: "3"

services:
    app:
        depends_on:
            - go
        image: nginx:1
        volumes:
            - ./app:/var/www/html
            - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
        ports:
            - "8080:80"
        tty: true
        working_dir: /var/www/html

    go:
        build:
            context: .
            dockerfile: ./go/Dockerfile
        volumes:
            - ./app:/var/www/html
        working_dir: /var/www/html

go/Dockerfile

FROM golang:1

RUN go get -u github.com/tockins/realize

CMD [ "bin/dev" ]

app/bin/dev

#!/bin/sh

go mod tidy
realize s

nginx/default.conf

server localhost:8080; を server go:8080; に変更したら解決した。
go:8080; の go は docker-compose.yaml の services: go: の go からとっている。
そこを仮に gogin とかに変更すると gogin:8080 になる。

go:8080 の8080は main.go の r.Run(":8080") からとっている。

upstream nginx_sample {
   # server localhost:8080; ← connect() failed (111: Connection refused) while connecting to upstream
   server go:8080;
}

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    root /var/www/html;

    proxy_redirect                          off;
    proxy_set_header Host                   $host;
    proxy_set_header X-Real-IP              $remote_addr;
    proxy_set_header X-Forwarded-Host       $host;
    proxy_set_header X-Forwarded-Server     $host;
    proxy_set_header X-Forwarded-For        $proxy_add_x_forwarded_for;

    location / {
        proxy_pass http://nginx_sample/;
    }

    index index.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
    	root   /usr/share/nginx/html;
    }


    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    location ~ /\.ht {
    	deny  all;
    }
}

app/main.go

package main

import "github.com/gin-gonic/gin"

func main() {
	r := gin.Default()
	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "hello world",
		})
	})
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	// r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
	r.Run(":8080")
}

起動

$ cd /path/to/your/project
$ docker-compose up --build

http://localhost:8080/ にアクセスして hello world がでたら成功。

まとめ

go 側コンテナで main.go: r.Run(":8080") の記述でサーバーを立てている。基本 localhost:8080 で扱うことになる。

この localhost:8080 を nginx 側で指定する必要があって、
nginx/default.conf で server localhost:8080(エラー出たのでコメントアウトしている)で試したのはそういう理由。

app 側コンテナの nginx/default.conf で go 側コンテナで立てたサーバー localhost:8080 を扱いたい場合、
localhost:8080 を go:8080 で扱う必要があった。
(go:8080 の go は docker-compose.yaml の services: go: の go からとっている)

コンテナ内部で扱うポート番号と外に出して実際アクセスする時に使うポート番号の関係性と扱い方が少し分かったかもしれない。