为什么我无法在Docker网络中连接到MongoDB?

huangapple go评论96阅读模式
英文:

Why can't I connect to mongodb in docker network

问题

我的Dockerfile

FROM golang:1.18

WORKDIR /usr/src/app

COPY go.mod go.sum ./
RUN go mod download && go mod verify

COPY . .
RUN go build -o app

CMD ["./app"]

我的docker-compose文件

version: "3.7"

services:
  api:
    container_name: 'api'
    build: './'
    ports:
      - '8080:8080'
    volumes:
      - './:/go/src/app'
    depends_on:
      - 'mongodb'
      - 'redis'
    networks:
      - api-network
  mongodb:
    image: mongo:latest
    ports:
      - "27017:27017"
    volumes:
      - ./data/mongo:/data/db
    networks:
      - api-network
  redis:
    image: redis:alpine
    ports:
      - "6379:6379"
    volumes:
      - ./data/redis:/data
    networks:
      - api-network
networks:
  api-network:

我的Go代码

package main

import (
	"context"
	"fmt"
	"go-redis/handler"
	"net/http"
	"os"
	"os/signal"
	"strconv"
	"time"

	"github.com/go-redis/redis/v8"
	"github.com/go-redis/redis_rate/v9"
	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"
	"github.com/labstack/gommon/log"
	"gopkg.in/mgo.v2"
)

var limiter *redis_rate.Limiter

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr: "redis:6379",
	})
	limiter = redis_rate.NewLimiter(rdb)
	e := echo.New()
	e.Logger.SetLevel(log.ERROR)
	e.Use(middleware.Logger())
	e.Use(middleware.GzipWithConfig(middleware.GzipConfig{
		Level: -1,
	}))
	e.Use(middleware.JWTWithConfig(middleware.JWTConfig{
		SigningKey: []byte(handler.JWT_KEY),
		Skipper: func(c echo.Context) bool {
			// Skip authentication for signup and login requests
			if c.Path() == "/login" || c.Path() == "/signup" || c.Path() == "/all" || c.Path() == "" {
				return true
			}
			return false
		},
	}))
	e.Use(rateLimiting)
	db, err := mgo.Dial("mongodb://mongodb:27017")
	if err != nil {
		e.Logger.Fatal(err)
	}
	// Create indices
	if err = db.Copy().DB("twitter").C("users").EnsureIndex(mgo.Index{
		Key:    []string{"email"},
		Unique: true,
	}); err != nil {
		log.Fatal(err)
	}
	// Initialize handler
	h := &handler.Handler{DB: db, Rdb: rdb}

	// Routes
	e.POST("/signup", h.SignUp)
	e.POST("/login", h.SignIn)
	e.POST("/follow/:id", h.FollowUser)
	e.POST("/posts", h.NewPost)
	e.GET("/feed", h.FetchPosts)
	e.GET("/users", h.GetUsers)
	e.GET("/all", h.AllPosts)
	e.GET("/", func(c echo.Context) error {
		return c.String(http.StatusOK, "hello world")
	})

	go func() {
		// Start server
		e.Logger.Fatal(e.Start(":1323"))
	}()
	closingChannel := make(chan os.Signal, 1)
	signal.Notify(closingChannel, os.Interrupt)
	<-closingChannel
	fmt.Println("starting to shut down the server...")
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	if err := e.Shutdown(ctx); err != nil {
		fmt.Println("couldnt shut down the server...")
	}
}

func rateLimiting(next echo.HandlerFunc) echo.HandlerFunc {
	return func(c echo.Context) error {
		res, err := limiter.Allow(c.Request().Context(), "project:123", redis_rate.PerMinute(10))
		if err != nil {
			return err
		}
		h := c.Response().Header()
		h.Set("RateLimit-Remaining", strconv.Itoa(res.Remaining))
		log.Printf("Remaining %d", res.Remaining)
		if res.Allowed == 0 {
			// We are rate limited.

			seconds := int(res.RetryAfter / time.Second)
			h.Set("RateLimit-RetryAfter", strconv.Itoa(seconds))

			// Stop processing and return the error.
			return c.JSON(http.StatusTooManyRequests, "Rate limit exceeded")
		}

		// Continue processing as normal.
		return next(c)
	}
}

我得到了"no reachable servers"错误。当我将主机名更改为localhost并运行go run main.go时,没有错误,但是当我想在Docker环境中运行Go应用程序时,无法从Go容器连接到另一个容器。

我以为这是因为MongoDB没有运行。但是Go应用程序依赖于它,所以它应该在执行Go文件之前运行。

你能帮我解决这个问题吗?

更新:

我知道这与问题无关,但我将docker-compose中的端口更改为与应用程序端口相同,即1323。

仍然收到以下错误:

{"time":"2022-06-08T09:19:29.1670281Z","level":"FATAL","prefix":"echo","file":"main.go","line":"47","message":"no reachable servers"}

在第47行。我在连接到MongoDB时记录了错误。

英文:

My dockerfile

FROM golang:1.18
WORKDIR /usr/src/app
COPY go.mod go.sum ./
RUN go mod download &amp;&amp; go mod verify
COPY . .
RUN go build -o app
CMD [&quot;./app&quot;]

My docker-compose file

version: &quot;3.7&quot;
services:
api:
container_name: &#39;api&#39;
build: &#39;./&#39;
ports:
&#160; &#160; &#160; - &#39;8080:8080&#39;
volumes:
&#160; &#160; &#160; - &#39;./:/go/src/app&#39;
depends_on:
&#160; &#160; &#160; - &#39;mongodb&#39;
&#160; &#160; &#160; - &#39;redis&#39;
networks:
&#160; &#160; &#160; - api-network
mongodb:
image: mongo:latest
ports:
&#160; &#160; &#160; - &quot;27017:27017&quot;
volumes:
&#160; &#160; &#160; - ./data/mongo:/data/db
networks:
&#160; &#160; &#160; - api-network
redis:
image: redis:alpine
ports:
&#160; &#160; &#160; - &quot;6379:6379&quot;
volumes:
&#160; &#160; &#160; - ./data/redis:/data
networks:
&#160; &#160; &#160; - api-network
networks:
api-network:

My go code

package main
import (
&quot;context&quot;
&quot;fmt&quot;
&quot;go-redis/handler&quot;
&quot;net/http&quot;
&quot;os&quot;
&quot;os/signal&quot;
&quot;strconv&quot;
&quot;time&quot;
&quot;github.com/go-redis/redis/v8&quot;
&quot;github.com/go-redis/redis_rate/v9&quot;
&quot;github.com/labstack/echo/v4&quot;
&quot;github.com/labstack/echo/v4/middleware&quot;
&quot;github.com/labstack/gommon/log&quot;
&quot;gopkg.in/mgo.v2&quot;
)
var limiter *redis_rate.Limiter
func main() {
rdb := redis.NewClient(&amp;redis.Options{
Addr: &quot;redis:6379&quot;,
})
limiter = redis_rate.NewLimiter(rdb)
e := echo.New()
e.Logger.SetLevel(log.ERROR)
e.Use(middleware.Logger())
e.Use(middleware.GzipWithConfig(middleware.GzipConfig{
Level: -1,
}))
e.Use(middleware.JWTWithConfig(middleware.JWTConfig{
SigningKey: []byte(handler.JWT_KEY),
Skipper: func(c echo.Context) bool {
// Skip authentication for signup and login requests
if c.Path() == &quot;/login&quot; || c.Path() == &quot;/signup&quot; || c.Path() == &quot;/all&quot; || c.Path() == &quot;&quot; {
return true
}
return false
},
}))
e.Use(rateLimiting)
db, err := mgo.Dial(&quot;mongodb://mongodb:27017&quot;)
if err != nil {
e.Logger.Fatal(err)
}
// Create indices
if err = db.Copy().DB(&quot;twitter&quot;).C(&quot;users&quot;).EnsureIndex(mgo.Index{
Key:    []string{&quot;email&quot;},
Unique: true,
}); err != nil {
log.Fatal(err)
}
// Initialize handler
h := &amp;handler.Handler{DB: db, Rdb: rdb}
// Routes
e.POST(&quot;/signup&quot;, h.SignUp)
e.POST(&quot;/login&quot;, h.SignIn)
e.POST(&quot;/follow/:id&quot;, h.FollowUser)
e.POST(&quot;/posts&quot;, h.NewPost)
e.GET(&quot;/feed&quot;, h.FetchPosts)
e.GET(&quot;/users&quot;, h.GetUsers)
e.GET(&quot;/all&quot;, h.AllPosts)
e.GET(&quot;/&quot;, func(c echo.Context) error {
return c.String(http.StatusOK, &quot;hello world&quot;)
})
go func() {
// Start server
e.Logger.Fatal(e.Start(&quot;:1323&quot;))
}()
closingChannel := make(chan os.Signal, 1)
signal.Notify(closingChannel, os.Interrupt)
&lt;-closingChannel
fmt.Println(&quot;starting to shut down the server...&quot;)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := e.Shutdown(ctx); err != nil {
fmt.Println(&quot;couldnt shut down the server...&quot;)
}
}
func rateLimiting(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
res, err := limiter.Allow(c.Request().Context(), &quot;project:123&quot;, redis_rate.PerMinute(10))
if err != nil {
return err
}
h := c.Response().Header()
h.Set(&quot;RateLimit-Remaining&quot;, strconv.Itoa(res.Remaining))
log.Printf(&quot;Remaining %d&quot;, res.Remaining)
if res.Allowed == 0 {
// We are rate limited.
seconds := int(res.RetryAfter / time.Second)
h.Set(&quot;RateLimit-RetryAfter&quot;, strconv.Itoa(seconds))
// Stop processing and return the error.
return c.JSON(http.StatusTooManyRequests, &quot;Rate limit exceeded&quot;)
}
// Continue processing as normal.
return next(c)
}
}

I get no reacable servers error. When I change hostnames with localhost and run go run main.go there are no errors but when I want to run go application in docker env and I can't connect to another container from go container.

I thought it was because mongodb is not running. But the go app depend on that so it should be running before go file got executed.

Can you help me with this problem?

Update:

I know it is not related but I changed ports in docker-compose with the same as application port which is 1323.

Still getting this error

{&quot;time&quot;:&quot;2022-06-08T09:19:29.1670281Z&quot;,&quot;level&quot;:&quot;FATAL&quot;,&quot;prefix&quot;:&quot;echo&quot;,&quot;file&quot;:&quot;main.go&quot;,&quot;line&quot;:&quot;47&quot;,&quot;message&quot;:&quot;no reachable servers&quot;}

On line 47. I am logging the error when connecting to mongodb.

答案1

得分: 1

主机操作系统是什么?

我已经测试了你的代码(注释掉与go-redis/handler相关的部分),结果第一次运行成功,但后续运行失败(尽管在这种情况下,mongodb容器无法启动),并给出了与go应用程序中获得的完全相同的错误消息。

故障发生在停止mongodb容器并将数据库写入磁盘时。如果删除mongodb容器的挂载(即使用docker卷),则后续运行正常。

所以也许解决方案是在你的docker compose设置中使用docker卷

编辑:除非OP添加更多上下文,否则这似乎是这个问题的重复,并且答案确实与使用挂载卷进行数据持久化有关。

英文:

What is the host OS ?

I've tested your code (commenting out what is related to go-redis/handler) and it results that the first run is succesfull but the subsequent runs fail (though in this cases, the mongodb container fails to start) giving the exact same error message you get in the go app.

The fault happens when mongodb container is stopped and database get written to disk. If the mount for mongodb container is removed (i.e. use a docker volume) then subsequent runs are ok.

So may be the solution would be to use a docker volume in your docker compose setup.

EDIT: Unless the OP add more context, this seems as a duplicate of this and the answer is indeed related to the use of mounted volume for data persistence.

huangapple
  • 本文由 发表于 2022年6月8日 17:16:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/72543097.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定